diff --git a/.gitignore b/.gitignore index f0f3a36cd6bc2d2df8736d3badc9b3d3479b9711..6c439934ffe7c4255f89e47f91b08172f332ae28 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ sysroot/ *.patch *.swp *.swo +/.vim diff --git a/Cargo.lock b/Cargo.lock index fd402669e38bcde496260eae4716ce4e22375391..1a00975c59af559da1561c6c67f34aaed1ac4c3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -35,8 +35,8 @@ dependencies = [ "heck", "indexmap", "log", - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2 1.0.56", + "quote 1.0.26", "serde", "serde_json", "syn 1.0.109", @@ -110,13 +110,13 @@ version = "0.1.0" [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -170,11 +170,17 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", @@ -191,12 +197,13 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ + "hermit-abi 0.3.1", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -220,15 +227,15 @@ version = "0.1.0" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" [[package]] name = "lock_api" @@ -275,9 +282,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.4.1" +version = "6.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" [[package]] name = "plain" @@ -300,9 +307,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -318,11 +325,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ - "proc-macro2 1.0.51", + "proc-macro2 1.0.56", ] [[package]] @@ -371,7 +378,7 @@ version = "0.1.0" dependencies = [ "goblin", "plain", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] @@ -382,18 +389,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb02a9aee8e8c7ad8d86890f1e16b49e0bbbffc9961ff3788c31d57c98bcbf03" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags", ] @@ -402,6 +400,7 @@ dependencies = [ name = "relibc" version = "0.2.5" dependencies = [ + "bitflags", "cbindgen", "cbitset", "cc", @@ -415,9 +414,9 @@ dependencies = [ "ralloc", "rand", "redox-exec", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", "sc", - "spin 0.9.5", + "spin 0.9.8", "unicode-width", ] @@ -441,16 +440,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.9" +version = "0.37.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -515,29 +514,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.154" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cdd151213925e7f1ab45a9bbfb129316bd00799784b174b7cc7bcd16961c49e" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.154" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc80d722935453bcafdc2c9a73cd6fac4dc1938f0346035d84bf99fa9e33217" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.109", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.15", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -552,9 +551,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" dependencies = [ "lock_api", ] @@ -582,22 +581,33 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2 1.0.56", + "quote 1.0.26", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", "unicode-ident", ] [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "rustix", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -681,81 +691,132 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-targets 0.42.2", ] [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.0", ] [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/Cargo.toml b/Cargo.toml index 1f301f7b0592b3390e0e0a4d7e877f1ea67f03dd..856da184c2ee0fa162e8135c6b4dddee5fdcc49f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,10 @@ exclude = ["core_io", "ralloc", "tests"] [build-dependencies] cbindgen = "0.24.3" cc = "1.0.25" +#env_logger = "0.10" [dependencies] +bitflags = "1" cbitset = "0.1.0" core_io = { path = "core_io", features = ["collections"] } lazy_static = { version = "1.4.0", default-features = false, features = ["spin_no_std"] } diff --git a/src/header/bits_pthread/cbindgen.toml b/src/header/bits_pthread/cbindgen.toml new file mode 100644 index 0000000000000000000000000000000000000000..5e37edbb7ce038fb03cd641efe50dd796753e480 --- /dev/null +++ b/src/header/bits_pthread/cbindgen.toml @@ -0,0 +1,37 @@ +sys_includes = ["bits/sched.h"] +include_guard = "_RELIBC_BITS_PTHREAD_H" +language = "C" +style = "type" +no_includes = true +cpp_compat = true +trailer = """ +#define PTHREAD_COND_INITIALIZER {0} +#define PTHREAD_MUTEX_INITIALIZER {0} +#define PTHREAD_ONCE_INIT {0} +#define PTHREAD_RWLOCK_INITIALIZER {0} +""" + +[export.rename] +"sched_param" = "struct sched_param" +"AtomicInt" = "int" +"AtomicUint" = "unsigned" + +[export] +include = [ + "pthread_attr_t", + "pthread_rwlockattr_t", + "pthread_rwlock_t", + "pthread_barrier_t", + "pthread_barrierattr_t", + "pthread_mutex_t", + "pthread_mutexattr_t", + "pthread_condattr_t", + "pthread_cond_t", + "pthread_spinlock_t", + "pthread_once_t", + "pthread_t", + "pthread_key_t", +] + +[enum] +prefix_with_name = true diff --git a/src/header/bits_pthread/mod.rs b/src/header/bits_pthread/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..1f87299427f457e36d52d5dc7ae804ace87c4ebd --- /dev/null +++ b/src/header/bits_pthread/mod.rs @@ -0,0 +1,81 @@ +#![allow(non_camel_case_types)] + +use crate::platform::types::*; + +use crate::header::sched::sched_param; + +use crate::sync::AtomicLock; +use core::sync::atomic::{AtomicU32 as AtomicUint, AtomicI32 as AtomicInt}; + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct pthread_attr_t { + pub detachstate: c_uchar, + pub inheritsched: c_uchar, + pub schedpolicy: c_uchar, + pub scope: c_uchar, + pub guardsize: size_t, + pub stacksize: size_t, + pub stack: size_t, + pub param: sched_param, +} + +#[repr(C)] +pub struct pthread_rwlockattr_t { + pub pshared: c_int, +} + +#[repr(C)] +pub struct pthread_rwlock_t { + pub state: AtomicInt, +} + +#[repr(C)] +pub struct pthread_barrier_t { + pub count: AtomicUint, + pub original_count: c_uint, + pub epoch: AtomicInt, +} + +#[repr(C)] +pub struct pthread_barrierattr_t { + pub pshared: c_int, +} + +#[repr(C)] +pub struct pthread_mutex_t { + pub inner: AtomicInt, +} + +#[repr(C)] +pub struct pthread_mutexattr_t { + pub prioceiling: c_int, + pub protocol: c_int, + pub pshared: c_int, + pub robust: c_int, + pub ty: c_int, +} + +#[repr(C)] +pub struct pthread_condattr_t { + pub clock: clockid_t, + pub pshared: c_int, +} + +#[repr(C)] +pub struct pthread_cond_t { + pub cur: AtomicInt, + pub prev: AtomicInt, +} +#[repr(C)] +pub struct pthread_spinlock_t { + pub inner: AtomicInt, +} + +#[repr(C)] +pub struct pthread_once_t { + pub inner: AtomicInt, +} + +pub type pthread_t = *mut (); +pub type pthread_key_t = c_ulong; diff --git a/src/header/bits_sched/cbindgen.toml b/src/header/bits_sched/cbindgen.toml new file mode 100644 index 0000000000000000000000000000000000000000..a208ab70efcaaa89f4f74ac22992609a34e94a59 --- /dev/null +++ b/src/header/bits_sched/cbindgen.toml @@ -0,0 +1,11 @@ +sys_includes = [] +include_guard = "_RELIBC_BITS_SCHED_H" +language = "C" +style = "tag" +no_includes = true +cpp_compat = true + +[export] +include = [ + "sched_param", +] diff --git a/src/header/bits_sched/mod.rs b/src/header/bits_sched/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..b092dbdd70b4819527af283e980c3cb1709ff5eb --- /dev/null +++ b/src/header/bits_sched/mod.rs @@ -0,0 +1,9 @@ +#![allow(non_camel_case_types)] + +use crate::platform::types::*; + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct sched_param { + pub sched_priority: c_int, +} diff --git a/src/header/mod.rs b/src/header/mod.rs index d1696f33c1dfbfc5dea9636ff93c479a7787f353..2bcabb4621051f26e4a9a52231f713d929f697fb 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -2,6 +2,8 @@ pub mod _aio; pub mod _fenv; pub mod arpa_inet; pub mod assert; +pub mod bits_pthread; +pub mod bits_sched; pub mod ctype; pub mod dirent; #[path = "dl-tls/mod.rs"] diff --git a/src/header/netdb/dns/mod.rs b/src/header/netdb/dns/mod.rs index e39098c6fa1de21ba4b1a43c93206fc16c6d0e69..30847ddf884300306b42afaaf585bd36102fca82 100644 --- a/src/header/netdb/dns/mod.rs +++ b/src/header/netdb/dns/mod.rs @@ -25,7 +25,7 @@ pub struct n16 { impl n16 { pub fn as_bytes(&self) -> &[u8] { - unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) } + unsafe { slice::from_raw_parts(core::ptr::addr_of!(self.inner).cast::<u8>(), 2) } } pub fn from_bytes(bytes: &[u8]) -> Self { diff --git a/src/header/pthread/attr.rs b/src/header/pthread/attr.rs index fbfcf45e6f5620462132844304ee20d3f97505ba..a13dac6140337861e8243f1f5e189a48a2964604 100644 --- a/src/header/pthread/attr.rs +++ b/src/header/pthread/attr.rs @@ -1,18 +1,8 @@ use super::*; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct Attr { - pub detachstate: u8, - pub inheritsched: u8, - pub schedpolicy: u8, - pub scope: u8, - pub guardsize: usize, - pub stacksize: usize, - pub stack: usize, - pub param: sched_param, -} -impl Default for Attr { +use crate::header::bits_pthread::pthread_attr_t; + +impl Default for pthread_attr_t { fn default() -> Self { Self { // Default according to POSIX. @@ -93,7 +83,7 @@ pub unsafe extern "C" fn pthread_attr_getstacksize(attr: *const pthread_attr_t, #[no_mangle] pub unsafe extern "C" fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int { - core::ptr::write(attr, Attr::default()); + core::ptr::write(attr, pthread_attr_t::default()); 0 } diff --git a/src/header/pthread/barrier.rs b/src/header/pthread/barrier.rs index a53be0467a384cf592ac74b0c5f4c187a01bde67..3e32ca4abfc6518bcc8b44dd67dbcb9a2279af80 100644 --- a/src/header/pthread/barrier.rs +++ b/src/header/pthread/barrier.rs @@ -1,22 +1,9 @@ use crate::header::errno::*; -use crate::sync::AtomicLock; -use core::sync::atomic::{AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, AtomicI32 as AtomicInt, Ordering}; use super::*; -#[repr(C)] -pub struct Barrier { - count: AtomicU32, - original_count: u32, - epoch: AtomicLock, -} - -#[repr(C)] -pub struct BarrierAttr { - pshared: c_int, -} - #[no_mangle] pub unsafe extern "C" fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int { // Behavior is undefined if any thread is currently waiting. @@ -29,10 +16,10 @@ pub unsafe extern "C" fn pthread_barrier_init(barrier: *mut pthread_barrier_t, a return EINVAL; } - core::ptr::write(barrier, Barrier { + core::ptr::write(barrier, pthread_barrier_t { count: AtomicU32::new(0), original_count: count, - epoch: AtomicLock::new(0), + epoch: AtomicInt::new(0), }); 0 } @@ -73,7 +60,7 @@ pub unsafe extern "C" fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) - #[no_mangle] pub unsafe extern "C" fn pthread_barrierattr_init(attr: *mut pthread_barrierattr_t) -> c_int { // PTHREAD_PROCESS_PRIVATE is default according to POSIX. - core::ptr::write(attr, BarrierAttr { pshared: PTHREAD_PROCESS_PRIVATE }); + core::ptr::write(attr, pthread_barrierattr_t { pshared: PTHREAD_PROCESS_PRIVATE }); 0 } diff --git a/src/header/pthread/cbindgen.toml b/src/header/pthread/cbindgen.toml index afb38e336e1257bac7b47ebd175ee069b6fdd615..3018f6160555e5f1a3c0cd4c949fd2aa6e50cfab 100644 --- a/src/header/pthread/cbindgen.toml +++ b/src/header/pthread/cbindgen.toml @@ -1,9 +1,13 @@ -sys_includes = ["sched.h", "time.h"] +sys_includes = ["sched.h", "time.h", "bits/pthread.h"] include_guard = "_RELIBC_PTHREAD_H" language = "C" -style = "Tag" +style = "tag" no_includes = true cpp_compat = true +[export.rename] +"sched_param" = "struct sched_param" +"timespec" = "struct timespec" + [enum] prefix_with_name = true diff --git a/src/header/pthread/cond.rs b/src/header/pthread/cond.rs index 45aaf13f73be803ab456f882bbec4243d03e115f..545d918a45b7c83dc69185ad2be5be4285c0fe24 100644 --- a/src/header/pthread/cond.rs +++ b/src/header/pthread/cond.rs @@ -6,18 +6,6 @@ use core::sync::atomic::{AtomicI32 as AtomicInt, Ordering}; // PTHREAD_COND_INITIALIZER -#[repr(C)] -pub struct CondAttr { - clock: clockid_t, - pshared: c_int, -} - -#[repr(C)] -pub struct Cond { - cur: AtomicInt, - prev: AtomicInt, -} - #[no_mangle] pub unsafe extern "C" fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_int { wake(cond, i32::MAX) @@ -43,7 +31,7 @@ pub unsafe extern "C" fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> c_in #[no_mangle] pub unsafe extern "C" fn pthread_cond_init(cond: *mut pthread_cond_t, _attr: *const pthread_condattr_t) -> c_int { - cond.write(Cond { + cond.write(pthread_cond_t { cur: AtomicInt::new(0), prev: AtomicInt::new(0), }); @@ -56,25 +44,24 @@ pub unsafe extern "C" fn pthread_cond_signal(cond: *mut pthread_cond_t) -> c_int } #[no_mangle] -pub unsafe extern "C" fn pthread_cond_timedwait(cond: *mut pthread_cond_t, mutex_ptr: *const pthread_mutex_t, timeout: *const timespec) -> c_int { +pub unsafe extern "C" fn pthread_cond_timedwait(cond: *mut pthread_cond_t, mutex_ptr: *mut pthread_mutex_t, timeout: *const timespec) -> c_int { // TODO: Error checking for certain types (i.e. robust and errorcheck) of mutexes, e.g. if the // mutex is not locked. let cond: &pthread_cond_t = &*cond; - let mutex: &pthread_mutex_t = &*mutex_ptr; let timeout: Option<×pec> = timeout.as_ref(); let current = cond.cur.load(Ordering::Relaxed); cond.prev.store(current, Ordering::SeqCst); - mutex.inner.manual_unlock(); + pthread_mutex_unlock(mutex_ptr); crate::sync::futex_wait(&cond.cur, current, timeout); - mutex.inner.manual_lock(); + pthread_mutex_lock(mutex_ptr); 0 } #[no_mangle] -pub unsafe extern "C" fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *const pthread_mutex_t) -> c_int { +pub unsafe extern "C" fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *mut pthread_mutex_t) -> c_int { pthread_cond_timedwait(cond, mutex, core::ptr::null()) } @@ -97,7 +84,7 @@ pub unsafe extern "C" fn pthread_condattr_getpshared(condattr: *const pthread_co #[no_mangle] pub unsafe extern "C" fn pthread_condattr_init(condattr: *mut pthread_condattr_t) -> c_int { - core::ptr::write(condattr, CondAttr { + core::ptr::write(condattr, pthread_condattr_t { // FIXME: system clock clock: 0, // Default diff --git a/src/header/pthread/mod.rs b/src/header/pthread/mod.rs index db215d811b023006cfe53ee7a999f8ff4ed87773..7bdf7de4def118849a9f75217b1815cf53e08f03 100644 --- a/src/header/pthread/mod.rs +++ b/src/header/pthread/mod.rs @@ -126,6 +126,7 @@ pub use self::once::*; pub mod rwlock; pub use self::rwlock::*; +#[no_mangle] pub unsafe extern "C" fn pthread_self() -> pthread_t { pthread::current_thread().unwrap_unchecked() as *const _ as *mut _ } diff --git a/src/header/pthread/mutex.rs b/src/header/pthread/mutex.rs index be8d40bf3b79694cd2ade1fe8855a6e093cbe1b9..3ea242e74db55ea1b5f0574101ef0fd135b19408 100644 --- a/src/header/pthread/mutex.rs +++ b/src/header/pthread/mutex.rs @@ -4,20 +4,6 @@ use crate::header::errno::EBUSY; // PTHREAD_MUTEX_INITIALIZER -#[repr(C)] -pub struct Mutex { - pub(crate) inner: crate::sync::Mutex<()>, -} - -#[repr(C)] -pub struct MutexAttr { - prioceiling: c_int, - protocol: c_int, - pshared: c_int, - robust: c_int, - ty: c_int, -} - // #[no_mangle] pub extern "C" fn pthread_mutex_consistent(mutex: *mut pthread_mutex_t) -> c_int { todo!(); @@ -36,14 +22,14 @@ pub extern "C" fn pthread_mutex_getprioceiling(mutex: *const pthread_mutex_t, pr #[no_mangle] pub unsafe extern "C" fn pthread_mutex_init(mutex: *mut pthread_mutex_t, _attr: *const pthread_mutexattr_t) -> c_int { // TODO: attr - mutex.write(Mutex { - inner: crate::sync::Mutex::new(()), + mutex.write(pthread_mutex_t { + inner: crate::sync::mutex::UNLOCKED.into(), }); 0 } #[no_mangle] pub unsafe extern "C" fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int { - (&*mutex).inner.manual_lock(); + crate::sync::mutex::manual_lock_generic(&(&*mutex).inner); 0 } @@ -59,14 +45,15 @@ pub extern "C" fn pthread_mutex_timedlock(mutex: *mut pthread_mutex_t, timespec: } #[no_mangle] pub unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> c_int { - match (&*mutex).inner.manual_try_lock() { - Ok(_) => 0, - Err(_) => EBUSY, + if crate::sync::mutex::manual_try_lock_generic(&(&*mutex).inner) { + 0 + } else { + EBUSY } } #[no_mangle] pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int { - (&*mutex).inner.manual_unlock(); + crate::sync::mutex::manual_unlock_generic(&(&*mutex).inner); 0 } @@ -105,7 +92,7 @@ pub unsafe extern "C" fn pthread_mutexattr_gettype(attr: *const pthread_mutexatt } #[no_mangle] pub unsafe extern "C" fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int { - attr.write(MutexAttr { + attr.write(pthread_mutexattr_t { robust: PTHREAD_MUTEX_STALLED, pshared: PTHREAD_PROCESS_PRIVATE, protocol: PTHREAD_PRIO_NONE, diff --git a/src/header/pthread/once.rs b/src/header/pthread/once.rs index f5cc09169c158482f077a8ddfe6da391fff568bd..9bb96616f233c1d95f0c92759a599968922f9cbc 100644 --- a/src/header/pthread/once.rs +++ b/src/header/pthread/once.rs @@ -1,10 +1,5 @@ use super::*; -#[repr(C)] -pub struct Once { - inner: crate::sync::Once<()>, -} - // PTHREAD_ONCE_INIT #[no_mangle] @@ -12,7 +7,7 @@ pub unsafe extern "C" fn pthread_once(once: *mut pthread_once_t, constructor: ex let once: &pthread_once_t = &*once; // TODO: Cancellation points - once.inner.call_once(|| constructor()); + crate::sync::once::call_once_generic(&once.inner, || constructor()); 0 } diff --git a/src/header/pthread/rwlock.rs b/src/header/pthread/rwlock.rs index 375a40828cec898f6e505e9ae4a9e08a95022473..be2fbf274fc18f4712b708c7d58e02f0fdd0715c 100644 --- a/src/header/pthread/rwlock.rs +++ b/src/header/pthread/rwlock.rs @@ -1,7 +1,6 @@ use super::*; -use crate::sync::AtomicLock; -use core::sync::atomic::Ordering; +use core::sync::atomic::{AtomicI32 as AtomicInt, Ordering}; use crate::header::errno::EBUSY; @@ -15,16 +14,6 @@ const EXCLUSIVE: u32 = (1 << (u32::BITS - 1)) - 1; // Separate "waiting for wrlocks" and "waiting for rdlocks"? //const WAITING: u32 = 1 << (u32::BITS - 1); -#[repr(C)] -pub struct Rwlock { - state: AtomicLock, -} - -#[repr(C)] -pub struct RwlockAttr { - pshared: c_int, -} - #[no_mangle] pub unsafe extern "C" fn pthread_rwlock_destroy(rwlock: *mut pthread_rwlock_t) -> c_int { // (Informing the compiler that this pointer is valid, might improve optimizations.) @@ -33,8 +22,8 @@ pub unsafe extern "C" fn pthread_rwlock_destroy(rwlock: *mut pthread_rwlock_t) - } #[no_mangle] pub unsafe extern "C" fn pthread_rwlock_init(rwlock: *mut pthread_rwlock_t, _attr: *const pthread_rwlockattr_t) -> c_int { - core::ptr::write(rwlock, Rwlock { - state: AtomicLock::new(0), + core::ptr::write(rwlock, pthread_rwlock_t { + state: AtomicInt::new(0), }); 0 @@ -50,7 +39,7 @@ pub unsafe extern "C" fn pthread_rwlock_timedrdlock(rwlock: *mut pthread_rwlock_ loop { if pthread_rwlock_tryrdlock(rwlock as *const _ as *mut _) == EBUSY { - rwlock.state.wait_if(EXCLUSIVE as i32, timeout); + crate::sync::futex_wait(&rwlock.state, EXCLUSIVE as i32, timeout); } return 0; } @@ -60,11 +49,20 @@ pub unsafe extern "C" fn pthread_rwlock_timedwrlock(rwlock: *mut pthread_rwlock_ let rwlock: &pthread_rwlock_t = &*rwlock; let timeout = timeout.as_ref(); - loop { + /*loop { if pthread_rwlock_trywrlock(rwlock as *const _ as *mut _) == EBUSY { - rwlock.state.wait_if(EXCLUSIVE as i32, timeout); + crate::sync::futex_wait(&rwlock.state, EXCLUSIVE as i32, timeout); } return 0; + }*/ + loop { + match rwlock.state.compare_exchange(0, EXCLUSIVE as i32, Ordering::Acquire, Ordering::Relaxed) { + Ok(_) => return 0, + Err(value) => { + // TODO: More than just forwarding the timeout. + crate::sync::futex_wait(&rwlock.state, value, timeout); + } + } } } #[no_mangle] @@ -105,7 +103,7 @@ pub unsafe extern "C" fn pthread_rwlock_unlock(rwlock: *const pthread_rwlock_t) let old = rwlock.state.swap(0, Ordering::Release) as u32; if old == EXCLUSIVE { - rwlock.state.notify_all(); + crate::sync::futex_wake(&rwlock.state, i32::MAX); } 0 @@ -129,7 +127,7 @@ pub unsafe extern "C" fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlo #[no_mangle] pub unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> c_int { - core::ptr::write(attr, RwlockAttr { + core::ptr::write(attr, pthread_rwlockattr_t { // Default according to POSIX. pshared: PTHREAD_PROCESS_PRIVATE, }); diff --git a/src/header/pthread/spin.rs b/src/header/pthread/spin.rs index 5233e04d20edad5cdd39fcc43f951b5156d353fa..9e957a63822a00f7b78424cfcb4482ed42a86d03 100644 --- a/src/header/pthread/spin.rs +++ b/src/header/pthread/spin.rs @@ -4,11 +4,6 @@ use crate::header::errno::EBUSY; use super::*; -#[repr(C)] -pub struct Spinlock { - inner: AtomicInt, -} - pub const UNLOCKED: c_int = 0; pub const LOCKED: c_int = 1; @@ -19,12 +14,12 @@ pub unsafe extern "C" fn pthread_spin_init(spinlock: *mut pthread_spinlock_t, _p // TODO: pshared doesn't matter in most situations, as memory is just memory, but this may be // different on some architectures... - core::ptr::write(spinlock, Spinlock { inner: AtomicInt::new(UNLOCKED) }); + core::ptr::write(spinlock, pthread_spinlock_t { inner: AtomicInt::new(UNLOCKED) }); 0 } pub unsafe extern "C" fn pthread_spin_lock(spinlock: *mut pthread_spinlock_t) -> c_int { - let spinlock: &Spinlock = &*spinlock; + let spinlock: &pthread_spinlock_t = &*spinlock; loop { match spinlock.inner.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed) { @@ -34,7 +29,7 @@ pub unsafe extern "C" fn pthread_spin_lock(spinlock: *mut pthread_spinlock_t) -> } } pub unsafe extern "C" fn pthread_spin_trylock(spinlock: *mut pthread_spinlock_t) -> c_int { - let spinlock: &Spinlock = &*spinlock; + let spinlock: &pthread_spinlock_t = &*spinlock; match spinlock.inner.compare_exchange(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed) { Ok(_) => 0, @@ -42,7 +37,7 @@ pub unsafe extern "C" fn pthread_spin_trylock(spinlock: *mut pthread_spinlock_t) } } pub unsafe extern "C" fn pthread_spin_unlock(spinlock: *mut pthread_spinlock_t) -> c_int { - let spinlock: &Spinlock = &*spinlock; + let spinlock: &pthread_spinlock_t = &*spinlock; spinlock.inner.store(UNLOCKED, Ordering::Release); diff --git a/src/header/pthread/tls.rs b/src/header/pthread/tls.rs index 19d614342d7f5d25dc68f8928b941cf25c3a16b9..d8211b3c05edaa048e7c9ec3c2764dacf1290798 100644 --- a/src/header/pthread/tls.rs +++ b/src/header/pthread/tls.rs @@ -6,15 +6,26 @@ use alloc::collections::BTreeMap; use core::cell::{Cell, RefCell}; use crate::header::errno::EINVAL; +use crate::sync::Mutex; // TODO: What should this limit be? pub const PTHREAD_KEYS_MAX: u32 = 4096 * 32; #[no_mangle] pub unsafe extern "C" fn pthread_getspecific(key: pthread_key_t) -> *mut c_void { - let Some(&Record { data, .. }) = DICT.borrow_mut().get(&key) else { + //print!("pthread_getspecific key={:#0x}: ", key); + + // TODO: Right? + if !KEYS.lock().contains_key(&key) { + //println!("= not found"); + return core::ptr::null_mut(); + } + + let Some(&Record { data, .. }) = VALUES.borrow_mut().get(&key) else { + //println!("= NULL"); return core::ptr::null_mut(); }; + //println!("= {:p}", data); data } @@ -22,14 +33,16 @@ pub unsafe extern "C" fn pthread_getspecific(key: pthread_key_t) -> *mut c_void pub unsafe extern "C" fn pthread_key_create(key_ptr: *mut pthread_key_t, destructor: extern "C" fn(value: *mut c_void)) -> c_int { let key = NEXTKEY.get(); NEXTKEY.set(key + 1); + //println!("pthread_key_create new key {:#0x}, dtor {:p}", key, destructor); // TODO //if key >= PTHREAD_KEYS_MAX { //} - DICT.borrow_mut().insert(key, Record { + KEYS.lock().insert(key, Dtor { destructor }); + + VALUES.borrow_mut().insert(key, Record { data: core::ptr::null_mut(), - destructor, }); key_ptr.write(key); @@ -39,35 +52,45 @@ pub unsafe extern "C" fn pthread_key_create(key_ptr: *mut pthread_key_t, destruc #[no_mangle] pub unsafe extern "C" fn pthread_key_delete(key: pthread_key_t) -> c_int { - if DICT.borrow_mut().remove(&key).is_none() { + if KEYS.lock().remove(&key).is_none() || VALUES.borrow_mut().remove(&key).is_none() { // We don't have to return anything, but it's not less expensive to ignore it. return EINVAL; } + //println!("pthread_key_delete {:#0x}", key); 0 } #[no_mangle] pub unsafe extern "C" fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int { - let mut guard = DICT.borrow_mut(); - - let Some(Record { data, .. }) = guard.get_mut(&key) else { + if !KEYS.lock().contains_key(&key) { // We don't have to return anything, but it's not less expensive to ignore it. + //println!("Invalid key for pthread_setspecific key {:#0x} value {:p}", key, value); return EINVAL; - }; + } + + let mut guard = VALUES.borrow_mut(); + + let Record { ref mut data, .. } = guard.entry(key).or_insert(Record { data: core::ptr::null_mut() }); + //println!("Valid key for pthread_setspecific key {:#0x} value {:p} (was {:p})", key, value, *data); *data = value as *mut c_void; 0 } +static KEYS: Mutex<BTreeMap<pthread_key_t, Dtor>> = Mutex::new(BTreeMap::new()); + +struct Dtor { + destructor: extern "C" fn(value: *mut c_void) +} + #[thread_local] -static DICT: RefCell<BTreeMap<u32, Record>> = RefCell::new(BTreeMap::new()); +static VALUES: RefCell<BTreeMap<pthread_key_t, Record>> = RefCell::new(BTreeMap::new()); struct Record { data: *mut c_void, - destructor: extern "C" fn(value: *mut c_void), } #[thread_local] -static NEXTKEY: Cell<u32> = Cell::new(1); +static NEXTKEY: Cell<pthread_key_t> = Cell::new(1); diff --git a/src/header/sched/cbindgen.toml b/src/header/sched/cbindgen.toml index 28efc6288d3028540a11bfbb243482e897e6a742..f6ba5253b3d8f82c3ef662d01a40c502c4e525be 100644 --- a/src/header/sched/cbindgen.toml +++ b/src/header/sched/cbindgen.toml @@ -1,4 +1,4 @@ -sys_includes = ["time.h"] +sys_includes = ["time.h", "bits/sched.h"] include_guard = "_RELIBC_SCHED_H" language = "C" style = "Tag" diff --git a/src/header/sched/mod.rs b/src/header/sched/mod.rs index 142d6b0aa629a47ec6984dc91850bed6df32b0eb..62512d4845317eabda9679fee13f719300ea5d3c 100644 --- a/src/header/sched/mod.rs +++ b/src/header/sched/mod.rs @@ -3,11 +3,7 @@ use crate::platform::{Pal, Sys, types::*}; use crate::header::time::timespec; -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub struct sched_param { - pub sched_priority: c_int, -} +pub use crate::header::bits_sched::sched_param; pub const SCHED_FIFO: c_int = 0; pub const SCHED_RR: c_int = 1; diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index ad54751c3f2d252203924c93093cf938c82020a2..4174802415b71284594a30e967024da477e60edd 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -275,7 +275,6 @@ pub unsafe extern "C" fn exit(status: c_int) { static __fini_array_start: extern "C" fn(); static __fini_array_end: extern "C" fn(); - fn pthread_terminate(); fn _fini(); } @@ -297,7 +296,7 @@ pub unsafe extern "C" fn exit(status: c_int) { ld_so::fini(); - pthread_terminate(); + crate::pthread::terminate_from_main_thread(); flush_io_streams(); diff --git a/src/header/sys_types/cbindgen.toml b/src/header/sys_types/cbindgen.toml index f9f83e156c3e9f98ba7ade3bdf5f63bbbb7d2462..e6f329441440db1a0b65cd6adb45f842f26d053d 100644 --- a/src/header/sys_types/cbindgen.toml +++ b/src/header/sys_types/cbindgen.toml @@ -5,7 +5,8 @@ sys_includes = [ "sys/types_internal.h", "stddef.h", - "sys/select.h" + "sys/select.h", + "bits/pthread.h", ] include_guard = "_SYS_TYPES_H" diff --git a/src/platform/redox/clone.rs b/src/platform/redox/clone.rs index d67350366151ff9eac2152efbf53134b8c8fd932..5f32f0207ebd21ca35723353192a1ee711f90736 100644 --- a/src/platform/redox/clone.rs +++ b/src/platform/redox/clone.rs @@ -14,7 +14,7 @@ use super::extra::{create_set_addr_space_buf, FdGuard}; pub use redox_exec::*; /// Spawns a new context sharing the same address space as the current one (i.e. a new thread). -pub unsafe fn pte_clone_impl(stack: *mut usize) -> Result<usize> { +pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result<usize> { let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?); let (new_pid_fd, new_pid) = new_context()?; @@ -47,7 +47,7 @@ pub unsafe fn pte_clone_impl(stack: *mut usize) -> Result<usize> { let buf = create_set_addr_space_buf( *cur_addr_space_fd, - __relibc_internal_pte_clone_ret as usize, + __relibc_internal_rlct_clone_ret as usize, stack as usize, ); let _ = syscall::write(*new_addr_space_sel_fd, &buf)?; @@ -86,16 +86,16 @@ pub unsafe fn pte_clone_impl(stack: *mut usize) -> Result<usize> { } extern "C" { - fn __relibc_internal_pte_clone_ret(); + fn __relibc_internal_rlct_clone_ret(); } #[cfg(target_arch = "aarch64")] core::arch::global_asm!( " - .globl __relibc_internal_pte_clone_ret - .type __relibc_internal_pte_clone_ret, @function + .globl __relibc_internal_rlct_clone_ret + .type __relibc_internal_rlct_clone_ret, @function .p2align 6 -__relibc_internal_pte_clone_ret: +__relibc_internal_rlct_clone_ret: # Load registers ldr x8, [sp], #8 ldr x0, [sp], #8 @@ -109,17 +109,17 @@ __relibc_internal_pte_clone_ret: blr x8 ret - .size __relibc_internal_pte_clone_ret, . - __relibc_internal_pte_clone_ret + .size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret " ); #[cfg(target_arch = "x86")] core::arch::global_asm!( " - .globl __relibc_internal_pte_clone_ret - .type __relibc_internal_pte_clone_ret, @function + .globl __relibc_internal_rlct_clone_ret + .type __relibc_internal_rlct_clone_ret, @function .p2align 6 -__relibc_internal_pte_clone_ret: +__relibc_internal_rlct_clone_ret: # Load registers pop eax @@ -136,17 +136,17 @@ __relibc_internal_pte_clone_ret: call eax ret - .size __relibc_internal_pte_clone_ret, . - __relibc_internal_pte_clone_ret + .size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret " ); #[cfg(target_arch = "x86_64")] core::arch::global_asm!( " - .globl __relibc_internal_pte_clone_ret - .type __relibc_internal_pte_clone_ret, @function + .globl __relibc_internal_rlct_clone_ret + .type __relibc_internal_rlct_clone_ret, @function .p2align 6 -__relibc_internal_pte_clone_ret: +__relibc_internal_rlct_clone_ret: # Load registers pop rax pop rdi @@ -169,6 +169,6 @@ __relibc_internal_pte_clone_ret: call rax ret - .size __relibc_internal_pte_clone_ret, . - __relibc_internal_pte_clone_ret + .size __relibc_internal_rlct_clone_ret, . - __relibc_internal_rlct_clone_ret " ); diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index e1d87f937ea256c762dae01de0daea638b2a10a3..a2e9a82384af6ba40683d8dbc1ff4332fce1a961 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -759,7 +759,7 @@ impl Pal for Sys { } unsafe fn rlct_clone(stack: *mut usize) -> Result<crate::pthread::OsTid, crate::pthread::Errno> { - clone::pte_clone_impl(stack).map(|context_id| crate::pthread::OsTid { context_id }).map_err(|error| crate::pthread::Errno(error.errno)) + clone::rlct_clone_impl(stack).map(|context_id| crate::pthread::OsTid { context_id }).map_err(|error| crate::pthread::Errno(error.errno)) } unsafe fn rlct_kill(os_tid: crate::pthread::OsTid, signal: usize) -> Result<(), crate::pthread::Errno> { syscall::kill(os_tid.context_id, signal).map_err(|error| crate::pthread::Errno(error.errno))?; diff --git a/src/platform/types.rs b/src/platform/types.rs index 037ba2d6a4d135575b35830c061fe14d44b51a60..3a42753b0e8da594f3502f5daadd712bff504357 100644 --- a/src/platform/types.rs +++ b/src/platform/types.rs @@ -77,16 +77,5 @@ pub type clock_t = c_long; pub type clockid_t = c_int; pub type timer_t = *mut c_void; -pub type pthread_attr_t = crate::header::pthread::attr::Attr; -pub type pthread_barrier_t = crate::header::pthread::barrier::Barrier; -pub type pthread_barrierattr_t = crate::header::pthread::barrier::BarrierAttr; -pub type pthread_cond_t = crate::header::pthread::cond::Cond; -pub type pthread_condattr_t = crate::header::pthread::cond::CondAttr; -pub type pthread_key_t = u32; -pub type pthread_mutex_t = crate::header::pthread::mutex::Mutex; -pub type pthread_mutexattr_t = crate::header::pthread::mutex::MutexAttr; -pub type pthread_once_t = crate::header::pthread::once::Once; -pub type pthread_rwlock_t = crate::header::pthread::rwlock::Rwlock; -pub type pthread_rwlockattr_t = crate::header::pthread::rwlock::RwlockAttr; -pub type pthread_spinlock_t = crate::header::pthread::spin::Spinlock; -pub type pthread_t = *mut c_void; +pub use crate::header::bits_pthread::*; +pub use crate::header::bits_sched::*; diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs index 1110895b550efdc6bfcc94b7ab1211607fe7cf50..b3573e18f729eaab5dfbbddd68d47c1681680064 100644 --- a/src/pthread/mod.rs +++ b/src/pthread/mod.rs @@ -2,7 +2,7 @@ use core::cell::{Cell, UnsafeCell}; use core::ptr::NonNull; -use core::sync::atomic::{AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use alloc::boxed::Box; use alloc::collections::BTreeMap; @@ -12,21 +12,47 @@ use crate::platform::{Pal, Sys, types::*}; use crate::header::sched::sched_param; use crate::header::errno::*; use crate::header::sys_mman; +use crate::header::pthread as header; use crate::ld_so::{linker::Linker, tcb::{Master, Tcb}}; use crate::ALLOCATOR; use crate::sync::{Mutex, waitval::Waitval}; -#[no_mangle] -extern "C" fn pthread_init() { +const MAIN_PTHREAD_ID: usize = 1; + +/// Called only by the main thread, as part of relibc_start. +pub unsafe fn init() { + let obj = Box::into_raw(Box::new(Pthread { + waitval: Waitval::new(), + wants_cancel: AtomicBool::new(false), + flags: PthreadFlags::empty().bits().into(), + + // TODO + stack_base: core::ptr::null_mut(), + stack_size: 0, + + os_tid: UnsafeCell::new(Sys::current_os_tid()), + })); + + PTHREAD_SELF.set(obj); } -#[no_mangle] -extern "C" fn pthread_terminate() { +pub unsafe fn terminate_from_main_thread() { + for (tid, pthread) in OS_TID_TO_PTHREAD.lock().iter() { + // TODO: Cancel? + Sys::rlct_kill(*tid, crate::header::signal::SIGTERM); + } +} + +bitflags::bitflags! { + struct PthreadFlags: usize { + const DETACHED = 1; + } } pub struct Pthread { waitval: Waitval<Retval>, wants_cancel: AtomicBool, + flags: AtomicUsize, stack_base: *mut c_void, stack_size: usize, @@ -45,7 +71,7 @@ pub struct OsTid { unsafe impl Send for Pthread {} unsafe impl Sync for Pthread {} -use crate::header::pthread::attr::Attr; +use crate::header::bits_pthread::pthread_attr_t; /// Positive error codes (EINVAL, not -EINVAL). #[derive(Debug, Eq, PartialEq)] @@ -75,7 +101,7 @@ pub unsafe fn create(attrs: Option<&pthread_attr_t>, start_routine: extern "C" f // TODO: Custom stacks let stack_base = sys_mman::mmap( core::ptr::null_mut(), - attrs.stacksize, + stack_size, sys_mman::PROT_READ | sys_mman::PROT_WRITE, sys_mman::MAP_SHARED | sys_mman::MAP_ANONYMOUS, -1, @@ -86,8 +112,17 @@ pub unsafe fn create(attrs: Option<&pthread_attr_t>, start_routine: extern "C" f return Err(Errno(EAGAIN)); } + let mut flags = PthreadFlags::empty(); + match i32::from(attrs.detachstate) { + header::PTHREAD_CREATE_DETACHED => flags |= PthreadFlags::DETACHED, + header::PTHREAD_CREATE_JOINABLE => (), + + other => unreachable!("unknown detachstate {}", other), + } + let pthread = Pthread { waitval: Waitval::new(), + flags: flags.bits().into(), wants_cancel: AtomicBool::new(false), stack_base, stack_size, @@ -134,13 +169,12 @@ pub unsafe fn create(attrs: Option<&pthread_attr_t>, start_routine: extern "C" f let Ok(os_tid) = Sys::rlct_clone(stack) else { return Err(Errno(EAGAIN)); }; + core::mem::forget(stack_raii); let _ = (&*synchronization_mutex).lock(); OS_TID_TO_PTHREAD.lock().insert(os_tid, ForceSendSync(ptr.cast())); - core::mem::forget(stack_raii); - Ok(ptr.cast()) } /// A shim to wrap thread entry points in logic to set up TLS, for example @@ -180,16 +214,24 @@ pub unsafe fn join(thread: &Pthread) -> Result<Retval, Errno> { if core::ptr::eq(thread, current_thread().unwrap_unchecked()) { return Err(Errno(EDEADLK)); } + // Waitval starts locked, and is unlocked when the thread finishes. let retval = *thread.waitval.wait(); - // TODO: Deinitialization code + // We have now awaited the thread and received its return value. POSIX states that the + // pthread_t of this thread, will no longer be valid. In practice, we can thus deallocate the + // thread state. + + OS_TID_TO_PTHREAD.lock().remove(&thread.os_tid.get().read()); + + dealloc_thread(thread); Ok(retval) } pub unsafe fn detach(thread: &Pthread) -> Result<(), Errno> { - todo!() + thread.flags.fetch_or(PthreadFlags::DETACHED.bits(), Ordering::Release); + Ok(()) } // Returns option because that's a no-op, but PTHREAD_SELF should always be initialized except in @@ -208,25 +250,52 @@ pub unsafe fn testcancel() { } pub unsafe fn exit_current_thread(retval: Retval) -> ! { - let this = current_thread().unwrap_unchecked(); - this.waitval.post(retval); + let this = current_thread().expect("failed to obtain current thread when exiting"); + + if this.flags.load(Ordering::Acquire) & PthreadFlags::DETACHED.bits() != 0 { + // When detached, the thread state no longer makes any sense, and can immediately be + // deallocated. + dealloc_thread(this); + } else { + // When joinable, the return value should be made available to other threads. + this.waitval.post(retval); + } Sys::exit_thread() } +// TODO: Use Arc? One strong reference from each OS_TID_TO_PTHREAD and one strong reference from +// PTHREAD_SELF. The latter ref disappears when the thread exits, while the former disappears when +// detaching. Isn't that sufficient? +unsafe fn dealloc_thread(thread: &Pthread) { + drop(Box::from_raw(thread as *const Pthread as *mut Pthread)); +} pub const SIGRT_RLCT_CANCEL: usize = 32; pub const SIGRT_RLCT_TIMER: usize = 33; +unsafe fn cancel_sighandler(_: c_int) { + // TODO: pthread_cleanup_push stack + // TODO: thread-specific data + + // Terminate the thread + exit_current_thread(Retval(header::PTHREAD_CANCELED)); +} + pub unsafe fn cancel(thread: &Pthread) -> Result<(), Errno> { + // TODO: Ordering thread.wants_cancel.store(true, Ordering::SeqCst); + Sys::rlct_kill(thread.os_tid.get().read(), SIGRT_RLCT_CANCEL)?; + todo!(); Ok(()) } // TODO: Hash map? -static OS_TID_TO_PTHREAD: Mutex<BTreeMap<OsTid, ForceSendSync<pthread_t>>> = Mutex::new(BTreeMap::new()); +// TODO: RwLock +static OS_TID_TO_PTHREAD: Mutex<BTreeMap<OsTid, ForceSendSync<*mut Pthread>>> = Mutex::new(BTreeMap::new()); +#[derive(Clone, Copy)] struct ForceSendSync<T>(T); unsafe impl<T> Send for ForceSendSync<T> {} unsafe impl<T> Sync for ForceSendSync<T> {} diff --git a/src/start.rs b/src/start.rs index 9f3f94e257414256d7250ba3657b496e76662d10..360b54ff60a82eef88fbc3a99977ab6c74203745 100644 --- a/src/start.rs +++ b/src/start.rs @@ -112,11 +112,8 @@ extern "C" fn init_array() { } } - extern "C" { - fn pthread_init(); - } unsafe { - pthread_init(); + crate::pthread::init(); init_complete = true } } diff --git a/src/sync/mod.rs b/src/sync/mod.rs index 8e1e1649fdfcb6eff7d3f2adce38c528ad004136..8ced156cd6b6ee74c8c44a41a140d61762d18ef1 100644 --- a/src/sync/mod.rs +++ b/src/sync/mod.rs @@ -37,10 +37,47 @@ pub unsafe fn futex_wait_ptr(ptr: *mut i32, value: i32, timeout_opt: Option<&tim Sys::futex(ptr, FUTEX_WAIT, value, timeout_opt.map_or(0, |t| t as *const _ as usize)) == Ok(0) } pub fn futex_wake(atomic: &AtomicInt, n: i32) -> usize { - unsafe { futex_wake_ptr(atomic.as_mut_ptr(), n) } + unsafe { futex_wake_ptr(atomic.as_ptr(), n) } } pub fn futex_wait(atomic: &AtomicInt, value: i32, timeout_opt: Option<×pec>) -> bool { - unsafe { futex_wait_ptr(atomic.as_mut_ptr(), value, timeout_opt) } + unsafe { futex_wait_ptr(atomic.as_ptr(), value, timeout_opt) } +} +pub fn wait_until_generic<F1, F2>(word: &AtomicInt, attempt: F1, mark_long: F2, long: c_int) +where + F1: Fn(&AtomicInt) -> AttemptStatus, + F2: Fn(&AtomicInt) -> AttemptStatus, +{ + // First, try spinning for really short durations + for _ in 0..999 { + atomic::spin_loop_hint(); + if attempt(word) == AttemptStatus::Desired { + return; + } + } + + // One last attempt, to initiate "previous" + let mut previous = attempt(word); + + // Ok, that seems to take quite some time. Let's go into a + // longer, more patient, wait. + loop { + if previous == AttemptStatus::Desired { + return; + } + + if + // If we or somebody else already initiated a long + // wait, OR + previous == AttemptStatus::Waiting || + // Otherwise, unless our attempt to initiate a long + // wait informed us that we might be done waiting + mark_long(word) != AttemptStatus::Desired + { + futex_wait(word, long, None); + } + + previous = attempt(word); + } } /// Convenient wrapper around the "futex" system call for @@ -92,37 +129,7 @@ impl AtomicLock { F1: Fn(&AtomicInt) -> AttemptStatus, F2: Fn(&AtomicInt) -> AttemptStatus, { - // First, try spinning for really short durations - for _ in 0..999 { - atomic::spin_loop_hint(); - if attempt(self) == AttemptStatus::Desired { - return; - } - } - - // One last attempt, to initiate "previous" - let mut previous = attempt(self); - - // Ok, that seems to take quite some time. Let's go into a - // longer, more patient, wait. - loop { - if previous == AttemptStatus::Desired { - return; - } - - if - // If we or somebody else already initiated a long - // wait, OR - previous == AttemptStatus::Waiting || - // Otherwise, unless our attempt to initiate a long - // wait informed us that we might be done waiting - mark_long(self) != AttemptStatus::Desired - { - self.wait_if(long, None); - } - - previous = attempt(self); - } + wait_until_generic(&self.atomic, attempt, mark_long, long) } } impl Deref for AtomicLock { diff --git a/src/sync/mutex.rs b/src/sync/mutex.rs index b286a90a73c9c7719011a3788fba5ad5bf121142..57db44dff3fa6a1054cb97388634ac89439eba43 100644 --- a/src/sync/mutex.rs +++ b/src/sync/mutex.rs @@ -3,12 +3,12 @@ use crate::platform::types::*; use core::{ cell::UnsafeCell, ops::{Deref, DerefMut}, - sync::atomic::Ordering::SeqCst, + sync::atomic::{AtomicI32 as AtomicInt, Ordering}, }; -const UNLOCKED: c_int = 0; -const LOCKED: c_int = 1; -const WAITING: c_int = 2; +pub(crate) const UNLOCKED: c_int = 0; +pub(crate) const LOCKED: c_int = 1; +pub(crate) const WAITING: c_int = 2; pub struct Mutex<T> { pub(crate) lock: AtomicLock, @@ -16,6 +16,39 @@ pub struct Mutex<T> { } unsafe impl<T: Send> Send for Mutex<T> {} unsafe impl<T: Send> Sync for Mutex<T> {} + +pub(crate) unsafe fn manual_try_lock_generic(word: &AtomicInt) -> bool { + word.compare_exchange(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed).is_ok() +} +pub(crate) unsafe fn manual_lock_generic(word: &AtomicInt) { + crate::sync::wait_until_generic( + word, + |lock| { + lock.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed) + .map(|_| AttemptStatus::Desired) + .unwrap_or_else(|e| match e { + WAITING => AttemptStatus::Waiting, + _ => AttemptStatus::Other, + }) + }, + |lock| match lock + // TODO: Ordering + .compare_exchange_weak(LOCKED, WAITING, Ordering::SeqCst, Ordering::SeqCst) + .unwrap_or_else(|e| e) + { + UNLOCKED => AttemptStatus::Desired, + WAITING => AttemptStatus::Waiting, + _ => AttemptStatus::Other, + }, + WAITING, + ); +} +pub(crate) unsafe fn manual_unlock_generic(word: &AtomicInt) { + if word.swap(UNLOCKED, Ordering::Release) == WAITING { + crate::sync::futex_wake(word, 1); + } +} + impl<T> Mutex<T> { /// Create a new mutex pub const fn new(content: T) -> Self { @@ -42,40 +75,22 @@ impl<T> Mutex<T> { /// on failure. You should probably not worry about this, it's used for /// internal optimizations. pub unsafe fn manual_try_lock(&self) -> Result<&mut T, c_int> { - self.lock - .compare_exchange(UNLOCKED, LOCKED, SeqCst, SeqCst) - .map(|_| &mut *self.content.get()) + if manual_try_lock_generic(&self.lock) { + Ok(&mut *self.content.get()) + } else { + Err(0) + } } /// Lock the mutex, returning the inner content. After doing this, it's /// your responsibility to unlock it after usage. Mostly useful for FFI: /// Prefer normal .lock() where possible. pub unsafe fn manual_lock(&self) -> &mut T { - self.lock.wait_until( - |lock| { - lock.compare_exchange_weak(UNLOCKED, LOCKED, SeqCst, SeqCst) - .map(|_| AttemptStatus::Desired) - .unwrap_or_else(|e| match e { - WAITING => AttemptStatus::Waiting, - _ => AttemptStatus::Other, - }) - }, - |lock| match lock - .compare_exchange_weak(LOCKED, WAITING, SeqCst, SeqCst) - .unwrap_or_else(|e| e) - { - UNLOCKED => AttemptStatus::Desired, - WAITING => AttemptStatus::Waiting, - _ => AttemptStatus::Other, - }, - WAITING, - ); + manual_lock_generic(&self.lock); &mut *self.content.get() } /// Unlock the mutex, if it's locked. pub unsafe fn manual_unlock(&self) { - if self.lock.swap(UNLOCKED, SeqCst) == WAITING { - self.lock.notify_one(); - } + manual_unlock_generic(&self.lock) } /// Tries to lock the mutex and returns a guard that automatically unlocks diff --git a/src/sync/once.rs b/src/sync/once.rs index 5118d866d9b3aba0265f751db90996701ab0f7cb..0073f51cc8d7b7a6cb5adbac769e76bd1299c1b9 100644 --- a/src/sync/once.rs +++ b/src/sync/once.rs @@ -1,14 +1,49 @@ use super::{AtomicLock, AttemptStatus}; use crate::platform::types::*; -use core::{cell::UnsafeCell, mem::MaybeUninit, sync::atomic::Ordering::SeqCst}; +use core::{cell::UnsafeCell, mem::MaybeUninit}; +use core::sync::atomic::{AtomicI32 as AtomicInt, Ordering::SeqCst}; const UNINITIALIZED: c_int = 0; const INITIALIZING: c_int = 1; const WAITING: c_int = 2; const INITIALIZED: c_int = 3; +pub(crate) fn call_once_generic(word: &AtomicInt, f: impl FnOnce()) { + match word.compare_and_swap(UNINITIALIZED, INITIALIZING, SeqCst) { + UNINITIALIZED => { + // We now have a lock, let's initiate things! + + // Mark the data as initialized + if word.swap(INITIALIZED, SeqCst) == WAITING { + // At least one thread is waiting on this to finish + crate::sync::futex_wake(word, i32::MAX); + } + } + INITIALIZING | WAITING => crate::sync::wait_until_generic( + word, + |lock| match lock.load(SeqCst) { + WAITING => AttemptStatus::Waiting, + INITIALIZED => AttemptStatus::Desired, + _ => AttemptStatus::Other, + }, + |lock| match lock + .compare_exchange_weak(INITIALIZING, WAITING, SeqCst, SeqCst) + .unwrap_or_else(|e| e) + { + WAITING => AttemptStatus::Waiting, + INITIALIZED => AttemptStatus::Desired, + _ => AttemptStatus::Other, + }, + WAITING, + ), + INITIALIZED => (), + _ => unreachable!("invalid state for Once<T>"), + } + +} + pub struct Once<T> { - status: AtomicLock, + status: AtomicInt, data: UnsafeCell<MaybeUninit<T>>, } unsafe impl<T: Send> Send for Once<T> {} @@ -16,47 +51,18 @@ unsafe impl<T: Send> Sync for Once<T> {} impl<T> Once<T> { pub const fn new() -> Self { Self { - status: AtomicLock::new(UNINITIALIZED), + status: AtomicInt::new(UNINITIALIZED), data: UnsafeCell::new(MaybeUninit::uninit()), } } + // FIXME: Isn't &mut UB? pub fn call_once<F>(&self, f: F) -> &mut T where F: FnOnce() -> T, { - match self - .status - .compare_and_swap(UNINITIALIZED, INITIALIZING, SeqCst) - { - UNINITIALIZED => { - // We now have a lock, let's initiate things! - let ret = unsafe { &mut *self.data.get() }.write(f()); - - // Mark the data as initialized - if self.status.swap(INITIALIZED, SeqCst) == WAITING { - // At least one thread is waiting on this to finish - self.status.notify_all(); - } - } - INITIALIZING | WAITING => self.status.wait_until( - |lock| match lock.load(SeqCst) { - WAITING => AttemptStatus::Waiting, - INITIALIZED => AttemptStatus::Desired, - _ => AttemptStatus::Other, - }, - |lock| match lock - .compare_exchange_weak(INITIALIZING, WAITING, SeqCst, SeqCst) - .unwrap_or_else(|e| e) - { - WAITING => AttemptStatus::Waiting, - INITIALIZED => AttemptStatus::Desired, - _ => AttemptStatus::Other, - }, - WAITING, - ), - INITIALIZED => (), - _ => unreachable!("invalid state for Once<T>"), - } + call_once_generic(&self.status, || { + unsafe { &mut *self.data.get() }.write(f()); + }); // At this point the data must be initialized! unsafe { &mut *(&mut *self.data.get()).as_mut_ptr() }