diff options
author | rpj <rpj> | 1998-12-06 02:52:22 +0000 |
---|---|---|
committer | rpj <rpj> | 1998-12-06 02:52:22 +0000 |
commit | 737e67dda7d7a2c4832e2d42132fd2fa3b211de5 (patch) | |
tree | 95de231d88047d8b5775c27019b9f293e65d32ed | |
parent | 47d04bda4e14c8aef0c3fa7e8ae64e690b25fb66 (diff) |
As well as patches from Anders, this commit includes some older changes
that hadn't been checked in. Those are to finish off the original TSD management
scheme which will now start to be replaced by John Bossom's implementation.
Anders' description of his changes:-
Fixes the problem with
`TryEnterCriticalSection' on w95 systems. Instead
of directly calling `TryEnterCriticalSection' it
tries to get a pointer at DLL startup and only calls
the function if it exists. See ChangeLog for things
changed.
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.
Fri Oct 30 15:15:50 1998 Ross Johnson <rpj@swan.canberra.edu.au>
* cleanup.c (_pthread_handler_push): Fixed bug appending new
handler to list reported by Peter Slacik
<Peter.Slacik@leibinger.freinet.de>.
(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.
-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; } |