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<&timespec> = 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<&timespec>) -> 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() }