1 /* threads.c: Thread Abstraction Functions
2 *
3 * Copyright (c) 1999, 2000 the icecast team <team@icecast.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #ifndef WIN32
25 #include <unistd.h>
26 #else
27 #include <winsock2.h>
28 #include <windows.h>
29 #include <winbase.h>
30 #endif
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include "global.h"
37
38 #ifdef TIME_WITH_SYS_TIME
39 # include <sys/time.h>
40 # include <time.h>
41 #else
42 # ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 # else
45 # include <time.h>
46 # endif
47 #endif
48
49 #ifdef HAVE_FTIME
50 #include <sys/timeb.h>
51 #endif
52
53 #include <signal.h>
54
55 #include <timing/timing.h>
56 #include <thread/thread.h>
57 #include <avl/avl.h>
58 #include <log/log.h>
59
60 #ifndef __FUNCTION__
61 #define __FUNCTION__ __FILE__
62 #endif
63
64 #ifdef THREAD_DEBUG
65 #define CATMODULE "thread"
66 #define LOG_ERROR(y) log_write(_logid, 1, CATMODULE "/", __FUNCTION__, y)
67 #define LOG_ERROR1(y, z1) log_write(_logid, 1, CATMODULE "/", __FUNCTION__, y, z1)
68 #define LOG_ERROR3(y, z1, z2, z3) log_write(_logid, 1, CATMODULE "/", __FUNCTION__, y, z1, z2, z3)
69 #define LOG_ERROR7(y, z1, z2, z3, z4, z5, z6, z7) log_write(_logid, 1, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5, z6, z7)
70
71 #define LOG_WARN(y) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y)
72 #define LOG_WARN3(y, z1, z2, z3) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y, z1, z2, z3)
73 #define LOG_WARN5(y, z1, z2, z3, z4, z5) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5)
74 #define LOG_WARN7(y, z1, z2, z3, z4, z5, z6, z7) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5, z6, z7)
75
76 #define LOG_INFO(y) log_write(_logid, 3, CATMODULE "/", __FUNCTION__, y)
77 #define LOG_INFO4(y, z1, z2, z3, z4) log_write(_logid, 3, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4)
78 #define LOG_INFO5(y, z1, z2, z3, z4, z5) log_write(_logid, 3, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5)
79
80 #define LOG_DEBUG(y) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y)
81 #define LOG_DEBUG1(y, z1) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y, z1)
82 #define LOG_DEBUG2(y, z1, z2) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y, z1, z2)
83 #define LOG_DEBUG3(y, z1, z2, z3) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y, z1, z2, z3)
84 #define LOG_DEBUG4(y, z1, z2, z3, z4) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4)
85 #define LOG_DEBUG5(y, z1, z2, z3, z4, z5) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5)
86 #endif
87
88 /* thread starting structure */
89 typedef struct thread_start_tag {
90 /* the real start routine and arg */
91 void *(*start_routine)(void *);
92 void *arg;
93
94 /* the other stuff we need to make sure this thread is inserted into
95 ** the thread tree
96 */
97 thread_type *thread;
98 pthread_t sys_thread;
99 } thread_start_t;
100
101 static long _next_thread_id = 0;
102 static int _initialized = 0;
103 static avl_tree *_threadtree = NULL;
104 static int lock_problem_abort;
105 static int thread_log;
106
107
108 #ifdef THREAD_DEBUG
109
110 /* this is x86 specific, but gets a very precise and low overhead
111 * timer, other platforms may have similar mechanisms
112 */
113 #define rdtscll(val) \
114 __asm__ __volatile__("rdtsc" : "=A" (val))
115
get_count(void)116 static inline unsigned long long get_count (void)
117 {
118 unsigned long long ret;
119
120 rdtscll(ret);
121 return ret;
122 }
123
124 static int _logid = -1;
125 static long _next_mutex_id = 0;
126 static avl_tree *_mutextree = NULL;
127
128 static mutex_t _threadtree_mutex;
129 static mutex_t _mutextree_mutex;
130 static mutex_t _library_mutex;
131
132 static int _compare_mutexes(void *compare_arg, void *a, void *b);
133 static int _free_mutex(void *key);
134
135 #else
136
137 static mutex_t _threadtree_mutex;
138 static mutex_t _library_mutex;
139
140 #endif
141
142 /* INTERNAL FUNCTIONS */
143
144 static int _compare_threads(void *compare_arg, void *a, void *b);
145 static int _free_thread(void *key);
146
147 /* mutex fuctions */
148 static void _mutex_create(mutex_t *mutex);
149 static void _mutex_lock_c(mutex_t *mutex, const char *file, int line);
150 static void _mutex_unlock_c(mutex_t *mutex, const char *file, int line);
151
152 /* misc thread stuff */
153 static void *_start_routine(void *arg);
154 static void _catch_signals(void);
155 static void _block_signals(void);
156
157 #define _mutex_lock(x) _mutex_lock_c((x),__FILE__,__LINE__)
158 #define _mutex_unlock(x) _mutex_unlock_c((x),__FILE__,__LINE__)
159
160 /* LIBRARY INITIALIZATION */
161
thread_initialize(void)162 void thread_initialize(void)
163 {
164 thread_type *thread;
165 const char *dbg;
166
167 /* set up logging */
168
169 #ifdef THREAD_DEBUG
170 /* create all the internal mutexes, and initialize the mutex tree */
171
172 _mutextree = avl_tree_new(_compare_mutexes, NULL);
173
174 /* we have to create this one by hand, because there's no
175 ** mutextree_mutex to lock yet!
176 */
177 _mutex_create(&_mutextree_mutex);
178
179 _mutextree_mutex.mutex_id = _next_mutex_id++;
180 avl_insert(_mutextree, (void *)&_mutextree_mutex);
181
182 log_initialize();
183 _logid = log_open("thread.log");
184 log_set_level(_logid, 4);
185 #endif
186
187 thread_mutex_create(&_threadtree_mutex);
188 thread_mutex_create(&_library_mutex);
189
190 /* initialize the thread tree and insert the main thread */
191
192 _threadtree = avl_tree_new(_compare_threads, NULL);
193
194 thread = (thread_type *)calloc(1, sizeof(thread_type));
195
196 thread->thread_id = _next_thread_id++;
197 thread->line = 0;
198 thread->file = "main.c";
199 thread->sys_thread = pthread_self();
200 thread->create_time = time(NULL);
201 thread->name = strdup("Main Thread");
202
203 avl_insert(_threadtree, (void *)thread);
204
205 _catch_signals();
206
207 lock_problem_abort = 0;
208 dbg = getenv ("ICE_LOCK_ABORT");
209 if (dbg)
210 lock_problem_abort = atoi (dbg);
211 _initialized = 1;
212 }
213
214
thread_use_log_id(int log_id)215 void thread_use_log_id (int log_id)
216 {
217 thread_log = log_id;
218 log_write (thread_log, 3, "thread/", "", "lock abort set to %d", lock_problem_abort);
219 }
220
221
thread_shutdown(void)222 void thread_shutdown(void)
223 {
224 if (_initialized == 1) {
225 thread_mutex_destroy(&_library_mutex);
226 thread_mutex_destroy(&_threadtree_mutex);
227 #ifdef THREAD_DEBUG
228 thread_mutex_destroy(&_mutextree_mutex);
229
230 avl_tree_free(_mutextree, _free_mutex);
231 #endif
232 avl_tree_free(_threadtree, _free_thread);
233 _threadtree = NULL;
234 }
235
236 #ifdef THREAD_DEBUG
237 log_close(_logid);
238 log_shutdown();
239 #endif
240
241 }
242
243 /*
244 * Signals should be handled by the main thread, nowhere else.
245 * I'm using POSIX signal interface here, until someone tells me
246 * that I should use signal/sigset instead
247 *
248 * This function only valid for non-Win32
249 */
_block_signals(void)250 static void _block_signals(void)
251 {
252 #ifndef _WIN32
253 sigset_t ss;
254
255 sigfillset(&ss);
256
257 /* These ones we want */
258 sigdelset(&ss, SIGKILL);
259 sigdelset(&ss, SIGSTOP);
260 sigdelset(&ss, SIGSEGV);
261 sigdelset(&ss, SIGCHLD);
262 sigdelset(&ss, SIGBUS);
263 if (pthread_sigmask(SIG_BLOCK, &ss, NULL) != 0) {
264 #ifdef THREAD_DEBUG
265 LOG_ERROR("Pthread_sigmask() failed for blocking signals");
266 #endif
267 }
268 #endif
269 }
270
271 /*
272 * Let the calling thread catch all the relevant signals
273 *
274 * This function only valid for non-Win32
275 */
_catch_signals(void)276 static void _catch_signals(void)
277 {
278 #ifndef _WIN32
279 sigset_t ss;
280
281 sigemptyset(&ss);
282
283 /* These ones should only be accepted by the signal handling thread (main thread) */
284 sigaddset(&ss, SIGHUP);
285 sigaddset(&ss, SIGCHLD);
286 sigaddset(&ss, SIGINT);
287 sigaddset(&ss, SIGPIPE);
288 sigaddset(&ss, SIGTERM);
289
290 if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) != 0) {
291 #ifdef THREAD_DEBUG
292 LOG_ERROR("pthread_sigmask() failed for catching signals!");
293 #endif
294 }
295 #endif
296 }
297
298
thread_create_c(char * name,void * (* start_routine)(void *),void * arg,int detached,int line,const char * file)299 thread_type *thread_create_c(char *name, void *(*start_routine)(void *),
300 void *arg, int detached, int line, const char *file)
301 {
302 thread_type *thread = NULL;
303 thread_start_t *start = NULL;
304 pthread_attr_t attr;
305
306 thread = (thread_type *)calloc(1, sizeof(thread_type));
307 do {
308 if (thread == NULL)
309 break;
310 start = (thread_start_t *)calloc(1, sizeof(thread_start_t));
311 if (start == NULL)
312 break;
313 if (pthread_attr_init (&attr) < 0)
314 break;
315
316 thread->line = line;
317 thread->file = file;
318
319 _mutex_lock (&_threadtree_mutex);
320 thread->thread_id = _next_thread_id++;
321 _mutex_unlock (&_threadtree_mutex);
322
323 thread->name = strdup(name);
324 thread->create_time = time(NULL);
325
326 start->start_routine = start_routine;
327 start->arg = arg;
328 start->thread = thread;
329
330 pthread_attr_setstacksize (&attr, 1024*1024);
331 pthread_attr_setinheritsched (&attr, PTHREAD_INHERIT_SCHED);
332 if (detached)
333 {
334 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
335 thread->detached = 1;
336 }
337
338 #ifdef __OpenBSD__
339 thread->running = 1;
340 #endif
341 if (pthread_create (&thread->sys_thread, &attr, _start_routine, start) == 0)
342 {
343 pthread_attr_destroy (&attr);
344 return thread;
345 }
346 else
347 pthread_attr_destroy (&attr);
348 }
349 while (0);
350
351 #ifdef THREAD_DEBUG
352 LOG_ERROR1("Could not create new thread %s", name);
353 #endif
354 if (start) free (start);
355 if (thread)
356 {
357 free (thread->name);
358 free (thread);
359 }
360 return NULL;
361 }
362
363 /* _mutex_create
364 **
365 ** creates a mutex
366 */
_mutex_create(mutex_t * mutex)367 static void _mutex_create(mutex_t *mutex)
368 {
369 #ifdef THREAD_DEBUG
370 mutex->thread_id = MUTEX_STATE_NEVERLOCKED;
371 mutex->line = -1;
372 #endif
373
374 if (lock_problem_abort == 2)
375 {
376 pthread_mutexattr_t attr;
377
378 pthread_mutexattr_init (&attr);
379 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK);
380 pthread_mutex_init (&mutex->sys_mutex, &attr);
381 pthread_mutexattr_destroy (&attr);
382 }
383 else
384 pthread_mutex_init(&mutex->sys_mutex, NULL);
385 }
386
thread_mutex_create_c(mutex_t * mutex,int line,const char * file)387 void thread_mutex_create_c(mutex_t *mutex, int line, const char *file)
388 {
389 _mutex_create(mutex);
390
391 #ifdef THREAD_DEBUG
392 mutex->name = malloc (strlen (file)+20);
393 sprintf (mutex->name, "%s:%d", file, line);
394 _mutex_lock(&_mutextree_mutex);
395 mutex->mutex_id = _next_mutex_id++;
396 avl_insert(_mutextree, (void *)mutex);
397 _mutex_unlock(&_mutextree_mutex);
398
399 LOG_DEBUG3 ("mutex %s created (%s:%d)", mutex->name, file, line);
400 #endif
401 }
402
thread_mutex_destroy_c(mutex_t * mutex,int line,const char * file)403 void thread_mutex_destroy_c (mutex_t *mutex, int line, const char *file)
404 {
405 int rc = pthread_mutex_destroy(&mutex->sys_mutex);
406 if (rc)
407 {
408 log_write (thread_log, 1, "thread/", "mutex", "destroy error triggered at %s:%d (%d)", file, line, rc);
409 abort();
410 }
411
412 #ifdef THREAD_DEBUG
413 _mutex_lock(&_mutextree_mutex);
414 avl_delete(_mutextree, mutex, _free_mutex);
415 _mutex_unlock(&_mutextree_mutex);
416 #endif
417 }
418
thread_mutex_lock_c(mutex_t * mutex,int line,const char * file)419 void thread_mutex_lock_c(mutex_t *mutex, int line, const char *file)
420 {
421 #ifdef THREAD_DEBUG
422 LOG_DEBUG3("Lock on %s requested at %s:%d", mutex->name, file, line);
423 #endif
424 _mutex_lock_c(mutex, file, line);
425 #ifdef THREAD_DEBUG
426 mutex->lock_start = get_count();
427 mutex->file = (char*)file;
428 mutex->line = line;
429 LOG_DEBUG3("Lock on %s acquired at %s:%d", mutex->name, file, line);
430 #endif /* THREAD_DEBUG */
431 }
432
thread_mutex_unlock_c(mutex_t * mutex,int line,const char * file)433 void thread_mutex_unlock_c(mutex_t *mutex, int line, const char *file)
434 {
435 _mutex_unlock_c(mutex, file, line);
436 #ifdef THREAD_DEBUG
437 LOG_DEBUG4 ("lock %s, at %s:%d lasted %llu", mutex->name, mutex->file,
438 mutex->line, get_count() - mutex->lock_start);
439 mutex->file = NULL;
440 #endif
441 }
442
thread_cond_create_c(cond_t * cond,int line,char * file)443 void thread_cond_create_c(cond_t *cond, int line, char *file)
444 {
445 int rc = pthread_cond_init(&cond->sys_cond, NULL);
446 if (rc)
447 log_write (thread_log, 1, "thread/", "cond", "create error triggered at %s:%d (%d)", file,line, rc);
448 }
449
thread_cond_destroy(cond_t * cond)450 void thread_cond_destroy(cond_t *cond)
451 {
452 int rc = pthread_cond_destroy(&cond->sys_cond);
453 if (rc)
454 log_write (thread_log, 1, "thread/", "cond", "destroy error triggered at (%d)", rc);
455 }
456
thread_cond_signal_c(cond_t * cond,int line,char * file)457 void thread_cond_signal_c(cond_t *cond, int line, char *file)
458 {
459 int rc;
460 cond->set = 1;
461 rc = pthread_cond_signal(&cond->sys_cond);
462 if (rc)
463 log_write (thread_log, 1, "thread/", "cond", "signal error triggered at %s:%d (%d)", file, line, rc);
464 }
465
thread_cond_broadcast_c(cond_t * cond,int line,char * file)466 void thread_cond_broadcast_c(cond_t *cond, int line, char *file)
467 {
468 pthread_cond_broadcast(&cond->sys_cond);
469 }
470
thread_cond_timedwait_c(cond_t * cond,mutex_t * mutex,struct timespec * ts,int line,char * file)471 void thread_cond_timedwait_c(cond_t *cond, mutex_t *mutex, struct timespec *ts, int line, char *file)
472 {
473 int rc = 0;
474
475 cond->set = 0;
476 while (cond->set == 0 && rc == 0)
477 rc = pthread_cond_timedwait(&cond->sys_cond, &mutex->sys_mutex, ts);
478 if (rc == 0 && cond->set == 1)
479 cond->set = 0;
480 if (rc && rc != ETIMEDOUT)
481 log_write (thread_log, 1, "thread/", "mutex", "timedwait error triggered at %s:%d (%d)", file,line, rc);
482 }
483
thread_cond_wait_c(cond_t * cond,mutex_t * mutex,int line,char * file)484 void thread_cond_wait_c(cond_t *cond, mutex_t *mutex,int line, char *file)
485 {
486 int rc = pthread_cond_wait(&cond->sys_cond, &mutex->sys_mutex);
487 if (rc)
488 log_write (thread_log, 1, "thread/", "cond", "wait error triggered at %s:%d (%d)", file,line, rc);
489 }
490
thread_rwlock_create_c(const char * name,rwlock_t * rwlock,int line,const char * file)491 void thread_rwlock_create_c(const char *name, rwlock_t *rwlock, int line, const char *file)
492 {
493 #if defined (PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP)
494 // later glibc ignores PTHREAD_RWLOCK_PREFER_WRITER_NP for deadlock cases if recursive calls are used. we
495 // assume that is never done so should never be a problem. these look to be enums not defines
496 rwlock->sys_rwlock = (pthread_rwlock_t) PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP;
497 #else
498 // win32 at least has issues if attributes are passed
499 pthread_rwlock_init(&rwlock->sys_rwlock, NULL);
500 #endif
501 #ifdef THREAD_DEBUG
502 rwlock->name = strdup (name);
503 LOG_DEBUG4 ("rwlock %s (%p) created (%s:%d)", rwlock->name, rwlock, file, line);
504 #endif
505 }
506
thread_rwlock_destroy(rwlock_t * rwlock)507 void thread_rwlock_destroy(rwlock_t *rwlock)
508 {
509 pthread_rwlock_destroy(&rwlock->sys_rwlock);
510 #ifdef THREAD_DEBUG
511 LOG_DEBUG1 ("rwlock %s destroyed", rwlock->name);
512 free (rwlock->name);
513 rwlock->name = NULL;
514 #endif
515 }
516
517
thread_rwlock_tryrlock_c(rwlock_t * rwlock,int line,const char * file)518 int thread_rwlock_tryrlock_c(rwlock_t *rwlock, int line, const char *file)
519 {
520 int ret = pthread_rwlock_tryrdlock (&rwlock->sys_rwlock);
521 #ifdef THREAD_DEBUG
522 LOG_DEBUG3("tryrLock on %s requested at %s:%d", rwlock->name, file, line);
523 #endif
524 switch (ret)
525 {
526 default:
527 log_write (thread_log, 1, "thread/", "rwlock", "try rlock error triggered at %p, %s:%d (%d)", rwlock, file, line, ret);
528 abort();
529 case 0:
530 return 0;
531 case EBUSY:
532 case EAGAIN:
533 return -1;
534 }
535 }
536
537
thread_rwlock_rlock_c(rwlock_t * rwlock,int line,const char * file)538 void thread_rwlock_rlock_c(rwlock_t *rwlock, int line, const char *file)
539 {
540 int rc;
541 #ifdef THREAD_DEBUG
542 LOG_DEBUG4("rLock on %s (%p) requested at %s:%d", rwlock->name, rwlock, file, line);
543 #endif
544 #if _POSIX_C_SOURCE>=200112L
545 if (lock_problem_abort)
546 {
547 struct timespec now;
548 thread_get_timespec (&now);
549 now.tv_sec += 7;
550 rc = pthread_rwlock_timedrdlock (&rwlock->sys_rwlock, &now);
551 }
552 else
553 #endif
554 rc = pthread_rwlock_rdlock(&rwlock->sys_rwlock);
555 if (rc)
556 {
557 log_write (thread_log, 1, "thread/", "rwlock", "rlock error triggered at %p, %s:%d (%d)", rwlock, file, line, rc);
558 abort();
559 }
560 #ifdef THREAD_DEBUG
561 LOG_DEBUG3("rLock on %s acquired at %s:%d", rwlock->name, file, line);
562 #endif
563 }
564
thread_rwlock_wlock_c(rwlock_t * rwlock,int line,const char * file)565 void thread_rwlock_wlock_c(rwlock_t *rwlock, int line, const char *file)
566 {
567 int rc;
568 #ifdef THREAD_DEBUG
569 LOG_DEBUG4("wLock on %s (%p) requested at %s:%d", rwlock->name, rwlock, file, line);
570 #endif
571 #if _POSIX_C_SOURCE>=200112L
572 if (lock_problem_abort)
573 {
574 struct timespec now;
575 thread_get_timespec (&now);
576 now.tv_sec += 6;
577 rc = pthread_rwlock_timedwrlock (&rwlock->sys_rwlock, &now);
578 }
579 else
580 #endif
581 rc = pthread_rwlock_wrlock(&rwlock->sys_rwlock);
582 if (rc)
583 {
584 log_write (thread_log, 1, "thread/", "rwlock", "wlock error triggered at %p, %s:%d (%d)", rwlock, file, line, rc);
585 abort();
586 }
587 #ifdef THREAD_DEBUG
588 LOG_DEBUG3("wLock on %s acquired at %s:%d", rwlock->name, file, line);
589 #endif
590 }
591
592
thread_rwlock_trywlock_c(rwlock_t * rwlock,int line,const char * file)593 int thread_rwlock_trywlock_c(rwlock_t *rwlock, int line, const char *file)
594 {
595 int ret = pthread_rwlock_trywrlock (&rwlock->sys_rwlock);
596 #ifdef THREAD_DEBUG
597 LOG_DEBUG3("trywLock on %s requested at %s:%d", rwlock->name, file, line);
598 #endif
599 switch (ret)
600 {
601 default:
602 log_write (thread_log, 1, "thread/", "rwlock", "try wlock error triggered at %p, %s:%d (%d)", rwlock, file, line, ret);
603 abort();
604 case 0:
605 return 0;
606 case EBUSY:
607 case EAGAIN:
608 return -1;
609 }
610 }
611
612
thread_rwlock_unlock_c(rwlock_t * rwlock,int line,const char * file)613 void thread_rwlock_unlock_c(rwlock_t *rwlock, int line, const char *file)
614 {
615 int rc = pthread_rwlock_unlock(&rwlock->sys_rwlock);
616 if (rc)
617 {
618 log_write (thread_log, 1, "thread/", "rwlock", "unlock error triggered at %p, %s:%d (%d)", rwlock, file, line, rc);
619 abort ();
620 }
621
622 #ifdef THREAD_DEBUG
623 LOG_DEBUG4 ("unlock %s (%p) at %s:%d", rwlock->name, rwlock, file, line);
624 #endif
625 }
626
thread_exit_c(long val,int line,char * file)627 void thread_exit_c(long val, int line, char *file)
628 {
629 thread_type *th = thread_self();
630
631 #if defined(DEBUG_MUTEXES) && defined(CHECK_MUTEXES)
632 if (th) {
633 avl_node *node;
634 mutex_t *tmutex;
635 char name[40];
636
637 _mutex_lock(&_mutextree_mutex);
638
639 while (node) {
640 tmutex = (mutex_t *)node->key;
641
642 if (tmutex->thread_id == th->thread_id) {
643 LOG_WARN("Thread %d [%s] exiting in file %s line %d, without unlocking mutex [%s]",
644 th->thread_id, th->name, file, line, mutex_to_string(tmutex, name));
645 }
646
647 node = avl_get_next (node);
648 }
649
650 _mutex_unlock(&_mutextree_mutex);
651 }
652 #endif
653 #ifdef __OpenBSD__
654 th->running = 0;
655 #endif
656
657 if (th)
658 {
659 #ifdef THREAD_DEBUG
660 LOG_DEBUG4("Removing thread %d [%s] started at [%s:%d]", th->thread_id,
661 th->name, th->file, th->line);
662 #endif
663 _mutex_lock(&_threadtree_mutex);
664 avl_delete(_threadtree, th, _free_thread);
665 _mutex_unlock(&_threadtree_mutex);
666 }
667
668 pthread_exit ((void*)(uintptr_t)val);
669 }
670
671 /* sleep for a number of microseconds */
thread_sleep(unsigned long len)672 void thread_sleep(unsigned long len)
673 {
674 #ifdef _WIN32
675 Sleep(len / 1000);
676 #else
677 # ifdef HAVE_NANOSLEEP
678 struct timespec time_sleep;
679 struct timespec time_remaining;
680 int ret;
681
682 time_sleep.tv_sec = len / 1000000;
683 time_sleep.tv_nsec = (len % 1000000) * 1000;
684
685 ret = nanosleep(&time_sleep, &time_remaining);
686 while (ret != 0 && errno == EINTR) {
687 time_sleep.tv_sec = time_remaining.tv_sec;
688 time_sleep.tv_nsec = time_remaining.tv_nsec;
689
690 ret = nanosleep(&time_sleep, &time_remaining);
691 }
692 # else
693 struct timeval tv;
694
695 tv.tv_sec = len / 1000000;
696 tv.tv_usec = (len % 1000000);
697
698 select(0, NULL, NULL, NULL, &tv);
699 # endif
700 #endif
701 }
702
_start_routine(void * arg)703 static void *_start_routine(void *arg)
704 {
705 thread_start_t *start = (thread_start_t *)arg;
706 void *(*start_routine)(void *) = start->start_routine;
707 void *real_arg = start->arg;
708 thread_type *thread = start->thread;
709
710 _block_signals();
711
712 /* insert thread into thread tree here */
713 _mutex_lock(&_threadtree_mutex);
714 avl_insert(_threadtree, (void *)thread);
715 _mutex_unlock(&_threadtree_mutex);
716
717 #ifdef THREAD_DEBUG
718 LOG_DEBUG4("Added thread %d [%s] started at [%s:%d]", thread->thread_id,
719 thread->name, thread->file, thread->line);
720 #endif
721
722 pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
723 free (start);
724
725 (start_routine)(real_arg);
726
727 #ifdef __OpenBSD__
728 thread->running = 0;
729 #endif
730
731 if (thread->detached)
732 {
733 _mutex_lock (&_threadtree_mutex);
734 avl_delete (_threadtree, thread, _free_thread);
735 _mutex_unlock (&_threadtree_mutex);
736 }
737
738 return NULL;
739 }
740
thread_self(void)741 thread_type *thread_self(void)
742 {
743 avl_node *node;
744 thread_type *th;
745 pthread_t sys_thread = pthread_self();
746
747 _mutex_lock(&_threadtree_mutex);
748
749 if (_threadtree == NULL) {
750 #ifdef THREAD_DEBUG
751 LOG_WARN("Thread tree is empty, this must be wrong!");
752 #endif
753 _mutex_unlock(&_threadtree_mutex);
754 return NULL;
755 }
756
757 node = avl_get_first(_threadtree);
758
759 while (node) {
760 th = (thread_type *)node->key;
761
762 if (th && pthread_equal(sys_thread, th->sys_thread)) {
763 _mutex_unlock(&_threadtree_mutex);
764 return th;
765 }
766
767 node = avl_get_next(node);
768 }
769 _mutex_unlock(&_threadtree_mutex);
770
771
772 #ifdef THREAD_DEBUG
773 LOG_ERROR("Nonexistant thread alive...");
774 #endif
775
776 return NULL;
777 }
778
thread_rename(const char * name)779 void thread_rename(const char *name)
780 {
781 thread_type *th;
782
783 th = thread_self();
784 if (th->name) free(th->name);
785
786 th->name = strdup(name);
787 }
788
_mutex_lock_c(mutex_t * mutex,const char * file,int line)789 static void _mutex_lock_c(mutex_t *mutex, const char *file, int line)
790 {
791 int rc;
792 #if _POSIX_C_SOURCE>=200112L
793 if (lock_problem_abort)
794 {
795 struct timespec now;
796 thread_get_timespec (&now);
797 now.tv_sec += 7;
798 rc = pthread_mutex_timedlock (&mutex->sys_mutex, &now);
799 }
800 else
801 #endif
802 rc = pthread_mutex_lock(&mutex->sys_mutex);
803 if (rc)
804 {
805 if (file)
806 log_write (thread_log, 1, "thread/", "mutex", "lock error triggered at %s:%d (%d)", file,line, rc);
807 else
808 log_write (thread_log, 1, "thread/", "mutex", "lock error triggered no reference (%d)", rc);
809 if (mutex->file)
810 log_write (thread_log, 1, "thread/", "mutex", "last lock at %s:%d", mutex->file,mutex->line);
811 abort();
812 }
813 mutex->file = file;
814 mutex->line = line;
815 }
816
_mutex_unlock_c(mutex_t * mutex,const char * file,int line)817 static void _mutex_unlock_c(mutex_t *mutex, const char *file, int line)
818 {
819 int rc;
820 mutex->file = NULL;
821 rc = pthread_mutex_unlock(&mutex->sys_mutex);
822 if (lock_problem_abort && rc)
823 {
824 if (file)
825 log_write (thread_log, 1, "thread/", "mutex", "unlock error triggered at %s:%d (%d)", file, line, rc);
826 else
827 log_write (thread_log, 1, "thread/", "mutex", "unlock error triggered no reference (%d)", rc);
828 abort ();
829 }
830 }
831
832
thread_library_lock(void)833 void thread_library_lock(void)
834 {
835 _mutex_lock(&_library_mutex);
836 }
837
thread_library_unlock(void)838 void thread_library_unlock(void)
839 {
840 _mutex_unlock(&_library_mutex);
841 }
842
thread_join(thread_type * thread)843 void thread_join(thread_type *thread)
844 {
845 void *ret;
846
847 #ifdef __OpenBSD__
848 /* openbsd masks signals while waiting */
849 while (thread->running)
850 thread_sleep (200000);
851 #endif
852 pthread_join (thread->sys_thread, &ret);
853 _mutex_lock(&_threadtree_mutex);
854 avl_delete(_threadtree, thread, _free_thread);
855 _mutex_unlock(&_threadtree_mutex);
856 }
857
858 /* AVL tree functions */
859
860 #ifdef THREAD_DEBUG
_compare_mutexes(void * compare_arg,void * a,void * b)861 static int _compare_mutexes(void *compare_arg, void *a, void *b)
862 {
863 mutex_t *m1, *m2;
864
865 m1 = (mutex_t *)a;
866 m2 = (mutex_t *)b;
867
868 if (m1->mutex_id > m2->mutex_id)
869 return 1;
870 if (m1->mutex_id < m2->mutex_id)
871 return -1;
872 return 0;
873 }
874 #endif
875
_compare_threads(void * compare_arg,void * a,void * b)876 static int _compare_threads(void *compare_arg, void *a, void *b)
877 {
878 thread_type *t1, *t2;
879
880 t1 = (thread_type *)a;
881 t2 = (thread_type *)b;
882
883 if (t1->thread_id > t2->thread_id)
884 return 1;
885 if (t1->thread_id < t2->thread_id)
886 return -1;
887 return 0;
888 }
889
890 #ifdef THREAD_DEBUG
_free_mutex(void * key)891 static int _free_mutex(void *key)
892 {
893 mutex_t *m;
894
895 m = (mutex_t *)key;
896
897 if (m && m->file) {
898 m->file = NULL;
899 }
900
901 /* all mutexes are static. don't need to free them */
902
903 return 1;
904 }
905 #endif
906
_free_thread(void * key)907 static int _free_thread(void *key)
908 {
909 thread_type *t;
910
911 t = (thread_type *)key;
912
913 if (t->name)
914 free(t->name);
915
916 free(t);
917
918 return 1;
919 }
920
921
922 #ifdef HAVE_PTHREAD_SPIN_LOCK
thread_spin_create(spin_t * spin)923 void thread_spin_create (spin_t *spin)
924 {
925 int x = pthread_spin_init (&spin->lock, PTHREAD_PROCESS_PRIVATE);
926 if (x)
927 abort();
928 }
929
thread_spin_destroy(spin_t * spin)930 void thread_spin_destroy (spin_t *spin)
931 {
932 pthread_spin_destroy (&spin->lock);
933 }
934
thread_spin_lock(spin_t * spin)935 void thread_spin_lock (spin_t *spin)
936 {
937 int x = pthread_spin_lock (&spin->lock);
938 if (x != 0)
939 abort();
940 }
941
thread_spin_unlock(spin_t * spin)942 void thread_spin_unlock (spin_t *spin)
943 {
944 pthread_spin_unlock (&spin->lock);
945 }
946 #endif
947
948
949 #ifdef HAVE_CLOCK_GETTIME
thread_get_timespec(struct timespec * now)950 void thread_get_timespec (struct timespec *now)
951 {
952 clock_gettime (CLOCK_REALTIME, now);
953 }
954 #elif HAVE_GETTIMEOFDAY
thread_get_timespec(struct timespec * now)955 void thread_get_timespec (struct timespec *now)
956 {
957 struct timeval mtv;
958
959 gettimeofday (&mtv, NULL);
960 now->tv_sec = mtv.tv_sec;
961 now->tv_nsec = mtv.tv_usec*1000;
962 }
963 #elif HAVE_FTIME
thread_get_timespec(struct timespec * now)964 void thread_get_timespec (struct timespec *now)
965 {
966 struct timeb t;
967
968 ftime (&t);
969 now->tv_sec = t.time;
970 now->tv_nsec = t.millitm * 1000000;
971 }
972 #endif
973
974
thread_time_add_ms(struct timespec * ts,unsigned long value)975 void thread_time_add_ms (struct timespec *ts, unsigned long value)
976 {
977 if (value > 999)
978 {
979 ts->tv_sec += value/1000;
980 value %= 1000;
981 }
982 ts->tv_nsec += (value*1000000);
983 if (ts->tv_nsec > 999999999)
984 {
985 ts->tv_sec++;
986 ts->tv_nsec -= 1000000000;
987 }
988 }
989
990
thread_mtx_create_callback(void ** p,int alloc)991 int thread_mtx_create_callback (void **p, int alloc)
992 {
993 mutex_t *mutex;
994 if (p == NULL)
995 return -1;
996 if (alloc)
997 {
998 mutex = malloc (sizeof(mutex_t));
999 thread_mutex_create (mutex);
1000 *p = mutex;
1001 }
1002 else
1003 {
1004 mutex = *p;
1005 thread_mutex_destroy (mutex);
1006 free (mutex);
1007 *p = NULL;
1008 }
1009 return 0;
1010 }
1011
1012
thread_mtx_lock_callback(void ** p,int lock)1013 int thread_mtx_lock_callback (void **p, int lock)
1014 {
1015 mutex_t *mutex;
1016 if (p == NULL)
1017 return -1;
1018 mutex = *p;
1019 if (lock)
1020 {
1021 thread_mutex_lock (mutex);
1022 }
1023 else
1024 {
1025 thread_mutex_unlock (mutex);
1026 }
1027 return 0;
1028 }
1029