cs: use new $record-ref, etc., primitive

Also, speed up hashing and logging a little by adjusting semaphores to
succeed with `$record-cas!` when no waiting is necessary.
This commit is contained in:
Matthew Flatt 2019-04-08 11:13:01 +02:00
parent 39c67f8b6a
commit d87be8789e
11 changed files with 94 additions and 57 deletions

View File

@ -12,7 +12,7 @@
(define collection 'multi) (define collection 'multi)
(define version "7.2.0.12") (define version "7.2.0.13")
(define deps `("racket-lib" (define deps `("racket-lib"
["racket" #:version ,version])) ["racket" #:version ,version]))

View File

@ -2,7 +2,8 @@
;; Mutable queue ;; Mutable queue
(provide make-queue (provide queue
make-queue
queue-empty? queue-empty?
queue-remove! queue-remove!
queue-fremove! queue-fremove!

View File

@ -53,6 +53,7 @@
(error 'eq-on-flonum "no"))))) (error 'eq-on-flonum "no")))))
(check-defined 'procedure-known-single-valued?) (check-defined 'procedure-known-single-valued?)
(check-defined 'compress-format) (check-defined 'compress-format)
(check-defined '#%$record-cas!)
;; ---------------------------------------- ;; ----------------------------------------

View File

@ -483,10 +483,10 @@
(let ([vec (locked-iterable-hash-cells ht)]) (let ([vec (locked-iterable-hash-cells ht)])
(cond (cond
[(and vec [(and vec
(let ([len (#%vector-length vec)] (fixnum? i)
[want-len (or i 0)]) (let ([len (#%vector-length vec)])
(or (> len want-len) (or (fx> len i)
(and (fx= len want-len) (and (fx= len i)
(not (locked-iterable-hash-retry? ht)))))) (not (locked-iterable-hash-retry? ht))))))
(lock-release (locked-iterable-hash-lock ht)) (lock-release (locked-iterable-hash-lock ht))
vec] vec]
@ -499,7 +499,7 @@
0) 0)
32))]) 32))])
(let ([len (#%vector-length new-vec)]) (let ([len (#%vector-length new-vec)])
(when (= len (hash-count ht)) (when (fx= len (hash-count ht))
(set-locked-iterable-hash-retry?! ht #f)) (set-locked-iterable-hash-retry?! ht #f))
(when weak? (when weak?
(let loop ([i 0]) (let loop ([i 0])
@ -653,20 +653,20 @@
p)) p))
'(#!bwp . #!bwp))] '(#!bwp . #!bwp))]
[key (car p)] [key (car p)]
[v (if (bwp-object? key) [v (cdr p)])
none (if (or (bwp-object? key)
(cdr p))]) (bwp-object? v))
(if (eq? v none)
(if (eq? bad-index-v none) (if (eq? bad-index-v none)
(raise-arguments-error who "no element at index" (raise-arguments-error who "no element at index"
"index" i) "index" i)
(bad-index-result key? value? pair? bad-index-v)) (bad-index-result key? value? pair? bad-index-v))
(cond (cond
[(and key? value?) [key?
(if value?
(if pair? (if pair?
(cons key v) (cons key v)
(values key v))] (values key v))
[key? key] key)]
[else v])))] [else v])))]
[(and (impersonator? ht) [(and (impersonator? ht)
(authentic-hash? (impersonator-val ht))) (authentic-hash? (impersonator-val ht)))

View File

@ -2,4 +2,3 @@
;; and other representation details ;; and other representation details
(define bytevector-content-offset 9) (define bytevector-content-offset 9)
(define vector-content-offset (if (> (fixnum-width) 32) 9 5)) (define vector-content-offset (if (> (fixnum-width) 32) 9 5))
(define record-content-offset vector-content-offset)

View File

@ -974,9 +974,9 @@
(putprop (record-type-uid rtd) 'guards new-guards)))))) (putprop (record-type-uid rtd) 'guards new-guards))))))
(define (unsafe-struct*-ref s i) (define (unsafe-struct*-ref s i)
(#%$object-ref 'scheme-object s (fx+ record-content-offset (fx* i (foreign-sizeof 'void*))))) (#%$record-ref s i))
(define (unsafe-struct*-set! s i v) (define (unsafe-struct*-set! s i v)
(#%$object-set! 'scheme-object s (fx+ record-content-offset (fx* i (foreign-sizeof 'void*))) v)) (#%$record-set! s i v))
(define (unsafe-struct? v r) (define (unsafe-struct? v r)
(#3%record? v r)) (#3%record? v r))

View File

@ -79,7 +79,7 @@
(define unsafe-vector*-cas! (unsafe-primitive vector-cas!)) (define unsafe-vector*-cas! (unsafe-primitive vector-cas!))
(define (unsafe-struct*-cas! s k old new) (define (unsafe-struct*-cas! s k old new)
(#%vector-cas! s k old new)) (#3%$record-cas! s k old new))
(define unsafe-unbox* (unsafe-primitive unbox)) (define unsafe-unbox* (unsafe-primitive unbox))
(define unsafe-set-box*! (unsafe-primitive set-box!)) (define unsafe-set-box*! (unsafe-primitive set-box!))

View File

@ -171,8 +171,8 @@
(|#%app| (|#%app| 1/exit-handler) v))) (|#%app| (|#%app| 1/exit-handler) v)))
(set-scheduler-lock-callbacks! (lambda () (1/make-semaphore 1)) (set-scheduler-lock-callbacks! (lambda () (1/make-semaphore 1))
1/semaphore-wait unsafe-semaphore-wait
1/semaphore-post) unsafe-semaphore-post)
(set-scheduler-atomicity-callbacks! (lambda () (set-scheduler-atomicity-callbacks! (lambda ()
(current-atomic (fx+ (current-atomic) 1))) (current-atomic (fx+ (current-atomic) 1)))

View File

@ -13,12 +13,12 @@
consistently.) consistently.)
*/ */
#define MZSCHEME_VERSION "7.2.0.12" #define MZSCHEME_VERSION "7.2.0.13"
#define MZSCHEME_VERSION_X 7 #define MZSCHEME_VERSION_X 7
#define MZSCHEME_VERSION_Y 2 #define MZSCHEME_VERSION_Y 2
#define MZSCHEME_VERSION_Z 0 #define MZSCHEME_VERSION_Z 0
#define MZSCHEME_VERSION_W 12 #define MZSCHEME_VERSION_W 13
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y) #define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W) #define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)

View File

@ -69,6 +69,8 @@
semaphore-wait/enable-break semaphore-wait/enable-break
call-with-semaphore call-with-semaphore
call-with-semaphore/enable-break call-with-semaphore/enable-break
unsafe-semaphore-post
unsafe-semaphore-wait
semaphore-peek-evt semaphore-peek-evt
semaphore-peek-evt? semaphore-peek-evt?

View File

@ -1,5 +1,6 @@
#lang racket/base #lang racket/base
(require "check.rkt" (require racket/unsafe/ops
"check.rkt"
"../common/queue.rkt" "../common/queue.rkt"
"internal-error.rkt" "internal-error.rkt"
"atomic.rkt" "atomic.rkt"
@ -22,14 +23,17 @@
semaphore-post/atomic semaphore-post/atomic
semaphore-wait/atomic semaphore-wait/atomic
semaphore-post-all/atomic) semaphore-post-all/atomic
(struct semaphore ([count #:mutable] unsafe-semaphore-post
queue) unsafe-semaphore-wait)
(struct semaphore queue ([count #:mutable]) ; -1 => non-empty queue
#:property #:property
prop:evt prop:evt
(poller (lambda (s poll-ctx) (poller (lambda (s poll-ctx)
(semaphore-wait/poll s poll-ctx)))) (semaphore-wait/poll s poll-ctx))))
(define count-field-pos 2) ; used with `unsafe-struct*-cas!`
(struct semaphore-peek-evt (sema) (struct semaphore-peek-evt (sema)
#:property #:property
@ -51,24 +55,37 @@
(number->string init) (number->string init)
" is too large") " is too large")
(current-continuation-marks)))) (current-continuation-marks))))
(semaphore init (make-queue))) (semaphore #f #f init))
;; ---------------------------------------- ;; ----------------------------------------
(define/who (semaphore-post s) (define/who (semaphore-post s)
(check who semaphore? s) (check who semaphore? s)
(atomically (semaphore-post/atomic s))) (unsafe-semaphore-post s))
(define (unsafe-semaphore-post s)
(define c (if (impersonator? s)
-1
(semaphore-count s)))
(cond
[(and (c . >= . 0)
(unsafe-struct*-cas! s count-field-pos c (add1 c)))
(void)]
[else
(atomically (semaphore-post/atomic s))]))
;; In atomic mode: ;; In atomic mode:
(define (semaphore-post/atomic s) (define (semaphore-post/atomic s)
(assert-atomic-mode) (assert-atomic-mode)
(let loop () (let loop ()
(define w (queue-remove! (semaphore-queue s))) (define w (queue-remove! s))
(cond (cond
[(not w) [(not w)
(set-semaphore-count! s (add1 (semaphore-count s)))] (set-semaphore-count! s (add1 (semaphore-count s)))]
[else [else
(waiter-resume! w s) (waiter-resume! w s)
(when (queue-empty? s)
(set-semaphore-count! s 0)) ; allow CAS again
(when (semaphore-peek-select-waiter? w) (when (semaphore-peek-select-waiter? w)
;; Don't consume a post for a peek waiter ;; Don't consume a post for a peek waiter
(loop))]))) (loop))])))
@ -77,7 +94,7 @@
(define (semaphore-post-all/atomic s) (define (semaphore-post-all/atomic s)
(set-semaphore-count! s +inf.0) (set-semaphore-count! s +inf.0)
(queue-remove-all! (queue-remove-all!
(semaphore-queue s) s
(lambda (w) (waiter-resume! w s)))) (lambda (w) (waiter-resume! w s))))
(define (semaphore-post-all s) (define (semaphore-post-all s)
@ -87,7 +104,7 @@
;; In atomic mode: ;; In atomic mode:
(define (semaphore-any-waiters? s) (define (semaphore-any-waiters? s)
(assert-atomic-mode) (assert-atomic-mode)
(not (queue-empty? (semaphore-queue s)))) (not (queue-empty? s)))
;; ---------------------------------------- ;; ----------------------------------------
@ -104,6 +121,17 @@
(define/who (semaphore-wait s) (define/who (semaphore-wait s)
(check who semaphore? s) (check who semaphore? s)
(unsafe-semaphore-wait s))
(define (unsafe-semaphore-wait s)
(define c (if (impersonator? s)
-1
(semaphore-count s)))
(cond
[(and (positive? c)
(unsafe-struct*-cas! s count-field-pos c (sub1 c)))
(void)]
[else
((atomically ((atomically
(define c (semaphore-count s)) (define c (semaphore-count s))
(cond (cond
@ -112,18 +140,21 @@
void] void]
[else [else
(define w (current-thread)) (define w (current-thread))
(define q (semaphore-queue s)) (define n (queue-add! s w))
(define n (queue-add! q w)) (set-semaphore-count! s -1) ; so CAS not tried for `semaphore-post`
(waiter-suspend! (waiter-suspend!
w w
;; On break/kill/suspend: ;; On break/kill/suspend:
(lambda () (queue-remove-node! q n)) (lambda ()
(queue-remove-node! s n)
(when (queue-empty? s)
(set-semaphore-count! s 0))) ; allow CAS again
;; This callback is used, in addition to the previous one, if ;; This callback is used, in addition to the previous one, if
;; the thread receives a break signal but doesn't escape ;; the thread receives a break signal but doesn't escape
;; (either because breaks are disabled or the handler ;; (either because breaks are disabled or the handler
;; continues), if if the interrupt was to suspend and the thread ;; continues), if if the interrupt was to suspend and the thread
;; is resumed: ;; is resumed:
(lambda () (semaphore-wait s)))])))) (lambda () (semaphore-wait s)))])))]))
;; In atomic mode ;; In atomic mode
(define (semaphore-wait/poll s poll-ctx (define (semaphore-wait/poll s poll-ctx
@ -144,8 +175,8 @@
(define w (if peek? (define w (if peek?
(semaphore-peek-select-waiter (poll-ctx-select-proc poll-ctx)) (semaphore-peek-select-waiter (poll-ctx-select-proc poll-ctx))
(select-waiter (poll-ctx-select-proc poll-ctx)))) (select-waiter (poll-ctx-select-proc poll-ctx))))
(define q (semaphore-queue s)) (define n (queue-add! s w))
(define n (queue-add! q w)) (set-semaphore-count! s -1) ; so CAS not tried for `semaphore-post`
;; Replace with `async-evt`, but the `sema-waiter` can select the ;; Replace with `async-evt`, but the `sema-waiter` can select the
;; event through a callback. Pair the event with a nack callback ;; event through a callback. Pair the event with a nack callback
;; to get back out of line. ;; to get back out of line.
@ -154,7 +185,9 @@
(control-state-evt async-evt (control-state-evt async-evt
(lambda () (lambda ()
(assert-atomic-mode) (assert-atomic-mode)
(queue-remove-node! q n)) (queue-remove-node! s n)
(when (queue-empty? s)
(set-semaphore-count! s 0))) ; allow CAS again
void void
(lambda () (lambda ()
;; Retry: decrement or requeue ;; Retry: decrement or requeue
@ -166,7 +199,8 @@
(set-semaphore-count! s (sub1 c))) (set-semaphore-count! s (sub1 c)))
(values result #t)] (values result #t)]
[else [else
(set! n (queue-add! q w)) (set! n (queue-add! s w))
(set-semaphore-count! s -1) ; so CAS not tried for `semaphore-post`
(values #f #f)]))) (values #f #f)])))
(lambda (v) result)))])) (lambda (v) result)))]))