home *** CD-ROM | disk | FTP | other *** search
/ Programming Win32 Under the API / ProgrammingWin32UnderTheApiPatVillani.iso / src / mingw-runtime-19991107 / mingw / mthr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-30  |  5.1 KB  |  207 lines

  1. /*
  2.  * mthr.c
  3.  *
  4.  * Implement Mingw thread-support DLL .
  5.  *
  6.  * This file is used iff the following conditions are met:
  7.  *  - gcc uses -mthreads option 
  8.  *  - user code uses C++ exceptions
  9.  *
  10.  * The sole job of the Mingw thread support DLL (MingwThr) is to catch 
  11.  * all the dying threads and clean up the data allocated in the TLSs 
  12.  * for exception contexts during C++ EH. Posix threads have key dtors, 
  13.  * but win32 TLS keys do not, hence the magic. Without this, there's at 
  14.  * least `6 * sizeof (void*)' bytes leaks for each catch/throw in each
  15.  * thread. The only public interface is __mingwthr_key_dtor(). 
  16.  *
  17.  * Created by Mumit Khan  <khan@nanotech.wisc.edu>
  18.  *
  19.  */
  20.  
  21. #define WIN32_LEAN_AND_MEAN
  22. #include <windows.h>
  23. #undef WIN32_LEAN_AND_MEAN
  24. #include <stdlib.h>
  25.  
  26. /* To protect the thread/key association data structure modifications. */
  27. CRITICAL_SECTION __mingwthr_cs;
  28.  
  29. typedef struct __mingwthr_thread __mingwthr_thread_t;
  30. typedef struct __mingwthr_key __mingwthr_key_t;
  31.  
  32. /* The list of threads active with key/dtor pairs. */
  33. struct __mingwthr_key {
  34.   DWORD key;
  35.   void (*dtor) (void *);
  36.   __mingwthr_key_t *next;
  37. };
  38.  
  39. /* The list of key/dtor pairs for a particular thread. */
  40. struct __mingwthr_thread {
  41.   DWORD thread_id;
  42.   __mingwthr_key_t *keys;
  43.   __mingwthr_thread_t *next;
  44. };
  45.  
  46. static __mingwthr_thread_t *__mingwthr_thread_list;
  47.  
  48. /*
  49.  * __mingwthr_key_add:
  50.  *
  51.  * Add key/dtor association for this thread. If the thread entry does not
  52.  * exist, create a new one and add to the head of the threads list; add
  53.  * the new assoc at the head of the keys list. 
  54.  *
  55.  */
  56.  
  57. static int
  58. __mingwthr_add_key_dtor (DWORD thread_id, DWORD key, void (*dtor) (void *))
  59. {
  60.   __mingwthr_thread_t *threadp;
  61.   __mingwthr_key_t *new_key;
  62.  
  63.   new_key = (__mingwthr_key_t *) calloc (1, sizeof (__mingwthr_key_t));
  64.   if (new_key == NULL)
  65.     return -1;
  66.   
  67.   new_key->key = key;
  68.   new_key->dtor = dtor;
  69.  
  70.   /* This may be called by multiple threads, and so we need to protect
  71.      the whole process of adding the key/dtor pair.  */ 
  72.   EnterCriticalSection (&__mingwthr_cs);
  73.  
  74.   for (threadp = __mingwthr_thread_list; 
  75.        threadp && (threadp->thread_id != thread_id); 
  76.        threadp = threadp->next)
  77.     ;
  78.   
  79.   if (threadp == NULL)
  80.     {
  81.       threadp = (__mingwthr_thread_t *) 
  82.         calloc (1, sizeof (__mingwthr_thread_t));
  83.       if (threadp == NULL)
  84.         {
  85.       free (new_key);
  86.       LeaveCriticalSection (&__mingwthr_cs);
  87.       return -1;
  88.     }
  89.       threadp->thread_id = thread_id;
  90.       threadp->next = __mingwthr_thread_list;
  91.       __mingwthr_thread_list = threadp;
  92.     }
  93.  
  94.   new_key->next = threadp->keys;
  95.   threadp->keys = new_key;
  96.  
  97.   LeaveCriticalSection (&__mingwthr_cs);
  98.  
  99. #ifdef DEBUG
  100.   printf ("%s: allocating: (%ld, %ld, %x)\n", 
  101.           __FUNCTION__, thread_id, key, dtor);
  102. #endif
  103.  
  104.   return 0;
  105. }
  106.  
  107. /*
  108.  * __mingwthr_run_key_dtors (DWORD thread_id):
  109.  *
  110.  * Callback from DllMain when thread detaches to clean up the key
  111.  * storage. 
  112.  *
  113.  * Note that this does not delete the key itself, but just runs
  114.  * the dtor if the current value are both non-NULL. Note that the
  115.  * keys with NULL dtors are not added by __mingwthr_key_dtor, the
  116.  * only public interface, so we don't need to check. 
  117.  *
  118.  */
  119.  
  120. void
  121. __mingwthr_run_key_dtors (DWORD thread_id)
  122. {
  123.   __mingwthr_thread_t *prev_threadp, *threadp;
  124.   __mingwthr_key_t *keyp;
  125.  
  126. #ifdef DEBUG
  127.   printf ("%s: Entering Thread id %ld\n", __FUNCTION__, thread_id);
  128. #endif
  129.  
  130.   /* Since this is called just once per thread, we only need to protect 
  131.      the part where we take out this thread's entry and reconfigure the 
  132.      list instead of wrapping the whole process in a critical section. */
  133.   EnterCriticalSection (&__mingwthr_cs);
  134.  
  135.   prev_threadp = NULL;
  136.   for (threadp = __mingwthr_thread_list; 
  137.        threadp && (threadp->thread_id != thread_id); 
  138.        prev_threadp = threadp, threadp = threadp->next)
  139.     ;
  140.   
  141.   if (threadp == NULL)
  142.     {
  143.       LeaveCriticalSection (&__mingwthr_cs);
  144.       return;
  145.     }
  146.  
  147.   /* take the damned thread out of the chain. */
  148.   if (prev_threadp == NULL)        /* first entry hit. */
  149.     __mingwthr_thread_list = threadp->next;
  150.   else
  151.     prev_threadp->next = threadp->next;
  152.  
  153.   LeaveCriticalSection (&__mingwthr_cs);
  154.  
  155.   for (keyp = threadp->keys; keyp; )
  156.     {
  157.       __mingwthr_key_t *prev_keyp;
  158.       LPVOID value = TlsGetValue (keyp->key);
  159.       if (GetLastError () == ERROR_SUCCESS)
  160.     {
  161. #ifdef DEBUG
  162.       printf ("   (%ld, %x)\n", keyp->key, keyp->dtor);
  163. #endif
  164.       if (value)
  165.         (*keyp->dtor) (value);
  166.     }
  167. #ifdef DEBUG
  168.       else
  169.     {
  170.       printf ("   TlsGetValue FAILED  (%ld, %x)\n", 
  171.           keyp->key, keyp->dtor);
  172.     }
  173. #endif
  174.       prev_keyp = keyp;
  175.       keyp = keyp->next;
  176.       free (prev_keyp);
  177.     }
  178.   
  179.   free (threadp);
  180.  
  181. #ifdef DEBUG
  182.   printf ("%s: Exiting Thread id %ld\n", __FUNCTION__, thread_id);
  183. #endif
  184. }
  185.   
  186. /*
  187.  * __mingwthr_register_key_dtor (DWORD key, void (*dtor) (void *))
  188.  *
  189.  * Public interface called by C++ exception handling mechanism in
  190.  * libgcc (cf: __gthread_key_create).
  191.  *
  192.  */
  193.  
  194. __declspec(dllexport)
  195. int
  196. __mingwthr_key_dtor (DWORD key, void (*dtor) (void *))
  197. {
  198.   if (dtor)
  199.     {
  200.       DWORD thread_id = GetCurrentThreadId ();
  201.       return __mingwthr_add_key_dtor (thread_id, key, dtor);
  202.     }
  203.  
  204.   return 0;
  205. }
  206.  
  207.