summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog41
-rw-r--r--cleanup.c63
-rw-r--r--dll.c11
-rw-r--r--global.c12
-rw-r--r--implement.h20
-rw-r--r--mutex.c9
-rw-r--r--private.c4
-rw-r--r--tsd.c33
8 files changed, 174 insertions, 19 deletions
diff --git a/ChangeLog b/ChangeLog
index b075d4e..3a9efff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/cleanup.c b/cleanup.c
index 1eac9f3..0c8f875 100644
--- a/cleanup.c
+++ b/cleanup.c
@@ -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;
}
}
diff --git a/dll.c b/dll.c
index 83edcce..a9fa81f 100644
--- a/dll.c
+++ b/dll.c
@@ -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:
diff --git a/global.c b/global.c
index 3bd3b4e..e3af52d 100644
--- a/global.c
+++ b/global.c
@@ -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 */
diff --git a/mutex.c b/mutex.c
index 03f3f48..aabee9e 100644
--- a/mutex.c
+++ b/mutex.c
@@ -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;
}
diff --git a/private.c b/private.c
index 783e0ef..32116ef 100644
--- a/private.c
+++ b/private.c
@@ -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
diff --git a/tsd.c b/tsd.c
index d700136..8c75e72 100644
--- a/tsd.c
+++ b/tsd.c
@@ -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;
}