1 /* Copyright 2008-2019 Bernhard R. Fischer, Daniel Haslinger.
2 *
3 * This file is part of OnionCat.
4 *
5 * OnionCat is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License.
8 *
9 * OnionCat is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with OnionCat. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*! \file ocatthread.c
19 * contains thread management functions. Basically these are
20 * wrapper functions around create_pthread.
21 *
22 * @author Bernhard R. Fischer <rahra _at_ cypherpunk at>
23 * \date 2019/09/08
24 */
25
26
27 #include "ocat.h"
28
29
30 // global thread id var and mutex for thread initializiation
31 static int thread_id_ = 0;
32 static pthread_mutex_t thread_mutex_ = PTHREAD_MUTEX_INITIALIZER;
33 static pthread_cond_t thread_cond_ = PTHREAD_COND_INITIALIZER;
34 static OcatThread_t *octh_ = NULL;
35
36
init_ocat_thread_struct(OcatThread_t * th)37 void init_ocat_thread_struct(OcatThread_t *th)
38 {
39 // init ocat thread structure
40 th->handle = pthread_self();
41 pthread_mutex_lock(&thread_mutex_);
42 th->id = thread_id_++;
43 th->next = octh_;
44 octh_ = th;
45 pthread_mutex_unlock(&thread_mutex_);
46 log_debug("_init_ thread %d", th->id);
47 }
48
49
init_ocat_thread(const char * name)50 const OcatThread_t *init_ocat_thread(const char *name)
51 {
52 OcatThread_t *th;
53
54 // get memory for the ocat internal thread structure
55 if (!(th = calloc(1, sizeof(OcatThread_t))))
56 {
57 log_msg(LOG_ERR, "could not get memory for thread struct: \"%s\"", strerror(errno));
58 return NULL;
59 }
60
61 strlcpy(th->name, name, THREAD_NAME_LEN);
62 init_ocat_thread_struct(th);
63
64 return th;
65 }
66
67
thread_run(void * p)68 void *thread_run(void *p)
69 {
70 OcatThread_t **tl;
71 void *r;
72 sigset_t ss;
73 #ifdef DEBUG
74 int ecnt, icnt;
75 static int exit_cnt_ = 0;
76 #endif
77
78 // block all signals for the thread
79 sigfillset(&ss);
80 pthread_sigmask(SIG_BLOCK, &ss, NULL);
81
82 // init internal ocat thread structure
83 init_ocat_thread_struct((OcatThread_t *) p);
84
85 // call thread entry function
86 log_debug("calling thread entry");
87 r = ((OcatThread_t*)p)->entry(((OcatThread_t*)p)->parm);
88 log_debug("thread function returned");
89
90 // delete thread struct from list and free memory
91 pthread_mutex_lock(&thread_mutex_);
92 for (tl = &octh_; *tl; tl = &(*tl)->next)
93 if ((*tl)->handle == ((OcatThread_t*)p)->handle)
94 break;
95 //free(p);
96 if ((p = *tl))
97 {
98 *tl = (*tl)->next;
99 free(p);
100 }
101 #ifdef DEBUG
102 ecnt = ++exit_cnt_;
103 icnt = thread_id_;
104 #endif
105 pthread_mutex_unlock(&thread_mutex_);
106
107 log_debug("_exit_ thread, %d inits, %d exits", icnt, ecnt);
108 return r;
109 }
110
111
run_ocat_thread(const char * name,void * (* thfunc)(void *),void * parm)112 int run_ocat_thread(const char *name, void *(*thfunc)(void*), void *parm)
113 {
114 int rc;
115 OcatThread_t *th;
116
117 // we need a helper structure on startup.
118 // this is because pthread_create pushes only one arg.
119 // the helper struct is freed again from the thread
120 // (within thread_run()).
121 if (!(th = calloc(1, sizeof(OcatThread_t))))
122 {
123 rc = errno;
124 log_msg(LOG_EMERG, "could not create thread %s: \"%s\"", name, strerror(errno));
125 return rc;
126 }
127
128 strlcpy(th->name, name, THREAD_NAME_LEN);
129 th->entry = thfunc;
130 th->parm = parm;
131
132 if ((rc = pthread_attr_init(&th->attr)))
133 {
134 log_msg(LOG_ERR, "could not init pthread attr: \"%s\"", strerror(rc));
135 return rc;
136 }
137
138 #ifdef DEBUG
139 size_t ss;
140 if ((rc - pthread_attr_getstacksize(&th->attr, &ss)))
141 log_debug("could not get thread stack size attr: \"%s\"", strerror(rc));
142 else
143 log_debug("default thread stack size %dk, setting to %dk", ss / 1024, THREAD_STACK_SIZE / 1024);
144 #endif
145
146 if ((rc - pthread_attr_setstacksize(&th->attr, THREAD_STACK_SIZE)))
147 {
148 log_msg(LOG_EMERG, "could not init thread stack size attr - system may be unstable: \"%s\"", strerror(rc));
149 return rc;
150 }
151
152 log_debug("starting [%s]", name);
153 if ((rc = pthread_create(&th->handle, &th->attr, thread_run, th)))
154 {
155 log_msg(LOG_EMERG, "could not start thread %s: \"%s\"", name, strerror(rc));
156 free(th);
157 }
158
159 return rc;
160 }
161
162
get_thread(void)163 const OcatThread_t *get_thread(void)
164 {
165 OcatThread_t *th;
166 pthread_t thread = pthread_self();
167
168 pthread_mutex_lock(&thread_mutex_);
169 for (th = octh_; th; th = th->next)
170 if (th->handle == thread)
171 break;
172 pthread_mutex_unlock(&thread_mutex_);
173
174 return th;
175 }
176
177
set_thread_name(const char * n)178 int set_thread_name(const char *n)
179 {
180 int e = -1;
181 OcatThread_t *th;
182 pthread_t thread = pthread_self();
183
184 pthread_mutex_lock(&thread_mutex_);
185 for (th = octh_; th; th = th->next)
186 if (th->handle == thread)
187 {
188 strlcpy(th->name, n, THREAD_NAME_LEN);
189 e = 0;
190 break;
191 }
192 pthread_mutex_unlock(&thread_mutex_);
193
194 return e;
195 }
196
197
198 /*! This function waits for a thread identified by name to become ready,
199 * meaning it set its ready flag with set_thread_ready(). If the thread is not
200 * found in the thread list, the function blocks. It wakes up again if any
201 * thread calls set_thread_ready() which reinitiates the reevaluation of the
202 * thread list. A thread my not appear in the thread list because it was not
203 * created, yet.
204 * @param s Pointer to thread name.
205 * @return The function always returns 1.
206 */
wait_thread_by_name_ready(const char * s)207 int wait_thread_by_name_ready(const char *s)
208 {
209 OcatThread_t *th;
210 int e;
211
212 log_debug("waiting for [%s] to become ready", s);
213 pthread_mutex_lock(&thread_mutex_);
214 for (e = 0; !e; )
215 {
216 // loop over all threads
217 for (th = octh_; th; th = th->next)
218 {
219 // match thread name
220 if (!strcmp(th->name, s))
221 {
222 // check if it is ready
223 while (!th->ready)
224 // and wait if not
225 pthread_cond_wait(&thread_cond_, &thread_mutex_);
226 // set ready flag and break loop
227 e = 1;
228 break;
229 }
230 }
231
232 // check if ready flag still not set, meaning thread was not found by name
233 if (!e)
234 {
235 pthread_cond_wait(&thread_cond_, &thread_mutex_);
236 }
237 }
238 pthread_mutex_unlock(&thread_mutex_);
239 log_debug("[%s] ready", s);
240
241 return e;
242 }
243
244
set_thread_ready(void)245 int set_thread_ready(void)
246 {
247 int e = -1;
248 OcatThread_t *th;
249 pthread_t thread = pthread_self();
250
251 log_debug("set_thread_ready()");
252 pthread_mutex_lock(&thread_mutex_);
253 for (th = octh_; th; th = th->next)
254 if (th->handle == thread)
255 {
256 th->ready = 1;
257 pthread_cond_broadcast(&thread_cond_);
258 e = 0;
259 break;
260 }
261 pthread_mutex_unlock(&thread_mutex_);
262
263 return e;
264 }
265
266
print_threads(FILE * f)267 void print_threads(FILE *f)
268 {
269 OcatThread_t *th;
270
271 pthread_mutex_lock(&thread_mutex_);
272 for (th = octh_; th; th = th->next)
273 {
274 fprintf(f, "[%s] "
275 "handle = 0x%08lx, "
276 "id = %d, "
277 "entry = %p, "
278 "parm = %p, "
279 "detached = %d\n",
280 th->name, (long) th->handle, th->id, th->entry, th->parm, th->detached);
281 }
282 pthread_mutex_unlock(&thread_mutex_);
283 }
284
285
join_threads(void)286 int join_threads(void)
287 {
288 OcatThread_t *th, thb;
289 void *ret;
290 int rc;
291
292 for (;;)
293 {
294 pthread_mutex_lock(&thread_mutex_);
295 for (th = octh_, rc = 0; th && th->detached; th = th->next, rc++);
296 if (!th)
297 {
298 pthread_mutex_unlock(&thread_mutex_);
299 break;
300 }
301 memcpy(&thb, th, sizeof(OcatThread_t));
302 pthread_mutex_unlock(&thread_mutex_);
303
304 log_debug("joing thread \"%s\" (%d)", thb.name, thb.id);
305 if ((rc = pthread_join(thb.handle, &ret)))
306 log_msg(LOG_ERR, "error joining thread: \"%s\"", strerror(rc));
307 log_debug("thread successful joined and return %p", ret);
308 }
309 log_debug("no more joinable threads available, %d detached", rc);
310 return rc;
311 }
312
313
detach_thread(void)314 void detach_thread(void)
315 {
316 OcatThread_t *th;
317 pthread_t thread = pthread_self();
318 int rc = 0;
319
320 pthread_mutex_lock(&thread_mutex_);
321 for (th = octh_; th; th = th->next)
322 if (th->handle == thread)
323 break;
324 if (th && !(rc = pthread_detach(thread)))
325 th->detached = 1;
326 pthread_mutex_unlock(&thread_mutex_);
327
328 if (!th)
329 log_msg(LOG_EMERG, "thread tries to detach but is not in list");
330 else if (rc)
331 log_msg(LOG_ERR, "could not detach thread: \"%s\"", strerror(rc));
332 else
333 log_debug("thread detached");
334 }
335
336
337 /*! Check for termination request.
338 * @return 1 if termination requested, otherwise 0.
339 */
term_req(void)340 int term_req(void)
341 {
342 int trq;
343
344 lock_setup();
345 trq = CNF(term_req);
346 unlock_setup();
347
348 return trq;
349 }
350
351
352 /*! Set termination request. */
set_term_req(void)353 void set_term_req(void)
354 {
355 lock_setup();
356 CNF(term_req) = 1;
357 unlock_setup();
358 }
359
360