| ︙ | | |
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
-
+
-
+
|
char nabuf[16];
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
#endif /* TCL_NO_DEPRECATED */
/*
* masterLock is used to serialize creation of mutexes, condition variables,
* globalLock is used to serialize creation of mutexes, condition variables,
* and thread local storage. This is the only place that can count on the
* ability to statically initialize the mutex.
*/
static pthread_mutex_t masterLock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t globalLock = PTHREAD_MUTEX_INITIALIZER;
/*
* initLock is used to serialize initialization and finalization of Tcl. It
* cannot use any dyamically allocated storage.
*/
static pthread_mutex_t initLock = PTHREAD_MUTEX_INITIALIZER;
|
| ︙ | | |
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
|
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
|
-
+
|
void
TclFinalizeLock(void)
{
#if TCL_THREADS
/*
* You do not need to destroy mutexes that were created with the
* PTHREAD_MUTEX_INITIALIZER macro. These mutexes do not need any
* destruction: masterLock, allocLock, and initLock.
* destruction: globalLock, allocLock, and initLock.
*/
pthread_mutex_unlock(&initLock);
#endif
}
/*
|
| ︙ | | |
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
|
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
|
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
|
pthread_mutex_unlock(&initLock);
#endif
}
/*
*----------------------------------------------------------------------
*
* TclpMasterLock
* TclpGlobalLock
*
* This procedure is used to grab a lock that serializes creation and
* finalization of serialization objects. This interface is only needed
* in finalization; it is hidden during creation of the objects.
*
* This lock must be different than the initLock because the initLock is
* held during creation of synchronization objects.
*
* Results:
* None.
*
* Side effects:
* Acquire the master mutex.
* Acquire the global mutex.
*
*----------------------------------------------------------------------
*/
void
TclpMasterLock(void)
TclpGlobalLock(void)
{
#if TCL_THREADS
pthread_mutex_lock(&masterLock);
pthread_mutex_lock(&globalLock);
#endif
}
/*
*----------------------------------------------------------------------
*
* TclpMasterUnlock
* TclpGlobalUnlock
*
* This procedure is used to release a lock that serializes creation and
* finalization of synchronization objects.
*
* Results:
* None.
*
* Side effects:
* Release the master mutex.
* Release the global mutex.
*
*----------------------------------------------------------------------
*/
void
TclpMasterUnlock(void)
TclpGlobalUnlock(void)
{
#if TCL_THREADS
pthread_mutex_unlock(&masterLock);
pthread_mutex_unlock(&globalLock);
#endif
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetAllocMutex
|
| ︙ | | |
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
|
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
|
-
+
-
+
-
+
|
void
Tcl_MutexLock(
Tcl_Mutex *mutexPtr) /* Really (PMutex **) */
{
PMutex *pmutexPtr;
if (*mutexPtr == NULL) {
pthread_mutex_lock(&masterLock);
pthread_mutex_lock(&globalLock);
if (*mutexPtr == NULL) {
/*
* Double inside master lock check to avoid a race condition.
* Double inside global lock check to avoid a race condition.
*/
pmutexPtr = (PMutex *)ckalloc(sizeof(PMutex));
PMutexInit(pmutexPtr);
*mutexPtr = (Tcl_Mutex) pmutexPtr;
TclRememberMutex(mutexPtr);
}
pthread_mutex_unlock(&masterLock);
pthread_mutex_unlock(&globalLock);
}
pmutexPtr = *((PMutex **) mutexPtr);
PMutexLock(pmutexPtr);
}
/*
*----------------------------------------------------------------------
|
| ︙ | | |
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
|
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
|
-
+
|
*----------------------------------------------------------------------
*
* TclpFinalizeMutex --
*
* This procedure is invoked to clean up one mutex. This is only safe to
* call at the end of time.
*
* This assumes the Master Lock is held.
* This assumes the Global Lock is held.
*
* Results:
* None.
*
* Side effects:
* The mutex list is deallocated.
*
|
| ︙ | | |
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
|
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
|
-
+
-
+
|
const Tcl_Time *timePtr) /* Timeout on waiting period */
{
pthread_cond_t *pcondPtr;
PMutex *pmutexPtr;
struct timespec ptime;
if (*condPtr == NULL) {
pthread_mutex_lock(&masterLock);
pthread_mutex_lock(&globalLock);
/*
* Double check inside mutex to avoid race, then initialize condition
* variable if necessary.
*/
if (*condPtr == NULL) {
pcondPtr = (pthread_cond_t *)ckalloc(sizeof(pthread_cond_t));
pthread_cond_init(pcondPtr, NULL);
*condPtr = (Tcl_Condition) pcondPtr;
TclRememberCondition(condPtr);
}
pthread_mutex_unlock(&masterLock);
pthread_mutex_unlock(&globalLock);
}
pmutexPtr = *((PMutex **) mutexPtr);
pcondPtr = *((pthread_cond_t **) condPtr);
if (timePtr == NULL) {
PCondWait(pcondPtr, pmutexPtr);
} else {
Tcl_Time now;
|
| ︙ | | |
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
|
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
|
-
+
|
*----------------------------------------------------------------------
*
* TclpFinalizeCondition --
*
* This procedure is invoked to clean up a condition variable. This is
* only safe to call at the end of time.
*
* This assumes the Master Lock is held.
* This assumes the Global Lock is held.
*
* Results:
* None.
*
* Side effects:
* The condition variable is deallocated.
*
|
| ︙ | | |
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
|
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
|
-
+
-
+
-
+
|
Tcl_Panic("unable to delete key!");
}
TclpSysFree(keyPtr);
}
void
TclpThreadSetMasterTSD(
TclpThreadSetGlobalTSD(
void *tsdKeyPtr,
void *ptr)
{
pthread_key_t *ptkeyPtr = (pthread_key_t *)tsdKeyPtr;
if (pthread_setspecific(*ptkeyPtr, ptr)) {
Tcl_Panic("unable to set master TSD value");
Tcl_Panic("unable to set global TSD value");
}
}
void *
TclpThreadGetMasterTSD(
TclpThreadGetGlobalTSD(
void *tsdKeyPtr)
{
pthread_key_t *ptkeyPtr = (pthread_key_t*)tsdKeyPtr;
return pthread_getspecific(*ptkeyPtr);
}
|
| ︙ | | |