diff options
-rw-r--r-- | ChangeLog | 41 | ||||
-rw-r--r-- | cleanup.c | 63 | ||||
-rw-r--r-- | dll.c | 11 | ||||
-rw-r--r-- | global.c | 12 | ||||
-rw-r--r-- | implement.h | 20 | ||||
-rw-r--r-- | mutex.c | 9 | ||||
-rw-r--r-- | private.c | 4 | ||||
-rw-r--r-- | tsd.c | 33 |
8 files changed, 174 insertions, 19 deletions
@@ -1,3 +1,21 @@ +1998-12-05 Anders Norlander <anorland@hem2.passagen.se> + + * implement.h (_pthread_try_enter_critical_section): New extern + * dll.c (_pthread_try_enter_critical_section): New pointer to + TryEnterCriticalSection if it exists; otherwise NULL. + * dll.c (PthreadsEntryPoint): + Initialize _pthread_try_enter_critical_section at startup + and release kernel32 handle when DLL is being unloaded. + * mutex.c (pthread_mutex_trylock): Replaced check for NT with + a check if _pthread_try_enter_critical_section is valid + pointer to a function. Call _pthread_try_enter_critical_section + instead of TryEnterCriticalSection to avoid errors on Win95. + +Sun Nov 15 21:24:06 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> + + * cleanup.c (_pthread_destructor_run_all): Declare missing void * arg. + Fixup CVS merge conflicts. + 1998-10-30 Ben Elliston <bje@cygnus.com> * condvar.c (cond_wait): Fix semantic error. Test for equality @@ -11,8 +29,31 @@ Fri Oct 30 15:15:50 1998 Ross Johnson <rpj@swan.canberra.edu.au> (new_thread): Rename poorly named local variable to "new_handler". +Sat Oct 24 18:34:59 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> + + * global.c: Add TSD key management array and index declarations. + + * implement.h: Ditto for externs. + +Fri Oct 23 00:08:09 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> + + * implement.h (_PTHREAD_TSD_KEY_REUSE): Add enum. + + * private.c (_pthread_delete_thread): Add call to + _pthread_destructor_run_all() to clean up the threads keys. + + * cleanup.c (_pthread_destructor_run_all): Check for no more dirty + keys to run destructors on. Assume that the destructor call always + succeeds and set the key value to NULL. + Thu Oct 22 21:44:44 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> + * tsd.c (pthread_setspecific): Add key management code. + (pthread_key_create): Ditto. + (pthread_key_delete): Ditto. + + * implement.h (struct _pthread_tsd_key): Add status member. + * tsd.c: Add description of pthread_key_delete() from the standard as a comment. @@ -127,6 +127,7 @@ _pthread_destructor_run_all() { _pthread_tsd_key_t * key; int count; + int dirty; /* This threads private keys */ key = _pthread_tsd_key_table; @@ -139,24 +140,76 @@ _pthread_destructor_run_all() for (count = 0; count < PTHREAD_DESTRUCTOR_ITERATIONS; count++) { int k; + void * arg; + + dirty = 0; /* Loop through all keys. */ for (k = 0; k < _POSIX_THREAD_KEYS_MAX; k++) { - /* If there's no destructor or the key isn't in use, skip it. */ - if (key->destructor != NULL && key->in_use == _PTHREAD_TSD_KEY_INUSE) - { - void * arg; + /* CRITICAL SECTION */ + pthread_mutex_lock(&_pthread_tsd_mutex); + switch (key->status) + { + case _PTHREAD_TSD_KEY_INUSE: arg = pthread_getspecific((pthread_key_t) k); - if (arg != NULL) + if (arg != NULL && key->destructor != NULL) { + /* The destructor must be called with the mutex off. */ + pthread_mutex_unlock(&_pthread_tsd_mutex); + /* END CRITICAL SECTION */ + + /* FIXME: Is the destructor supposed to set the key value + to NULL? How is this done when arg is the key value, not + a pointer to it? For now we assume that the destructor + always succeeds. + */ (void) (key->destructor)(arg); + + /* CRITICAL SECTION */ + pthread_mutex_lock(&_pthread_tsd_mutex); + + pthread_setspecific((pthread_key_t) k, NULL); +#if 0 + /* Only needed if we don't assume the destructor + always succeeds. + */ + dirty = 1; +#endif + } + break; + + case _PTHREAD_TSD_KEY_DELETED: + key->status = _PTHREAD_TSD_KEY_INUSE; + pthread_setspecific((pthread_key_t) k, NULL); + + if (key->in_use <= 0) + { + /* This is the last thread to use this + deleted key. It can now be made available + for re-use. + */ + key->status = _PTHREAD_TSD_KEY_REUSE; + } + else + { + key->status = _PTHREAD_TSD_KEY_DELETED; } + break; + + default: + break; } + pthread_mutex_unlock(&_pthread_tsd_mutex); + /* END CRITICAL SECTION */ + key++; } + + if (!dirty) + break; } } @@ -26,6 +26,12 @@ DWORD _pthread_threadID_TlsIndex; DWORD _pthread_TSD_keys_TlsIndex; +/* Function pointer to TryEnterCriticalSection if it exists; otherwise NULL */ +BOOL (WINAPI *_pthread_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL; + +/* Handle to kernel32.dll */ +static HINSTANCE _pthread_h_kernel32; + BOOL WINAPI PthreadsEntryPoint(HINSTANCE dllHandle, DWORD reason, LPVOID situation) @@ -54,11 +60,16 @@ BOOL WINAPI PthreadsEntryPoint(HINSTANCE dllHandle, { return FALSE; } + + /* Load KERNEL32 and try to get address of TryEnterCriticalSection */ + _pthread_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL")); + _pthread_try_enter_critical_section = GetProcAddress(_pthread_h_kernel32, "TryEnterCriticalSection"); break; case DLL_PROCESS_DETACH: (void) TlsFree(_pthread_TSD_keys_TlsIndex); (void) TlsFree(_pthread_threadID_TlsIndex); + (void) FreeLibrary(_pthread_h_kernel32); break; default: @@ -69,3 +69,15 @@ pthread_mutex_t _pthread_tsd_mutex = PTHREAD_MUTEX_INITIALIZER; /* Index to the next available TSD key. */ int _pthread_tsd_key_next = 0; + +/* An array of pthread_key_t */ +pthread_key_t _pthread_key_virgins[_PTHREAD_MAX_KEYS]; + +/* Index to the next available previously unused pthread_key_t */ +int _pthread_key_virgin_next; + +/* An array of pthread_key_t */ +pthread_key_t _pthread_key_reuse[_PTHREAD_MAX_KEYS]; + +/* Index to the first available reusable pthread_key_t. */ +int _pthread_key_reuse_top; diff --git a/implement.h b/implement.h index 135fc18..db6b5a2 100644 --- a/implement.h +++ b/implement.h @@ -22,7 +22,8 @@ enum { enum { _PTHREAD_TSD_KEY_DELETED, - _PTHREAD_TSD_KEY_INUSE + _PTHREAD_TSD_KEY_INUSE, + _PTHREAD_TSD_KEY_REUSE }; #define _PTHREAD_VALID(T) \ @@ -51,6 +52,7 @@ typedef struct _pthread_tsd_key _pthread_tsd_key_t; struct _pthread_tsd_key { int in_use; + int status; void (* destructor)(void *); }; @@ -177,7 +179,19 @@ extern _pthread_tsd_key_t _pthread_tsd_key_table[]; /* Mutex lock for TSD operations */ extern pthread_mutex_t _pthread_tsd_mutex; -/* Index to the next available TSD key. */ -extern int _pthread_tsd_key_next; +/* Function pointer to TryEnterCriticalSection if it exists; otherwise NULL */ +extern BOOL (WINAPI *_pthread_try_enter_critical_section)(LPCRITICAL_SECTION); + +/* An array of pthread_key_t */ +extern pthread_key_t _pthread_key_virgins[]; + +/* Index to the next available previously unused pthread_key_t */ +extern int _pthread_key_virgin_next; + +/* An array of pthread_key_t */ +extern pthread_key_t _pthread_key_reuse[]; + +/* Index to the first available reusable pthread_key_t. */ +extern int _pthread_key_reuse_top; #endif /* _IMPLEMENT_H */ @@ -88,12 +88,9 @@ pthread_mutex_unlock(pthread_mutex_t *mutex) int pthread_mutex_trylock(pthread_mutex_t *mutex) { - /* Typically evaluates to 31. */ - int numbits = (sizeof(DWORD) * 8) - 1; - - if ((GetVersion() >> numbits) != 1) + if (_pthread_try_enter_critical_section == NULL) { - /* We're not on Windows NT; return ENOSYS. */ + /* TryEnterCriticalSection does not exist in the OS; return ENOSYS. */ return ENOSYS; } @@ -107,5 +104,5 @@ pthread_mutex_trylock(pthread_mutex_t *mutex) pthread_mutex_init(mutex, NULL); } - return (TryEnterCriticalSection(&mutex->cs) != TRUE) ? EBUSY : 0; + return ((*_pthread_try_enter_critical_section)(&mutex->cs) != TRUE) ? EBUSY : 0; } @@ -120,6 +120,10 @@ _pthread_delete_thread(_pthread_t * thread) /* We don't check that the thread has been properly cleaned up, so it had better be done already. */ + /* Release any keys */ + + _pthread_destructor_run_all(); + /* Remove the thread entry if necessary. */ if (thread != NULL @@ -65,9 +65,14 @@ pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) if (_pthread_tsd_key_next >= PTHREAD_KEYS_MAX) ret = EAGAIN; + /* FIXME: This needs to be implemented as a list plus a re-use stack as for + thread IDs. _pthread_destructor_run_all() then needs to be changed + to push keys onto the re-use stack. + */ k = _pthread_tsd_key_next++; - _pthread_tsd_key_table[k].in_use = _PTHREAD_TSD_KEY_INUSE; + _pthread_tsd_key_table[k].in_use = 0; + _pthread_tsd_key_table[k].status = _PTHREAD_TSD_KEY_INUSE; _pthread_tsd_key_table[k].destructor = destructor; pthread_mutex_unlock(&_pthread_tsd_mutex); @@ -87,7 +92,7 @@ pthread_setspecific(pthread_key_t key, void *value) /* CRITICAL SECTION */ pthread_mutex_lock(&_pthread_tsd_mutex); - inuse = (_pthread_tsd_key_table[key].in_use == _PTHREAD_TSD_KEY_INUSE); + inuse = (_pthread_tsd_key_table[key].status == _PTHREAD_TSD_KEY_INUSE); pthread_mutex_unlock(&_pthread_tsd_mutex); /* END CRITICAL SECTION */ @@ -96,6 +101,24 @@ pthread_setspecific(pthread_key_t key, void *value) return EINVAL; keys = (void **) TlsGetValue(_pthread_TSD_keys_TlsIndex); + + if (keys[key] != NULL) + { + if (value == NULL) + { + /* Key is no longer in use by this thread. */ + _pthread_tsd_key_table[key].in_use--; + } + } + else + { + if (value != NULL) + { + /* Key is now in use by this thread. */ + _pthread_tsd_key_table[key].in_use++; + } + } + keys[key] = value; return 0; @@ -110,7 +133,7 @@ pthread_getspecific(pthread_key_t key) /* CRITICAL SECTION */ pthread_mutex_lock(&_pthread_tsd_mutex); - inuse = (_pthread_tsd_key_table[key].in_use == _PTHREAD_TSD_KEY_INUSE); + inuse = (_pthread_tsd_key_table[key].status == _PTHREAD_TSD_KEY_INUSE); pthread_mutex_unlock(&_pthread_tsd_mutex); /* END CRITICAL SECTION */ @@ -153,13 +176,13 @@ pthread_key_delete(pthread_key_t key) /* CRITICAL SECTION */ pthread_mutex_lock(&_pthread_tsd_mutex); - if (_pthread_tsd_key_table[key].in_use != _PTHREAD_TSD_KEY_INUSE) + if (_pthread_tsd_key_table[key].status != _PTHREAD_TSD_KEY_INUSE) { ret = EINVAL; } else { - _pthread_tsd_key_table[key].in_use = _PTHREAD_TSD_KEY_DELETED; + _pthread_tsd_key_table[key].status = _PTHREAD_TSD_KEY_DELETED; _pthread_tsd_key_table[key].destructor = NULL; } |