From a6ca4f40d01acfbf09751710149f49bb1053542b Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Wed, 31 Oct 2001 03:50:45 +0000 Subject: SF patch #474500: Make OS/2 locks work like posix locks, from Michael Muller. --- Misc/ACKS | 1 + Python/thread_os2.h | 91 +++++++++++++++++++++++++++++++++++------------------ 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS index 188e78d..9c032a7 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -297,6 +297,7 @@ The Dragon De Monsyne Skip Montanaro Sape Mullender Sjoerd Mullender +Michael Muller Takahiro Nakayama Travers Naran Fredrik Nehr diff --git a/Python/thread_os2.h b/Python/thread_os2.h index 31800d6..cfd0834 100644 --- a/Python/thread_os2.h +++ b/Python/thread_os2.h @@ -101,82 +101,113 @@ PyThread__exit_prog(int status) #endif /* NO_EXIT_PROG */ /* - * Lock support. It has too be implemented as semaphores. - * I [Dag] tried to implement it with mutex but I could find a way to - * tell whether a thread already own the lock or not. + * Lock support. This is implemented with an event semaphore and critical + * sections to make it behave more like a posix mutex than its OS/2 + # counterparts. */ + +typedef struct os2_lock_t { + int is_set; + HEV changed; +} *type_os2_lock; + PyThread_type_lock PyThread_allocate_lock(void) { - HMTX aLock; APIRET rc; + type_os2_lock lock = (type_os2_lock)malloc(sizeof(struct os2_lock_t)); dprintf(("PyThread_allocate_lock called\n")); if (!initialized) PyThread_init_thread(); - DosCreateMutexSem(NULL, /* Sem name */ - &aLock, /* the semaphore */ - 0, /* shared ? */ - 0); /* initial state */ + lock->is_set = 0; - dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock)); + DosCreateEventSem(NULL, &lock->changed, 0, 0); - return (PyThread_type_lock) aLock; + dprintf(("%ld: PyThread_allocate_lock() -> %p\n", + PyThread_get_thread_ident(), + lock->changed)); + + return (PyThread_type_lock) lock; } void PyThread_free_lock(PyThread_type_lock aLock) { + type_os2_lock lock = (type_os2_lock)aLock; dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); - DosCloseMutexSem((HMTX)aLock); + DosCloseEventSem(lock->changed); + free(aLock); } /* * Return 1 on success if the lock was acquired * - * and 0 if the lock was not acquired. This means a 0 is returned - * if the lock has already been acquired by this thread! + * and 0 if the lock was not acquired. */ int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) { - int success = 1; - ULONG rc, count; + int done = 0; + ULONG count; PID pid = 0; TID tid = 0; + type_os2_lock lock = (type_os2_lock)aLock; dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(), aLock, waitflag)); - DosQueryMutexSem((HMTX)aLock,&pid,&tid,&count); - if( tid == PyThread_get_thread_ident() ) { /* if we own this lock */ - success = 0; - } else { - rc = DosRequestMutexSem((HMTX) aLock, - (waitflag == 1 ? SEM_INDEFINITE_WAIT : 0)); + while (!done) { + /* if the lock is currently set, we have to wait for the state to change */ + if (lock->is_set) { + if (!waitflag) + return 0; + DosWaitEventSem(lock->changed, SEM_INDEFINITE_WAIT); + } - if( rc != 0) { - success = 0; /* We failed */ + /* + * enter a critical section and try to get the semaphore. If + * it is still locked, we will try again. + */ + if (DosEnterCritSec()) + return 0; + + if (!lock->is_set) { + lock->is_set = 1; + DosResetEventSem(lock->changed, &count); + done = 1; } - } - dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", - PyThread_get_thread_ident(),aLock, waitflag, success)); + DosExitCritSec(); + } - return success; + return 1; } -void -PyThread_release_lock(PyThread_type_lock aLock) +void PyThread_release_lock(PyThread_type_lock aLock) { + type_os2_lock lock = (type_os2_lock)aLock; dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); - if ( DosReleaseMutexSem( (HMTX) aLock ) != 0 ) { + if (!lock->is_set) { + dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", + PyThread_get_thread_ident(), aLock, GetLastError())); + return; + } + + + if (DosEnterCritSec()) { dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", PyThread_get_thread_ident(), aLock, GetLastError())); + return; } + + lock->is_set = 0; + DosPostEventSem(lock->changed); + + DosExitCritSec(); } /* -- cgit v0.12