-
-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathSetTimeout.cpp
More file actions
106 lines (84 loc) · 3.15 KB
/
SetTimeout.cpp
File metadata and controls
106 lines (84 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <dispatch/dispatch.h>
#include "SetTimeout.h"
#include "Helpers.h"
#include "Caches.h"
using namespace v8;
namespace tns {
void SetTimeout::Init(Isolate* isolate, Local<ObjectTemplate> globalTemplate) {
Local<FunctionTemplate> setTimeoutFuncTemplate = FunctionTemplate::New(isolate, SetTimeoutCallback);
globalTemplate->Set(ToV8String(isolate, "setTimeout"), setTimeoutFuncTemplate);
Local<FunctionTemplate> clearTimeoutFuncTemplate = FunctionTemplate::New(isolate, ClearTimeoutCallback);
globalTemplate->Set(ToV8String(isolate, "clearTimeout"), clearTimeoutFuncTemplate);
}
void SetTimeout::SetTimeoutCallback(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (!args[0]->IsFunction()) {
tns::Assert(false, isolate);
}
Local<Context> context = isolate->GetCurrentContext();
double timeout = 0.0;
if (args.Length() > 1 && args[1]->IsNumber()) {
if (!args[1]->NumberValue(context).To(&timeout)) {
tns::Assert(false, isolate);
}
}
// TODO: implement better unique number generator
uint32_t key = ++count_;
Local<v8::Function> callback = args[0].As<v8::Function>();
dispatch_block_t block = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{ Elapsed(key); });
CacheEntry entry(isolate, new Persistent<v8::Function>(isolate, callback));
cache_.emplace(key, entry);
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, timeout * NSEC_PER_MSEC);
dispatch_after(time, dispatch_get_main_queue(), block);
args.GetReturnValue().Set(key);
}
void SetTimeout::ClearTimeoutCallback(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (!args[0]->IsNumber()) {
tns::Assert(false, isolate);
}
Local<Context> context = isolate->GetCurrentContext();
double value;
if (!args[0]->NumberValue(context).To(&value)) {
tns::Assert(false, isolate);
}
uint32_t key = value;
auto it = cache_.find(key);
if (it == cache_.end()) {
return;
}
RemoveKey(key);
}
void SetTimeout::Elapsed(const uint32_t key) {
auto it = cache_.find(key);
if (it == cache_.end()) {
return;
}
Isolate* isolate = it->second.isolate_;
Persistent<v8::Function>* poCallback = it->second.callback_;
v8::Locker locker(isolate);
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
Local<v8::Function> cb = poCallback->Get(isolate);
std::shared_ptr<Caches> cache = Caches::Get(isolate);
Local<Context> context = cache->GetContext();
Local<Object> global = context->Global();
Local<Value> result;
if (!cb->Call(context, global, 0, nullptr).ToLocal(&result)) {
tns::Assert(false, isolate);
}
RemoveKey(key);
}
void SetTimeout::RemoveKey(const uint32_t key) {
auto it = cache_.find(key);
if (it == cache_.end()) {
return;
}
Persistent<v8::Function>* poCallback = it->second.callback_;
poCallback->Reset();
delete poCallback;
cache_.erase(it);
}
robin_hood::unordered_map<uint32_t, SetTimeout::CacheEntry> SetTimeout::cache_;
uint32_t SetTimeout::count_ = 0;
}