• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "uv.h"
15 
16 namespace node {
17 
18 class NodePlatform;
19 class IsolateData;
20 class PerIsolatePlatformData;
21 
22 template <class T>
23 class TaskQueue {
24  public:
25   TaskQueue();
26   ~TaskQueue() = default;
27 
28   void Push(std::unique_ptr<T> task);
29   std::unique_ptr<T> Pop();
30   std::unique_ptr<T> BlockingPop();
31   std::queue<std::unique_ptr<T>> PopAll();
32   void NotifyOfCompletion();
33   void BlockingDrain();
34   void Stop();
35 
36  private:
37   Mutex lock_;
38   ConditionVariable tasks_available_;
39   ConditionVariable tasks_drained_;
40   int outstanding_tasks_;
41   bool stopped_;
42   std::queue<std::unique_ptr<T>> task_queue_;
43 };
44 
45 struct DelayedTask {
46   std::unique_ptr<v8::Task> task;
47   uv_timer_t timer;
48   double timeout;
49   std::shared_ptr<PerIsolatePlatformData> platform_data;
50 };
51 
52 // This acts as the foreground task runner for a given Isolate.
53 class PerIsolatePlatformData :
54     public IsolatePlatformDelegate,
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() override;
60 
61   std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner() override;
62   void PostTask(std::unique_ptr<v8::Task> task) override;
63   void PostIdleTask(std::unique_ptr<v8::IdleTask> task) override;
64   void PostDelayedTask(std::unique_ptr<v8::Task> task,
65                        double delay_in_seconds) override;
IdleTasksEnabled()66   bool IdleTasksEnabled() override { return false; }
67 
68   // Non-nestable tasks are treated like regular tasks.
NonNestableTasksEnabled()69   bool NonNestableTasksEnabled() const override { return true; }
NonNestableDelayedTasksEnabled()70   bool NonNestableDelayedTasksEnabled() const override { return true; }
71   void PostNonNestableTask(std::unique_ptr<v8::Task> task) override;
72   void PostNonNestableDelayedTask(std::unique_ptr<v8::Task> task,
73                                   double delay_in_seconds) override;
74 
75   void AddShutdownCallback(void (*callback)(void*), void* data);
76   void Shutdown();
77 
78   // Returns true if work was dispatched or executed. New tasks that are
79   // posted during flushing of the queue are postponed until the next
80   // flushing.
81   bool FlushForegroundTasksInternal();
82 
event_loop()83   const uv_loop_t* event_loop() const { return loop_; }
84 
85  private:
86   void DeleteFromScheduledTasks(DelayedTask* task);
87   void DecreaseHandleCount();
88 
89   static void FlushTasks(uv_async_t* handle);
90   void RunForegroundTask(std::unique_ptr<v8::Task> task);
91   static void RunForegroundTask(uv_timer_t* timer);
92 
93   struct ShutdownCallback {
94     void (*cb)(void*);
95     void* data;
96   };
97   typedef std::vector<ShutdownCallback> ShutdownCbList;
98   ShutdownCbList shutdown_callbacks_;
99   // shared_ptr to self to keep this object alive during shutdown.
100   std::shared_ptr<PerIsolatePlatformData> self_reference_;
101   uint32_t uv_handle_count_ = 1;  // 1 = flush_tasks_
102 
103   v8::Isolate* const isolate_;
104   uv_loop_t* const loop_;
105   uv_async_t* flush_tasks_ = nullptr;
106   TaskQueue<v8::Task> foreground_tasks_;
107   TaskQueue<DelayedTask> foreground_delayed_tasks_;
108 
109   // Use a custom deleter because libuv needs to close the handle first.
110   typedef std::unique_ptr<DelayedTask, void(*)(DelayedTask*)>
111       DelayedTaskPointer;
112   std::vector<DelayedTaskPointer> scheduled_delayed_tasks_;
113 };
114 
115 // This acts as the single worker thread task runner for all Isolates.
116 class WorkerThreadsTaskRunner {
117  public:
118   explicit WorkerThreadsTaskRunner(int thread_pool_size);
119 
120   void PostTask(std::unique_ptr<v8::Task> task);
121   void PostDelayedTask(std::unique_ptr<v8::Task> task,
122                        double delay_in_seconds);
123 
124   void BlockingDrain();
125   void Shutdown();
126 
127   int NumberOfWorkerThreads() const;
128 
129  private:
130   TaskQueue<v8::Task> pending_worker_tasks_;
131 
132   class DelayedTaskScheduler;
133   std::unique_ptr<DelayedTaskScheduler> delayed_task_scheduler_;
134 
135   std::vector<std::unique_ptr<uv_thread_t>> threads_;
136 };
137 
138 class NodePlatform : public MultiIsolatePlatform {
139  public:
140   NodePlatform(int thread_pool_size,
141                v8::TracingController* tracing_controller,
142                v8::PageAllocator* page_allocator = nullptr);
143   ~NodePlatform() override;
144 
145   void DrainTasks(v8::Isolate* isolate) override;
146   void Shutdown();
147 
148   // v8::Platform implementation.
149   int NumberOfWorkerThreads() override;
150   void CallOnWorkerThread(std::unique_ptr<v8::Task> task) override;
151   void CallDelayedOnWorkerThread(std::unique_ptr<v8::Task> task,
152                                  double delay_in_seconds) override;
153   bool IdleTasksEnabled(v8::Isolate* isolate) override;
154   double MonotonicallyIncreasingTime() override;
155   double CurrentClockTimeMillis() override;
156   v8::TracingController* GetTracingController() override;
157   bool FlushForegroundTasks(v8::Isolate* isolate) override;
158   std::unique_ptr<v8::JobHandle> PostJob(
159       v8::TaskPriority priority,
160       std::unique_ptr<v8::JobTask> job_task) override;
161 
162   void RegisterIsolate(v8::Isolate* isolate, uv_loop_t* loop) override;
163   void RegisterIsolate(v8::Isolate* isolate,
164                        IsolatePlatformDelegate* delegate) override;
165 
166   void UnregisterIsolate(v8::Isolate* isolate) override;
167   void AddIsolateFinishedCallback(v8::Isolate* isolate,
168                                   void (*callback)(void*), void* data) override;
169 
170   std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(
171       v8::Isolate* isolate) override;
172 
173   Platform::StackTracePrinter GetStackTracePrinter() override;
174   v8::PageAllocator* GetPageAllocator() override;
175 
176  private:
177   IsolatePlatformDelegate* ForIsolate(v8::Isolate* isolate);
178   std::shared_ptr<PerIsolatePlatformData> ForNodeIsolate(v8::Isolate* isolate);
179 
180   Mutex per_isolate_mutex_;
181   using DelegatePair = std::pair<
182     IsolatePlatformDelegate*, std::shared_ptr<PerIsolatePlatformData>>;
183   std::unordered_map<v8::Isolate*, DelegatePair> per_isolate_;
184 
185   v8::TracingController* tracing_controller_;
186   v8::PageAllocator* page_allocator_;
187   std::shared_ptr<WorkerThreadsTaskRunner> worker_thread_task_runner_;
188   bool has_shut_down_ = false;
189 };
190 
191 }  // namespace node
192 
193 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
194 
195 #endif  // SRC_NODE_PLATFORM_H_
196