5 (macrolet ((test (init op
)
6 `(with-test (:name
(:cas
:basics
,(intern (symbol-name op
) "KEYWORD")))
10 (assert (eql nil
(compare-and-swap (,op x
) nil y
)))
11 (assert (eql y
(compare-and-swap (,op x
) nil z
)))
12 (assert (eql y
(,op x
)))
13 (let ((x (eval "foo"))) ; hide the compile-time type error
14 (multiple-value-bind (res err
)
15 (ignore-errors (compare-and-swap (,op x
) nil nil
))
17 (error "Wanted NIL and type-error, got: ~S" res
))
18 (assert (typep err
'type-error
))))))))
19 (test (cons nil
:no
) car
)
20 (test (cons nil
:no
) first
)
21 (test (cons :no nil
) cdr
)
22 (test (cons :no nil
) rest
)
23 (test '.foo. symbol-plist
)
24 (test (progn (set '.bar. nil
) '.bar.
) symbol-value
)
25 (test (make-xxx) xxx-yyy
))
29 ;;; thread-local bindings
31 (with-test (:name
(:cas
:tls
))
34 (assert (eql nil
(compare-and-swap (symbol-value '*foo
*) nil t
)))
35 (assert (eql t
(compare-and-swap (symbol-value '*foo
*) nil
:foo
)))
36 (assert (eql t
*foo
*)))
37 (assert (eql 42 *foo
*))))
39 ;;; unbound symbols + symbol-value
41 (assert (not (boundp '*foo
*)))
43 (with-test (:name
(:cas
:unbound
))
44 (multiple-value-bind (res err
)
45 (ignore-errors (compare-and-swap (symbol-value '*foo
*) nil t
))
47 (assert (typep err
'unbound-variable
))))
51 (with-test (:name
(:cas
:unbound
2))
54 (multiple-value-bind (res err
)
55 (ignore-errors (compare-and-swap (symbol-value '*bar
*) nil t
))
57 (assert (typep err
'unbound-variable
)))))
61 (defvar *v
* (vector 1))
64 (with-test (:name
(:cas
:svref
))
65 (assert (eql 1 (compare-and-swap (svref *v
* 0) 1 2)))
66 (assert (eql 2 (compare-and-swap (svref *v
* 0) 1 3)))
67 (assert (eql 2 (svref *v
* 0))))
70 (with-test (:name
(:cas
:svref
:bounds
))
71 (multiple-value-bind (res err
)
72 (ignore-errors (compare-and-swap (svref *v
* -
1) 1 2))
74 (assert (typep err
'type-error
)))
75 (multiple-value-bind (res err
)
76 (ignore-errors (compare-and-swap (svref *v
* 1) 1 2))
78 (assert (typep err
'type-error
))))
80 ;; type of the first argument
81 (with-test (:name
(:cas
:svref
:type
))
82 (multiple-value-bind (res err
)
83 (ignore-errors (compare-and-swap (svref (eval "foo") 1) 1 2))
85 (assert (typep err
'type-error
))))
87 ;; Check that we don't modify constants
88 (defconstant +a-constant
+ 42)
89 (with-test (:name
(:cas
:symbol-value
:constant-modification
))
93 (sb-ext:compare-and-swap
(symbol-value '+a-constant
+) 42 13)
95 (let ((name '+a-constant
+))
99 (sb-ext:compare-and-swap
(symbol-value name
) 42 13)
100 (error () :error
))))))
102 ;; Check that we don't mess declaimed types
103 (declaim (boolean *a-boolean
*))
104 (defparameter *a-boolean
* t
)
105 (with-test (:name
(:cas
:symbol-value
:type-checking
))
109 (sb-ext:compare-and-swap
(symbol-value '*a-boolean
*) t
(eval 42))
111 (let ((name '*a-boolean
*))
115 (sb-ext:compare-and-swap
(symbol-value name
) t
(eval 42))
116 (error () :error
))))))
118 ;;;; ATOMIC-INCF and ATOMIC-DECF (we should probably rename this file atomic-ops...)
121 (word 0 :type sb-vm
:word
))
123 ;; Have the following tests check that CAS access to the superclass
124 ;; works in the presence of a subclass sharing the conc-name.
125 (defstruct (subbox (:include box
) (:conc-name
"BOX-")))
127 (defun inc-box (box n
)
128 (declare (fixnum n
) (box box
))
130 do
(sb-ext:atomic-incf
(box-word box
))))
132 (defun dec-box (box n
)
133 (declare (fixnum n
) (box box
))
135 do
(sb-ext:atomic-decf
(box-word box
))))
137 (with-test (:name
:atomic-incf
/decf
)
138 (let ((box (make-box)))
140 (assert (= 10000 (box-word box
)))
142 (assert (= 0 (box-word box
)))))
144 (with-test (:name
:atomic-incf-wraparound
)
145 (let ((box (make-box :word sb-ext
:most-positive-word
)))
146 (sb-ext:atomic-incf
(box-word box
) 2)
147 (assert (= 1 (box-word box
)))))
149 (with-test (:name
:atomic-decf-wraparound
)
150 (let ((box (make-box :word
0)))
151 (sb-ext:atomic-decf
(box-word box
) 2)
152 (assert (= (- (ash 1 sb-vm
:n-word-bits
) 2) (box-word box
)))))
154 (with-test (:name
:cas-raw-instance-ref-word
155 :skipped-on
(not (or :x86
:x86-64
)))
156 (let ((foo (make-box :word
42)))
157 ;; basic smoke test - not checking for atomicity or anything
158 (assert (eql (cas (box-word foo
) 42 43) 42))
159 (assert (eql (cas (box-word foo
) 43 44) 43))))
161 (with-test (:name
:atomic-incf-full-call-lp1381867
162 :skipped-on
(not (or :x86
:x86-64
:ppc
)))
163 ;; contortions to avoid reader errors
164 (let* ((%riai
/w
(intern "%RAW-INSTANCE-ATOMIC-INCF/WORD" "SB-KERNEL"))
167 ;; Rebind %RAW-INSTANCE-ATOMIC-INCF/WORD as a local
168 ;; function. Declaring it locally notinline fails because
169 ;; it is marked with the ALWAYS-TRANSLATABLE attribute, so
170 ;; it's a bug to call it even though we've asked to call
171 ;; it. (Maybe that's a bug?) And I don't want to call it
172 ;; explictly - I want the macro to do it so that I don't
173 ;; have to inject any of the sign masking noise and such.
174 (declare (disable-package-locks ,%riai
/w
))
175 (let ((b (make-box :word
0))
176 (delta (- (ash 1 (1- sb-vm
:n-word-bits
))))
177 (f (fdefinition ',%riai
/w
)))
178 (flet ((,%riai
/w
(a b c
) (funcall f a b c
)))
179 (assert (= (atomic-incf (box-word b
) delta
) 0))
180 (assert (= (atomic-incf (box-word b
) delta
)
181 (ash 1 (1- sb-vm
:n-word-bits
))))
182 (assert (= (box-word b
) 0))
183 (atomic-decf (box-word b
))
184 (assert (= (box-word b
) sb-ext
:most-positive-word
)))))))
188 (with-test (:name
(:atomic-incf
/decf
:threads
))
189 (let* ((box (make-box))
190 (threads (loop repeat
64
191 collect
(sb-thread:make-thread
(lambda ()
196 :name
"inc/dec thread"))))
197 (mapc #'sb-thread
:join-thread threads
)
198 (assert (= 0 (box-word box
)))))
200 (defglobal **my-atomic-counter
* 0)
201 (declaim (fixnum **my-atomic-counter
*))
202 ;; Assert that safe (atomic-incf car) type-checks the car.
203 (with-test (:name
:atomic-incf-car-safe
)
204 (let ((x (cons (1+ most-positive-fixnum
) 0))) ; a bignum
205 (assert (eq (handler-case (atomic-incf (car x
))
206 (type-error () 'win
)) 'win
))))
208 ;; Basic correctness tests, not testing atomicity
212 ;; using a constant for the delta
213 (assert (eq (atomic-incf ,place
2) 0))
214 (assert (eq ,place
2))
215 (assert (eq (atomic-incf ,place -
1) 2))
216 (assert (eq ,place
1))
217 (assert (eq (atomic-decf ,place
1) 1))
218 (assert (eq ,place
0))
219 ;; using a non-constant for the delta
220 (assert (eq (atomic-incf ,place
(eval 2)) 0))
221 (assert (eq ,place
2))
222 (assert (eq (atomic-incf ,place
(eval -
1)) 2))
223 (assert (eq ,place
1))
224 (assert (eq (atomic-decf ,place
(eval 1)) 1))
225 (assert (eq ,place
0))
226 (setf ,place most-positive-fixnum
)
228 (assert (eq ,place most-negative-fixnum
))
230 (assert (eq ,place most-positive-fixnum
)))))
231 (with-test (:name
(:atomic-incf
:global-var
))
232 (test-place **my-atomic-counter
*))
233 (with-test (:name
(:atomic-incf
:car
))
234 (let ((x (cons 0 'foo
)))
235 (test-place (car x
))))
236 (with-test (:name
(:atomic-incf
:cdr
))
237 (let ((x (cons 'foo
0)))
238 (test-place (cdr x
))))
239 ;; Fast code for (atomic-{incf|decf} {car|cdr}) is decidedly unsafe
240 ;; on x86-64. Ensure basic correctness when used correctly.
241 (with-test (:name
(:atomic-incf-fast
:car
))
242 (let ((x (cons 0 'foo
)))
243 (declare (optimize (safety 0)))
244 (test-place (car x
))))
245 (with-test (:name
(:atomic-incf-fast
:cdr
))
246 (let ((x (cons 'foo
0)))
247 (declare (optimize (safety 0)))
248 (test-place (cdr x
)))))
250 ;;; STANDARD-INSTANCE-ACCESS, FUNCALLABLE-STANDARD-INSTANCE-ACCESS
252 (defclass sia-cas-test
()
256 (with-test (:name
(:cas
:standard-instance-access
))
257 (flet ((slot-loc (slot class
)
258 (sb-mop:slot-definition-location
259 (find slot
(sb-mop:class-slots class
) :key
#'sb-mop
:slot-definition-name
))))
260 (let* ((class (find-class 'sia-cas-test
))
261 (instance (make-instance class
:a
'a
:b
'b
))
262 (a-loc (slot-loc 'a class
))
263 (b-loc (slot-loc 'b class
)))
264 (assert (eq 'a
(slot-value instance
'a
)))
265 (assert (eq 'a
(compare-and-swap (sb-mop:standard-instance-access instance a-loc
)
267 (assert (eq 'a
(sb-mop:standard-instance-access instance a-loc
)))
268 (assert (eq 'a
(compare-and-swap (sb-mop:standard-instance-access instance a-loc
)
270 (assert (eq 'a2
(sb-mop:standard-instance-access instance a-loc
)))
271 (assert (eq 'a2
(slot-value instance
'a
)))
272 (assert (eq 'b
(slot-value instance
'b
)))
273 (assert (eq 'b
(sb-mop:standard-instance-access instance b-loc
))))))
275 (defclass fia-cas-test
(sb-mop:funcallable-standard-object
)
278 (:metaclass sb-mop
:funcallable-standard-class
))
280 (with-test (:name
(:cas
:standard-instance-access
))
281 (flet ((slot-loc (slot class
)
282 (sb-mop:slot-definition-location
283 (find slot
(sb-mop:class-slots class
) :key
#'sb-mop
:slot-definition-name
))))
284 (let* ((class (find-class 'fia-cas-test
))
285 (instance (make-instance class
:a
'a
:b
'b
))
286 (a-loc (slot-loc 'a class
))
287 (b-loc (slot-loc 'b class
)))
288 (sb-mop:set-funcallable-instance-function instance
(lambda () :ok
))
289 (eq :ok
(funcall instance
))
290 (assert (eq 'a
(slot-value instance
'a
)))
291 (assert (eq 'a
(compare-and-swap
292 (sb-mop:funcallable-standard-instance-access instance a-loc
)
294 (assert (eq 'a
(sb-mop:funcallable-standard-instance-access instance a-loc
)))
295 (assert (eq 'a
(compare-and-swap
296 (sb-mop:funcallable-standard-instance-access instance a-loc
)
298 (assert (eq 'a2
(sb-mop:funcallable-standard-instance-access instance a-loc
)))
299 (assert (eq 'a2
(slot-value instance
'a
)))
300 (assert (eq 'b
(slot-value instance
'b
)))
301 (assert (eq 'b
(sb-mop:funcallable-standard-instance-access instance b-loc
))))))
305 (defclass standard-thing
()
309 (defmethod slot-unbound ((class standard-class
) (obj standard-thing
) slot
)
310 (list :unbound slot
))
312 (defmethod slot-missing ((class standard-class
) (obj standard-thing
) slot op
&optional val
)
313 (list :missing slot op val
))
315 (with-test (:name
(:cas
:slot-value
:standard-object
))
316 (let ((x (make-instance 'standard-thing
)))
317 (assert (eql 42 (slot-value x
'x
)))
318 (assert (eql 42 (compare-and-swap (slot-value x
'x
) 0 :foo
)))
319 (assert (eql 42 (slot-value x
'x
)))
320 (assert (eql 42 (compare-and-swap (slot-value x
'x
) 42 :foo
)))
321 (assert (eql :foo
(slot-value x
'x
)))))
323 (with-test (:name
(:cas
:slot-value
:slot-unbound
))
324 (let ((x (make-instance 'standard-thing
)))
325 (assert (equal '(:unbound y
) (slot-value x
'y
)))
326 (assert (equal '(:unbound y
) (compare-and-swap (slot-value x
'y
) 0 :foo
)))
327 (assert (equal '(:unbound y
) (slot-value x
'y
)))
328 (assert (eq sb-pcl
:+slot-unbound
+
329 (compare-and-swap (slot-value x
'y
) sb-pcl
:+slot-unbound
+ :foo
)))
330 (assert (eq :foo
(slot-value x
'y
)))))
332 (with-test (:name
(:cas
:slot-value
:slot-missing
))
333 (let ((x (make-instance 'standard-thing
)))
334 (assert (equal '(:missing z slot-value nil
) (slot-value x
'z
)))
335 (assert (equal '(:missing z sb-ext
:cas
(0 :foo
)) (compare-and-swap (slot-value x
'z
) 0 :foo
)))
336 (assert (equal '(:missing z slot-value nil
) (slot-value x
'z
)))))
338 (defclass non-standard-class
(standard-class)
341 (defmethod sb-mop:validate-superclass
((class non-standard-class
) (superclass standard-class
))
344 (defclass non-standard-thing-0
()
346 (:metaclass non-standard-class
))
348 (defclass non-standard-thing-1
()
350 (:metaclass non-standard-class
))
352 (defclass non-standard-thing-2
()
354 (:metaclass non-standard-class
))
356 (defclass non-standard-thing-3
()
358 (:metaclass non-standard-class
))
360 (defvar *access-list
* nil
)
362 (defmethod sb-mop:slot-value-using-class
363 ((class non-standard-class
) (obj non-standard-thing-1
) slotd
)
364 (let ((v (call-next-method)))
365 (push :read
*access-list
*)
368 (defmethod (setf sb-mop
:slot-value-using-class
)
369 (value (class non-standard-class
) (obj non-standard-thing-2
) slotd
)
370 (let ((v (call-next-method)))
371 (push :write
*access-list
*)
374 (defmethod sb-mop:slot-boundp-using-class
375 ((class non-standard-class
) (obj non-standard-thing-3
) slotd
)
376 (let ((v (call-next-method)))
377 (push :boundp
*access-list
*)
380 (with-test (:name
(:cas
:slot-value
:non-standard-object
:standard-access
))
381 (let ((x (make-instance 'non-standard-thing-0
)))
382 (assert (eql 13 (slot-value x
'x
)))
383 (assert (eql 13 (compare-and-swap (slot-value x
'x
) 0 :bar
)))
384 (assert (eql 13 (slot-value x
'x
)))
385 (assert (eql 13 (compare-and-swap (slot-value x
'x
) 13 :bar
)))
386 (assert (eql :bar
(slot-value x
'x
)))))
388 (with-test (:name
(:cas
:slot-value
:non-standard-object
:slot-value-using-class
))
389 (setf *access-list
* nil
)
390 (let ((x (make-instance 'non-standard-thing-1
)))
391 (declare (notinline slot-value
))
392 (assert (null *access-list
*))
393 (assert (eql 13 (slot-value x
'x
)))
394 (assert (equal '(:read
) *access-list
*))
397 (compare-and-swap (slot-value x
'x
) 0 :bar
)
399 (assert (eql 13 (slot-value x
'x
)))
400 (assert (equal '(:read
:read
) *access-list
*))))
402 (with-test (:name
(:cas
:slot-value
:non-standard-object
:setf-slot-value-using-class
))
403 (setf *access-list
* nil
)
404 (let ((x (make-instance 'non-standard-thing-2
)))
405 (assert (equal '(:write
) *access-list
*))
406 (assert (eql 13 (slot-value x
'x
)))
407 (assert (equal '(:write
) *access-list
*))
410 (compare-and-swap (slot-value x
'x
) 0 :bar
)
412 (assert (eql 13 (slot-value x
'x
)))
413 (assert (equal '(:write
) *access-list
*))))
415 (with-test (:name
(:cas
:slot-value
:non-standard-object
:slot-boundp-using-class
))
416 (setf *access-list
* nil
)
417 (let ((x (make-instance 'non-standard-thing-3
)))
418 (assert (equal '(:boundp
) *access-list
*))
419 (assert (eql 13 (slot-value x
'x
)))
422 (compare-and-swap (slot-value x
'x
) 0 :bar
)
424 (assert (eql 13 (slot-value x
'x
)))))
431 (defun (cas foo
) (old new
)
432 (cas (symbol-value '*foo
*) old new
))
434 (with-test (:name
(:cas
:defun
))
435 (assert (null (foo)))
436 (assert (null (cas (foo) nil t
)))
437 (assert (eq t
(foo)))
438 (assert (eq t
(cas (foo) nil
:oops
)))
439 (assert (eq t
(foo))))
441 (with-test (:name
(:cas
:flet
))
443 (flet (((cas x
) (old new
)
451 (assert (null (cas (x) nil t
)))
453 (assert (eq t
(cas (x) nil
:oops
)))
454 (assert (eq t
(x))))))
456 (defgeneric (cas thing
) (old new thing
))
458 (defmethod (cas thing
) (old new
(thing cons
))
459 (cas (car thing
) old new
))
461 (defmethod (cas thing
) (old new
(thing symbol
))
462 (cas (symbol-value thing
) old new
))
464 (defgeneric thing
(thing)
467 (:method
((x symbol
))
470 (with-test (:name
(:cas
:defgeneric
))
474 (assert (null (thing a
)))
475 (assert (null (thing b
)))
476 (assert (null (cas (thing a
) nil t
)))
477 (assert (null (cas (thing b
) nil t
)))
478 (assert (eq t
(thing a
)))
479 (assert (eq t
(thing b
)))
480 (assert (eq t
(cas (thing a
) nil
:oops
)))
481 (assert (eq t
(cas (thing b
) nil
:oops
)))
482 (assert (eq t
(thing a
)))
483 (assert (eq t
(thing b
)))))
485 ;;; SYMBOL-VALUE with a constant argument used to return a bogus read-form
486 (with-test (:name
:symbol-value-cas-expansion
)
487 (multiple-value-bind (vars vals old new cas-form read-form
)
488 (get-cas-expansion `(symbol-value t
))
489 (declare (ignore old new cas-form
))
492 (assert (eq t
(eval read-form
))))
493 (multiple-value-bind (vars vals old new cas-form read-form
)
494 (get-cas-expansion `(symbol-value *))
495 (declare (ignore old new cas-form
))
498 (eval `(let (,@(mapcar 'list vars vals
))
502 (eval `(let (,@(mapcar 'list vars vals
))
505 (with-test (:name
:atomic-push
506 :skipped-on
(not :sb-thread
))
507 (let ((store (cons nil nil
))
509 (symbol-macrolet ((x (car store
))
513 (mapc #'sb-thread
:join-thread
514 (loop repeat
(ecase sb-vm
:n-word-bits
(32 100) (64 1000))
515 collect
(sb-thread:make-thread
517 (loop for z
= (atomic-pop y
)
522 (assert (eql n
(length x
))))))
524 (with-test (:name
:local-special-symbol-value
)
526 (= (funcall (compile nil
529 (declare (special x
))
530 (cas (symbol-value 'x
) 10 12)
538 (declare (special x
))
539 (atomic-pop (symbol-value 'x
))))))
542 (defclass cas-fsc
(generic-function)
544 (:metaclass sb-mop
:funcallable-standard-class
))
546 (with-test (:name
:cas-funcallable-instance
)
547 (let ((x (make-instance 'cas-fsc
)))
549 (= (funcall (compile nil
551 (cas (slot-value x
'a
) 0 1)))
554 (assert (eql (slot-value x
'a
) 2))
556 (= (funcall (compile nil
558 (cas (slot-value x
'a
) 2 3)))
561 (assert (eql (slot-value x
'a
) 3))))
565 ;;; This file defines a structure, so is an 'impure' test
567 ;; The slots under test have to be naturally aligned for a double-Lispword,
568 ;; at least on x86-64, so add a random slot if there is no layout slot.
569 #+compact-instance-header fluff
573 (declare (muffle-conditions style-warning
)) ; functions don't exist for non-x86
574 (defun test-a-cons (acons oldcar oldcdr newcar newcdr
)
575 (%cons-cas-pair acons oldcar oldcdr newcar newcdr
))
576 (defun test-a-vect (avect ind old1 old2 new1 new2
)
577 (%vector-cas-pair avect ind old1 old2 new1 new2
))
578 (defun test-a-struct (inst ind old1 old2 new1 new2
)
579 (%instance-cas-pair inst ind old1 old2 new1 new2
))
581 (defun test-wide-cmpxchg ()
582 (let ((x (cons 'a
'b
)))
583 (multiple-value-bind (old1 old2
) (test-a-cons x
'a
'b
'foo
'bar
)
584 (assert (and (eq old1
'a
) (eq old2
'b
) (equal x
'(foo . bar
)))))
585 (multiple-value-bind (old1 old2
) (test-a-cons x
0 0 1 2)
586 (assert (and (eq old1
'foo
) (eq old2
'bar
) (equal x
'(foo . bar
))))))
588 ;; This is just testing that the offsets are correct.
589 ;; Correct working of the instruction is tested by the CONS example.
590 (let ((x (make-array 6 :initial-element nil
)))
591 (multiple-value-bind (old1 old2
) (test-a-vect x
2 nil nil
'foo
'bar
)
592 (assert (and (null old1
) (null old2
) (equalp x
#(nil nil foo bar nil nil
))))))
594 ;; Same remark applies - just check that the offset to the slot is right.
595 (let ((s (make-my-struct :three
'the
:four
'floor
)))
596 ;; in slots 3 and 4 put your bootee (a baby shoe, i.e.) on the floor
597 (multiple-value-bind (old1 old2
) (test-a-struct s
3 'the
'floor
'your
'bootee
)
598 (assert (and (eq old1
'the
) (eq old2
'floor
)
599 (eq (my-struct-three s
) 'your
)
600 (eq (my-struct-four s
) 'bootee
)))))
603 (test-util:with-test
(:name
:wide-compare-and-exchange
604 :skipped-on
(not (or :x86
:x86-64
)))
605 (multiple-value-bind (a b c d
) (%cpu-identification
0 0)
606 (declare (ignore b c d
))
607 ;; paranoidly check for whether we can execute function ID 1
608 (or (and (>= a
1) ; the highest function ID
609 (multiple-value-bind (a b c d
) (%cpu-identification
1 0)
610 (declare (ignore a b
) (ignorable c d
))
611 ;; paranoidly check for CMPXCHGxB presence
612 ;; constants from Table 3-20 and 3-21 of Intel manual
613 (and #+x86
(logbitp 8 d
) #+x86-64
(logbitp 13 c
)
614 (test-wide-cmpxchg))))
615 (format t
"Double-width compare-and-swap NOT TESTED~%"))))
617 (test-util:with-test
(:name
:cas-sap-ref-smoke-test
618 :skipped-on
(not (and :sb-thread
(or :ppc64
:x86-64
))))
619 (let ((data (make-array 1 :element-type
'sb-vm
:word
)))
620 (sb-sys:with-pinned-objects
(data)
621 (let ((sap (sb-sys:vector-sap data
)))
622 ;; It's important to exercise an initial value that has lots of bits on,
623 ;; because I made at least two mistakes in the x86-64 lispword-sized vop:
624 ;; 1. it was using a :dword move where it should have used a :qword
625 ;; 2. it was emitting constants as bignums instead of inline raw constants
626 (macrolet ((test (signedp nbits newval
627 &aux
(ref (symbolicate (if signedp
"SIGNED-" "")
630 (ldb (byte nbits
0) most-positive-word
))))
632 ;; (format t "Testing ~a with initial bits ~x~%" ',ref ,init)
633 (setf (,ref sap
0) ,init
)
634 (let ((old (cas (,ref sap
0) 0 5)))
635 (assert (eql old
,init
)) ; actual old
636 (assert (eql (,ref sap
0) ,init
))) ; memory should not have changed
637 (let ((old (cas (,ref sap
0) ,init
,newval
)))
638 (assert (eql old
,init
)) ; actual old
639 (assert (eql (,ref sap
0) ,newval
)))))) ; should have changed
640 (test nil
64 #xdeadc0fefe00
)
641 (test t
64 most-negative-fixnum
)
642 (test nil
32 #xbabab00e
)
643 #-ppc64
(test nil
16 #xfafa
) ; gets "illegal instruction" if unimplemented
644 #-ppc64
(test nil
8 #xbb
)
647 (setf (aref data
0) 0)
648 (let ((old (cas (sap-ref-sap sap
0) (int-sap 1) (int-sap #xffff
))))
649 (assert (sb-sys:sap
= old
(int-sap 0))) ; actual old
650 (assert (sb-sys:sap
= (sap-ref-sap sap
0) (int-sap 0)))) ; memory should not have changed
651 (let ((old (cas (sap-ref-sap sap
0) (int-sap 0) (int-sap sb-ext
:most-positive-word
))))
652 (assert (sb-sys:sap
= old
(int-sap 0)))
653 (assert (sb-sys:sap
= (sap-ref-sap sap
0) (int-sap sb-ext
:most-positive-word
))))
655 (setf (aref data
0) sb-vm
:nil-value
)
656 (let ((old (cas (sap-ref-lispobj sap
0) t
'*print-base
*)))
657 (assert (eq old nil
)) ; actual old
658 (assert (eq (sap-ref-lispobj sap
0) nil
))) ; memory should not have changed
659 (let ((old (cas (sap-ref-lispobj sap
0) nil t
)))
660 (assert (eq old nil
))
661 (assert (eq (sap-ref-lispobj sap
0) t
)))))))
663 (test-util:with-test
(:name
:cas-sap-ref-stress-test
664 :skipped-on
(not (and :sb-thread
(or :ppc64
:x86-64
))))
665 (let ((data (make-array 1 :element-type
'sb-vm
:word
666 :initial-element
0)))
667 (sb-sys:with-pinned-objects
(data)
668 (let ((sap (sb-sys:vector-sap data
))
670 (n-increments 100000)
674 (dotimes (i n-increments fails
)
675 (let ((old (sap-ref-32 sap
0)))
677 (let ((actual (cas (sap-ref-32 sap
0) old
(1+ old
))))
678 (if (eq actual old
) (return))
680 (setq old actual
))))))))
681 (dotimes (i n-threads
)
682 (push (sb-thread:make-thread
#'increment
) threads
))
683 (mapc 'sb-thread
:join-thread threads
)
684 (assert (= (sap-ref-32 sap
0) (* n-threads n-increments
))))))))
686 (define-alien-variable "small_generation_limit" (signed 8))
687 ;; PPC64 shouldn't fail, but depending on the CPU revision it might not
688 ;; have the needed instruction, and I don't know how to test for it.
689 ;; And surely it doesn't really depend on endian-ness, but the machine
690 ;; that I'm testing on which is little-endian passes the test.
691 #+(and sb-thread
(or x86-64
(and ppc64 little-endian
)))
693 (defun cas-an-alien-byte (x y
) (cas small-generation-limit x y
))
694 (compile 'cas-an-alien-byte
)
695 (test-util:with-test
(:name
:cas-alien
)
696 (assert (= small-generation-limit
1))
697 (assert (= (cas-an-alien-byte 0 5) 1))
698 (assert (= (cas-an-alien-byte 1 6) 1))
699 (assert (= small-generation-limit
6))
700 (setf small-generation-limit
1)))