1 #ifndef THREAD_WRAPPER_H
2 #define THREAD_WRAPPER_H
9 /* thanks to mathias gaunard for BOOST_PP advice */
10 #include <boost/preprocessor/array/elem.hpp>
11 #include <boost/preprocessor/repetition.hpp>
15 //RcB: LINK "-lpthread"
19 /* example of what will be generated by the macros */
28 } worker_func_thread_data
;
30 static void* worker_func_child_thread(void* data
) {
31 worker_func_thread_data
*child_thread_data
= data
;
32 child_thread_data
->result
= worker_func(child_thread_data
->x
, child_thread_data
->y
, child_thread_data
->z
);
35 /* returns NULL on success, otherwise error message string
36 * if an error happens, the pthread_attr_t member of ti gets
37 * automatically cleaned up. */
38 static const char* worker_func_thread_launcher(size_t stacksize
, void ** vti
, int x
, void* y
, int z
) {
39 const char* errmsg
= NULL
;
40 worker_func_thread_data
** ti
= vti
;
41 worker_func_thread_data
* p
;
42 p
= *ti
= calloc(1, sizeof(worker_func_thread_data
));
51 if((errno
= pthread_attr_init(&p
->attr
))) {
52 errmsg
= "pthread_attr_init";
56 if((errno
= pthread_attr_setstacksize(&p
->attr
, stacksize
))) {
57 errmsg
= "pthread_attr_setstacksize";
60 if((errno
= pthread_create(&p
->thread
, &p
->attr
, worker_func_child_thread
, *ti
))) {
61 errmsg
= "pthread_create";
69 pthread_attr_destroy(&p
->attr
);
76 static const char* worker_func_wait(int* result
, void** vti
) {
77 worker_func_thread_data
** ti
= vti
;
78 worker_func_thread_data
* p
= *ti
;
79 const char* errmsg
= NULL
;
81 if((errno
= pthread_join(p
->thread
, NULL
))) {
82 errmsg
= "pthread_join";
83 pthread_attr_destroy(&p
->attr
);
86 if((errno
= pthread_attr_destroy(&p
->attr
))) {
87 errmsg
= "pthread_attr_destroy";
97 #define THREAD_WRAPPER_EXPAND_FUNCTION_ARGS(z, n, data) child_thread_data->BOOST_PP_ARRAY_ELEM(n,data)
98 #define THREAD_WRAPPER_ASSIGN(z, n, data) p->BOOST_PP_ARRAY_ELEM(n,data) = BOOST_PP_ARRAY_ELEM(n,data);
99 #define THREAD_WRAPPER_EXPAND_SEMICOLON(z, n, data) BOOST_PP_ARRAY_ELEM(n,data);
100 #define THREAD_WRAPPER(returntype, function, argcount, types_and_args, args) \
102 pthread_attr_t attr; \
105 BOOST_PP_REPEAT(argcount, THREAD_WRAPPER_EXPAND_SEMICOLON, (argcount, types_and_args)) \
106 } function ## _thread_data; \
107 static void* function ## _child_thread(void* data) { \
108 function ## _thread_data *child_thread_data = data; \
109 child_thread_data->result = function(BOOST_PP_ENUM(argcount, THREAD_WRAPPER_EXPAND_FUNCTION_ARGS, (argcount, args))); \
112 static const char* function ## _thread_launcher(size_t stacksize, void ** vti, BOOST_PP_TUPLE_REM_I(argcount) types_and_args) { \
113 const char* errmsg = NULL; \
114 function ## _thread_data** ti = (function ## _thread_data**) vti; \
115 function ## _thread_data* p; \
116 p = *ti = calloc(1, sizeof(function ## _thread_data)); \
117 if(!p) { errmsg = "OOM"; goto ret; } \
118 BOOST_PP_REPEAT(argcount, THREAD_WRAPPER_ASSIGN, (argcount, args)) \
119 if((errno = pthread_attr_init(&p->attr))) { \
120 errmsg = "pthread_attr_init"; \
124 if((errno = pthread_attr_setstacksize(&p->attr, stacksize))) { \
125 errmsg = "pthread_attr_setstacksize"; \
128 if((errno = pthread_create(&p->thread, &p->attr, function ## _child_thread, p))) { \
129 errmsg = "pthread_create"; \
137 pthread_attr_destroy(&p->attr); \
144 static const char* function ## _wait(returntype * result, void** vti) { \
145 function ## _thread_data** ti = (function ## _thread_data**) vti; \
146 function ## _thread_data* p = *ti; \
147 const char* errmsg = NULL; \
149 if((errno = pthread_join(p->thread, NULL))) { \
150 errmsg = "pthread_join"; \
151 pthread_attr_destroy(&p->attr); \
154 if((errno = pthread_attr_destroy(&p->attr))) { \
155 errmsg = "pthread_attr_destroy"; \
157 *result = p->result; \
164 #define THREAD_LAUNCH(stacksize, name, function, argcount, args) \
165 function ## _thread_launcher(stacksize, &(name), BOOST_PP_TUPLE_REM_I(argcount) args )
168 #define THREAD_WAIT(presult, name, function) \
169 function ## _wait(presult, &(name))