8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- /*!
12
- * Atomic types
13
- *
14
- * Basic atomic types supporting atomic operations. Each method takes an
15
- * `Ordering` which represents the strength of the memory barrier for that
16
- * operation. These orderings are the same as C++11 atomic orderings
17
- * [http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync]
18
- *
19
- * All atomic types are a single word in size.
20
- */
11
+ //! Atomic types
12
+ //!
13
+ //! Atomic types provide primitive shared-memory communication between
14
+ //! threads, and are the building blocks of other concurrent
15
+ //! types.
16
+ //!
17
+ //! This module defines atomic versions of a select number of primitive
18
+ //! types, including `AtomicBool`, `AtomicInt`, `AtomicUint`, and `AtomicOption`.
19
+ //! Atomic types present operations that, when used correctly, synchronize
20
+ //! updates between threads.
21
+ //!
22
+ //! Each method takes an `Ordering` which represents the strength of
23
+ //! the memory barrier for that operation. These orderings are the
24
+ //! same as [C++11 atomic orderings][1].
25
+ //!
26
+ //! [1]: http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
27
+ //!
28
+ //! Atomic variables are safe to share between threads (they implement `Share`)
29
+ //! but they do not themselves provide the mechanism for sharing. The most
30
+ //! common way to share an atomic variable is to put it into an `Arc` (an
31
+ //! atomically-reference-counted shared pointer).
32
+ //!
33
+ //! Most atomic types may be stored in static variables, initialized using
34
+ //! the provided static initializers like `INIT_ATOMIC_BOOL`. Atomic statics
35
+ //! are often used for lazy global initialization.
36
+ //!
37
+ //!
38
+ //! # Examples
39
+ //!
40
+ //! A simple spinlock:
41
+ //!
42
+ //! ```ignore
43
+ //! # // FIXME: Needs PR #12430
44
+ //! extern crate sync;
45
+ //!
46
+ //! use sync::Arc;
47
+ //! use std::sync::atomics::{AtomicUint, SeqCst};
48
+ //! use std::task::deschedule;
49
+ //!
50
+ //! fn main() {
51
+ //! let spinlock = Arc::new(AtomicUint::new(1));
52
+ //!
53
+ //! let spinlock_clone = spinlock.clone();
54
+ //! spawn(proc() {
55
+ //! spinlock_clone.store(0, SeqCst);
56
+ //! });
57
+ //!
58
+ //! // Wait for the other task to release the lock
59
+ //! while spinlock.load(SeqCst) != 0 {
60
+ //! // Since tasks may not be preemptive (if they are green threads)
61
+ //! // yield to the scheduler to let the other task run. Low level
62
+ //! // concurrent code needs to take into account Rust's two threading
63
+ //! // models.
64
+ //! deschedule();
65
+ //! }
66
+ //! }
67
+ //! ```
68
+ //!
69
+ //! Transferring a heap object with `AtomicOption`:
70
+ //!
71
+ //! ```ignore
72
+ //! # // FIXME: Needs PR #12430
73
+ //! extern crate sync;
74
+ //!
75
+ //! use sync::Arc;
76
+ //! use std::sync::atomics::{AtomicOption, SeqCst};
77
+ //!
78
+ //! fn main() {
79
+ //! struct BigObject;
80
+ //!
81
+ //! let shared_big_object = Arc::new(AtomicOption::empty());
82
+ //!
83
+ //! let shared_big_object_clone = shared_big_object.clone();
84
+ //! spawn(proc() {
85
+ //! let unwrapped_big_object = shared_big_object_clone.take(SeqCst);
86
+ //! if unwrapped_big_object.is_some() {
87
+ //! println!("got a big object from another task");
88
+ //! } else {
89
+ //! println!("other task hasn't sent big object yet");
90
+ //! }
91
+ //! });
92
+ //!
93
+ //! shared_big_object.swap(~BigObject, SeqCst);
94
+ //! }
95
+ //! ```
96
+ //!
97
+ //! Keep a global count of live tasks:
98
+ //!
99
+ //! ```
100
+ //! use std::sync::atomics::{AtomicUint, SeqCst, INIT_ATOMIC_UINT};
101
+ //!
102
+ //! static mut GLOBAL_TASK_COUNT: AtomicUint = INIT_ATOMIC_UINT;
103
+ //!
104
+ //! unsafe {
105
+ //! let old_task_count = GLOBAL_TASK_COUNT.fetch_add(1, SeqCst);
106
+ //! println!("live tasks: {}", old_task_count + 1);
107
+ //! }
108
+ //! ```
21
109
22
110
#[ allow( missing_doc) ] ;
23
111
@@ -27,165 +115,353 @@ use std::kinds::marker;
27
115
use option:: { Option , Some , None } ;
28
116
use ops:: Drop ;
29
117
30
- /**
31
- * An atomic boolean type.
32
- */
118
+ /// An atomic boolean type.
33
119
pub struct AtomicBool {
34
120
priv v: uint ,
35
121
priv nopod : marker:: NoPod
36
122
}
37
123
38
- /**
39
- * A signed atomic integer type, supporting basic atomic arithmetic operations
40
- */
124
+ /// A signed atomic integer type, supporting basic atomic arithmetic operations
41
125
pub struct AtomicInt {
42
126
priv v: int ,
43
127
priv nopod : marker:: NoPod
44
128
}
45
129
46
- /**
47
- * An unsigned atomic integer type, supporting basic atomic arithmetic operations
48
- */
130
+ /// An unsigned atomic integer type, supporting basic atomic arithmetic operations
49
131
pub struct AtomicUint {
50
132
priv v: uint ,
51
133
priv nopod : marker:: NoPod
52
134
}
53
135
54
- /**
55
- * An unsigned atomic integer type that is forced to be 64-bits. This does not
56
- * support all operations.
57
- */
136
+ /// An unsigned atomic integer type that is forced to be 64-bits. This does not
137
+ /// support all operations.
58
138
pub struct AtomicU64 {
59
139
priv v: u64 ,
60
140
priv nopod : marker:: NoPod
61
141
}
62
142
63
- /**
64
- * An unsafe atomic pointer. Only supports basic atomic operations
65
- */
143
+ /// An unsafe atomic pointer. Only supports basic atomic operations
66
144
pub struct AtomicPtr < T > {
67
145
priv p: uint ,
68
146
priv nopod : marker:: NoPod
69
147
}
70
148
71
- /**
72
- * An owned atomic pointer. Ensures that only a single reference to the data is held at any time.
73
- */
149
+ /// An atomic, nullable unique pointer
150
+ ///
151
+ /// This can be used as the concurrency primitive for operations that transfer
152
+ /// owned heap objects across tasks.
74
153
#[ unsafe_no_drop_flag]
75
154
pub struct AtomicOption < T > {
76
155
priv p: uint ,
77
156
}
78
157
158
+ /// Atomic memory orderings
159
+ ///
160
+ /// Memory orderings limit the ways that both the compiler and CPU may reorder
161
+ /// instructions around atomic operations. At its most restrictive,
162
+ /// "sequentially consistent" atomics allow neither reads nor writes
163
+ /// to be moved either before or after the atomic operation; on the other end
164
+ /// "relaxed" atomics allow all reorderings.
165
+ ///
166
+ /// Rust's memory orderings are the same as in C++[1].
167
+ ///
168
+ /// [1]: http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
79
169
pub enum Ordering {
170
+ /// No ordering constraints, only atomic operations
80
171
Relaxed ,
172
+ /// When coupled with a store, all previous writes become visible
173
+ /// to another thread that performs a load with `Acquire` ordering
174
+ /// on the same value
81
175
Release ,
176
+ /// When coupled with a load, all subsequent loads will see data
177
+ /// written before a store with `Release` ordering on the same value
178
+ /// in another thread
82
179
Acquire ,
180
+ /// When coupled with a load, uses `Acquire` ordering, and with a store
181
+ /// `Release` ordering
83
182
AcqRel ,
183
+ /// Like `AcqRel` with the additional guarantee that all threads see all
184
+ /// sequentially consistent operations in the same order.
84
185
SeqCst
85
186
}
86
187
188
+ /// An `AtomicBool` initialized to `false`
87
189
pub static INIT_ATOMIC_BOOL : AtomicBool = AtomicBool { v : 0 , nopod : marker:: NoPod } ;
190
+ /// An `AtomicInt` initialized to `0`
88
191
pub static INIT_ATOMIC_INT : AtomicInt = AtomicInt { v : 0 , nopod : marker:: NoPod } ;
192
+ /// An `AtomicUint` initialized to `0`
89
193
pub static INIT_ATOMIC_UINT : AtomicUint = AtomicUint { v : 0 , nopod : marker:: NoPod } ;
194
+ /// An `AtomicU64` initialized to `0`
90
195
pub static INIT_ATOMIC_U64 : AtomicU64 = AtomicU64 { v : 0 , nopod : marker:: NoPod } ;
91
196
197
+
198
+ // NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
199
+ static UINT_TRUE : uint = -1 ;
200
+
92
201
impl AtomicBool {
202
+ /// Create a new `AtomicBool`
93
203
pub fn new ( v : bool ) -> AtomicBool {
94
- AtomicBool { v : if v { 1 } else { 0 } , nopod : marker:: NoPod }
204
+ AtomicBool { v : if v { UINT_TRUE } else { 0 } , nopod : marker:: NoPod }
95
205
}
96
206
207
+ /// Load the value
97
208
#[ inline]
98
209
pub fn load ( & self , order : Ordering ) -> bool {
99
210
unsafe { atomic_load ( & self . v , order) > 0 }
100
211
}
101
212
213
+ /// Store the value
102
214
#[ inline]
103
215
pub fn store ( & mut self , val : bool , order : Ordering ) {
104
- let val = if val { 1 } else { 0 } ;
216
+ let val = if val { UINT_TRUE } else { 0 } ;
105
217
106
218
unsafe { atomic_store ( & mut self . v , val, order) ; }
107
219
}
108
220
221
+ /// Store a value, returning the old value
109
222
#[ inline]
110
223
pub fn swap ( & mut self , val : bool , order : Ordering ) -> bool {
111
- let val = if val { 1 } else { 0 } ;
224
+ let val = if val { UINT_TRUE } else { 0 } ;
112
225
113
226
unsafe { atomic_swap ( & mut self . v , val, order) > 0 }
114
227
}
115
228
229
+ /// If the current value is the same as expected, store a new value
230
+ ///
231
+ /// Compare the current value with `old`; if they are the same then
232
+ /// replace the current value with `new`. Return the previous value.
233
+ /// If the return value is equal to `old` then the value was updated.
234
+ ///
235
+ /// # Examples
236
+ ///
237
+ /// ```ignore
238
+ /// # // FIXME: Needs PR #12430
239
+ /// extern crate sync;
240
+ ///
241
+ /// use sync::Arc;
242
+ /// use std::sync::atomics::{AtomicBool, SeqCst};
243
+ ///
244
+ /// fn main() {
245
+ /// let spinlock = Arc::new(AtomicBool::new(false));
246
+ /// let spinlock_clone = spin_lock.clone();
247
+ ///
248
+ /// spawn(proc() {
249
+ /// with_lock(&spinlock, || println!("task 1 in lock"));
250
+ /// });
251
+ ///
252
+ /// spawn(proc() {
253
+ /// with_lock(&spinlock_clone, || println!("task 2 in lock"));
254
+ /// });
255
+ /// }
256
+ ///
257
+ /// fn with_lock(spinlock: &Arc<AtomicBool>, f: || -> ()) {
258
+ /// // CAS loop until we are able to replace `false` with `true`
259
+ /// while spinlock.compare_and_swap(false, true, SeqCst) == false {
260
+ /// // Since tasks may not be preemptive (if they are green threads)
261
+ /// // yield to the scheduler to let the other task run. Low level
262
+ /// // concurrent code needs to take into account Rust's two threading
263
+ /// // models.
264
+ /// deschedule();
265
+ /// }
266
+ ///
267
+ /// // Now we have the spinlock
268
+ /// f();
269
+ ///
270
+ /// // Release the lock
271
+ /// spinlock.store(false);
272
+ /// }
273
+ /// ```
116
274
#[ inline]
117
275
pub fn compare_and_swap ( & mut self , old : bool , new : bool , order : Ordering ) -> bool {
118
- let old = if old { 1 } else { 0 } ;
119
- let new = if new { 1 } else { 0 } ;
276
+ let old = if old { UINT_TRUE } else { 0 } ;
277
+ let new = if new { UINT_TRUE } else { 0 } ;
120
278
121
279
unsafe { atomic_compare_and_swap ( & mut self . v , old, new, order) > 0 }
122
280
}
123
281
124
- /// Returns the old value
282
+ /// A logical "and" operation
283
+ ///
284
+ /// Performs a logical "and" operation on the current value and the
285
+ /// argument `val`, and sets the new value to the result.
286
+ /// Returns the previous value.
287
+ ///
288
+ /// # Examples
289
+ ///
290
+ /// ```
291
+ /// use std::sync::atomics::{AtomicBool, SeqCst};
292
+ ///
293
+ /// let mut foo = AtomicBool::new(true);
294
+ /// assert_eq!(true, foo.fetch_and(false, SeqCst));
295
+ /// assert_eq!(false, foo.load(SeqCst));
296
+ ///
297
+ /// let mut foo = AtomicBool::new(true);
298
+ /// assert_eq!(true, foo.fetch_and(true, SeqCst));
299
+ /// assert_eq!(true, foo.load(SeqCst));
300
+ ///
301
+ /// let mut foo = AtomicBool::new(false);
302
+ /// assert_eq!(false, foo.fetch_and(false, SeqCst));
303
+ /// assert_eq!(false, foo.load(SeqCst));
304
+ /// ```
125
305
#[ inline]
126
306
pub fn fetch_and ( & mut self , val : bool , order : Ordering ) -> bool {
127
- let val = if val { 1 } else { 0 } ;
307
+ let val = if val { UINT_TRUE } else { 0 } ;
128
308
129
309
unsafe { atomic_and ( & mut self . v , val, order) > 0 }
130
310
}
131
311
132
- /// Returns the old value
312
+ /// A logical "nand" operation
313
+ ///
314
+ /// Performs a logical "nand" operation on the current value and the
315
+ /// argument `val`, and sets the new value to the result.
316
+ /// Returns the previous value.
317
+ ///
318
+ /// # Examples
319
+ ///
320
+ /// ```
321
+ /// use std::sync::atomics::{AtomicBool, SeqCst};
322
+ ///
323
+ /// let mut foo = AtomicBool::new(true);
324
+ /// assert_eq!(true, foo.fetch_nand(false, SeqCst));
325
+ /// assert_eq!(true, foo.load(SeqCst));
326
+ ///
327
+ /// let mut foo = AtomicBool::new(true);
328
+ /// assert_eq!(true, foo.fetch_nand(true, SeqCst));
329
+ /// assert_eq!(0, foo.load(SeqCst) as int);
330
+ /// assert_eq!(false, foo.load(SeqCst));
331
+ ///
332
+ /// let mut foo = AtomicBool::new(false);
333
+ /// assert_eq!(false, foo.fetch_nand(false, SeqCst));
334
+ /// assert_eq!(true, foo.load(SeqCst));
335
+ /// ```
133
336
#[ inline]
134
337
pub fn fetch_nand ( & mut self , val : bool , order : Ordering ) -> bool {
135
- let val = if val { 1 } else { 0 } ;
338
+ let val = if val { UINT_TRUE } else { 0 } ;
136
339
137
340
unsafe { atomic_nand ( & mut self . v , val, order) > 0 }
138
341
}
139
342
140
- /// Returns the old value
343
+ /// A logical "or" operation
344
+ ///
345
+ /// Performs a logical "or" operation on the current value and the
346
+ /// argument `val`, and sets the new value to the result.
347
+ /// Returns the previous value.
348
+ ///
349
+ /// # Examples
350
+ ///
351
+ /// ```
352
+ /// use std::sync::atomics::{AtomicBool, SeqCst};
353
+ ///
354
+ /// let mut foo = AtomicBool::new(true);
355
+ /// assert_eq!(true, foo.fetch_or(false, SeqCst));
356
+ /// assert_eq!(true, foo.load(SeqCst));
357
+ ///
358
+ /// let mut foo = AtomicBool::new(true);
359
+ /// assert_eq!(true, foo.fetch_or(true, SeqCst));
360
+ /// assert_eq!(true, foo.load(SeqCst));
361
+ ///
362
+ /// let mut foo = AtomicBool::new(false);
363
+ /// assert_eq!(false, foo.fetch_or(false, SeqCst));
364
+ /// assert_eq!(false, foo.load(SeqCst));
365
+ /// ```
141
366
#[ inline]
142
367
pub fn fetch_or ( & mut self , val : bool , order : Ordering ) -> bool {
143
- let val = if val { 1 } else { 0 } ;
368
+ let val = if val { UINT_TRUE } else { 0 } ;
144
369
145
370
unsafe { atomic_or ( & mut self . v , val, order) > 0 }
146
371
}
147
372
148
- /// Returns the old value
373
+ /// A logical "xor" operation
374
+ ///
375
+ /// Performs a logical "xor" operation on the current value and the
376
+ /// argument `val`, and sets the new value to the result.
377
+ /// Returns the previous value.
378
+ ///
379
+ /// # Examples
380
+ ///
381
+ /// ```
382
+ /// use std::sync::atomics::{AtomicBool, SeqCst};
383
+ ///
384
+ /// let mut foo = AtomicBool::new(true);
385
+ /// assert_eq!(true, foo.fetch_xor(false, SeqCst));
386
+ /// assert_eq!(true, foo.load(SeqCst));
387
+ ///
388
+ /// let mut foo = AtomicBool::new(true);
389
+ /// assert_eq!(true, foo.fetch_xor(true, SeqCst));
390
+ /// assert_eq!(false, foo.load(SeqCst));
391
+ ///
392
+ /// let mut foo = AtomicBool::new(false);
393
+ /// assert_eq!(false, foo.fetch_xor(false, SeqCst));
394
+ /// assert_eq!(false, foo.load(SeqCst));
395
+ /// ```
149
396
#[ inline]
150
397
pub fn fetch_xor ( & mut self , val : bool , order : Ordering ) -> bool {
151
- let val = if val { 1 } else { 0 } ;
398
+ let val = if val { UINT_TRUE } else { 0 } ;
152
399
153
400
unsafe { atomic_xor ( & mut self . v , val, order) > 0 }
154
401
}
155
402
}
156
403
157
404
impl AtomicInt {
405
+ /// Create a new `AtomicInt`
158
406
pub fn new ( v : int ) -> AtomicInt {
159
407
AtomicInt { v : v, nopod : marker:: NoPod }
160
408
}
161
409
410
+ /// Load the value
162
411
#[ inline]
163
412
pub fn load ( & self , order : Ordering ) -> int {
164
413
unsafe { atomic_load ( & self . v , order) }
165
414
}
166
415
416
+ /// Store the value
167
417
#[ inline]
168
418
pub fn store ( & mut self , val : int , order : Ordering ) {
169
419
unsafe { atomic_store ( & mut self . v , val, order) ; }
170
420
}
171
421
422
+ /// Store a value, returning the old value
172
423
#[ inline]
173
424
pub fn swap ( & mut self , val : int , order : Ordering ) -> int {
174
425
unsafe { atomic_swap ( & mut self . v , val, order) }
175
426
}
176
427
428
+ /// If the current value is the same as expected, store a new value
429
+ ///
430
+ /// Compare the current value with `old`; if they are the same then
431
+ /// replace the current value with `new`. Return the previous value.
432
+ /// If the return value is equal to `old` then the value was updated.
177
433
#[ inline]
178
434
pub fn compare_and_swap ( & mut self , old : int , new : int , order : Ordering ) -> int {
179
435
unsafe { atomic_compare_and_swap ( & mut self . v , old, new, order) }
180
436
}
181
437
182
- /// Returns the old value (like __sync_fetch_and_add).
438
+ /// Add to the current value, returning the previous
439
+ ///
440
+ /// # Examples
441
+ ///
442
+ /// ```
443
+ /// use std::sync::atomics::{AtomicInt, SeqCst};
444
+ ///
445
+ /// let mut foo = AtomicInt::new(0);
446
+ /// assert_eq!(0, foo.fetch_add(10, SeqCst));
447
+ /// assert_eq!(10, foo.load(SeqCst));
448
+ /// ```
183
449
#[ inline]
184
450
pub fn fetch_add ( & mut self , val : int , order : Ordering ) -> int {
185
451
unsafe { atomic_add ( & mut self . v , val, order) }
186
452
}
187
453
188
- /// Returns the old value (like __sync_fetch_and_sub).
454
+ /// Subtract from the current value, returning the previous
455
+ ///
456
+ /// # Examples
457
+ ///
458
+ /// ```
459
+ /// use std::sync::atomics::{AtomicInt, SeqCst};
460
+ ///
461
+ /// let mut foo = AtomicInt::new(0);
462
+ /// assert_eq!(0, foo.fetch_sub(10, SeqCst));
463
+ /// assert_eq!(-10, foo.load(SeqCst));
464
+ /// ```
189
465
#[ inline]
190
466
pub fn fetch_sub ( & mut self , val : int , order : Ordering ) -> int {
191
467
unsafe { atomic_sub ( & mut self . v , val, order) }
@@ -233,65 +509,103 @@ impl AtomicU64 {
233
509
}
234
510
235
511
impl AtomicUint {
512
+ /// Create a new `AtomicUint`
236
513
pub fn new ( v : uint ) -> AtomicUint {
237
514
AtomicUint { v : v, nopod : marker:: NoPod }
238
515
}
239
516
517
+ /// Load the value
240
518
#[ inline]
241
519
pub fn load ( & self , order : Ordering ) -> uint {
242
520
unsafe { atomic_load ( & self . v , order) }
243
521
}
244
522
523
+ /// Store the value
245
524
#[ inline]
246
525
pub fn store ( & mut self , val : uint , order : Ordering ) {
247
526
unsafe { atomic_store ( & mut self . v , val, order) ; }
248
527
}
249
528
529
+ /// Store a value, returning the old value
250
530
#[ inline]
251
531
pub fn swap ( & mut self , val : uint , order : Ordering ) -> uint {
252
532
unsafe { atomic_swap ( & mut self . v , val, order) }
253
533
}
254
534
535
+ /// If the current value is the same as expected, store a new value
536
+ ///
537
+ /// Compare the current value with `old`; if they are the same then
538
+ /// replace the current value with `new`. Return the previous value.
539
+ /// If the return value is equal to `old` then the value was updated.
255
540
#[ inline]
256
541
pub fn compare_and_swap ( & mut self , old : uint , new : uint , order : Ordering ) -> uint {
257
542
unsafe { atomic_compare_and_swap ( & mut self . v , old, new, order) }
258
543
}
259
544
260
- /// Returns the old value (like __sync_fetch_and_add).
545
+ /// Add to the current value, returning the previous
546
+ ///
547
+ /// # Examples
548
+ ///
549
+ /// ```
550
+ /// use std::sync::atomics::{AtomicUint, SeqCst};
551
+ ///
552
+ /// let mut foo = AtomicUint::new(0);
553
+ /// assert_eq!(0, foo.fetch_add(10, SeqCst));
554
+ /// assert_eq!(10, foo.load(SeqCst));
555
+ /// ```
261
556
#[ inline]
262
557
pub fn fetch_add ( & mut self , val : uint , order : Ordering ) -> uint {
263
558
unsafe { atomic_add ( & mut self . v , val, order) }
264
559
}
265
560
266
- /// Returns the old value (like __sync_fetch_and_sub)..
561
+ /// Subtract from the current value, returning the previous
562
+ ///
563
+ /// # Examples
564
+ ///
565
+ /// ```
566
+ /// use std::sync::atomics::{AtomicUint, SeqCst};
567
+ ///
568
+ /// let mut foo = AtomicUint::new(10);
569
+ /// assert_eq!(10, foo.fetch_sub(10, SeqCst));
570
+ /// assert_eq!(0, foo.load(SeqCst));
571
+ /// ```
267
572
#[ inline]
268
573
pub fn fetch_sub ( & mut self , val : uint , order : Ordering ) -> uint {
269
574
unsafe { atomic_sub ( & mut self . v , val, order) }
270
575
}
271
576
}
272
577
273
578
impl < T > AtomicPtr < T > {
579
+ /// Create a new `AtomicPtr`
274
580
pub fn new ( p : * mut T ) -> AtomicPtr < T > {
275
581
AtomicPtr { p : p as uint , nopod : marker:: NoPod }
276
582
}
277
583
584
+ /// Load the value
278
585
#[ inline]
279
586
pub fn load ( & self , order : Ordering ) -> * mut T {
280
587
unsafe {
281
588
atomic_load ( & self . p , order) as * mut T
282
589
}
283
590
}
284
591
592
+ /// Store the value
285
593
#[ inline]
286
594
pub fn store ( & mut self , ptr : * mut T , order : Ordering ) {
287
595
unsafe { atomic_store ( & mut self . p , ptr as uint , order) ; }
288
596
}
289
597
598
+ /// Store a value, returning the old value
290
599
#[ inline]
291
600
pub fn swap ( & mut self , ptr : * mut T , order : Ordering ) -> * mut T {
292
601
unsafe { atomic_swap ( & mut self . p , ptr as uint , order) as * mut T }
293
602
}
294
603
604
+ /// If the current value is the same as expected, store a new value
605
+ ///
606
+ /// Compare the current value with `old`; if they are the same then
607
+ /// replace the current value with `new`. Return the previous value.
608
+ /// If the return value is equal to `old` then the value was updated.
295
609
#[ inline]
296
610
pub fn compare_and_swap ( & mut self , old : * mut T , new : * mut T , order : Ordering ) -> * mut T {
297
611
unsafe {
@@ -302,12 +616,15 @@ impl<T> AtomicPtr<T> {
302
616
}
303
617
304
618
impl < T > AtomicOption < T > {
619
+ /// Create a new `AtomicOption`
305
620
pub fn new ( p : ~T ) -> AtomicOption < T > {
306
621
unsafe { AtomicOption { p : cast:: transmute ( p) } }
307
622
}
308
623
624
+ /// Create a new `AtomicOption` that doesn't contain a value
309
625
pub fn empty ( ) -> AtomicOption < T > { AtomicOption { p : 0 } }
310
626
627
+ /// Store a value, returning the old value
311
628
#[ inline]
312
629
pub fn swap ( & mut self , val : ~T , order : Ordering ) -> Option < ~T > {
313
630
unsafe {
@@ -322,13 +639,16 @@ impl<T> AtomicOption<T> {
322
639
}
323
640
}
324
641
642
+ /// Remove the value, leaving the `AtomicOption` empty.
325
643
#[ inline]
326
644
pub fn take ( & mut self , order : Ordering ) -> Option < ~T > {
327
645
unsafe { self . swap ( cast:: transmute ( 0 ) , order) }
328
646
}
329
647
330
- /// A compare-and-swap. Succeeds if the option is 'None' and returns 'None'
331
- /// if so. If the option was already 'Some', returns 'Some' of the rejected
648
+ /// Replace an empty value with a non-empty value.
649
+ ///
650
+ /// Succeeds if the option is `None` and returns `None` if so. If
651
+ /// the option was already `Some`, returns `Some` of the rejected
332
652
/// value.
333
653
#[ inline]
334
654
pub fn fill ( & mut self , val : ~T , order : Ordering ) -> Option < ~T > {
@@ -344,6 +664,8 @@ impl<T> AtomicOption<T> {
344
664
}
345
665
}
346
666
667
+ /// Returns `true` if the `AtomicOption` is empty.
668
+ ///
347
669
/// Be careful: The caller must have some external method of ensuring the
348
670
/// result does not get invalidated by another task after this returns.
349
671
#[ inline]
@@ -470,32 +792,35 @@ pub unsafe fn atomic_xor<T>(dst: &mut T, val: T, order: Ordering) -> T {
470
792
}
471
793
472
794
473
- /**
474
- * An atomic fence.
475
- *
476
- * A fence 'A' which has `Release` ordering semantics, synchronizes with a
477
- * fence 'B' with (at least) `Acquire` semantics, if and only if there exists
478
- * atomic operations X and Y, both operating on some atomic object 'M' such
479
- * that A is sequenced before X, Y is synchronized before B and Y observers
480
- * the change to M. This provides a happens-before dependence between A and B.
481
- *
482
- * Atomic operations with `Release` or `Acquire` semantics can also synchronize
483
- * with a fence.
484
- *
485
- * A fence with has `SeqCst` ordering, in addition to having both `Acquire` and
486
- * `Release` semantics, participates in the global program order of the other
487
- * `SeqCst` operations and/or fences.
488
- *
489
- * Accepts `Acquire`, `Release`, `AcqRel` and `SeqCst` orderings.
490
- */
795
+ /// An atomic fence.
796
+ ///
797
+ /// A fence 'A' which has `Release` ordering semantics, synchronizes with a
798
+ /// fence 'B' with (at least) `Acquire` semantics, if and only if there exists
799
+ /// atomic operations X and Y, both operating on some atomic object 'M' such
800
+ /// that A is sequenced before X, Y is synchronized before B and Y observers
801
+ /// the change to M. This provides a happens-before dependence between A and B.
802
+ ///
803
+ /// Atomic operations with `Release` or `Acquire` semantics can also synchronize
804
+ /// with a fence.
805
+ ///
806
+ /// A fence with has `SeqCst` ordering, in addition to having both `Acquire` and
807
+ /// `Release` semantics, participates in the global program order of the other
808
+ /// `SeqCst` operations and/or fences.
809
+ ///
810
+ /// Accepts `Acquire`, `Release`, `AcqRel` and `SeqCst` orderings.
811
+ ///
812
+ /// # Failure
813
+ ///
814
+ /// Fails if `order` is `Relaxed`
491
815
#[ inline]
492
816
pub fn fence ( order : Ordering ) {
493
817
unsafe {
494
818
match order {
495
819
Acquire => intrinsics:: atomic_fence_acq ( ) ,
496
820
Release => intrinsics:: atomic_fence_rel ( ) ,
497
- AcqRel => intrinsics:: atomic_fence_rel ( ) ,
498
- _ => intrinsics:: atomic_fence ( ) ,
821
+ AcqRel => intrinsics:: atomic_fence_acqrel ( ) ,
822
+ SeqCst => intrinsics:: atomic_fence ( ) ,
823
+ Relaxed => fail ! ( "there is no such thing as a relaxed fence" )
499
824
}
500
825
}
501
826
}
0 commit comments