/[dtapublic]/projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclwinthrd.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclwinthrd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 29 - (show annotations) (download)
Sat Oct 8 07:08:47 2016 UTC (8 years ago) by dashley
Original Path: to_be_filed/sf_code/esrgpcpj/shared/tcl_base/tclwinthrd.c
File MIME type: text/plain
File size: 23651 byte(s)
Directories relocated.
1 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tcl_base/tclwinthrd.c,v 1.1.1.1 2001/06/13 04:50:42 dtashley Exp $ */
2
3 /*
4 * tclWinThread.c --
5 *
6 * This file implements the Windows-specific thread operations.
7 *
8 * Copyright (c) 1998 by Sun Microsystems, Inc.
9 * Copyright (c) 1999 by Scriptics Corporation
10 *
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 *
14 * RCS: @(#) $Id: tclwinthrd.c,v 1.1.1.1 2001/06/13 04:50:42 dtashley Exp $
15 */
16
17 #include "tclWinInt.h"
18
19 #include <dos.h>
20 #include <fcntl.h>
21 #include <io.h>
22 #include <sys/stat.h>
23
24 /*
25 * This is the master lock used to serialize access to other
26 * serialization data structures.
27 */
28
29 static CRITICAL_SECTION masterLock;
30 static int init = 0;
31 #define MASTER_LOCK EnterCriticalSection(&masterLock)
32 #define MASTER_UNLOCK LeaveCriticalSection(&masterLock)
33
34 /*
35 * This is the master lock used to serialize initialization and finalization
36 * of Tcl as a whole.
37 */
38
39 static CRITICAL_SECTION initLock;
40
41 /*
42 * allocLock is used by Tcl's version of malloc for synchronization.
43 * For obvious reasons, cannot use any dyamically allocated storage.
44 */
45
46 static CRITICAL_SECTION allocLock;
47 static Tcl_Mutex allocLockPtr = (Tcl_Mutex) &allocLock;
48
49 /*
50 * Condition variables are implemented with a combination of a
51 * per-thread Windows Event and a per-condition waiting queue.
52 * The idea is that each thread has its own Event that it waits
53 * on when it is doing a ConditionWait; it uses the same event for
54 * all condition variables because it only waits on one at a time.
55 * Each condition variable has a queue of waiting threads, and a
56 * mutex used to serialize access to this queue.
57 *
58 * Special thanks to David Nichols and
59 * Jim Davidson for advice on the Condition Variable implementation.
60 */
61
62 /*
63 * The per-thread event and queue pointers.
64 */
65
66 typedef struct ThreadSpecificData {
67 HANDLE condEvent; /* Per-thread condition event */
68 struct ThreadSpecificData *nextPtr; /* Queue pointers */
69 struct ThreadSpecificData *prevPtr;
70 int flags; /* See flags below */
71 } ThreadSpecificData;
72 static Tcl_ThreadDataKey dataKey;
73
74 /*
75 * State bits for the thread.
76 * WIN_THREAD_UNINIT Uninitialized. Must be zero because
77 * of the way ThreadSpecificData is created.
78 * WIN_THREAD_RUNNING Running, not waiting.
79 * WIN_THREAD_BLOCKED Waiting, or trying to wait.
80 * WIN_THREAD_DEAD Dying - no per-thread event anymore.
81 */
82
83 #define WIN_THREAD_UNINIT 0x0
84 #define WIN_THREAD_RUNNING 0x1
85 #define WIN_THREAD_BLOCKED 0x2
86 #define WIN_THREAD_DEAD 0x4
87
88 /*
89 * The per condition queue pointers and the
90 * Mutex used to serialize access to the queue.
91 */
92
93 typedef struct WinCondition {
94 CRITICAL_SECTION condLock; /* Lock to serialize queuing on the condition */
95 struct ThreadSpecificData *firstPtr; /* Queue pointers */
96 struct ThreadSpecificData *lastPtr;
97 } WinCondition;
98
99 static void FinalizeConditionEvent(ClientData data);
100
101
102 /*
103 *----------------------------------------------------------------------
104 *
105 * Tcl_CreateThread --
106 *
107 * This procedure creates a new thread.
108 *
109 * Results:
110 * TCL_OK if the thread could be created. The thread ID is
111 * returned in a parameter.
112 *
113 * Side effects:
114 * A new thread is created.
115 *
116 *----------------------------------------------------------------------
117 */
118
119 int
120 Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags)
121 Tcl_ThreadId *idPtr; /* Return, the ID of the thread */
122 Tcl_ThreadCreateProc proc; /* Main() function of the thread */
123 ClientData clientData; /* The one argument to Main() */
124 int stackSize; /* Size of stack for the new thread */
125 int flags; /* Flags controlling behaviour of
126 * the new thread */
127 {
128 unsigned long code;
129
130 code = _beginthreadex(NULL, stackSize, proc, clientData, 0,
131 (unsigned *)idPtr);
132 if (code == 0) {
133 return TCL_ERROR;
134 } else {
135 return TCL_OK;
136 }
137 }
138
139 /*
140 *----------------------------------------------------------------------
141 *
142 * TclpThreadExit --
143 *
144 * This procedure terminates the current thread.
145 *
146 * Results:
147 * None.
148 *
149 * Side effects:
150 * This procedure terminates the current thread.
151 *
152 *----------------------------------------------------------------------
153 */
154
155 void
156 TclpThreadExit(status)
157 int status;
158 {
159 _endthreadex((DWORD)status);
160 }
161
162
163 /*
164 *----------------------------------------------------------------------
165 *
166 * Tcl_GetCurrentThread --
167 *
168 * This procedure returns the ID of the currently running thread.
169 *
170 * Results:
171 * A thread ID.
172 *
173 * Side effects:
174 * None.
175 *
176 *----------------------------------------------------------------------
177 */
178
179 Tcl_ThreadId
180 Tcl_GetCurrentThread()
181 {
182 return (Tcl_ThreadId)GetCurrentThreadId();
183 }
184
185
186 /*
187 *----------------------------------------------------------------------
188 *
189 * TclpInitLock
190 *
191 * This procedure is used to grab a lock that serializes initialization
192 * and finalization of Tcl. On some platforms this may also initialize
193 * the mutex used to serialize creation of more mutexes and thread
194 * local storage keys.
195 *
196 * Results:
197 * None.
198 *
199 * Side effects:
200 * Acquire the initialization mutex.
201 *
202 *----------------------------------------------------------------------
203 */
204
205 void
206 TclpInitLock()
207 {
208 if (!init) {
209 /*
210 * There is a fundamental race here that is solved by creating
211 * the first Tcl interpreter in a single threaded environment.
212 * Once the interpreter has been created, it is safe to create
213 * more threads that create interpreters in parallel.
214 */
215 init = 1;
216 InitializeCriticalSection(&initLock);
217 InitializeCriticalSection(&masterLock);
218 }
219 EnterCriticalSection(&initLock);
220 }
221
222
223 /*
224 *----------------------------------------------------------------------
225 *
226 * TclpInitUnlock
227 *
228 * This procedure is used to release a lock that serializes initialization
229 * and finalization of Tcl.
230 *
231 * Results:
232 * None.
233 *
234 * Side effects:
235 * Release the initialization mutex.
236 *
237 *----------------------------------------------------------------------
238 */
239
240 void
241 TclpInitUnlock()
242 {
243 LeaveCriticalSection(&initLock);
244 }
245
246
247 /*
248 *----------------------------------------------------------------------
249 *
250 * TclpMasterLock
251 *
252 * This procedure is used to grab a lock that serializes creation
253 * of mutexes, condition variables, and thread local storage keys.
254 *
255 * This lock must be different than the initLock because the
256 * initLock is held during creation of syncronization objects.
257 *
258 * Results:
259 * None.
260 *
261 * Side effects:
262 * Acquire the master mutex.
263 *
264 *----------------------------------------------------------------------
265 */
266
267 void
268 TclpMasterLock()
269 {
270 if (!init) {
271 /*
272 * There is a fundamental race here that is solved by creating
273 * the first Tcl interpreter in a single threaded environment.
274 * Once the interpreter has been created, it is safe to create
275 * more threads that create interpreters in parallel.
276 */
277 init = 1;
278 InitializeCriticalSection(&initLock);
279 InitializeCriticalSection(&masterLock);
280 }
281 EnterCriticalSection(&masterLock);
282 }
283
284
285 /*
286 *----------------------------------------------------------------------
287 *
288 * Tcl_GetAllocMutex
289 *
290 * This procedure returns a pointer to a statically initialized
291 * mutex for use by the memory allocator. The alloctor must
292 * use this lock, because all other locks are allocated...
293 *
294 * Results:
295 * A pointer to a mutex that is suitable for passing to
296 * Tcl_MutexLock and Tcl_MutexUnlock.
297 *
298 * Side effects:
299 * None.
300 *
301 *----------------------------------------------------------------------
302 */
303
304 Tcl_Mutex *
305 Tcl_GetAllocMutex()
306 {
307 #ifdef TCL_THREADS
308 InitializeCriticalSection(&allocLock);
309 return &allocLockPtr;
310 #else
311 return NULL;
312 #endif
313 }
314
315
316 #ifdef TCL_THREADS
317 /*
318 *----------------------------------------------------------------------
319 *
320 * TclpMasterUnlock
321 *
322 * This procedure is used to release a lock that serializes creation
323 * and deletion of synchronization objects.
324 *
325 * Results:
326 * None.
327 *
328 * Side effects:
329 * Release the master mutex.
330 *
331 *----------------------------------------------------------------------
332 */
333
334 void
335 TclpMasterUnlock()
336 {
337 LeaveCriticalSection(&masterLock);
338 }
339
340
341 /*
342 *----------------------------------------------------------------------
343 *
344 * Tcl_MutexLock --
345 *
346 * This procedure is invoked to lock a mutex. This is a self
347 * initializing mutex that is automatically finalized during
348 * Tcl_Finalize.
349 *
350 * Results:
351 * None.
352 *
353 * Side effects:
354 * May block the current thread. The mutex is aquired when
355 * this returns.
356 *
357 *----------------------------------------------------------------------
358 */
359
360 void
361 Tcl_MutexLock(mutexPtr)
362 Tcl_Mutex *mutexPtr; /* The lock */
363 {
364 CRITICAL_SECTION *csPtr;
365 if (*mutexPtr == NULL) {
366 MASTER_LOCK;
367
368 /*
369 * Double inside master lock check to avoid a race.
370 */
371
372 if (*mutexPtr == NULL) {
373 csPtr = (CRITICAL_SECTION *)ckalloc(sizeof(CRITICAL_SECTION));
374 InitializeCriticalSection(csPtr);
375 *mutexPtr = (Tcl_Mutex)csPtr;
376 TclRememberMutex(mutexPtr);
377 }
378 MASTER_UNLOCK;
379 }
380 csPtr = *((CRITICAL_SECTION **)mutexPtr);
381 EnterCriticalSection(csPtr);
382 }
383
384
385 /*
386 *----------------------------------------------------------------------
387 *
388 * Tcl_MutexUnlock --
389 *
390 * This procedure is invoked to unlock a mutex.
391 *
392 * Results:
393 * None.
394 *
395 * Side effects:
396 * The mutex is released when this returns.
397 *
398 *----------------------------------------------------------------------
399 */
400
401 void
402 Tcl_MutexUnlock(mutexPtr)
403 Tcl_Mutex *mutexPtr; /* The lock */
404 {
405 CRITICAL_SECTION *csPtr = *((CRITICAL_SECTION **)mutexPtr);
406 LeaveCriticalSection(csPtr);
407 }
408
409
410 /*
411 *----------------------------------------------------------------------
412 *
413 * TclpFinalizeMutex --
414 *
415 * This procedure is invoked to clean up one mutex. This is only
416 * safe to call at the end of time.
417 *
418 * Results:
419 * None.
420 *
421 * Side effects:
422 * The mutex list is deallocated.
423 *
424 *----------------------------------------------------------------------
425 */
426
427 void
428 TclpFinalizeMutex(mutexPtr)
429 Tcl_Mutex *mutexPtr;
430 {
431 CRITICAL_SECTION *csPtr = *(CRITICAL_SECTION **)mutexPtr;
432 if (csPtr != NULL) {
433 ckfree((char *)csPtr);
434 *mutexPtr = NULL;
435 }
436 }
437
438
439 /*
440 *----------------------------------------------------------------------
441 *
442 * TclpThreadDataKeyInit --
443 *
444 * This procedure initializes a thread specific data block key.
445 * Each thread has table of pointers to thread specific data.
446 * all threads agree on which table entry is used by each module.
447 * this is remembered in a "data key", that is just an index into
448 * this table. To allow self initialization, the interface
449 * passes a pointer to this key and the first thread to use
450 * the key fills in the pointer to the key. The key should be
451 * a process-wide static.
452 *
453 * Results:
454 * None.
455 *
456 * Side effects:
457 * Will allocate memory the first time this process calls for
458 * this key. In this case it modifies its argument
459 * to hold the pointer to information about the key.
460 *
461 *----------------------------------------------------------------------
462 */
463
464 void
465 TclpThreadDataKeyInit(keyPtr)
466 Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
467 * really (DWORD **) */
468 {
469 DWORD *indexPtr;
470
471 MASTER_LOCK;
472 if (*keyPtr == NULL) {
473 indexPtr = (DWORD *)ckalloc(sizeof(DWORD));
474 *indexPtr = TlsAlloc();
475 *keyPtr = (Tcl_ThreadDataKey)indexPtr;
476 TclRememberDataKey(keyPtr);
477 }
478 MASTER_UNLOCK;
479 }
480
481
482 /*
483 *----------------------------------------------------------------------
484 *
485 * TclpThreadDataKeyGet --
486 *
487 * This procedure returns a pointer to a block of thread local storage.
488 *
489 * Results:
490 * A thread-specific pointer to the data structure, or NULL
491 * if the memory has not been assigned to this key for this thread.
492 *
493 * Side effects:
494 * None.
495 *
496 *----------------------------------------------------------------------
497 */
498
499 VOID *
500 TclpThreadDataKeyGet(keyPtr)
501 Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
502 * really (DWORD **) */
503 {
504 DWORD *indexPtr = *(DWORD **)keyPtr;
505 if (indexPtr == NULL) {
506 return NULL;
507 } else {
508 return (VOID *) TlsGetValue(*indexPtr);
509 }
510 }
511
512
513 /*
514 *----------------------------------------------------------------------
515 *
516 * TclpThreadDataKeySet --
517 *
518 * This procedure sets the pointer to a block of thread local storage.
519 *
520 * Results:
521 * None.
522 *
523 * Side effects:
524 * Sets up the thread so future calls to TclpThreadDataKeyGet with
525 * this key will return the data pointer.
526 *
527 *----------------------------------------------------------------------
528 */
529
530 void
531 TclpThreadDataKeySet(keyPtr, data)
532 Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
533 * really (pthread_key_t **) */
534 VOID *data; /* Thread local storage */
535 {
536 DWORD *indexPtr = *(DWORD **)keyPtr;
537 TlsSetValue(*indexPtr, (void *)data);
538 }
539
540
541 /*
542 *----------------------------------------------------------------------
543 *
544 * TclpFinalizeThreadData --
545 *
546 * This procedure cleans up the thread-local storage. This is
547 * called once for each thread.
548 *
549 * Results:
550 * None.
551 *
552 * Side effects:
553 * Frees up the memory.
554 *
555 *----------------------------------------------------------------------
556 */
557
558 void
559 TclpFinalizeThreadData(keyPtr)
560 Tcl_ThreadDataKey *keyPtr;
561 {
562 VOID *result;
563 DWORD *indexPtr;
564
565 if (*keyPtr != NULL) {
566 indexPtr = *(DWORD **)keyPtr;
567 result = (VOID *)TlsGetValue(*indexPtr);
568 if (result != NULL) {
569 ckfree((char *)result);
570 TlsSetValue(*indexPtr, (void *)NULL);
571 }
572 }
573 }
574
575 /*
576 *----------------------------------------------------------------------
577 *
578 * TclpFinalizeThreadDataKey --
579 *
580 * This procedure is invoked to clean up one key. This is a
581 * process-wide storage identifier. The thread finalization code
582 * cleans up the thread local storage itself.
583 *
584 * This assumes the master lock is held.
585 *
586 * Results:
587 * None.
588 *
589 * Side effects:
590 * The key is deallocated.
591 *
592 *----------------------------------------------------------------------
593 */
594
595 void
596 TclpFinalizeThreadDataKey(keyPtr)
597 Tcl_ThreadDataKey *keyPtr;
598 {
599 DWORD *indexPtr;
600 if (*keyPtr != NULL) {
601 indexPtr = *(DWORD **)keyPtr;
602 TlsFree(*indexPtr);
603 ckfree((char *)indexPtr);
604 *keyPtr = NULL;
605 }
606 }
607
608 /*
609 *----------------------------------------------------------------------
610 *
611 * Tcl_ConditionWait --
612 *
613 * This procedure is invoked to wait on a condition variable.
614 * The mutex is automically released as part of the wait, and
615 * automatically grabbed when the condition is signaled.
616 *
617 * The mutex must be held when this procedure is called.
618 *
619 * Results:
620 * None.
621 *
622 * Side effects:
623 * May block the current thread. The mutex is aquired when
624 * this returns. Will allocate memory for a HANDLE
625 * and initialize this the first time this Tcl_Condition is used.
626 *
627 *----------------------------------------------------------------------
628 */
629
630 void
631 Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
632 Tcl_Condition *condPtr; /* Really (WinCondition **) */
633 Tcl_Mutex *mutexPtr; /* Really (CRITICAL_SECTION **) */
634 Tcl_Time *timePtr; /* Timeout on waiting period */
635 {
636 WinCondition *winCondPtr; /* Per-condition queue head */
637 CRITICAL_SECTION *csPtr; /* Caller's Mutex, after casting */
638 DWORD wtime; /* Windows time value */
639 int timeout; /* True if we got a timeout */
640 int doExit = 0; /* True if we need to do exit setup */
641 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
642
643 if (tsdPtr->flags & WIN_THREAD_DEAD) {
644 /*
645 * No more per-thread event on which to wait.
646 */
647
648 return;
649 }
650
651 /*
652 * Self initialize the two parts of the contition.
653 * The per-condition and per-thread parts need to be
654 * handled independently.
655 */
656
657 if (tsdPtr->flags == WIN_THREAD_UNINIT) {
658 MASTER_LOCK;
659
660 /*
661 * Create the per-thread event and queue pointers.
662 */
663
664 if (tsdPtr->flags == WIN_THREAD_UNINIT) {
665 tsdPtr->condEvent = CreateEvent(NULL, TRUE /* manual reset */,
666 FALSE /* non signaled */, NULL);
667 tsdPtr->nextPtr = NULL;
668 tsdPtr->prevPtr = NULL;
669 tsdPtr->flags = WIN_THREAD_RUNNING;
670 doExit = 1;
671 }
672 MASTER_UNLOCK;
673
674 if (doExit) {
675 /*
676 * Create a per-thread exit handler to clean up the condEvent.
677 * We must be careful do do this outside the Master Lock
678 * because Tcl_CreateThreadExitHandler uses its own
679 * ThreadSpecificData, and initializing that may drop
680 * back into the Master Lock.
681 */
682
683 Tcl_CreateThreadExitHandler(FinalizeConditionEvent,
684 (ClientData) tsdPtr);
685 }
686 }
687
688 if (*condPtr == NULL) {
689 MASTER_LOCK;
690
691 /*
692 * Initialize the per-condition queue pointers and Mutex.
693 */
694
695 if (*condPtr == NULL) {
696 winCondPtr = (WinCondition *)ckalloc(sizeof(WinCondition));
697 InitializeCriticalSection(&winCondPtr->condLock);
698 winCondPtr->firstPtr = NULL;
699 winCondPtr->lastPtr = NULL;
700 *condPtr = (Tcl_Condition)winCondPtr;
701 TclRememberCondition(condPtr);
702 }
703 MASTER_UNLOCK;
704 }
705 csPtr = *((CRITICAL_SECTION **)mutexPtr);
706 winCondPtr = *((WinCondition **)condPtr);
707 if (timePtr == NULL) {
708 wtime = INFINITE;
709 } else {
710 wtime = timePtr->sec * 1000 + timePtr->usec / 1000;
711 }
712
713 /*
714 * Queue the thread on the condition, using
715 * the per-condition lock for serialization.
716 */
717
718 tsdPtr->flags = WIN_THREAD_BLOCKED;
719 tsdPtr->nextPtr = NULL;
720 EnterCriticalSection(&winCondPtr->condLock);
721 tsdPtr->prevPtr = winCondPtr->lastPtr; /* A: */
722 winCondPtr->lastPtr = tsdPtr;
723 if (tsdPtr->prevPtr != NULL) {
724 tsdPtr->prevPtr->nextPtr = tsdPtr;
725 }
726 if (winCondPtr->firstPtr == NULL) {
727 winCondPtr->firstPtr = tsdPtr;
728 }
729
730 /*
731 * Unlock the caller's mutex and wait for the condition, or a timeout.
732 * There is a minor issue here in that we don't count down the
733 * timeout if we get notified, but another thread grabs the condition
734 * before we do. In that race condition we'll wait again for the
735 * full timeout. Timed waits are dubious anyway. Either you have
736 * the locking protocol wrong and are masking a deadlock,
737 * or you are using conditions to pause your thread.
738 */
739
740 LeaveCriticalSection(csPtr);
741 timeout = 0;
742 while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) {
743 ResetEvent(tsdPtr->condEvent);
744 LeaveCriticalSection(&winCondPtr->condLock);
745 if (WaitForSingleObject(tsdPtr->condEvent, wtime) == WAIT_TIMEOUT) {
746 timeout = 1;
747 }
748 EnterCriticalSection(&winCondPtr->condLock);
749 }
750
751 /*
752 * Be careful on timeouts because the signal might arrive right around
753 * time time limit and someone else could have taken us off the queue.
754 */
755
756 if (timeout) {
757 if (tsdPtr->flags & WIN_THREAD_RUNNING) {
758 timeout = 0;
759 } else {
760 /*
761 * When dequeuing, we can leave the tsdPtr->nextPtr
762 * and tsdPtr->prevPtr with dangling pointers because
763 * they are reinitialilzed w/out reading them when the
764 * thread is enqueued later.
765 */
766
767 if (winCondPtr->firstPtr == tsdPtr) {
768 winCondPtr->firstPtr = tsdPtr->nextPtr;
769 } else {
770 tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
771 }
772 if (winCondPtr->lastPtr == tsdPtr) {
773 winCondPtr->lastPtr = tsdPtr->prevPtr;
774 } else {
775 tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
776 }
777 tsdPtr->flags = WIN_THREAD_RUNNING;
778 }
779 }
780
781 LeaveCriticalSection(&winCondPtr->condLock);
782 EnterCriticalSection(csPtr);
783 }
784
785
786 /*
787 *----------------------------------------------------------------------
788 *
789 * Tcl_ConditionNotify --
790 *
791 * This procedure is invoked to signal a condition variable.
792 *
793 * The mutex must be held during this call to avoid races,
794 * but this interface does not enforce that.
795 *
796 * Results:
797 * None.
798 *
799 * Side effects:
800 * May unblock another thread.
801 *
802 *----------------------------------------------------------------------
803 */
804
805 void
806 Tcl_ConditionNotify(condPtr)
807 Tcl_Condition *condPtr;
808 {
809 WinCondition *winCondPtr;
810 ThreadSpecificData *tsdPtr;
811 if (condPtr != NULL) {
812 winCondPtr = *((WinCondition **)condPtr);
813
814 /*
815 * Loop through all the threads waiting on the condition
816 * and notify them (i.e., broadcast semantics). The queue
817 * manipulation is guarded by the per-condition coordinating mutex.
818 */
819
820 EnterCriticalSection(&winCondPtr->condLock);
821 while (winCondPtr->firstPtr != NULL) {
822 tsdPtr = winCondPtr->firstPtr;
823 winCondPtr->firstPtr = tsdPtr->nextPtr;
824 if (winCondPtr->lastPtr == tsdPtr) {
825 winCondPtr->lastPtr = NULL;
826 }
827 tsdPtr->flags = WIN_THREAD_RUNNING;
828 tsdPtr->nextPtr = NULL;
829 tsdPtr->prevPtr = NULL; /* Not strictly necessary, see A: */
830 SetEvent(tsdPtr->condEvent);
831 }
832 LeaveCriticalSection(&winCondPtr->condLock);
833 } else {
834 /*
835 * Noone has used the condition variable, so there are no waiters.
836 */
837 }
838 }
839
840
841 /*
842 *----------------------------------------------------------------------
843 *
844 * FinalizeConditionEvent --
845 *
846 * This procedure is invoked to clean up the per-thread
847 * event used to implement condition waiting.
848 * This is only safe to call at the end of time.
849 *
850 * Results:
851 * None.
852 *
853 * Side effects:
854 * The per-thread event is closed.
855 *
856 *----------------------------------------------------------------------
857 */
858
859 static void
860 FinalizeConditionEvent(data)
861 ClientData data;
862 {
863 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)data;
864 tsdPtr->flags = WIN_THREAD_DEAD;
865 CloseHandle(tsdPtr->condEvent);
866 }
867
868 /*
869 *----------------------------------------------------------------------
870 *
871 * TclpFinalizeCondition --
872 *
873 * This procedure is invoked to clean up a condition variable.
874 * This is only safe to call at the end of time.
875 *
876 * This assumes the Master Lock is held.
877 *
878 * Results:
879 * None.
880 *
881 * Side effects:
882 * The condition variable is deallocated.
883 *
884 *----------------------------------------------------------------------
885 */
886
887 void
888 TclpFinalizeCondition(condPtr)
889 Tcl_Condition *condPtr;
890 {
891 WinCondition *winCondPtr = *(WinCondition **)condPtr;
892
893 /*
894 * Note - this is called long after the thread-local storage is
895 * reclaimed. The per-thread condition waiting event is
896 * reclaimed earlier in a per-thread exit handler, which is
897 * called before thread local storage is reclaimed.
898 */
899
900 if (winCondPtr != NULL) {
901 ckfree((char *)winCondPtr);
902 *condPtr = NULL;
903 }
904 }
905 #endif /* TCL_THREADS */
906
907
908 /* $History: tclwinthrd.c $
909 *
910 * ***************** Version 1 *****************
911 * User: Dtashley Date: 1/02/01 Time: 12:25a
912 * Created in $/IjuScripter, IjuConsole/Source/Tcl Base
913 * Initial check-in.
914 */
915
916 /* End of TCLWINTHRD.C */

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25