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