📄 thread.c,v
字号:
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.25date 2003.07.14.02.17.52; author brendan; state Exp;branches;next 1.24;1.24date 2003.03.15.02.10.18; author msmith; state Exp;branches;next 1.23;1.23date 2003.03.12.03.59.55; author karl; state Exp;branches;next 1.22;1.22date 2003.03.09.22.56.46; author karl; state Exp;branches;next 1.21;1.21date 2003.03.08.16.05.38; author karl; state Exp;branches;next 1.20;1.20date 2003.03.04.15.31.34; author msmith; state Exp;branches;next 1.19;1.19date 2003.01.17.09.01.04; author msmith; state Exp;branches;next 1.18;1.18date 2002.12.29.09.55.50; author msmith; state Exp;branches;next 1.17;1.17date 2002.11.22.13.00.44; author msmith; state Exp;branches;next 1.16;1.16date 2002.09.24.07.09.08; author msmith; state Exp;branches;next 1.15;1.15date 2002.08.16.14.23.17; author msmith; state Exp;branches;next 1.14;1.14date 2002.08.13.01.08.15; author msmith; state Exp;branches;next 1.13;1.13date 2002.08.10.03.22.44; author msmith; state Exp;branches;next 1.12;1.12date 2002.08.09.06.52.07; author msmith; state Exp;branches;next 1.11;1.11date 2002.08.05.14.48.03; author msmith; state Exp;branches;next 1.10;1.10date 2002.08.03.08.14.56; author msmith; state Exp;branches;next 1.9;1.9date 2002.04.30.06.50.47; author msmith; state Exp;branches;next 1.8;1.8date 2002.03.05.23.59.38; author jack; state Exp;branches;next 1.7;1.7date 2002.02.08.03.51.19; author jack; state Exp;branches;next 1.6;1.6date 2002.02.07.01.04.09; author jack; state Exp;branches;next 1.5;1.5date 2001.10.21.02.04.27; author jack; state Exp;branches;next 1.4;1.4date 2001.10.20.22.27.52; author jack; state Exp;branches;next 1.3;1.3date 2001.10.20.05.35.30; author jack; state Exp;branches;next 1.2;1.2date 2001.10.20.03.39.10; author jack; state Exp;branches;next 1.1;1.1date 2001.09.10.02.26.33; author jack; state Exp;branches 1.1.1.1;next ;1.1.1.1date 2001.09.10.02.26.33; author jack; state Exp;branches;next ;desc@@1.25log@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_MUTEXESstatic mutex_t _threadtree_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1, PTHREAD_MUTEX_INITIALIZER};#elsestatic mutex_t _threadtree_mutex = { PTHREAD_MUTEX_INITIALIZER };#endif#ifdef DEBUG_MUTEXESstatic 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_MUTEXESstatic mutex_t _library_mutex = { -1, NULL, MUTEX_STATE_UNINIT, NULL, -1, PTHREAD_MUTEX_INITIALIZER};#elsestatic mutex_t _library_mutex = { PTHREAD_MUTEX_INITIALIZER };#endif/* INTERNAL FUNCTIONS *//* avl tree functions */#ifdef DEBUG_MUTEXESstatic int _compare_mutexes(void *compare_arg, void *a, void *b);static int _free_mutex(void *key);#endifstatic 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -