diff --git a/atom/common/api/atom_bindings.cc b/atom/common/api/atom_bindings.cc index fcb65e73969d..3f274cc1c11e 100644 --- a/atom/common/api/atom_bindings.cc +++ b/atom/common/api/atom_bindings.cc @@ -4,6 +4,7 @@ #include "atom/common/api/atom_bindings.h" +#include #include #include "atom/common/atom_version.h" @@ -18,9 +19,6 @@ namespace atom { namespace { -// Async handle to wake up uv loop. -uv_async_t g_next_tick_uv_handle; - // Async handle to execute the stored v8 callback. uv_async_t g_callback_uv_handle; @@ -30,25 +28,6 @@ base::Closure g_v8_callback; // Dummy class type that used for crashing the program. struct DummyClass { bool crash; }; -// Async handler to call next process.nextTick callbacks. -void UvCallNextTick(uv_async_t* handle) { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - node::Environment* env = node::Environment::GetCurrent(isolate); - node::Environment::TickInfo* tick_info = env->tick_info(); - - if (tick_info->in_tick()) - return; - - if (tick_info->length() == 0) { - tick_info->set_index(0); - return; - } - - tick_info->set_in_tick(true); - env->tick_callback_function()->Call(env->process_object(), 0, NULL); - tick_info->set_in_tick(false); -} - // Async handler to execute the stored v8 callback. void UvOnCallback(uv_async_t* handle) { g_v8_callback.Run(); @@ -65,10 +44,6 @@ void FatalErrorCallback(const char* location, const char* message) { Crash(); } -void ActivateUVLoop() { - uv_async_send(&g_next_tick_uv_handle); -} - void Log(const base::string16& message) { logging::LogMessage("CONSOLE", 0, 0).stream() << message; } @@ -82,7 +57,9 @@ void ScheduleCallback(const base::Closure& callback) { AtomBindings::AtomBindings() { - uv_async_init(uv_default_loop(), &g_next_tick_uv_handle, UvCallNextTick); + uv_async_init(uv_default_loop(), &call_next_tick_async_, OnCallNextTick); + call_next_tick_async_.data = this; + uv_async_init(uv_default_loop(), &g_callback_uv_handle, UvOnCallback); v8::V8::SetFatalErrorHandler(FatalErrorCallback); } @@ -94,9 +71,10 @@ void AtomBindings::BindTo(v8::Isolate* isolate, v8::Handle process) { mate::Dictionary dict(isolate, process); dict.SetMethod("crash", &Crash); - dict.SetMethod("activateUvLoop", &ActivateUVLoop); dict.SetMethod("log", &Log); dict.SetMethod("scheduleCallback", &ScheduleCallback); + dict.SetMethod("activateUvLoop", + base::Bind(&AtomBindings::ActivateUVLoop, base::Unretained(this))); v8::Handle versions; if (dict.Get("versions", &versions)) @@ -104,4 +82,40 @@ void AtomBindings::BindTo(v8::Isolate* isolate, mate::StringToV8(isolate, ATOM_VERSION_STRING)); } +void AtomBindings::ActivateUVLoop(v8::Isolate* isolate) { + node::Environment* env = node::Environment::GetCurrent(isolate); + if (std::find(pending_next_ticks_.begin(), pending_next_ticks_.end(), env) != + pending_next_ticks_.end()) + return; + + pending_next_ticks_.push_back(env); + uv_async_send(&call_next_tick_async_); +} + +// static +void AtomBindings::OnCallNextTick(uv_async_t* handle) { + AtomBindings* self = static_cast(handle->data); + for (std::list::const_iterator it = + self->pending_next_ticks_.begin(); + it != self->pending_next_ticks_.end(); ++it) { + node::Environment* env = *it; + node::Environment::TickInfo* tick_info = env->tick_info(); + + v8::Context::Scope context_scope(env->context()); + if (tick_info->in_tick()) + continue; + + if (tick_info->length() == 0) { + tick_info->set_index(0); + continue; + } + + tick_info->set_in_tick(true); + env->tick_callback_function()->Call(env->process_object(), 0, NULL); + tick_info->set_in_tick(false); + } + + self->pending_next_ticks_.clear(); +} + } // namespace atom diff --git a/atom/common/api/atom_bindings.h b/atom/common/api/atom_bindings.h index fadb535848f2..807ffcfc1cce 100644 --- a/atom/common/api/atom_bindings.h +++ b/atom/common/api/atom_bindings.h @@ -5,8 +5,15 @@ #ifndef ATOM_COMMON_API_ATOM_BINDINGS_H_ #define ATOM_COMMON_API_ATOM_BINDINGS_H_ +#include + #include "base/strings/string16.h" #include "v8/include/v8.h" +#include "vendor/node/deps/uv/include/uv.h" + +namespace node { +class Environment; +} namespace atom { @@ -20,6 +27,13 @@ class AtomBindings { virtual void BindTo(v8::Isolate* isolate, v8::Handle process); private: + void ActivateUVLoop(v8::Isolate* isolate); + + static void OnCallNextTick(uv_async_t* handle); + + uv_async_t call_next_tick_async_; + std::list pending_next_ticks_; + DISALLOW_COPY_AND_ASSIGN(AtomBindings); };