Chromium Code Reviews| Index: runtime/vm/service.cc |
| diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc |
| index 7596e7aab7f683d8eeaaef25bc719fbc61f5ee18..d03972277002490a83c384a080486eee3dc0a1cc 100644 |
| --- a/runtime/vm/service.cc |
| +++ b/runtime/vm/service.cc |
| @@ -104,6 +104,45 @@ class Resources { |
| }; |
| +class EmbedderServiceHandler { |
| + public: |
| + explicit EmbedderServiceHandler(const char* name) : name_(NULL), |
| + callback_(NULL), |
| + user_data_(NULL), |
| + next_(NULL) { |
| + ASSERT(name != NULL); |
| + name_ = strdup(name); |
| + } |
| + |
| + ~EmbedderServiceHandler() { |
| + free(name_); |
| + } |
| + |
| + const char* name() const { return name_; } |
| + |
| + Dart_ServiceRequestCallback callback() const { return callback_; } |
| + void set_callback(Dart_ServiceRequestCallback callback) { |
| + callback_ = callback; |
| + } |
| + |
| + void* user_data() const { return user_data_; } |
| + void set_user_data(void* user_data) { |
| + user_data_ = user_data; |
| + } |
| + |
| + EmbedderServiceHandler* next() const { return next_; } |
| + void set_next(EmbedderServiceHandler* next) { |
| + next_ = next; |
| + } |
| + |
| + private: |
| + char* name_; |
| + Dart_ServiceRequestCallback callback_; |
| + void* user_data_; |
| + EmbedderServiceHandler* next_; |
| +}; |
| + |
| + |
| static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { |
| void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); |
| return reinterpret_cast<uint8_t*>(new_ptr); |
| @@ -186,10 +225,13 @@ static Dart_NativeFunction VmServiceNativeResolver(Dart_Handle name, |
| } |
| +EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL; |
| +EmbedderServiceHandler* Service::root_service_handler_head_ = NULL; |
| Isolate* Service::service_isolate_ = NULL; |
| Dart_LibraryTagHandler Service::default_handler_ = NULL; |
| Dart_Port Service::port_ = ILLEGAL_PORT; |
| + |
| static Dart_Port ExtractPort(Dart_Handle receivePort) { |
| HANDLESCOPE(Isolate::Current()); |
| const Object& unwrapped_rp = Object::Handle(Api::UnwrapHandle(receivePort)); |
| @@ -524,16 +566,29 @@ void Service::HandleIsolateMessage(Isolate* isolate, const Instance& msg) { |
| IsolateMessageHandler handler = |
| FindIsolateMessageHandler(path_segment_c); |
| + if (handler == NULL) { |
| + // Check for an embedder handler. |
| + EmbedderServiceHandler* e_handler = |
| + FindIsolateEmbedderHandler(path_segment_c); |
| + if (e_handler != NULL) { |
| + JSONStream js; |
| + js.Setup(zone.GetZone(), reply_port, path, option_keys, option_values); |
| + EmbedderHandleMessage(e_handler, &js); |
| + // TODO(johnmccutchan): Support asynchronous replies. |
| + js.PostReply(); |
| + return; |
| + } |
| + } |
| { |
| JSONStream js; |
| js.Setup(zone.GetZone(), reply_port, path, option_keys, option_values); |
| - |
| if (handler == NULL) { |
|
turnidge
2014/02/18 22:25:12
What if you moved the EmbedderServiceHandler looku
Cutch
2014/02/18 22:34:10
Done and it does!
|
| PrintError(&js, "Unrecognized path"); |
| js.PostReply(); |
| } else { |
| if (handler(isolate, &js)) { |
| // Handler returns true if the reply is ready to be posted. |
| + // TODO(johnmccutchan): Support asynchronous replies. |
|
turnidge
2014/02/18 22:25:12
Do we need this TODO here?
Cutch
2014/02/18 22:34:10
Done.
|
| js.PostReply(); |
| } |
| } |
| @@ -1096,12 +1151,29 @@ void Service::HandleRootMessage(const Instance& msg) { |
| ASSERT(option_keys.Length() == option_values.Length()); |
| String& path_segment = String::Handle(); |
| - path_segment ^= path.At(0); |
| + if (path.Length() > 0) { |
| + path_segment ^= path.At(0); |
| + } else { |
| + path_segment ^= Symbols::Empty().raw(); |
| + } |
| ASSERT(!path_segment.IsNull()); |
| const char* path_segment_c = path_segment.ToCString(); |
| + |
| RootMessageHandler handler = |
| FindRootMessageHandler(path_segment_c); |
| - |
| + if (handler == NULL) { |
| + // Check for an embedder handler. |
| + EmbedderServiceHandler* e_handler = |
| + FindRootEmbedderHandler(path_segment_c); |
| + if (e_handler != NULL) { |
| + JSONStream js; |
| + js.Setup(zone.GetZone(), reply_port, path, option_keys, option_values); |
| + EmbedderHandleMessage(e_handler, &js); |
| + // TODO(johnmccutchan): Support asynchronous replies. |
| + js.PostReply(); |
| + return; |
| + } |
| + } |
| { |
| JSONStream js; |
| js.Setup(zone.GetZone(), reply_port, path, option_keys, option_values); |
| @@ -1111,6 +1183,7 @@ void Service::HandleRootMessage(const Instance& msg) { |
| } else { |
| if (handler(&js)) { |
| // Handler returns true if the reply is ready to be posted. |
| + // TODO(johnmccutchan): Support asynchronous replies. |
| js.PostReply(); |
| } |
| } |
| @@ -1156,4 +1229,100 @@ static RootMessageHandler FindRootMessageHandler(const char* command) { |
| return NULL; |
| } |
| + |
| +void Service::EmbedderHandleMessage(EmbedderServiceHandler* handler, |
| + JSONStream* js) { |
| + ASSERT(handler != NULL); |
| + Dart_ServiceRequestCallback callback = handler->callback(); |
| + ASSERT(callback != NULL); |
| + const char* r = NULL; |
| + const char* name = js->command(); |
| + const char** arguments = js->arguments(); |
| + const char** keys = js->option_keys(); |
| + const char** values = js->option_values(); |
| + r = callback(name, arguments, js->num_arguments(), keys, values, |
| + js->num_options(), handler->user_data()); |
| + ASSERT(r != NULL); |
| + // TODO(johnmccutchan): Allow for NULL returns? |
| + TextBuffer* buffer = js->buffer(); |
| + buffer->AddString(r); |
| + free(const_cast<char*>(r)); |
| +} |
| + |
| + |
| +void Service::RegisterIsolateEmbedderCallback( |
| + const char* name, |
| + Dart_ServiceRequestCallback callback, |
| + void* user_data) { |
| + if (name == NULL) { |
| + return; |
| + } |
| + EmbedderServiceHandler* handler = FindIsolateEmbedderHandler(name); |
| + if (handler != NULL) { |
| + // Update existing handler entry. |
| + handler->set_callback(callback); |
| + handler->set_user_data(user_data); |
| + return; |
| + } |
| + // Create a new handler. |
| + handler = new EmbedderServiceHandler(name); |
| + handler->set_callback(callback); |
| + handler->set_user_data(user_data); |
| + |
| + // Insert into isolate_service_handler_head_ list. |
| + handler->set_next(isolate_service_handler_head_); |
| + isolate_service_handler_head_ = handler; |
| +} |
| + |
| + |
| +EmbedderServiceHandler* Service::FindIsolateEmbedderHandler( |
| + const char* name) { |
| + EmbedderServiceHandler* current = isolate_service_handler_head_; |
| + while (current != NULL) { |
| + if (!strcmp(name, current->name())) { |
| + return current; |
| + } |
| + current = current->next(); |
| + } |
| + return NULL; |
| +} |
| + |
| + |
| +void Service::RegisterRootEmbedderCallback( |
| + const char* name, |
| + Dart_ServiceRequestCallback callback, |
| + void* user_data) { |
| + if (name == NULL) { |
| + return; |
| + } |
| + EmbedderServiceHandler* handler = FindRootEmbedderHandler(name); |
| + if (handler != NULL) { |
| + // Update existing handler entry. |
| + handler->set_callback(callback); |
| + handler->set_user_data(user_data); |
| + return; |
| + } |
| + // Create a new handler. |
| + handler = new EmbedderServiceHandler(name); |
| + handler->set_callback(callback); |
| + handler->set_user_data(user_data); |
| + |
| + // Insert into root_service_handler_head_ list. |
| + handler->set_next(root_service_handler_head_); |
| + root_service_handler_head_ = handler; |
| +} |
| + |
| + |
| +EmbedderServiceHandler* Service::FindRootEmbedderHandler( |
| + const char* name) { |
| + EmbedderServiceHandler* current = root_service_handler_head_; |
| + while (current != NULL) { |
| + if (!strcmp(name, current->name())) { |
| + return current; |
| + } |
| + current = current->next(); |
| + } |
| + return NULL; |
| +} |
| + |
| } // namespace dart |