1 // DO NOT include later.h directly from other packages; use later_api.h instead!
2 #ifndef _later_later_h
3 #define _later_later_h
4 
5 #include <iostream>
6 
7 #ifndef R_NO_REMAP
8 #define R_NO_REMAP
9 #endif
10 
11 #ifndef STRICT_R_HEADERS
12 #define STRICT_R_HEADERS
13 #endif
14 
15 #include <Rinternals.h>
16 
17 // Needed for R_GetCCallable on R 3.3 and older; in more recent versions, this
18 // is included via Rinternals.h.
19 #include <R_ext/Rdynload.h>
20 
21 #ifdef _WIN32
22 #define WIN32_LEAN_AND_MEAN
23 // Taken from http://tolstoy.newcastle.edu.au/R/e2/devel/06/11/1242.html
24 // Undefine the Realloc macro, which is defined by both R and by Windows stuff
25 #undef Realloc
26 // Also need to undefine the Free macro
27 #undef Free
28 #include <windows.h>
29 #else // _WIN32
30 #include <pthread.h>
31 #endif // _WIN32
32 
33 namespace later {
34 
35 // This is the version of the later API provided by this file. Ideally, this
36 // should match the version of the API provided by the later DLL that is
37 // installed on the user's system. However, since this file is compiled into
38 // other packages (like httpuv and promises), it is possible that there will
39 // be a mismatch. In the future we will be able to compare at runtime it to
40 // the result from apiVersion(), with:
41 //
42 // int (*dll_api_version)() = (int (*)()) R_GetCCallable("later", "apiVersion");
43 // if (LATER_H_API_VERSION != (*dll_api_version)()) { ... }
44 #define LATER_H_API_VERSION 2
45 #define GLOBAL_LOOP 0
46 
47 
later(void (* func)(void *),void * data,double secs,int loop_id)48 inline void later(void (*func)(void*), void* data, double secs, int loop_id) {
49   // This function works by retrieving the later::execLaterNative2 function
50   // pointer using R_GetCCallable the first time it's called (per compilation
51   // unit, since it's inline). execLaterNative2 is designed to be safe to call
52   // from any thread, but R_GetCCallable is only safe to call from R's main
53   // thread (otherwise you get stack imbalance warnings or worse). Therefore,
54   // we have to ensure that the first call to execLaterNative2 happens on the
55   // main thread. We accomplish this using a statically initialized object,
56   // in later_api.h. Therefore, any other packages wanting to call
57   // execLaterNative2 need to use later_api.h, not later.h.
58   //
59   // You may wonder why we used the filenames later_api.h/later.h instead of
60   // later.h/later_impl.h; it's because Rcpp treats $PACKAGE.h files
61   // specially by including them in RcppExports.cpp, and we definitely
62   // do not want the static initialization to happen there.
63 
64   // The function type for the real execLaterNative2
65   typedef void (*elnfun)(void (*func)(void*), void*, double, int);
66   static elnfun eln = NULL;
67   if (!eln) {
68     // Initialize if necessary
69     if (func) {
70       // We're not initialized but someone's trying to actually schedule
71       // some code to be executed!
72       REprintf(
73         "Warning: later::execLaterNative2 called in uninitialized state. "
74         "If you're using <later.h>, please switch to <later_api.h>.\n"
75       );
76     }
77     eln = (elnfun)R_GetCCallable("later", "execLaterNative2");
78   }
79 
80   // We didn't want to execute anything, just initialize
81   if (!func) {
82     return;
83   }
84 
85   eln(func, data, secs, loop_id);
86 }
87 
later(void (* func)(void *),void * data,double secs)88 inline void later(void (*func)(void*), void* data, double secs) {
89   later(func, data, secs, GLOBAL_LOOP);
90 }
91 
92 
93 class BackgroundTask {
94 
95 public:
BackgroundTask()96   BackgroundTask() {}
~BackgroundTask()97   virtual ~BackgroundTask() {}
98 
99   // Start executing the task
begin()100   void begin() {
101 #ifndef _WIN32
102     pthread_attr_t attr;
103     pthread_attr_init(&attr);
104     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
105     pthread_t t;
106     pthread_create(&t, NULL, BackgroundTask::task_main, this);
107     pthread_attr_destroy(&attr);
108 #else
109     HANDLE hThread = ::CreateThread(
110       NULL, 0,
111       BackgroundTask::task_main_win,
112       this,
113       0,
114       NULL
115     );
116     ::CloseHandle(hThread);
117 #endif
118   }
119 
120 protected:
121   // The task to be executed on the background thread.
122   // Neither the R runtime nor any R data structures may be
123   // touched from the background thread; any values that need
124   // to be passed into or out of the Execute method must be
125   // included as fields on the Task subclass object.
126   virtual void execute() = 0;
127 
128   // A short task that runs on the main R thread after the
129   // background task has completed. It's safe to access the
130   // R runtime and R data structures from here.
131   virtual void complete() = 0;
132 
133 private:
task_main(void * data)134   static void* task_main(void* data) {
135     BackgroundTask* task = reinterpret_cast<BackgroundTask*>(data);
136     // TODO: Error handling
137     task->execute();
138     later(&BackgroundTask::result_callback, task, 0);
139     return NULL;
140   }
141 
142 #ifdef _WIN32
task_main_win(LPVOID lpParameter)143   static DWORD WINAPI task_main_win(LPVOID lpParameter) {
144     task_main(lpParameter);
145     return 1;
146   }
147 #endif
148 
result_callback(void * data)149   static void result_callback(void* data) {
150     BackgroundTask* task = reinterpret_cast<BackgroundTask*>(data);
151     // TODO: Error handling
152     task->complete();
153     delete task;
154   }
155 };
156 
157 } // namespace later
158 
159 #endif
160