diff --git a/libc-test/build.rs b/libc-test/build.rs
index 76dea8e77c1a7..28e87669635be 100644
--- a/libc-test/build.rs
+++ b/libc-test/build.rs
@@ -449,6 +449,7 @@ fn test_apple(target: &str) {
             // OSX calls this something else
             "sighandler_t" => "sig_t".to_string(),
 
+            "_opaque_pthread_t" => format!("struct {}", ty),
             t if is_union => format!("union {}", t),
             t if t.ends_with("_t") => t.to_string(),
             t if is_struct => format!("struct {}", t),
@@ -4064,8 +4065,7 @@ fn test_linux(target: &str) {
             "epoll_params" => true,
 
             // FIXME(linux): Requires >= 6.12 kernel headers.
-            "dmabuf_cmsg" |
-            "dmabuf_token" => true,
+            "dmabuf_cmsg" | "dmabuf_token" => true,
 
             _ => false,
         }
diff --git a/libc-test/semver/apple.txt b/libc-test/semver/apple.txt
index 800d4a7996d0d..977cc021f29b8 100644
--- a/libc-test/semver/apple.txt
+++ b/libc-test/semver/apple.txt
@@ -1779,8 +1779,12 @@ __PTHREAD_MUTEX_SIZE__
 __PTHREAD_ONCE_SIZE__
 __PTHREAD_RWLOCKATTR_SIZE__
 __PTHREAD_RWLOCK_SIZE__
+__PTHREAD_SIZE__
 __darwin_mcontext64
+__darwin_pthread_handler_rec
+__darwin_pthread_t
 __error
+_opaque_pthread_t
 abs
 acct
 aio_cancel
diff --git a/src/unix/bsd/apple/b32/mod.rs b/src/unix/bsd/apple/b32/mod.rs
index 3753ffb085907..e1032b842f213 100644
--- a/src/unix/bsd/apple/b32/mod.rs
+++ b/src/unix/bsd/apple/b32/mod.rs
@@ -125,6 +125,7 @@ cfg_if! {
 #[deprecated(since = "0.2.55")]
 pub const NET_RT_MAXID: c_int = 10;
 
+pub const __PTHREAD_SIZE__: usize = 4088;
 pub const __PTHREAD_MUTEX_SIZE__: usize = 40;
 pub const __PTHREAD_COND_SIZE__: usize = 24;
 pub const __PTHREAD_CONDATTR_SIZE__: usize = 4;
diff --git a/src/unix/bsd/apple/b64/mod.rs b/src/unix/bsd/apple/b64/mod.rs
index 2bd682313428e..1c4989a1f7079 100644
--- a/src/unix/bsd/apple/b64/mod.rs
+++ b/src/unix/bsd/apple/b64/mod.rs
@@ -118,6 +118,7 @@ cfg_if! {
 #[deprecated(since = "0.2.55")]
 pub const NET_RT_MAXID: c_int = 11;
 
+pub const __PTHREAD_SIZE__: usize = 8176;
 pub const __PTHREAD_MUTEX_SIZE__: usize = 56;
 pub const __PTHREAD_COND_SIZE__: usize = 40;
 pub const __PTHREAD_CONDATTR_SIZE__: usize = 8;
diff --git a/src/unix/bsd/mod.rs b/src/unix/bsd/mod.rs
index 867898cec72cb..f55884a233f3c 100644
--- a/src/unix/bsd/mod.rs
+++ b/src/unix/bsd/mod.rs
@@ -5,7 +5,34 @@ pub type useconds_t = u32;
 pub type blkcnt_t = i64;
 pub type socklen_t = u32;
 pub type sa_family_t = u8;
-pub type pthread_t = crate::uintptr_t;
+
+cfg_if! {
+    if #[cfg(any(
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "tvos",
+        target_os = "watchos",
+        target_os = "visionos",
+    ))] {
+        pub type __darwin_pthread_t = *mut _opaque_pthread_t;
+        pub type pthread_t = __darwin_pthread_t;
+        s! {
+            pub struct __darwin_pthread_handler_rec {
+                __routine: Option<unsafe extern "C" fn(*mut c_void)>,
+                __arg: *mut c_void,
+                __next: *mut __darwin_pthread_handler_rec,
+            }
+            pub struct _opaque_pthread_t {
+                __sig: c_long,
+                __cleanup_stack: *mut __darwin_pthread_handler_rec,
+                __opaque: [c_char; __PTHREAD_SIZE__],
+            }
+        }
+    } else {
+        pub type pthread_t = crate::uintptr_t;
+    }
+}
+
 pub type nfds_t = c_uint;
 pub type regoff_t = off_t;