std/net,std/os: classify macOS as BSD for socket/fcntl constants

ober

bd3d97d764b1326431704d3c8eec6db0c900c444

diff --git a/lib/std/net/tcp.ss b/lib/std/net/tcp.ss
index 7d9f808..b7d9913 100644
--- a/lib/std/net/tcp.ss
+++ b/lib/std/net/tcp.ss
@@ -77,20 +77,35 @@
          (foreign-procedure "__errno_location" () void*)))))
   (def (get-errno) (foreign-ref 'int (c-errno-location) 0))
   (def EINTR 4)
-  (def *freebsd?* (memq (machine-type) '(a6fb ta6fb i3fb ti3fb arm64fb)))
-  (def EAGAIN (if *freebsd?* 35 11))
+  ;; macOS (Darwin) and FreeBSD share the BSD socket ABI: O_NONBLOCK=0x4,
+  ;; EAGAIN=35, SOL_SOCKET=0xffff, SO_REUSEADDR=4, and sockaddr_in carries a
+  ;; sin_len byte at offset 0. Linux differs on every one of these. Chez tags
+  ;; macOS machine-types with an "osx" suffix (e.g. tarm64osx); they were
+  ;; absent from the list below, so macOS silently used the LINUX constants.
+  ;; Worst effect: set-nonblocking! wrote O_EXCL(0x800), not O_NONBLOCK(0x4),
+  ;; leaving sockets BLOCKING — and a blocking c-read (a plain, non-
+  ;; __collect_safe foreign-procedure) then pins Chez's collector for the
+  ;; whole read, freezing every thread. (The errno probe above already
+  ;; treats osx as BSD; the socket constants just never matched.)
+  (def *bsd?*
+    (let ([mt (symbol->string (machine-type))])
+      (or (memq (machine-type) '(a6fb ta6fb i3fb ti3fb arm64fb))
+          (and (>= (string-length mt) 3)
+               (string=? (substring mt (- (string-length mt) 3)
+                                    (string-length mt))
+                         "osx")))))
+  (def EAGAIN (if *bsd?* 35 11))
 
   ;; fcntl constants
   (def F_GETFL 3)
   (def F_SETFL 4)
-  (def O_NONBLOCK
-    (if (memq (machine-type) '(a6fb ta6fb i3fb ti3fb arm64fb)) #x4 #x800))
+  (def O_NONBLOCK (if *bsd?* #x4 #x800))
 
   ;; Constants
   (def AF_INET 2)
   (def SOCK_STREAM 1)
-  (def SOL_SOCKET   (if *freebsd?* #xffff 1))
-  (def SO_REUSEADDR (if *freebsd?* 4 2))
+  (def SOL_SOCKET   (if *bsd?* #xffff 1))
+  (def SO_REUSEADDR (if *bsd?* 4 2))
   (def SOCKADDR_IN_SIZE 16)  ;; sizeof(struct sockaddr_in) on Linux
 
   ;; GC-safe retry delay: 10ms via Chez's sleep (not a foreign call).
@@ -112,9 +127,9 @@
           (foreign-set! 'unsigned-8 buf i 0)
           (lp (+ i 1))))
       ;; sin_family = AF_INET
-      ;; FreeBSD sockaddr_in has sin_len (uint8) at offset 0, sin_family (uint8) at offset 1
+      ;; BSD/Darwin sockaddr_in has sin_len (uint8) at offset 0, sin_family (uint8) at offset 1
       ;; Linux sockaddr_in has sin_family (uint16) at offset 0
-      (if *freebsd?*
+      (if *bsd?*
         (begin
           (foreign-set! 'unsigned-8 buf 0 16)        ;; sin_len = sizeof(sockaddr_in)
           (foreign-set! 'unsigned-8 buf 1 AF_INET))  ;; sin_family (uint8)
diff --git a/lib/std/os/fcntl.ss b/lib/std/os/fcntl.ss
index 1783011..fdcd813 100644
--- a/lib/std/os/fcntl.ss
+++ b/lib/std/os/fcntl.ss
@@ -54,10 +54,26 @@
   (def F_SETFL 4)
 
   ;; File status flags (F_GETFL/F_SETFL)
+  ;; macOS (Darwin), FreeBSD, and Linux use different fcntl flag bits.
+  ;; O_NONBLOCK/O_APPEND match between Darwin and FreeBSD, but O_CLOEXEC
+  ;; differs across all three (Darwin 0x1000000, FreeBSD 0x100000, Linux
+  ;; 0x80000). Chez tags macOS machine-types with an "osx" suffix (e.g.
+  ;; tarm64osx). Misclassifying macOS as Linux gave O_NONBLOCK=0x800 — which
+  ;; is Darwin's O_EXCL — so set-nonblocking! silently failed, leaving fds
+  ;; BLOCKING; a plain (non-__collect_safe) read on such an fd then pins
+  ;; Chez's collector for the whole read and freezes every thread.
   (def *freebsd?* (memq (machine-type) '(a6fb ta6fb i3fb ti3fb arm64fb)))
-  (def O_APPEND    (if *freebsd?* #x8      #x400))
-  (def O_NONBLOCK  (if *freebsd?* #x4      #x800))
-  (def O_CLOEXEC   (if *freebsd?* #x100000 #x80000))
+  (def *darwin?*
+    (let ([mt (symbol->string (machine-type))])
+      (and (>= (string-length mt) 3)
+           (string=? (substring mt (- (string-length mt) 3) (string-length mt))
+                     "osx"))))
+  (def *bsd?* (or *freebsd?* *darwin?*))
+  (def O_APPEND    (if *bsd?* #x8 #x400))
+  (def O_NONBLOCK  (if *bsd?* #x4 #x800))
+  (def O_CLOEXEC   (cond (*darwin?*  #x1000000)
+                        (*freebsd?* #x100000)
+                        (else       #x80000)))
 
   ;; File descriptor flags (F_GETFD/F_SETFD)
   (def FD_CLOEXEC 1)