diff options
author | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-04 05:58:58 +0000 |
---|---|---|
committer | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-04 05:58:58 +0000 |
commit | 82f8b0f47d58226fe5dc8951637c9f614c2d6545 (patch) | |
tree | aff46e1aebb7288a8feb975890fa21bca5d2e312 /mojo | |
parent | e9476cd6510e31d114e4de13e01bb54e317d2168 (diff) | |
download | chromium_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')
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: |