1 #ifndef SRC_NODE_PLATFORM_H_
2 #define SRC_NODE_PLATFORM_H_
3 
4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5 
6 #include <queue>
7 #include <unordered_map>
8 #include <vector>
9 #include <functional>
10 
11 #include "libplatform/libplatform.h"
12 #include "node.h"
13 #include "node_mutex.h"
14 #include "tracing/agent.h"
15 #include "uv.h"
16 
17 namespace node {
18 
19 class NodePlatform;
20 class IsolateData;
21 class PerIsolatePlatformData;
22 
23 template <class T>
24 class TaskQueue {
25  public:
26   TaskQueue();
~TaskQueue()27   ~TaskQueue() {}
28 
29   void Push(std::unique_ptr<T> task);
30   std::unique_ptr<T> Pop();
31   std::unique_ptr<T> BlockingPop();
32   std::queue<std::unique_ptr<T>> PopAll();
33   void NotifyOfCompletion();
34   void BlockingDrain();
35   void Stop();
36 
37  private:
38   Mutex lock_;
39   ConditionVariable tasks_available_;
40   ConditionVariable tasks_drained_;
41   int outstanding_tasks_;
42   bool stopped_;
43   std::queue<std::unique_ptr<T>> task_queue_;
44 };
45 
46 struct DelayedTask {
47   std::unique_ptr<v8::Task> task;
48   uv_timer_t timer;
49   double timeout;
50   std::shared_ptr<PerIsolatePlatformData> platform_data;
51 };
52 
53 // This acts as the foreground task runner for a given Isolate.
54 class PerIsolatePlatformData :
55     public v8::TaskRunner,
56     public std::enable_shared_from_this<PerIsolatePlatformData> {
57  public:
58   PerIsolatePlatformData(v8::Isolate* isolate, uv_loop_t* loop);
59   ~PerIsolatePlatformData();
60 
61   void PostTask(std::unique_ptr<v8::Task> task) override;
62   void PostIdleTask(std::unique_ptr<v8::IdleTask> task) override;
63   void PostDelayedTask(std::unique_ptr<v8::Task> task,
64                        double delay_in_seconds) override;
IdleTasksEnabled()65   bool IdleTasksEnabled() override { return false; }
66 
67   void Shutdown();
68 
69   void ref();
70   int unref();
71 
72   // Returns true if work was dispatched or executed. New tasks that are
73   // posted during flushing of the queue are postponed until the next
74   // flushing.
75   bool FlushForegroundTasksInternal();
76   void CancelPendingDelayedTasks();
77 
event_loop()78   const uv_loop_t* event_loop() const { return loop_; }
79 
80  private:
81   void DeleteFromScheduledTasks(DelayedTask* task);
82 
83   static void FlushTasks(uv_async_t* handle);
84   static void RunForegroundTask(std::unique_ptr<v8::Task> task);
85   static void RunForegroundTask(uv_timer_t* timer);
86 
87   int ref_count_ = 1;
88   uv_loop_t* const loop_;
89   uv_async_t* flush_tasks_ = nullptr;
90   TaskQueue<v8::Task> foreground_tasks_;
91   TaskQueue<DelayedTask> foreground_delayed_tasks_;
92 
93   // Use a custom deleter because libuv needs to close the handle first.
94   typedef std::unique_ptr<DelayedTask, std::function<void(DelayedTask*)>>
95       DelayedTaskPointer;
96   std::vector<DelayedTaskPointer> scheduled_delayed_tasks_;
97 };
98 
99 // This acts as the single background task runner for all Isolates.
100 class BackgroundTaskRunner : public v8::TaskRunner {
101  public:
102   explicit BackgroundTaskRunner(int thread_pool_size);
103 
104   void PostTask(std::unique_ptr<v8::Task> task) override;
105   void PostIdleTask(std::unique_ptr<v8::IdleTask> task) override;
106   void PostDelayedTask(std::unique_ptr<v8::Task> task,
107                        double delay_in_seconds) override;
IdleTasksEnabled()108   bool IdleTasksEnabled() override { return false; };
109 
110   void BlockingDrain();
111   void Shutdown();
112 
113   size_t NumberOfAvailableBackgroundThreads() const;
114 
115  private:
116   TaskQueue<v8::Task> background_tasks_;
117 
118   class DelayedTaskScheduler;
119   std::unique_ptr<DelayedTaskScheduler> delayed_task_scheduler_;
120 
121   std::vector<std::unique_ptr<uv_thread_t>> threads_;
122 };
123 
124 class NodePlatform : public MultiIsolatePlatform {
125  public:
126   NodePlatform(int thread_pool_size,
127                node::tracing::TracingController* tracing_controller);
~NodePlatform()128   virtual ~NodePlatform() {}
129 
130   void DrainBackgroundTasks(v8::Isolate* isolate) override;
131   void CancelPendingDelayedTasks(v8::Isolate* isolate) override;
132   void Shutdown();
133 
134   // v8::Platform implementation.
135   size_t NumberOfAvailableBackgroundThreads() override;
136   void CallOnBackgroundThread(v8::Task* task,
137                               ExpectedRuntime expected_runtime) override;
138   void CallOnForegroundThread(v8::Isolate* isolate, v8::Task* task) override;
139   void CallDelayedOnForegroundThread(v8::Isolate* isolate, v8::Task* task,
140                                      double delay_in_seconds) override;
141   bool IdleTasksEnabled(v8::Isolate* isolate) override;
142   double MonotonicallyIncreasingTime() override;
143   double CurrentClockTimeMillis() override;
144   node::tracing::TracingController* GetTracingController() override;
145   bool FlushForegroundTasks(v8::Isolate* isolate) override;
146 
147   void RegisterIsolate(IsolateData* isolate_data, uv_loop_t* loop) override;
148   void UnregisterIsolate(IsolateData* isolate_data) override;
149 
150   std::shared_ptr<v8::TaskRunner> GetBackgroundTaskRunner(
151       v8::Isolate* isolate) override;
152   std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
153       v8::Isolate* isolate) override;
154 
155  private:
156   std::shared_ptr<PerIsolatePlatformData> ForIsolate(v8::Isolate* isolate);
157 
158   Mutex per_isolate_mutex_;
159   std::unordered_map<v8::Isolate*,
160                      std::shared_ptr<PerIsolatePlatformData>> per_isolate_;
161 
162   node::tracing::TracingController* tracing_controller_;
163   std::shared_ptr<BackgroundTaskRunner> background_task_runner_;
164 };
165 
166 }  // namespace node
167 
168 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
169 
170 #endif  // SRC_NODE_PLATFORM_H_
171