+++ /dev/null
-\r
-/* Posix threads interface */\r
-\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR)\r
-#define destructor xxdestructor\r
-#endif\r
-#include <pthread.h>\r
-#if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR)\r
-#undef destructor\r
-#endif\r
-#include <signal.h>\r
-\r
-/* The POSIX spec requires that use of pthread_attr_setstacksize\r
- be conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */\r
-#ifdef _POSIX_THREAD_ATTR_STACKSIZE\r
-#ifndef THREAD_STACK_SIZE\r
-#define THREAD_STACK_SIZE 0 /* use default stack size */\r
-#endif\r
-\r
-#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0\r
- /* The default stack size for new threads on OSX is small enough that\r
- * we'll get hard crashes instead of 'maximum recursion depth exceeded'\r
- * exceptions.\r
- *\r
- * The default stack size below is the minimal stack size where a\r
- * simple recursive function doesn't cause a hard crash.\r
- */\r
-#undef THREAD_STACK_SIZE\r
-#define THREAD_STACK_SIZE 0x400000\r
-#endif\r
-/* for safety, ensure a viable minimum stacksize */\r
-#define THREAD_STACK_MIN 0x8000 /* 32kB */\r
-#else /* !_POSIX_THREAD_ATTR_STACKSIZE */\r
-#ifdef THREAD_STACK_SIZE\r
-#error "THREAD_STACK_SIZE defined but _POSIX_THREAD_ATTR_STACKSIZE undefined"\r
-#endif\r
-#endif\r
-\r
-/* The POSIX spec says that implementations supporting the sem_*\r
- family of functions must indicate this by defining\r
- _POSIX_SEMAPHORES. */\r
-#ifdef _POSIX_SEMAPHORES\r
-/* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so\r
- we need to add 0 to make it work there as well. */\r
-#if (_POSIX_SEMAPHORES+0) == -1\r
-#define HAVE_BROKEN_POSIX_SEMAPHORES\r
-#else\r
-#include <semaphore.h>\r
-#include <errno.h>\r
-#endif\r
-#endif\r
-\r
-/* Before FreeBSD 5.4, system scope threads was very limited resource\r
- in default setting. So the process scope is preferred to get\r
- enough number of threads to work. */\r
-#ifdef __FreeBSD__\r
-#include <osreldate.h>\r
-#if __FreeBSD_version >= 500000 && __FreeBSD_version < 504101\r
-#undef PTHREAD_SYSTEM_SCHED_SUPPORTED\r
-#endif\r
-#endif\r
-\r
-#if !defined(pthread_attr_default)\r
-# define pthread_attr_default ((pthread_attr_t *)NULL)\r
-#endif\r
-#if !defined(pthread_mutexattr_default)\r
-# define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL)\r
-#endif\r
-#if !defined(pthread_condattr_default)\r
-# define pthread_condattr_default ((pthread_condattr_t *)NULL)\r
-#endif\r
-\r
-\r
-/* Whether or not to use semaphores directly rather than emulating them with\r
- * mutexes and condition variables:\r
- */\r
-#if defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES)\r
-# define USE_SEMAPHORES\r
-#else\r
-# undef USE_SEMAPHORES\r
-#endif\r
-\r
-\r
-/* On platforms that don't use standard POSIX threads pthread_sigmask()\r
- * isn't present. DEC threads uses sigprocmask() instead as do most\r
- * other UNIX International compliant systems that don't have the full\r
- * pthread implementation.\r
- */\r
-#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)\r
-# define SET_THREAD_SIGMASK pthread_sigmask\r
-#else\r
-# define SET_THREAD_SIGMASK sigprocmask\r
-#endif\r
-\r
-\r
-/* A pthread mutex isn't sufficient to model the Python lock type\r
- * because, according to Draft 5 of the docs (P1003.4a/D5), both of the\r
- * following are undefined:\r
- * -> a thread tries to lock a mutex it already has locked\r
- * -> a thread tries to unlock a mutex locked by a different thread\r
- * pthread mutexes are designed for serializing threads over short pieces\r
- * of code anyway, so wouldn't be an appropriate implementation of\r
- * Python's locks regardless.\r
- *\r
- * The pthread_lock struct implements a Python lock as a "locked?" bit\r
- * and a <condition, mutex> pair. In general, if the bit can be acquired\r
- * instantly, it is, else the pair is used to block the thread until the\r
- * bit is cleared. 9 May 1994 tim@ksr.com\r
- */\r
-\r
-typedef struct {\r
- char locked; /* 0=unlocked, 1=locked */\r
- /* a <cond, mutex> pair to handle an acquire of a locked lock */\r
- pthread_cond_t lock_released;\r
- pthread_mutex_t mut;\r
-} pthread_lock;\r
-\r
-#define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; }\r
-\r
-/*\r
- * Initialization.\r
- */\r
-\r
-#ifdef _HAVE_BSDI\r
-static\r
-void _noop(void)\r
-{\r
-}\r
-\r
-static void\r
-PyThread__init_thread(void)\r
-{\r
- /* DO AN INIT BY STARTING THE THREAD */\r
- static int dummy = 0;\r
- pthread_t thread1;\r
- pthread_create(&thread1, NULL, (void *) _noop, &dummy);\r
- pthread_join(thread1, NULL);\r
-}\r
-\r
-#else /* !_HAVE_BSDI */\r
-\r
-static void\r
-PyThread__init_thread(void)\r
-{\r
-#if defined(_AIX) && defined(__GNUC__)\r
- pthread_init();\r
-#endif\r
-}\r
-\r
-#endif /* !_HAVE_BSDI */\r
-\r
-/*\r
- * Thread support.\r
- */\r
-\r
-\r
-long\r
-PyThread_start_new_thread(void (*func)(void *), void *arg)\r
-{\r
- pthread_t th;\r
- int status;\r
-#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)\r
- pthread_attr_t attrs;\r
-#endif\r
-#if defined(THREAD_STACK_SIZE)\r
- size_t tss;\r
-#endif\r
-\r
- dprintf(("PyThread_start_new_thread called\n"));\r
- if (!initialized)\r
- PyThread_init_thread();\r
-\r
-#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)\r
- if (pthread_attr_init(&attrs) != 0)\r
- return -1;\r
-#endif\r
-#if defined(THREAD_STACK_SIZE)\r
- tss = (_pythread_stacksize != 0) ? _pythread_stacksize\r
- : THREAD_STACK_SIZE;\r
- if (tss != 0) {\r
- if (pthread_attr_setstacksize(&attrs, tss) != 0) {\r
- pthread_attr_destroy(&attrs);\r
- return -1;\r
- }\r
- }\r
-#endif\r
-#if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)\r
- pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);\r
-#endif\r
-\r
- status = pthread_create(&th,\r
-#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)\r
- &attrs,\r
-#else\r
- (pthread_attr_t*)NULL,\r
-#endif\r
- (void* (*)(void *))func,\r
- (void *)arg\r
- );\r
-\r
-#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)\r
- pthread_attr_destroy(&attrs);\r
-#endif\r
- if (status != 0)\r
- return -1;\r
-\r
- pthread_detach(th);\r
-\r
-#if SIZEOF_PTHREAD_T <= SIZEOF_LONG\r
- return (long) th;\r
-#else\r
- return (long) *(long *) &th;\r
-#endif\r
-}\r
-\r
-/* XXX This implementation is considered (to quote Tim Peters) "inherently\r
- hosed" because:\r
- - It does not guarantee the promise that a non-zero integer is returned.\r
- - The cast to long is inherently unsafe.\r
- - It is not clear that the 'volatile' (for AIX?) and ugly casting in the\r
- latter return statement (for Alpha OSF/1) are any longer necessary.\r
-*/\r
-long\r
-PyThread_get_thread_ident(void)\r
-{\r
- volatile pthread_t threadid;\r
- if (!initialized)\r
- PyThread_init_thread();\r
- /* Jump through some hoops for Alpha OSF/1 */\r
- threadid = pthread_self();\r
-#if SIZEOF_PTHREAD_T <= SIZEOF_LONG\r
- return (long) threadid;\r
-#else\r
- return (long) *(long *) &threadid;\r
-#endif\r
-}\r
-\r
-void\r
-PyThread_exit_thread(void)\r
-{\r
- dprintf(("PyThread_exit_thread called\n"));\r
- if (!initialized) {\r
- exit(0);\r
- }\r
-}\r
-\r
-#ifdef USE_SEMAPHORES\r
-\r
-/*\r
- * Lock support.\r
- */\r
-\r
-PyThread_type_lock\r
-PyThread_allocate_lock(void)\r
-{\r
- sem_t *lock;\r
- int status, error = 0;\r
-\r
- dprintf(("PyThread_allocate_lock called\n"));\r
- if (!initialized)\r
- PyThread_init_thread();\r
-\r
- lock = (sem_t *)malloc(sizeof(sem_t));\r
-\r
- if (lock) {\r
- status = sem_init(lock,0,1);\r
- CHECK_STATUS("sem_init");\r
-\r
- if (error) {\r
- free((void *)lock);\r
- lock = NULL;\r
- }\r
- }\r
-\r
- dprintf(("PyThread_allocate_lock() -> %p\n", lock));\r
- return (PyThread_type_lock)lock;\r
-}\r
-\r
-void\r
-PyThread_free_lock(PyThread_type_lock lock)\r
-{\r
- sem_t *thelock = (sem_t *)lock;\r
- int status, error = 0;\r
-\r
- dprintf(("PyThread_free_lock(%p) called\n", lock));\r
-\r
- if (!thelock)\r
- return;\r
-\r
- status = sem_destroy(thelock);\r
- CHECK_STATUS("sem_destroy");\r
-\r
- free((void *)thelock);\r
-}\r
-\r
-/*\r
- * As of February 2002, Cygwin thread implementations mistakenly report error\r
- * codes in the return value of the sem_ calls (like the pthread_ functions).\r
- * Correct implementations return -1 and put the code in errno. This supports\r
- * either.\r
- */\r
-static int\r
-fix_status(int status)\r
-{\r
- return (status == -1) ? errno : status;\r
-}\r
-\r
-int\r
-PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)\r
-{\r
- int success;\r
- sem_t *thelock = (sem_t *)lock;\r
- int status, error = 0;\r
-\r
- dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));\r
-\r
- do {\r
- if (waitflag)\r
- status = fix_status(sem_wait(thelock));\r
- else\r
- status = fix_status(sem_trywait(thelock));\r
- } while (status == EINTR); /* Retry if interrupted by a signal */\r
-\r
- if (waitflag) {\r
- CHECK_STATUS("sem_wait");\r
- } else if (status != EAGAIN) {\r
- CHECK_STATUS("sem_trywait");\r
- }\r
-\r
- success = (status == 0) ? 1 : 0;\r
-\r
- dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));\r
- return success;\r
-}\r
-\r
-void\r
-PyThread_release_lock(PyThread_type_lock lock)\r
-{\r
- sem_t *thelock = (sem_t *)lock;\r
- int status, error = 0;\r
-\r
- dprintf(("PyThread_release_lock(%p) called\n", lock));\r
-\r
- status = sem_post(thelock);\r
- CHECK_STATUS("sem_post");\r
-}\r
-\r
-#else /* USE_SEMAPHORES */\r
-\r
-/*\r
- * Lock support.\r
- */\r
-PyThread_type_lock\r
-PyThread_allocate_lock(void)\r
-{\r
- pthread_lock *lock;\r
- int status, error = 0;\r
-\r
- dprintf(("PyThread_allocate_lock called\n"));\r
- if (!initialized)\r
- PyThread_init_thread();\r
-\r
- lock = (pthread_lock *) malloc(sizeof(pthread_lock));\r
- if (lock) {\r
- memset((void *)lock, '\0', sizeof(pthread_lock));\r
- lock->locked = 0;\r
-\r
- status = pthread_mutex_init(&lock->mut,\r
- pthread_mutexattr_default);\r
- CHECK_STATUS("pthread_mutex_init");\r
-\r
- status = pthread_cond_init(&lock->lock_released,\r
- pthread_condattr_default);\r
- CHECK_STATUS("pthread_cond_init");\r
-\r
- if (error) {\r
- free((void *)lock);\r
- lock = 0;\r
- }\r
- }\r
-\r
- dprintf(("PyThread_allocate_lock() -> %p\n", lock));\r
- return (PyThread_type_lock) lock;\r
-}\r
-\r
-void\r
-PyThread_free_lock(PyThread_type_lock lock)\r
-{\r
- pthread_lock *thelock = (pthread_lock *)lock;\r
- int status, error = 0;\r
-\r
- dprintf(("PyThread_free_lock(%p) called\n", lock));\r
-\r
- status = pthread_mutex_destroy( &thelock->mut );\r
- CHECK_STATUS("pthread_mutex_destroy");\r
-\r
- status = pthread_cond_destroy( &thelock->lock_released );\r
- CHECK_STATUS("pthread_cond_destroy");\r
-\r
- free((void *)thelock);\r
-}\r
-\r
-int\r
-PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)\r
-{\r
- int success;\r
- pthread_lock *thelock = (pthread_lock *)lock;\r
- int status, error = 0;\r
-\r
- dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));\r
-\r
- status = pthread_mutex_lock( &thelock->mut );\r
- CHECK_STATUS("pthread_mutex_lock[1]");\r
- success = thelock->locked == 0;\r
-\r
- if ( !success && waitflag ) {\r
- /* continue trying until we get the lock */\r
-\r
- /* mut must be locked by me -- part of the condition\r
- * protocol */\r
- while ( thelock->locked ) {\r
- status = pthread_cond_wait(&thelock->lock_released,\r
- &thelock->mut);\r
- CHECK_STATUS("pthread_cond_wait");\r
- }\r
- success = 1;\r
- }\r
- if (success) thelock->locked = 1;\r
- status = pthread_mutex_unlock( &thelock->mut );\r
- CHECK_STATUS("pthread_mutex_unlock[1]");\r
-\r
- if (error) success = 0;\r
- dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));\r
- return success;\r
-}\r
-\r
-void\r
-PyThread_release_lock(PyThread_type_lock lock)\r
-{\r
- pthread_lock *thelock = (pthread_lock *)lock;\r
- int status, error = 0;\r
-\r
- dprintf(("PyThread_release_lock(%p) called\n", lock));\r
-\r
- status = pthread_mutex_lock( &thelock->mut );\r
- CHECK_STATUS("pthread_mutex_lock[3]");\r
-\r
- thelock->locked = 0;\r
-\r
- status = pthread_mutex_unlock( &thelock->mut );\r
- CHECK_STATUS("pthread_mutex_unlock[3]");\r
-\r
- /* wake up someone (anyone, if any) waiting on the lock */\r
- status = pthread_cond_signal( &thelock->lock_released );\r
- CHECK_STATUS("pthread_cond_signal");\r
-}\r
-\r
-#endif /* USE_SEMAPHORES */\r
-\r
-/* set the thread stack size.\r
- * Return 0 if size is valid, -1 if size is invalid,\r
- * -2 if setting stack size is not supported.\r
- */\r
-static int\r
-_pythread_pthread_set_stacksize(size_t size)\r
-{\r
-#if defined(THREAD_STACK_SIZE)\r
- pthread_attr_t attrs;\r
- size_t tss_min;\r
- int rc = 0;\r
-#endif\r
-\r
- /* set to default */\r
- if (size == 0) {\r
- _pythread_stacksize = 0;\r
- return 0;\r
- }\r
-\r
-#if defined(THREAD_STACK_SIZE)\r
-#if defined(PTHREAD_STACK_MIN)\r
- tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN\r
- : THREAD_STACK_MIN;\r
-#else\r
- tss_min = THREAD_STACK_MIN;\r
-#endif\r
- if (size >= tss_min) {\r
- /* validate stack size by setting thread attribute */\r
- if (pthread_attr_init(&attrs) == 0) {\r
- rc = pthread_attr_setstacksize(&attrs, size);\r
- pthread_attr_destroy(&attrs);\r
- if (rc == 0) {\r
- _pythread_stacksize = size;\r
- return 0;\r
- }\r
- }\r
- }\r
- return -1;\r
-#else\r
- return -2;\r
-#endif\r
-}\r
-\r
-#define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x)\r