Subject: bug#70474: Possible bug with `atomic-box-swap!` on OSX/M3 (?!?!)

From: Tony Garnock-Jones <[email-masked]>
Date: Fri, 19 Apr 2024 12:54:32 +0200

Hello all,

I'm seeing some very strange behaviour from `atomic-box-swap!` (but not 
`atomic-box-compare-and-swap!`) on Guile 3.0.9 from Homebrew on OSX 
Sonoma using an M3 Pro cpu. The issue does not seem to manifest on 
x86_64. Could it be some interaction between Guile and M3 CPUs?

Or am I just doing something very silly that shouldn't work at all and 
just happens to look like it works on x86_64?

Here's the program that fails. It will run for a few hundred million 
rounds and then yield "q null in get". Note that using CAS seems to 
work, but plain old swap doesn't.

;;--

;; Eventually this fails with "q null in get" if `atomic-box-swap!` is
;; used where marked (*) below. It takes usually between hundreds of
;; millions and a few billion increments to fail.
;;
;; It does NOT fail if the line marked (*) is commented out and the line
;; below it mentioning `atomic-box-compare-and-swap!` is uncommented and
;; used instead.
;;
;; The failure happens on OSX Sonoma 14.4.1 on a MacBook Pro running an
;; M3 Pro CPU using Guile version 3.0.9 from Homebrew as of 2024-04-17.
;;
;; It does NOT happen on AMD x86_64 Debian linux with Guile 3.0.9 from
;; Debian packaging.

(use-modules (ice-9 atomic))

(define r (make-atomic-box '(0)))

(let loop ()
   (let ((v (let ((q (atomic-box-ref r)))
              (when (null? q) (error "q null in get"))
              (unless (eq? (atomic-box-compare-and-swap! r q (cdr q)) q)
                (error "CAS failed in get"))
              (car q))))

     (when (zero? (remainder v 10000000)) (write v) (newline))

     (unless (null?
              (atomic-box-swap! r (list (+ v 1))) ;; (*)
              ;; (atomic-box-compare-and-swap! r '() (list (+ v 1)))
              )
       (error "swap failed in put"))

     (loop)))