From a1f698754bc05deaea56dba1e7d61b9f476862b0 Mon Sep 17 00:00:00 2001 From: Amaury Forgeot d'Arc Date: Wed, 24 Feb 2010 00:10:48 +0000 Subject: Merged revisions 78393 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ........ r78393 | amaury.forgeotdarc | 2010-02-24 00:19:39 +0100 (mer., 24 févr. 2010) | 2 lines #4852: Remove dead code in every thread implementation, unused for many years. ........ --- Python/thread_pthread.h | 46 +++------------------------------------------- 1 file changed, 3 insertions(+), 43 deletions(-) (limited to 'Python/thread_pthread.h') diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 60d2fb216e..4305a198ba 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -225,55 +225,15 @@ PyThread_get_thread_ident(void) #endif } -static void -do_PyThread_exit_thread(int no_cleanup) +void +PyThread_exit_thread(void) { dprintf(("PyThread_exit_thread called\n")); if (!initialized) { - if (no_cleanup) - _exit(0); - else - exit(0); + 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_PROG -static 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 /* -- cgit v1.2.1 From 15801a1d52c25fa2a19d649ea2671080f138fca1 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 14 Apr 2010 15:44:10 +0000 Subject: Issue #7316: the acquire() method of lock objects in the :mod:`threading` module now takes an optional timeout argument in seconds. Timeout support relies on the system threading library, so as to avoid a semi-busy wait loop. --- Python/thread_pthread.h | 101 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 20 deletions(-) (limited to 'Python/thread_pthread.h') diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 4305a198ba..6088c71fdb 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -83,6 +83,26 @@ #endif +/* We assume all modern POSIX systems have gettimeofday() */ +#ifdef GETTIMEOFDAY_NO_TZ +#define GETTIMEOFDAY(ptv) gettimeofday(ptv) +#else +#define GETTIMEOFDAY(ptv) gettimeofday(ptv, (struct timezone *)NULL) +#endif + +#define MICROSECONDS_TO_TIMESPEC(microseconds, ts) \ +do { \ + struct timeval tv; \ + GETTIMEOFDAY(&tv); \ + tv.tv_usec += microseconds % 1000000; \ + tv.tv_sec += microseconds / 1000000; \ + tv.tv_sec += tv.tv_usec / 1000000; \ + tv.tv_usec %= 1000000; \ + ts.tv_sec = tv.tv_sec; \ + ts.tv_nsec = tv.tv_usec * 1000; \ +} while(0) + + /* 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: @@ -295,34 +315,53 @@ fix_status(int status) return (status == -1) ? errno : status; } -int -PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +int +PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) { int success; sem_t *thelock = (sem_t *)lock; int status, error = 0; + struct timespec ts; - dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld) called\n", + lock, microseconds)); + if (microseconds > 0) + MICROSECONDS_TO_TIMESPEC(microseconds, ts); do { - if (waitflag) - status = fix_status(sem_wait(thelock)); - else + if (microseconds > 0) + status = fix_status(sem_timedwait(thelock, &ts)); + else if (microseconds == 0) status = fix_status(sem_trywait(thelock)); + else + status = fix_status(sem_wait(thelock)); } while (status == EINTR); /* Retry if interrupted by a signal */ - if (waitflag) { + if (microseconds > 0) { + if (status != ETIMEDOUT) + CHECK_STATUS("sem_timedwait"); + } + else if (microseconds == 0) { + if (status != EAGAIN) + CHECK_STATUS("sem_trywait"); + } + else { 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)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld) -> %d\n", + lock, microseconds, success)); return success; } +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0); +} + void PyThread_release_lock(PyThread_type_lock lock) { @@ -390,40 +429,62 @@ PyThread_free_lock(PyThread_type_lock lock) free((void *)thelock); } -int -PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +int +PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) { int success; pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; - dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld) called\n", + lock, microseconds)); status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS("pthread_mutex_lock[1]"); success = thelock->locked == 0; - if ( !success && waitflag ) { + if (!success && microseconds != 0) { + struct timespec ts; + if (microseconds > 0) + MICROSECONDS_TO_TIMESPEC(microseconds, ts); /* 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"); + while (thelock->locked) { + if (microseconds > 0) { + status = pthread_cond_timedwait( + &thelock->lock_released, + &thelock->mut, &ts); + if (status == ETIMEDOUT) + break; + CHECK_STATUS("pthread_cond_timed_wait"); + } + else { + status = pthread_cond_wait( + &thelock->lock_released, + &thelock->mut); + CHECK_STATUS("pthread_cond_wait"); + } } - success = 1; + success = (status == 0); } 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)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld) -> %d\n", + lock, microseconds, success)); return success; } +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0); +} + void PyThread_release_lock(PyThread_type_lock lock) { -- cgit v1.2.1 From 8cc1fda6b8c2d74a3abd2b8a007880656add8997 Mon Sep 17 00:00:00 2001 From: Jeffrey Yasskin Date: Mon, 3 May 2010 19:29:34 +0000 Subject: Make (most of) Python's tests pass under Thread Sanitizer. http://code.google.com/p/data-race-test/wiki/ThreadSanitizer is a dynamic data race detector that runs on top of valgrind. With this patch, the binaries at http://code.google.com/p/data-race-test/wiki/ThreadSanitizer#Binaries pass many but not all of the Python tests. All of regrtest still passes outside of tsan. I've implemented part of the C1x atomic types so that we can explicitly mark variables that are used across threads, and get defined behavior as compilers advance. I've added tsan's client header and implementation to the codebase in dynamic_annotations.{h,c} (docs at http://code.google.com/p/data-race-test/wiki/DynamicAnnotations). Unfortunately, I haven't been able to get helgrind and drd to give sensible error messages, even when I use their client annotations, so I'm not supporting them. --- Python/thread_pthread.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Python/thread_pthread.h') diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 6088c71fdb..f60f36dc2e 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -397,6 +397,12 @@ PyThread_allocate_lock(void) status = pthread_mutex_init(&lock->mut, pthread_mutexattr_default); CHECK_STATUS("pthread_mutex_init"); + /* Mark the pthread mutex underlying a Python mutex as + pure happens-before. We can't simply mark the + Python-level mutex as a mutex because it can be + acquired and released in different threads, which + will cause errors. */ + _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&lock->mut); status = pthread_cond_init(&lock->lock_released, pthread_condattr_default); -- cgit v1.2.1 From 567b94adaaceb622c33f9be1998735dfb95f1707 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 9 May 2010 15:52:27 +0000 Subject: Recorded merge of revisions 81029 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r81029 | antoine.pitrou | 2010-05-09 16:46:46 +0200 (dim., 09 mai 2010) | 3 lines Untabify C files. Will watch buildbots. ........ --- Python/thread_pthread.h | 528 ++++++++++++++++++++++++------------------------ 1 file changed, 264 insertions(+), 264 deletions(-) (limited to 'Python/thread_pthread.h') diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index f60f36dc2e..5e52b3977e 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -16,10 +16,10 @@ 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 */ +#define THREAD_STACK_SIZE 0 /* use default stack size */ #endif /* for safety, ensure a viable minimum stacksize */ -#define THREAD_STACK_MIN 0x8000 /* 32kB */ +#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" @@ -28,9 +28,9 @@ /* The POSIX spec says that implementations supporting the sem_* family of functions must indicate this by defining - _POSIX_SEMAPHORES. */ + _POSIX_SEMAPHORES. */ #ifdef _POSIX_SEMAPHORES -/* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so +/* 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 @@ -92,14 +92,14 @@ #define MICROSECONDS_TO_TIMESPEC(microseconds, ts) \ do { \ - struct timeval tv; \ - GETTIMEOFDAY(&tv); \ - tv.tv_usec += microseconds % 1000000; \ - tv.tv_sec += microseconds / 1000000; \ - tv.tv_sec += tv.tv_usec / 1000000; \ - tv.tv_usec %= 1000000; \ - ts.tv_sec = tv.tv_sec; \ - ts.tv_nsec = tv.tv_usec * 1000; \ + struct timeval tv; \ + GETTIMEOFDAY(&tv); \ + tv.tv_usec += microseconds % 1000000; \ + tv.tv_sec += microseconds / 1000000; \ + tv.tv_sec += tv.tv_usec / 1000000; \ + tv.tv_usec %= 1000000; \ + ts.tv_sec = tv.tv_sec; \ + ts.tv_nsec = tv.tv_usec * 1000; \ } while(0) @@ -119,10 +119,10 @@ do { \ */ typedef struct { - char locked; /* 0=unlocked, 1=locked */ - /* a pair to handle an acquire of a locked lock */ - pthread_cond_t lock_released; - pthread_mutex_t mut; + char locked; /* 0=unlocked, 1=locked */ + /* a 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; } @@ -140,11 +140,11 @@ void _noop(void) static void PyThread__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); + /* 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 */ @@ -153,7 +153,7 @@ static void PyThread__init_thread(void) { #if defined(_AIX) && defined(__GNUC__) - pthread_init(); + pthread_init(); #endif } @@ -167,59 +167,59 @@ PyThread__init_thread(void) long PyThread_start_new_thread(void (*func)(void *), void *arg) { - pthread_t th; - int status; + pthread_t th; + int status; #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) - pthread_attr_t attrs; + pthread_attr_t attrs; #endif #if defined(THREAD_STACK_SIZE) - size_t tss; + size_t tss; #endif - dprintf(("PyThread_start_new_thread called\n")); - if (!initialized) - PyThread_init_thread(); + 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; + 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; - } - } + 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); + pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); #endif - status = pthread_create(&th, + status = pthread_create(&th, #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) - &attrs, + &attrs, #else - (pthread_attr_t*)NULL, + (pthread_attr_t*)NULL, #endif - (void* (*)(void *))func, - (void *)arg - ); + (void* (*)(void *))func, + (void *)arg + ); #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) - pthread_attr_destroy(&attrs); + pthread_attr_destroy(&attrs); #endif - if (status != 0) - return -1; + if (status != 0) + return -1; - pthread_detach(th); + pthread_detach(th); #if SIZEOF_PTHREAD_T <= SIZEOF_LONG - return (long) th; + return (long) th; #else - return (long) *(long *) &th; + return (long) *(long *) &th; #endif } @@ -230,28 +230,28 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) - 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 +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(); + 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; + return (long) threadid; #else - return (long) *(long *) &threadid; + return (long) *(long *) &threadid; #endif } -void +void PyThread_exit_thread(void) { - dprintf(("PyThread_exit_thread called\n")); - if (!initialized) { - exit(0); - } + dprintf(("PyThread_exit_thread called\n")); + if (!initialized) { + exit(0); + } } #ifdef USE_SEMAPHORES @@ -260,47 +260,47 @@ PyThread_exit_thread(void) * Lock support. */ -PyThread_type_lock +PyThread_type_lock PyThread_allocate_lock(void) { - sem_t *lock; - int status, error = 0; + sem_t *lock; + int status, error = 0; - dprintf(("PyThread_allocate_lock called\n")); - if (!initialized) - PyThread_init_thread(); + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); - lock = (sem_t *)malloc(sizeof(sem_t)); + lock = (sem_t *)malloc(sizeof(sem_t)); - if (lock) { - status = sem_init(lock,0,1); - CHECK_STATUS("sem_init"); + if (lock) { + status = sem_init(lock,0,1); + CHECK_STATUS("sem_init"); - if (error) { - free((void *)lock); - lock = NULL; - } - } + if (error) { + free((void *)lock); + lock = NULL; + } + } - dprintf(("PyThread_allocate_lock() -> %p\n", lock)); - return (PyThread_type_lock)lock; + dprintf(("PyThread_allocate_lock() -> %p\n", lock)); + return (PyThread_type_lock)lock; } -void +void PyThread_free_lock(PyThread_type_lock lock) { - sem_t *thelock = (sem_t *)lock; - int status, error = 0; + sem_t *thelock = (sem_t *)lock; + int status, error = 0; - dprintf(("PyThread_free_lock(%p) called\n", lock)); + dprintf(("PyThread_free_lock(%p) called\n", lock)); - if (!thelock) - return; + if (!thelock) + return; - status = sem_destroy(thelock); - CHECK_STATUS("sem_destroy"); + status = sem_destroy(thelock); + CHECK_STATUS("sem_destroy"); - free((void *)thelock); + free((void *)thelock); } /* @@ -312,66 +312,66 @@ PyThread_free_lock(PyThread_type_lock lock) static int fix_status(int status) { - return (status == -1) ? errno : status; + return (status == -1) ? errno : status; } int PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) { - int success; - sem_t *thelock = (sem_t *)lock; - int status, error = 0; - struct timespec ts; - - dprintf(("PyThread_acquire_lock_timed(%p, %lld) called\n", - lock, microseconds)); - - if (microseconds > 0) - MICROSECONDS_TO_TIMESPEC(microseconds, ts); - do { - if (microseconds > 0) - status = fix_status(sem_timedwait(thelock, &ts)); - else if (microseconds == 0) - status = fix_status(sem_trywait(thelock)); - else - status = fix_status(sem_wait(thelock)); - } while (status == EINTR); /* Retry if interrupted by a signal */ - - if (microseconds > 0) { - if (status != ETIMEDOUT) - CHECK_STATUS("sem_timedwait"); - } - else if (microseconds == 0) { - if (status != EAGAIN) - CHECK_STATUS("sem_trywait"); - } - else { - CHECK_STATUS("sem_wait"); - } - - success = (status == 0) ? 1 : 0; - - dprintf(("PyThread_acquire_lock_timed(%p, %lld) -> %d\n", - lock, microseconds, success)); - return success; + int success; + sem_t *thelock = (sem_t *)lock; + int status, error = 0; + struct timespec ts; + + dprintf(("PyThread_acquire_lock_timed(%p, %lld) called\n", + lock, microseconds)); + + if (microseconds > 0) + MICROSECONDS_TO_TIMESPEC(microseconds, ts); + do { + if (microseconds > 0) + status = fix_status(sem_timedwait(thelock, &ts)); + else if (microseconds == 0) + status = fix_status(sem_trywait(thelock)); + else + status = fix_status(sem_wait(thelock)); + } while (status == EINTR); /* Retry if interrupted by a signal */ + + if (microseconds > 0) { + if (status != ETIMEDOUT) + CHECK_STATUS("sem_timedwait"); + } + else if (microseconds == 0) { + if (status != EAGAIN) + CHECK_STATUS("sem_trywait"); + } + else { + CHECK_STATUS("sem_wait"); + } + + success = (status == 0) ? 1 : 0; + + dprintf(("PyThread_acquire_lock_timed(%p, %lld) -> %d\n", + lock, microseconds, success)); + return success; } -int +int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) { - return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0); + return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0); } -void +void PyThread_release_lock(PyThread_type_lock lock) { - sem_t *thelock = (sem_t *)lock; - int status, error = 0; + sem_t *thelock = (sem_t *)lock; + int status, error = 0; - dprintf(("PyThread_release_lock(%p) called\n", lock)); + dprintf(("PyThread_release_lock(%p) called\n", lock)); - status = sem_post(thelock); - CHECK_STATUS("sem_post"); + status = sem_post(thelock); + CHECK_STATUS("sem_post"); } #else /* USE_SEMAPHORES */ @@ -379,137 +379,137 @@ PyThread_release_lock(PyThread_type_lock lock) /* * Lock support. */ -PyThread_type_lock +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"); - /* Mark the pthread mutex underlying a Python mutex as - pure happens-before. We can't simply mark the - Python-level mutex as a mutex because it can be - acquired and released in different threads, which - will cause errors. */ - _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&lock->mut); - - 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; + 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"); + /* Mark the pthread mutex underlying a Python mutex as + pure happens-before. We can't simply mark the + Python-level mutex as a mutex because it can be + acquired and released in different threads, which + will cause errors. */ + _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&lock->mut); + + 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 +void PyThread_free_lock(PyThread_type_lock lock) { - pthread_lock *thelock = (pthread_lock *)lock; - int status, error = 0; + pthread_lock *thelock = (pthread_lock *)lock; + int status, error = 0; - dprintf(("PyThread_free_lock(%p) called\n", lock)); + dprintf(("PyThread_free_lock(%p) called\n", lock)); - status = pthread_mutex_destroy( &thelock->mut ); - CHECK_STATUS("pthread_mutex_destroy"); + status = pthread_mutex_destroy( &thelock->mut ); + CHECK_STATUS("pthread_mutex_destroy"); - status = pthread_cond_destroy( &thelock->lock_released ); - CHECK_STATUS("pthread_cond_destroy"); + status = pthread_cond_destroy( &thelock->lock_released ); + CHECK_STATUS("pthread_cond_destroy"); - free((void *)thelock); + free((void *)thelock); } int PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) { - int success; - pthread_lock *thelock = (pthread_lock *)lock; - int status, error = 0; - - dprintf(("PyThread_acquire_lock_timed(%p, %lld) called\n", - lock, microseconds)); - - status = pthread_mutex_lock( &thelock->mut ); - CHECK_STATUS("pthread_mutex_lock[1]"); - success = thelock->locked == 0; - - if (!success && microseconds != 0) { - struct timespec ts; - if (microseconds > 0) - MICROSECONDS_TO_TIMESPEC(microseconds, ts); - /* continue trying until we get the lock */ - - /* mut must be locked by me -- part of the condition - * protocol */ - while (thelock->locked) { - if (microseconds > 0) { - status = pthread_cond_timedwait( - &thelock->lock_released, - &thelock->mut, &ts); - if (status == ETIMEDOUT) - break; - CHECK_STATUS("pthread_cond_timed_wait"); - } - else { - status = pthread_cond_wait( - &thelock->lock_released, - &thelock->mut); - CHECK_STATUS("pthread_cond_wait"); - } - } - success = (status == 0); - } - 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_timed(%p, %lld) -> %d\n", - lock, microseconds, success)); - return success; + int success; + pthread_lock *thelock = (pthread_lock *)lock; + int status, error = 0; + + dprintf(("PyThread_acquire_lock_timed(%p, %lld) called\n", + lock, microseconds)); + + status = pthread_mutex_lock( &thelock->mut ); + CHECK_STATUS("pthread_mutex_lock[1]"); + success = thelock->locked == 0; + + if (!success && microseconds != 0) { + struct timespec ts; + if (microseconds > 0) + MICROSECONDS_TO_TIMESPEC(microseconds, ts); + /* continue trying until we get the lock */ + + /* mut must be locked by me -- part of the condition + * protocol */ + while (thelock->locked) { + if (microseconds > 0) { + status = pthread_cond_timedwait( + &thelock->lock_released, + &thelock->mut, &ts); + if (status == ETIMEDOUT) + break; + CHECK_STATUS("pthread_cond_timed_wait"); + } + else { + status = pthread_cond_wait( + &thelock->lock_released, + &thelock->mut); + CHECK_STATUS("pthread_cond_wait"); + } + } + success = (status == 0); + } + 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_timed(%p, %lld) -> %d\n", + lock, microseconds, success)); + return success; } -int +int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) { - return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0); + return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0); } -void +void PyThread_release_lock(PyThread_type_lock lock) { - pthread_lock *thelock = (pthread_lock *)lock; - int status, error = 0; + pthread_lock *thelock = (pthread_lock *)lock; + int status, error = 0; - dprintf(("PyThread_release_lock(%p) called\n", lock)); + dprintf(("PyThread_release_lock(%p) called\n", lock)); - status = pthread_mutex_lock( &thelock->mut ); - CHECK_STATUS("pthread_mutex_lock[3]"); + status = pthread_mutex_lock( &thelock->mut ); + CHECK_STATUS("pthread_mutex_lock[3]"); - thelock->locked = 0; + thelock->locked = 0; - status = pthread_mutex_unlock( &thelock->mut ); - CHECK_STATUS("pthread_mutex_unlock[3]"); + 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"); + /* 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 */ @@ -522,39 +522,39 @@ 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; + pthread_attr_t attrs; + size_t tss_min; + int rc = 0; #endif - /* set to default */ - if (size == 0) { - _pythread_stacksize = 0; - return 0; - } + /* 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; + tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN + : THREAD_STACK_MIN; #else - tss_min = THREAD_STACK_MIN; + tss_min = THREAD_STACK_MIN; #endif - if (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; + if (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; #else - return -2; + return -2; #endif } -#define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x) +#define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x) -- cgit v1.2.1 From 4a6fcda50b929b61836ed82e57937dec5d47961a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Mon, 20 Sep 2010 02:11:49 +0000 Subject: issue 9786 Native TLS support for pthreads PyThread_create_key now has a failure mode that the applicatino can detect. --- Python/thread_pthread.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'Python/thread_pthread.h') diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 5e52b3977e..a529b7a7eb 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -558,3 +558,46 @@ _pythread_pthread_set_stacksize(size_t size) } #define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x) + +#define Py_HAVE_NATIVE_TLS + +int +PyThread_create_key(void) +{ + pthread_key_t key; + int fail = pthread_key_create(&key, NULL); + return fail ? -1 : key; +} + +void +PyThread_delete_key(int key) +{ + pthread_key_delete(key); +} + +void +PyThread_delete_key_value(int key) +{ + pthread_setspecific(key, NULL); +} + +int +PyThread_set_key_value(int key, void *value) +{ + int fail; + void *oldValue = pthread_getspecific(key); + if (oldValue != NULL) + return 0; + fail = pthread_setspecific(key, value); + return fail ? -1 : 0; +} + +void * +PyThread_get_key_value(int key) +{ + return pthread_getspecific(key); +} + +void +PyThread_ReInitTLS(void) +{} -- cgit v1.2.1 From e0d43318123b33c83747fee9593c834171a9faaf Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 10 Oct 2010 08:37:22 +0000 Subject: Issue #10062: Allow building on platforms which do not have sem_timedwait. --- Python/thread_pthread.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Python/thread_pthread.h') diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index a529b7a7eb..c007c8b906 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -64,7 +64,8 @@ /* 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) +#if (defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) && \ + defined(HAVE_SEM_TIMEDWAIT)) # define USE_SEMAPHORES #else # undef USE_SEMAPHORES -- cgit v1.2.1 From 6a156f487e0a2b723984dcd54640976b6436ac79 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 15 Dec 2010 22:59:16 +0000 Subject: Issue #8844: Regular and recursive lock acquisitions can now be interrupted by signals on platforms using pthreads. Patch by Reid Kleckner. --- Python/thread_pthread.h | 112 +++++++++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 45 deletions(-) (limited to 'Python/thread_pthread.h') diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index c007c8b906..ffc791c578 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -316,16 +316,17 @@ fix_status(int status) return (status == -1) ? errno : status; } -int -PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) +PyLockStatus +PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, + int intr_flag) { - int success; + PyLockStatus success; sem_t *thelock = (sem_t *)lock; int status, error = 0; struct timespec ts; - dprintf(("PyThread_acquire_lock_timed(%p, %lld) called\n", - lock, microseconds)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", + lock, microseconds, intr_flag)); if (microseconds > 0) MICROSECONDS_TO_TIMESPEC(microseconds, ts); @@ -336,33 +337,38 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) status = fix_status(sem_trywait(thelock)); else status = fix_status(sem_wait(thelock)); - } while (status == EINTR); /* Retry if interrupted by a signal */ - - if (microseconds > 0) { - if (status != ETIMEDOUT) - CHECK_STATUS("sem_timedwait"); - } - else if (microseconds == 0) { - if (status != EAGAIN) - CHECK_STATUS("sem_trywait"); - } - else { - CHECK_STATUS("sem_wait"); + /* Retry if interrupted by a signal, unless the caller wants to be + notified. */ + } while (!intr_flag && status == EINTR); + + /* Don't check the status if we're stopping because of an interrupt. */ + if (!(intr_flag && status == EINTR)) { + if (microseconds > 0) { + if (status != ETIMEDOUT) + CHECK_STATUS("sem_timedwait"); + } + else if (microseconds == 0) { + if (status != EAGAIN) + CHECK_STATUS("sem_trywait"); + } + else { + CHECK_STATUS("sem_wait"); + } } - success = (status == 0) ? 1 : 0; + if (status == 0) { + success = PY_LOCK_ACQUIRED; + } else if (intr_flag && status == EINTR) { + success = PY_LOCK_INTR; + } else { + success = PY_LOCK_FAILURE; + } - dprintf(("PyThread_acquire_lock_timed(%p, %lld) -> %d\n", - lock, microseconds, success)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", + lock, microseconds, intr_flag, success)); return success; } -int -PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) -{ - return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0); -} - void PyThread_release_lock(PyThread_type_lock lock) { @@ -436,21 +442,25 @@ PyThread_free_lock(PyThread_type_lock lock) free((void *)thelock); } -int -PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) +PyLockStatus +PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, + int intr_flag) { - int success; + PyLockStatus success; pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; - dprintf(("PyThread_acquire_lock_timed(%p, %lld) called\n", - lock, microseconds)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", + lock, microseconds, intr_flag)); status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS("pthread_mutex_lock[1]"); - success = thelock->locked == 0; - if (!success && microseconds != 0) { + if (thelock->locked == 0) { + success = PY_LOCK_ACQUIRED; + } else if (microseconds == 0) { + success = PY_LOCK_FAILURE; + } else { struct timespec ts; if (microseconds > 0) MICROSECONDS_TO_TIMESPEC(microseconds, ts); @@ -458,7 +468,8 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) /* mut must be locked by me -- part of the condition * protocol */ - while (thelock->locked) { + success = PY_LOCK_FAILURE; + while (success == PY_LOCK_FAILURE) { if (microseconds > 0) { status = pthread_cond_timedwait( &thelock->lock_released, @@ -473,25 +484,30 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) &thelock->mut); CHECK_STATUS("pthread_cond_wait"); } + + if (intr_flag && status == 0 && thelock->locked) { + /* We were woken up, but didn't get the lock. We probably received + * a signal. Return PY_LOCK_INTR to allow the caller to handle + * it and retry. */ + success = PY_LOCK_INTR; + break; + } else if (status == 0 && !thelock->locked) { + success = PY_LOCK_ACQUIRED; + } else { + success = PY_LOCK_FAILURE; + } } - success = (status == 0); } - if (success) thelock->locked = 1; + if (success == PY_LOCK_ACQUIRED) thelock->locked = 1; status = pthread_mutex_unlock( &thelock->mut ); CHECK_STATUS("pthread_mutex_unlock[1]"); - if (error) success = 0; - dprintf(("PyThread_acquire_lock_timed(%p, %lld) -> %d\n", - lock, microseconds, success)); + if (error) success = PY_LOCK_FAILURE; + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", + lock, microseconds, intr_flag, success)); return success; } -int -PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) -{ - return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0); -} - void PyThread_release_lock(PyThread_type_lock lock) { @@ -515,6 +531,12 @@ PyThread_release_lock(PyThread_type_lock lock) #endif /* USE_SEMAPHORES */ +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0, /*intr_flag=*/0); +} + /* set the thread stack size. * Return 0 if size is valid, -1 if size is invalid, * -2 if setting stack size is not supported. -- cgit v1.2.1