windows-pthread-rwlock-20081017
[openafs.git] / src / WINNT / pthread / pthread.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * This file contains a skeleton pthread implementation for NT.
12  * This is not intended to be a fully compliant pthread implementation
13  * The purpose of this file is to only implement those functions that
14  * are truly needed to support the afs code base.
15  *
16  * A secondary goal is to allow a "real" pthread implementation to 
17  * replace this file without any modification to code that depends upon
18  * this file
19  *
20  * The function signatures and argument types are meant to be the same
21  * as their UNIX prototypes.
22  * Where possible, the POSIX specified return values are used.
23  * For situations where an error can occur, but no corresponding
24  * POSIX error value exists, unique (within a given function) negative 
25  * numbers are used for errors to avoid collsions with the errno
26  * style values.
27  */
28
29 #include <afs/param.h>
30 #include <afs/stds.h>
31
32 #include <pthread.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <process.h>
37 #include <errno.h>
38 #include <sys/timeb.h>
39
40 #define PTHREAD_EXIT_EXCEPTION 0x1
41
42 /*
43  * Posix threads uses static initialization for pthread_once control
44  * objects, and under NT, every sophisticated synchronization primitive
45  * uses procedural initialization.  This forces the use of CompareExchange
46  * (aka test and set) and busy waiting for threads that compete to run
47  * a pthread_once'd function.  We make these "busy" threads give up their
48  * timeslice - which should cause acceptable behavior on a single processor
49  * machine, but on a multiprocessor machine this could very well result
50  * in busy waiting.
51  */
52
53 int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) {
54     int rc = 0;
55
56     if ((once_control != NULL) && (init_routine != NULL)) {
57         if (InterlockedExchange((LPLONG)&once_control->call_started,
58                                 (LONG) 1) == 0) {
59             (*init_routine)();
60             once_control->call_running = 0;
61         } else {
62             /* use Sleep() since SwitchToThread() not available on Win95 */
63             while(once_control->call_running) Sleep(20);
64         }
65     } else {
66         rc = EINVAL;
67     }
68     return rc;
69 }
70
71 /*
72  * For now only support PTHREAD_PROCESS_PRIVATE mutexes.
73  * if PTHREAD_PROCESS_SHARED are required later they can be added
74  */
75
76 int pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr) {
77     int rc = 0;
78
79     if ((mp != NULL) && (attr == NULL)) {
80         InitializeCriticalSection(&mp->cs);
81         mp->isLocked = 0;
82         mp->tid = 0;
83     } else {
84         rc = EINVAL;
85     }
86     return rc;
87 }
88
89 /*
90  * Under NT, critical sections can be locked recursively by the owning
91  * thread.  This is opposite of the pthread spec, and so we keep track
92  * of the thread that has locked a critical section.  If the same thread
93  * tries to lock a critical section more than once we fail.
94  */
95 int pthread_mutex_trylock(pthread_mutex_t *mp) {
96     int rc = 0;
97
98 #ifdef AFS_WIN95_ENV
99     /* TryEnterCriticalSection() not available on Win95, so just wait for
100      * the lock.  Correct code generally can't depend on how long the
101      * function takes to return, so the only code that will be broken is
102      * that for which 1) the mutex *mp is obtained and never released or
103      * 2) the mutex *mp is intentionally held until trylock() returns.
104      * These cases are unusual and don't appear in normal (non-test) AFS
105      * code; furthermore, we can reduce (but not eliminate!) the problem by
106      * sneaking a look at isLocked even though we don't hold the
107      * CRITICAL_SECTION in mutex *mp and are thus vulnerable to race
108      * conditions.  Note that self-deadlock isn't a problem since
109      * CRITICAL_SECTION objects are recursive.
110      *
111      * Given the very restricted usage of the pthread library on Windows 95,
112      * we can live with these limitations.
113      */
114     if (mp != NULL) {
115         if (mp->isLocked) {
116             rc = EBUSY;
117         } else {
118             rc = pthread_mutex_lock(mp);
119         }
120     } else {
121         rc = EINVAL;
122     }
123 #else
124     /* TryEnterCriticalSection() provided on other MS platforms of interest */
125     if (mp != NULL) {
126         if (TryEnterCriticalSection(&mp->cs)) {
127             if (mp->isLocked) {
128                 /* same thread tried to recursively lock, fail */
129                 LeaveCriticalSection(&mp->cs);
130                 rc = EDEADLK;
131             } else {
132                 mp->isLocked = 1;
133                 mp->tid = GetCurrentThreadId();
134                 rc = 0;
135             }
136         } else {
137             rc = EBUSY;
138         }
139     } else {
140         rc = EINVAL;
141     }
142 #endif /* AFS_WIN95_ENV */
143
144     return rc;
145 }
146
147
148 int pthread_mutex_lock(pthread_mutex_t *mp) {
149     int rc = 0;
150
151     if (mp != NULL) {
152         EnterCriticalSection(&mp->cs);
153         if (!mp->isLocked) {
154             mp->isLocked = 1;
155             mp->tid = GetCurrentThreadId();
156         } else {
157             /* 
158              * same thread tried to recursively lock this mutex.
159              * Under real POSIX, this would cause a deadlock, but NT only 
160              * supports recursive mutexes so we indicate the situation
161              * by returning EDEADLK.
162              */
163             LeaveCriticalSection(&mp->cs);
164             rc = EDEADLK;
165 #ifdef PTHREAD_DEBUG
166             DebugBreak();
167 #endif
168         }
169     } else {
170 #ifdef PTHREAD_DEBUG
171         DebugBreak();
172 #endif
173         rc = EINVAL;
174     }
175         
176     return rc;
177 }
178
179 int pthread_mutex_unlock(pthread_mutex_t *mp) {
180     int rc = 0;
181
182     if (mp != NULL) {
183         if (mp->tid == GetCurrentThreadId()) {
184             mp->isLocked = 0;
185             mp->tid = 0;
186             LeaveCriticalSection(&mp->cs);
187         } else {
188 #ifdef PTHREAD_DEBUG
189             DebugBreak();
190 #endif
191             rc = EPERM;
192         }
193     } else {
194 #ifdef PTHREAD_DEBUG
195         DebugBreak();
196 #endif
197         rc = EINVAL;
198     }
199     return rc;
200 }
201
202 int pthread_mutex_destroy(pthread_mutex_t *mp) {
203     int rc = 0;
204
205     if (mp != NULL) {
206         DeleteCriticalSection(&mp->cs);
207     } else {
208 #ifdef PTHREAD_DEBUG
209         DebugBreak();
210 #endif
211         rc = EINVAL;
212     }
213
214     return rc;
215 }
216
217 int pthread_rwlock_destroy(pthread_rwlock_t *rwp)
218 {
219     int rc = 0;
220
221     if (rwp != NULL) {
222         pthread_mutex_destroy(&rwp->read_access_completion_mutex);
223         pthread_mutex_destroy(&rwp->write_access_mutex);
224         pthread_cond_destroy(&rwp->read_access_completion_wait);
225     } else {
226 #ifdef PTHREAD_DEBUG
227         DebugBreak();
228 #endif
229         rc = EINVAL;
230     }
231
232     return rc;
233 }
234
235 int pthread_rwlock_init(pthread_rwlock_t *rwp, const pthread_rwlockattr_t *attr)
236 {
237     int rc = 0;
238
239     if (rwp == NULL)
240         return EINVAL;
241
242     rwp->readers = 0;
243
244     rc = pthread_mutex_init(&rwp->write_access_mutex, NULL);
245     if (rc)
246         return rc;
247
248     rc = pthread_mutex_init(&rwp->read_access_completion_mutex, NULL);
249     if (rc)
250         goto error1;
251
252     rc = pthread_cond_init(&rwp->read_access_completion_wait, NULL);
253     if (rc == 0)
254         return 0;       /* success */
255
256     pthread_mutex_destroy(&rwp->read_access_completion_mutex);
257
258   error1:
259     pthread_mutex_destroy(&rwp->write_access_mutex);
260
261     return rc;
262 }
263
264 int pthread_rwlock_wrlock(pthread_rwlock_t *rwp)
265 {
266     int rc = 0;
267
268     if (rwp == NULL)
269         return EINVAL;
270
271     if ((rc = pthread_mutex_lock(&rwp->write_access_mutex)) != 0)
272         return rc;
273
274     if ((rc = pthread_mutex_lock(&rwp->read_access_completion_mutex)) != 0)
275     {
276         pthread_mutex_unlock(&rwp->write_access_mutex);
277         return rc;
278     }
279
280     while (rc == 0 && rwp->readers > 0) {
281         rc = pthread_cond_wait( &rwp->read_access_completion_wait, 
282                                 &rwp->read_access_completion_mutex);
283     }
284
285     pthread_mutex_unlock(&rwp->read_access_completion_mutex);
286
287     if (rc)
288         pthread_mutex_unlock(&rwp->write_access_mutex);
289
290     return rc;
291 }
292
293 int pthread_rwlock_rdlock(pthread_rwlock_t *rwp)
294 {
295     int rc = 0;
296
297     if (rwp == NULL)
298         return EINVAL;
299
300     if ((rc = pthread_mutex_lock(&rwp->write_access_mutex)) != 0)
301         return rc;
302
303     if ((rc = pthread_mutex_lock(&rwp->read_access_completion_mutex)) != 0)
304     {
305         pthread_mutex_unlock(&rwp->write_access_mutex);
306         return rc;
307     }
308
309     rwp->readers++;
310
311     pthread_mutex_unlock(&rwp->read_access_completion_mutex);
312
313     pthread_mutex_unlock(&rwp->write_access_mutex);
314
315     return rc;
316         
317 }
318
319 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwp)
320 {
321     int rc = 0;
322
323     if (rwp == NULL)
324         return EINVAL;
325
326     if ((rc = pthread_mutex_trylock(&rwp->write_access_mutex)) != 0)
327         return rc;
328
329     if ((rc = pthread_mutex_trylock(&rwp->read_access_completion_mutex)) != 0) {
330         pthread_mutex_unlock(&rwp->write_access_mutex);
331         return rc;
332     }
333
334     rwp->readers++;
335
336     pthread_mutex_unlock(&rwp->read_access_completion_mutex);
337
338     pthread_mutex_unlock(&rwp->write_access_mutex);
339
340     return rc;
341 }
342
343 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwp)
344 {
345     int rc = 0;
346
347     if (rwp == NULL)
348         return EINVAL;
349
350     if ((rc = pthread_mutex_trylock(&rwp->write_access_mutex)) != 0)
351         return rc;
352
353     if ((rc = pthread_mutex_trylock(&rwp->read_access_completion_mutex)) != 0)
354     {
355         pthread_mutex_unlock(&rwp->write_access_mutex);
356         return rc;
357     }
358
359     if (rwp->readers > 0)
360         rc = EBUSY;
361
362     pthread_mutex_unlock(&rwp->read_access_completion_mutex);
363
364     if (rc)
365         pthread_mutex_unlock(&rwp->write_access_mutex);
366
367     return rc;
368 }
369
370 int pthread_rwlock_unlock(pthread_rwlock_t *rwp)
371 {
372     int rc = 0;
373
374     if (rwp == NULL)
375         return EINVAL;
376
377     rc = pthread_mutex_trylock(&rwp->write_access_mutex);
378     if (rc != EDEADLK)
379     {
380         /* unlock a read lock */
381         if (rc == 0)
382             pthread_mutex_unlock(&rwp->write_access_mutex);
383         
384         if ((rc = pthread_mutex_lock(&rwp->read_access_completion_mutex)) != 0)
385         {
386             pthread_mutex_unlock(&rwp->write_access_mutex);
387             return rc;
388         }
389
390         if (rwp->readers <= 0)
391         {
392             rc = EINVAL;
393         }
394         else 
395         {
396             if (--rwp->readers == 0) 
397                 pthread_cond_broadcast(&rwp->read_access_completion_wait);
398         }
399
400         pthread_mutex_unlock(&rwp->read_access_completion_mutex);
401     } 
402     else
403     {
404         /* unlock a write lock */
405         rc = pthread_mutex_unlock(&rwp->write_access_mutex);
406     }
407
408     return rc;
409 }
410
411
412 /*
413  * keys is used to keep track of which keys are currently
414  * in use by the threads library.  pthread_tsd_mutex is used
415  * to protect keys.
416  *
417  * The bookkeeping for keys in use and destructor function/key is
418  * at the library level.  Each individual thread only keeps its
419  * per key data value.  This implies that the keys array and the
420  * tsd array in the pthread_t structure need to always be exactly
421  * the same size since the same index is used for both arrays.
422  */
423
424 typedef struct {
425     int inuse;
426     void (*destructor)(void *);
427 } pthread_tsd_table_t;
428
429 static pthread_tsd_table_t keys[PTHREAD_KEYS_MAX];
430 static pthread_mutex_t pthread_tsd_mutex;
431 static pthread_once_t pthread_tsd_once = PTHREAD_ONCE_INIT;
432
433 /*
434  * In order to support p_self() and p_join() under NT,
435  * we have to keep our own list of active threads and provide a mapping
436  * function that maps the NT thread id to our internal structure.
437  * The main reason that this is necessary is that GetCurrentThread
438  * returns a special constant not an actual handle to the thread.
439  * This makes it impossible to write a p_self() function that works
440  * with only the native NT functions.
441  */
442
443 static struct rx_queue active_Q;
444 static struct rx_queue cache_Q;
445
446 static pthread_mutex_t active_Q_mutex;
447 static pthread_mutex_t cache_Q_mutex;
448
449 static pthread_once_t pthread_cache_once = PTHREAD_ONCE_INIT;
450 static int pthread_cache_done;
451
452 typedef struct thread {
453     struct rx_queue thread_queue;
454     void *rc;
455     int running;
456     pthread_cond_t wait_terminate;
457     int waiter_count;
458     int is_joinable;
459     int has_been_joined;
460     HANDLE t_handle;
461     DWORD NT_id;
462     int native_thread;
463     char **tsd;
464 } thread_t, *thread_p;
465
466 static void create_once(void) {
467     queue_Init(&active_Q);
468     queue_Init(&cache_Q);
469     pthread_mutex_init(&active_Q_mutex, (const pthread_mutexattr_t*)0);
470     pthread_mutex_init(&cache_Q_mutex, (const pthread_mutexattr_t*)0);
471     pthread_cache_done = 1;
472 }
473
474 static void cleanup_pthread_cache(void) {
475     thread_p cur = NULL, next = NULL;
476
477     if (pthread_cache_done) {
478         for(queue_Scan(&active_Q, cur, next, thread)) {
479             queue_Remove(cur);
480         }
481         for(queue_Scan(&cache_Q, cur, next, thread)) {
482             queue_Remove(cur);
483         }
484
485         pthread_mutex_destroy(&active_Q_mutex);
486         pthread_mutex_destroy(&cache_Q_mutex);
487
488         pthread_cache_done = 0;
489     }
490 }       
491
492 static void put_thread(thread_p old) {
493  
494     CloseHandle(old->t_handle);
495     pthread_mutex_lock(&cache_Q_mutex);
496     queue_Prepend(&cache_Q, old);
497     pthread_mutex_unlock(&cache_Q_mutex);
498 }
499
500 static thread_p get_thread() {
501     thread_p new = NULL;
502  
503     pthread_mutex_lock(&cache_Q_mutex);
504  
505     if (queue_IsEmpty(&cache_Q)) {
506         new = (thread_p) malloc(sizeof(thread_t));
507         if (new != NULL) {
508             /*
509              * One time initialization - we assume threads put back have
510              * unlocked mutexes and condition variables with no waiters
511              *
512              * These functions cannot fail currently.
513              */
514             pthread_cond_init(&new->wait_terminate,(const pthread_condattr_t *)0);
515         }
516     } else {
517         new = queue_First(&cache_Q, thread);
518         queue_Remove(new);
519     }
520  
521     pthread_mutex_unlock(&cache_Q_mutex);
522
523     /* 
524      * Initialization done every time we hand out a thread_t
525      */
526
527     if (new != NULL) {
528         new->rc = NULL;
529         new->running = 1;
530         new->waiter_count = 0;
531         new->has_been_joined = 0;
532     }
533     return new;
534  
535 }
536  
537 /*
538  * The thread start function signature is different on NT than the pthread
539  * spec so we create a tiny stub to map from one signature to the next.
540  * This assumes that a void * can be stored within a DWORD.
541  */
542
543 typedef struct {
544     void *(*func)(void *);
545     void *arg;
546     char *tsd[PTHREAD_KEYS_MAX];
547     thread_p me;
548 } pthread_create_t;
549
550 static DWORD tsd_index = 0xffffffff;
551 static DWORD tsd_pthread_index = 0xffffffff;
552 static pthread_once_t global_tsd_once = PTHREAD_ONCE_INIT;
553 static int tsd_done;
554
555 static void tsd_once(void) {
556     while(tsd_index == 0xffffffff) {
557         tsd_index = TlsAlloc();
558     }
559     while(tsd_pthread_index == 0xffffffff) {
560         tsd_pthread_index = TlsAlloc();
561     }
562     tsd_done = 1;
563 }
564
565 static void tsd_free_all(char *tsd[PTHREAD_KEYS_MAX]) {
566     int call_more_destructors = 0;
567     do {
568         int i;
569         void *value;
570         void (*destructor)(void *);
571         call_more_destructors = 0;
572         for(i=0;i<PTHREAD_KEYS_MAX;i++) {
573             if (tsd[i] != NULL) {
574                 destructor = keys[i].destructor;
575                 value = (void *)tsd[i];
576                 tsd[i] = NULL;
577                 if (destructor != NULL) {
578                     (destructor)(value);
579                     /*
580                      * A side-effect of calling a destructor function is that
581                      * more thread specific may be created for this thread.
582                      * If we call a destructor, we must recycle through the
583                      * entire list again and run any new destructors.
584                      */
585                     call_more_destructors = 1;
586                 }
587             }
588         }
589     } while(call_more_destructors);
590 }
591
592 static void cleanup_global_tsd(void)
593 {
594     thread_p cur = NULL, next = NULL;
595
596     if (tsd_done) {
597         for(queue_Scan(&active_Q, cur, next, thread)) {
598             tsd_free_all(cur->tsd);
599         }
600
601         TlsFree(tsd_pthread_index);
602         tsd_pthread_index = 0xFFFFFFFF;
603         TlsFree(tsd_index);
604         tsd_index = 0xFFFFFFFF;
605         tsd_done = 0;
606     }
607 }
608
609 static DWORD WINAPI afs_pthread_create_stub(LPVOID param) {
610     pthread_create_t *t = (pthread_create_t *) param;
611     void *rc;
612
613     /* 
614      * Initialize thread specific storage structures.
615      */
616
617     memset(t->tsd, 0, (sizeof(char *) * PTHREAD_KEYS_MAX));
618     (tsd_done || pthread_once(&global_tsd_once, tsd_once));
619     TlsSetValue(tsd_index, (LPVOID) (t->tsd));
620     TlsSetValue(tsd_pthread_index, (LPVOID) (t->me));
621
622     /*
623      * Call the function the user passed to pthread_create and catch the
624      * pthread exit exception if it is raised.
625      */
626
627     __try {
628         rc = (*(t->func))(t->arg);
629     } __except(GetExceptionCode() == PTHREAD_EXIT_EXCEPTION) {
630         rc = t->me->rc; /* rc is set at pthread_exit */
631     }
632
633     /*
634      * Cycle through the thread specific data for this thread and
635      * call the destructor function for each non-NULL datum
636      */
637
638     tsd_free_all (t->tsd);
639     t->me->tsd = NULL;
640
641     /*
642      * If we are joinable, signal any waiters.
643      */
644
645     pthread_mutex_lock(&active_Q_mutex);
646     if (t->me->is_joinable) {
647         t->me->running = 0;
648         t->me->rc = rc;
649         if (t->me->waiter_count) {
650             pthread_cond_broadcast(&t->me->wait_terminate);
651         }
652     } else {
653         queue_Remove(t->me);
654         put_thread(t->me);
655     }
656     pthread_mutex_unlock(&active_Q_mutex);
657
658     free(t);
659     return 0;
660 }
661
662 /*
663  * If a pthread function is called on a thread which was not created by
664  * pthread_create(), that thread will have an entry added to the active_Q
665  * by pthread_self(). When the thread terminates, we need to know
666  * about it, so that we can perform cleanup. A dedicated thread is therefore
667  * maintained, which watches for any thread marked "native_thread==1"
668  * in the active_Q to terminate. The thread spends most of its time sleeping:
669  * it can be signalled by a dedicated event in order to alert it to the
670  * presense of a new thread to watch, or will wake up automatically when
671  * a native thread terminates.
672  */
673
674 static DWORD terminate_thread_id = 0;
675 static HANDLE terminate_thread_handle = INVALID_HANDLE_VALUE;
676 static HANDLE terminate_thread_wakeup_event = INVALID_HANDLE_VALUE;
677 static HANDLE *terminate_thread_wakeup_list = NULL;
678 static size_t terminate_thread_wakeup_list_size = 0;
679
680 static DWORD WINAPI terminate_thread_routine(LPVOID param) {
681     thread_p cur, next;
682     DWORD native_thread_count;
683     int should_terminate;
684     int terminate_thread_wakeup_list_index;
685
686     for (;;) {
687         /*
688          * Grab the active_Q_mutex, and while we hold it, scan the active_Q
689          * to see how many native threads we need to watch. If we don't need
690          * to watch any, we can stop this watcher thread entirely (or not);
691          * if we do need to watch some, fill the terminate_thread_wakeup_list
692          * array and go to sleep.
693          */
694         cur = NULL;
695         next = NULL;
696         native_thread_count = 0;
697         should_terminate = FALSE;
698         pthread_mutex_lock(&active_Q_mutex);
699
700         for(queue_Scan(&active_Q, cur, next, thread)) {
701             if (cur->native_thread)
702                 ++native_thread_count;
703         }
704
705         /*
706          * At this point we could decide to terminate this watcher thread
707          * whenever there are no longer any native threads to watch--however,
708          * since thread creation is a time-consuming thing, and since this
709          * thread spends all its time sleeping anyway, there's no real
710          * compelling reason to do so. Thus, the following statement is
711          * commented out:
712          *
713          * if (!native_thread_count) {
714          *    should_terminate = TRUE;
715          * }
716          *
717          * Restore the snippet above to cause this watcher thread to only
718          * live whenever there are native threads to watch.
719          *
720          */
721
722         /*
723          * Make sure that our wakeup_list array is large enough to contain
724          * the handles of all the native threads /and/ to contain an
725          * entry for our wakeup_event (in case another native thread comes
726          * along).
727          */
728         if (terminate_thread_wakeup_list_size < (1+native_thread_count)) {
729             if (terminate_thread_wakeup_list)
730                 free (terminate_thread_wakeup_list);
731             terminate_thread_wakeup_list = (HANDLE*)malloc (sizeof(HANDLE) *
732                                 (1+native_thread_count));
733             if (terminate_thread_wakeup_list == NULL) {
734                 should_terminate = TRUE;
735             } else {
736                 terminate_thread_wakeup_list_size = 1+native_thread_count;
737             }
738         }
739
740         if (should_terminate) {
741             /*
742              * Here, we've decided to terminate this watcher thread.
743              * Free our wakeup event and wakeup list, then release the
744              * active_Q_mutex and break this loop.
745              */
746             if (terminate_thread_wakeup_list)
747                 free (terminate_thread_wakeup_list);
748             CloseHandle (terminate_thread_wakeup_event);
749             terminate_thread_id = 0;
750             terminate_thread_handle = INVALID_HANDLE_VALUE;
751             terminate_thread_wakeup_event = INVALID_HANDLE_VALUE;
752             terminate_thread_wakeup_list = NULL;
753             terminate_thread_wakeup_list_size = 0;
754             pthread_mutex_unlock(&active_Q_mutex);
755             break;
756         } else {
757             /*
758              * Here, we've decided to wait for native threads et al.
759              * Fill out the wakeup_list.
760              */
761             memset(terminate_thread_wakeup_list, 0x00, (sizeof(HANDLE) * 
762                                 (1+native_thread_count)));
763
764             terminate_thread_wakeup_list[0] = terminate_thread_wakeup_event;
765             terminate_thread_wakeup_list_index = 1;
766
767             cur = NULL;
768             next = NULL;
769             for(queue_Scan(&active_Q, cur, next, thread)) {
770                 if (cur->native_thread) {
771                     terminate_thread_wakeup_list[terminate_thread_wakeup_list_index]
772                         = cur->t_handle;
773                     ++terminate_thread_wakeup_list_index;
774                 }
775             }
776
777             ResetEvent (terminate_thread_wakeup_event);
778         }
779
780         pthread_mutex_unlock(&active_Q_mutex);
781
782         /*
783          * Time to sleep. We'll wake up if either of the following happen:
784          * 1) Someone sets the terminate_thread_wakeup_event (this will
785          *    happen if another native thread gets added to the active_Q)
786          * 2) One or more of the native threads terminate
787          */
788         terminate_thread_wakeup_list_index = WaitForMultipleObjects(
789                                         1+native_thread_count,
790                                         terminate_thread_wakeup_list,
791                                         FALSE,
792                                         INFINITE);
793
794         /*
795          * If we awoke from sleep because an event other than
796          * terminate_thread_wakeup_event was triggered, it means the
797          * specified thread has terminated. (If more than one thread
798          * terminated, we'll handle this first one and loop around--
799          * the event's handle will still be triggered, so we just won't
800          * block at all when we sleep next time around.)
801          */
802         if (terminate_thread_wakeup_list_index > 0) {
803             pthread_mutex_lock(&active_Q_mutex);
804
805             cur = NULL;
806             next = NULL;
807             for(queue_Scan(&active_Q, cur, next, thread)) {
808                 if (cur->t_handle == terminate_thread_wakeup_list[ terminate_thread_wakeup_list_index ])
809                     break;
810             }
811
812             if(cur != NULL) {
813                 /*
814                  * Cycle through the thread specific data for the specified
815                  * thread and call the destructor function for each non-NULL
816                  * datum. Then remove the thread_t from active_Q and put it
817                  * back on cache_Q for possible later re-use.
818                  */
819                 if(cur->tsd != NULL) {
820                     tsd_free_all(cur->tsd);
821                     free(cur->tsd);
822                     cur->tsd = NULL;
823                 }
824                 queue_Remove(cur);
825                 put_thread(cur);
826             }
827
828             pthread_mutex_unlock(&active_Q_mutex);
829         }
830     }
831     return 0;
832 }
833
834
835 static void pthread_sync_terminate_thread(void) {
836     (pthread_cache_done || pthread_once(&pthread_cache_once, create_once));
837
838     if (terminate_thread_handle == INVALID_HANDLE_VALUE) {
839         CHAR eventName[MAX_PATH];
840         static eventCount = 0;
841         sprintf(eventName, "terminate_thread_wakeup_event %d::%d", _getpid(), eventCount++);
842         terminate_thread_wakeup_event = CreateEvent((LPSECURITY_ATTRIBUTES) 0,
843                                                      TRUE, FALSE, (LPCTSTR) eventName);
844         terminate_thread_handle = CreateThread((LPSECURITY_ATTRIBUTES) 0, 0, 
845                                                 terminate_thread_routine, (LPVOID) 0, 0, 
846                                                 &terminate_thread_id);
847     } else {
848         SetEvent (terminate_thread_wakeup_event);
849     }
850 }
851
852
853 /*
854  * Only support the detached attribute specifier for pthread_create.
855  * Under NT, thread stacks grow automatically as needed.
856  */
857
858 int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func)(void *), void *arg) {
859     int rc = 0;
860     pthread_create_t *t = NULL;
861
862     (pthread_cache_done || pthread_once(&pthread_cache_once, create_once));
863
864     if ((tid != NULL) && (func != NULL)) {
865         if ((t = (pthread_create_t *) malloc(sizeof(pthread_create_t))) &&
866             (t->me = get_thread()) ) {
867             t->func = func;
868             t->arg = arg;
869             *tid = (pthread_t) t->me;
870             if (attr != NULL) {
871                 t->me->is_joinable = attr->is_joinable;
872             } else {
873                 t->me->is_joinable = PTHREAD_CREATE_JOINABLE;
874             }
875             t->me->native_thread = 0;
876             t->me->tsd = t->tsd;
877             /*
878              * At the point (before we actually create the thread)
879              * we need to add our entry to the active queue.  This ensures
880              * us that other threads who may run after this thread returns
881              * will find an entry for the create thread regardless of
882              * whether the newly created thread has run or not.
883              * In the event the thread create fails, we will have temporarily
884              * added an entry to the list that was never valid, but we
885              * (i.e. the thread that is calling thread_create) are the
886              * only one who could possibly know about the bogus entry
887              * since we hold the active_Q_mutex.
888              */
889             pthread_mutex_lock(&active_Q_mutex);
890             queue_Prepend(&active_Q, t->me);
891             t->me->t_handle = CreateThread((LPSECURITY_ATTRIBUTES) 0, 0, 
892                                 afs_pthread_create_stub, (LPVOID) t, 0, 
893                                 &t->me->NT_id);
894             if (t->me->t_handle == 0) {
895                 /* 
896                  * we only free t if the thread wasn't created, otherwise
897                  * it's free'd by the new thread.
898                  */
899                 queue_Remove(t->me);
900                 put_thread(t->me);
901                 free(t);
902                 rc = EAGAIN;
903             }
904             pthread_mutex_unlock(&active_Q_mutex);
905         } else {
906             if (t != NULL) {
907                 free(t);
908             }
909             rc = ENOMEM;
910         }
911     } else {
912         rc = EINVAL;
913     }
914     return rc;
915 }
916
917 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) {
918     int rc = 0;
919
920     /*
921      * Only support default attribute -> must pass a NULL pointer for
922      * attr parameter.
923      */
924     if ((attr == NULL) && (cond != NULL)) {
925         InitializeCriticalSection(&cond->cs);
926         queue_Init(&cond->waiting_threads);
927     } else {
928         rc = EINVAL;
929     }
930
931     return rc;
932 }
933
934 /*
935  * In order to optimize the performance of condition variables,
936  * we maintain a pool of cond_waiter_t's that have been dynamically
937  * allocated.  There is no attempt made to garbage collect these -
938  * once they have been created, they stay in the cache for the life
939  * of the process.
940  */
941  
942 static struct rx_queue waiter_cache;
943 static CRITICAL_SECTION waiter_cache_cs;
944 static int waiter_cache_init;
945 static pthread_once_t waiter_cache_once = PTHREAD_ONCE_INIT;
946  
947 static void init_waiter_cache(void) {
948     InitializeCriticalSection(&waiter_cache_cs);
949     queue_Init(&waiter_cache);
950     waiter_cache_init = 1;
951 }
952  
953 static void cleanup_waiter_cache(void)
954 {
955     cond_waiters_t * cur = NULL, * next = NULL;
956
957     if (waiter_cache_init) {
958         for(queue_Scan(&waiter_cache, cur, next, cond_waiter)) {
959             queue_Remove(cur);
960
961             CloseHandle(cur->event);
962             free(cur);
963         }
964
965         DeleteCriticalSection(&waiter_cache_cs);
966         waiter_cache_init = 0;
967     }
968 }
969
970 static cond_waiters_t *get_waiter() {
971     cond_waiters_t *new = NULL;
972  
973     (waiter_cache_init || pthread_once(&waiter_cache_once, init_waiter_cache));
974  
975     EnterCriticalSection(&waiter_cache_cs);
976  
977     if (queue_IsEmpty(&waiter_cache)) {
978         new = (cond_waiters_t *) malloc(sizeof(cond_waiters_t));
979         if (new != NULL) {
980         CHAR eventName[MAX_PATH];
981         static eventCount = 0;
982         sprintf(eventName, "cond_waiters_t %d::%d", _getpid(), eventCount++);
983         new->event = CreateEvent((LPSECURITY_ATTRIBUTES) 0, FALSE,
984                                   FALSE, (LPCTSTR) eventName);
985             if (new->event == NULL) {
986                 free(new);
987                 new = NULL;
988             }
989         }
990     } else {
991         new = queue_First(&waiter_cache, cond_waiter);
992         queue_Remove(new);
993     }
994  
995     LeaveCriticalSection(&waiter_cache_cs);
996     return new;
997  
998 }
999  
1000 static void put_waiter(cond_waiters_t *old) {
1001  
1002     (waiter_cache_init || pthread_once(&waiter_cache_once, init_waiter_cache));
1003  
1004     EnterCriticalSection(&waiter_cache_cs);
1005     queue_Prepend(&waiter_cache, old);
1006     LeaveCriticalSection(&waiter_cache_cs);
1007 }
1008
1009 static int cond_wait_internal(pthread_cond_t *cond, pthread_mutex_t *mutex, const DWORD time) {
1010     int rc=0;
1011     cond_waiters_t *my_entry = get_waiter();
1012     cond_waiters_t *cur, *next;
1013     int hasnt_been_signalled=0;
1014
1015     if ((cond != NULL) && (mutex != NULL) && (my_entry != NULL)) {
1016         EnterCriticalSection(&cond->cs);
1017         queue_Append(&cond->waiting_threads, my_entry);
1018         LeaveCriticalSection(&cond->cs);
1019
1020         if (pthread_mutex_unlock(mutex) == 0) {
1021             switch(WaitForSingleObject(my_entry->event, time)) {
1022             case WAIT_FAILED:
1023                 rc = -1;
1024                 break;
1025             case WAIT_TIMEOUT:
1026                 rc = ETIMEDOUT;
1027                 /*
1028                  * This is a royal pain.  We've timed out waiting
1029                  * for the signal, but between the time out and here
1030                  * it is possible that we were actually signalled by 
1031                  * another thread.  So we grab the condition lock
1032                  * and scan the waiting thread queue to see if we are
1033                  * still there.  If we are, we just remove ourselves.
1034                  *
1035                  * If we are no longer listed in the waiter queue,
1036                  * it means that we were signalled after the time
1037                  * out occurred and so we have to do another wait
1038                  * WHICH HAS TO SUCCEED!  In this case, we reset
1039                  * rc to indicate that we were signalled.
1040                  *
1041                  * We have to wait or otherwise, the event
1042                  * would be cached in the signalled state, which
1043                  * is wrong.  It might be more efficient to just
1044                  * close and reopen the event.
1045                  */
1046                 EnterCriticalSection(&cond->cs);
1047                 for(queue_Scan(&cond->waiting_threads, cur,
1048                                 next, cond_waiter)) {
1049                     if (cur == my_entry) {
1050                         hasnt_been_signalled = 1;
1051                         break;
1052                     }
1053                 }
1054                 if (hasnt_been_signalled) {
1055                     queue_Remove(cur);
1056                 } else {
1057                     rc = 0;
1058                     if (!ResetEvent(my_entry->event)) {
1059                         rc = -6;
1060                     }
1061                 }
1062                 LeaveCriticalSection(&cond->cs);
1063                 break;
1064             case WAIT_ABANDONED:
1065                 rc = -2;
1066                 break;
1067             case WAIT_OBJECT_0:
1068                 rc = 0;
1069                 break;
1070             default:
1071                 rc = -4;
1072                 break;
1073             }
1074             if (pthread_mutex_lock(mutex) != 0) {
1075                 rc = -3;
1076             }   
1077         } else {
1078             rc = EINVAL;
1079         }
1080     } else {
1081         rc = EINVAL;
1082     }
1083
1084     if (my_entry != NULL) {
1085         put_waiter(my_entry);
1086     }
1087
1088     return rc;
1089 }
1090
1091 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
1092     int rc = 0;
1093
1094     rc = cond_wait_internal(cond, mutex, INFINITE);
1095     return rc;
1096 }
1097
1098 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) {
1099     int rc = 0;
1100     struct _timeb now, then;
1101     afs_uint32 n_milli, t_milli;
1102
1103     if (abstime->tv_nsec < 1000000000) {
1104
1105         /*
1106          * pthread timedwait uses an absolute time, NT uses relative so
1107          * we convert here.  The millitm field in the timeb struct is
1108          * unsigned, but we need to do subtraction preserving the sign, 
1109          * so we copy the fields into temporary variables.
1110          *
1111          * WARNING:
1112          * In NT 4.0 SP3, WaitForSingleObject can occassionally timeout
1113          * earlier than requested.  Therefore, our pthread_cond_timedwait
1114          * can also return early.
1115          */
1116
1117         _ftime(&now);
1118         n_milli = now.millitm;
1119         then.time = abstime->tv_sec;
1120         t_milli = abstime->tv_nsec/1000000;
1121
1122         if((then.time > now.time || 
1123            (then.time == now.time && t_milli > n_milli))) {
1124             if((t_milli -= n_milli) < 0) {
1125                 t_milli += 1000;
1126                 then.time--;
1127             }
1128             then.time -= now.time;
1129
1130             if ((then.time + (clock() / CLOCKS_PER_SEC)) <= 50000000) {
1131                 /*
1132                  * Under NT, we can only wait for milliseconds, so we
1133                  * round up the wait time here.
1134                  */
1135                 rc = cond_wait_internal(cond, mutex, 
1136                                  (DWORD)((then.time * 1000) + (t_milli)));
1137             } else {
1138                 rc = EINVAL;
1139             }
1140         } else {
1141             rc = ETIME;
1142         }
1143     } else {
1144         rc = EINVAL;
1145     }
1146
1147     return rc;
1148 }
1149
1150 int pthread_cond_signal(pthread_cond_t *cond) {
1151     int rc = 0;
1152     cond_waiters_t *release_thread;
1153
1154     if (cond != NULL) {
1155         EnterCriticalSection(&cond->cs);
1156
1157         /*
1158          * remove the first waiting thread from the queue
1159          * and resume his execution
1160          */
1161         if (queue_IsNotEmpty(&cond->waiting_threads)) {
1162             release_thread = queue_First(&cond->waiting_threads,
1163                                          cond_waiter);
1164             queue_Remove(release_thread);
1165             if (!SetEvent(release_thread->event)) {
1166                 rc = -1;
1167             }
1168         }
1169
1170         LeaveCriticalSection(&cond->cs);
1171     } else {
1172         rc = EINVAL;
1173     }
1174
1175     return rc;
1176 }
1177
1178 int pthread_cond_broadcast(pthread_cond_t *cond) {
1179     int rc = 0;
1180     cond_waiters_t *release_thread, *next_thread;
1181
1182     if(cond != NULL) {
1183         EnterCriticalSection(&cond->cs);
1184
1185         /*
1186          * Empty the waiting_threads queue. 
1187          */
1188         if (queue_IsNotEmpty(&cond->waiting_threads)) {
1189             for(queue_Scan(&cond->waiting_threads, release_thread,
1190                            next_thread, cond_waiter)) {
1191                 queue_Remove(release_thread);
1192                 if (!SetEvent(release_thread->event)) {
1193                     rc = -1;
1194                 }
1195             }
1196         }
1197
1198         LeaveCriticalSection(&cond->cs);
1199     } else {
1200         rc = EINVAL;
1201     }
1202
1203     return rc;
1204 }
1205
1206 int pthread_cond_destroy(pthread_cond_t *cond) {
1207     int rc = 0;
1208
1209     if (cond != NULL) {
1210         DeleteCriticalSection(&cond->cs);
1211     } else {
1212         rc = EINVAL;
1213     }
1214         
1215     /*
1216      * A previous version of this file had code to check the waiter
1217      * queue and empty it here.  This has been removed in the hopes
1218      * that it will aid in debugging.
1219      */
1220
1221     return rc;
1222 }
1223
1224 int pthread_join(pthread_t target_thread, void **status) {
1225     int rc = 0;
1226     thread_p me, target;
1227     thread_p cur, next;
1228
1229     target = (thread_p) target_thread;
1230     me = (thread_p) pthread_self();
1231
1232     if (me != target) {
1233         /*
1234          * Check to see that the target thread is joinable and hasn't
1235          * already been joined.
1236          */
1237
1238         pthread_mutex_lock(&active_Q_mutex);
1239
1240         for(queue_Scan(&active_Q, cur, next, thread)) {
1241             if (target == cur) break;
1242         }
1243
1244         if (target == cur) {
1245             if ((!target->is_joinable) || (target->has_been_joined)) {
1246                 rc = ESRCH;
1247             }
1248         } else {
1249             rc = ESRCH;
1250         }
1251
1252         if (rc) {
1253             pthread_mutex_unlock(&active_Q_mutex);
1254             return rc;
1255         }
1256
1257         target->waiter_count++;
1258         while(target->running) {
1259             pthread_cond_wait(&target->wait_terminate, &active_Q_mutex);
1260         }
1261
1262         /*
1263          * Only one waiter gets the status and is allowed to join, all the
1264          * others get an error.
1265          */
1266
1267         if (target->has_been_joined) {
1268             rc = ESRCH;
1269         } else {
1270             target->has_been_joined = 1;
1271             if (status) {
1272                 *status = target->rc;
1273             }
1274         }
1275
1276         /*
1277          * If we're the last waiter it is our responsibility to remove
1278          * this entry from the terminated list and put it back in the
1279          * cache.
1280          */
1281
1282         target->waiter_count--;
1283         if (target->waiter_count == 0) {
1284             queue_Remove(target);
1285             pthread_mutex_unlock(&active_Q_mutex);
1286             put_thread(target);
1287         } else {
1288             pthread_mutex_unlock(&active_Q_mutex);
1289         }
1290     } else {
1291         rc = EDEADLK;
1292     }
1293
1294     return rc;
1295 }
1296
1297 /*
1298  * Note that we can't return an error from pthread_getspecific so
1299  * we return a NULL pointer instead.
1300  */
1301
1302 void *pthread_getspecific(pthread_key_t key) {
1303     void *rc = NULL;
1304     char **tsd = TlsGetValue(tsd_index);
1305
1306     if (tsd == NULL)
1307         return NULL;
1308
1309     if ((key > -1) && (key < PTHREAD_KEYS_MAX )) {
1310         rc = (void *) *(tsd + key);
1311     }
1312
1313     return rc;
1314 }
1315
1316 static int p_tsd_done;
1317
1318 static void pthread_tsd_init(void) {
1319     pthread_mutex_init(&pthread_tsd_mutex, (const pthread_mutexattr_t*)0);
1320     p_tsd_done = 1;
1321 }
1322
1323 int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *value)) {
1324     int rc = 0;
1325     int i;
1326
1327     if (p_tsd_done || (!pthread_once(&pthread_tsd_once, pthread_tsd_init))) {
1328         if (!pthread_mutex_lock(&pthread_tsd_mutex)) {
1329             for(i=0;i<PTHREAD_KEYS_MAX;i++) {
1330                 if (!keys[i].inuse) break;
1331             }
1332
1333             if (!keys[i].inuse) {
1334                 keys[i].inuse = 1;
1335                 keys[i].destructor = destructor;
1336                 *keyp = i;
1337             } else {
1338                 rc = EAGAIN;
1339             }
1340             pthread_mutex_unlock(&pthread_tsd_mutex);
1341         } else {
1342             rc = -1;
1343         }
1344     } else {
1345         rc = -2;
1346     }
1347
1348     return rc;
1349 }
1350
1351 int pthread_key_delete(pthread_key_t key) {
1352     int rc = 0;
1353
1354     if (p_tsd_done || (!pthread_once(&pthread_tsd_once, pthread_tsd_init))) {
1355         if ((key > -1) && (key < PTHREAD_KEYS_MAX )) {
1356             if (!pthread_mutex_lock(&pthread_tsd_mutex)) {
1357                 keys[key].inuse = 0;
1358                 keys[key].destructor = NULL;
1359                 pthread_mutex_unlock(&pthread_tsd_mutex);
1360             } else {
1361                 rc = -1;
1362             }
1363         } else {
1364             rc = EINVAL;
1365         }
1366     } else {
1367         rc = -2;
1368     }
1369
1370     return rc;
1371 }
1372
1373 int pthread_setspecific(pthread_key_t key, const void *value) {
1374     int rc = 0;
1375     char **tsd;
1376
1377     /* make sure all thread-local storage has been allocated */
1378     pthread_self();
1379
1380     if (p_tsd_done || (!pthread_once(&pthread_tsd_once, pthread_tsd_init))) {
1381         if ((key > -1) && (key < PTHREAD_KEYS_MAX )) {
1382             if (!pthread_mutex_lock(&pthread_tsd_mutex)) {
1383                 if (keys[key].inuse) {
1384                     tsd = TlsGetValue(tsd_index);
1385                     *(tsd + key) = (char *) value;
1386                 } else {
1387                     rc = EINVAL;
1388                 }
1389                 pthread_mutex_unlock(&pthread_tsd_mutex);
1390             } else {
1391                 rc = -1;
1392             }
1393         } else {
1394             rc = EINVAL;
1395         }
1396     } else {
1397       rc = -2;
1398     }
1399
1400     return rc;
1401 }
1402
1403 pthread_t pthread_self(void) {
1404     thread_p cur;
1405     DWORD my_id = GetCurrentThreadId();
1406
1407     (pthread_cache_done || pthread_once(&pthread_cache_once, create_once));
1408     (tsd_done || pthread_once(&global_tsd_once, tsd_once));
1409
1410     pthread_mutex_lock(&active_Q_mutex);
1411
1412     cur = TlsGetValue (tsd_pthread_index);
1413
1414     if(!cur) {
1415         /*
1416          * This thread's ID was not found in our list of pthread-API client
1417          * threads (e.g., those threads created via pthread_create). Create
1418          * an entry for it.
1419          */
1420         if ((cur = get_thread()) != NULL) {
1421             cur->is_joinable = 0;
1422             cur->NT_id = my_id;
1423             cur->native_thread = 1;
1424             DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
1425              GetCurrentProcess(), &cur->t_handle, 0,
1426              TRUE, DUPLICATE_SAME_ACCESS);
1427
1428             /*
1429              * We'll also need a place to store key data for this thread
1430              */
1431             if ((cur->tsd = malloc(sizeof(char*) * PTHREAD_KEYS_MAX)) != NULL) {
1432                 memset(cur->tsd, 0, (sizeof(char*) * PTHREAD_KEYS_MAX));
1433             }
1434             TlsSetValue(tsd_index, (LPVOID)cur->tsd);
1435             TlsSetValue(tsd_pthread_index, (LPVOID)cur);
1436
1437             /*
1438              * The thread_t structure is complete; add it to the active_Q
1439              */
1440             queue_Prepend(&active_Q, cur);
1441
1442             /*
1443              * We were able to successfully insert a new entry into the
1444              * active_Q; however, when this thread terminates, we will need
1445              * to know about it. The pthread_sync_terminate_thread() routine
1446              * will make sure there is a dedicated thread waiting for any
1447              * native-thread entries in the active_Q to terminate.
1448              */
1449             pthread_sync_terminate_thread();
1450         }
1451     }
1452
1453     pthread_mutex_unlock(&active_Q_mutex);
1454
1455     return (void *) cur;
1456 }
1457
1458 int pthread_equal(pthread_t t1, pthread_t t2) {
1459     return (t1 == t2);
1460 }
1461
1462 int pthread_attr_destroy(pthread_attr_t *attr) {
1463     int rc = 0;
1464
1465     return rc;
1466 }
1467
1468 int pthread_attr_init(pthread_attr_t *attr) {
1469     int rc = 0;
1470
1471     if (attr != NULL) {
1472         attr->is_joinable = PTHREAD_CREATE_JOINABLE;
1473     } else {
1474         rc = EINVAL;
1475     }
1476
1477     return rc;
1478 }
1479
1480 int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate) {
1481     int rc = 0;
1482
1483     if ((attr != NULL) && (detachstate != NULL)) {
1484             *detachstate = attr->is_joinable;
1485     } else {
1486         rc = EINVAL;
1487     }
1488     return rc;
1489 }
1490
1491 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) {
1492     int rc = 0;
1493
1494     if ((attr != NULL) && ((detachstate == PTHREAD_CREATE_JOINABLE) ||
1495         (detachstate == PTHREAD_CREATE_DETACHED))) {
1496         attr->is_joinable = detachstate;
1497     } else {
1498         rc = EINVAL;
1499     }
1500     return rc;
1501 }
1502
1503 void pthread_exit(void *status) {
1504     thread_p me = (thread_p) pthread_self();
1505
1506     /*
1507      * Support pthread_exit for thread's created by calling pthread_create
1508      * only.  Do this by using an exception that will transfer control
1509      * back to afs_pthread_create_stub.  Store away our status before
1510      * returning.
1511      *
1512      * If this turns out to be a native thread, the exception will be
1513      * unhandled and the process will terminate.
1514      */
1515
1516     me->rc = status;
1517     RaiseException(PTHREAD_EXIT_EXCEPTION, 0, 0, NULL);
1518
1519 }
1520
1521 /*
1522  * DllMain() -- Entry-point function called by the DllMainCRTStartup()
1523  *     function in the MSVC runtime DLL (msvcrt.dll).
1524  *
1525  *     Note: the system serializes calls to this function.
1526  */
1527 BOOL WINAPI
1528 DllMain(HINSTANCE dllInstHandle,/* instance handle for this DLL module */
1529         DWORD reason,           /* reason function is being called */
1530         LPVOID reserved)
1531 {                               /* reserved for future use */
1532     switch (reason) {
1533     case DLL_PROCESS_ATTACH:
1534         /* library is being attached to a process */
1535         /* disable thread attach/detach notifications */
1536         (void)DisableThreadLibraryCalls(dllInstHandle);
1537
1538         pthread_once(&pthread_cache_once, create_once);
1539         pthread_once(&global_tsd_once, tsd_once);
1540         pthread_once(&waiter_cache_once, init_waiter_cache);
1541         return TRUE;
1542
1543     case DLL_PROCESS_DETACH:
1544         cleanup_waiter_cache();
1545         cleanup_global_tsd();
1546         cleanup_pthread_cache();
1547         return TRUE;
1548
1549     default:
1550         return FALSE;
1551     }
1552 }
1553