2 gcc -Wall -Wextra thread_test.c -g -lpthread
9 #include <boost/preprocessor/array/elem.hpp>
10 #include <boost/preprocessor/repetition.hpp>
12 #define KB(x) (x * 1024)
15 # define BOOST_PP_TUPLE_REM(size) BOOST_PP_TUPLE_REM_OO((size))
16 # define BOOST_PP_TUPLE_REM_OO(par) BOOST_PP_TUPLE_REM_I ## par
17 # define BOOST_PP_TUPLE_REM_I(size) BOOST_PP_TUPLE_REM_ ## size
19 # define BOOST_PP_TUPLE_REM_0()
20 # define BOOST_PP_TUPLE_REM_1(a) a
21 # define BOOST_PP_TUPLE_REM_2(a, b) a, b
22 # define BOOST_PP_TUPLE_REM_3(a, b, c) a, b, c
23 # define BOOST_PP_TUPLE_REM_4(a, b, c, d) a, b, c, d
26 /* we want to call this func from a thread. */
27 int worker_func(int x
, void* y
, int z
, void* a
) {
42 } worker_func_thread_data
;
44 static void* worker_func_child_thread(void* data
) {
45 worker_func_thread_data
*child_thread_data
= data
;
46 child_thread_data
->result
= worker_func(child_thread_data
->x
, child_thread_data
->y
, child_thread_data
->z
);
49 /* returns NULL on success, otherwise error message string
50 * if an error happens, the pthread_attr_t member of ti gets
51 * automatically cleaned up. */
52 static const char* worker_func_thread_launcher(size_t stacksize
, void ** vti
, int x
, void* y
, int z
) {
53 const char* errmsg
= NULL
;
54 worker_func_thread_data
** ti
= vti
;
55 worker_func_thread_data
* p
;
56 p
= *ti
= calloc(1, sizeof(worker_func_thread_data
));
65 if((errno
= pthread_attr_init(&p
->attr
))) {
66 errmsg
= "pthread_attr_init";
70 if((errno
= pthread_attr_setstacksize(&p
->attr
, stacksize
))) {
71 errmsg
= "pthread_attr_setstacksize";
74 if((errno
= pthread_create(&p
->thread
, &p
->attr
, worker_func_child_thread
, *ti
))) {
75 errmsg
= "pthread_create";
83 pthread_attr_destroy(&p
->attr
);
90 static const char* worker_func_wait(int* result
, void** vti
) {
91 worker_func_thread_data
** ti
= vti
;
92 worker_func_thread_data
* p
= *ti
;
93 const char* errmsg
= NULL
;
95 if((errno
= pthread_join(p
->thread
, NULL
))) {
96 errmsg
= "pthread_join";
97 pthread_attr_destroy(&p
->attr
);
100 if((errno
= pthread_attr_destroy(&p
->attr
))) {
101 errmsg
= "pthread_attr_destroy";
111 #define THREAD_WRAPPER_EXPAND_FUNCTION_ARGS(z, n, data) child_thread_data->BOOST_PP_ARRAY_ELEM(n,data)
112 #define THREAD_WRAPPER_ASSIGN(z, n, data) p->BOOST_PP_ARRAY_ELEM(n,data) = BOOST_PP_ARRAY_ELEM(n,data);
113 #define THREAD_WRAPPER_EXPAND_SEMICOLON(z, n, data) BOOST_PP_ARRAY_ELEM(n,data);
114 #define THREAD_WRAPPER(returntype, function, argcount, types_and_args, args) \
116 pthread_attr_t attr; \
119 BOOST_PP_REPEAT(argcount, THREAD_WRAPPER_EXPAND_SEMICOLON, (argcount, types_and_args)) \
120 } function ## _thread_data; \
121 static void* function ## _child_thread(void* data) { \
122 function ## _thread_data *child_thread_data = data; \
123 child_thread_data->result = function(BOOST_PP_ENUM(argcount, THREAD_WRAPPER_EXPAND_FUNCTION_ARGS, (argcount, args))); \
126 static const char* function ## _thread_launcher(size_t stacksize, void ** vti, BOOST_PP_TUPLE_REM_I(argcount) types_and_args) { \
127 const char* errmsg = NULL; \
128 function ## _thread_data** ti = (function ## _thread_data**) vti; \
129 function ## _thread_data* p; \
130 p = *ti = calloc(1, sizeof(function ## _thread_data)); \
131 if(!p) { errmsg = "OOM"; goto ret; } \
132 BOOST_PP_REPEAT(argcount, THREAD_WRAPPER_ASSIGN, (argcount, args)) \
133 if((errno = pthread_attr_init(&p->attr))) { \
134 errmsg = "pthread_attr_init"; \
138 if((errno = pthread_attr_setstacksize(&p->attr, stacksize))) { \
139 errmsg = "pthread_attr_setstacksize"; \
142 if((errno = pthread_create(&p->thread, &p->attr, function ## _child_thread, p))) { \
143 errmsg = "pthread_create"; \
151 pthread_attr_destroy(&p->attr); \
158 static const char* function ## _wait(returntype * result, void** vti) { \
159 function ## _thread_data** ti = (function ## _thread_data**) vti; \
160 function ## _thread_data* p = *ti; \
161 const char* errmsg = NULL; \
163 if((errno = pthread_join(p->thread, NULL))) { \
164 errmsg = "pthread_join"; \
165 pthread_attr_destroy(&p->attr); \
168 if((errno = pthread_attr_destroy(&p->attr))) { \
169 errmsg = "pthread_attr_destroy"; \
171 *result = p->result; \
178 THREAD_WRAPPER(int, worker_func
, 4, (int x
, void* y
, int z
, void* a
), (x
, y
, z
, a
));
181 #define THREAD_LAUNCH(stacksize, name, function, argcount, args) \
182 function ## _thread_launcher(stacksize, &(name), BOOST_PP_TUPLE_REM_I(argcount) args )
185 #define THREAD_WAIT(presult, name, function) \
186 function ## _wait(presult, &(name))
192 if((errmsg
= THREAD_LAUNCH(KB(128), child
, worker_func
, 4, (0, NULL
, 1, (void*) 0xdeadbeef)))) goto pt_err
;
193 if((errmsg
= THREAD_WAIT(&result
, child
, worker_func
))) goto pt_err
;
195 printf("workerfunc returned %d\n", result
);