| head 1.25; |
| access; |
| symbols |
| libshout-2_0:1.24 |
| libshout-2_0b3:1.24 |
| libshout-2_0b2:1.24 |
| libshout_2_0b1:1.24 |
| libogg2-zerocopy:1.17.0.2 |
| branch-beta2-rewrite:1.5.0.2 |
| start:1.1.1.1 |
| xiph:1.1.1; |
| locks; strict; |
| comment @ * @; |
| |
| |
| 1.25 |
| date 2003.07.14.02.17.52; author brendan; state Exp; |
| branches; |
| next 1.24; |
| |
| 1.24 |
| date 2003.03.15.02.10.18; author msmith; state Exp; |
| branches; |
| next 1.23; |
| |
| 1.23 |
| date 2003.03.12.03.59.55; author karl; state Exp; |
| branches; |
| next 1.22; |
| |
| 1.22 |
| date 2003.03.09.22.56.46; author karl; state Exp; |
| branches; |
| next 1.21; |
| |
| 1.21 |
| date 2003.03.08.16.05.38; author karl; state Exp; |
| branches; |
| next 1.20; |
| |
| 1.20 |
| date 2003.03.04.15.31.34; author msmith; state Exp; |
| branches; |
| next 1.19; |
| |
| 1.19 |
| date 2003.01.17.09.01.04; author msmith; state Exp; |
| branches; |
| next 1.18; |
| |
| 1.18 |
| date 2002.12.29.09.55.50; author msmith; state Exp; |
| branches; |
| next 1.17; |
| |
| 1.17 |
| date 2002.11.22.13.00.44; author msmith; state Exp; |
| branches; |
| next 1.16; |
| |
| 1.16 |
| date 2002.09.24.07.09.08; author msmith; state Exp; |
| branches; |
| next 1.15; |
| |
| 1.15 |
| date 2002.08.16.14.23.17; author msmith; state Exp; |
| branches; |
| next 1.14; |
| |
| 1.14 |
| date 2002.08.13.01.08.15; author msmith; state Exp; |
| branches; |
| next 1.13; |
| |
| 1.13 |
| date 2002.08.10.03.22.44; author msmith; state Exp; |
| branches; |
| next 1.12; |
| |
| 1.12 |
| date 2002.08.09.06.52.07; author msmith; state Exp; |
| branches; |
| next 1.11; |
| |
| 1.11 |
| date 2002.08.05.14.48.03; author msmith; state Exp; |
| branches; |
| next 1.10; |
| |
| 1.10 |
| date 2002.08.03.08.14.56; author msmith; state Exp; |
| branches; |
| next 1.9; |
| |
| 1.9 |
| date 2002.04.30.06.50.47; author msmith; state Exp; |
| branches; |
| next 1.8; |
| |
| 1.8 |
| date 2002.03.05.23.59.38; author jack; state Exp; |
| branches; |
| next 1.7; |
| |
| 1.7 |
| date 2002.02.08.03.51.19; author jack; state Exp; |
| branches; |
| next 1.6; |
| |
| 1.6 |
| date 2002.02.07.01.04.09; author jack; state Exp; |
| branches; |
| next 1.5; |
| |
| 1.5 |
| date 2001.10.21.02.04.27; author jack; state Exp; |
| branches; |
| next 1.4; |
| |
| 1.4 |
| date 2001.10.20.22.27.52; author jack; state Exp; |
| branches; |
| next 1.3; |
| |
| 1.3 |
| date 2001.10.20.05.35.30; author jack; state Exp; |
| branches; |
| next 1.2; |
| |
| 1.2 |
| date 2001.10.20.03.39.10; author jack; state Exp; |
| branches; |
| next 1.1; |
| |
| 1.1 |
| date 2001.09.10.02.26.33; author jack; state Exp; |
| branches |
| 1.1.1.1; |
| next ; |
| |
| 1.1.1.1 |
| date 2001.09.10.02.26.33; author jack; state Exp; |
| branches; |
| next ; |
| |
| |
| desc |
| @@ |
| |
| |
| 1.25 |
| log |
| @Assign LGP to thread module |
| @ |
| text |
| @/* threads.c: Thread Abstraction Functions |
| * |
| * Copyright (c) 1999, 2000 the icecast team <team@@icecast.org> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the Free |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <time.h> |
| #include <sys/types.h> |
| |
| #include <pthread.h> |
| |
| #ifndef _WIN32 |
| #include <unistd.h> |
| #include <sys/time.h> |
| #else |
| #include <windows.h> |
| #include <winbase.h> |
| #include <implement.h> |
| #endif |
| |
| #include <signal.h> |
| |
| #include <thread/thread.h> |
| #include <avl/avl.h> |
| #ifdef THREAD_DEBUG |
| #include <log/log.h> |
| #endif |
| |
| #ifdef _WIN32 |
| #define __FUNCTION__ __FILE__ |
| #endif |
| |
| #ifdef THREAD_DEBUG |
| #define CATMODULE "thread" |
| #define LOG_ERROR(y) log_write(_logid, 1, CATMODULE "/", __FUNCTION__, y) |
| #define LOG_ERROR3(y, z1, z2, z3) log_write(_logid, 1, CATMODULE "/", __FUNCTION__, y, z1, z2, z3) |
| #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) |
| |
| #define LOG_WARN(y) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y) |
| #define LOG_WARN3(y, z1, z2, z3) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y, z1, z2, z3) |
| #define LOG_WARN5(y, z1, z2, z3, z4, z5) log_write(_logid, 2, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5) |
| #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) |
| |
| #define LOG_INFO(y) log_write(_logid, 3, CATMODULE "/", __FUNCTION__, y) |
| #define LOG_INFO4(y, z1, z2, z3, z4) log_write(_logid, 3, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4) |
| #define LOG_INFO5(y, z1, z2, z3, z4, z5) log_write(_logid, 3, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5) |
| |
| #define LOG_DEBUG(y) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y) |
| #define LOG_DEBUG2(y, z1, z2) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y, z1, z2) |
| #define LOG_DEBUG5(y, z1, z2, z3, z4, z5) log_write(_logid, 4, CATMODULE "/", __FUNCTION__, y, z1, z2, z3, z4, z5) |
| #endif |
| |
| /* thread starting structure */ |
| typedef struct thread_start_tag { |
| /* the real start routine and arg */ |
| void *(*start_routine)(void *); |
| void *arg; |
| |
| /* whether to create the threaded in detached state */ |
| int detached; |
| |
| /* the other stuff we need to make sure this thread is inserted into |
| ** the thread tree |
| */ |
| thread_type *thread; |
| pthread_t sys_thread; |
| } thread_start_t; |
| |
| static long _next_thread_id = 0; |
| static int _initialized = 0; |
| static avl_tree *_threadtree = NULL; |
| |
| #ifdef DEBUG_MUTEXES |
| static mutex_t _threadtree_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1, |
| PTHREAD_MUTEX_INITIALIZER}; |
| #else |
| static mutex_t _threadtree_mutex = { PTHREAD_MUTEX_INITIALIZER }; |
| #endif |
| |
| |
| |
| #ifdef DEBUG_MUTEXES |
| static int _logid = -1; |
| static long _next_mutex_id = 0; |
| |
| static avl_tree *_mutextree = NULL; |
| static mutex_t _mutextree_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1, |
| PTHREAD_MUTEX_INITIALIZER}; |
| #endif |
| |
| #ifdef DEBUG_MUTEXES |
| static mutex_t _library_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1, |
| PTHREAD_MUTEX_INITIALIZER}; |
| #else |
| static mutex_t _library_mutex = { PTHREAD_MUTEX_INITIALIZER }; |
| #endif |
| |
| /* INTERNAL FUNCTIONS */ |
| |
| /* avl tree functions */ |
| #ifdef DEBUG_MUTEXES |
| static int _compare_mutexes(void *compare_arg, void *a, void *b); |
| static int _free_mutex(void *key); |
| #endif |
| |
| static int _compare_threads(void *compare_arg, void *a, void *b); |
| static int _free_thread(void *key); |
| static int _free_thread_if_detached(void *key); |
| |
| /* mutex fuctions */ |
| static void _mutex_create(mutex_t *mutex); |
| static void _mutex_lock(mutex_t *mutex); |
| static void _mutex_unlock(mutex_t *mutex); |
| |
| /* misc thread stuff */ |
| static void *_start_routine(void *arg); |
| static void _catch_signals(void); |
| static void _block_signals(void); |
| |
| /* LIBRARY INITIALIZATION */ |
| |
| void thread_initialize(void) |
| { |
| thread_type *thread; |
| |
| /* set up logging */ |
| |
| #ifdef THREAD_DEBUG |
| log_initialize(); |
| _logid = log_open("thread.log"); |
| log_set_level(_logid, THREAD_DEBUG); |
| #endif |
| |
| #ifdef DEBUG_MUTEXES |
| /* create all the internal mutexes, and initialize the mutex tree */ |
| |
| _mutextree = avl_tree_new(_compare_mutexes, NULL); |
| |
| /* we have to create this one by hand, because there's no |
| ** mutextree_mutex to lock yet! |
| */ |
| _mutex_create(&_mutextree_mutex); |
| |
| _mutextree_mutex.mutex_id = _next_mutex_id++; |
| avl_insert(_mutextree, (void *)&_mutextree_mutex); |
| #endif |
| |
| thread_mutex_create(&_threadtree_mutex); |
| thread_mutex_create(&_library_mutex); |
| |
| /* initialize the thread tree and insert the main thread */ |
| |
| _threadtree = avl_tree_new(_compare_threads, NULL); |
| |
| thread = (thread_type *)malloc(sizeof(thread_type)); |
| |
| thread->thread_id = _next_thread_id++; |
| thread->line = 0; |
| thread->file = strdup("main.c"); |
| thread->sys_thread = pthread_self(); |
| thread->create_time = time(NULL); |
| thread->name = strdup("Main Thread"); |
| |
| avl_insert(_threadtree, (void *)thread); |
| |
| _catch_signals(); |
| |
| _initialized = 1; |
| } |
| |
| void thread_shutdown(void) |
| { |
| if (_initialized == 1) { |
| thread_mutex_destroy(&_library_mutex); |
| thread_mutex_destroy(&_threadtree_mutex); |
| #ifdef THREAD_DEBUG |
| thread_mutex_destroy(&_mutextree_mutex); |
| |
| avl_tree_free(_mutextree, _free_mutex); |
| #endif |
| avl_tree_free(_threadtree, _free_thread); |
| } |
| |
| #ifdef THREAD_DEBUG |
| log_close(_logid); |
| log_shutdown(); |
| #endif |
| |
| } |
| |
| /* |
| * Signals should be handled by the main thread, nowhere else. |
| * I'm using POSIX signal interface here, until someone tells me |
| * that I should use signal/sigset instead |
| * |
| * This function only valid for non-Win32 |
| */ |
| static void _block_signals(void) |
| { |
| #ifndef _WIN32 |
| sigset_t ss; |
| |
| sigfillset(&ss); |
| |
| /* These ones we want */ |
| sigdelset(&ss, SIGKILL); |
| sigdelset(&ss, SIGSTOP); |
| sigdelset(&ss, SIGTERM); |
| sigdelset(&ss, SIGSEGV); |
| sigdelset(&ss, SIGBUS); |
| if (pthread_sigmask(SIG_BLOCK, &ss, NULL) != 0) { |
| #ifdef THREAD_DEBUG |
| LOG_ERROR("Pthread_sigmask() failed for blocking signals"); |
| #endif |
| } |
| #endif |
| } |
| |
| /* |
| * Let the calling thread catch all the relevant signals |
| * |
| * This function only valid for non-Win32 |
| */ |
| static void _catch_signals(void) |
| { |
| #ifndef _WIN32 |
| sigset_t ss; |
| |
| sigemptyset(&ss); |
| |
| /* These ones should only be accepted by the signal handling thread (main thread) */ |
| sigaddset(&ss, SIGHUP); |
| sigaddset(&ss, SIGCHLD); |
| sigaddset(&ss, SIGINT); |
| sigaddset(&ss, SIGPIPE); |
| |
| if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) != 0) { |
| #ifdef THREAD_DEBUG |
| LOG_ERROR("pthread_sigmask() failed for catching signals!"); |
| #endif |
| } |
| #endif |
| } |
| |
| |
| thread_type *thread_create_c(char *name, void *(*start_routine)(void *), |
| void *arg, int detached, int line, char *file) |
| { |
| int created; |
| thread_type *thread; |
| thread_start_t *start; |
| |
| thread = (thread_type *)malloc(sizeof(thread_type)); |
| start = (thread_start_t *)malloc(sizeof(thread_start_t)); |
| thread->line = line; |
| thread->file = strdup(file); |
| |
| _mutex_lock(&_threadtree_mutex); |
| thread->thread_id = _next_thread_id++; |
| _mutex_unlock(&_threadtree_mutex); |
| |
| thread->name = strdup(name); |
| thread->create_time = time(NULL); |
| thread->detached = 0; |
| |
| start->start_routine = start_routine; |
| start->arg = arg; |
| start->thread = thread; |
| start->detached = detached; |
| |
| created = 0; |
| if (pthread_create(&thread->sys_thread, NULL, _start_routine, start) == 0) |
| created = 1; |
| #ifdef THREAD_DEBUG |
| else |
| LOG_ERROR("Could not create new thread"); |
| #endif |
| |
| if (created == 0) { |
| #ifdef THREAD_DEBUG |
| LOG_ERROR("System won't let me create more threads, giving up"); |
| #endif |
| return NULL; |
| } |
| |
| return thread; |
| } |
| |
| /* _mutex_create |
| ** |
| ** creates a mutex |
| */ |
| static void _mutex_create(mutex_t *mutex) |
| { |
| #ifdef DEBUG_MUTEXES |
| mutex->thread_id = MUTEX_STATE_NEVERLOCKED; |
| mutex->line = -1; |
| #endif |
| |
| pthread_mutex_init(&mutex->sys_mutex, NULL); |
| } |
| |
| void thread_mutex_create_c(mutex_t *mutex, int line, char *file) |
| { |
| _mutex_create(mutex); |
| |
| #ifdef DEBUG_MUTEXES |
| _mutex_lock(&_mutextree_mutex); |
| mutex->mutex_id = _next_mutex_id++; |
| avl_insert(_mutextree, (void *)mutex); |
| _mutex_unlock(&_mutextree_mutex); |
| #endif |
| } |
| |
| void thread_mutex_destroy (mutex_t *mutex) |
| { |
| pthread_mutex_destroy(&mutex->sys_mutex); |
| |
| #ifdef DEBUG_MUTEXES |
| _mutex_lock(&_mutextree_mutex); |
| avl_delete(_mutextree, mutex, _free_mutex); |
| _mutex_unlock(&_mutextree_mutex); |
| #endif |
| } |
| |
| void thread_mutex_lock_c(mutex_t *mutex, int line, char *file) |
| { |
| #ifdef DEBUG_MUTEXES |
| thread_type *th = thread_self(); |
| |
| if (!th) LOG_WARN("No mt record for %u in lock [%s:%d]", thread_self(), file, line); |
| |
| LOG_DEBUG5("Locking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1); |
| |
| # ifdef CHECK_MUTEXES |
| /* Just a little sanity checking to make sure that we're locking |
| ** mutexes correctly |
| */ |
| |
| if (th) { |
| int locks = 0; |
| avl_node *node; |
| mutex_t *tmutex; |
| |
| _mutex_lock(&_mutextree_mutex); |
| |
| node = avl_get_first (_mutextree); |
| |
| while (node) { |
| tmutex = (mutex_t *)node->key; |
| |
| if (tmutex->mutex_id == mutex->mutex_id) { |
| if (tmutex->thread_id == th->thread_id) { |
| /* Deadlock, same thread can't lock the same mutex twice */ |
| LOG_ERROR7("DEADLOCK AVOIDED (%d == %d) on mutex [%s] in file %s line %d by thread %d [%s]", |
| tmutex->thread_id, th->thread_id, mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name); |
| |
| _mutex_unlock(&_mutextree_mutex); |
| return; |
| } |
| } else if (tmutex->thread_id == th->thread_id) { |
| /* Mutex locked by this thread (not this mutex) */ |
| locks++; |
| } |
| |
| node = avl_get_next(node); |
| } |
| |
| if (locks > 0) { |
| /* Has already got a mutex locked */ |
| if (_multi_mutex.thread_id != th->thread_id) { |
| /* Tries to lock two mutexes, but has not got the double mutex, norty boy! */ |
| LOG_WARN("(%d != %d) Thread %d [%s] tries to lock a second mutex [%s] in file %s line %d, without locking double mutex!", |
| _multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line); |
| } |
| } |
| |
| _mutex_unlock(&_mutextree_mutex); |
| } |
| # endif /* CHECK_MUTEXES */ |
| |
| _mutex_lock(mutex); |
| |
| _mutex_lock(&_mutextree_mutex); |
| |
| LOG_DEBUG2("Locked %p by thread %d", mutex, th ? th->thread_id : -1); |
| mutex->line = line; |
| if (th) { |
| mutex->thread_id = th->thread_id; |
| } |
| |
| _mutex_unlock(&_mutextree_mutex); |
| #else |
| _mutex_lock(mutex); |
| #endif /* DEBUG_MUTEXES */ |
| } |
| |
| void thread_mutex_unlock_c(mutex_t *mutex, int line, char *file) |
| { |
| #ifdef DEBUG_MUTEXES |
| thread_type *th = thread_self(); |
| |
| if (!th) { |
| LOG_ERROR3("No record for %u in unlock [%s:%d]", thread_self(), file, line); |
| } |
| |
| LOG_DEBUG5("Unlocking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1); |
| |
| mutex->line = line; |
| |
| # ifdef CHECK_MUTEXES |
| if (th) { |
| int locks = 0; |
| avl_node *node; |
| mutex_t *tmutex; |
| |
| _mutex_lock(&_mutextree_mutex); |
| |
| while (node) { |
| tmutex = (mutex_t *)node->key; |
| |
| if (tmutex->mutex_id == mutex->mutex_id) { |
| if (tmutex->thread_id != th->thread_id) { |
| LOG_ERROR7("ILLEGAL UNLOCK (%d != %d) on mutex [%s] in file %s line %d by thread %d [%s]", tmutex->thread_id, th->thread_id, |
| mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name); |
| _mutex_unlock(&_mutextree_mutex); |
| return; |
| } |
| } else if (tmutex->thread_id == th->thread_id) { |
| locks++; |
| } |
| |
| node = avl_get_next (node); |
| } |
| |
| if ((locks > 0) && (_multi_mutex.thread_id != th->thread_id)) { |
| /* Don't have double mutex, has more than this mutex left */ |
| |
| LOG_WARN("(%d != %d) Thread %d [%s] tries to unlock a mutex [%s] in file %s line %d, without owning double mutex!", |
| _multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line); |
| } |
| |
| _mutex_unlock(&_mutextree_mutex); |
| } |
| # endif /* CHECK_MUTEXES */ |
| |
| _mutex_unlock(mutex); |
| |
| _mutex_lock(&_mutextree_mutex); |
| |
| LOG_DEBUG2("Unlocked %p by thread %d", mutex, th ? th->thread_id : -1); |
| mutex->line = -1; |
| if (mutex->thread_id == th->thread_id) { |
| mutex->thread_id = MUTEX_STATE_NOTLOCKED; |
| } |
| |
| _mutex_unlock(&_mutextree_mutex); |
| #else |
| _mutex_unlock(mutex); |
| #endif /* DEBUG_MUTEXES */ |
| } |
| |
| void thread_cond_create_c(cond_t *cond, int line, char *file) |
| { |
| pthread_cond_init(&cond->sys_cond, NULL); |
| pthread_mutex_init(&cond->cond_mutex, NULL); |
| } |
| |
| void thread_cond_destroy(cond_t *cond) |
| { |
| pthread_mutex_destroy(&cond->cond_mutex); |
| pthread_cond_destroy(&cond->sys_cond); |
| } |
| |
| void thread_cond_signal_c(cond_t *cond, int line, char *file) |
| { |
| pthread_cond_signal(&cond->sys_cond); |
| } |
| |
| void thread_cond_broadcast_c(cond_t *cond, int line, char *file) |
| { |
| pthread_cond_broadcast(&cond->sys_cond); |
| } |
| |
| void thread_cond_timedwait_c(cond_t *cond, int millis, int line, char *file) |
| { |
| struct timespec time; |
| |
| time.tv_sec = millis/1000; |
| time.tv_nsec = (millis - time.tv_sec*1000)*1000000; |
| |
| pthread_mutex_lock(&cond->cond_mutex); |
| pthread_cond_timedwait(&cond->sys_cond, &cond->cond_mutex, &time); |
| pthread_mutex_unlock(&cond->cond_mutex); |
| } |
| |
| void thread_cond_wait_c(cond_t *cond, int line, char *file) |
| { |
| pthread_mutex_lock(&cond->cond_mutex); |
| pthread_cond_wait(&cond->sys_cond, &cond->cond_mutex); |
| pthread_mutex_unlock(&cond->cond_mutex); |
| } |
| |
| void thread_rwlock_create_c(rwlock_t *rwlock, int line, char *file) |
| { |
| pthread_rwlock_init(&rwlock->sys_rwlock, NULL); |
| } |
| |
| void thread_rwlock_destroy(rwlock_t *rwlock) |
| { |
| pthread_rwlock_destroy(&rwlock->sys_rwlock); |
| } |
| |
| void thread_rwlock_rlock_c(rwlock_t *rwlock, int line, char *file) |
| { |
| pthread_rwlock_rdlock(&rwlock->sys_rwlock); |
| } |
| |
| void thread_rwlock_wlock_c(rwlock_t *rwlock, int line, char *file) |
| { |
| pthread_rwlock_wrlock(&rwlock->sys_rwlock); |
| } |
| |
| void thread_rwlock_unlock_c(rwlock_t *rwlock, int line, char *file) |
| { |
| pthread_rwlock_unlock(&rwlock->sys_rwlock); |
| } |
| |
| void thread_exit_c(int val, int line, char *file) |
| { |
| thread_type *th = thread_self(); |
| |
| #if defined(DEBUG_MUTEXES) && defined(CHECK_MUTEXES) |
| if (th) { |
| avl_node *node; |
| mutex_t *tmutex; |
| char name[40]; |
| |
| _mutex_lock(&_mutextree_mutex); |
| |
| while (node) { |
| tmutex = (mutex_t *)node->key; |
| |
| if (tmutex->thread_id == th->thread_id) { |
| LOG_WARN("Thread %d [%s] exiting in file %s line %d, without unlocking mutex [%s]", |
| th->thread_id, th->name, file, line, mutex_to_string(tmutex, name)); |
| } |
| |
| node = avl_get_next (node); |
| } |
| |
| _mutex_unlock(&_mutextree_mutex); |
| } |
| #endif |
| |
| if (th) { |
| #ifdef THREAD_DEBUG |
| LOG_INFO4("Removing thread %d [%s] started at [%s:%d], reason: 'Thread Exited'", th->thread_id, th->name, th->file, th->line); |
| #endif |
| |
| _mutex_lock(&_threadtree_mutex); |
| avl_delete(_threadtree, th, _free_thread_if_detached); |
| _mutex_unlock(&_threadtree_mutex); |
| } |
| |
| pthread_exit((void *)val); |
| } |
| |
| /* sleep for a number of microseconds */ |
| void thread_sleep(unsigned long len) |
| { |
| #ifdef _WIN32 |
| Sleep(len / 1000); |
| #else |
| # ifdef HAVE_NANOSLEEP |
| struct timespec time_sleep; |
| struct timespec time_remaining; |
| int ret; |
| |
| time_sleep.tv_sec = len / 1000000; |
| time_sleep.tv_nsec = (len % 1000000) * 1000; |
| |
| ret = nanosleep(&time_sleep, &time_remaining); |
| while (ret != 0 && errno == EINTR) { |
| time_sleep.tv_sec = time_remaining.tv_sec; |
| time_sleep.tv_nsec = time_remaining.tv_nsec; |
| |
| ret = nanosleep(&time_sleep, &time_remaining); |
| } |
| # else |
| struct timeval tv; |
| |
| tv.tv_sec = len / 1000000; |
| tv.tv_usec = (len % 1000000); |
| |
| select(0, NULL, NULL, NULL, &tv); |
| # endif |
| #endif |
| } |
| |
| static void *_start_routine(void *arg) |
| { |
| thread_start_t *start = (thread_start_t *)arg; |
| void *(*start_routine)(void *) = start->start_routine; |
| void *real_arg = start->arg; |
| thread_type *thread = start->thread; |
| int detach = start->detached; |
| |
| _block_signals(); |
| |
| free(start); |
| |
| /* insert thread into thread tree here */ |
| _mutex_lock(&_threadtree_mutex); |
| thread->sys_thread = pthread_self(); |
| avl_insert(_threadtree, (void *)thread); |
| _mutex_unlock(&_threadtree_mutex); |
| |
| #ifdef THREAD_DEBUG |
| LOG_INFO4("Added thread %d [%s] started at [%s:%d]", thread->thread_id, thread->name, thread->file, thread->line); |
| #endif |
| |
| if (detach) { |
| pthread_detach(thread->sys_thread); |
| thread->detached = 1; |
| } |
| pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
| |
| /* call the real start_routine and start the thread |
| ** this should never exit! |
| */ |
| (start_routine)(real_arg); |
| |
| #ifdef THREAD_DEBUG |
| LOG_WARN("Thread x should never exit from here!!!"); |
| #endif |
| |
| return NULL; |
| } |
| |
| thread_type *thread_self(void) |
| { |
| avl_node *node; |
| thread_type *th; |
| pthread_t sys_thread = pthread_self(); |
| |
| _mutex_lock(&_threadtree_mutex); |
| |
| if (_threadtree == NULL) { |
| #ifdef THREAD_DEBUG |
| LOG_WARN("Thread tree is empty, this must be wrong!"); |
| #endif |
| _mutex_unlock(&_threadtree_mutex); |
| return NULL; |
| } |
| |
| node = avl_get_first(_threadtree); |
| |
| while (node) { |
| th = (thread_type *)node->key; |
| |
| if (th && pthread_equal(sys_thread, th->sys_thread)) { |
| _mutex_unlock(&_threadtree_mutex); |
| return th; |
| } |
| |
| node = avl_get_next(node); |
| } |
| _mutex_unlock(&_threadtree_mutex); |
| |
| |
| #ifdef THREAD_DEBUG |
| LOG_ERROR("Nonexistant thread alive..."); |
| #endif |
| |
| return NULL; |
| } |
| |
| void thread_rename(const char *name) |
| { |
| thread_type *th; |
| |
| th = thread_self(); |
| if (th->name) free(th->name); |
| |
| th->name = strdup(name); |
| } |
| |
| static void _mutex_lock(mutex_t *mutex) |
| { |
| pthread_mutex_lock(&mutex->sys_mutex); |
| } |
| |
| static void _mutex_unlock(mutex_t *mutex) |
| { |
| pthread_mutex_unlock(&mutex->sys_mutex); |
| } |
| |
| |
| void thread_library_lock(void) |
| { |
| _mutex_lock(&_library_mutex); |
| } |
| |
| void thread_library_unlock(void) |
| { |
| _mutex_unlock(&_library_mutex); |
| } |
| |
| void thread_join(thread_type *thread) |
| { |
| void *ret; |
| int i; |
| |
| i = pthread_join(thread->sys_thread, &ret); |
| _mutex_lock(&_threadtree_mutex); |
| avl_delete(_threadtree, thread, _free_thread); |
| _mutex_unlock(&_threadtree_mutex); |
| } |
| |
| /* AVL tree functions */ |
| |
| #ifdef DEBUG_MUTEXES |
| static int _compare_mutexes(void *compare_arg, void *a, void *b) |
| { |
| mutex_t *m1, *m2; |
| |
| m1 = (mutex_t *)a; |
| m2 = (mutex_t *)b; |
| |
| if (m1->mutex_id > m2->mutex_id) |
| return 1; |
| if (m1->mutex_id < m2->mutex_id) |
| return -1; |
| return 0; |
| } |
| #endif |
| |
| static int _compare_threads(void *compare_arg, void *a, void *b) |
| { |
| thread_type *t1, *t2; |
| |
| t1 = (thread_type *)a; |
| t2 = (thread_type *)b; |
| |
| if (t1->thread_id > t2->thread_id) |
| return 1; |
| if (t1->thread_id < t2->thread_id) |
| return -1; |
| return 0; |
| } |
| |
| #ifdef DEBUG_MUTEXES |
| static int _free_mutex(void *key) |
| { |
| mutex_t *m; |
| |
| m = (mutex_t *)key; |
| |
| if (m && m->file) { |
| free(m->file); |
| m->file = NULL; |
| } |
| |
| /* all mutexes are static. don't need to free them */ |
| |
| return 1; |
| } |
| #endif |
| |
| static int _free_thread(void *key) |
| { |
| thread_type *t; |
| |
| t = (thread_type *)key; |
| |
| if (t->file) |
| free(t->file); |
| if (t->name) |
| free(t->name); |
| |
| free(t); |
| |
| return 1; |
| } |
| |
| static int _free_thread_if_detached(void *key) |
| { |
| thread_type *t = key; |
| if(t->detached) |
| return _free_thread(key); |
| return 1; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| @ |
| |
| |
| 1.24 |
| log |
| @Brendan was getting pissed off about inconsistent indentation styles. |
| Convert all tabs to 4 spaces. All code must now use 4 space indents. |
| @ |
| text |
| @d1 18 |
| a18 19 |
| /* threads.c |
| ** - Thread Abstraction Functions |
| ** |
| ** Copyright (c) 1999, 2000 the icecast team |
| ** |
| ** This program is free software; you can redistribute it and/or |
| ** modify it under the terms of the GNU General Public License |
| ** as published by the Free Software Foundation; either version 2 |
| ** of the License, or (at your option) any latfer version. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU General Public License for more details. |
| ** |
| ** You should have received a copy of the GNU General Public License |
| ** along with this program; if not, write to the Free Software |
| ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| */ |
| @ |
| |
| |
| 1.23 |
| log |
| @avoid freeing a thread structure a second time. |
| @ |
| text |
| @d77 12 |
| a88 12 |
| /* the real start routine and arg */ |
| void *(*start_routine)(void *); |
| void *arg; |
| |
| /* whether to create the threaded in detached state */ |
| int detached; |
| |
| /* the other stuff we need to make sure this thread is inserted into |
| ** the thread tree |
| */ |
| thread_type *thread; |
| pthread_t sys_thread; |
| d146 1 |
| a146 1 |
| thread_type *thread; |
| d148 1 |
| a148 1 |
| /* set up logging */ |
| d151 3 |
| a153 3 |
| log_initialize(); |
| _logid = log_open("thread.log"); |
| log_set_level(_logid, THREAD_DEBUG); |
| d157 1 |
| a157 1 |
| /* create all the internal mutexes, and initialize the mutex tree */ |
| d159 1 |
| a159 1 |
| _mutextree = avl_tree_new(_compare_mutexes, NULL); |
| d161 4 |
| a164 4 |
| /* we have to create this one by hand, because there's no |
| ** mutextree_mutex to lock yet! |
| */ |
| _mutex_create(&_mutextree_mutex); |
| d166 2 |
| a167 2 |
| _mutextree_mutex.mutex_id = _next_mutex_id++; |
| avl_insert(_mutextree, (void *)&_mutextree_mutex); |
| d170 2 |
| a171 2 |
| thread_mutex_create(&_threadtree_mutex); |
| thread_mutex_create(&_library_mutex); |
| d173 1 |
| a173 1 |
| /* initialize the thread tree and insert the main thread */ |
| d175 1 |
| a175 1 |
| _threadtree = avl_tree_new(_compare_threads, NULL); |
| d177 1 |
| a177 1 |
| thread = (thread_type *)malloc(sizeof(thread_type)); |
| d179 6 |
| a184 6 |
| thread->thread_id = _next_thread_id++; |
| thread->line = 0; |
| thread->file = strdup("main.c"); |
| thread->sys_thread = pthread_self(); |
| thread->create_time = time(NULL); |
| thread->name = strdup("Main Thread"); |
| d186 1 |
| a186 1 |
| avl_insert(_threadtree, (void *)thread); |
| d188 1 |
| a188 1 |
| _catch_signals(); |
| d190 1 |
| a190 1 |
| _initialized = 1; |
| d195 3 |
| a197 3 |
| if (_initialized == 1) { |
| thread_mutex_destroy(&_library_mutex); |
| thread_mutex_destroy(&_threadtree_mutex); |
| d199 3 |
| a201 3 |
| thread_mutex_destroy(&_mutextree_mutex); |
| |
| avl_tree_free(_mutextree, _free_mutex); |
| d203 2 |
| a204 2 |
| avl_tree_free(_threadtree, _free_thread); |
| } |
| d207 2 |
| a208 2 |
| log_close(_logid); |
| log_shutdown(); |
| d271 8 |
| a278 12 |
| int created; |
| thread_type *thread; |
| thread_start_t *start; |
| |
| thread = (thread_type *)malloc(sizeof(thread_type)); |
| start = (thread_start_t *)malloc(sizeof(thread_start_t)); |
| thread->line = line; |
| thread->file = strdup(file); |
| |
| _mutex_lock(&_threadtree_mutex); |
| thread->thread_id = _next_thread_id++; |
| _mutex_unlock(&_threadtree_mutex); |
| d280 6 |
| a285 2 |
| thread->name = strdup(name); |
| thread->create_time = time(NULL); |
| d288 4 |
| a291 4 |
| start->start_routine = start_routine; |
| start->arg = arg; |
| start->thread = thread; |
| start->detached = detached; |
| d293 3 |
| a295 3 |
| created = 0; |
| if (pthread_create(&thread->sys_thread, NULL, _start_routine, start) == 0) |
| created = 1; |
| d297 2 |
| a298 2 |
| else |
| LOG_ERROR("Could not create new thread"); |
| d301 1 |
| a301 1 |
| if (created == 0) { |
| d303 1 |
| a303 1 |
| LOG_ERROR("System won't let me create more threads, giving up"); |
| d305 2 |
| a306 2 |
| return NULL; |
| } |
| d308 1 |
| a308 1 |
| return thread; |
| d318 2 |
| a319 2 |
| mutex->thread_id = MUTEX_STATE_NEVERLOCKED; |
| mutex->line = -1; |
| d322 1 |
| a322 1 |
| pthread_mutex_init(&mutex->sys_mutex, NULL); |
| d327 1 |
| a327 1 |
| _mutex_create(mutex); |
| d330 4 |
| a333 4 |
| _mutex_lock(&_mutextree_mutex); |
| mutex->mutex_id = _next_mutex_id++; |
| avl_insert(_mutextree, (void *)mutex); |
| _mutex_unlock(&_mutextree_mutex); |
| d339 1 |
| a339 1 |
| pthread_mutex_destroy(&mutex->sys_mutex); |
| d342 3 |
| a344 3 |
| _mutex_lock(&_mutextree_mutex); |
| avl_delete(_mutextree, mutex, _free_mutex); |
| _mutex_unlock(&_mutextree_mutex); |
| d351 1 |
| a351 1 |
| thread_type *th = thread_self(); |
| d353 1 |
| a353 1 |
| if (!th) LOG_WARN("No mt record for %u in lock [%s:%d]", thread_self(), file, line); |
| d355 1 |
| a355 1 |
| LOG_DEBUG5("Locking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1); |
| d358 44 |
| a401 44 |
| /* Just a little sanity checking to make sure that we're locking |
| ** mutexes correctly |
| */ |
| |
| if (th) { |
| int locks = 0; |
| avl_node *node; |
| mutex_t *tmutex; |
| |
| _mutex_lock(&_mutextree_mutex); |
| |
| node = avl_get_first (_mutextree); |
| |
| while (node) { |
| tmutex = (mutex_t *)node->key; |
| |
| if (tmutex->mutex_id == mutex->mutex_id) { |
| if (tmutex->thread_id == th->thread_id) { |
| /* Deadlock, same thread can't lock the same mutex twice */ |
| LOG_ERROR7("DEADLOCK AVOIDED (%d == %d) on mutex [%s] in file %s line %d by thread %d [%s]", |
| tmutex->thread_id, th->thread_id, mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name); |
| |
| _mutex_unlock(&_mutextree_mutex); |
| return; |
| } |
| } else if (tmutex->thread_id == th->thread_id) { |
| /* Mutex locked by this thread (not this mutex) */ |
| locks++; |
| } |
| |
| node = avl_get_next(node); |
| } |
| |
| if (locks > 0) { |
| /* Has already got a mutex locked */ |
| if (_multi_mutex.thread_id != th->thread_id) { |
| /* Tries to lock two mutexes, but has not got the double mutex, norty boy! */ |
| LOG_WARN("(%d != %d) Thread %d [%s] tries to lock a second mutex [%s] in file %s line %d, without locking double mutex!", |
| _multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line); |
| } |
| } |
| |
| _mutex_unlock(&_mutextree_mutex); |
| } |
| d403 10 |
| a412 10 |
| |
| _mutex_lock(mutex); |
| |
| _mutex_lock(&_mutextree_mutex); |
| |
| LOG_DEBUG2("Locked %p by thread %d", mutex, th ? th->thread_id : -1); |
| mutex->line = line; |
| if (th) { |
| mutex->thread_id = th->thread_id; |
| } |
| d414 1 |
| a414 1 |
| _mutex_unlock(&_mutextree_mutex); |
| d416 1 |
| a416 1 |
| _mutex_lock(mutex); |
| d423 1 |
| a423 1 |
| thread_type *th = thread_self(); |
| d425 3 |
| a427 3 |
| if (!th) { |
| LOG_ERROR3("No record for %u in unlock [%s:%d]", thread_self(), file, line); |
| } |
| d429 1 |
| a429 1 |
| LOG_DEBUG5("Unlocking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1); |
| d431 1 |
| a431 1 |
| mutex->line = line; |
| d434 20 |
| a453 30 |
| if (th) { |
| int locks = 0; |
| avl_node *node; |
| mutex_t *tmutex; |
| |
| _mutex_lock(&_mutextree_mutex); |
| |
| while (node) { |
| tmutex = (mutex_t *)node->key; |
| |
| if (tmutex->mutex_id == mutex->mutex_id) { |
| if (tmutex->thread_id != th->thread_id) { |
| LOG_ERROR7("ILLEGAL UNLOCK (%d != %d) on mutex [%s] in file %s line %d by thread %d [%s]", tmutex->thread_id, th->thread_id, |
| mutex->name ? mutex->name : "undefined", file, line, th->thread_id, th->name); |
| _mutex_unlock(&_mutextree_mutex); |
| return; |
| } |
| } else if (tmutex->thread_id == th->thread_id) { |
| locks++; |
| } |
| |
| node = avl_get_next (node); |
| } |
| |
| if ((locks > 0) && (_multi_mutex.thread_id != th->thread_id)) { |
| /* Don't have double mutex, has more than this mutex left */ |
| |
| LOG_WARN("(%d != %d) Thread %d [%s] tries to unlock a mutex [%s] in file %s line %d, without owning double mutex!", |
| _multi_mutex.thread_id, th->thread_id, th->thread_id, th->name, mutex->name ? mutex->name : "undefined", file, line); |
| } |
| d455 12 |
| a466 2 |
| _mutex_unlock(&_mutextree_mutex); |
| } |
| d469 1 |
| a469 1 |
| _mutex_unlock(mutex); |
| d471 1 |
| a471 1 |
| _mutex_lock(&_mutextree_mutex); |
| d473 5 |
| a477 5 |
| LOG_DEBUG2("Unlocked %p by thread %d", mutex, th ? th->thread_id : -1); |
| mutex->line = -1; |
| if (mutex->thread_id == th->thread_id) { |
| mutex->thread_id = MUTEX_STATE_NOTLOCKED; |
| } |
| d479 1 |
| a479 1 |
| _mutex_unlock(&_mutextree_mutex); |
| d481 1 |
| a481 1 |
| _mutex_unlock(mutex); |
| d487 2 |
| a488 2 |
| pthread_cond_init(&cond->sys_cond, NULL); |
| pthread_mutex_init(&cond->cond_mutex, NULL); |
| d493 2 |
| a494 2 |
| pthread_mutex_destroy(&cond->cond_mutex); |
| pthread_cond_destroy(&cond->sys_cond); |
| d499 1 |
| a499 1 |
| pthread_cond_signal(&cond->sys_cond); |
| d504 1 |
| a504 1 |
| pthread_cond_broadcast(&cond->sys_cond); |
| d521 3 |
| a523 3 |
| pthread_mutex_lock(&cond->cond_mutex); |
| pthread_cond_wait(&cond->sys_cond, &cond->cond_mutex); |
| pthread_mutex_unlock(&cond->cond_mutex); |
| d528 1 |
| a528 1 |
| pthread_rwlock_init(&rwlock->sys_rwlock, NULL); |
| d533 1 |
| a533 1 |
| pthread_rwlock_destroy(&rwlock->sys_rwlock); |
| d538 1 |
| a538 1 |
| pthread_rwlock_rdlock(&rwlock->sys_rwlock); |
| d543 1 |
| a543 1 |
| pthread_rwlock_wrlock(&rwlock->sys_rwlock); |
| d548 1 |
| a548 1 |
| pthread_rwlock_unlock(&rwlock->sys_rwlock); |
| d553 1 |
| a553 1 |
| thread_type *th = thread_self(); |
| d556 14 |
| a569 4 |
| if (th) { |
| avl_node *node; |
| mutex_t *tmutex; |
| char name[40]; |
| d571 2 |
| a572 4 |
| _mutex_lock(&_mutextree_mutex); |
| |
| while (node) { |
| tmutex = (mutex_t *)node->key; |
| d574 2 |
| a575 10 |
| if (tmutex->thread_id == th->thread_id) { |
| LOG_WARN("Thread %d [%s] exiting in file %s line %d, without unlocking mutex [%s]", |
| th->thread_id, th->name, file, line, mutex_to_string(tmutex, name)); |
| } |
| |
| node = avl_get_next (node); |
| } |
| |
| _mutex_unlock(&_mutextree_mutex); |
| } |
| d577 2 |
| a578 2 |
| |
| if (th) { |
| d580 1 |
| a580 1 |
| LOG_INFO4("Removing thread %d [%s] started at [%s:%d], reason: 'Thread Exited'", th->thread_id, th->name, th->file, th->line); |
| d583 6 |
| a588 6 |
| _mutex_lock(&_threadtree_mutex); |
| avl_delete(_threadtree, th, _free_thread_if_detached); |
| _mutex_unlock(&_threadtree_mutex); |
| } |
| |
| pthread_exit((void *)val); |
| d595 1 |
| a595 1 |
| Sleep(len / 1000); |
| d598 14 |
| a611 14 |
| struct timespec time_sleep; |
| struct timespec time_remaining; |
| int ret; |
| |
| time_sleep.tv_sec = len / 1000000; |
| time_sleep.tv_nsec = (len % 1000000) * 1000; |
| |
| ret = nanosleep(&time_sleep, &time_remaining); |
| while (ret != 0 && errno == EINTR) { |
| time_sleep.tv_sec = time_remaining.tv_sec; |
| time_sleep.tv_nsec = time_remaining.tv_nsec; |
| |
| ret = nanosleep(&time_sleep, &time_remaining); |
| } |
| d613 1 |
| a613 1 |
| struct timeval tv; |
| d615 2 |
| a616 2 |
| tv.tv_sec = len / 1000000; |
| tv.tv_usec = (len % 1000000); |
| d618 1 |
| a618 1 |
| select(0, NULL, NULL, NULL, &tv); |
| d625 4 |
| a628 4 |
| thread_start_t *start = (thread_start_t *)arg; |
| void *(*start_routine)(void *) = start->start_routine; |
| void *real_arg = start->arg; |
| thread_type *thread = start->thread; |
| d631 1 |
| a631 1 |
| _block_signals(); |
| d633 1 |
| a633 1 |
| free(start); |
| d635 5 |
| a639 5 |
| /* insert thread into thread tree here */ |
| _mutex_lock(&_threadtree_mutex); |
| thread->sys_thread = pthread_self(); |
| avl_insert(_threadtree, (void *)thread); |
| _mutex_unlock(&_threadtree_mutex); |
| d642 1 |
| a642 1 |
| LOG_INFO4("Added thread %d [%s] started at [%s:%d]", thread->thread_id, thread->name, thread->file, thread->line); |
| d645 2 |
| a646 2 |
| if (detach) { |
| pthread_detach(thread->sys_thread); |
| d648 2 |
| a649 2 |
| } |
| pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
| d651 4 |
| a654 4 |
| /* call the real start_routine and start the thread |
| ** this should never exit! |
| */ |
| (start_routine)(real_arg); |
| d657 1 |
| a657 1 |
| LOG_WARN("Thread x should never exit from here!!!"); |
| d660 1 |
| a660 1 |
| return NULL; |
| d665 3 |
| a667 3 |
| avl_node *node; |
| thread_type *th; |
| pthread_t sys_thread = pthread_self(); |
| d669 1 |
| a669 1 |
| _mutex_lock(&_threadtree_mutex); |
| d671 1 |
| a671 1 |
| if (_threadtree == NULL) { |
| d673 1 |
| a673 1 |
| LOG_WARN("Thread tree is empty, this must be wrong!"); |
| d675 17 |
| a691 17 |
| _mutex_unlock(&_threadtree_mutex); |
| return NULL; |
| } |
| |
| node = avl_get_first(_threadtree); |
| |
| while (node) { |
| th = (thread_type *)node->key; |
| |
| if (th && pthread_equal(sys_thread, th->sys_thread)) { |
| _mutex_unlock(&_threadtree_mutex); |
| return th; |
| } |
| |
| node = avl_get_next(node); |
| } |
| _mutex_unlock(&_threadtree_mutex); |
| d695 1 |
| a695 1 |
| LOG_ERROR("Nonexistant thread alive..."); |
| d697 2 |
| a698 2 |
| |
| return NULL; |
| d703 1 |
| a703 1 |
| thread_type *th; |
| d705 2 |
| a706 2 |
| th = thread_self(); |
| if (th->name) free(th->name); |
| d708 1 |
| a708 1 |
| th->name = strdup(name); |
| d713 1 |
| a713 1 |
| pthread_mutex_lock(&mutex->sys_mutex); |
| d718 1 |
| a718 1 |
| pthread_mutex_unlock(&mutex->sys_mutex); |
| d724 1 |
| a724 1 |
| _mutex_lock(&_library_mutex); |
| d729 1 |
| a729 1 |
| _mutex_unlock(&_library_mutex); |
| d734 2 |
| a735 2 |
| void *ret; |
| int i; |
| d737 1 |
| a737 1 |
| i = pthread_join(thread->sys_thread, &ret); |
| d748 1 |
| a748 1 |
| mutex_t *m1, *m2; |
| d750 2 |
| a751 2 |
| m1 = (mutex_t *)a; |
| m2 = (mutex_t *)b; |
| d753 5 |
| a757 5 |
| if (m1->mutex_id > m2->mutex_id) |
| return 1; |
| if (m1->mutex_id < m2->mutex_id) |
| return -1; |
| return 0; |
| d763 1 |
| a763 1 |
| thread_type *t1, *t2; |
| d765 2 |
| a766 2 |
| t1 = (thread_type *)a; |
| t2 = (thread_type *)b; |
| d768 5 |
| a772 5 |
| if (t1->thread_id > t2->thread_id) |
| return 1; |
| if (t1->thread_id < t2->thread_id) |
| return -1; |
| return 0; |
| d778 1 |
| a778 1 |
| mutex_t *m; |
| d780 1 |
| a780 1 |
| m = (mutex_t *)key; |
| d782 4 |
| a785 4 |
| if (m && m->file) { |
| free(m->file); |
| m->file = NULL; |
| } |
| d787 1 |
| a787 1 |
| /* all mutexes are static. don't need to free them */ |
| d789 1 |
| a789 1 |
| return 1; |
| d795 1 |
| a795 1 |
| thread_type *t; |
| d797 1 |
| a797 1 |
| t = (thread_type *)key; |
| d799 4 |
| a802 4 |
| if (t->file) |
| free(t->file); |
| if (t->name) |
| free(t->name); |
| d804 1 |
| a804 1 |
| free(t); |
| d806 1 |
| a806 1 |
| return 1; |
| @ |
| |
| |
| 1.22 |
| log |
| @reduce include file namespace clutter for libshout and the associated |
| smaller libs. |
| @ |
| text |
| @a740 1 |
| _free_thread(thread); |
| @ |
| |
| |
| 1.21 |
| log |
| @include the automake config.h file if the application defines one |
| @ |
| text |
| @d45 2 |
| a46 2 |
| #include "thread.h" |
| #include "avl.h" |
| d48 1 |
| a48 1 |
| #include "log.h" |
| @ |
| |
| |
| 1.20 |
| log |
| @Make various thread structures omit the bits only used in debug mode. |
| Some of these are pretty heavily used, so saving 10-20 bytes each can be |
| quite significant. |
| |
| No functional differences. |
| @ |
| text |
| @d21 4 |
| @ |
| |
| |
| 1.19 |
| log |
| @Fix some warnings, fix cflags. |
| @ |
| text |
| @a86 1 |
| static int _logid = -1; |
| d90 2 |
| d94 4 |
| d99 3 |
| d103 1 |
| d107 3 |
| d112 3 |
| d119 1 |
| d121 3 |
| a124 1 |
| static int _free_mutex(void *key); |
| d152 1 |
| a161 1 |
| #ifdef DEBUG_MUTEXES |
| d194 1 |
| d198 1 |
| d313 1 |
| d316 1 |
| a521 2 |
| static int rwlocknum = 0; |
| |
| d742 1 |
| d756 1 |
| d772 1 |
| d788 1 |
| @ |
| |
| |
| 1.18 |
| log |
| @Rename thread_t to avoid problems on OS X |
| @ |
| text |
| @d91 2 |
| a92 1 |
| static mutex_t _threadtree_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1 }; |
| d96 4 |
| a99 2 |
| static mutex_t _mutextree_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1 }; |
| static mutex_t _library_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1 }; |
| @ |
| |
| |
| 1.17 |
| log |
| @Lots of bugfixes contributed by Karl Heyes. |
| @ |
| text |
| @d83 1 |
| a83 1 |
| thread_t *thread; |
| d121 1 |
| a121 1 |
| thread_t *thread; |
| d152 1 |
| a152 1 |
| thread = (thread_t *)malloc(sizeof(thread_t)); |
| d241 2 |
| a242 1 |
| thread_t *thread_create_c(char *name, void *(*start_routine)(void *), void *arg, int detached, int line, char *file) |
| d245 1 |
| a245 1 |
| thread_t *thread; |
| d248 1 |
| a248 1 |
| thread = (thread_t *)malloc(sizeof(thread_t)); |
| d322 1 |
| a322 1 |
| thread_t *th = thread_self(); |
| d394 1 |
| a394 1 |
| thread_t *th = thread_self(); |
| d526 1 |
| a526 1 |
| thread_t *th = thread_self(); |
| d601 1 |
| a601 1 |
| thread_t *thread = start->thread; |
| d636 1 |
| a636 1 |
| thread_t *thread_self(void) |
| d639 1 |
| a639 1 |
| thread_t *th; |
| d655 1 |
| a655 1 |
| th = (thread_t *)node->key; |
| d676 1 |
| a676 1 |
| thread_t *th; |
| d705 1 |
| a705 1 |
| void thread_join(thread_t *thread) |
| d735 1 |
| a735 1 |
| thread_t *t1, *t2; |
| d737 2 |
| a738 2 |
| t1 = (thread_t *)a; |
| t2 = (thread_t *)b; |
| d765 1 |
| a765 1 |
| thread_t *t; |
| d767 1 |
| a767 1 |
| t = (thread_t *)key; |
| d781 1 |
| a781 1 |
| thread_t *t = key; |
| @ |
| |
| |
| 1.16 |
| log |
| @Bugfix: thread_join is often called after a thread has already exited, which it |
| does using thread_exit(). thread_exit() was freeing the thread structure, so |
| thread_join was using freed memory. Rearrange things so that if the thread |
| is detached, the freeing happens in thread_join instead. |
| @ |
| text |
| @d710 3 |
| @ |
| |
| |
| 1.15 |
| log |
| @Liberally sprinkle #ifdef THREAD_DEBUG around so libshout doesn't need to link |
| with it. |
| @ |
| text |
| @d105 1 |
| d258 1 |
| d556 1 |
| a556 1 |
| avl_delete(_threadtree, th, _free_thread); |
| d619 1 |
| d710 1 |
| d775 7 |
| @ |
| |
| |
| 1.14 |
| log |
| @Timing fixes |
| @ |
| text |
| @a40 1 |
| #include "log.h" |
| d43 3 |
| d51 1 |
| d69 1 |
| d124 1 |
| a125 2 |
| |
| #ifdef THREAD_DEBUG |
| d180 1 |
| a182 1 |
| log_shutdown(); |
| d205 2 |
| a206 1 |
| if (pthread_sigmask(SIG_BLOCK, &ss, NULL) != 0) |
| d209 2 |
| d231 2 |
| a232 1 |
| if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) != 0) |
| d235 2 |
| d266 1 |
| d269 1 |
| d272 1 |
| d274 1 |
| d549 1 |
| d551 1 |
| d611 1 |
| d613 1 |
| d625 1 |
| d627 1 |
| d641 1 |
| d643 1 |
| d663 1 |
| d665 1 |
| @ |
| |
| |
| 1.13 |
| log |
| @Various cleanups |
| @ |
| text |
| @d571 1 |
| a571 1 |
| tv.tv_usec = (len % 1000000) / 1000; |
| @ |
| |
| |
| 1.12 |
| log |
| @oddsock's xslt stats support, slightly cleaned up |
| @ |
| text |
| @d231 1 |
| a231 1 |
| long thread_create_c(char *name, void *(*start_routine)(void *), void *arg, int detached, int line, char *file) |
| d262 1 |
| a262 1 |
| return -1; |
| d265 1 |
| a265 2 |
| // return thread->thread_id; |
| return thread->sys_thread; |
| d678 1 |
| a678 1 |
| void thread_join(long thread) |
| d683 1 |
| a683 1 |
| i = pthread_join(thread, &ret); |
| @ |
| |
| |
| 1.11 |
| log |
| @Cleaned up version of Ciaran Anscomb's relaying patch. |
| @ |
| text |
| @a117 5 |
| /* this must be called to init pthreads-win32 */ |
| #ifdef _WIN32 |
| ptw32_processInitialize(); |
| #endif |
| |
| d127 1 |
| a127 1 |
| /* create all the interal mutexes, and initialize the mutex tree */ |
| @ |
| |
| |
| 1.10 |
| log |
| @Lots of patches committable now that my sound card works properly again. |
| |
| logging API changed slightly (I got sick of gcc warnings about deprecated |
| features). |
| |
| resampling (for live input, not yet for reencoding) is in there. |
| |
| several patches from Karl Heyes have been incorporated. |
| @ |
| text |
| @d468 12 |
| d486 2 |
| @ |
| |
| |
| 1.9 |
| log |
| @Don't use start after freeing it in thread startup code. |
| @ |
| text |
| @d50 16 |
| a65 16 |
| #define LOG_ERROR(y) log_write(_logid, 1, CATMODULE "/" __FUNCTION__, y) |
| #define LOG_ERROR3(y, z1, z2, z3) log_write(_logid, 1, CATMODULE "/" __FUNCTION__, y, z1, z2, z3) |
| #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) |
| |
| #define LOG_WARN(y) log_write(_logid, 2, CATMODULE "/" __FUNCTION__, y) |
| #define LOG_WARN3(y, z1, z2, z3) log_write(_logid, 2, CATMODULE "/" __FUNCTION__, y, z1, z2, z3) |
| #define LOG_WARN5(y, z1, z2, z3, z4, z5) log_write(_logid, 2, CATMODULE "/" __FUNCTION__, y, z1, z2, z3, z4, z5) |
| #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) |
| |
| #define LOG_INFO(y) log_write(_logid, 3, CATMODULE "/" __FUNCTION__, y) |
| #define LOG_INFO4(y, z1, z2, z3, z4) log_write(_logid, 3, CATMODULE "/" __FUNCTION__, y, z1, z2, z3, z4) |
| #define LOG_INFO5(y, z1, z2, z3, z4, z5) log_write(_logid, 3, CATMODULE "/" __FUNCTION__, y, z1, z2, z3, z4, z5) |
| |
| #define LOG_DEBUG(y) log_write(_logid, 4, CATMODULE "/" __FUNCTION__, y) |
| #define LOG_DEBUG2(y, z1, z2) log_write(_logid, 4, CATMODULE "/" __FUNCTION__, y, z1, z2) |
| #define LOG_DEBUG5(y, z1, z2, z3, z4, z5) log_write(_logid, 4, CATMODULE "/" __FUNCTION__, y, z1, z2, z3, z4, z5) |
| a257 1 |
| |
| @ |
| |
| |
| 1.8 |
| log |
| @win32 patches from Ed |
| @ |
| text |
| @d577 1 |
| d591 1 |
| a591 1 |
| if (start->detached) { |
| @ |
| |
| |
| 1.7 |
| log |
| @More win32 fixes. |
| @ |
| text |
| @d28 2 |
| d36 1 |
| a38 2 |
| #include <pthread.h> |
| |
| d46 1 |
| a46 1 |
| #define __FUNCTION__ __FILE__ ":" __LINE__ |
| @ |
| |
| |
| 1.6 |
| log |
| @minor build fixes for win32 courtesy of Oddsock |
| @ |
| text |
| @d117 5 |
| @ |
| |
| |
| 1.5 |
| log |
| @Revert the stacksize work. It's stupid. |
| |
| The original patch from Ben Laurie some years ago was needed because |
| FreeBSD's default stack size was < 8k and this wasn't acceptable. |
| Both Linux and Solaris had reasonable defaults for stacksize, or grew the |
| stack as needed to a reasonable size. |
| |
| Testing today and consulting documentation shows that the default stack |
| sizes on FreeBSD, Linux, and Solaris are all acceptable. Linux can grow |
| to 2MB, 32bit Solaris defaults to 1MB, 64bit Solaris defaults to 2MB, and |
| FreeBSD defaults to 64k. |
| |
| In my opinion FreeBSD needs to get with the program and provide a |
| reasonable default. 64k is enough for us, but might not be for others. |
| @ |
| text |
| @d31 3 |
| d43 4 |
| @ |
| |
| |
| 1.4 |
| log |
| @Stack size per thread needs to be configurable. Setting it on a global |
| bases is not enough. ices and icecast need this to be different, and |
| if one is interested in tuning memory usage, one will want to alter this |
| per thread. |
| @ |
| text |
| @d223 1 |
| a223 1 |
| long thread_create_c(char *name, void *(*start_routine)(void *), void *arg, int stacksize, int detached, int line, char *file) |
| a224 1 |
| pthread_attr_t attr; |
| a245 2 |
| pthread_attr_init(&attr); |
| pthread_attr_setstacksize(&attr, stacksize); |
| d248 1 |
| a248 1 |
| if (pthread_create(&thread->sys_thread, &attr, _start_routine, start) == 0) |
| a251 2 |
| |
| pthread_attr_destroy(&attr); |
| @ |
| |
| |
| 1.3 |
| log |
| @Win32 fixes. Specifically a header change and not using the gcc extensions |
| for vararg macros. It's not as pretty, but it works. |
| @ |
| text |
| @a58 3 |
| /* INTERNAL DATA */ |
| #define STACKSIZE 8192 |
| |
| d223 1 |
| a223 1 |
| long thread_create_c(char *name, void *(*start_routine)(void *), void *arg, int detached, int line, char *file) |
| d248 1 |
| a248 1 |
| pthread_attr_setstacksize(&attr, STACKSIZE); |
| @ |
| |
| |
| 1.2 |
| log |
| @Oddsock found this bug when working with icecast2 on freebsd. Nanoseconds |
| were off by a few orders of magnitude. |
| @ |
| text |
| @a26 1 |
| #include <sys/time.h> |
| d30 1 |
| d42 16 |
| a57 4 |
| #define LOG_ERROR(y, z...) log_write(_logid, 1, CATMODULE "/" __FUNCTION__, y, ##z) |
| #define LOG_WARN(y, z...) log_write(_logid, 2, CATMODULE "/" __FUNCTION__, y, ##z) |
| #define LOG_INFO(y, z...) log_write(_logid, 3, CATMODULE "/" __FUNCTION__, y, ##z) |
| #define LOG_DEBUG(y, z...) log_write(_logid, 4, CATMODULE "/" __FUNCTION__, y, ##z) |
| d312 1 |
| a312 1 |
| LOG_DEBUG("Locking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1); |
| d334 1 |
| a334 1 |
| LOG_ERROR("DEADLOCK AVOIDED (%d == %d) on mutex [%s] in file %s line %d by thread %d [%s]", |
| d365 1 |
| a365 1 |
| LOG_DEBUG("Locked %p by thread %d", mutex, th ? th->thread_id : -1); |
| d383 1 |
| a383 1 |
| LOG_ERROR("No record for %u in unlock [%s:%d]", thread_self(), file, line); |
| d386 1 |
| a386 1 |
| LOG_DEBUG("Unlocking %p (%s) on line %d in file %s by thread %d", mutex, mutex->name, line, file, th ? th->thread_id : -1); |
| d403 1 |
| a403 1 |
| LOG_ERROR("ILLEGAL UNLOCK (%d != %d) on mutex [%s] in file %s line %d by thread %d [%s]", tmutex->thread_id, th->thread_id, |
| d430 1 |
| a430 1 |
| LOG_DEBUG("Unlocked %p by thread %d", mutex, th ? th->thread_id : -1); |
| d524 1 |
| a524 1 |
| LOG_INFO("Removing thread %d [%s] started at [%s:%d], reason: 'Thread Exited'", th->thread_id, th->name, th->file, th->line); |
| d583 1 |
| a583 1 |
| LOG_INFO("Added thread %d [%s] started at [%s:%d]", thread->thread_id, thread->name, thread->file, thread->line); |
| @ |
| |
| |
| 1.1 |
| log |
| @Initial revision |
| @ |
| text |
| @d534 1 |
| a534 1 |
| time_sleep.tv_nsec = len % 1000000; |
| @ |
| |
| |
| 1.1.1.1 |
| log |
| @move to cvs |
| @ |
| text |
| @@ |