summaryrefslogtreecommitdiffstats
path: root/mojo
diff options
context:
space:
mode:
authordarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-04 05:58:58 +0000
committerdarin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-04 05:58:58 +0000
commit82f8b0f47d58226fe5dc8951637c9f614c2d6545 (patch)
treeaff46e1aebb7288a8feb975890fa21bca5d2e312 /mojo
parente9476cd6510e31d114e4de13e01bb54e317d2168 (diff)
downloadchromium_src-82f8b0f47d58226fe5dc8951637c9f614c2d6545.zip
chromium_src-82f8b0f47d58226fe5dc8951637c9f614c2d6545.tar.gz
chromium_src-82f8b0f47d58226fe5dc8951637c9f614c2d6545.tar.bz2
Mojo: Generate bindings that make use of ScopedMessagePipeHandle.
R=abarth@chromium.org, davemoore@google.com, viettrungluu@chromium.org Review URL: https://codereview.chromium.org/97713002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238592 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
-rw-r--r--mojo/apps/js/bindings/codec_unittests.js19
-rw-r--r--mojo/apps/js/bindings/connector_unittests.js7
-rw-r--r--mojo/examples/sample_app/native_viewport_client_impl.cc2
-rw-r--r--mojo/mojo_public.gypi2
-rw-r--r--mojo/public/bindings/generators/cpp_templates/interface_stub_case3
-rw-r--r--mojo/public/bindings/generators/cpp_templates/module.cc-template2
-rw-r--r--mojo/public/bindings/generators/cpp_templates/params_serialization6
-rw-r--r--mojo/public/bindings/generators/cpp_templates/struct_builder_definition2
-rw-r--r--mojo/public/bindings/generators/cpp_templates/struct_declaration2
-rw-r--r--mojo/public/bindings/generators/cpp_templates/struct_definition4
-rw-r--r--mojo/public/bindings/generators/cpp_templates/struct_destructor4
-rw-r--r--mojo/public/bindings/generators/cpp_templates/struct_serialization4
-rw-r--r--mojo/public/bindings/generators/cpp_templates/struct_serialization_definition8
-rw-r--r--mojo/public/bindings/generators/cpp_templates/struct_serialization_traits3
-rw-r--r--mojo/public/bindings/generators/cpp_templates/template_declaration4
-rw-r--r--mojo/public/bindings/generators/mojom.py30
-rw-r--r--mojo/public/bindings/generators/mojom_cpp_generator.py130
-rw-r--r--mojo/public/bindings/generators/mojom_generator.py3
-rw-r--r--mojo/public/bindings/generators/mojom_js_generator.py108
-rw-r--r--mojo/public/bindings/generators/mojom_pack.py27
-rw-r--r--mojo/public/bindings/lib/bindings_internal.h10
-rw-r--r--mojo/public/bindings/lib/bindings_serialization.cc11
-rw-r--r--mojo/public/bindings/lib/bindings_serialization.h26
-rw-r--r--mojo/public/bindings/lib/buffer.cc35
-rw-r--r--mojo/public/bindings/lib/buffer.h21
-rw-r--r--mojo/public/bindings/lib/message.cc9
-rw-r--r--mojo/public/bindings/mojom_bindings_generator.gypi1
-rwxr-xr-xmojo/public/bindings/parse/mojo_parser.py15
-rwxr-xr-xmojo/public/bindings/parse/mojo_translate.py3
-rw-r--r--mojo/public/bindings/sample/sample_service.mojom4
-rw-r--r--mojo/public/bindings/sample/sample_service_unittests.cc25
-rw-r--r--mojo/public/bindings/sample/sample_service_unittests.js11
-rw-r--r--mojo/public/system/core_cpp.h6
-rw-r--r--mojo/public/tests/bindings_connector_unittest.cc2
-rw-r--r--mojo/public/tests/bindings_handle_passing_unittest.cc128
-rw-r--r--mojo/public/tests/sample_factory.mojom30
-rw-r--r--mojo/public/tests/test_support.cc47
-rw-r--r--mojo/public/tests/test_support.h6
-rw-r--r--mojo/services/native_viewport/native_viewport.mojom2
-rw-r--r--mojo/services/native_viewport/native_viewport_impl.cc7
-rw-r--r--mojo/services/native_viewport/native_viewport_impl.h3
41 files changed, 590 insertions, 182 deletions
diff --git a/mojo/apps/js/bindings/codec_unittests.js b/mojo/apps/js/bindings/codec_unittests.js
index d8d8ba0..4511033 100644
--- a/mojo/apps/js/bindings/codec_unittests.js
+++ b/mojo/apps/js/bindings/codec_unittests.js
@@ -76,13 +76,11 @@ define([
foo.extra_bars[i].gamma = 3 * i;
}
foo.name = "I am a banana";
- foo.files = [
- // These are supposed to be handles, but we fake them with integers.
- 23423782, 32549823, 98320423, 38502383, 92834093,
- ];
+ // This is supposed to be a handle, but we fake it with an integer.
+ foo.source = 23423782;
var messageName = 31;
- var payloadSize = 232;
+ var payloadSize = 192;
var builder = new codec.MessageBuilder(messageName, payloadSize);
builder.encodeStruct(sample.Foo, foo);
@@ -90,20 +88,19 @@ define([
var message = builder.finish();
var expectedMemory = new Uint8Array([
- /* 0: */ 240, 0, 0, 0, 31, 0, 0, 0,
- /* 8: */ 64, 0, 0, 0, 10, 0, 0, 0,
+ /* 0: */ 200, 0, 0, 0, 31, 0, 0, 0,
+ /* 8: */ 56, 0, 0, 0, 10, 0, 0, 0,
/* 16: */ 0xD5, 0xB4, 0x12, 0x02, 0x93, 0x6E, 0x01, 0,
/* 24: */ 5, 0, 0, 0, 0, 0, 0, 0,
- /* 32: */ 40, 0, 0, 0, 0, 0, 0, 0,
+ /* 32: */ 32, 0, 0, 0, 0, 0, 0, 0,
]);
// TODO(abarth): Test more of the message's raw memory.
var actualMemory = new Uint8Array(message.memory.buffer,
0, expectedMemory.length);
-
expect(actualMemory).toEqual(expectedMemory);
var expectedHandles = [
- 23423782, 32549823, 98320423, 38502383, 92834093,
+ 23423782,
];
expect(message.handles).toEqual(expectedHandles);
@@ -127,7 +124,7 @@ define([
expect(foo2.extra_bars).toEqual(foo.extra_bars);
expect(foo2.name).toBe(foo.name);
- expect(foo2.files).toEqual(foo.files);
+ expect(foo2.source).toEqual(foo.source);
}
function testAlign() {
diff --git a/mojo/apps/js/bindings/connector_unittests.js b/mojo/apps/js/bindings/connector_unittests.js
index 8aa533f..650cf78 100644
--- a/mojo/apps/js/bindings/connector_unittests.js
+++ b/mojo/apps/js/bindings/connector_unittests.js
@@ -90,6 +90,7 @@ define([
var pipe = core.createMessagePipe();
var anotherPipe = core.createMessagePipe();
+ var sourcePipe = core.createMessagePipe();
var connection0 = new connector.Connection(
pipe.handle0, ServiceImpl, sample.ServiceClientProxy);
@@ -100,6 +101,7 @@ define([
var foo = new sample.Foo();
foo.bar = new sample.Bar();
foo.name = "Example name";
+ foo.source = sourcePipe.handle0;
connection1.remote.frobinate(foo, true, anotherPipe.handle0);
mockSupport.pumpOnce(core.RESULT_OK);
@@ -112,6 +114,11 @@ define([
expect(mockSupport.numberOfWaitingCallbacks()).toBe(0);
+ // sourcePipe.handle0 was closed automatically when sent over IPC.
+ expect(core.close(sourcePipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT);
+ // sourcePipe.handle1 hasn't been closed yet.
+ expect(core.close(sourcePipe.handle1)).toBe(core.RESULT_OK);
+
// anotherPipe.handle0 was closed automatically when sent over IPC.
expect(core.close(anotherPipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT);
// anotherPipe.handle1 hasn't been closed yet.
diff --git a/mojo/examples/sample_app/native_viewport_client_impl.cc b/mojo/examples/sample_app/native_viewport_client_impl.cc
index 5d70df1..c956051 100644
--- a/mojo/examples/sample_app/native_viewport_client_impl.cc
+++ b/mojo/examples/sample_app/native_viewport_client_impl.cc
@@ -26,7 +26,7 @@ void NativeViewportClientImpl::Open() {
CreateMessagePipe(&gles2, &gles2_client);
gles2_client_.reset(new GLES2ClientImpl(gles2.Pass()));
- service_->CreateGLES2Context(gles2_client.release());
+ service_->CreateGLES2Context(gles2_client.Pass());
}
void NativeViewportClientImpl::DidOpen() {
diff --git a/mojo/mojo_public.gypi b/mojo/mojo_public.gypi
index 01dd9a2..ea671cb 100644
--- a/mojo/mojo_public.gypi
+++ b/mojo/mojo_public.gypi
@@ -27,10 +27,12 @@
],
'sources': [
'public/tests/bindings_connector_unittest.cc',
+ 'public/tests/bindings_handle_passing_unittest.cc',
'public/tests/bindings_remote_ptr_unittest.cc',
'public/tests/bindings_type_conversion_unittest.cc',
'public/tests/buffer_unittest.cc',
'public/tests/math_calculator.mojom',
+ 'public/tests/sample_factory.mojom',
'public/tests/system_core_cpp_unittest.cc',
'public/tests/system_core_unittest.cc',
'public/tests/test_structs.mojom',
diff --git a/mojo/public/bindings/generators/cpp_templates/interface_stub_case b/mojo/public/bindings/generators/cpp_templates/interface_stub_case
index f02702a..808cdb3 100644
--- a/mojo/public/bindings/generators/cpp_templates/interface_stub_case
+++ b/mojo/public/bindings/generators/cpp_templates/interface_stub_case
@@ -3,8 +3,9 @@
reinterpret_cast<internal::${CLASS}_${METHOD}_Params_Data*>(
message->data->payload);
- if (!mojo::internal::DecodePointersAndHandles(params, *message))
+ if (!mojo::internal::DecodePointersAndHandles(params, message))
return false;
$METHOD_CALL
+ mojo::internal::CloseHandles(params);
break;
}
diff --git a/mojo/public/bindings/generators/cpp_templates/module.cc-template b/mojo/public/bindings/generators/cpp_templates/module.cc-template
index 404d923..e8100fb 100644
--- a/mojo/public/bindings/generators/cpp_templates/module.cc-template
+++ b/mojo/public/bindings/generators/cpp_templates/module.cc-template
@@ -26,6 +26,8 @@ $PARAM_DEFINITIONS
$STRUCT_DEFINITIONS
+$STRUCT_DESTRUCTORS
+
} // namespace internal
$STRUCT_BUILDER_DEFINITIONS
diff --git a/mojo/public/bindings/generators/cpp_templates/params_serialization b/mojo/public/bindings/generators/cpp_templates/params_serialization
index c3a57b5..0a89cd9 100644
--- a/mojo/public/bindings/generators/cpp_templates/params_serialization
+++ b/mojo/public/bindings/generators/cpp_templates/params_serialization
@@ -1,6 +1,10 @@
template <>
class ObjectTraits<$CLASS> {
public:
+ static void CloseHandles($CLASS* $NAME) {
+$CLOSES
+ }
+
static void EncodePointersAndHandles(
$CLASS* $NAME,
std::vector<Handle>* handles) {
@@ -10,7 +14,7 @@ $ENCODE_HANDLES
static bool DecodePointersAndHandles(
$CLASS* $NAME,
- const Message& message) {
+ Message* message) {
$DECODES
$DECODE_HANDLES
return true;
diff --git a/mojo/public/bindings/generators/cpp_templates/struct_builder_definition b/mojo/public/bindings/generators/cpp_templates/struct_builder_definition
index 0e31319..0bc36d7 100644
--- a/mojo/public/bindings/generators/cpp_templates/struct_builder_definition
+++ b/mojo/public/bindings/generators/cpp_templates/struct_builder_definition
@@ -1,5 +1,5 @@
$CLASS::Builder::Builder(mojo::Buffer* buf)
- : data_(Data::New(buf)) {
+ : data_(Data::New(buf, $DTOR)) {
}
$CLASS $CLASS::Builder::Finish() {
diff --git a/mojo/public/bindings/generators/cpp_templates/struct_declaration b/mojo/public/bindings/generators/cpp_templates/struct_declaration
index 138028b..a780d65 100644
--- a/mojo/public/bindings/generators/cpp_templates/struct_declaration
+++ b/mojo/public/bindings/generators/cpp_templates/struct_declaration
@@ -2,7 +2,7 @@ class $CLASS {
public:
typedef $WRAPPER Wrapper;
- static $CLASS* New(mojo::Buffer* buf);
+ static $CLASS* New(mojo::Buffer* buf, mojo::Buffer::Destructor dtor = NULL);
$SETTERS
diff --git a/mojo/public/bindings/generators/cpp_templates/struct_definition b/mojo/public/bindings/generators/cpp_templates/struct_definition
index cbfebc5..e69d787 100644
--- a/mojo/public/bindings/generators/cpp_templates/struct_definition
+++ b/mojo/public/bindings/generators/cpp_templates/struct_definition
@@ -1,6 +1,6 @@
// static
-$CLASS* $CLASS::New(mojo::Buffer* buf) {
- return new (buf->Allocate(sizeof($CLASS))) $CLASS();
+$CLASS* $CLASS::New(mojo::Buffer* buf, mojo::Buffer::Destructor dtor) {
+ return new (buf->Allocate(sizeof($CLASS), dtor)) $CLASS();
}
$CLASS::$CLASS() {
diff --git a/mojo/public/bindings/generators/cpp_templates/struct_destructor b/mojo/public/bindings/generators/cpp_templates/struct_destructor
new file mode 100644
index 0000000..6b5e67e
--- /dev/null
+++ b/mojo/public/bindings/generators/cpp_templates/struct_destructor
@@ -0,0 +1,4 @@
+static void ${CLASS}_Data_Destructor(void* address) {
+ ${CLASS}_Data* data = static_cast<${CLASS}_Data*>(address);
+ $BODY
+}
diff --git a/mojo/public/bindings/generators/cpp_templates/struct_serialization b/mojo/public/bindings/generators/cpp_templates/struct_serialization
index 5b9d45d2..c321c82 100644
--- a/mojo/public/bindings/generators/cpp_templates/struct_serialization
+++ b/mojo/public/bindings/generators/cpp_templates/struct_serialization
@@ -7,8 +7,8 @@ $ENCODE_HANDLES
// static
bool ObjectTraits<$CLASS>::DecodePointersAndHandles(
- $CLASS* $NAME, const mojo::Message& message) {
+ $CLASS* $NAME, mojo::Message* message) {
$DECODES
$DECODE_HANDLES
return true;
-} \ No newline at end of file
+}
diff --git a/mojo/public/bindings/generators/cpp_templates/struct_serialization_definition b/mojo/public/bindings/generators/cpp_templates/struct_serialization_definition
index 1d688bb..b404276 100644
--- a/mojo/public/bindings/generators/cpp_templates/struct_serialization_definition
+++ b/mojo/public/bindings/generators/cpp_templates/struct_serialization_definition
@@ -10,7 +10,15 @@ $CLASS* ObjectTraits<$CLASS>::Clone(
$CLASS* clone = $CLASS::New(buf);
memcpy(clone, $NAME, sizeof(*$NAME));
$CLONES
+$HANDLE_RELEASES
return clone;
}
+// static
+void ObjectTraits<$CLASS>::CloseHandles(
+ $CLASS* $NAME) {
+$CLOSES
+$DTOR
+}
+
$SERIALIZATION
diff --git a/mojo/public/bindings/generators/cpp_templates/struct_serialization_traits b/mojo/public/bindings/generators/cpp_templates/struct_serialization_traits
index cbb739b..9975742 100644
--- a/mojo/public/bindings/generators/cpp_templates/struct_serialization_traits
+++ b/mojo/public/bindings/generators/cpp_templates/struct_serialization_traits
@@ -3,8 +3,9 @@ class ObjectTraits<$FULL_CLASS> {
public:
static size_t ComputeSizeOf(const $FULL_CLASS* $NAME);
static $FULL_CLASS* Clone(const $FULL_CLASS* $NAME, Buffer* buf);
+ static void CloseHandles($FULL_CLASS* $NAME);
static void EncodePointersAndHandles($FULL_CLASS* $NAME,
std::vector<mojo::Handle>* handles);
static bool DecodePointersAndHandles($FULL_CLASS* $NAME,
- const mojo::Message& message);
+ mojo::Message* message);
};
diff --git a/mojo/public/bindings/generators/cpp_templates/template_declaration b/mojo/public/bindings/generators/cpp_templates/template_declaration
index 9b923e4..fe9c82c 100644
--- a/mojo/public/bindings/generators/cpp_templates/template_declaration
+++ b/mojo/public/bindings/generators/cpp_templates/template_declaration
@@ -1,10 +1,12 @@
template <>
class ObjectTraits<$NAMESPACE::internal::$CLASS> {
public:
+ static void CloseHandles(
+ $NAMESPACE::internal::$CLASS* params);
static void EncodePointersAndHandles(
$NAMESPACE::internal::$CLASS* params,
std::vector<mojo::Handle>* handles);
static bool DecodePointersAndHandles(
$NAMESPACE::internal::$CLASS* params,
- const mojo::Message& message);
+ mojo::Message* message);
};
diff --git a/mojo/public/bindings/generators/mojom.py b/mojo/public/bindings/generators/mojom.py
index 658e2b5..84804dc 100644
--- a/mojo/public/bindings/generators/mojom.py
+++ b/mojo/public/bindings/generators/mojom.py
@@ -17,19 +17,20 @@ class Kind(object):
# Initialize the set of primitive types. These can be accessed by clients.
-BOOL = Kind('b')
-INT8 = Kind('i8')
-INT16 = Kind('i16')
-INT32 = Kind('i32')
-INT64 = Kind('i64')
-UINT8 = Kind('u8')
-UINT16 = Kind('u16')
-UINT32 = Kind('u32')
-UINT64 = Kind('u64')
-FLOAT = Kind('f')
-DOUBLE = Kind('d')
-STRING = Kind('s')
-HANDLE = Kind('h')
+BOOL = Kind('b')
+INT8 = Kind('i8')
+INT16 = Kind('i16')
+INT32 = Kind('i32')
+INT64 = Kind('i64')
+UINT8 = Kind('u8')
+UINT16 = Kind('u16')
+UINT32 = Kind('u32')
+UINT64 = Kind('u64')
+FLOAT = Kind('f')
+DOUBLE = Kind('d')
+STRING = Kind('s')
+HANDLE = Kind('h')
+MSGPIPE = Kind('h:m')
# Collection of all Primitive types
@@ -46,7 +47,8 @@ PRIMITIVES = (
FLOAT,
DOUBLE,
STRING,
- HANDLE
+ HANDLE,
+ MSGPIPE
)
diff --git a/mojo/public/bindings/generators/mojom_cpp_generator.py b/mojo/public/bindings/generators/mojom_cpp_generator.py
index 76e5930..354263e 100644
--- a/mojo/public/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/bindings/generators/mojom_cpp_generator.py
@@ -46,6 +46,8 @@ class CPPGenerator(mojom_generator.Generator):
Template(" +\n mojo::internal::ComputeSizeOf($NAME->$FIELD())")
struct_serialization_clone_template = Template(
" clone->set_$FIELD(mojo::internal::Clone($NAME->$FIELD(), buf));")
+ struct_serialization_handle_release_template = Template(
+ " (void) $NAME->$FIELD();")
struct_serialization_encode_template = Template(
" Encode(&$NAME->${FIELD}_, handles);")
struct_serialization_encode_handle_template = Template(
@@ -54,9 +56,16 @@ class CPPGenerator(mojom_generator.Generator):
" if (!Decode(&$NAME->${FIELD}_, message))\n"
" return false;")
struct_serialization_decode_handle_template = Template(
- " if (!DecodeHandle(&$NAME->${FIELD}_, message.handles))\n"
+ " if (!DecodeHandle(&$NAME->${FIELD}_, &message->handles))\n"
" return false;")
- param_set_template = Template(" params->set_$NAME($NAME);")
+ struct_destructor_body_template = Template(
+ "mojo::MakeScopedHandle(data->$FIELD());")
+ close_handles_template = Template(
+ " mojo::internal::CloseHandles($NAME->${FIELD}_.ptr);")
+ param_set_template = Template(
+ " params->set_$NAME($NAME);")
+ param_handle_set_template = Template(
+ " params->set_$NAME($NAME.release());")
param_struct_set_template = Template(
" params->set_$NAME(\n"
" mojo::internal::Clone(mojo::internal::Unwrap($NAME),\n"
@@ -66,6 +75,7 @@ class CPPGenerator(mojom_generator.Generator):
" mojo::internal::Unwrap($NAME));")
field_template = Template(" $TYPE ${FIELD}_;")
bool_field_template = Template(" uint8_t ${FIELD}_ : 1;")
+ handle_field_template = Template(" mutable $TYPE ${FIELD}_;")
setter_template = \
Template(" void set_$FIELD($TYPE $FIELD) { ${FIELD}_ = $FIELD; }")
ptr_setter_template = \
@@ -74,34 +84,44 @@ class CPPGenerator(mojom_generator.Generator):
Template(" $TYPE $FIELD() const { return ${FIELD}_; }")
ptr_getter_template = \
Template(" const $TYPE $FIELD() const { return ${FIELD}_.ptr; }")
+ handle_getter_template = \
+ Template(" $TYPE $FIELD() const { " \
+ "return mojo::internal::FetchAndReset(&${FIELD}_); }")
wrapper_setter_template = \
Template(" void set_$FIELD($TYPE $FIELD) { " \
"data_->set_$FIELD($FIELD); }")
wrapper_obj_setter_template = \
Template(" void set_$FIELD($TYPE $FIELD) { " \
"data_->set_$FIELD(mojo::internal::Unwrap($FIELD)); }")
+ wrapper_handle_setter_template = \
+ Template(" void set_$FIELD($TYPE $FIELD) { " \
+ "data_->set_$FIELD($FIELD.release()); }")
wrapper_getter_template = \
Template(" $TYPE $FIELD() const { return data_->$FIELD(); }")
wrapper_obj_getter_template = \
Template(" const $TYPE $FIELD() const { " \
"return mojo::internal::Wrap(data_->$FIELD()); }")
+ wrapper_handle_getter_template = \
+ Template(" $TYPE $FIELD() const { " \
+ "return mojo::MakeScopedHandle(data_->$FIELD()); }")
pad_template = Template(" uint8_t _pad${COUNT}_[$PAD];")
templates = {}
HEADER_SIZE = 8
kind_to_type = {
- mojom.BOOL: "bool",
- mojom.INT8: "int8_t",
- mojom.UINT8: "uint8_t",
- mojom.INT16: "int16_t",
- mojom.UINT16: "uint16_t",
- mojom.INT32: "int32_t",
- mojom.UINT32: "uint32_t",
- mojom.FLOAT: "float",
- mojom.HANDLE: "mojo::Handle",
- mojom.INT64: "int64_t",
- mojom.UINT64: "uint64_t",
- mojom.DOUBLE: "double",
+ mojom.BOOL: "bool",
+ mojom.INT8: "int8_t",
+ mojom.UINT8: "uint8_t",
+ mojom.INT16: "int16_t",
+ mojom.UINT16: "uint16_t",
+ mojom.INT32: "int32_t",
+ mojom.UINT32: "uint32_t",
+ mojom.FLOAT: "float",
+ mojom.HANDLE: "mojo::Handle",
+ mojom.MSGPIPE: "mojo::MessagePipeHandle",
+ mojom.INT64: "int64_t",
+ mojom.UINT64: "uint64_t",
+ mojom.DOUBLE: "double",
}
@classmethod
@@ -142,6 +162,8 @@ class CPPGenerator(mojom_generator.Generator):
subs = {'FIELD': field.name, 'TYPE': cls.GetType(field.kind)}
if mojom_generator.IsObjectKind(field.kind):
return cls.ptr_getter_template.substitute(subs)
+ elif mojom_generator.IsHandleKind(field.kind):
+ return cls.handle_getter_template.substitute(subs)
else:
return cls.getter_template.substitute(subs)
@@ -161,6 +183,10 @@ class CPPGenerator(mojom_generator.Generator):
return "mojo::Array<%s >" % cls.GetWrapperType(kind.kind)
if kind.spec == 's':
return "mojo::String"
+ if kind.spec == 'h':
+ return "mojo::ScopedHandle"
+ if kind.spec == 'h:m':
+ return "mojo::ScopedMessagePipeHandle"
return cls.kind_to_type[kind]
@classmethod
@@ -171,6 +197,10 @@ class CPPGenerator(mojom_generator.Generator):
return "const mojo::Array<%s >&" % cls.GetWrapperType(kind.kind)
if kind.spec == 's':
return "const mojo::String&"
+ if kind.spec == 'h':
+ return "mojo::ScopedHandle"
+ if kind.spec == 'h:m':
+ return "mojo::ScopedMessagePipeHandle"
return cls.kind_to_type[kind]
@classmethod
@@ -178,6 +208,8 @@ class CPPGenerator(mojom_generator.Generator):
subs = {'FIELD': field.name, 'TYPE': cls.GetWrapperType(field.kind)}
if mojom_generator.IsObjectKind(field.kind):
return cls.wrapper_obj_getter_template.substitute(subs)
+ elif mojom_generator.IsHandleKind(field.kind):
+ return cls.wrapper_handle_getter_template.substitute(subs)
else:
return cls.wrapper_getter_template.substitute(subs)
@@ -186,6 +218,8 @@ class CPPGenerator(mojom_generator.Generator):
subs = {'FIELD': field.name, 'TYPE': cls.GetConstWrapperType(field.kind)}
if mojom_generator.IsObjectKind(field.kind):
return cls.wrapper_obj_setter_template.substitute(subs)
+ elif mojom_generator.IsHandleKind(field.kind):
+ return cls.wrapper_handle_setter_template.substitute(subs)
else:
return cls.wrapper_setter_template.substitute(subs)
@@ -194,6 +228,9 @@ class CPPGenerator(mojom_generator.Generator):
kind = field.kind
if kind.spec == 'b':
return cls.bool_field_template.substitute(FIELD=field.name)
+ if mojom_generator.IsHandleKind(kind):
+ return cls.handle_field_template.substitute(FIELD=field.name,
+ TYPE=cls.kind_to_type[kind])
itype = None
if isinstance(kind, mojom.Struct):
itype = "mojo::internal::StructPointer<%s_Data>" % kind.name
@@ -210,6 +247,8 @@ class CPPGenerator(mojom_generator.Generator):
line = None
if mojom_generator.IsObjectKind(kind):
line = "mojo::internal::Wrap(params->%s())" % (name)
+ elif mojom_generator.IsHandleKind(kind):
+ line = "mojo::MakeScopedHandle(params->%s())" % (name)
else:
line = "params->%s()" % name
return line
@@ -240,10 +279,25 @@ class CPPGenerator(mojom_generator.Generator):
def GetHandleFields(cls, ps):
fields = []
for pf in ps.packed_fields:
- if pf.field.kind.spec == 'h':
+ if mojom_generator.IsHandleKind(pf.field.kind):
fields.append(pf.field)
return fields
+ @classmethod
+ def IsStructWithHandles(cls, struct):
+ for field in struct.fields:
+ if mojom_generator.IsHandleKind(field.kind):
+ return True
+ return False
+
+ @classmethod
+ def GetStructsWithHandles(cls, structs):
+ result = []
+ for struct in structs:
+ if cls.IsStructWithHandles(struct):
+ result.append(struct)
+ return result
+
def GetHeaderGuard(self, name):
return "MOJO_GENERATED_BINDINGS_%s_%s_H_" % \
(self.module.name.upper(), name.upper())
@@ -307,6 +361,7 @@ class CPPGenerator(mojom_generator.Generator):
def GetStructSerialization(
self, class_name, param_name, ps, template, indent = None):
struct = ps.struct
+ closes = Lines(self.close_handles_template, indent)
encodes = Lines(self.struct_serialization_encode_template, indent)
encode_handles = \
Lines(self.struct_serialization_encode_handle_template, indent)
@@ -319,6 +374,7 @@ class CPPGenerator(mojom_generator.Generator):
substitutions = {'NAME': param_name, 'FIELD': field.name}
encodes.Add(substitutions)
decodes.Add(substitutions)
+ closes.Add(substitutions)
for field in handle_fields:
substitutions = {'NAME': param_name, 'FIELD': field.name}
encode_handles.Add(substitutions)
@@ -327,6 +383,7 @@ class CPPGenerator(mojom_generator.Generator):
CLASS = \
"%s::internal::%s" % (self.module.namespace, class_name + '_Data'),
NAME = param_name,
+ CLOSES = closes,
ENCODES = encodes,
DECODES = decodes,
ENCODE_HANDLES = encode_handles,
@@ -435,10 +492,34 @@ class CPPGenerator(mojom_generator.Generator):
NUM_FIELDS = len(s.fields)),
self.module.structs));
+ def GetStructDestructorBody(self, struct):
+ body = Lines(self.struct_destructor_body_template)
+ for field in struct.fields:
+ if mojom_generator.IsHandleKind(field.kind):
+ body.Add(FIELD=field.name)
+ return body
+
+ def GetStructDestructors(self):
+ template = self.GetTemplate("struct_destructor")
+ return '\n'.join(map(
+ lambda s: template.substitute(
+ CLASS = s.name,
+ BODY = self.GetStructDestructorBody(s)),
+ self.GetStructsWithHandles(self.module.structs)));
+
+ def GetStructDestructorAddress(self, struct):
+ if self.IsStructWithHandles(struct):
+ return '&internal::' + struct.name + '_Data_Destructor';
+ return 'NULL'
+
def GetStructBuilderDefinitions(self):
template = self.GetTemplate("struct_builder_definition")
+ dtor = 'NULL'
return '\n'.join(map(
- lambda s: template.substitute(CLASS = s.name), self.module.structs));
+ lambda s: template.substitute(
+ CLASS = s.name,
+ DTOR = self.GetStructDestructorAddress(s)),
+ self.module.structs));
def GetInterfaceDefinition(self, interface):
cases = []
@@ -453,6 +534,9 @@ class CPPGenerator(mojom_generator.Generator):
sets.append(
self.param_struct_set_template.substitute(NAME=param.name))
computes.Add(NAME=param.name)
+ elif mojom_generator.IsHandleKind(param.kind):
+ sets.append(
+ self.param_handle_set_template.substitute(NAME=param.name))
else:
sets.append(self.param_set_template.substitute(NAME=param.name))
params_list = map(
@@ -487,7 +571,10 @@ class CPPGenerator(mojom_generator.Generator):
ps = mojom_pack.PackedStruct(struct)
param_name = mojom_generator.CamelToUnderscores(struct.name)
+ dtor = ''
+ closes = Lines(self.close_handles_template)
clones = Lines(self.struct_serialization_clone_template)
+ handle_releases = Lines(self.struct_serialization_handle_release_template)
sizes = " return sizeof(*%s)" % param_name
fields = self.GetSerializedFields(ps)
for field in fields:
@@ -495,6 +582,13 @@ class CPPGenerator(mojom_generator.Generator):
sizes += \
self.struct_serialization_compute_template.substitute(substitutions)
clones.Add(substitutions)
+ closes.Add(substitutions)
+ handle_fields = self.GetHandleFields(ps)
+ for field in handle_fields:
+ substitutions = {'NAME': param_name, 'FIELD': field.name}
+ handle_releases.Add(substitutions)
+ if len(handle_fields) > 0:
+ dtor = " %s_Data_Destructor(%s);" % (struct.name, param_name)
sizes += ";"
serialization = self.GetStructSerialization(
struct.name, param_name, ps, self.GetTemplate("struct_serialization"))
@@ -503,6 +597,9 @@ class CPPGenerator(mojom_generator.Generator):
CLASS = "%s::internal::%s_Data" % (self.module.namespace, struct.name),
SIZES = sizes,
CLONES = clones,
+ HANDLE_RELEASES = handle_releases,
+ CLOSES = closes,
+ DTOR = dtor,
SERIALIZATION = serialization)
def GetStructSerializationDefinitions(self):
@@ -537,6 +634,7 @@ class CPPGenerator(mojom_generator.Generator):
HEADER = self.GetHeaderFile(self.module.name),
PARAM_DEFINITIONS = self.GetParamsDefinitions(),
STRUCT_DEFINITIONS = self.GetStructDefinitions(),
+ STRUCT_DESTRUCTORS = self.GetStructDestructors(),
STRUCT_BUILDER_DEFINITIONS = self.GetStructBuilderDefinitions(),
INTERFACE_DEFINITIONS = self.GetInterfaceDefinitions(),
STRUCT_SERIALIZATION_DEFINITIONS =
diff --git a/mojo/public/bindings/generators/mojom_generator.py b/mojo/public/bindings/generators/mojom_generator.py
index 4320bbb..f2ee3e0 100644
--- a/mojo/public/bindings/generators/mojom_generator.py
+++ b/mojo/public/bindings/generators/mojom_generator.py
@@ -18,6 +18,9 @@ def GetStructFromMethod(interface, method):
def IsObjectKind(kind):
return isinstance(kind, (mojom.Struct, mojom.Array)) or kind.spec == 's'
+def IsHandleKind(kind):
+ return kind.spec.startswith('h')
+
def CamelToUnderscores(camel):
s = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', camel)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s).lower()
diff --git a/mojo/public/bindings/generators/mojom_js_generator.py b/mojo/public/bindings/generators/mojom_js_generator.py
index 2bfe9e8..82b9b8e 100644
--- a/mojo/public/bindings/generators/mojom_js_generator.py
+++ b/mojo/public/bindings/generators/mojom_js_generator.py
@@ -13,19 +13,20 @@ from functools import partial
from template_expander import UseJinja
_kind_to_default_value = {
- mojom.BOOL: "false",
- mojom.INT8: "0",
- mojom.UINT8: "0",
- mojom.INT16: "0",
- mojom.UINT16: "0",
- mojom.INT32: "0",
- mojom.UINT32: "0",
- mojom.FLOAT: "0",
- mojom.HANDLE: "core.kInvalidHandle",
- mojom.INT64: "0",
- mojom.UINT64: "0",
- mojom.DOUBLE: "0",
- mojom.STRING: '""',
+ mojom.BOOL: "false",
+ mojom.INT8: "0",
+ mojom.UINT8: "0",
+ mojom.INT16: "0",
+ mojom.UINT16: "0",
+ mojom.INT32: "0",
+ mojom.UINT32: "0",
+ mojom.FLOAT: "0",
+ mojom.HANDLE: "core.kInvalidHandle",
+ mojom.MSGPIPE: "core.kInvalidHandle",
+ mojom.INT64: "0",
+ mojom.UINT64: "0",
+ mojom.DOUBLE: "0",
+ mojom.STRING: '""',
}
@@ -51,19 +52,20 @@ def PayloadSize(packed):
_kind_to_javascript_type = {
- mojom.BOOL: "codec.Uint8",
- mojom.INT8: "codec.Int8",
- mojom.UINT8: "codec.Uint8",
- mojom.INT16: "codec.Int16",
- mojom.UINT16: "codec.Uint16",
- mojom.INT32: "codec.Int32",
- mojom.UINT32: "codec.Uint32",
- mojom.FLOAT: "codec.Float",
- mojom.HANDLE: "codec.Handle",
- mojom.INT64: "codec.Int64",
- mojom.UINT64: "codec.Uint64",
- mojom.DOUBLE: "codec.Double",
- mojom.STRING: "codec.String",
+ mojom.BOOL: "codec.Uint8",
+ mojom.INT8: "codec.Int8",
+ mojom.UINT8: "codec.Uint8",
+ mojom.INT16: "codec.Int16",
+ mojom.UINT16: "codec.Uint16",
+ mojom.INT32: "codec.Int32",
+ mojom.UINT32: "codec.Uint32",
+ mojom.FLOAT: "codec.Float",
+ mojom.HANDLE: "codec.Handle",
+ mojom.MSGPIPE: "codec.Handle",
+ mojom.INT64: "codec.Int64",
+ mojom.UINT64: "codec.Uint64",
+ mojom.DOUBLE: "codec.Double",
+ mojom.STRING: "codec.String",
}
@@ -78,19 +80,20 @@ def GetJavaScriptType(kind):
_kind_to_decode_snippet = {
- mojom.BOOL: "read8() & 1",
- mojom.INT8: "read8()",
- mojom.UINT8: "read8()",
- mojom.INT16: "read16()",
- mojom.UINT16: "read16()",
- mojom.INT32: "read32()",
- mojom.UINT32: "read32()",
- mojom.FLOAT: "decodeFloat()",
- mojom.HANDLE: "decodeHandle()",
- mojom.INT64: "read64()",
- mojom.UINT64: "read64()",
- mojom.DOUBLE: "decodeDouble()",
- mojom.STRING: "decodeStringPointer()",
+ mojom.BOOL: "read8() & 1",
+ mojom.INT8: "read8()",
+ mojom.UINT8: "read8()",
+ mojom.INT16: "read16()",
+ mojom.UINT16: "read16()",
+ mojom.INT32: "read32()",
+ mojom.UINT32: "read32()",
+ mojom.FLOAT: "decodeFloat()",
+ mojom.HANDLE: "decodeHandle()",
+ mojom.MSGPIPE: "decodeHandle()",
+ mojom.INT64: "read64()",
+ mojom.UINT64: "read64()",
+ mojom.DOUBLE: "decodeDouble()",
+ mojom.STRING: "decodeStringPointer()",
}
@@ -104,19 +107,20 @@ def DecodeSnippet(kind):
_kind_to_encode_snippet = {
- mojom.BOOL: "write8(1 & ",
- mojom.INT8: "write8(",
- mojom.UINT8: "write8(",
- mojom.INT16: "write16(",
- mojom.UINT16: "write16(",
- mojom.INT32: "write32(",
- mojom.UINT32: "write32(",
- mojom.FLOAT: "encodeFloat(",
- mojom.HANDLE: "encodeHandle(",
- mojom.INT64: "write64(",
- mojom.UINT64: "write64(",
- mojom.DOUBLE: "encodeDouble(",
- mojom.STRING: "encodeStringPointer(",
+ mojom.BOOL: "write8(1 & ",
+ mojom.INT8: "write8(",
+ mojom.UINT8: "write8(",
+ mojom.INT16: "write16(",
+ mojom.UINT16: "write16(",
+ mojom.INT32: "write32(",
+ mojom.UINT32: "write32(",
+ mojom.FLOAT: "encodeFloat(",
+ mojom.HANDLE: "encodeHandle(",
+ mojom.MSGPIPE: "encodeHandle(",
+ mojom.INT64: "write64(",
+ mojom.UINT64: "write64(",
+ mojom.DOUBLE: "encodeDouble(",
+ mojom.STRING: "encodeStringPointer(",
}
diff --git a/mojo/public/bindings/generators/mojom_pack.py b/mojo/public/bindings/generators/mojom_pack.py
index 7aea9c4..63b70a7 100644
--- a/mojo/public/bindings/generators/mojom_pack.py
+++ b/mojo/public/bindings/generators/mojom_pack.py
@@ -13,19 +13,20 @@ import mojom
class PackedField(object):
kind_to_size = {
- mojom.BOOL: 1,
- mojom.INT8: 1,
- mojom.UINT8: 1,
- mojom.INT16: 2,
- mojom.UINT16: 2,
- mojom.INT32: 4,
- mojom.UINT32: 4,
- mojom.FLOAT: 4,
- mojom.HANDLE: 4,
- mojom.INT64: 8,
- mojom.UINT64: 8,
- mojom.DOUBLE: 8,
- mojom.STRING: 8
+ mojom.BOOL: 1,
+ mojom.INT8: 1,
+ mojom.UINT8: 1,
+ mojom.INT16: 2,
+ mojom.UINT16: 2,
+ mojom.INT32: 4,
+ mojom.UINT32: 4,
+ mojom.FLOAT: 4,
+ mojom.HANDLE: 4,
+ mojom.MSGPIPE: 4,
+ mojom.INT64: 8,
+ mojom.UINT64: 8,
+ mojom.DOUBLE: 8,
+ mojom.STRING: 8
}
@classmethod
diff --git a/mojo/public/bindings/lib/bindings_internal.h b/mojo/public/bindings/lib/bindings_internal.h
index 2471240..1d5a24a 100644
--- a/mojo/public/bindings/lib/bindings_internal.h
+++ b/mojo/public/bindings/lib/bindings_internal.h
@@ -53,6 +53,13 @@ MOJO_COMPILE_ASSERT(sizeof(StringPointer) == 8, bad_sizeof_StringPointer);
#pragma pack(pop)
template <typename T>
+T FetchAndReset(T* value) {
+ T temp = *value;
+ *value = T();
+ return temp;
+}
+
+template <typename T>
class WrapperHelper {
public:
static const T Wrap(const typename T::Data* data) {
@@ -115,6 +122,9 @@ template <> struct TypeTraits<double> {
template <> struct TypeTraits<Handle> {
static const bool kIsObject = false;
};
+template <> struct TypeTraits<MessagePipeHandle> {
+ static const bool kIsObject = false;
+};
template <typename T>
struct ArrayDataTraits {
diff --git a/mojo/public/bindings/lib/bindings_serialization.cc b/mojo/public/bindings/lib/bindings_serialization.cc
index 952eac1..7b45b37 100644
--- a/mojo/public/bindings/lib/bindings_serialization.cc
+++ b/mojo/public/bindings/lib/bindings_serialization.cc
@@ -49,10 +49,11 @@ void EncodeHandle(Handle* handle, std::vector<Handle>* handles) {
handle->set_value(static_cast<MojoHandle>(handles->size() - 1));
}
-bool DecodeHandle(Handle* handle, const std::vector<Handle>& handles) {
- if (handle->value() >= handles.size())
+bool DecodeHandle(Handle* handle, std::vector<Handle>* handles) {
+ if (handle->value() >= handles->size())
return false;
- *handle = handles[handle->value()];
+ // Just leave holes in the vector so we don't screw up other indices.
+ *handle = FetchAndReset(&handles->at(handle->value()));
return true;
}
@@ -69,9 +70,9 @@ void ArrayHelper<Handle>::EncodePointersAndHandles(
bool ArrayHelper<Handle>::DecodePointersAndHandles(
const ArrayHeader* header,
ElementType* elements,
- const Message& message) {
+ Message* message) {
for (uint32_t i = 0; i < header->num_elements; ++i) {
- if (!DecodeHandle(&elements[i], message.handles))
+ if (!DecodeHandle(&elements[i], &message->handles))
return false;
}
return true;
diff --git a/mojo/public/bindings/lib/bindings_serialization.h b/mojo/public/bindings/lib/bindings_serialization.h
index ac08984..863aed4 100644
--- a/mojo/public/bindings/lib/bindings_serialization.h
+++ b/mojo/public/bindings/lib/bindings_serialization.h
@@ -39,7 +39,7 @@ bool ValidatePointer(const void* ptr, const Message& message);
// Handles are encoded as indices into a vector of handles. These functions
// manipulate the value of |handle|, mapping it to and from an index.
void EncodeHandle(Handle* handle, std::vector<Handle>* handles);
-bool DecodeHandle(Handle* handle, const std::vector<Handle>& handles);
+bool DecodeHandle(Handle* handle, std::vector<Handle>* handles);
// All objects (structs and arrays) support the following operations:
// - computing size
@@ -61,13 +61,19 @@ inline T* Clone(const T* obj, Buffer* buf) {
}
template <typename T>
+inline void CloseHandles(T* obj) {
+ if (obj)
+ ObjectTraits<T>::CloseHandles(obj);
+}
+
+template <typename T>
inline void EncodePointersAndHandles(T* obj,
std::vector<Handle>* handles) {
ObjectTraits<T>::EncodePointersAndHandles(obj, handles);
}
template <typename T>
-inline bool DecodePointersAndHandles(T* obj, const Message& message) {
+inline bool DecodePointersAndHandles(T* obj, Message* message) {
return ObjectTraits<T>::DecodePointersAndHandles(obj, message);
}
@@ -82,10 +88,10 @@ inline void Encode(T* obj, std::vector<Handle>* handles) {
}
template <typename T>
-inline bool Decode(T* obj, const Message& message) {
+inline bool Decode(T* obj, Message* message) {
DecodePointer(&obj->offset, &obj->ptr);
if (obj->ptr) {
- if (!ValidatePointer(obj->ptr, message))
+ if (!ValidatePointer(obj->ptr, *message))
return false;
if (!DecodePointersAndHandles(obj->ptr, message))
return false;
@@ -118,7 +124,7 @@ struct ArrayHelper {
}
static bool DecodePointersAndHandles(const ArrayHeader* header,
ElementType* elements,
- const Message& message) {
+ Message* message) {
return true;
}
};
@@ -142,7 +148,7 @@ struct ArrayHelper<Handle> {
std::vector<Handle>* handles);
static bool DecodePointersAndHandles(const ArrayHeader* header,
ElementType* elements,
- const Message& message);
+ Message* message);
};
template <typename P>
@@ -172,7 +178,7 @@ struct ArrayHelper<P*> {
}
static bool DecodePointersAndHandles(const ArrayHeader* header,
ElementType* elements,
- const Message& message) {
+ Message* message) {
for (uint32_t i = 0; i < header->num_elements; ++i) {
if (!Decode(&elements[i], message))
return false;
@@ -200,6 +206,10 @@ class ObjectTraits<Array_Data<T> > {
return clone;
}
+ static void CloseHandles(Array_Data<T>* array) {
+ // TODO(darin): Implement!
+ }
+
static void EncodePointersAndHandles(Array_Data<T>* array,
std::vector<Handle>* handles) {
ArrayHelper<T>::EncodePointersAndHandles(&array->header_, array->storage(),
@@ -207,7 +217,7 @@ class ObjectTraits<Array_Data<T> > {
}
static bool DecodePointersAndHandles(Array_Data<T>* array,
- const Message& message) {
+ Message* message) {
return ArrayHelper<T>::DecodePointersAndHandles(&array->header_,
array->storage(),
message);
diff --git a/mojo/public/bindings/lib/buffer.cc b/mojo/public/bindings/lib/buffer.cc
index eb40126..3265b80 100644
--- a/mojo/public/bindings/lib/buffer.cc
+++ b/mojo/public/bindings/lib/buffer.cc
@@ -45,6 +45,11 @@ ScratchBuffer::ScratchBuffer()
}
ScratchBuffer::~ScratchBuffer() {
+ // Invoke destructors in reverse order to mirror allocation order.
+ std::deque<PendingDestructor>::reverse_iterator it;
+ for (it = pending_dtors_.rbegin(); it != pending_dtors_.rend(); ++it)
+ it->func(it->address);
+
while (overflow_) {
Segment* doomed = overflow_;
overflow_ = overflow_->next;
@@ -52,21 +57,27 @@ ScratchBuffer::~ScratchBuffer() {
}
}
-void* ScratchBuffer::Allocate(size_t delta) {
+void* ScratchBuffer::Allocate(size_t delta, Destructor func) {
delta = internal::Align(delta);
void* result = AllocateInSegment(&fixed_, delta);
- if (result)
- return result;
-
- if (overflow_) {
- result = AllocateInSegment(overflow_, delta);
- if (result)
- return result;
+ if (!result) {
+ if (overflow_)
+ result = AllocateInSegment(overflow_, delta);
+
+ if (!result) {
+ AddOverflowSegment(delta);
+ result = AllocateInSegment(overflow_, delta);
+ }
}
- AddOverflowSegment(delta);
- return AllocateInSegment(overflow_, delta);
+ if (func) {
+ PendingDestructor dtor;
+ dtor.func = func;
+ dtor.address = result;
+ pending_dtors_.push_back(dtor);
+ }
+ return result;
}
void* ScratchBuffer::AllocateInSegment(Segment* segment, size_t delta) {
@@ -109,7 +120,9 @@ FixedBuffer::~FixedBuffer() {
free(ptr_);
}
-void* FixedBuffer::Allocate(size_t delta) {
+void* FixedBuffer::Allocate(size_t delta, Destructor dtor) {
+ assert(!dtor);
+
delta = internal::Align(delta);
// TODO(darin): Using <assert.h> is probably not going to cut it.
diff --git a/mojo/public/bindings/lib/buffer.h b/mojo/public/bindings/lib/buffer.h
index 37e76d2..6f0ce88 100644
--- a/mojo/public/bindings/lib/buffer.h
+++ b/mojo/public/bindings/lib/buffer.h
@@ -7,17 +7,22 @@
#include <stddef.h>
+#include <deque>
+
#include "mojo/public/system/macros.h"
namespace mojo {
-// Allocations are 8-byte aligned and zero-filled.
+// Buffer provides a way to allocate memory. Allocations are 8-byte aligned and
+// zero-initialized. Allocations remain valid for the lifetime of the Buffer.
class Buffer {
public:
+ typedef void (*Destructor)(void* address);
+
Buffer();
virtual ~Buffer();
- virtual void* Allocate(size_t num_bytes) = 0;
+ virtual void* Allocate(size_t num_bytes, Destructor func = NULL) = 0;
static Buffer* current();
@@ -34,7 +39,8 @@ class ScratchBuffer : public Buffer {
ScratchBuffer();
virtual ~ScratchBuffer();
- virtual void* Allocate(size_t num_bytes) MOJO_OVERRIDE;
+ virtual void* Allocate(size_t num_bytes, Destructor func = NULL)
+ MOJO_OVERRIDE;
private:
enum { kMinSegmentSize = 512 };
@@ -52,6 +58,12 @@ class ScratchBuffer : public Buffer {
Segment fixed_;
Segment* overflow_;
+ struct PendingDestructor {
+ Destructor func;
+ void* address;
+ };
+ std::deque<PendingDestructor> pending_dtors_;
+
MOJO_DISALLOW_COPY_AND_ASSIGN(ScratchBuffer);
};
@@ -87,7 +99,8 @@ class FixedBuffer : public Buffer {
// Grows the buffer by |num_bytes| and returns a pointer to the start of the
// addition. The resulting address is 8-byte aligned, and the content of the
// memory is zero-filled.
- virtual void* Allocate(size_t num_bytes) MOJO_OVERRIDE;
+ virtual void* Allocate(size_t num_bytes, Destructor func = NULL)
+ MOJO_OVERRIDE;
size_t size() const { return size_; }
diff --git a/mojo/public/bindings/lib/message.cc b/mojo/public/bindings/lib/message.cc
index c9eb38d..ba255d6 100644
--- a/mojo/public/bindings/lib/message.cc
+++ b/mojo/public/bindings/lib/message.cc
@@ -16,9 +16,12 @@ Message::Message()
Message::~Message() {
free(data);
- // TODO(davemoore): We don't close the handles because they're typically
- // owned by the Connection. This could result in some Handle leaks. This will
- // be fixed by a later cl.
+
+ for (std::vector<Handle>::iterator it = handles.begin(); it != handles.end();
+ ++it) {
+ if (it->is_valid())
+ CloseRaw(*it);
+ }
}
void Message::Swap(Message* other) {
diff --git a/mojo/public/bindings/mojom_bindings_generator.gypi b/mojo/public/bindings/mojom_bindings_generator.gypi
index 341e1a7..45efe76 100644
--- a/mojo/public/bindings/mojom_bindings_generator.gypi
+++ b/mojo/public/bindings/mojom_bindings_generator.gypi
@@ -32,6 +32,7 @@
'<(DEPTH)/mojo/public/bindings/generators/cpp_templates/proxy_implementation',
'<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_builder_definition',
'<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_declaration',
+ '<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_destructor',
'<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_definition',
'<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_serialization',
'<(DEPTH)/mojo/public/bindings/generators/cpp_templates/struct_serialization_definition',
diff --git a/mojo/public/bindings/parse/mojo_parser.py b/mojo/public/bindings/parse/mojo_parser.py
index 9bc9489..71bad65 100755
--- a/mojo/public/bindings/parse/mojo_parser.py
+++ b/mojo/public/bindings/parse/mojo_parser.py
@@ -51,6 +51,9 @@ class Lexer(object):
'ARRAY',
'ORDINAL',
+ 'MSGPIPE',
+ 'MSGPIPEARRAY',
+
'MODULE',
'STRUCT',
'INTERFACE',
@@ -81,6 +84,14 @@ class Lexer(object):
t_NUMBER = r'\d+'
t_ORDINAL = r'@[0-9]*'
+ def t_MSGPIPE(self, t):
+ r'handle<message_pipe>'
+ return t
+
+ def t_MSGPIPEARRAY(self, t):
+ r'handle<message_pipe>\[\]'
+ return t
+
def t_MODULE(self, t):
r'module'
return t
@@ -199,7 +210,9 @@ class Parser(object):
def p_typename(self, p):
"""typename : NAME
- | ARRAY"""
+ | ARRAY
+ | MSGPIPE
+ | MSGPIPEARRAY"""
p[0] = p[1]
def p_ordinal(self, p):
diff --git a/mojo/public/bindings/parse/mojo_translate.py b/mojo/public/bindings/parse/mojo_translate.py
index 472e1ce..8db79d8 100755
--- a/mojo/public/bindings/parse/mojo_translate.py
+++ b/mojo/public/bindings/parse/mojo_translate.py
@@ -23,7 +23,8 @@ def MapKind(kind):
'float': 'f',
'double': 'd',
'string': 's',
- 'handle': 'h' }
+ 'handle': 'h',
+ 'handle<message_pipe>': 'h:m' }
if kind.endswith('[]'):
return 'a:' + MapKind(kind[0:len(kind)-2])
if kind in map_to_kind:
diff --git a/mojo/public/bindings/sample/sample_service.mojom b/mojo/public/bindings/sample/sample_service.mojom
index 4251dd8..01b66ef 100644
--- a/mojo/public/bindings/sample/sample_service.mojom
+++ b/mojo/public/bindings/sample/sample_service.mojom
@@ -21,12 +21,12 @@ struct Foo {
Bar bar @5;
Bar[] extra_bars @7;
uint8[] data @6;
- handle[] files @9;
+ handle<message_pipe> source @9;
};
[Peer=ServiceClient]
interface Service {
- void Frobinate(Foo foo @0, bool baz @1, handle port @2) @0;
+ void Frobinate(Foo foo @0, bool baz @1, handle<message_pipe> port @2) @0;
};
[Peer=Service]
diff --git a/mojo/public/bindings/sample/sample_service_unittests.cc b/mojo/public/bindings/sample/sample_service_unittests.cc
index fc8d59a..51c7b49 100644
--- a/mojo/public/bindings/sample/sample_service_unittests.cc
+++ b/mojo/public/bindings/sample/sample_service_unittests.cc
@@ -54,9 +54,8 @@ Foo MakeFoo() {
for (size_t i = 0; i < data.size(); ++i)
data[i] = static_cast<uint8_t>(data.size() - i);
- mojo::Array<mojo::Handle>::Builder files(4);
- for (size_t i = 0; i < files.size(); ++i)
- files[i] = mojo::Handle(static_cast<MojoHandle>(0xFFFF - i));
+ mojo::ScopedMessagePipeHandle pipe0, pipe1;
+ mojo::CreateMessagePipe(&pipe0, &pipe1);
Foo::Builder foo;
foo.set_name(name);
@@ -68,7 +67,7 @@ Foo MakeFoo() {
foo.set_bar(bar.Finish());
foo.set_extra_bars(extra_bars.Finish());
foo.set_data(data.Finish());
- foo.set_files(files.Finish());
+ foo.set_source(pipe1.Pass());
return foo.Finish();
}
@@ -107,14 +106,8 @@ void CheckFoo(const Foo& foo) {
for (size_t i = 0; i < foo.data().size(); ++i) {
EXPECT_EQ(static_cast<uint8_t>(foo.data().size() - i), foo.data()[i]) << i;
}
-
- EXPECT_EQ(4u, foo.files().size());
- for (size_t i = 0; i < foo.files().size(); ++i)
- EXPECT_EQ(static_cast<MojoHandle>(0xFFFF - i),
- foo.files()[i].value()) << i;
}
-
static void PrintSpacer(int depth) {
for (int i = 0; i < depth; ++i)
printf(" ");
@@ -188,7 +181,6 @@ static void Print(int depth, const char* name, const Foo& foo) {
Print(depth, "bar", foo.bar());
Print(depth, "extra_bars", foo.extra_bars());
Print(depth, "data", foo.data());
- Print(depth, "files", foo.files());
--depth;
}
}
@@ -211,14 +203,14 @@ static void DumpHex(const uint8_t* bytes, uint32_t num_bytes) {
class ServiceImpl : public ServiceStub {
public:
- virtual void Frobinate(const Foo& foo, bool baz, mojo::Handle port)
+ virtual void Frobinate(const Foo& foo, bool baz,
+ mojo::ScopedMessagePipeHandle port)
MOJO_OVERRIDE {
// Users code goes here to handle the incoming Frobinate message.
// We mainly check that we're given the expected arguments.
CheckFoo(foo);
EXPECT_TRUE(baz);
- EXPECT_EQ(static_cast<MojoHandle>(10), port.value());
// Also dump the Foo structure and all of its members.
// TODO(vtl): Make it optional, so that the test spews less?
@@ -226,7 +218,7 @@ class ServiceImpl : public ServiceStub {
int depth = 1;
Print(depth, "foo", foo);
Print(depth, "baz", baz);
- Print(depth, "port", port);
+ Print(depth, "port", port.get());
}
};
@@ -267,9 +259,10 @@ TEST(BindingsSampleTest, Basic) {
Foo foo = MakeFoo();
CheckFoo(foo);
- mojo::Handle port(static_cast<MojoHandle>(10));
+ mojo::ScopedMessagePipeHandle port0, port1;
+ mojo::CreateMessagePipe(&port0, &port1);
- service->Frobinate(foo, true, port);
+ service->Frobinate(foo, true, port0.Pass());
}
} // namespace sample
diff --git a/mojo/public/bindings/sample/sample_service_unittests.js b/mojo/public/bindings/sample/sample_service_unittests.js
index 0adae31..9712f37 100644
--- a/mojo/public/bindings/sample/sample_service_unittests.js
+++ b/mojo/public/bindings/sample/sample_service_unittests.js
@@ -34,10 +34,7 @@ define([
data[i] = data.length - i;
}
- var files = new Array(4);
- for (var i = 0; i < files.length; ++i) {
- files[i] = 0xFFFF - i;
- }
+ var source = 0xFFFF; // Invent a dummy handle.
var foo = new sample.Foo();
foo.name = "foopy";
@@ -49,7 +46,7 @@ define([
foo.bar = bar;
foo.extra_bars = extra_bars;
foo.data = data;
- foo.files = files;
+ foo.source = source;
return foo;
}
@@ -77,9 +74,7 @@ define([
for (var i = 0; i < foo.data.length; ++i)
expect(foo.data[i]).toBe(foo.data.length - i);
- expect(foo.files.length).toBe(4);
- for (var i = 0; i < foo.files.length; ++i)
- expect(foo.files[i]).toBe(0xFFFF - i);
+ expect(foo.source).toBe(0xFFFF);
}
function ServiceImpl() {
diff --git a/mojo/public/system/core_cpp.h b/mojo/public/system/core_cpp.h
index 02ae4d5..3bc9349 100644
--- a/mojo/public/system/core_cpp.h
+++ b/mojo/public/system/core_cpp.h
@@ -25,6 +25,7 @@ class ScopedHandleBase {
public:
ScopedHandleBase() {}
+ explicit ScopedHandleBase(HandleType handle) : handle_(handle) {}
~ScopedHandleBase() { CloseIfNecessary(); }
// Move-only constructor and operator=.
@@ -66,6 +67,11 @@ class ScopedHandleBase {
HandleType handle_;
};
+template <typename HandleType>
+inline ScopedHandleBase<HandleType> MakeScopedHandle(HandleType handle) {
+ return ScopedHandleBase<HandleType>(handle);
+}
+
// Handle ----------------------------------------------------------------------
const MojoHandle kInvalidHandleValue = MOJO_HANDLE_INVALID;
diff --git a/mojo/public/tests/bindings_connector_unittest.cc b/mojo/public/tests/bindings_connector_unittest.cc
index 10de52c..47052ab 100644
--- a/mojo/public/tests/bindings_connector_unittest.cc
+++ b/mojo/public/tests/bindings_connector_unittest.cc
@@ -210,6 +210,8 @@ TEST_F(BindingsConnectorTest, MessageWithHandles) {
// TODO(vtl): Do we need a better way of "downcasting" the handle types?
ScopedMessagePipeHandle smph;
smph.reset(MessagePipeHandle(message_received.handles[0].value()));
+ message_received.handles[0] = Handle(); // |smph| now owns this handle.
+
Connector connector_received(smph.Pass());
Connector connector_original(handles[1].Pass());
diff --git a/mojo/public/tests/bindings_handle_passing_unittest.cc b/mojo/public/tests/bindings_handle_passing_unittest.cc
new file mode 100644
index 0000000..6ebc1bd
--- /dev/null
+++ b/mojo/public/tests/bindings_handle_passing_unittest.cc
@@ -0,0 +1,128 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/public/bindings/lib/remote_ptr.h"
+#include "mojo/public/tests/simple_bindings_support.h"
+#include "mojo/public/tests/test_support.h"
+#include "mojom/sample_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace test {
+namespace {
+
+const char kText1[] = "hello";
+const char kText2[] = "world";
+
+class SampleFactoryImpl : public sample::FactoryStub {
+ public:
+ explicit SampleFactoryImpl(ScopedMessagePipeHandle pipe)
+ : client_(pipe.Pass()) {
+ client_.SetPeer(this);
+ }
+
+ virtual void DoStuff(const sample::Request& request,
+ ScopedMessagePipeHandle pipe) MOJO_OVERRIDE {
+ std::string text1;
+ EXPECT_TRUE(ReadTextMessage(pipe.get(), &text1));
+
+ std::string text2;
+ EXPECT_TRUE(ReadTextMessage(request.pipe().get(), &text2));
+
+ ScopedMessagePipeHandle pipe0;
+ CreateMessagePipe(&pipe0, &pipe1_);
+
+ EXPECT_TRUE(WriteTextMessage(pipe1_.get(), text2));
+
+ AllocationScope scope;
+ sample::Response::Builder response;
+ response.set_x(2);
+ response.set_pipe(pipe0.Pass());
+ client_->DidStuff(response.Finish(), text1);
+ }
+
+ private:
+ RemotePtr<sample::FactoryClient> client_;
+ ScopedMessagePipeHandle pipe1_;
+};
+
+class SampleFactoryClientImpl : public sample::FactoryClientStub {
+ public:
+ explicit SampleFactoryClientImpl(ScopedMessagePipeHandle pipe)
+ : factory_(pipe.Pass()),
+ got_response_(false) {
+ factory_.SetPeer(this);
+ }
+
+ void Start() {
+ ScopedMessagePipeHandle pipe0;
+ CreateMessagePipe(&pipe0, &pipe1_);
+
+ EXPECT_TRUE(WriteTextMessage(pipe1_.get(), kText1));
+
+ ScopedMessagePipeHandle pipe2;
+ CreateMessagePipe(&pipe2, &pipe3_);
+
+ EXPECT_TRUE(WriteTextMessage(pipe3_.get(), kText2));
+
+ AllocationScope scope;
+ sample::Request::Builder request;
+ request.set_x(1);
+ request.set_pipe(pipe2.Pass());
+ factory_->DoStuff(request.Finish(), pipe0.Pass());
+ }
+
+ bool got_response() const {
+ return got_response_;
+ }
+
+ virtual void DidStuff(const sample::Response& response,
+ const String& text1) MOJO_OVERRIDE {
+ EXPECT_EQ(std::string(kText1), text1.To<std::string>());
+
+ std::string text2;
+ EXPECT_TRUE(ReadTextMessage(response.pipe().get(), &text2));
+ EXPECT_EQ(std::string(kText2), text2);
+
+ got_response_ = true;
+ }
+
+ private:
+ RemotePtr<sample::Factory> factory_;
+ ScopedMessagePipeHandle pipe1_;
+ ScopedMessagePipeHandle pipe3_;
+ bool got_response_;
+};
+
+} // namespace
+
+class BindingsHandlePassingTest : public testing::Test {
+ public:
+ void PumpMessages() {
+ bindings_support_.Process();
+ }
+
+ private:
+ SimpleBindingsSupport bindings_support_;
+};
+
+TEST_F(BindingsHandlePassingTest, Basic) {
+ ScopedMessagePipeHandle pipe0;
+ ScopedMessagePipeHandle pipe1;
+ CreateMessagePipe(&pipe0, &pipe1);
+
+ SampleFactoryImpl factory(pipe0.Pass());
+ SampleFactoryClientImpl factory_client(pipe1.Pass());
+
+ factory_client.Start();
+
+ EXPECT_FALSE(factory_client.got_response());
+
+ PumpMessages();
+
+ EXPECT_TRUE(factory_client.got_response());
+}
+
+} // namespace test
+} // namespace mojo
diff --git a/mojo/public/tests/sample_factory.mojom b/mojo/public/tests/sample_factory.mojom
new file mode 100644
index 0000000..7ae6b34
--- /dev/null
+++ b/mojo/public/tests/sample_factory.mojom
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module sample {
+
+// This sample shows how handles to MessagePipes can be sent as both parameters
+// to methods as well as fields on structs.
+
+struct Request {
+ int32 x;
+ handle<message_pipe> pipe;
+};
+
+struct Response {
+ int32 x;
+ handle<message_pipe> pipe;
+};
+
+[Peer=FactoryClient]
+interface Factory {
+ void DoStuff(Request request, handle<message_pipe> pipe);
+};
+
+[Peer=Factory]
+interface FactoryClient {
+ void DidStuff(Response response, string text);
+};
+
+} // module sample
diff --git a/mojo/public/tests/test_support.cc b/mojo/public/tests/test_support.cc
index 151fae3..81a0c3a2 100644
--- a/mojo/public/tests/test_support.cc
+++ b/mojo/public/tests/test_support.cc
@@ -10,6 +10,53 @@
namespace mojo {
namespace test {
+bool WriteTextMessage(MessagePipeHandle handle, const std::string& text) {
+ MojoResult rv = WriteMessageRaw(handle,
+ text.data(),
+ static_cast<uint32_t>(text.size()),
+ NULL,
+ 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE);
+ return rv == MOJO_RESULT_OK;
+}
+
+bool ReadTextMessage(MessagePipeHandle handle, std::string* text) {
+ MojoResult rv;
+ bool did_wait = false;
+
+ uint32_t num_bytes = 0, num_handles = 0;
+ for (;;) {
+ rv = ReadMessageRaw(handle,
+ NULL,
+ &num_bytes,
+ NULL,
+ &num_handles,
+ MOJO_READ_MESSAGE_FLAG_NONE);
+ if (rv == MOJO_RESULT_NOT_FOUND) {
+ if (did_wait) {
+ assert(false); // Looping endlessly!?
+ return false;
+ }
+ rv = Wait(handle, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE);
+ if (rv != MOJO_RESULT_OK)
+ return false;
+ did_wait = true;
+ } else {
+ assert(!num_handles);
+ break;
+ }
+ }
+
+ text->resize(num_bytes);
+ rv = ReadMessageRaw(handle,
+ &text->at(0),
+ &num_bytes,
+ NULL,
+ &num_handles,
+ MOJO_READ_MESSAGE_FLAG_NONE);
+ return rv == MOJO_RESULT_OK;
+}
+
void IterateAndReportPerf(const char* test_name,
base::Callback<void()> single_iteration) {
// TODO(vtl): These should be specifiable using command-line flags.
diff --git a/mojo/public/tests/test_support.h b/mojo/public/tests/test_support.h
index bddd7a0..9c144a3 100644
--- a/mojo/public/tests/test_support.h
+++ b/mojo/public/tests/test_support.h
@@ -5,11 +5,17 @@
#ifndef MOJO_PUBLIC_TESTS_TEST_SUPPORT_H_
#define MOJO_PUBLIC_TESTS_TEST_SUPPORT_H_
+#include <string>
+
#include "base/callback.h"
+#include "mojo/public/system/core_cpp.h"
namespace mojo {
namespace test {
+bool WriteTextMessage(MessagePipeHandle handle, const std::string& text);
+bool ReadTextMessage(MessagePipeHandle handle, std::string* text);
+
// Run |single_iteration| an appropriate number of times and report its
// performance appropriately. (This actually runs |single_iteration| for a fixed
// amount of time and reports the number of iterations per unit time.)
diff --git a/mojo/services/native_viewport/native_viewport.mojom b/mojo/services/native_viewport/native_viewport.mojom
index bd43b93..caae29a 100644
--- a/mojo/services/native_viewport/native_viewport.mojom
+++ b/mojo/services/native_viewport/native_viewport.mojom
@@ -8,7 +8,7 @@ module mojo {
interface NativeViewport {
void Open();
void Close();
- void CreateGLES2Context(handle gles2_client);
+ void CreateGLES2Context(handle<message_pipe> gles2_client);
};
[Peer=NativeViewport]
diff --git a/mojo/services/native_viewport/native_viewport_impl.cc b/mojo/services/native_viewport/native_viewport_impl.cc
index 80c1afa..bce78e3 100644
--- a/mojo/services/native_viewport/native_viewport_impl.cc
+++ b/mojo/services/native_viewport/native_viewport_impl.cc
@@ -35,10 +35,9 @@ void NativeViewportImpl::Close() {
native_viewport_->Close();
}
-void NativeViewportImpl::CreateGLES2Context(mojo::Handle gles2_client) {
- ScopedMessagePipeHandle handle;
- handle.reset(MessagePipeHandle(gles2_client.value()));
- gles2_.reset(new GLES2Impl(handle.Pass()));
+void NativeViewportImpl::CreateGLES2Context(
+ ScopedMessagePipeHandle gles2_client) {
+ gles2_.reset(new GLES2Impl(gles2_client.Pass()));
CreateGLES2ContextIfNeeded();
}
diff --git a/mojo/services/native_viewport/native_viewport_impl.h b/mojo/services/native_viewport/native_viewport_impl.h
index 9a90d91..332105e 100644
--- a/mojo/services/native_viewport/native_viewport_impl.h
+++ b/mojo/services/native_viewport/native_viewport_impl.h
@@ -29,7 +29,8 @@ class NativeViewportImpl : public NativeViewportStub,
virtual void Open() OVERRIDE;
virtual void Close() OVERRIDE;
- virtual void CreateGLES2Context(mojo::Handle gles2_client) OVERRIDE;
+ virtual void CreateGLES2Context(
+ ScopedMessagePipeHandle gles2_client) OVERRIDE;
private:
// Overridden from services::NativeViewportDelegate: