-
-
Notifications
You must be signed in to change notification settings - Fork 136
/
Copy pathTimers.h
136 lines (113 loc) · 4.57 KB
/
Timers.h
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#ifndef TEST_APP_TIMERS_H
#define TEST_APP_TIMERS_H
#include <android/looper.h>
#include "v8.h"
#include "ObjectManager.h"
#include "condition_variable"
#include "thread"
#include "robin_hood.h"
namespace tns {
/**
* A Timer Task
* this class is used to store the persistent values and context
* once Unschedule is called everything is released
*/
class TimerTask {
public:
inline TimerTask(v8::Isolate *isolate, const v8::Local<v8::Context> &context,
const v8::Local<v8::Function> &callback, double frequency,
bool repeats,
const std::shared_ptr<std::vector<std::shared_ptr<v8::Persistent<v8::Value>>>> &args,
int id, double startTime)
: isolate_(isolate), callback_(isolate, callback),
frequency_(frequency), repeats_(repeats), args_(args), id_(id),
startTime_(startTime) {
}
inline double NextTime(double targetTime) {
if (frequency_ <= 0) {
return targetTime;
}
auto timeDiff = targetTime - startTime_;
auto div = std::div((long) timeDiff, (long) frequency_);
return startTime_ + frequency_ * (div.quot + 1);
}
inline void Unschedule() {
callback_.Reset();
args_.reset();
isolate_ = nullptr;
queued_ = false;
}
int nestingLevel_ = 0;
v8::Isolate *isolate_;
v8::Persistent<v8::Function> callback_;
std::shared_ptr<std::vector<std::shared_ptr<v8::Persistent<v8::Value>>>> args_;
bool repeats_ = false;
/**
* this helper parameter is used in the following way:
* task scheduled means queued_ = true
* this is set to false right before the callback is executed
* if this is false then it's not on the background thread queue
*/
bool queued_ = false;
double frequency_ = 0;
double dueTime_ = -1;
double startTime_ = -1;
int id_;
};
struct TimerReference {
int id;
double dueTime;
};
class Timers {
public:
/**
* Initializes the global functions setTimeout, setInterval, clearTimeout and clearInterval
* also creates helper threads and binds the timers to the executing thread
* @param isolate target isolate
* @param globalObjectTemplate global template
*/
void Init(v8::Isolate *isolate, v8::Local<v8::ObjectTemplate> &globalObjectTemplate);
static void InitStatic(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate> globalObjectTemplate);
/**
* Disposes the timers. This will clear all references and stop all thread.
* MUST be called in the same thread Init was called
* This methods blocks until the threads are stopped.
* This method doesn't need to be called most of the time as it's called on object destruction
* Reusing this class is not advised
*/
void Destroy();
/**
* Calls Destruct
*/
~Timers();
private:
static void SetTimeoutCallback(const v8::FunctionCallbackInfo<v8::Value> &args);
static void SetIntervalCallback(const v8::FunctionCallbackInfo<v8::Value> &args);
static void SetTimer(const v8::FunctionCallbackInfo<v8::Value> &args, bool repeatable);
static void ClearTimer(const v8::FunctionCallbackInfo<v8::Value> &args);
void threadLoop();
static int PumpTimerLoopCallback(int fd, int events, void *data);
void addTask(std::shared_ptr<TimerTask> task);
void removeTask(const std::shared_ptr<TimerTask> &task);
void removeTask(const int &taskId);
v8::Isolate *isolate_ = nullptr;
ALooper *looper_;
int currentTimerId = 0;
int nesting = 0;
// stores the map of timer tasks
robin_hood::unordered_map<int, std::shared_ptr<TimerTask>> timerMap_;
std::vector<std::shared_ptr<TimerReference>> sortedTimers_;
// sets are faster than vector iteration
// so we use this to avoid redundant isolate locks and we don't care about the
// background thread lost cycles
std::set<int> deletedTimers_;
int fd_[2];
std::atomic_bool isBufferFull = ATOMIC_VAR_INIT(false);
std::condition_variable taskReady;
std::condition_variable bufferFull;
std::mutex mutex;
std::thread watcher_;
bool stopped = false;
};
}
#endif //TEST_APP_TIMERS_H