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