cinap_lenrekadd hg and python4bb9e2215 years agoHistory
533 lines · 12.1 KB · C
RawDownload
 /* 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_setstacksize   be 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, so    we 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 resource   in default setting.  So the process scope is preferred to get   enough 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;#endif 	dprintf(("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);#endif 	status = 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);#endif	if (status != 0)            return -1;         pthread_detach(th); #if SIZEOF_PTHREAD_T <= SIZEOF_LONG	return (long) th;#else	return (long) *(long *) &th;#endif} /* XXX This implementation is considered (to quote Tim Peters) "inherently   hosed" 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 the       latter return statement (for Alpha OSF/1) are any longer necessary.*/long PyThread_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_LONG	return (long) threadid;#else	return (long) *(long *) &threadid;#endif} static void do_PyThread_exit_thread(int no_cleanup){	dprintf(("PyThread_exit_thread called\n"));	if (!initialized) {		if (no_cleanup)			_exit(0);		else			exit(0);	}} void PyThread_exit_thread(void){	do_PyThread_exit_thread(0);} void PyThread__exit_thread(void){	do_PyThread_exit_thread(1);} #ifndef NO_EXIT_PROGstatic void do_PyThread_exit_prog(int status, int no_cleanup){	dprintf(("PyThread_exit_prog(%d) called\n", status));	if (!initialized)		if (no_cleanup)			_exit(status);		else			exit(status);} void PyThread_exit_prog(int status){	do_PyThread_exit_prog(status, 0);} void PyThread__exit_prog(int status){	do_PyThread_exit_prog(status, 1);}#endif /* NO_EXIT_PROG */ #ifdef USE_SEMAPHORES /* * Lock support. */ PyThread_type_lock PyThread_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;} void PyThread_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;} int PyThread_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));		else			status = 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;} void PyThread_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_lock PyThread_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;} void PyThread_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);} int PyThread_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;} void PyThread_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;

Lines 1–500 of 533.