Skip to content

Commit 31779e7

Browse files
committed
Adding atomic-fetch-compare-and-swap! procedure
1 parent 7fbe30a commit 31779e7

File tree

7 files changed

+80
-39
lines changed

7 files changed

+80
-39
lines changed

doc/sagittarius/atomic.md

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
###### [!Library] `(sagittarius atomic)` **[@since] `0.9.13`**
55

66
This library provides atomic operation. The underlying implementation
7-
of this library can be either `stdatomic` from C11 or `libatomic_ops`.
7+
of this library can be either `stdatomic` from C11 or `<atomic>` from C++11.
88
If the platform supports the first one, then that'd be chosen, otherwise
99
the latter one.
1010

11+
NOTE: if the platform doesn't support none of them, then compilation error.
12+
1113
###### [!Function] `atomic?` _obj_
1214

1315
Returns `#t` if the given _obj_ is an atomic object, otherwise `#f`.
@@ -16,6 +18,14 @@ Returns `#t` if the given _obj_ is an atomic object, otherwise `#f`.
1618

1719
Creates a fresh atomic object whoes initial value is _obj_.
1820

21+
###### [!Function] `atomic-flag?` _obj_
22+
23+
Returns `#t` if the given _obj_ is an atomic flag object, otherwise `#f`.
24+
25+
###### [!Function] `make-atomic-flag`
26+
27+
Creates a fresh atomic flag. The flag is unset.
28+
1929
###### [!Function] `atomic-fixnum?` _obj_
2030

2131
Returns `#t` if the given _obj_ is an atomic fixnum object, otherwise `#f`.
@@ -24,6 +34,16 @@ Returns `#t` if the given _obj_ is an atomic fixnum object, otherwise `#f`.
2434

2535
Creates a fresh atomic fixnum object whoes initial value is _n_.
2636

37+
###### [!Function] `atomic-pair?` _obj_
38+
39+
Returns `#t` if the given _obj_ is an atomic pair object, otherwise `#f`.
40+
41+
###### [!Function] `make-atomic-pair` _head_ _tail_
42+
43+
Creates a fresh atomic pair object whoes initial values are _first_ and _tail_.
44+
45+
This is double word atomic object.
46+
2747
###### [!Function] `memory-order?` _obj_
2848

2949
Returns `#t` if the given _obj_ is a fixnum and value of memory order.
@@ -73,11 +93,22 @@ and returns the previous value of _a_.
7393
Exchange the value of _a_ with given _v_ or _n_ and returns the old value
7494
of _a_.
7595

76-
###### [!Function] `atomic-compare-and-swap!` (_a_ `atomic?`) _v_ :optional (_order_ `memory-order?`)
96+
###### [!Function] `atomic-compare-and-swap!` (_a_ `atomic?`) _e_ _v_ :optional (_order_ `memory-order?`)
97+
98+
CAS operation. Returns `#t` if the operation succeed, otherwise `#f`.
99+
100+
###### [!Function] `atomic-fetch-compare-and-swap!` (_a_ `atomic?`) _e_ _v_ :optional (_order_ `memory-order?`)
77101

78-
CAS operation.
102+
CAS operation. Returns previously set value if the operation **failed**,
103+
otherwise the _e_.
79104

80105
###### [!Function] `atomic-fixnum-inc!` (_a_ `atomic-fixnum?`) :optional (_order_ `memory-order?`)
81106
###### [!Function] `atomic-fixnum-dec!` (_a_ `atomic-fixnum?`) :optional (_order_ `memory-order?`)
82107

83108
Increment or decrement the value of given _a_ and updates the value.
109+
110+
111+
###### [!Function] `atomic-thread-fence` (_order_ `memory-order?`)
112+
113+
Establishes memory synchronization ordering of non-atomic and relaxed
114+
atomic accesses.

ext/atomic/atomic.stub

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,21 @@
7171
(define-c-proc atomic-exchange! (a::<atomic> v :optional (order::<memory-order> (default-memory-order))) Sg_AtomicExchange)
7272
(define-c-proc atomic-fixnum-exchange! (a::<atomic-fixnum> v::<fixnum> :optional (order::<memory-order> (default-memory-order))) ::<fixnum> Sg_AtomicFixnumExchange)
7373

74-
(define-c-proc atomic-compare-and-swap! (a::<atomic> e v :optional (success::<memory-order> (default-memory-order)) (failure::<memory-order> (default-memory-order))) ::<boolean> Sg_AtomicCompareAndSwap)
74+
(define-c-proc atomic-compare-and-swap!
75+
(a::<atomic> e v
76+
:optional (success::<memory-order> (default-memory-order))
77+
(failure::<memory-order> (default-memory-order)))
78+
::<boolean>
79+
(result (Sg_AtomicCompareAndSwap a e v NULL success failure)))
80+
81+
(define-c-proc atomic-fetch-compare-and-swap!
82+
(a::<atomic> e v
83+
:optional (success::<memory-order> (default-memory-order))
84+
(failure::<memory-order> (default-memory-order)))
85+
(let ((r NULL))
86+
(if (Sg_AtomicCompareAndSwap a e v (& r) success failure)
87+
(result e)
88+
(result r))))
7589

7690
(define-c-proc atomic-flag-test-and-set! (a::<atomic-flag> :optional (order::<memory-order> (default-memory-order))) ::<boolean> Sg_AtomicFlagTestAndSet)
7791
(define-c-proc atomic-flag-clear! (a::<atomic-flag> :optional (order::<memory-order> (default-memory-order))) ::<void> Sg_AtomicFlagClear)

ext/atomic/sagittarius-atomic.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,10 @@ long Sg_AtomicFixnumAnd(volatile SgAtomic *o, long v, SgMemoryOrder order)
445445
}
446446

447447
int Sg_AtomicCompareAndSwap(volatile SgAtomic *o, SgObject e, SgObject v,
448+
SgObject *r,
448449
SgMemoryOrder success, SgMemoryOrder failure)
449450
{
451+
int result;
450452
no_atomic_flag(o);
451453
switch (o->type) {
452454
case SG_ATOMIC_FIXNUM:
@@ -455,29 +457,42 @@ int Sg_AtomicCompareAndSwap(volatile SgAtomic *o, SgObject e, SgObject v,
455457
}
456458
{
457459
long ev = SG_INT_VALUE(e);
458-
return atomic_compare_exchange_strong_explicit(&SG_ATOMIC_REF_FIXNUM(o),
459-
&ev,
460-
SG_INT_VALUE(v),
461-
success, failure);
460+
result = atomic_compare_exchange_strong_explicit(&SG_ATOMIC_REF_FIXNUM(o),
461+
&ev,
462+
SG_INT_VALUE(v),
463+
success, failure);
464+
if (!result && r) {
465+
*r = SG_MAKE_INT(ev);
466+
}
462467
}
468+
break;
463469
case SG_ATOMIC_PAIR:
464470
if (!SG_PAIRP(e) && !SG_PAIRP(v)) {
465471
Sg_Error(UC("atomic_pair must take pair but got %S and %S"), e, v);
466472
}
467473
{
468474
pair_t ev = { SG_CAR(e), SG_CDR(e) };
469475
pair_t vv = { SG_CAR(v), SG_CDR(v) };
470-
return atomic_compare_exchange_strong_explicit(&SG_ATOMIC_REF_PAIR(o),
476+
result = atomic_compare_exchange_strong_explicit(&SG_ATOMIC_REF_PAIR(o),
471477
&ev, vv, success, failure);
478+
if (!result && r) {
479+
*r = Sg_Cons(ev.car, ev.cdr);
480+
}
472481
}
482+
break;
473483
default:
474484
{
475485
object_t ev = (object_t)e;
476-
return atomic_compare_exchange_strong_explicit(&SG_ATOMIC_REF_OBJECT(o),
477-
&ev, (object_t)v,
478-
success, failure);
486+
result = atomic_compare_exchange_strong_explicit(&SG_ATOMIC_REF_OBJECT(o),
487+
&ev, (object_t)v,
488+
success, failure);
489+
if (!result && r) {
490+
*r = SG_OBJ(ev);
491+
}
479492
}
493+
break;
480494
}
495+
return result;
481496
}
482497

483498
int Sg_AtomicFlagTestAndSet(volatile SgAtomic *o, SgMemoryOrder order)

ext/atomic/sagittarius-atomic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ SG_EXTERN long Sg_AtomicFixnumAnd(volatile SgAtomic *o, long v,
174174

175175
SG_EXTERN int Sg_AtomicCompareAndSwap(volatile SgAtomic *o,
176176
SgObject e, SgObject v,
177+
SgObject *r,
177178
SgMemoryOrder success,
178179
SgMemoryOrder failure);
179180
SG_EXTERN int Sg_AtomicFlagTestAndSet(volatile SgAtomic *o,

ext/atomic/sagittarius/atomic.scm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050

5151
atomic-exchange! atomic-fixnum-exchange!
5252

53-
atomic-compare-and-swap!
53+
atomic-compare-and-swap! atomic-fetch-compare-and-swap!
5454

5555
atomic-flag-test-and-set! atomic-flag-clear!
5656

sitelib/srfi/%3a230/atomic.scm

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,7 @@
6262
(import (rnrs)
6363
(rename (except (sagittarius atomic) memory-order?)
6464
(atomic-flag-test-and-set! a:atomic-flag-test-and-set!)
65-
(atomic-flag-clear! a:atomic-flag-clear!))
66-
(srfi :18 multithreading))
67-
(define *lock* (make-mutex))
68-
(define-syntax lock-guard
69-
(syntax-rules ()
70-
((_ expr ...)
71-
(dynamic-wind
72-
(lambda ()
73-
(guard (c ((abandoned-mutex-exception? c) #f))
74-
(mutex-lock! *lock*)))
75-
(lambda () expr ...)
76-
(lambda () (mutex-unlock! *lock*))))))
77-
65+
(atomic-flag-clear! a:atomic-flag-clear!)) )
7866
;; memory order
7967
(define-enumeration memory-order
8068
(relaxed acquire release acquire-release sequentially-consistent)
@@ -106,10 +94,7 @@
10694
(atomic-exchange! box obj (memory-order->value order)))
10795
(define (atomic-box-compare-and-swap! (box atomic-box?) old new
10896
:optional (order *default-order*))
109-
(lock-guard
110-
(let ((r (atomic-box-ref box order)))
111-
(atomic-compare-and-swap! box old new (memory-order->value order))
112-
r)))
97+
(atomic-fetch-compare-and-swap! box old new (memory-order->value order)))
11398

11499
;; atomic fixnum
115100
(define (make-atomic-fxbox (fx fixnum?)) (make-atomic-fixnum fx))
@@ -126,10 +111,7 @@
126111
(define (atomic-fxbox-compare-and-swap! (afx atomic-fxbox?)
127112
(old fixnum?) (new fixnum?)
128113
:optional (order *default-order*))
129-
(lock-guard
130-
(let ((r (atomic-fxbox-ref afx order)))
131-
(atomic-compare-and-swap! afx old new (memory-order->value order))
132-
r)))
114+
(atomic-fetch-compare-and-swap! afx old new (memory-order->value order)))
133115
(define (atomic-fxbox+/fetch! (afx atomic-fxbox?) (fx fixnum?)
134116
:optional (order *default-order*))
135117
(atomic-fixnum-add! afx fx (memory-order->value order)))
@@ -162,10 +144,8 @@
162144
(define (atomic-pair-compare-and-swap! (ap atomic-pair?) oa od na nd
163145
:optional (order *default-order*))
164146
(define morder (memory-order->value order))
165-
(lock-guard
166-
(let-values (((ra rd) (atomic-pair-ref ap order)))
167-
(atomic-compare-and-swap! ap (cons oa od) (cons na nd) morder)
168-
(values ra rd))))
147+
(let ((r (atomic-fetch-compare-and-swap! ap (cons oa od) (cons na nd) morder)))
148+
(values (car r) (cdr r))))
169149

170150
(define (atomic-fence (order memory-order?))
171151
(atomic-thread-fence (memory-order->value order)))

sitelib/util/concurrent/atomic.scm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
atomic-exchange! atomic-fixnum-exchange!
5353

54-
atomic-compare-and-swap!
54+
atomic-compare-and-swap! atomic-fetch-compare-and-swap!
5555

5656
atomic-flag-test-and-set! atomic-flag-clear!
5757

0 commit comments

Comments
 (0)