1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
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
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
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
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
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
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
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
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Copyright 2016 Joyent, Inc.
* Copyright 2018 Nexenta Systems, Inc.
*/
#ifndef _THR_UBERDATA_H
#define _THR_UBERDATA_H
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <ucontext.h>
#include <thread.h>
#include <pthread.h>
#include <atomic.h>
#include <link.h>
#include <sys/resource.h>
#include <sys/lwp.h>
#include <errno.h>
#include <sys/asm_linkage.h>
#include <sys/regset.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <synch.h>
#include <door.h>
#include <limits.h>
#include <sys/synch32.h>
#include <schedctl.h>
#include <sys/priocntl.h>
#include <thread_db.h>
#include <setjmp.h>
#include <sys/thread.h>
#include "libc_int.h"
#include "tdb_agent.h"
#include "thr_debug.h"
/*
* This is an implementation-specific include file for threading support.
* It is not to be seen by the clients of the library.
*
* This file also describes uberdata in libc.
*
* The term "uberdata" refers to data that is unique and visible across
* all link maps. The name is meant to imply that such data is truly
* global, not just locally global to a particular link map.
*
* See the Linker and Libraries Guide for a full description of alternate
* link maps and how they are set up and used.
*
* Alternate link maps implement multiple global namespaces within a single
* process. There may be multiple instances of identical dynamic libraries
* loaded in a process's address space at the same time, each on a different
* link map (as determined by the dynamic linker), each with its own set of
* global variables. Which particular instance of a global variable is seen
* by a thread running in the process is determined by the link map on which
* the thread happens to be executing at the time.
*
* However, there are aspects of a process that are unique across all
* link maps, in particular the structures used to implement threads
* of control (in Sparc terminology, there is only one %g7 regardless
* of the link map on which the thread is executing).
*
* All uberdata is referenced from a base pointer in the thread's ulwp_t
* structure (which is also uberdata). All allocations and deallocations
* of uberdata are made via the uberdata-aware lmalloc() and lfree()
* interfaces (malloc() and free() are simply locally-global).
*/
/*
* Special libc-private access to errno.
* We do this so that references to errno do not invoke the dynamic linker.
*/
#undef errno
#define errno (*curthread->ul_errnop)
/*
* See <sys/synch32.h> for the reasons for these values
* and why they are different for sparc and intel.
*/
#if defined(__sparc)
/* lock.lock64.pad[x] 4 5 6 7 */
#define LOCKMASK 0xff000000
#define WAITERMASK 0x000000ff
#define SPINNERMASK 0x00ff0000
#define SPINNERSHIFT 16
#define WAITER 0x00000001
#define LOCKSET 0xff
#define LOCKCLEAR 0
#define PIDSHIFT 32
#define LOCKMASK64 0xffffffffff000000ULL
#define LOCKBYTE64 0x00000000ff000000ULL
#define WAITERMASK64 0x00000000000000ffULL
#define SPINNERMASK64 0x0000000000ff0000ULL
#elif defined(__x86)
/* lock.lock64.pad[x] 7 6 5 4 */
#define LOCKMASK 0xff000000
#define WAITERMASK 0x00ff0000
#define SPINNERMASK 0x0000ff00
#define SPINNERSHIFT 8
#define WAITER 0x00010000
#define LOCKSET 0x01
#define LOCKCLEAR 0
#define PIDSHIFT 0
#define LOCKMASK64 0xff000000ffffffffULL
#define LOCKBYTE64 0x0100000000000000ULL
#define WAITERMASK64 0x00ff000000000000ULL
#define SPINNERMASK64 0x0000ff0000000000ULL
#else
#error "neither __sparc nor __x86 is defined"
#endif
/*
* Fetch the owner of a USYNC_THREAD mutex.
* Don't use this with process-shared mutexes;
* the owing thread may be in a different process.
*/
#define MUTEX_OWNER(mp) ((ulwp_t *)(uintptr_t)(mp)->mutex_owner)
/*
* Test if a thread owns a process-private (USYNC_THREAD) mutex.
* This is inappropriate for a process-shared (USYNC_PROCESS) mutex.
* The 'mp' argument must not have side-effects since it is evaluated twice.
*/
#define MUTEX_OWNED(mp, thrp) \
((mp)->mutex_lockw != 0 && MUTEX_OWNER(mp) == thrp)
/*
* uberflags.uf_tdb_register_sync is an interface with libc_db to enable the
* collection of lock statistics by a debugger or other collecting tool.
*
* uberflags.uf_thread_error_detection is set by an environment variable:
* _THREAD_ERROR_DETECTION
* 0 == no detection of locking primitive errors.
* 1 == detect errors and issue a warning message.
* 2 == detect errors, issue a warning message, and dump core.
*
* We bundle these together in uberflags.uf_trs_ted to make a test of either
* being non-zero a single memory reference (for speed of mutex_lock(), etc).
*
* uberflags.uf_mt is set non-zero when the first thread (in addition
* to the main thread) is created.
*
* We bundle all these flags together in uberflags.uf_all to make a test
* of any being non-zero a single memory reference (again, for speed).
*/
typedef union {
int uf_all; /* combined all flags */
struct {
short h_pad;
short h_trs_ted; /* combined reg sync & error detect */
} uf_h;
struct {
char x_mt;
char x_pad;
char x_tdb_register_sync;
char x_thread_error_detection;
} uf_x;
} uberflags_t;
#define uf_mt uf_x.x_mt
#define uf_tdb_register_sync uf_x.x_tdb_register_sync
#define uf_thread_error_detection uf_x.x_thread_error_detection
#define uf_trs_ted uf_h.h_trs_ted /* both of the above */
/*
* NOTE WELL:
* To enable further optimization, the "ul_schedctl_called" member
* of the ulwp_t structure (below) serves double-duty:
* 1. If NULL, it means that the thread must call __schedctl()
* to set up its schedctl mappings before acquiring a mutex.
* This is required by the implementation of adaptive mutex locking.
* 2. If non-NULL, it points to uberdata.uberflags, so that tests of
* uberflags can be made without additional memory references.
* This allows the common case of _mutex_lock() and _mutex_unlock() for
* USYNC_THREAD mutexes with no error detection and no lock statistics
* to be optimized for speed.
*/
/* double the default stack size for 64-bit processes */
#ifdef _LP64
#define MINSTACK (8 * 1024)
#define DEFAULTSTACK (2 * 1024 * 1024)
#else
#define MINSTACK (4 * 1024)
#define DEFAULTSTACK (1024 * 1024)
#endif
#define MUTEX_TRY 0
#define MUTEX_LOCK 1
#define MUTEX_NOCEIL 0x40
#if defined(__x86)
typedef struct { /* structure returned by fnstenv */
int fctrl; /* control word */
int fstat; /* status word (flags, etc) */
int ftag; /* tag of which regs busy */
int misc[4]; /* other stuff, 28 bytes total */
} fpuenv_t;
#ifdef _SYSCALL32
typedef fpuenv_t fpuenv32_t;
#endif /* _SYSCALL32 */
#elif defined(__sparc)
typedef struct { /* fp state structure */
greg_t fsr;
greg_t fpu_en;
} fpuenv_t;
#ifdef _SYSCALL32
typedef struct {
greg32_t fsr;
greg32_t fpu_en;
} fpuenv32_t;
#endif /* _SYSCALL32 */
#endif /* __x86 */
#if defined(__x86)
extern void ht_pause(void); /* "pause" instruction */
#define SMT_PAUSE() ht_pause()
#elif defined(SMT_PAUSE_FUNCTION)
extern void SMT_PAUSE_FUNCTION(void);
#define SMT_PAUSE() SMT_PAUSE_FUNCTION()
#else
#define SMT_PAUSE() smt_pause()
#endif /* __x86 */
/*
* Cleanup handler related data.
* This structure is exported as _cleanup_t in pthread.h.
* pthread.h exports only the size of this structure, so check
* _cleanup_t in pthread.h before making any change here.
*/
typedef struct __cleanup {
struct __cleanup *next; /* pointer to next handler */
caddr_t fp; /* current frame pointer */
void (*func)(void *); /* cleanup handler address */
void *arg; /* handler's argument */
} __cleanup_t;
/*
* Thread-Specific Data (TSD)
* TSD_NFAST includes the invalid key zero, so there
* are really only (TSD_NFAST - 1) fast key slots.
*/
typedef void (*PFrV)(void *);
#define TSD_UNALLOCATED ((PFrV)1)
#define TSD_NFAST 9
/*
* The tsd union is designed to burn a little memory (9 words) to make
* lookups blindingly fast. Note that tsd_nalloc could be placed at the
* end of the pad region to increase the likelihood that it falls on the
* same cache line as the data.
*/
typedef union tsd {
uint_t tsd_nalloc; /* Amount of allocated storage */
void *tsd_pad[TSD_NFAST];
void *tsd_data[1];
} tsd_t;
typedef struct {
mutex_t tsdm_lock; /* Lock protecting the data */
uint_t tsdm_nkeys; /* Number of allocated keys */
uint_t tsdm_nused; /* Number of used keys */
PFrV *tsdm_destro; /* Per-key destructors */
char tsdm_pad[64 - /* pad to 64 bytes */
(sizeof (mutex_t) + 2 * sizeof (uint_t) + sizeof (PFrV *))];
} tsd_metadata_t;
#ifdef _SYSCALL32
typedef union tsd32 {
uint_t tsd_nalloc; /* Amount of allocated storage */
caddr32_t tsd_pad[TSD_NFAST];
caddr32_t tsd_data[1];
} tsd32_t;
typedef struct {
mutex_t tsdm_lock; /* Lock protecting the data */
uint_t tsdm_nkeys; /* Number of allocated keys */
uint_t tsdm_nused; /* Number of used keys */
caddr32_t tsdm_destro; /* Per-key destructors */
char tsdm_pad[64 - /* pad to 64 bytes */
(sizeof (mutex_t) + 2 * sizeof (uint_t) + sizeof (caddr32_t))];
} tsd_metadata32_t;
#endif /* _SYSCALL32 */
/*
* Thread-Local Storage (TLS)
*/
typedef struct {
void *tls_data;
size_t tls_size;
} tls_t;
typedef struct {
mutex_t tls_lock; /* Lock protecting the data */
tls_t tls_modinfo; /* Root of all TLS_modinfo data */
tls_t static_tls; /* Template for static TLS */
char tls_pad[64 - /* pad to 64 bytes */
(sizeof (mutex_t) + 2 * sizeof (tls_t))];
} tls_metadata_t;
#ifdef _SYSCALL32
typedef struct {
caddr32_t tls_data;
size32_t tls_size;
} tls32_t;
typedef struct {
mutex_t tls_lock; /* Lock protecting the data */
tls32_t tls_modinfo; /* Root of all TLS_modinfo data */
tls32_t static_tls; /* Template for static TLS */
char tls_pad[64 - /* pad to 64 bytes */
(sizeof (mutex_t) + 2 * sizeof (tls32_t))];
} tls_metadata32_t;
#endif /* _SYSCALL32 */
/*
* Sleep queue root for USYNC_THREAD condvars and mutexes.
* There is a default queue root for each queue head (see below).
* Also, each ulwp_t contains a queue root that can be used
* when the thread is enqueued on the queue, if necessary
* (when more than one wchan hashes to the same queue head).
*/
typedef struct queue_root {
struct queue_root *qr_next;
struct queue_root *qr_prev;
struct ulwp *qr_head;
struct ulwp *qr_tail;
void *qr_wchan;
uint32_t qr_rtcount;
uint32_t qr_qlen;
uint32_t qr_qmax;
} queue_root_t;
#ifdef _SYSCALL32
typedef struct queue_root32 {
caddr32_t qr_next;
caddr32_t qr_prev;
caddr32_t qr_head;
caddr32_t qr_tail;
caddr32_t qr_wchan;
uint32_t qr_rtcount;
uint32_t qr_qlen;
uint32_t qr_qmax;
} queue_root32_t;
#endif
/*
* Sleep queue heads for USYNC_THREAD condvars and mutexes.
* The size and alignment is 128 bytes to reduce cache conflicts.
* Each queue head points to a list of queue roots, defined above.
* Each queue head contains a default queue root for use when only one
* is needed. It is always at the tail of the queue root hash chain.
*/
typedef union {
uint64_t qh_64[16];
struct {
mutex_t q_lock;
uint8_t q_qcnt;
uint8_t q_type; /* MX or CV */
uint8_t q_pad1[2];
uint32_t q_lockcount;
uint32_t q_qlen;
uint32_t q_qmax;
void *q_wchan; /* valid only while locked */
struct queue_root *q_root; /* valid only while locked */
struct queue_root *q_hlist;
#if !defined(_LP64)
caddr_t q_pad2[3];
#endif
queue_root_t q_def_root;
uint32_t q_hlen;
uint32_t q_hmax;
} qh_qh;
} queue_head_t;
#define qh_lock qh_qh.q_lock
#define qh_qcnt qh_qh.q_qcnt
#define qh_type qh_qh.q_type
#if defined(THREAD_DEBUG)
#define qh_lockcount qh_qh.q_lockcount
#define qh_qlen qh_qh.q_qlen
#define qh_qmax qh_qh.q_qmax
#endif
#define qh_wchan qh_qh.q_wchan
#define qh_root qh_qh.q_root
#define qh_hlist qh_qh.q_hlist
#define qh_def_root qh_qh.q_def_root
#define qh_hlen qh_qh.q_hlen
#define qh_hmax qh_qh.q_hmax
/* queue types passed to queue_lock() */
#define MX 0
#define CV 1
#define QHASHSHIFT 9 /* number of hashing bits */
#define QHASHSIZE (1 << QHASHSHIFT) /* power of 2 (1<<9 == 512) */
#define QUEUE_HASH(wchan, type) ((uint_t) \
((((uintptr_t)(wchan) >> 3) \
^ ((uintptr_t)(wchan) >> (QHASHSHIFT + 3))) \
& (QHASHSIZE - 1)) + (((type) == MX)? 0 : QHASHSIZE))
extern queue_head_t *queue_lock(void *, int);
extern void queue_unlock(queue_head_t *);
extern void enqueue(queue_head_t *, struct ulwp *, int);
extern struct ulwp *dequeue(queue_head_t *, int *);
extern struct ulwp **queue_slot(queue_head_t *, struct ulwp **, int *);
extern struct ulwp *queue_waiter(queue_head_t *);
extern int dequeue_self(queue_head_t *);
extern void queue_unlink(queue_head_t *,
struct ulwp **, struct ulwp *);
extern void unsleep_self(void);
extern void spin_lock_set(mutex_t *);
extern void spin_lock_clear(mutex_t *);
/*
* Scheduling class information structure.
*/
typedef struct {
short pcc_state;
short pcc_policy;
pri_t pcc_primin;
pri_t pcc_primax;
pcinfo_t pcc_info;
} pcclass_t;
/*
* Memory block for chain of owned ceiling mutexes.
*/
typedef struct mxchain {
struct mxchain *mxchain_next;
mutex_t *mxchain_mx;
} mxchain_t;
/*
* Pointer to an rwlock that is held for reading.
* Used in rw_rdlock() to allow a thread that already holds a read
* lock to acquire another read lock on the same rwlock even if
* there are writers waiting. This to avoid deadlock when acquiring
* a read lock more than once in the presence of pending writers.
* POSIX mandates this behavior.
*/
typedef struct {
void *rd_rwlock; /* the rwlock held for reading */
size_t rd_count; /* count of read locks applied */
} readlock_t;
#ifdef _SYSCALL32
typedef struct {
caddr32_t rd_rwlock;
size32_t rd_count;
} readlock32_t;
#endif /* _SYSCALL32 */
/*
* As part of per-thread caching libumem (ptcumem), we add a small amount to the
* thread's uberdata to facilitate it. The tm_roots are the roots of linked
* lists which is used by libumem to chain together allocations. tm_size is used
* to track the total amount of data stored across those linked lists. For more
* information, see libumem's big theory statement.
*/
#define NTMEMBASE 16
typedef struct {
size_t tm_size;
void *tm_roots[NTMEMBASE];
} tumem_t;
#ifdef _SYSCALL32
typedef struct {
uint32_t tm_size;
caddr32_t tm_roots[NTMEMBASE];
} tumem32_t;
#endif
typedef void (*tmem_func_t)(void *, int);
/*
* Maximum number of read locks allowed for one thread on one rwlock.
* This could be as large as INT_MAX, but the SUSV3 test suite would
* take an inordinately long time to complete. This is big enough.
*/
#define READ_LOCK_MAX 100000
#define ul_tlsent ul_tls.tls_data /* array of pointers to dynamic TLS */
#define ul_ntlsent ul_tls.tls_size /* number of entries in ul_tlsent */
/*
* Round up an integral value to a multiple of 64
*/
#define roundup64(x) (-(-(x) & -64))
/*
* NOTE: Whatever changes are made to ulwp_t must be
* reflected in $SRC/cmd/mdb/common/modules/libc/libc.c
*
* NOTE: ul_self *must* be the first member of ulwp_t on x86
* Low-level x86 code relies on this.
*/
typedef struct ulwp {
/*
* These members always need to come first on sparc.
* For dtrace, a ulwp_t must be aligned on a 64-byte boundary.
*/
#if defined(__sparc)
uint32_t ul_dinstr; /* scratch space for dtrace */
uint32_t ul_padsparc0[15];
uint32_t ul_dsave; /* dtrace: save %g1, %g0, %sp */
uint32_t ul_drestore; /* dtrace: restore %g0, %g0, %g0 */
uint32_t ul_dftret; /* dtrace: return probe fasttrap */
uint32_t ul_dreturn; /* dtrace: return %o0 */
#endif
struct ulwp *ul_self; /* pointer to self */
#if defined(__i386)
uint8_t ul_dinstr[40]; /* scratch space for dtrace */
#elif defined(__amd64)
uint8_t ul_dinstr[56]; /* scratch space for dtrace */
#endif
struct uberdata *ul_uberdata; /* uber (super-global) data */
tls_t ul_tls; /* dynamic thread-local storage base */
struct ulwp *ul_forw; /* forw, back all_lwps list, */
struct ulwp *ul_back; /* protected by link_lock */
struct ulwp *ul_next; /* list to keep track of stacks */
struct ulwp *ul_hash; /* hash chain linked list */
void *ul_rval; /* return value from thr_exit() */
caddr_t ul_stk; /* mapping base of the stack */
size_t ul_mapsiz; /* mapping size of the stack */
size_t ul_guardsize; /* normally _lpagesize */
uintptr_t ul_stktop; /* broken thr_stksegment() interface */
size_t ul_stksiz; /* broken thr_stksegment() interface */
stack_t ul_ustack; /* current stack boundaries */
int ul_ix; /* hash index */
lwpid_t ul_lwpid; /* thread id, aka the lwp id */
pri_t ul_pri; /* scheduling priority */
pri_t ul_epri; /* real-time ceiling priority */
char ul_policy; /* scheduling policy */
char ul_cid; /* scheduling class id */
union {
struct {
char cursig; /* deferred signal number */
char pleasestop; /* lwp requested to stop itself */
} s;
short curplease; /* for testing both at once */
} ul_cp;
char ul_stop; /* reason for stopping */
char ul_signalled; /* this lwp was cond_signal()d */
char ul_dead; /* this lwp has called thr_exit */
char ul_unwind; /* posix: unwind C++ stack */
char ul_detached; /* THR_DETACHED at thread_create() */
/* or pthread_detach() was called */
char ul_writer; /* sleeping in rw_wrlock() */
char ul_stopping; /* set by curthread: stopping self */
char ul_cancel_prologue; /* for _cancel_prologue() */
short ul_preempt; /* no_preempt()/preempt() */
short ul_savpreempt; /* pre-existing preempt value */
char ul_sigsuspend; /* thread is in sigsuspend/pollsys */
char ul_main; /* thread is the main thread */
char ul_fork; /* thread is performing a fork */
char ul_primarymap; /* primary link-map is initialized */
/* per-thread copies of the corresponding global variables */
uint8_t ul_max_spinners; /* thread_max_spinners */
char ul_door_noreserve; /* thread_door_noreserve */
char ul_queue_fifo; /* thread_queue_fifo */
char ul_cond_wait_defer; /* thread_cond_wait_defer */
char ul_error_detection; /* thread_error_detection */
char ul_async_safe; /* thread_async_safe */
char ul_rt; /* found on an RT queue */
char ul_rtqueued; /* was RT when queued */
char ul_misaligned; /* thread_locks_misaligned */
char ul_pad[3];
int ul_adaptive_spin; /* thread_adaptive_spin */
int ul_queue_spin; /* thread_queue_spin */
volatile int ul_critical; /* non-zero == in a critical region */
int ul_sigdefer; /* non-zero == defer signals */
int ul_vfork; /* thread is the child of vfork() */
int ul_cancelable; /* _cancelon()/_canceloff() */
char ul_cancel_pending; /* pthread_cancel() was called */
char ul_cancel_disabled; /* PTHREAD_CANCEL_DISABLE */
char ul_cancel_async; /* PTHREAD_CANCEL_ASYNCHRONOUS */
char ul_save_async; /* saved copy of ul_cancel_async */
char ul_mutator; /* lwp is a mutator (java interface) */
char ul_created; /* created suspended */
char ul_replace; /* replacement; must be free()d */
uchar_t ul_nocancel; /* cancellation can't happen */
int ul_errno; /* per-thread errno */
int *ul_errnop; /* pointer to errno or self->ul_errno */
__cleanup_t *ul_clnup_hdr; /* head of cleanup handlers list */
uberflags_t *ul_schedctl_called; /* ul_schedctl is set up */
volatile sc_shared_t *ul_schedctl; /* schedctl data */
int ul_bindflags; /* bind_guard() interface to ld.so.1 */
uint_t ul_libc_locks; /* count of cancel_safe_mutex_lock()s */
tsd_t *ul_stsd; /* slow TLS for keys >= TSD_NFAST */
void *ul_ftsd[TSD_NFAST]; /* fast TLS for keys < TSD_NFAST */
td_evbuf_t ul_td_evbuf; /* event buffer */
char ul_td_events_enable; /* event mechanism enabled */
char ul_sync_obj_reg; /* tdb_sync_obj_register() */
char ul_qtype; /* MX or CV */
char ul_cv_wake; /* != 0: just wake up, don't requeue */
int ul_rtld; /* thread is running inside ld.so.1 */
int ul_usropts; /* flags given to thr_create() */
void *(*ul_startpc)(void *); /* start func (thr_create()) */
void *ul_startarg; /* argument for start function */
void *ul_wchan; /* synch object when sleeping */
struct ulwp *ul_link; /* sleep queue link */
queue_head_t *ul_sleepq; /* sleep queue thread is waiting on */
mutex_t *ul_cvmutex; /* mutex dropped when waiting on a cv */
mxchain_t *ul_mxchain; /* chain of owned ceiling mutexes */
int ul_save_state; /* bind_guard() interface to ld.so.1 */
uint_t ul_rdlockcnt; /* # entries in ul_readlock array */
/* 0 means there is but a single entry */
union { /* single entry or pointer to array */
readlock_t single;
readlock_t *array;
} ul_readlock;
uint_t ul_heldlockcnt; /* # entries in ul_heldlocks array */
/* 0 means there is but a single entry */
union { /* single entry or pointer to array */
mutex_t *single;
mutex_t **array;
} ul_heldlocks;
/* PROBE_SUPPORT begin */
void *ul_tpdp;
/* PROBE_SUPPORT end */
ucontext_t *ul_siglink; /* pointer to previous context */
uint_t ul_spin_lock_spin; /* spin lock statistics */
uint_t ul_spin_lock_spin2;
uint_t ul_spin_lock_sleep;
uint_t ul_spin_lock_wakeup;
queue_root_t ul_queue_root; /* root of a sleep queue */
id_t ul_rtclassid; /* real-time class id */
uint_t ul_pilocks; /* count of PI locks held */
/* the following members *must* be last in the structure */
/* they are discarded when ulwp is replaced on thr_exit() */
sigset_t ul_sigmask; /* thread's current signal mask */
sigset_t ul_tmpmask; /* signal mask for sigsuspend/pollsys */
siginfo_t ul_siginfo; /* deferred siginfo */
mutex_t ul_spinlock; /* used when suspending/continuing */
fpuenv_t ul_fpuenv; /* floating point state */
uintptr_t ul_sp; /* stack pointer when blocked */
void *ul_ex_unwind; /* address of _ex_unwind() or -1 */
#if defined(sparc)
void *ul_unwind_ret; /* used only by _ex_clnup_handler() */
#endif
tumem_t ul_tmem; /* used only by umem */
uint_t ul_ptinherit; /* pthreads sched inherit value */
char ul_ntoabuf[18]; /* thread-specific inet_ntoa buffer */
} ulwp_t;
#define ul_cursig ul_cp.s.cursig /* deferred signal number */
#define ul_pleasestop ul_cp.s.pleasestop /* lwp requested to stop */
#define ul_curplease ul_cp.curplease /* for testing both at once */
/*
* This is the size of a replacement ulwp, retained only for the benefit
* of thr_join(). The trailing members are unneeded for this purpose.
*/
#define REPLACEMENT_SIZE ((size_t)&((ulwp_t *)NULL)->ul_sigmask)
/*
* Definitions for static initialization of signal sets,
* plus some sneaky optimizations in various places.
*/
#define SIGMASK(sig) ((uint32_t)1 << (((sig) - 1) & (32 - 1)))
#if (MAXSIG > (2 * 32) && MAXSIG <= (3 * 32))
#define FILLSET0 0xffffffffu
#define FILLSET1 0xffffffffu
#define FILLSET2 ((1u << (MAXSIG - 64)) - 1)
#define FILLSET3 0
#else
#error "fix me: MAXSIG out of bounds"
#endif
#define CANTMASK0 (SIGMASK(SIGKILL) | SIGMASK(SIGSTOP))
#define CANTMASK1 0
#define CANTMASK2 0
#define CANTMASK3 0
#define MASKSET0 (FILLSET0 & ~CANTMASK0)
#define MASKSET1 (FILLSET1 & ~CANTMASK1)
#define MASKSET2 (FILLSET2 & ~CANTMASK2)
#define MASKSET3 (FILLSET3 & ~CANTMASK3)
extern const sigset_t maskset; /* set of all maskable signals */
extern int thread_adaptive_spin;
extern uint_t thread_max_spinners;
extern int thread_queue_spin;
extern int thread_queue_fifo;
extern int thread_queue_dump;
extern int thread_cond_wait_defer;
extern int thread_async_safe;
extern int thread_queue_verify;
/*
* pthread_atfork() related data, used to store atfork handlers.
*/
typedef struct atfork {
struct atfork *forw; /* forward pointer */
struct atfork *back; /* backward pointer */
void (*prepare)(void); /* pre-fork handler */
void (*parent)(void); /* post-fork parent handler */
void (*child)(void); /* post-fork child handler */
} atfork_t;
/*
* Element in the table and in the list of registered process
* robust locks. We keep track of these to make sure that we
* only call ___lwp_mutex_register() once for each such lock
* after it is first mapped in (or newly mapped in).
*/
typedef struct robust {
struct robust *robust_next; /* hash table list */
struct robust *robust_list; /* global list */
mutex_t *robust_lock;
} robust_t;
/*
* Invalid address, used to mark an unused element in the hash table.
*/
#define INVALID_ADDR ((void *)(uintptr_t)(-1L))
/*
* Parameters of the lock registration hash table.
*/
#define LOCKSHIFT 15 /* number of hashing bits */
#define LOCKHASHSZ (1 << LOCKSHIFT) /* power of 2 (1<<15 == 32K) */
#define LOCK_HASH(addr) (uint_t) \
((((uintptr_t)(addr) >> 3) \
^ ((uintptr_t)(addr) >> (LOCKSHIFT + 3))) \
& (LOCKHASHSZ - 1))
/*
* Make our hot locks reside on private cache lines (64 bytes).
*/
typedef struct {
mutex_t pad_lock;
char pad_pad[64 - sizeof (mutex_t)];
} pad_lock_t;
/*
* Make our semi-hot locks reside on semi-private cache lines (32 bytes).
*/
typedef struct {
mutex_t pad_lock;
char pad_pad[32 - sizeof (mutex_t)];
} pad32_lock_t;
/*
* The threads hash table is used for fast lookup and locking of an active
* thread structure (ulwp_t) given a thread-id. It is an N-element array of
* thr_hash_table_t structures, where N == 1 before the main thread creates
* the first additional thread and N == 1024 afterwards. Each element of the
* table is 64 bytes in size and alignment to reduce cache conflicts.
*/
typedef struct {
mutex_t hash_lock; /* lock per bucket */
cond_t hash_cond; /* convar per bucket */
ulwp_t *hash_bucket; /* hash bucket points to the list of ulwps */
char hash_pad[64 - /* pad out to 64 bytes */
(sizeof (mutex_t) + sizeof (cond_t) + sizeof (ulwp_t *))];
} thr_hash_table_t;
#ifdef _SYSCALL32
typedef struct {
mutex_t hash_lock;
cond_t hash_cond;
caddr32_t hash_bucket;
char hash_pad[64 -
(sizeof (mutex_t) + sizeof (cond_t) + sizeof (caddr32_t))];
} thr_hash_table32_t;
#endif /* _SYSCALL32 */
/*
* siguaction members have 128-byte size and 64-byte alignment.
* We know that sizeof (struct sigaction) is 32 bytes for both
* _ILP32 and _LP64 and that sizeof (rwlock_t) is 64 bytes.
*/
typedef struct {
rwlock_t sig_lock;
struct sigaction sig_uaction;
char sig_pad[128 - sizeof (rwlock_t) - sizeof (struct sigaction)];
} siguaction_t;
#ifdef _SYSCALL32
typedef struct {
rwlock_t sig_lock;
struct sigaction32 sig_uaction;
char sig_pad[128 - sizeof (rwlock_t) - sizeof (struct sigaction32)];
} siguaction32_t;
#endif /* _SYSCALL32 */
/*
* Bucket structures, used by lmalloc()/lfree().
* See port/threads/alloc.c for details.
* A bucket's size and alignment is 64 bytes.
*/
typedef struct {
mutex_t bucket_lock; /* protects the free list allocations */
void *free_list; /* LIFO list of blocks to allocate/free */
size_t chunks; /* number of 64K blocks mmap()ed last time */
char pad64[64 - /* pad out to 64 bytes */
(sizeof (mutex_t) + sizeof (void *) + sizeof (size_t))];
} bucket_t;
#ifdef _SYSCALL32
typedef struct {
mutex_t bucket_lock;
caddr32_t free_list;
size32_t chunks;
char pad64[64 - /* pad out to 64 bytes */
(sizeof (mutex_t) + sizeof (caddr32_t) + sizeof (size32_t))];
} bucket32_t;
#endif /* _SYSCALL32 */
#define NBUCKETS 10 /* sizes ranging from 64 to 32768 */
/*
* atexit() data structures.
* See port/gen/atexit.c for details.
*/
typedef void (*_exithdlr_func_t) (void*);
typedef struct _exthdlr {
struct _exthdlr *next; /* next in handler list */
_exithdlr_func_t hdlr; /* handler itself */
void *arg; /* argument to handler */
void *dso; /* DSO associated with handler */
} _exthdlr_t;
typedef struct {
mutex_t exitfns_lock;
_exthdlr_t *head;
/*
* exit_frame_monitor is part of a private contract between libc and
* the Sun C++ runtime.
*
* It should be NULL until exit() is called, and thereafter hold the
* frame pointer of the function implementing our exit processing.
*/
void *exit_frame_monitor;
char exit_pad[64 - /* pad out to 64 bytes */
(sizeof (mutex_t) + sizeof (_exthdlr_t *) + sizeof (void *))];
} atexit_root_t;
#ifdef _SYSCALL32
typedef struct {
mutex_t exitfns_lock;
caddr32_t head;
caddr32_t exit_frame_monitor;
char exit_pad[64 - /* pad out to 64 bytes */
(sizeof (mutex_t) + sizeof (caddr32_t) + sizeof (caddr32_t))];
} atexit_root32_t;
#endif /* _SYSCALL32 */
/*
* at_quick_exit() and quick_exit() data structures. The ISO/IEC C11 odd
* siblings of atexit()
*/
typedef void (*_quick_exithdlr_func_t)(void);
typedef struct _qexthdlr {
struct _qexthdlr *next; /* next in handler list */
_quick_exithdlr_func_t hdlr; /* handler itself */
} _qexthdlr_t;
/*
* We add a pad on 32-bit systems to allow us to always have the structure size
* be 32-bytes which helps us deal with the compiler's alignment when building
* in ILP32 / LP64 systems.
*/
typedef struct {
mutex_t exitfns_lock;
_qexthdlr_t *head;
#if !defined(_LP64)
uint32_t pad;
#endif
} quickexit_root_t;
#ifdef _SYSCALL32
typedef struct {
mutex_t exitfns_lock;
caddr32_t head;
uint32_t pad;
} quickexit_root32_t;
#endif /* _SYSCALL32 */
/*
* This is data that is global to all link maps (uberdata, aka super-global).
* Note: When changing this, please be sure to keep the 32-bit variant of
* this in sync. (see uberdata32_t below)
*/
typedef struct uberdata {
pad_lock_t _link_lock;
pad_lock_t _ld_lock;
pad_lock_t _fork_lock;
pad_lock_t _atfork_lock;
pad32_lock_t _callout_lock;
pad32_lock_t _tdb_hash_lock;
tdb_sync_stats_t tdb_hash_lock_stats;
siguaction_t siguaction[NSIG];
bucket_t bucket[NBUCKETS];
atexit_root_t atexit_root;
quickexit_root_t quickexit_root;
tsd_metadata_t tsd_metadata;
tls_metadata_t tls_metadata;
/*
* Every object before this point has size and alignment of 64 bytes.
* Don't add any other type of data before this point.
*/
char primary_map; /* set when primary link map is initialized */
char bucket_init; /* set when bucket[NBUCKETS] is initialized */
char pad[2];
uberflags_t uberflags;
queue_head_t *queue_head;
thr_hash_table_t *thr_hash_table;
uint_t hash_size; /* # of entries in thr_hash_table[] */
uint_t hash_mask; /* hash_size - 1 */
ulwp_t *ulwp_one; /* main thread */
ulwp_t *all_lwps; /* circular ul_forw/ul_back list of live lwps */
ulwp_t *all_zombies; /* circular ul_forw/ul_back list of zombies */
int nthreads; /* total number of live threads/lwps */
int nzombies; /* total number of zombie threads */
int ndaemons; /* total number of THR_DAEMON threads/lwps */
pid_t pid; /* the current process's pid */
void (*sigacthandler)(int, siginfo_t *, void *);
int (*setctxt)(const ucontext_t *);
ulwp_t *lwp_stacks;
ulwp_t *lwp_laststack;
int nfreestack;
int thread_stack_cache;
ulwp_t *ulwp_freelist;
ulwp_t *ulwp_lastfree;
ulwp_t *ulwp_replace_free;
ulwp_t *ulwp_replace_last;
atfork_t *atforklist; /* circular Q for fork handlers */
robust_t **robustlocks; /* table of registered robust locks */
robust_t *robustlist; /* list of registered robust locks */
char *progname; /* the basename of the program, from argv[0] */
char *ub_broot; /* the root of the native code in the brand */
void *ub_comm_page; /* arch-specific comm page of kernel data */
struct uberdata **tdb_bootstrap;
tdb_t tdb; /* thread debug interfaces (for libc_db) */
} uberdata_t;
#define link_lock _link_lock.pad_lock
#define ld_lock _ld_lock.pad_lock
#define fork_lock _fork_lock.pad_lock
#define atfork_lock _atfork_lock.pad_lock
#define callout_lock _callout_lock.pad_lock
#define tdb_hash_lock _tdb_hash_lock.pad_lock
#pragma align 64(__uberdata)
extern uberdata_t __uberdata;
extern uberdata_t **__tdb_bootstrap; /* known to libc_db and mdb */
extern int primary_link_map;
#define ulwp_mutex(ulwp, udp) \
(&(udp)->thr_hash_table[(ulwp)->ul_ix].hash_lock)
#define ulwp_condvar(ulwp, udp) \
(&(udp)->thr_hash_table[(ulwp)->ul_ix].hash_cond)
/*
* Grab and release the hash table lock for the specified lwp.
*/
#define ulwp_lock(ulwp, udp) lmutex_lock(ulwp_mutex(ulwp, udp))
#define ulwp_unlock(ulwp, udp) lmutex_unlock(ulwp_mutex(ulwp, udp))
#ifdef _SYSCALL32 /* needed by libc_db */
typedef struct ulwp32 {
#if defined(__sparc)
uint32_t ul_dinstr; /* scratch space for dtrace */
uint32_t ul_padsparc0[15];
uint32_t ul_dsave; /* dtrace: save %g1, %g0, %sp */
uint32_t ul_drestore; /* dtrace: restore %g0, %g0, %g0 */
uint32_t ul_dftret; /* dtrace: return probe fasttrap */
uint32_t ul_dreturn; /* dtrace: return %o0 */
#endif
caddr32_t ul_self; /* pointer to self */
#if defined(__x86)
uint8_t ul_dinstr[40]; /* scratch space for dtrace */
#endif
caddr32_t ul_uberdata; /* uber (super-global) data */
tls32_t ul_tls; /* dynamic thread-local storage base */
caddr32_t ul_forw; /* forw, back all_lwps list, */
caddr32_t ul_back; /* protected by link_lock */
caddr32_t ul_next; /* list to keep track of stacks */
caddr32_t ul_hash; /* hash chain linked list */
caddr32_t ul_rval; /* return value from thr_exit() */
caddr32_t ul_stk; /* mapping base of the stack */
size32_t ul_mapsiz; /* mapping size of the stack */
size32_t ul_guardsize; /* normally _lpagesize */
caddr32_t ul_stktop; /* broken thr_stksegment() interface */
size32_t ul_stksiz; /* broken thr_stksegment() interface */
stack32_t ul_ustack; /* current stack boundaries */
int ul_ix; /* hash index */
lwpid_t ul_lwpid; /* thread id, aka the lwp id */
pri_t ul_pri; /* scheduling priority */
pri_t ul_epri; /* real-time ceiling priority */
char ul_policy; /* scheduling policy */
char ul_cid; /* scheduling class id */
union {
struct {
char cursig; /* deferred signal number */
char pleasestop; /* lwp requested to stop itself */
} s;
short curplease; /* for testing both at once */
} ul_cp;
char ul_stop; /* reason for stopping */
char ul_signalled; /* this lwp was cond_signal()d */
char ul_dead; /* this lwp has called thr_exit */
char ul_unwind; /* posix: unwind C++ stack */
char ul_detached; /* THR_DETACHED at thread_create() */
/* or pthread_detach() was called */
char ul_writer; /* sleeping in rw_wrlock() */
char ul_stopping; /* set by curthread: stopping self */
char ul_cancel_prologue; /* for _cancel_prologue() */
short ul_preempt; /* no_preempt()/preempt() */
short ul_savpreempt; /* pre-existing preempt value */
char ul_sigsuspend; /* thread is in sigsuspend/pollsys */
char ul_main; /* thread is the main thread */
char ul_fork; /* thread is performing a fork */
char ul_primarymap; /* primary link-map is initialized */
/* per-thread copies of the corresponding global variables */
uint8_t ul_max_spinners; /* thread_max_spinners */
char ul_door_noreserve; /* thread_door_noreserve */
char ul_queue_fifo; /* thread_queue_fifo */
char ul_cond_wait_defer; /* thread_cond_wait_defer */
char ul_error_detection; /* thread_error_detection */
char ul_async_safe; /* thread_async_safe */
char ul_rt; /* found on an RT queue */
char ul_rtqueued; /* was RT when queued */
char ul_misaligned; /* thread_locks_misaligned */
char ul_pad[3];
int ul_adaptive_spin; /* thread_adaptive_spin */
int ul_queue_spin; /* thread_queue_spin */
int ul_critical; /* non-zero == in a critical region */
int ul_sigdefer; /* non-zero == defer signals */
int ul_vfork; /* thread is the child of vfork() */
int ul_cancelable; /* _cancelon()/_canceloff() */
char ul_cancel_pending; /* pthread_cancel() was called */
char ul_cancel_disabled; /* PTHREAD_CANCEL_DISABLE */
char ul_cancel_async; /* PTHREAD_CANCEL_ASYNCHRONOUS */
char ul_save_async; /* saved copy of ul_cancel_async */
char ul_mutator; /* lwp is a mutator (java interface) */
char ul_created; /* created suspended */
char ul_replace; /* replacement; must be free()d */
uchar_t ul_nocancel; /* cancellation can't happen */
int ul_errno; /* per-thread errno */
caddr32_t ul_errnop; /* pointer to errno or self->ul_errno */
caddr32_t ul_clnup_hdr; /* head of cleanup handlers list */
caddr32_t ul_schedctl_called; /* ul_schedctl is set up */
caddr32_t ul_schedctl; /* schedctl data */
int ul_bindflags; /* bind_guard() interface to ld.so.1 */
uint_t ul_libc_locks; /* count of cancel_safe_mutex_lock()s */
caddr32_t ul_stsd; /* slow TLS for keys >= TSD_NFAST */
caddr32_t ul_ftsd[TSD_NFAST]; /* fast TLS for keys < TSD_NFAST */
td_evbuf32_t ul_td_evbuf; /* event buffer */
char ul_td_events_enable; /* event mechanism enabled */
char ul_sync_obj_reg; /* tdb_sync_obj_register() */
char ul_qtype; /* MX or CV */
char ul_cv_wake; /* != 0: just wake up, don't requeue */
int ul_rtld; /* thread is running inside ld.so.1 */
int ul_usropts; /* flags given to thr_create() */
caddr32_t ul_startpc; /* start func (thr_create()) */
caddr32_t ul_startarg; /* argument for start function */
caddr32_t ul_wchan; /* synch object when sleeping */
caddr32_t ul_link; /* sleep queue link */
caddr32_t ul_sleepq; /* sleep queue thread is waiting on */
caddr32_t ul_cvmutex; /* mutex dropped when waiting on a cv */
caddr32_t ul_mxchain; /* chain of owned ceiling mutexes */
int ul_save_state; /* bind_guard() interface to ld.so.1 */
uint_t ul_rdlockcnt; /* # entries in ul_readlock array */
/* 0 means there is but a single entry */
union { /* single entry or pointer to array */
readlock32_t single;
caddr32_t array;
} ul_readlock;
uint_t ul_heldlockcnt; /* # entries in ul_heldlocks array */
/* 0 means there is but a single entry */
union { /* single entry or pointer to array */
caddr32_t single;
caddr32_t array;
} ul_heldlocks;
/* PROBE_SUPPORT begin */
caddr32_t ul_tpdp;
/* PROBE_SUPPORT end */
caddr32_t ul_siglink; /* pointer to previous context */
uint_t ul_spin_lock_spin; /* spin lock statistics */
uint_t ul_spin_lock_spin2;
uint_t ul_spin_lock_sleep;
uint_t ul_spin_lock_wakeup;
queue_root32_t ul_queue_root; /* root of a sleep queue */
id_t ul_rtclassid; /* real-time class id */
uint_t ul_pilocks; /* count of PI locks held */
/* the following members *must* be last in the structure */
/* they are discarded when ulwp is replaced on thr_exit() */
sigset_t ul_sigmask; /* thread's current signal mask */
sigset_t ul_tmpmask; /* signal mask for sigsuspend/pollsys */
siginfo32_t ul_siginfo; /* deferred siginfo */
mutex_t ul_spinlock; /* used when suspending/continuing */
fpuenv32_t ul_fpuenv; /* floating point state */
caddr32_t ul_sp; /* stack pointer when blocked */
#if defined(sparc)
caddr32_t ul_unwind_ret; /* used only by _ex_clnup_handler() */
#endif
tumem32_t ul_tmem; /* used only by umem */
} ulwp32_t;
#define REPLACEMENT_SIZE32 ((size_t)&((ulwp32_t *)NULL)->ul_sigmask)
typedef struct uberdata32 {
pad_lock_t _link_lock;
pad_lock_t _ld_lock;
pad_lock_t _fork_lock;
pad_lock_t _atfork_lock;
pad32_lock_t _callout_lock;
pad32_lock_t _tdb_hash_lock;
tdb_sync_stats_t tdb_hash_lock_stats;
siguaction32_t siguaction[NSIG];
bucket32_t bucket[NBUCKETS];
atexit_root32_t atexit_root;
quickexit_root32_t quickexit_root;
tsd_metadata32_t tsd_metadata;
tls_metadata32_t tls_metadata;
char primary_map;
char bucket_init;
char pad[2];
uberflags_t uberflags;
caddr32_t queue_head;
caddr32_t thr_hash_table;
uint_t hash_size;
uint_t hash_mask;
caddr32_t ulwp_one;
caddr32_t all_lwps;
caddr32_t all_zombies;
int nthreads;
int nzombies;
int ndaemons;
int pid;
caddr32_t sigacthandler;
caddr32_t setctxt;
caddr32_t lwp_stacks;
caddr32_t lwp_laststack;
int nfreestack;
int thread_stack_cache;
caddr32_t ulwp_freelist;
caddr32_t ulwp_lastfree;
caddr32_t ulwp_replace_free;
caddr32_t ulwp_replace_last;
caddr32_t atforklist;
caddr32_t robustlocks;
caddr32_t robustlist;
caddr32_t progname;
caddr32_t ub_broot;
caddr32_t ub_comm_page;
caddr32_t tdb_bootstrap;
tdb32_t tdb;
} uberdata32_t;
#endif /* _SYSCALL32 */
/* ul_stop values */
#define TSTP_REGULAR 0x01 /* Stopped by thr_suspend() */
#define TSTP_MUTATOR 0x08 /* stopped by thr_suspend_*mutator*() */
#define TSTP_FORK 0x20 /* stopped by suspend_fork() */
/*
* Implementation-specific attribute types for pthread_mutexattr_init() etc.
*/
typedef struct _cvattr {
int pshared;
clockid_t clockid;
} cvattr_t;
typedef struct _mattr {
int pshared;
int protocol;
int prioceiling;
int type;
int robustness;
} mattr_t;
typedef struct _thrattr {
size_t stksize;
void *stkaddr;
int detachstate;
int daemonstate;
int scope;
int prio;
int policy;
int inherit;
size_t guardsize;
char name[THREAD_NAME_MAX];
} thrattr_t;
typedef struct _rwlattr {
int pshared;
} rwlattr_t;
/* _curthread() is inline for speed */
extern ulwp_t *_curthread(void);
#define curthread (_curthread())
/* this version (also inline) can be tested for NULL */
extern ulwp_t *__curthread(void);
/* get the current stack pointer (also inline) */
extern greg_t stkptr(void);
/*
* Suppress __attribute__((...)) if we are not compiling with gcc
*/
#if !defined(__GNUC__)
#define __attribute__(string)
#endif
/* Fetch the dispatch (kernel) priority of a thread */
#define real_priority(ulwp) \
((ulwp)->ul_schedctl? (ulwp)->ul_schedctl->sc_priority : 0)
/*
* Implementation functions. Not visible outside of the library itself.
*/
extern int __nanosleep(const timespec_t *, timespec_t *);
extern void getgregs(ulwp_t *, gregset_t);
extern void setgregs(ulwp_t *, gregset_t);
extern void thr_panic(const char *);
#pragma rarely_called(thr_panic)
extern void mutex_panic(mutex_t *, const char *);
#pragma rarely_called(mutex_panic)
extern ulwp_t *find_lwp(thread_t);
extern void finish_init(void);
extern void update_sched(ulwp_t *);
extern void queue_alloc(void);
extern void tmem_exit(void);
extern void tsd_exit(void);
extern void tsd_free(ulwp_t *);
extern void tls_setup(void);
extern void tls_exit(void);
extern void tls_free(ulwp_t *);
extern void rwl_free(ulwp_t *);
extern void heldlock_exit(void);
extern void heldlock_free(ulwp_t *);
extern void sigacthandler(int, siginfo_t *, void *);
extern int setctxt(const ucontext_t *);
extern void signal_init(void);
extern int sigequalset(const sigset_t *, const sigset_t *);
extern void mutex_setup(void);
extern void take_deferred_signal(int);
extern void *setup_top_frame(void *, size_t, ulwp_t *);
extern int setup_context(ucontext_t *, void *(*func)(ulwp_t *),
ulwp_t *ulwp, caddr_t stk, size_t stksize);
extern volatile sc_shared_t *setup_schedctl(void);
extern void *lmalloc(size_t);
extern void lfree(void *, size_t);
extern void *libc_malloc(size_t);
extern void *libc_realloc(void *, size_t);
extern void libc_free(void *);
extern char *libc_strdup(const char *);
extern void ultos(uint64_t, int, char *);
extern void lock_error(const mutex_t *, const char *, void *, const char *);
extern void rwlock_error(const rwlock_t *, const char *, const char *);
extern void thread_error(const char *);
extern void grab_assert_lock(void);
extern void dump_queue_statistics(void);
extern void collect_queue_statistics(void);
extern void record_spin_locks(ulwp_t *);
extern void remember_lock(mutex_t *);
extern void forget_lock(mutex_t *);
extern void register_lock(mutex_t *);
extern void unregister_locks(void);
#if defined(__sparc)
extern void _flush_windows(void);
#else
#define _flush_windows()
#endif
extern void set_curthread(void *);
/*
* Utility function used when waking up many threads (more than MAXLWPS)
* all at once. See mutex_wakeup_all(), cond_broadcast(), and rw_unlock().
*/
#define MAXLWPS 128 /* max remembered lwpids before overflow */
#define NEWLWPS 2048 /* max remembered lwpids at first overflow */
extern lwpid_t *alloc_lwpids(lwpid_t *, int *, int *);
/* enter a critical section */
#define enter_critical(self) (self->ul_critical++)
/* exit a critical section, take deferred actions if necessary */
extern void do_exit_critical(void);
#define exit_critical(self) \
(void) (self->ul_critical--, \
((self->ul_curplease && self->ul_critical == 0)? \
(do_exit_critical(), 0) : 0))
/*
* Like enter_critical()/exit_critical() but just for deferring signals.
* Unlike enter_critical()/exit_critical(), ul_sigdefer may be set while
* calling application functions like constructors and destructors.
* Care must be taken if the application function attempts to set
* the signal mask while a deferred signal is present; the setting
* of the signal mask must also be deferred.
*/
#define sigoff(self) (self->ul_sigdefer++)
#define sigon(self) \
(void) ((--self->ul_sigdefer == 0 && \
self->ul_curplease && self->ul_critical == 0)? \
(do_exit_critical(), 0) : 0)
/* these are exported functions */
extern void _sigoff(void);
extern void _sigon(void);
#define sigorset(s1, s2) \
(((s1)->__sigbits[0] |= (s2)->__sigbits[0]), \
((s1)->__sigbits[1] |= (s2)->__sigbits[1]), \
((s1)->__sigbits[2] |= (s2)->__sigbits[2]), \
((s1)->__sigbits[3] |= (s2)->__sigbits[3]))
#define sigandset(s1, s2) \
(((s1)->__sigbits[0] &= (s2)->__sigbits[0]), \
((s1)->__sigbits[1] &= (s2)->__sigbits[1]), \
((s1)->__sigbits[2] &= (s2)->__sigbits[2]), \
((s1)->__sigbits[3] &= (s2)->__sigbits[3]))
#define sigdiffset(s1, s2) \
(((s1)->__sigbits[0] &= ~(s2)->__sigbits[0]), \
((s1)->__sigbits[1] &= ~(s2)->__sigbits[1]), \
((s1)->__sigbits[2] &= ~(s2)->__sigbits[2]), \
((s1)->__sigbits[3] &= ~(s2)->__sigbits[3]))
#define delete_reserved_signals(s) \
(((s)->__sigbits[0] &= MASKSET0), \
((s)->__sigbits[1] &= (MASKSET1 & ~SIGMASK(SIGCANCEL))),\
((s)->__sigbits[2] &= MASKSET2), \
((s)->__sigbits[3] &= MASKSET3))
extern void block_all_signals(ulwp_t *self);
/*
* When restoring the signal mask after having previously called
* block_all_signals(), if we have a deferred signal present then
* do nothing other than ASSERT() that we are in a critical region.
* The signal mask will be set when we emerge from the critical region
* and call take_deferred_signal(). There is no race condition here
* because the kernel currently has all signals blocked for this thread.
*/
#define restore_signals(self) \
((void) ((self)->ul_cursig? \
(ASSERT((self)->ul_critical + (self)->ul_sigdefer != 0), 0) : \
__lwp_sigmask(SIG_SETMASK, &(self)->ul_sigmask)))
extern void set_cancel_pending_flag(ulwp_t *, int);
extern void set_cancel_eintr_flag(ulwp_t *);
extern void set_parking_flag(ulwp_t *, int);
extern int cancel_active(void);
extern void *_thrp_setup(ulwp_t *);
extern void _fpinherit(ulwp_t *);
extern void _lwp_start(void);
extern void _lwp_terminate(void);
extern void lmutex_lock(mutex_t *);
extern void lmutex_unlock(mutex_t *);
extern void lrw_rdlock(rwlock_t *);
extern void lrw_wrlock(rwlock_t *);
extern void lrw_unlock(rwlock_t *);
extern void sig_mutex_lock(mutex_t *);
extern void sig_mutex_unlock(mutex_t *);
extern int sig_mutex_trylock(mutex_t *);
extern int sig_cond_wait(cond_t *, mutex_t *);
extern int sig_cond_reltimedwait(cond_t *, mutex_t *, const timespec_t *);
extern void cancel_safe_mutex_lock(mutex_t *);
extern void cancel_safe_mutex_unlock(mutex_t *);
extern int cancel_safe_mutex_trylock(mutex_t *);
extern void _prefork_handler(void);
extern void _postfork_parent_handler(void);
extern void _postfork_child_handler(void);
extern void postfork1_child(void);
extern void postfork1_child_aio(void);
extern void postfork1_child_sigev_aio(void);
extern void postfork1_child_sigev_mq(void);
extern void postfork1_child_sigev_timer(void);
extern void postfork1_child_tpool(void);
extern void fork_lock_enter(void);
extern void fork_lock_exit(void);
extern void suspend_fork(void);
extern void continue_fork(int);
extern void do_sigcancel(void);
extern void setup_cancelsig(int);
extern void init_sigev_thread(void);
extern void init_aio(void);
extern void init_progname(void);
extern void _cancelon(void);
extern void _canceloff(void);
extern void _canceloff_nocancel(void);
extern void _cancel_prologue(void);
extern void _cancel_epilogue(void);
extern void no_preempt(ulwp_t *);
extern void preempt(ulwp_t *);
extern void _thrp_unwind(void *);
extern pid_t __forkx(int);
extern pid_t __forkallx(int);
extern int __open(const char *, int, mode_t);
extern int __open64(const char *, int, mode_t);
extern int __openat(int, const char *, int, mode_t);
extern int __openat64(int, const char *, int, mode_t);
extern int __close(int);
extern ssize_t __read(int, void *, size_t);
extern ssize_t __write(int, const void *, size_t);
extern int __fcntl(int, int, ...);
extern int __lwp_continue(lwpid_t);
extern int __lwp_create(ucontext_t *, uint_t, lwpid_t *);
extern int ___lwp_suspend(lwpid_t);
extern int lwp_wait(lwpid_t, lwpid_t *);
extern int __lwp_wait(lwpid_t, lwpid_t *);
extern int __lwp_detach(lwpid_t);
extern sc_shared_t *__schedctl(void);
/* actual system call traps */
extern int __setcontext(const ucontext_t *);
extern int __getcontext(ucontext_t *);
extern int __clock_gettime(clockid_t, timespec_t *);
extern void abstime_to_reltime(clockid_t, const timespec_t *, timespec_t *);
extern void hrt2ts(hrtime_t, timespec_t *);
extern int __sigaction(int, const struct sigaction *, struct sigaction *);
extern int __sigprocmask(int, const sigset_t *, sigset_t *);
extern int __lwp_sigmask(int, const sigset_t *);
extern void __sighndlr(int, siginfo_t *, ucontext_t *, void (*)());
extern caddr_t __sighndlrend;
#pragma unknown_control_flow(__sighndlr)
/* belongs in <pthread.h> */
#define PTHREAD_CREATE_DAEMON_NP 0x100 /* = THR_DAEMON */
#define PTHREAD_CREATE_NONDAEMON_NP 0
extern int pthread_attr_setdaemonstate_np(pthread_attr_t *, int);
extern int pthread_attr_getdaemonstate_np(const pthread_attr_t *, int *);
extern int mutex_held(mutex_t *);
extern int mutex_lock_internal(mutex_t *, timespec_t *, int);
extern int mutex_unlock_internal(mutex_t *, int);
/* not cancellation points: */
extern int __cond_wait(cond_t *, mutex_t *);
extern int __cond_timedwait(cond_t *, mutex_t *, const timespec_t *);
extern int __cond_reltimedwait(cond_t *, mutex_t *, const timespec_t *);
extern int rw_read_held(rwlock_t *);
extern int rw_write_held(rwlock_t *);
extern int _thrp_create(void *, size_t, void *(*)(void *), void *, long,
thread_t *, size_t, const char *);
extern int _thrp_suspend(thread_t, uchar_t);
extern int _thrp_continue(thread_t, uchar_t);
extern void _thrp_terminate(void *);
extern void _thrp_exit(void);
extern const pcclass_t *get_info_by_class(id_t);
extern const pcclass_t *get_info_by_policy(int);
extern const thrattr_t *def_thrattr(void);
extern id_t setparam(idtype_t, id_t, int, int);
extern id_t setprio(idtype_t, id_t, int, int *);
extern id_t getparam(idtype_t, id_t, int *, struct sched_param *);
/*
* System call wrappers (direct interfaces to the kernel)
*/
extern int ___lwp_mutex_register(mutex_t *, mutex_t **);
extern int ___lwp_mutex_trylock(mutex_t *, ulwp_t *);
extern int ___lwp_mutex_timedlock(mutex_t *, timespec_t *, ulwp_t *);
extern int ___lwp_mutex_unlock(mutex_t *);
extern int ___lwp_mutex_wakeup(mutex_t *, int);
extern int ___lwp_cond_wait(cond_t *, mutex_t *, timespec_t *, int);
extern int ___lwp_sema_timedwait(lwp_sema_t *, timespec_t *, int);
extern int __lwp_rwlock_rdlock(rwlock_t *, timespec_t *);
extern int __lwp_rwlock_wrlock(rwlock_t *, timespec_t *);
extern int __lwp_rwlock_tryrdlock(rwlock_t *);
extern int __lwp_rwlock_trywrlock(rwlock_t *);
extern int __lwp_rwlock_unlock(rwlock_t *);
extern int __lwp_park(timespec_t *, lwpid_t);
extern int __lwp_unpark(lwpid_t);
extern int __lwp_unpark_all(lwpid_t *, int);
#if defined(__x86)
extern int ___lwp_private(int, int, void *);
#endif /* __x86 */
/*
* inlines
*/
extern int set_lock_byte(volatile uint8_t *);
extern uint32_t atomic_swap_32(volatile uint32_t *, uint32_t);
extern uint32_t atomic_cas_32(volatile uint32_t *, uint32_t, uint32_t);
extern void atomic_inc_32(volatile uint32_t *);
extern void atomic_dec_32(volatile uint32_t *);
extern void atomic_and_32(volatile uint32_t *, uint32_t);
extern void atomic_or_32(volatile uint32_t *, uint32_t);
#if defined(__sparc)
extern ulong_t caller(void);
extern ulong_t getfp(void);
#endif /* __sparc */
#include "thr_inlines.h"
#endif /* _THR_UBERDATA_H */
|