rearrange argument order
[rofl0r-thread_wrapper.git] / thread_test.c
blobf1b85218d78fde63821e748cc638db0c2e03f8e9
1 /*
2 gcc -Wall -Wextra thread_test.c -g -lpthread
3 */
4 #include <pthread.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <stdlib.h>
9 #include <boost/preprocessor/array/elem.hpp>
10 #include <boost/preprocessor/repetition.hpp>
12 #define KB(x) (x * 1024)
14 #if 0
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
24 #endif
26 /* we want to call this func from a thread. */
27 int worker_func(int x, void* y, int z, void* a) {
28 return z;
33 #if 0
35 typedef struct {
36 pthread_attr_t attr;
37 pthread_t thread;
38 int result;
39 int x;
40 void* y;
41 int z;
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);
47 return NULL;
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));
57 if(!p) {
58 errmsg = "OOM";
59 goto ret;
61 p->x = x;
62 p->y = y;
63 p->z = z;
65 if((errno = pthread_attr_init(&p->attr))) {
66 errmsg = "pthread_attr_init";
67 goto err;
70 if((errno = pthread_attr_setstacksize(&p->attr, stacksize))) {
71 errmsg = "pthread_attr_setstacksize";
72 goto pt_err_attr;
74 if((errno = pthread_create(&p->thread, &p->attr, worker_func_child_thread, *ti))) {
75 errmsg = "pthread_create";
76 goto pt_err_attr;
79 ret:
80 return errmsg;
82 pt_err_attr:
83 pthread_attr_destroy(&p->attr);
84 err:
85 free(p);
86 (*ti) = NULL;
87 goto ret;
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);
98 goto ret;
100 if((errno = pthread_attr_destroy(&p->attr))) {
101 errmsg = "pthread_attr_destroy";
103 *result = p->result;
104 ret:
105 free(p);
106 *ti = NULL;
107 return errmsg;
109 #endif
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) \
115 typedef struct { \
116 pthread_attr_t attr; \
117 pthread_t thread; \
118 returntype result; \
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))); \
124 return NULL; \
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"; \
135 goto err; \
138 if((errno = pthread_attr_setstacksize(&p->attr, stacksize))) { \
139 errmsg = "pthread_attr_setstacksize"; \
140 goto pt_err_attr; \
142 if((errno = pthread_create(&p->thread, &p->attr, function ## _child_thread, p))) { \
143 errmsg = "pthread_create"; \
144 goto pt_err_attr; \
147 ret: \
148 return errmsg; \
150 pt_err_attr: \
151 pthread_attr_destroy(&p->attr); \
152 err: \
153 free(p); \
154 *ti = NULL; \
155 goto ret; \
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); \
166 goto ret; \
168 if((errno = pthread_attr_destroy(&p->attr))) { \
169 errmsg = "pthread_attr_destroy"; \
171 *result = p->result; \
172 ret: \
173 free(p); \
174 *ti = NULL; \
175 return errmsg; \
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))
188 int main() {
189 void* child;
190 int result;
191 const char* errmsg;
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);
197 return 0;
198 pt_err:
199 perror(errmsg);
200 return 1;