/* Posix threads interface */#include <stdlib.h>#include <string.h>#if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR)#define destructor xxdestructor#endif#include <pthread.h>#if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR)#undef destructor#endif#include <signal.h>/* The POSIX spec requires that use of pthread_attr_setstacksizebe conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */#ifdef _POSIX_THREAD_ATTR_STACKSIZE#ifndef THREAD_STACK_SIZE#define THREAD_STACK_SIZE 0 /* use default stack size */#endif/* for safety, ensure a viable minimum stacksize */#define THREAD_STACK_MIN 0x8000 /* 32kB */#else /* !_POSIX_THREAD_ATTR_STACKSIZE */#ifdef THREAD_STACK_SIZE#error "THREAD_STACK_SIZE defined but _POSIX_THREAD_ATTR_STACKSIZE undefined"#endif#endif/* The POSIX spec says that implementations supporting the sem_*family of functions must indicate this by defining_POSIX_SEMAPHORES. */#ifdef _POSIX_SEMAPHORES/* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, sowe need to add 0 to make it work there as well. */#if (_POSIX_SEMAPHORES+0) == -1#define HAVE_BROKEN_POSIX_SEMAPHORES#else#include <semaphore.h>#include <errno.h>#endif#endif/* Before FreeBSD 5.4, system scope threads was very limited resourcein default setting. So the process scope is preferred to getenough number of threads to work. */#ifdef __FreeBSD__#include <osreldate.h>#if __FreeBSD_version >= 500000 && __FreeBSD_version < 504101#undef PTHREAD_SYSTEM_SCHED_SUPPORTED#endif#endif#if !defined(pthread_attr_default)# define pthread_attr_default ((pthread_attr_t *)NULL)#endif#if !defined(pthread_mutexattr_default)# define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL)#endif#if !defined(pthread_condattr_default)# define pthread_condattr_default ((pthread_condattr_t *)NULL)#endif/* Whether or not to use semaphores directly rather than emulating them with* mutexes and condition variables:*/#if defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES)# define USE_SEMAPHORES#else# undef USE_SEMAPHORES#endif/* On platforms that don't use standard POSIX threads pthread_sigmask()* isn't present. DEC threads uses sigprocmask() instead as do most* other UNIX International compliant systems that don't have the full* pthread implementation.*/#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)# define SET_THREAD_SIGMASK pthread_sigmask#else# define SET_THREAD_SIGMASK sigprocmask#endif/* A pthread mutex isn't sufficient to model the Python lock type* because, according to Draft 5 of the docs (P1003.4a/D5), both of the* following are undefined:* -> a thread tries to lock a mutex it already has locked* -> a thread tries to unlock a mutex locked by a different thread* pthread mutexes are designed for serializing threads over short pieces* of code anyway, so wouldn't be an appropriate implementation of* Python's locks regardless.** The pthread_lock struct implements a Python lock as a "locked?" bit* and a <condition, mutex> pair. In general, if the bit can be acquired* instantly, it is, else the pair is used to block the thread until the* bit is cleared. 9 May 1994 tim@ksr.com*/typedef struct {char locked; /* 0=unlocked, 1=locked *//* a <cond, mutex> pair to handle an acquire of a locked lock */pthread_cond_t lock_released;pthread_mutex_t mut;} pthread_lock;#define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; }/** Initialization.*/#ifdef _HAVE_BSDIstaticvoid _noop(void){}static voidPyThread__init_thread(void){/* DO AN INIT BY STARTING THE THREAD */static int dummy = 0;pthread_t thread1;pthread_create(&thread1, NULL, (void *) _noop, &dummy);pthread_join(thread1, NULL);}#else /* !_HAVE_BSDI */static voidPyThread__init_thread(void){#if defined(_AIX) && defined(__GNUC__)pthread_init();#endif}#endif /* !_HAVE_BSDI *//** Thread support.*/longPyThread_start_new_thread(void (*func)(void *), void *arg){pthread_t th;int status;#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)pthread_attr_t attrs;#endif#if defined(THREAD_STACK_SIZE)size_t tss;#endifdprintf(("PyThread_start_new_thread called\n"));if (!initialized)PyThread_init_thread();#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)if (pthread_attr_init(&attrs) != 0)return -1;#endif#if defined(THREAD_STACK_SIZE)tss = (_pythread_stacksize != 0) ? _pythread_stacksize: THREAD_STACK_SIZE;if (tss != 0) {if (pthread_attr_setstacksize(&attrs, tss) != 0) {pthread_attr_destroy(&attrs);return -1;}}#endif#if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);#endifstatus = pthread_create(&th,#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)&attrs,#else(pthread_attr_t*)NULL,#endif(void* (*)(void *))func,(void *)arg);#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)pthread_attr_destroy(&attrs);#endifif (status != 0)return -1;pthread_detach(th);#if SIZEOF_PTHREAD_T <= SIZEOF_LONGreturn (long) th;#elsereturn (long) *(long *) &th;#endif}/* XXX This implementation is considered (to quote Tim Peters) "inherentlyhosed" because:- It does not guarantee the promise that a non-zero integer is returned.- The cast to long is inherently unsafe.- It is not clear that the 'volatile' (for AIX?) and ugly casting in thelatter return statement (for Alpha OSF/1) are any longer necessary.*/longPyThread_get_thread_ident(void){volatile pthread_t threadid;if (!initialized)PyThread_init_thread();/* Jump through some hoops for Alpha OSF/1 */threadid = pthread_self();#if SIZEOF_PTHREAD_T <= SIZEOF_LONGreturn (long) threadid;#elsereturn (long) *(long *) &threadid;#endif}static voiddo_PyThread_exit_thread(int no_cleanup){dprintf(("PyThread_exit_thread called\n"));if (!initialized) {if (no_cleanup)_exit(0);elseexit(0);}}voidPyThread_exit_thread(void){do_PyThread_exit_thread(0);}voidPyThread__exit_thread(void){do_PyThread_exit_thread(1);}#ifndef NO_EXIT_PROGstatic voiddo_PyThread_exit_prog(int status, int no_cleanup){dprintf(("PyThread_exit_prog(%d) called\n", status));if (!initialized)if (no_cleanup)_exit(status);elseexit(status);}voidPyThread_exit_prog(int status){do_PyThread_exit_prog(status, 0);}voidPyThread__exit_prog(int status){do_PyThread_exit_prog(status, 1);}#endif /* NO_EXIT_PROG */#ifdef USE_SEMAPHORES/** Lock support.*/PyThread_type_lockPyThread_allocate_lock(void){sem_t *lock;int status, error = 0;dprintf(("PyThread_allocate_lock called\n"));if (!initialized)PyThread_init_thread();lock = (sem_t *)malloc(sizeof(sem_t));if (lock) {status = sem_init(lock,0,1);CHECK_STATUS("sem_init");if (error) {free((void *)lock);lock = NULL;}}dprintf(("PyThread_allocate_lock() -> %p\n", lock));return (PyThread_type_lock)lock;}voidPyThread_free_lock(PyThread_type_lock lock){sem_t *thelock = (sem_t *)lock;int status, error = 0;dprintf(("PyThread_free_lock(%p) called\n", lock));if (!thelock)return;status = sem_destroy(thelock);CHECK_STATUS("sem_destroy");free((void *)thelock);}/** As of February 2002, Cygwin thread implementations mistakenly report error* codes in the return value of the sem_ calls (like the pthread_ functions).* Correct implementations return -1 and put the code in errno. This supports* either.*/static intfix_status(int status){return (status == -1) ? errno : status;}intPyThread_acquire_lock(PyThread_type_lock lock, int waitflag){int success;sem_t *thelock = (sem_t *)lock;int status, error = 0;dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));do {if (waitflag)status = fix_status(sem_wait(thelock));elsestatus = fix_status(sem_trywait(thelock));} while (status == EINTR); /* Retry if interrupted by a signal */if (waitflag) {CHECK_STATUS("sem_wait");} else if (status != EAGAIN) {CHECK_STATUS("sem_trywait");}success = (status == 0) ? 1 : 0;dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));return success;}voidPyThread_release_lock(PyThread_type_lock lock){sem_t *thelock = (sem_t *)lock;int status, error = 0;dprintf(("PyThread_release_lock(%p) called\n", lock));status = sem_post(thelock);CHECK_STATUS("sem_post");}#else /* USE_SEMAPHORES *//** Lock support.*/PyThread_type_lockPyThread_allocate_lock(void){pthread_lock *lock;int status, error = 0;dprintf(("PyThread_allocate_lock called\n"));if (!initialized)PyThread_init_thread();lock = (pthread_lock *) malloc(sizeof(pthread_lock));if (lock) {memset((void *)lock, '0円', sizeof(pthread_lock));lock->locked = 0;status = pthread_mutex_init(&lock->mut,pthread_mutexattr_default);CHECK_STATUS("pthread_mutex_init");status = pthread_cond_init(&lock->lock_released,pthread_condattr_default);CHECK_STATUS("pthread_cond_init");if (error) {free((void *)lock);lock = 0;}}dprintf(("PyThread_allocate_lock() -> %p\n", lock));return (PyThread_type_lock) lock;}voidPyThread_free_lock(PyThread_type_lock lock){pthread_lock *thelock = (pthread_lock *)lock;int status, error = 0;dprintf(("PyThread_free_lock(%p) called\n", lock));status = pthread_mutex_destroy( &thelock->mut );CHECK_STATUS("pthread_mutex_destroy");status = pthread_cond_destroy( &thelock->lock_released );CHECK_STATUS("pthread_cond_destroy");free((void *)thelock);}intPyThread_acquire_lock(PyThread_type_lock lock, int waitflag){int success;pthread_lock *thelock = (pthread_lock *)lock;int status, error = 0;dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));status = pthread_mutex_lock( &thelock->mut );CHECK_STATUS("pthread_mutex_lock[1]");success = thelock->locked == 0;if ( !success && waitflag ) {/* continue trying until we get the lock *//* mut must be locked by me -- part of the condition* protocol */while ( thelock->locked ) {status = pthread_cond_wait(&thelock->lock_released,&thelock->mut);CHECK_STATUS("pthread_cond_wait");}success = 1;}if (success) thelock->locked = 1;status = pthread_mutex_unlock( &thelock->mut );CHECK_STATUS("pthread_mutex_unlock[1]");if (error) success = 0;dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));return success;}voidPyThread_release_lock(PyThread_type_lock lock){pthread_lock *thelock = (pthread_lock *)lock;int status, error = 0;dprintf(("PyThread_release_lock(%p) called\n", lock));status = pthread_mutex_lock( &thelock->mut );CHECK_STATUS("pthread_mutex_lock[3]");thelock->locked = 0;status = pthread_mutex_unlock( &thelock->mut );CHECK_STATUS("pthread_mutex_unlock[3]");/* wake up someone (anyone, if any) waiting on the lock */status = pthread_cond_signal( &thelock->lock_released );CHECK_STATUS("pthread_cond_signal");}#endif /* USE_SEMAPHORES *//* set the thread stack size.* Return 0 if size is valid, -1 if size is invalid,* -2 if setting stack size is not supported.*/static int_pythread_pthread_set_stacksize(size_t size){#if defined(THREAD_STACK_SIZE)pthread_attr_t attrs;size_t tss_min;int rc = 0;#endif/* set to default */if (size == 0) {_pythread_stacksize = 0;return 0;}#if defined(THREAD_STACK_SIZE)#if defined(PTHREAD_STACK_MIN)tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN: THREAD_STACK_MIN;#elsetss_min = THREAD_STACK_MIN;#endifif (size >= tss_min) {/* validate stack size by setting thread attribute */if (pthread_attr_init(&attrs) == 0) {rc = pthread_attr_setstacksize(&attrs, size);pthread_attr_destroy(&attrs);if (rc == 0) {_pythread_stacksize = size;return 0;}}}return -1;#elsereturn -2;#endif}#define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。