Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/mingw/mthr.c')
-rw-r--r--winsup/mingw/mthr.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/winsup/mingw/mthr.c b/winsup/mingw/mthr.c
new file mode 100644
index 000000000..24855479a
--- /dev/null
+++ b/winsup/mingw/mthr.c
@@ -0,0 +1,206 @@
+/*
+ * mthr.c
+ *
+ * Implement Mingw thread-support DLL .
+ *
+ * This file is used iff the following conditions are met:
+ * - gcc uses -mthreads option
+ * - user code uses C++ exceptions
+ *
+ * The sole job of the Mingw thread support DLL (MingwThr) is to catch
+ * all the dying threads and clean up the data allocated in the TLSs
+ * for exception contexts during C++ EH. Posix threads have key dtors,
+ * but win32 TLS keys do not, hence the magic. Without this, there's at
+ * least `6 * sizeof (void*)' bytes leaks for each catch/throw in each
+ * thread. The only public interface is __mingwthr_key_dtor().
+ *
+ * Created by Mumit Khan <khan@nanotech.wisc.edu>
+ *
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <stdlib.h>
+
+/* To protect the thread/key association data structure modifications. */
+CRITICAL_SECTION __mingwthr_cs;
+
+typedef struct __mingwthr_thread __mingwthr_thread_t;
+typedef struct __mingwthr_key __mingwthr_key_t;
+
+/* The list of threads active with key/dtor pairs. */
+struct __mingwthr_key {
+ DWORD key;
+ void (*dtor) (void *);
+ __mingwthr_key_t *next;
+};
+
+/* The list of key/dtor pairs for a particular thread. */
+struct __mingwthr_thread {
+ DWORD thread_id;
+ __mingwthr_key_t *keys;
+ __mingwthr_thread_t *next;
+};
+
+static __mingwthr_thread_t *__mingwthr_thread_list;
+
+/*
+ * __mingwthr_key_add:
+ *
+ * Add key/dtor association for this thread. If the thread entry does not
+ * exist, create a new one and add to the head of the threads list; add
+ * the new assoc at the head of the keys list.
+ *
+ */
+
+static int
+__mingwthr_add_key_dtor (DWORD thread_id, DWORD key, void (*dtor) (void *))
+{
+ __mingwthr_thread_t *threadp;
+ __mingwthr_key_t *new_key;
+
+ new_key = (__mingwthr_key_t *) calloc (1, sizeof (__mingwthr_key_t));
+ if (new_key == NULL)
+ return -1;
+
+ new_key->key = key;
+ new_key->dtor = dtor;
+
+ /* This may be called by multiple threads, and so we need to protect
+ the whole process of adding the key/dtor pair. */
+ EnterCriticalSection (&__mingwthr_cs);
+
+ for (threadp = __mingwthr_thread_list;
+ threadp && (threadp->thread_id != thread_id);
+ threadp = threadp->next)
+ ;
+
+ if (threadp == NULL)
+ {
+ threadp = (__mingwthr_thread_t *)
+ calloc (1, sizeof (__mingwthr_thread_t));
+ if (threadp == NULL)
+ {
+ free (new_key);
+ LeaveCriticalSection (&__mingwthr_cs);
+ return -1;
+ }
+ threadp->thread_id = thread_id;
+ threadp->next = __mingwthr_thread_list;
+ __mingwthr_thread_list = threadp;
+ }
+
+ new_key->next = threadp->keys;
+ threadp->keys = new_key;
+
+ LeaveCriticalSection (&__mingwthr_cs);
+
+#ifdef DEBUG
+ printf ("%s: allocating: (%ld, %ld, %x)\n",
+ __FUNCTION__, thread_id, key, dtor);
+#endif
+
+ return 0;
+}
+
+/*
+ * __mingwthr_run_key_dtors (DWORD thread_id):
+ *
+ * Callback from DllMain when thread detaches to clean up the key
+ * storage.
+ *
+ * Note that this does not delete the key itself, but just runs
+ * the dtor if the current value are both non-NULL. Note that the
+ * keys with NULL dtors are not added by __mingwthr_key_dtor, the
+ * only public interface, so we don't need to check.
+ *
+ */
+
+void
+__mingwthr_run_key_dtors (DWORD thread_id)
+{
+ __mingwthr_thread_t *prev_threadp, *threadp;
+ __mingwthr_key_t *keyp;
+
+#ifdef DEBUG
+ printf ("%s: Entering Thread id %ld\n", __FUNCTION__, thread_id);
+#endif
+
+ /* Since this is called just once per thread, we only need to protect
+ the part where we take out this thread's entry and reconfigure the
+ list instead of wrapping the whole process in a critical section. */
+ EnterCriticalSection (&__mingwthr_cs);
+
+ prev_threadp = NULL;
+ for (threadp = __mingwthr_thread_list;
+ threadp && (threadp->thread_id != thread_id);
+ prev_threadp = threadp, threadp = threadp->next)
+ ;
+
+ if (threadp == NULL)
+ {
+ LeaveCriticalSection (&__mingwthr_cs);
+ return;
+ }
+
+ /* take the damned thread out of the chain. */
+ if (prev_threadp == NULL) /* first entry hit. */
+ __mingwthr_thread_list = threadp->next;
+ else
+ prev_threadp->next = threadp->next;
+
+ LeaveCriticalSection (&__mingwthr_cs);
+
+ for (keyp = threadp->keys; keyp; )
+ {
+ __mingwthr_key_t *prev_keyp;
+ LPVOID value = TlsGetValue (keyp->key);
+ if (GetLastError () == ERROR_SUCCESS)
+ {
+#ifdef DEBUG
+ printf (" (%ld, %x)\n", keyp->key, keyp->dtor);
+#endif
+ if (value)
+ (*keyp->dtor) (value);
+ }
+#ifdef DEBUG
+ else
+ {
+ printf (" TlsGetValue FAILED (%ld, %x)\n",
+ keyp->key, keyp->dtor);
+ }
+#endif
+ prev_keyp = keyp;
+ keyp = keyp->next;
+ free (prev_keyp);
+ }
+
+ free (threadp);
+
+#ifdef DEBUG
+ printf ("%s: Exiting Thread id %ld\n", __FUNCTION__, thread_id);
+#endif
+}
+
+/*
+ * __mingwthr_register_key_dtor (DWORD key, void (*dtor) (void *))
+ *
+ * Public interface called by C++ exception handling mechanism in
+ * libgcc (cf: __gthread_key_create).
+ *
+ */
+
+__declspec(dllexport)
+int
+__mingwthr_key_dtor (DWORD key, void (*dtor) (void *))
+{
+ if (dtor)
+ {
+ DWORD thread_id = GetCurrentThreadId ();
+ return __mingwthr_add_key_dtor (thread_id, key, dtor);
+ }
+
+ return 0;
+}
+