
Although a future thread used an atomic compare-and-swap to set "is a list" or "not a list" flag on pairs via the JIT-implemented `list?', the hashing function in the runtime thread did not; as a result, it might be possible to lose a hash code due to cache inconsistency (although I'm not sure it's actually possible, and I couldn't trigger a problem with a test). Most of the changes are related to using an atomic compare-and-swap when setting a hash code, as well as clean-ups to related code. Processor-count tests avoid using atomic compare-and-swap on uniprocessors, which might not support the relevant machine instructions. As significantly, the compare-and-swap operation for the JIT-implemented `list?' did not actually set flags on a pair that has a hash code. This could lead to `list?' tests that were not constant time (but only if the relevant pair's `eq?' hash code had been used previously).
31 lines
944 B
Racket
31 lines
944 B
Racket
#lang racket
|
|
(require racket/future)
|
|
|
|
;; This test tries to trigger race conditions between computing an eq
|
|
;; hash code in the runtime thread and setting "is a list" flags in a
|
|
;; future thread. It also effectively checks that `list?' is a
|
|
;; constant-time operation (i.e., that "is a list" flags are set
|
|
;; correctly), since it uses a long chain of pairs.
|
|
|
|
(define N 1000000)
|
|
|
|
(define v (make-vector N null))
|
|
(for ([i N])
|
|
(vector-set! v i (cons i (vector-ref v (max 0 (sub1 i))))))
|
|
|
|
(define v2 (make-vector (vector-length v)))
|
|
(define f (future (lambda ()
|
|
(for/and ([a (in-vector v)])
|
|
(and (car a) (list? a))))))
|
|
|
|
(for ([i (vector-length v)])
|
|
(let ([a (vector-ref v i)])
|
|
(when (car a)
|
|
(vector-set! v2 i (eq-hash-code a)))))
|
|
|
|
(unless (touch f) (error "future fail?"))
|
|
|
|
(for ([i (vector-length v)])
|
|
(unless (eq? (vector-ref v2 i) (eq-hash-code (vector-ref v i)))
|
|
(error "fail")))
|