+152
-91
Cargo.lock
+152
-91
Cargo.lock
···
8
8
source = "registry+https://github.com/rust-lang/crates.io-index"
9
9
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
10
10
dependencies = [
11
-
"hermit-abi",
11
+
"hermit-abi 0.1.19",
12
12
"libc",
13
13
"winapi",
14
14
]
···
35
35
"heck",
36
36
"indexmap",
37
37
"log",
38
-
"proc-macro2 1.0.51",
39
-
"quote 1.0.23",
38
+
"proc-macro2 1.0.56",
39
+
"quote 1.0.26",
40
40
"serde",
41
41
"serde_json",
42
42
"syn 1.0.109",
···
110
110
111
111
[[package]]
112
112
name = "errno"
113
-
version = "0.2.8"
113
+
version = "0.3.1"
114
114
source = "registry+https://github.com/rust-lang/crates.io-index"
115
-
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
115
+
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
116
116
dependencies = [
117
117
"errno-dragonfly",
118
118
"libc",
119
-
"winapi",
119
+
"windows-sys 0.48.0",
120
120
]
121
121
122
122
[[package]]
···
171
171
]
172
172
173
173
[[package]]
174
+
name = "hermit-abi"
175
+
version = "0.3.1"
176
+
source = "registry+https://github.com/rust-lang/crates.io-index"
177
+
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
178
+
179
+
[[package]]
174
180
name = "indexmap"
175
-
version = "1.9.2"
181
+
version = "1.9.3"
176
182
source = "registry+https://github.com/rust-lang/crates.io-index"
177
-
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
183
+
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
178
184
dependencies = [
179
185
"autocfg",
180
186
"hashbrown",
···
191
197
192
198
[[package]]
193
199
name = "io-lifetimes"
194
-
version = "1.0.6"
200
+
version = "1.0.10"
195
201
source = "registry+https://github.com/rust-lang/crates.io-index"
196
-
checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3"
202
+
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
197
203
dependencies = [
204
+
"hermit-abi 0.3.1",
198
205
"libc",
199
-
"windows-sys 0.45.0",
206
+
"windows-sys 0.48.0",
200
207
]
201
208
202
209
[[package]]
···
220
227
221
228
[[package]]
222
229
name = "libc"
223
-
version = "0.2.140"
230
+
version = "0.2.141"
224
231
source = "registry+https://github.com/rust-lang/crates.io-index"
225
-
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
232
+
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
226
233
227
234
[[package]]
228
235
name = "linux-raw-sys"
229
-
version = "0.1.4"
236
+
version = "0.3.1"
230
237
source = "registry+https://github.com/rust-lang/crates.io-index"
231
-
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
238
+
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
232
239
233
240
[[package]]
234
241
name = "lock_api"
···
275
282
276
283
[[package]]
277
284
name = "os_str_bytes"
278
-
version = "6.4.1"
285
+
version = "6.5.0"
279
286
source = "registry+https://github.com/rust-lang/crates.io-index"
280
-
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
287
+
checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
281
288
282
289
[[package]]
283
290
name = "plain"
···
300
307
301
308
[[package]]
302
309
name = "proc-macro2"
303
-
version = "1.0.51"
310
+
version = "1.0.56"
304
311
source = "registry+https://github.com/rust-lang/crates.io-index"
305
-
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
312
+
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
306
313
dependencies = [
307
314
"unicode-ident",
308
315
]
···
318
325
319
326
[[package]]
320
327
name = "quote"
321
-
version = "1.0.23"
328
+
version = "1.0.26"
322
329
source = "registry+https://github.com/rust-lang/crates.io-index"
323
-
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
330
+
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
324
331
dependencies = [
325
-
"proc-macro2 1.0.51",
332
+
"proc-macro2 1.0.56",
326
333
]
327
334
328
335
[[package]]
···
371
378
dependencies = [
372
379
"goblin",
373
380
"plain",
374
-
"redox_syscall 0.3.4",
381
+
"redox_syscall 0.3.5",
375
382
]
376
383
377
384
[[package]]
···
382
389
383
390
[[package]]
384
391
name = "redox_syscall"
385
-
version = "0.2.16"
386
-
source = "registry+https://github.com/rust-lang/crates.io-index"
387
-
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
388
-
dependencies = [
389
-
"bitflags",
390
-
]
391
-
392
-
[[package]]
393
-
name = "redox_syscall"
394
-
version = "0.3.4"
392
+
version = "0.3.5"
395
393
source = "registry+https://github.com/rust-lang/crates.io-index"
396
-
checksum = "fb02a9aee8e8c7ad8d86890f1e16b49e0bbbffc9961ff3788c31d57c98bcbf03"
394
+
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
397
395
dependencies = [
398
396
"bitflags",
399
397
]
···
402
400
name = "relibc"
403
401
version = "0.2.5"
404
402
dependencies = [
403
+
"bitflags",
405
404
"cbindgen",
406
405
"cbitset",
407
406
"cc",
···
415
414
"ralloc",
416
415
"rand",
417
416
"redox-exec",
418
-
"redox_syscall 0.3.4",
417
+
"redox_syscall 0.3.5",
419
418
"sc",
420
-
"spin 0.9.5",
419
+
"spin 0.9.8",
421
420
"unicode-width",
422
421
]
423
422
···
441
440
442
441
[[package]]
443
442
name = "rustix"
444
-
version = "0.36.9"
443
+
version = "0.37.11"
445
444
source = "registry+https://github.com/rust-lang/crates.io-index"
446
-
checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc"
445
+
checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
447
446
dependencies = [
448
447
"bitflags",
449
448
"errno",
450
449
"io-lifetimes",
451
450
"libc",
452
451
"linux-raw-sys",
453
-
"windows-sys 0.45.0",
452
+
"windows-sys 0.48.0",
454
453
]
455
454
456
455
[[package]]
···
515
514
516
515
[[package]]
517
516
name = "serde"
518
-
version = "1.0.154"
517
+
version = "1.0.160"
519
518
source = "registry+https://github.com/rust-lang/crates.io-index"
520
-
checksum = "8cdd151213925e7f1ab45a9bbfb129316bd00799784b174b7cc7bcd16961c49e"
519
+
checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
521
520
dependencies = [
522
521
"serde_derive",
523
522
]
524
523
525
524
[[package]]
526
525
name = "serde_derive"
527
-
version = "1.0.154"
526
+
version = "1.0.160"
528
527
source = "registry+https://github.com/rust-lang/crates.io-index"
529
-
checksum = "4fc80d722935453bcafdc2c9a73cd6fac4dc1938f0346035d84bf99fa9e33217"
528
+
checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
530
529
dependencies = [
531
-
"proc-macro2 1.0.51",
532
-
"quote 1.0.23",
533
-
"syn 1.0.109",
530
+
"proc-macro2 1.0.56",
531
+
"quote 1.0.26",
532
+
"syn 2.0.15",
534
533
]
535
534
536
535
[[package]]
537
536
name = "serde_json"
538
-
version = "1.0.94"
537
+
version = "1.0.96"
539
538
source = "registry+https://github.com/rust-lang/crates.io-index"
540
-
checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
539
+
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
541
540
dependencies = [
542
541
"itoa",
543
542
"ryu",
···
552
551
553
552
[[package]]
554
553
name = "spin"
555
-
version = "0.9.5"
554
+
version = "0.9.8"
556
555
source = "registry+https://github.com/rust-lang/crates.io-index"
557
-
checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc"
556
+
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
558
557
dependencies = [
559
558
"lock_api",
560
559
]
···
582
581
source = "registry+https://github.com/rust-lang/crates.io-index"
583
582
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
584
583
dependencies = [
585
-
"proc-macro2 1.0.51",
586
-
"quote 1.0.23",
584
+
"proc-macro2 1.0.56",
585
+
"quote 1.0.26",
586
+
"unicode-ident",
587
+
]
588
+
589
+
[[package]]
590
+
name = "syn"
591
+
version = "2.0.15"
592
+
source = "registry+https://github.com/rust-lang/crates.io-index"
593
+
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
594
+
dependencies = [
595
+
"proc-macro2 1.0.56",
596
+
"quote 1.0.26",
587
597
"unicode-ident",
588
598
]
589
599
590
600
[[package]]
591
601
name = "tempfile"
592
-
version = "3.4.0"
602
+
version = "3.5.0"
593
603
source = "registry+https://github.com/rust-lang/crates.io-index"
594
-
checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
604
+
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
595
605
dependencies = [
596
606
"cfg-if",
597
607
"fastrand",
598
-
"redox_syscall 0.2.16",
608
+
"redox_syscall 0.3.5",
599
609
"rustix",
600
-
"windows-sys 0.42.0",
610
+
"windows-sys 0.45.0",
601
611
]
602
612
603
613
[[package]]
···
681
691
682
692
[[package]]
683
693
name = "windows-sys"
684
-
version = "0.42.0"
694
+
version = "0.45.0"
685
695
source = "registry+https://github.com/rust-lang/crates.io-index"
686
-
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
696
+
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
687
697
dependencies = [
688
-
"windows_aarch64_gnullvm",
689
-
"windows_aarch64_msvc",
690
-
"windows_i686_gnu",
691
-
"windows_i686_msvc",
692
-
"windows_x86_64_gnu",
693
-
"windows_x86_64_gnullvm",
694
-
"windows_x86_64_msvc",
698
+
"windows-targets 0.42.2",
695
699
]
696
700
697
701
[[package]]
698
702
name = "windows-sys"
699
-
version = "0.45.0"
703
+
version = "0.48.0"
704
+
source = "registry+https://github.com/rust-lang/crates.io-index"
705
+
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
706
+
dependencies = [
707
+
"windows-targets 0.48.0",
708
+
]
709
+
710
+
[[package]]
711
+
name = "windows-targets"
712
+
version = "0.42.2"
700
713
source = "registry+https://github.com/rust-lang/crates.io-index"
701
-
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
714
+
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
702
715
dependencies = [
703
-
"windows-targets",
716
+
"windows_aarch64_gnullvm 0.42.2",
717
+
"windows_aarch64_msvc 0.42.2",
718
+
"windows_i686_gnu 0.42.2",
719
+
"windows_i686_msvc 0.42.2",
720
+
"windows_x86_64_gnu 0.42.2",
721
+
"windows_x86_64_gnullvm 0.42.2",
722
+
"windows_x86_64_msvc 0.42.2",
704
723
]
705
724
706
725
[[package]]
707
726
name = "windows-targets"
708
-
version = "0.42.1"
727
+
version = "0.48.0"
709
728
source = "registry+https://github.com/rust-lang/crates.io-index"
710
-
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
729
+
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
711
730
dependencies = [
712
-
"windows_aarch64_gnullvm",
713
-
"windows_aarch64_msvc",
714
-
"windows_i686_gnu",
715
-
"windows_i686_msvc",
716
-
"windows_x86_64_gnu",
717
-
"windows_x86_64_gnullvm",
718
-
"windows_x86_64_msvc",
731
+
"windows_aarch64_gnullvm 0.48.0",
732
+
"windows_aarch64_msvc 0.48.0",
733
+
"windows_i686_gnu 0.48.0",
734
+
"windows_i686_msvc 0.48.0",
735
+
"windows_x86_64_gnu 0.48.0",
736
+
"windows_x86_64_gnullvm 0.48.0",
737
+
"windows_x86_64_msvc 0.48.0",
719
738
]
720
739
721
740
[[package]]
722
741
name = "windows_aarch64_gnullvm"
723
-
version = "0.42.1"
742
+
version = "0.42.2"
743
+
source = "registry+https://github.com/rust-lang/crates.io-index"
744
+
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
745
+
746
+
[[package]]
747
+
name = "windows_aarch64_gnullvm"
748
+
version = "0.48.0"
749
+
source = "registry+https://github.com/rust-lang/crates.io-index"
750
+
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
751
+
752
+
[[package]]
753
+
name = "windows_aarch64_msvc"
754
+
version = "0.42.2"
724
755
source = "registry+https://github.com/rust-lang/crates.io-index"
725
-
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
756
+
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
726
757
727
758
[[package]]
728
759
name = "windows_aarch64_msvc"
729
-
version = "0.42.1"
760
+
version = "0.48.0"
730
761
source = "registry+https://github.com/rust-lang/crates.io-index"
731
-
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
762
+
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
732
763
733
764
[[package]]
734
765
name = "windows_i686_gnu"
735
-
version = "0.42.1"
766
+
version = "0.42.2"
736
767
source = "registry+https://github.com/rust-lang/crates.io-index"
737
-
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
768
+
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
769
+
770
+
[[package]]
771
+
name = "windows_i686_gnu"
772
+
version = "0.48.0"
773
+
source = "registry+https://github.com/rust-lang/crates.io-index"
774
+
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
738
775
739
776
[[package]]
740
777
name = "windows_i686_msvc"
741
-
version = "0.42.1"
778
+
version = "0.42.2"
779
+
source = "registry+https://github.com/rust-lang/crates.io-index"
780
+
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
781
+
782
+
[[package]]
783
+
name = "windows_i686_msvc"
784
+
version = "0.48.0"
742
785
source = "registry+https://github.com/rust-lang/crates.io-index"
743
-
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
786
+
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
744
787
745
788
[[package]]
746
789
name = "windows_x86_64_gnu"
747
-
version = "0.42.1"
790
+
version = "0.42.2"
791
+
source = "registry+https://github.com/rust-lang/crates.io-index"
792
+
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
793
+
794
+
[[package]]
795
+
name = "windows_x86_64_gnu"
796
+
version = "0.48.0"
748
797
source = "registry+https://github.com/rust-lang/crates.io-index"
749
-
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
798
+
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
750
799
751
800
[[package]]
752
801
name = "windows_x86_64_gnullvm"
753
-
version = "0.42.1"
802
+
version = "0.42.2"
754
803
source = "registry+https://github.com/rust-lang/crates.io-index"
755
-
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
804
+
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
805
+
806
+
[[package]]
807
+
name = "windows_x86_64_gnullvm"
808
+
version = "0.48.0"
809
+
source = "registry+https://github.com/rust-lang/crates.io-index"
810
+
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
756
811
757
812
[[package]]
758
813
name = "windows_x86_64_msvc"
759
-
version = "0.42.1"
814
+
version = "0.42.2"
815
+
source = "registry+https://github.com/rust-lang/crates.io-index"
816
+
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
817
+
818
+
[[package]]
819
+
name = "windows_x86_64_msvc"
820
+
version = "0.48.0"
760
821
source = "registry+https://github.com/rust-lang/crates.io-index"
761
-
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
822
+
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+2
Cargo.toml
+2
Cargo.toml
···
15
15
[build-dependencies]
16
16
cbindgen = "0.24.3"
17
17
cc = "1.0.25"
18
+
#env_logger = "0.10"
18
19
19
20
[dependencies]
21
+
bitflags = "1"
20
22
cbitset = "0.1.0"
21
23
core_io = { path = "core_io", features = ["collections"] }
22
24
lazy_static = { version = "1.4.0", default-features = false, features = ["spin_no_std"] }
+37
src/header/bits_pthread/cbindgen.toml
+37
src/header/bits_pthread/cbindgen.toml
···
1
+
sys_includes = ["bits/sched.h"]
2
+
include_guard = "_RELIBC_BITS_PTHREAD_H"
3
+
language = "C"
4
+
style = "type"
5
+
no_includes = true
6
+
cpp_compat = true
7
+
trailer = """
8
+
#define PTHREAD_COND_INITIALIZER {0}
9
+
#define PTHREAD_MUTEX_INITIALIZER {0}
10
+
#define PTHREAD_ONCE_INIT {0}
11
+
#define PTHREAD_RWLOCK_INITIALIZER {0}
12
+
"""
13
+
14
+
[export.rename]
15
+
"sched_param" = "struct sched_param"
16
+
"AtomicInt" = "int"
17
+
"AtomicUint" = "unsigned"
18
+
19
+
[export]
20
+
include = [
21
+
"pthread_attr_t",
22
+
"pthread_rwlockattr_t",
23
+
"pthread_rwlock_t",
24
+
"pthread_barrier_t",
25
+
"pthread_barrierattr_t",
26
+
"pthread_mutex_t",
27
+
"pthread_mutexattr_t",
28
+
"pthread_condattr_t",
29
+
"pthread_cond_t",
30
+
"pthread_spinlock_t",
31
+
"pthread_once_t",
32
+
"pthread_t",
33
+
"pthread_key_t",
34
+
]
35
+
36
+
[enum]
37
+
prefix_with_name = true
+81
src/header/bits_pthread/mod.rs
+81
src/header/bits_pthread/mod.rs
···
1
+
#![allow(non_camel_case_types)]
2
+
3
+
use crate::platform::types::*;
4
+
5
+
use crate::header::sched::sched_param;
6
+
7
+
use crate::sync::AtomicLock;
8
+
use core::sync::atomic::{AtomicU32 as AtomicUint, AtomicI32 as AtomicInt};
9
+
10
+
#[repr(C)]
11
+
#[derive(Clone, Copy)]
12
+
pub struct pthread_attr_t {
13
+
pub detachstate: c_uchar,
14
+
pub inheritsched: c_uchar,
15
+
pub schedpolicy: c_uchar,
16
+
pub scope: c_uchar,
17
+
pub guardsize: size_t,
18
+
pub stacksize: size_t,
19
+
pub stack: size_t,
20
+
pub param: sched_param,
21
+
}
22
+
23
+
#[repr(C)]
24
+
pub struct pthread_rwlockattr_t {
25
+
pub pshared: c_int,
26
+
}
27
+
28
+
#[repr(C)]
29
+
pub struct pthread_rwlock_t {
30
+
pub state: AtomicInt,
31
+
}
32
+
33
+
#[repr(C)]
34
+
pub struct pthread_barrier_t {
35
+
pub count: AtomicUint,
36
+
pub original_count: c_uint,
37
+
pub epoch: AtomicInt,
38
+
}
39
+
40
+
#[repr(C)]
41
+
pub struct pthread_barrierattr_t {
42
+
pub pshared: c_int,
43
+
}
44
+
45
+
#[repr(C)]
46
+
pub struct pthread_mutex_t {
47
+
pub inner: AtomicInt,
48
+
}
49
+
50
+
#[repr(C)]
51
+
pub struct pthread_mutexattr_t {
52
+
pub prioceiling: c_int,
53
+
pub protocol: c_int,
54
+
pub pshared: c_int,
55
+
pub robust: c_int,
56
+
pub ty: c_int,
57
+
}
58
+
59
+
#[repr(C)]
60
+
pub struct pthread_condattr_t {
61
+
pub clock: clockid_t,
62
+
pub pshared: c_int,
63
+
}
64
+
65
+
#[repr(C)]
66
+
pub struct pthread_cond_t {
67
+
pub cur: AtomicInt,
68
+
pub prev: AtomicInt,
69
+
}
70
+
#[repr(C)]
71
+
pub struct pthread_spinlock_t {
72
+
pub inner: AtomicInt,
73
+
}
74
+
75
+
#[repr(C)]
76
+
pub struct pthread_once_t {
77
+
pub inner: AtomicInt,
78
+
}
79
+
80
+
pub type pthread_t = *mut ();
81
+
pub type pthread_key_t = c_ulong;
+11
src/header/bits_sched/cbindgen.toml
+11
src/header/bits_sched/cbindgen.toml
+9
src/header/bits_sched/mod.rs
+9
src/header/bits_sched/mod.rs
+2
src/header/mod.rs
+2
src/header/mod.rs
+1
-1
src/header/netdb/dns/mod.rs
+1
-1
src/header/netdb/dns/mod.rs
+4
-14
src/header/pthread/attr.rs
+4
-14
src/header/pthread/attr.rs
···
1
1
use super::*;
2
2
3
-
#[repr(C)]
4
-
#[derive(Clone, Copy)]
5
-
pub struct Attr {
6
-
pub detachstate: u8,
7
-
pub inheritsched: u8,
8
-
pub schedpolicy: u8,
9
-
pub scope: u8,
10
-
pub guardsize: usize,
11
-
pub stacksize: usize,
12
-
pub stack: usize,
13
-
pub param: sched_param,
14
-
}
15
-
impl Default for Attr {
3
+
use crate::header::bits_pthread::pthread_attr_t;
4
+
5
+
impl Default for pthread_attr_t {
16
6
fn default() -> Self {
17
7
Self {
18
8
// Default according to POSIX.
···
93
83
94
84
#[no_mangle]
95
85
pub unsafe extern "C" fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int {
96
-
core::ptr::write(attr, Attr::default());
86
+
core::ptr::write(attr, pthread_attr_t::default());
97
87
0
98
88
}
99
89
+4
-17
src/header/pthread/barrier.rs
+4
-17
src/header/pthread/barrier.rs
···
1
1
use crate::header::errno::*;
2
2
3
-
use crate::sync::AtomicLock;
4
-
use core::sync::atomic::{AtomicU32, Ordering};
3
+
use core::sync::atomic::{AtomicU32, AtomicI32 as AtomicInt, Ordering};
5
4
6
5
use super::*;
7
6
8
-
#[repr(C)]
9
-
pub struct Barrier {
10
-
count: AtomicU32,
11
-
original_count: u32,
12
-
epoch: AtomicLock,
13
-
}
14
-
15
-
#[repr(C)]
16
-
pub struct BarrierAttr {
17
-
pshared: c_int,
18
-
}
19
-
20
7
#[no_mangle]
21
8
pub unsafe extern "C" fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int {
22
9
// Behavior is undefined if any thread is currently waiting.
···
29
16
return EINVAL;
30
17
}
31
18
32
-
core::ptr::write(barrier, Barrier {
19
+
core::ptr::write(barrier, pthread_barrier_t {
33
20
count: AtomicU32::new(0),
34
21
original_count: count,
35
-
epoch: AtomicLock::new(0),
22
+
epoch: AtomicInt::new(0),
36
23
});
37
24
0
38
25
}
···
73
60
#[no_mangle]
74
61
pub unsafe extern "C" fn pthread_barrierattr_init(attr: *mut pthread_barrierattr_t) -> c_int {
75
62
// PTHREAD_PROCESS_PRIVATE is default according to POSIX.
76
-
core::ptr::write(attr, BarrierAttr { pshared: PTHREAD_PROCESS_PRIVATE });
63
+
core::ptr::write(attr, pthread_barrierattr_t { pshared: PTHREAD_PROCESS_PRIVATE });
77
64
78
65
0
79
66
}
+6
-2
src/header/pthread/cbindgen.toml
+6
-2
src/header/pthread/cbindgen.toml
···
1
-
sys_includes = ["sched.h", "time.h"]
1
+
sys_includes = ["sched.h", "time.h", "bits/pthread.h"]
2
2
include_guard = "_RELIBC_PTHREAD_H"
3
3
language = "C"
4
-
style = "Tag"
4
+
style = "tag"
5
5
no_includes = true
6
6
cpp_compat = true
7
+
8
+
[export.rename]
9
+
"sched_param" = "struct sched_param"
10
+
"timespec" = "struct timespec"
7
11
8
12
[enum]
9
13
prefix_with_name = true
+6
-19
src/header/pthread/cond.rs
+6
-19
src/header/pthread/cond.rs
···
6
6
7
7
// PTHREAD_COND_INITIALIZER
8
8
9
-
#[repr(C)]
10
-
pub struct CondAttr {
11
-
clock: clockid_t,
12
-
pshared: c_int,
13
-
}
14
-
15
-
#[repr(C)]
16
-
pub struct Cond {
17
-
cur: AtomicInt,
18
-
prev: AtomicInt,
19
-
}
20
-
21
9
#[no_mangle]
22
10
pub unsafe extern "C" fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_int {
23
11
wake(cond, i32::MAX)
···
43
31
44
32
#[no_mangle]
45
33
pub unsafe extern "C" fn pthread_cond_init(cond: *mut pthread_cond_t, _attr: *const pthread_condattr_t) -> c_int {
46
-
cond.write(Cond {
34
+
cond.write(pthread_cond_t {
47
35
cur: AtomicInt::new(0),
48
36
prev: AtomicInt::new(0),
49
37
});
···
56
44
}
57
45
58
46
#[no_mangle]
59
-
pub unsafe extern "C" fn pthread_cond_timedwait(cond: *mut pthread_cond_t, mutex_ptr: *const pthread_mutex_t, timeout: *const timespec) -> c_int {
47
+
pub unsafe extern "C" fn pthread_cond_timedwait(cond: *mut pthread_cond_t, mutex_ptr: *mut pthread_mutex_t, timeout: *const timespec) -> c_int {
60
48
// TODO: Error checking for certain types (i.e. robust and errorcheck) of mutexes, e.g. if the
61
49
// mutex is not locked.
62
50
let cond: &pthread_cond_t = &*cond;
63
-
let mutex: &pthread_mutex_t = &*mutex_ptr;
64
51
let timeout: Option<×pec> = timeout.as_ref();
65
52
66
53
let current = cond.cur.load(Ordering::Relaxed);
67
54
cond.prev.store(current, Ordering::SeqCst);
68
55
69
-
mutex.inner.manual_unlock();
56
+
pthread_mutex_unlock(mutex_ptr);
70
57
crate::sync::futex_wait(&cond.cur, current, timeout);
71
-
mutex.inner.manual_lock();
58
+
pthread_mutex_lock(mutex_ptr);
72
59
73
60
0
74
61
}
75
62
76
63
#[no_mangle]
77
-
pub unsafe extern "C" fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *const pthread_mutex_t) -> c_int {
64
+
pub unsafe extern "C" fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *mut pthread_mutex_t) -> c_int {
78
65
pthread_cond_timedwait(cond, mutex, core::ptr::null())
79
66
}
80
67
···
97
84
98
85
#[no_mangle]
99
86
pub unsafe extern "C" fn pthread_condattr_init(condattr: *mut pthread_condattr_t) -> c_int {
100
-
core::ptr::write(condattr, CondAttr {
87
+
core::ptr::write(condattr, pthread_condattr_t {
101
88
// FIXME: system clock
102
89
clock: 0,
103
90
// Default
+1
src/header/pthread/mod.rs
+1
src/header/pthread/mod.rs
+9
-22
src/header/pthread/mutex.rs
+9
-22
src/header/pthread/mutex.rs
···
4
4
5
5
// PTHREAD_MUTEX_INITIALIZER
6
6
7
-
#[repr(C)]
8
-
pub struct Mutex {
9
-
pub(crate) inner: crate::sync::Mutex<()>,
10
-
}
11
-
12
-
#[repr(C)]
13
-
pub struct MutexAttr {
14
-
prioceiling: c_int,
15
-
protocol: c_int,
16
-
pshared: c_int,
17
-
robust: c_int,
18
-
ty: c_int,
19
-
}
20
-
21
7
// #[no_mangle]
22
8
pub extern "C" fn pthread_mutex_consistent(mutex: *mut pthread_mutex_t) -> c_int {
23
9
todo!();
···
36
22
#[no_mangle]
37
23
pub unsafe extern "C" fn pthread_mutex_init(mutex: *mut pthread_mutex_t, _attr: *const pthread_mutexattr_t) -> c_int {
38
24
// TODO: attr
39
-
mutex.write(Mutex {
40
-
inner: crate::sync::Mutex::new(()),
25
+
mutex.write(pthread_mutex_t {
26
+
inner: crate::sync::mutex::UNLOCKED.into(),
41
27
});
42
28
0
43
29
}
44
30
#[no_mangle]
45
31
pub unsafe extern "C" fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int {
46
-
(&*mutex).inner.manual_lock();
32
+
crate::sync::mutex::manual_lock_generic(&(&*mutex).inner);
47
33
48
34
0
49
35
}
···
59
45
}
60
46
#[no_mangle]
61
47
pub unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> c_int {
62
-
match (&*mutex).inner.manual_try_lock() {
63
-
Ok(_) => 0,
64
-
Err(_) => EBUSY,
48
+
if crate::sync::mutex::manual_try_lock_generic(&(&*mutex).inner) {
49
+
0
50
+
} else {
51
+
EBUSY
65
52
}
66
53
}
67
54
#[no_mangle]
68
55
pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int {
69
-
(&*mutex).inner.manual_unlock();
56
+
crate::sync::mutex::manual_unlock_generic(&(&*mutex).inner);
70
57
0
71
58
}
72
59
···
105
92
}
106
93
#[no_mangle]
107
94
pub unsafe extern "C" fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int {
108
-
attr.write(MutexAttr {
95
+
attr.write(pthread_mutexattr_t {
109
96
robust: PTHREAD_MUTEX_STALLED,
110
97
pshared: PTHREAD_PROCESS_PRIVATE,
111
98
protocol: PTHREAD_PRIO_NONE,
+1
-6
src/header/pthread/once.rs
+1
-6
src/header/pthread/once.rs
···
1
1
use super::*;
2
2
3
-
#[repr(C)]
4
-
pub struct Once {
5
-
inner: crate::sync::Once<()>,
6
-
}
7
-
8
3
// PTHREAD_ONCE_INIT
9
4
10
5
#[no_mangle]
···
12
7
let once: &pthread_once_t = &*once;
13
8
14
9
// TODO: Cancellation points
15
-
once.inner.call_once(|| constructor());
10
+
crate::sync::once::call_once_generic(&once.inner, || constructor());
16
11
17
12
0
18
13
}
+17
-19
src/header/pthread/rwlock.rs
+17
-19
src/header/pthread/rwlock.rs
···
1
1
use super::*;
2
2
3
-
use crate::sync::AtomicLock;
4
-
use core::sync::atomic::Ordering;
3
+
use core::sync::atomic::{AtomicI32 as AtomicInt, Ordering};
5
4
6
5
use crate::header::errno::EBUSY;
7
6
···
15
14
// Separate "waiting for wrlocks" and "waiting for rdlocks"?
16
15
//const WAITING: u32 = 1 << (u32::BITS - 1);
17
16
18
-
#[repr(C)]
19
-
pub struct Rwlock {
20
-
state: AtomicLock,
21
-
}
22
-
23
-
#[repr(C)]
24
-
pub struct RwlockAttr {
25
-
pshared: c_int,
26
-
}
27
-
28
17
#[no_mangle]
29
18
pub unsafe extern "C" fn pthread_rwlock_destroy(rwlock: *mut pthread_rwlock_t) -> c_int {
30
19
// (Informing the compiler that this pointer is valid, might improve optimizations.)
···
33
22
}
34
23
#[no_mangle]
35
24
pub unsafe extern "C" fn pthread_rwlock_init(rwlock: *mut pthread_rwlock_t, _attr: *const pthread_rwlockattr_t) -> c_int {
36
-
core::ptr::write(rwlock, Rwlock {
37
-
state: AtomicLock::new(0),
25
+
core::ptr::write(rwlock, pthread_rwlock_t {
26
+
state: AtomicInt::new(0),
38
27
});
39
28
40
29
0
···
50
39
51
40
loop {
52
41
if pthread_rwlock_tryrdlock(rwlock as *const _ as *mut _) == EBUSY {
53
-
rwlock.state.wait_if(EXCLUSIVE as i32, timeout);
42
+
crate::sync::futex_wait(&rwlock.state, EXCLUSIVE as i32, timeout);
54
43
}
55
44
return 0;
56
45
}
···
60
49
let rwlock: &pthread_rwlock_t = &*rwlock;
61
50
let timeout = timeout.as_ref();
62
51
63
-
loop {
52
+
/*loop {
64
53
if pthread_rwlock_trywrlock(rwlock as *const _ as *mut _) == EBUSY {
65
-
rwlock.state.wait_if(EXCLUSIVE as i32, timeout);
54
+
crate::sync::futex_wait(&rwlock.state, EXCLUSIVE as i32, timeout);
66
55
}
67
56
return 0;
57
+
}*/
58
+
loop {
59
+
match rwlock.state.compare_exchange(0, EXCLUSIVE as i32, Ordering::Acquire, Ordering::Relaxed) {
60
+
Ok(_) => return 0,
61
+
Err(value) => {
62
+
// TODO: More than just forwarding the timeout.
63
+
crate::sync::futex_wait(&rwlock.state, value, timeout);
64
+
}
65
+
}
68
66
}
69
67
}
70
68
#[no_mangle]
···
105
103
let old = rwlock.state.swap(0, Ordering::Release) as u32;
106
104
107
105
if old == EXCLUSIVE {
108
-
rwlock.state.notify_all();
106
+
crate::sync::futex_wake(&rwlock.state, i32::MAX);
109
107
}
110
108
111
109
0
···
129
127
130
128
#[no_mangle]
131
129
pub unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> c_int {
132
-
core::ptr::write(attr, RwlockAttr {
130
+
core::ptr::write(attr, pthread_rwlockattr_t {
133
131
// Default according to POSIX.
134
132
pshared: PTHREAD_PROCESS_PRIVATE,
135
133
});
+4
-9
src/header/pthread/spin.rs
+4
-9
src/header/pthread/spin.rs
···
4
4
5
5
use super::*;
6
6
7
-
#[repr(C)]
8
-
pub struct Spinlock {
9
-
inner: AtomicInt,
10
-
}
11
-
12
7
pub const UNLOCKED: c_int = 0;
13
8
pub const LOCKED: c_int = 1;
14
9
···
19
14
// TODO: pshared doesn't matter in most situations, as memory is just memory, but this may be
20
15
// different on some architectures...
21
16
22
-
core::ptr::write(spinlock, Spinlock { inner: AtomicInt::new(UNLOCKED) });
17
+
core::ptr::write(spinlock, pthread_spinlock_t { inner: AtomicInt::new(UNLOCKED) });
23
18
24
19
0
25
20
}
26
21
pub unsafe extern "C" fn pthread_spin_lock(spinlock: *mut pthread_spinlock_t) -> c_int {
27
-
let spinlock: &Spinlock = &*spinlock;
22
+
let spinlock: &pthread_spinlock_t = &*spinlock;
28
23
29
24
loop {
30
25
match spinlock.inner.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed) {
···
34
29
}
35
30
}
36
31
pub unsafe extern "C" fn pthread_spin_trylock(spinlock: *mut pthread_spinlock_t) -> c_int {
37
-
let spinlock: &Spinlock = &*spinlock;
32
+
let spinlock: &pthread_spinlock_t = &*spinlock;
38
33
39
34
match spinlock.inner.compare_exchange(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed) {
40
35
Ok(_) => 0,
···
42
37
}
43
38
}
44
39
pub unsafe extern "C" fn pthread_spin_unlock(spinlock: *mut pthread_spinlock_t) -> c_int {
45
-
let spinlock: &Spinlock = &*spinlock;
40
+
let spinlock: &pthread_spinlock_t = &*spinlock;
46
41
47
42
spinlock.inner.store(UNLOCKED, Ordering::Release);
48
43
+34
-11
src/header/pthread/tls.rs
+34
-11
src/header/pthread/tls.rs
···
6
6
use core::cell::{Cell, RefCell};
7
7
8
8
use crate::header::errno::EINVAL;
9
+
use crate::sync::Mutex;
9
10
10
11
// TODO: What should this limit be?
11
12
pub const PTHREAD_KEYS_MAX: u32 = 4096 * 32;
12
13
13
14
#[no_mangle]
14
15
pub unsafe extern "C" fn pthread_getspecific(key: pthread_key_t) -> *mut c_void {
15
-
let Some(&Record { data, .. }) = DICT.borrow_mut().get(&key) else {
16
+
//print!("pthread_getspecific key={:#0x}: ", key);
17
+
18
+
// TODO: Right?
19
+
if !KEYS.lock().contains_key(&key) {
20
+
//println!("= not found");
21
+
return core::ptr::null_mut();
22
+
}
23
+
24
+
let Some(&Record { data, .. }) = VALUES.borrow_mut().get(&key) else {
25
+
//println!("= NULL");
16
26
return core::ptr::null_mut();
17
27
};
28
+
//println!("= {:p}", data);
18
29
19
30
data
20
31
}
···
22
33
pub unsafe extern "C" fn pthread_key_create(key_ptr: *mut pthread_key_t, destructor: extern "C" fn(value: *mut c_void)) -> c_int {
23
34
let key = NEXTKEY.get();
24
35
NEXTKEY.set(key + 1);
36
+
//println!("pthread_key_create new key {:#0x}, dtor {:p}", key, destructor);
25
37
26
38
// TODO
27
39
//if key >= PTHREAD_KEYS_MAX {
28
40
//}
29
41
30
-
DICT.borrow_mut().insert(key, Record {
42
+
KEYS.lock().insert(key, Dtor { destructor });
43
+
44
+
VALUES.borrow_mut().insert(key, Record {
31
45
data: core::ptr::null_mut(),
32
-
destructor,
33
46
});
34
47
35
48
key_ptr.write(key);
···
39
52
40
53
#[no_mangle]
41
54
pub unsafe extern "C" fn pthread_key_delete(key: pthread_key_t) -> c_int {
42
-
if DICT.borrow_mut().remove(&key).is_none() {
55
+
if KEYS.lock().remove(&key).is_none() || VALUES.borrow_mut().remove(&key).is_none() {
43
56
// We don't have to return anything, but it's not less expensive to ignore it.
44
57
return EINVAL;
45
58
}
59
+
//println!("pthread_key_delete {:#0x}", key);
46
60
47
61
0
48
62
}
49
63
50
64
#[no_mangle]
51
65
pub unsafe extern "C" fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int {
52
-
let mut guard = DICT.borrow_mut();
53
-
54
-
let Some(Record { data, .. }) = guard.get_mut(&key) else {
66
+
if !KEYS.lock().contains_key(&key) {
55
67
// We don't have to return anything, but it's not less expensive to ignore it.
68
+
//println!("Invalid key for pthread_setspecific key {:#0x} value {:p}", key, value);
56
69
return EINVAL;
57
-
};
70
+
}
71
+
72
+
let mut guard = VALUES.borrow_mut();
73
+
74
+
let Record { ref mut data, .. } = guard.entry(key).or_insert(Record { data: core::ptr::null_mut() });
75
+
//println!("Valid key for pthread_setspecific key {:#0x} value {:p} (was {:p})", key, value, *data);
58
76
59
77
*data = value as *mut c_void;
60
78
61
79
0
62
80
}
63
81
82
+
static KEYS: Mutex<BTreeMap<pthread_key_t, Dtor>> = Mutex::new(BTreeMap::new());
83
+
84
+
struct Dtor {
85
+
destructor: extern "C" fn(value: *mut c_void)
86
+
}
87
+
64
88
#[thread_local]
65
-
static DICT: RefCell<BTreeMap<u32, Record>> = RefCell::new(BTreeMap::new());
89
+
static VALUES: RefCell<BTreeMap<pthread_key_t, Record>> = RefCell::new(BTreeMap::new());
66
90
67
91
struct Record {
68
92
data: *mut c_void,
69
-
destructor: extern "C" fn(value: *mut c_void),
70
93
}
71
94
72
95
#[thread_local]
73
-
static NEXTKEY: Cell<u32> = Cell::new(1);
96
+
static NEXTKEY: Cell<pthread_key_t> = Cell::new(1);
+1
-1
src/header/sched/cbindgen.toml
+1
-1
src/header/sched/cbindgen.toml
+1
-5
src/header/sched/mod.rs
+1
-5
src/header/sched/mod.rs
···
3
3
use crate::platform::{Pal, Sys, types::*};
4
4
use crate::header::time::timespec;
5
5
6
-
#[repr(C)]
7
-
#[derive(Clone, Copy, Debug)]
8
-
pub struct sched_param {
9
-
pub sched_priority: c_int,
10
-
}
6
+
pub use crate::header::bits_sched::sched_param;
11
7
12
8
pub const SCHED_FIFO: c_int = 0;
13
9
pub const SCHED_RR: c_int = 1;
+1
-2
src/header/stdlib/mod.rs
+1
-2
src/header/stdlib/mod.rs
···
275
275
static __fini_array_start: extern "C" fn();
276
276
static __fini_array_end: extern "C" fn();
277
277
278
-
fn pthread_terminate();
279
278
fn _fini();
280
279
}
281
280
···
297
296
298
297
ld_so::fini();
299
298
300
-
pthread_terminate();
299
+
crate::pthread::terminate_from_main_thread();
301
300
302
301
flush_io_streams();
303
302
+2
-1
src/header/sys_types/cbindgen.toml
+2
-1
src/header/sys_types/cbindgen.toml
+15
-15
src/platform/redox/clone.rs
+15
-15
src/platform/redox/clone.rs
···
14
14
pub use redox_exec::*;
15
15
16
16
/// Spawns a new context sharing the same address space as the current one (i.e. a new thread).
17
-
pub unsafe fn pte_clone_impl(stack: *mut usize) -> Result<usize> {
17
+
pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result<usize> {
18
18
let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?);
19
19
let (new_pid_fd, new_pid) = new_context()?;
20
20
···
47
47
48
48
let buf = create_set_addr_space_buf(
49
49
*cur_addr_space_fd,
50
-
__relibc_internal_pte_clone_ret as usize,
50
+
__relibc_internal_rlct_clone_ret as usize,
51
51
stack as usize,
52
52
);
53
53
let _ = syscall::write(*new_addr_space_sel_fd, &buf)?;
···
86
86
}
87
87
88
88
extern "C" {
89
-
fn __relibc_internal_pte_clone_ret();
89
+
fn __relibc_internal_rlct_clone_ret();
90
90
}
91
91
92
92
#[cfg(target_arch = "aarch64")]
93
93
core::arch::global_asm!(
94
94
"
95
-
.globl __relibc_internal_pte_clone_ret
96
-
.type __relibc_internal_pte_clone_ret, @function
95
+
.globl __relibc_internal_rlct_clone_ret
96
+
.type __relibc_internal_rlct_clone_ret, @function
97
97
.p2align 6
98
-
__relibc_internal_pte_clone_ret:
98
+
__relibc_internal_rlct_clone_ret:
99
99
# Load registers
100
100
ldr x8, [sp], #8
101
101
ldr x0, [sp], #8
···
109
109
blr x8
110
110
111
111
ret
112
-
.size __relibc_internal_pte_clone_ret, . - __relibc_internal_pte_clone_ret
112
+
.size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret
113
113
"
114
114
);
115
115
116
116
#[cfg(target_arch = "x86")]
117
117
core::arch::global_asm!(
118
118
"
119
-
.globl __relibc_internal_pte_clone_ret
120
-
.type __relibc_internal_pte_clone_ret, @function
119
+
.globl __relibc_internal_rlct_clone_ret
120
+
.type __relibc_internal_rlct_clone_ret, @function
121
121
.p2align 6
122
-
__relibc_internal_pte_clone_ret:
122
+
__relibc_internal_rlct_clone_ret:
123
123
# Load registers
124
124
pop eax
125
125
···
136
136
call eax
137
137
138
138
ret
139
-
.size __relibc_internal_pte_clone_ret, . - __relibc_internal_pte_clone_ret
139
+
.size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret
140
140
"
141
141
);
142
142
143
143
#[cfg(target_arch = "x86_64")]
144
144
core::arch::global_asm!(
145
145
"
146
-
.globl __relibc_internal_pte_clone_ret
147
-
.type __relibc_internal_pte_clone_ret, @function
146
+
.globl __relibc_internal_rlct_clone_ret
147
+
.type __relibc_internal_rlct_clone_ret, @function
148
148
.p2align 6
149
-
__relibc_internal_pte_clone_ret:
149
+
__relibc_internal_rlct_clone_ret:
150
150
# Load registers
151
151
pop rax
152
152
pop rdi
···
169
169
call rax
170
170
171
171
ret
172
-
.size __relibc_internal_pte_clone_ret, . - __relibc_internal_pte_clone_ret
172
+
.size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret
173
173
"
174
174
);
+1
-1
src/platform/redox/mod.rs
+1
-1
src/platform/redox/mod.rs
···
759
759
}
760
760
761
761
unsafe fn rlct_clone(stack: *mut usize) -> Result<crate::pthread::OsTid, crate::pthread::Errno> {
762
-
clone::pte_clone_impl(stack).map(|context_id| crate::pthread::OsTid { context_id }).map_err(|error| crate::pthread::Errno(error.errno))
762
+
clone::rlct_clone_impl(stack).map(|context_id| crate::pthread::OsTid { context_id }).map_err(|error| crate::pthread::Errno(error.errno))
763
763
}
764
764
unsafe fn rlct_kill(os_tid: crate::pthread::OsTid, signal: usize) -> Result<(), crate::pthread::Errno> {
765
765
syscall::kill(os_tid.context_id, signal).map_err(|error| crate::pthread::Errno(error.errno))?;
+2
-13
src/platform/types.rs
+2
-13
src/platform/types.rs
···
77
77
pub type clockid_t = c_int;
78
78
pub type timer_t = *mut c_void;
79
79
80
-
pub type pthread_attr_t = crate::header::pthread::attr::Attr;
81
-
pub type pthread_barrier_t = crate::header::pthread::barrier::Barrier;
82
-
pub type pthread_barrierattr_t = crate::header::pthread::barrier::BarrierAttr;
83
-
pub type pthread_cond_t = crate::header::pthread::cond::Cond;
84
-
pub type pthread_condattr_t = crate::header::pthread::cond::CondAttr;
85
-
pub type pthread_key_t = u32;
86
-
pub type pthread_mutex_t = crate::header::pthread::mutex::Mutex;
87
-
pub type pthread_mutexattr_t = crate::header::pthread::mutex::MutexAttr;
88
-
pub type pthread_once_t = crate::header::pthread::once::Once;
89
-
pub type pthread_rwlock_t = crate::header::pthread::rwlock::Rwlock;
90
-
pub type pthread_rwlockattr_t = crate::header::pthread::rwlock::RwlockAttr;
91
-
pub type pthread_spinlock_t = crate::header::pthread::spin::Spinlock;
92
-
pub type pthread_t = *mut c_void;
80
+
pub use crate::header::bits_pthread::*;
81
+
pub use crate::header::bits_sched::*;
+83
-14
src/pthread/mod.rs
+83
-14
src/pthread/mod.rs
···
2
2
3
3
use core::cell::{Cell, UnsafeCell};
4
4
use core::ptr::NonNull;
5
-
use core::sync::atomic::{AtomicBool, Ordering};
5
+
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
6
6
7
7
use alloc::boxed::Box;
8
8
use alloc::collections::BTreeMap;
···
12
12
use crate::header::sched::sched_param;
13
13
use crate::header::errno::*;
14
14
use crate::header::sys_mman;
15
+
use crate::header::pthread as header;
15
16
use crate::ld_so::{linker::Linker, tcb::{Master, Tcb}};
16
17
use crate::ALLOCATOR;
17
18
18
19
use crate::sync::{Mutex, waitval::Waitval};
19
20
20
-
#[no_mangle]
21
-
extern "C" fn pthread_init() {
21
+
const MAIN_PTHREAD_ID: usize = 1;
22
+
23
+
/// Called only by the main thread, as part of relibc_start.
24
+
pub unsafe fn init() {
25
+
let obj = Box::into_raw(Box::new(Pthread {
26
+
waitval: Waitval::new(),
27
+
wants_cancel: AtomicBool::new(false),
28
+
flags: PthreadFlags::empty().bits().into(),
29
+
30
+
// TODO
31
+
stack_base: core::ptr::null_mut(),
32
+
stack_size: 0,
33
+
34
+
os_tid: UnsafeCell::new(Sys::current_os_tid()),
35
+
}));
36
+
37
+
PTHREAD_SELF.set(obj);
38
+
}
39
+
pub unsafe fn terminate_from_main_thread() {
40
+
for (tid, pthread) in OS_TID_TO_PTHREAD.lock().iter() {
41
+
// TODO: Cancel?
42
+
Sys::rlct_kill(*tid, crate::header::signal::SIGTERM);
43
+
}
22
44
}
23
-
#[no_mangle]
24
-
extern "C" fn pthread_terminate() {
45
+
46
+
bitflags::bitflags! {
47
+
struct PthreadFlags: usize {
48
+
const DETACHED = 1;
49
+
}
25
50
}
26
51
27
52
pub struct Pthread {
28
53
waitval: Waitval<Retval>,
29
54
wants_cancel: AtomicBool,
55
+
flags: AtomicUsize,
30
56
31
57
stack_base: *mut c_void,
32
58
stack_size: usize,
···
45
71
unsafe impl Send for Pthread {}
46
72
unsafe impl Sync for Pthread {}
47
73
48
-
use crate::header::pthread::attr::Attr;
74
+
use crate::header::bits_pthread::pthread_attr_t;
49
75
50
76
/// Positive error codes (EINVAL, not -EINVAL).
51
77
#[derive(Debug, Eq, PartialEq)]
···
75
101
// TODO: Custom stacks
76
102
let stack_base = sys_mman::mmap(
77
103
core::ptr::null_mut(),
78
-
attrs.stacksize,
104
+
stack_size,
79
105
sys_mman::PROT_READ | sys_mman::PROT_WRITE,
80
106
sys_mman::MAP_SHARED | sys_mman::MAP_ANONYMOUS,
81
107
-1,
···
86
112
return Err(Errno(EAGAIN));
87
113
}
88
114
115
+
let mut flags = PthreadFlags::empty();
116
+
match i32::from(attrs.detachstate) {
117
+
header::PTHREAD_CREATE_DETACHED => flags |= PthreadFlags::DETACHED,
118
+
header::PTHREAD_CREATE_JOINABLE => (),
119
+
120
+
other => unreachable!("unknown detachstate {}", other),
121
+
}
122
+
89
123
let pthread = Pthread {
90
124
waitval: Waitval::new(),
125
+
flags: flags.bits().into(),
91
126
wants_cancel: AtomicBool::new(false),
92
127
stack_base,
93
128
stack_size,
···
134
169
let Ok(os_tid) = Sys::rlct_clone(stack) else {
135
170
return Err(Errno(EAGAIN));
136
171
};
172
+
core::mem::forget(stack_raii);
137
173
138
174
let _ = (&*synchronization_mutex).lock();
139
175
140
176
OS_TID_TO_PTHREAD.lock().insert(os_tid, ForceSendSync(ptr.cast()));
141
-
142
-
core::mem::forget(stack_raii);
143
177
144
178
Ok(ptr.cast())
145
179
}
···
180
214
if core::ptr::eq(thread, current_thread().unwrap_unchecked()) {
181
215
return Err(Errno(EDEADLK));
182
216
}
217
+
183
218
// Waitval starts locked, and is unlocked when the thread finishes.
184
219
let retval = *thread.waitval.wait();
185
220
186
-
// TODO: Deinitialization code
221
+
// We have now awaited the thread and received its return value. POSIX states that the
222
+
// pthread_t of this thread, will no longer be valid. In practice, we can thus deallocate the
223
+
// thread state.
224
+
225
+
OS_TID_TO_PTHREAD.lock().remove(&thread.os_tid.get().read());
226
+
227
+
dealloc_thread(thread);
187
228
188
229
Ok(retval)
189
230
}
190
231
191
232
pub unsafe fn detach(thread: &Pthread) -> Result<(), Errno> {
192
-
todo!()
233
+
thread.flags.fetch_or(PthreadFlags::DETACHED.bits(), Ordering::Release);
234
+
Ok(())
193
235
}
194
236
195
237
// Returns option because that's a no-op, but PTHREAD_SELF should always be initialized except in
···
208
250
}
209
251
210
252
pub unsafe fn exit_current_thread(retval: Retval) -> ! {
211
-
let this = current_thread().unwrap_unchecked();
212
-
this.waitval.post(retval);
253
+
let this = current_thread().expect("failed to obtain current thread when exiting");
254
+
255
+
if this.flags.load(Ordering::Acquire) & PthreadFlags::DETACHED.bits() != 0 {
256
+
// When detached, the thread state no longer makes any sense, and can immediately be
257
+
// deallocated.
258
+
dealloc_thread(this);
259
+
} else {
260
+
// When joinable, the return value should be made available to other threads.
261
+
this.waitval.post(retval);
262
+
}
213
263
214
264
Sys::exit_thread()
215
265
}
216
266
267
+
// TODO: Use Arc? One strong reference from each OS_TID_TO_PTHREAD and one strong reference from
268
+
// PTHREAD_SELF. The latter ref disappears when the thread exits, while the former disappears when
269
+
// detaching. Isn't that sufficient?
270
+
unsafe fn dealloc_thread(thread: &Pthread) {
271
+
drop(Box::from_raw(thread as *const Pthread as *mut Pthread));
272
+
}
217
273
pub const SIGRT_RLCT_CANCEL: usize = 32;
218
274
pub const SIGRT_RLCT_TIMER: usize = 33;
219
275
276
+
unsafe fn cancel_sighandler(_: c_int) {
277
+
// TODO: pthread_cleanup_push stack
278
+
// TODO: thread-specific data
279
+
280
+
// Terminate the thread
281
+
exit_current_thread(Retval(header::PTHREAD_CANCELED));
282
+
}
283
+
220
284
pub unsafe fn cancel(thread: &Pthread) -> Result<(), Errno> {
285
+
// TODO: Ordering
221
286
thread.wants_cancel.store(true, Ordering::SeqCst);
287
+
222
288
Sys::rlct_kill(thread.os_tid.get().read(), SIGRT_RLCT_CANCEL)?;
289
+
223
290
todo!();
224
291
Ok(())
225
292
}
226
293
227
294
// TODO: Hash map?
228
-
static OS_TID_TO_PTHREAD: Mutex<BTreeMap<OsTid, ForceSendSync<pthread_t>>> = Mutex::new(BTreeMap::new());
295
+
// TODO: RwLock
296
+
static OS_TID_TO_PTHREAD: Mutex<BTreeMap<OsTid, ForceSendSync<*mut Pthread>>> = Mutex::new(BTreeMap::new());
229
297
298
+
#[derive(Clone, Copy)]
230
299
struct ForceSendSync<T>(T);
231
300
unsafe impl<T> Send for ForceSendSync<T> {}
232
301
unsafe impl<T> Sync for ForceSendSync<T> {}
+1
-4
src/start.rs
+1
-4
src/start.rs
+40
-33
src/sync/mod.rs
+40
-33
src/sync/mod.rs
···
37
37
Sys::futex(ptr, FUTEX_WAIT, value, timeout_opt.map_or(0, |t| t as *const _ as usize)) == Ok(0)
38
38
}
39
39
pub fn futex_wake(atomic: &AtomicInt, n: i32) -> usize {
40
-
unsafe { futex_wake_ptr(atomic.as_mut_ptr(), n) }
40
+
unsafe { futex_wake_ptr(atomic.as_ptr(), n) }
41
41
}
42
42
pub fn futex_wait(atomic: &AtomicInt, value: i32, timeout_opt: Option<×pec>) -> bool {
43
-
unsafe { futex_wait_ptr(atomic.as_mut_ptr(), value, timeout_opt) }
43
+
unsafe { futex_wait_ptr(atomic.as_ptr(), value, timeout_opt) }
44
+
}
45
+
pub fn wait_until_generic<F1, F2>(word: &AtomicInt, attempt: F1, mark_long: F2, long: c_int)
46
+
where
47
+
F1: Fn(&AtomicInt) -> AttemptStatus,
48
+
F2: Fn(&AtomicInt) -> AttemptStatus,
49
+
{
50
+
// First, try spinning for really short durations
51
+
for _ in 0..999 {
52
+
atomic::spin_loop_hint();
53
+
if attempt(word) == AttemptStatus::Desired {
54
+
return;
55
+
}
56
+
}
57
+
58
+
// One last attempt, to initiate "previous"
59
+
let mut previous = attempt(word);
60
+
61
+
// Ok, that seems to take quite some time. Let's go into a
62
+
// longer, more patient, wait.
63
+
loop {
64
+
if previous == AttemptStatus::Desired {
65
+
return;
66
+
}
67
+
68
+
if
69
+
// If we or somebody else already initiated a long
70
+
// wait, OR
71
+
previous == AttemptStatus::Waiting ||
72
+
// Otherwise, unless our attempt to initiate a long
73
+
// wait informed us that we might be done waiting
74
+
mark_long(word) != AttemptStatus::Desired
75
+
{
76
+
futex_wait(word, long, None);
77
+
}
78
+
79
+
previous = attempt(word);
80
+
}
44
81
}
45
82
46
83
/// Convenient wrapper around the "futex" system call for
···
92
129
F1: Fn(&AtomicInt) -> AttemptStatus,
93
130
F2: Fn(&AtomicInt) -> AttemptStatus,
94
131
{
95
-
// First, try spinning for really short durations
96
-
for _ in 0..999 {
97
-
atomic::spin_loop_hint();
98
-
if attempt(self) == AttemptStatus::Desired {
99
-
return;
100
-
}
101
-
}
102
-
103
-
// One last attempt, to initiate "previous"
104
-
let mut previous = attempt(self);
105
-
106
-
// Ok, that seems to take quite some time. Let's go into a
107
-
// longer, more patient, wait.
108
-
loop {
109
-
if previous == AttemptStatus::Desired {
110
-
return;
111
-
}
112
-
113
-
if
114
-
// If we or somebody else already initiated a long
115
-
// wait, OR
116
-
previous == AttemptStatus::Waiting ||
117
-
// Otherwise, unless our attempt to initiate a long
118
-
// wait informed us that we might be done waiting
119
-
mark_long(self) != AttemptStatus::Desired
120
-
{
121
-
self.wait_if(long, None);
122
-
}
123
-
124
-
previous = attempt(self);
125
-
}
132
+
wait_until_generic(&self.atomic, attempt, mark_long, long)
126
133
}
127
134
}
128
135
impl Deref for AtomicLock {
+44
-29
src/sync/mutex.rs
+44
-29
src/sync/mutex.rs
···
3
3
use core::{
4
4
cell::UnsafeCell,
5
5
ops::{Deref, DerefMut},
6
-
sync::atomic::Ordering::SeqCst,
6
+
sync::atomic::{AtomicI32 as AtomicInt, Ordering},
7
7
};
8
8
9
-
const UNLOCKED: c_int = 0;
10
-
const LOCKED: c_int = 1;
11
-
const WAITING: c_int = 2;
9
+
pub(crate) const UNLOCKED: c_int = 0;
10
+
pub(crate) const LOCKED: c_int = 1;
11
+
pub(crate) const WAITING: c_int = 2;
12
12
13
13
pub struct Mutex<T> {
14
14
pub(crate) lock: AtomicLock,
···
16
16
}
17
17
unsafe impl<T: Send> Send for Mutex<T> {}
18
18
unsafe impl<T: Send> Sync for Mutex<T> {}
19
+
20
+
pub(crate) unsafe fn manual_try_lock_generic(word: &AtomicInt) -> bool {
21
+
word.compare_exchange(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed).is_ok()
22
+
}
23
+
pub(crate) unsafe fn manual_lock_generic(word: &AtomicInt) {
24
+
crate::sync::wait_until_generic(
25
+
word,
26
+
|lock| {
27
+
lock.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed)
28
+
.map(|_| AttemptStatus::Desired)
29
+
.unwrap_or_else(|e| match e {
30
+
WAITING => AttemptStatus::Waiting,
31
+
_ => AttemptStatus::Other,
32
+
})
33
+
},
34
+
|lock| match lock
35
+
// TODO: Ordering
36
+
.compare_exchange_weak(LOCKED, WAITING, Ordering::SeqCst, Ordering::SeqCst)
37
+
.unwrap_or_else(|e| e)
38
+
{
39
+
UNLOCKED => AttemptStatus::Desired,
40
+
WAITING => AttemptStatus::Waiting,
41
+
_ => AttemptStatus::Other,
42
+
},
43
+
WAITING,
44
+
);
45
+
}
46
+
pub(crate) unsafe fn manual_unlock_generic(word: &AtomicInt) {
47
+
if word.swap(UNLOCKED, Ordering::Release) == WAITING {
48
+
crate::sync::futex_wake(word, 1);
49
+
}
50
+
}
51
+
19
52
impl<T> Mutex<T> {
20
53
/// Create a new mutex
21
54
pub const fn new(content: T) -> Self {
···
42
75
/// on failure. You should probably not worry about this, it's used for
43
76
/// internal optimizations.
44
77
pub unsafe fn manual_try_lock(&self) -> Result<&mut T, c_int> {
45
-
self.lock
46
-
.compare_exchange(UNLOCKED, LOCKED, SeqCst, SeqCst)
47
-
.map(|_| &mut *self.content.get())
78
+
if manual_try_lock_generic(&self.lock) {
79
+
Ok(&mut *self.content.get())
80
+
} else {
81
+
Err(0)
82
+
}
48
83
}
49
84
/// Lock the mutex, returning the inner content. After doing this, it's
50
85
/// your responsibility to unlock it after usage. Mostly useful for FFI:
51
86
/// Prefer normal .lock() where possible.
52
87
pub unsafe fn manual_lock(&self) -> &mut T {
53
-
self.lock.wait_until(
54
-
|lock| {
55
-
lock.compare_exchange_weak(UNLOCKED, LOCKED, SeqCst, SeqCst)
56
-
.map(|_| AttemptStatus::Desired)
57
-
.unwrap_or_else(|e| match e {
58
-
WAITING => AttemptStatus::Waiting,
59
-
_ => AttemptStatus::Other,
60
-
})
61
-
},
62
-
|lock| match lock
63
-
.compare_exchange_weak(LOCKED, WAITING, SeqCst, SeqCst)
64
-
.unwrap_or_else(|e| e)
65
-
{
66
-
UNLOCKED => AttemptStatus::Desired,
67
-
WAITING => AttemptStatus::Waiting,
68
-
_ => AttemptStatus::Other,
69
-
},
70
-
WAITING,
71
-
);
88
+
manual_lock_generic(&self.lock);
72
89
&mut *self.content.get()
73
90
}
74
91
/// Unlock the mutex, if it's locked.
75
92
pub unsafe fn manual_unlock(&self) {
76
-
if self.lock.swap(UNLOCKED, SeqCst) == WAITING {
77
-
self.lock.notify_one();
78
-
}
93
+
manual_unlock_generic(&self.lock)
79
94
}
80
95
81
96
/// Tries to lock the mutex and returns a guard that automatically unlocks
+42
-36
src/sync/once.rs
+42
-36
src/sync/once.rs
···
1
1
use super::{AtomicLock, AttemptStatus};
2
2
use crate::platform::types::*;
3
-
use core::{cell::UnsafeCell, mem::MaybeUninit, sync::atomic::Ordering::SeqCst};
3
+
use core::{cell::UnsafeCell, mem::MaybeUninit};
4
+
use core::sync::atomic::{AtomicI32 as AtomicInt, Ordering::SeqCst};
4
5
5
6
const UNINITIALIZED: c_int = 0;
6
7
const INITIALIZING: c_int = 1;
7
8
const WAITING: c_int = 2;
8
9
const INITIALIZED: c_int = 3;
9
10
11
+
pub(crate) fn call_once_generic(word: &AtomicInt, f: impl FnOnce()) {
12
+
match word.compare_and_swap(UNINITIALIZED, INITIALIZING, SeqCst) {
13
+
UNINITIALIZED => {
14
+
// We now have a lock, let's initiate things!
15
+
16
+
// Mark the data as initialized
17
+
if word.swap(INITIALIZED, SeqCst) == WAITING {
18
+
// At least one thread is waiting on this to finish
19
+
crate::sync::futex_wake(word, i32::MAX);
20
+
}
21
+
}
22
+
INITIALIZING | WAITING => crate::sync::wait_until_generic(
23
+
word,
24
+
|lock| match lock.load(SeqCst) {
25
+
WAITING => AttemptStatus::Waiting,
26
+
INITIALIZED => AttemptStatus::Desired,
27
+
_ => AttemptStatus::Other,
28
+
},
29
+
|lock| match lock
30
+
.compare_exchange_weak(INITIALIZING, WAITING, SeqCst, SeqCst)
31
+
.unwrap_or_else(|e| e)
32
+
{
33
+
WAITING => AttemptStatus::Waiting,
34
+
INITIALIZED => AttemptStatus::Desired,
35
+
_ => AttemptStatus::Other,
36
+
},
37
+
WAITING,
38
+
),
39
+
INITIALIZED => (),
40
+
_ => unreachable!("invalid state for Once<T>"),
41
+
}
42
+
43
+
}
44
+
10
45
pub struct Once<T> {
11
-
status: AtomicLock,
46
+
status: AtomicInt,
12
47
data: UnsafeCell<MaybeUninit<T>>,
13
48
}
14
49
unsafe impl<T: Send> Send for Once<T> {}
···
16
51
impl<T> Once<T> {
17
52
pub const fn new() -> Self {
18
53
Self {
19
-
status: AtomicLock::new(UNINITIALIZED),
54
+
status: AtomicInt::new(UNINITIALIZED),
20
55
data: UnsafeCell::new(MaybeUninit::uninit()),
21
56
}
22
57
}
58
+
// FIXME: Isn't &mut UB?
23
59
pub fn call_once<F>(&self, f: F) -> &mut T
24
60
where
25
61
F: FnOnce() -> T,
26
62
{
27
-
match self
28
-
.status
29
-
.compare_and_swap(UNINITIALIZED, INITIALIZING, SeqCst)
30
-
{
31
-
UNINITIALIZED => {
32
-
// We now have a lock, let's initiate things!
33
-
let ret = unsafe { &mut *self.data.get() }.write(f());
34
-
35
-
// Mark the data as initialized
36
-
if self.status.swap(INITIALIZED, SeqCst) == WAITING {
37
-
// At least one thread is waiting on this to finish
38
-
self.status.notify_all();
39
-
}
40
-
}
41
-
INITIALIZING | WAITING => self.status.wait_until(
42
-
|lock| match lock.load(SeqCst) {
43
-
WAITING => AttemptStatus::Waiting,
44
-
INITIALIZED => AttemptStatus::Desired,
45
-
_ => AttemptStatus::Other,
46
-
},
47
-
|lock| match lock
48
-
.compare_exchange_weak(INITIALIZING, WAITING, SeqCst, SeqCst)
49
-
.unwrap_or_else(|e| e)
50
-
{
51
-
WAITING => AttemptStatus::Waiting,
52
-
INITIALIZED => AttemptStatus::Desired,
53
-
_ => AttemptStatus::Other,
54
-
},
55
-
WAITING,
56
-
),
57
-
INITIALIZED => (),
58
-
_ => unreachable!("invalid state for Once<T>"),
59
-
}
63
+
call_once_generic(&self.status, || {
64
+
unsafe { &mut *self.data.get() }.write(f());
65
+
});
60
66
61
67
// At this point the data must be initialized!
62
68
unsafe { &mut *(&mut *self.data.get()).as_mut_ptr() }