credits
[rofl0r-thread_wrapper.git] / thread_wrapper.h
bloba48a33c8d539e2b9c7668bef504393f96fd0b410
1 #ifndef THREAD_WRAPPER_H
2 #define THREAD_WRAPPER_H
4 #include <pthread.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <stdlib.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"
17 #if 0
19 /* example of what will be generated by the macros */
21 typedef struct {
22 pthread_attr_t attr;
23 pthread_t thread;
24 int result;
25 int x;
26 void* y;
27 int z;
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);
33 return NULL;
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));
43 if(!p) {
44 errmsg = "OOM";
45 goto ret;
47 p->x = x;
48 p->y = y;
49 p->z = z;
51 if((errno = pthread_attr_init(&p->attr))) {
52 errmsg = "pthread_attr_init";
53 goto err;
56 if((errno = pthread_attr_setstacksize(&p->attr, stacksize))) {
57 errmsg = "pthread_attr_setstacksize";
58 goto pt_err_attr;
60 if((errno = pthread_create(&p->thread, &p->attr, worker_func_child_thread, *ti))) {
61 errmsg = "pthread_create";
62 goto pt_err_attr;
65 ret:
66 return errmsg;
68 pt_err_attr:
69 pthread_attr_destroy(&p->attr);
70 err:
71 free(p);
72 (*ti) = NULL;
73 goto ret;
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);
84 goto ret;
86 if((errno = pthread_attr_destroy(&p->attr))) {
87 errmsg = "pthread_attr_destroy";
89 *result = p->result;
90 ret:
91 free(p);
92 *ti = NULL;
93 return errmsg;
95 #endif
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) \
101 typedef struct { \
102 pthread_attr_t attr; \
103 pthread_t thread; \
104 returntype result; \
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))); \
110 return NULL; \
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"; \
121 goto err; \
124 if((errno = pthread_attr_setstacksize(&p->attr, stacksize))) { \
125 errmsg = "pthread_attr_setstacksize"; \
126 goto pt_err_attr; \
128 if((errno = pthread_create(&p->thread, &p->attr, function ## _child_thread, p))) { \
129 errmsg = "pthread_create"; \
130 goto pt_err_attr; \
133 ret: \
134 return errmsg; \
136 pt_err_attr: \
137 pthread_attr_destroy(&p->attr); \
138 err: \
139 free(p); \
140 *ti = NULL; \
141 goto ret; \
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); \
152 goto ret; \
154 if((errno = pthread_attr_destroy(&p->attr))) { \
155 errmsg = "pthread_attr_destroy"; \
157 *result = p->result; \
158 ret: \
159 free(p); \
160 *ti = NULL; \
161 return errmsg; \
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))
172 #endif