Browse Source

Go back to the `spin` crate as a dependency

Bradlee Speice 4 months ago
parent
commit
6d72249253

+ 3
- 3
Cargo.toml View File

@@ -1,6 +1,6 @@
1 1
 [package]
2 2
 name = "qadapt"
3
-version = "1.0.1"
3
+version = "1.0.2"
4 4
 authors = ["Bradlee Speice <bradlee@speice.io>"]
5 5
 description = "The Quick And Dirty Allocation Profiling Tool"
6 6
 license = "Apache-2.0"
@@ -19,9 +19,9 @@ edition = "2018"
19 19
 maintenance = { status = "actively-developed" }
20 20
 
21 21
 [dependencies]
22
+spin = "0.5"
22 23
 thread-id = "3.3"
23
-qadapt-macro = { version = "1.0.0", path = "./qadapt-macro" }
24
-qadapt-spin = { version = "1.0.0", path = "./qadapt-spin" }
24
+qadapt-macro = { version = "1.0.2", path = "./qadapt-macro" }
25 25
 
26 26
 [dev-dependencies]
27 27
 futures = "0.1"

+ 1
- 1
qadapt-macro/Cargo.toml View File

@@ -1,6 +1,6 @@
1 1
 [package]
2 2
 name = "qadapt-macro"
3
-version = "1.0.1"
3
+version = "1.0.2"
4 4
 authors = ["Bradlee Speice <bradlee@speice.io>"]
5 5
 description = "The Quick And Dirty Allocation Profiling Tool - Support Macros"
6 6
 license = "Apache-2.0"

+ 0
- 3
qadapt-spin/.gitignore View File

@@ -1,3 +0,0 @@
1
-/target
2
-**/*.rs.bk
3
-Cargo.lock

+ 0
- 15
qadapt-spin/Cargo.toml View File

@@ -1,15 +0,0 @@
1
-[package]
2
-
3
-name = "qadapt-spin"
4
-version = "1.0.1"
5
-authors = [ "Mathijs van de Nes <git@mathijs.vd-nes.nl>",
6
-            "John Ericson <John_Ericson@Yahoo.com>" ]
7
-license = "MIT"
8
-repository = "https://github.com/mvdnes/spin-rs.git"
9
-documentation = "https://mvdnes.github.io/rust-docs/spin-rs/spin/index.html"
10
-keywords = ["spinlock", "mutex", "rwlock"]
11
-description = """
12
-Synchronization primitives based on spinning.
13
-They may contain data, are usable without `std`,
14
-and static initializers are available.
15
-"""

+ 0
- 21
qadapt-spin/LICENSE View File

@@ -1,21 +0,0 @@
1
-The MIT License (MIT)
2
-
3
-Copyright (c) 2014 Mathijs van de Nes
4
-
5
-Permission is hereby granted, free of charge, to any person obtaining a copy
6
-of this software and associated documentation files (the "Software"), to deal
7
-in the Software without restriction, including without limitation the rights
8
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
-copies of the Software, and to permit persons to whom the Software is
10
-furnished to do so, subject to the following conditions:
11
-
12
-The above copyright notice and this permission notice shall be included in all
13
-copies or substantial portions of the Software.
14
-
15
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
-SOFTWARE.

+ 0
- 4
qadapt-spin/README.md View File

@@ -1,4 +0,0 @@
1
-qadapt-spin
2
-===========
3
-
4
-Placeholder for a stable-compatible [`spin-rs`](https://github.com/mvdnes/spin-rs) crate.

+ 0
- 21
qadapt-spin/examples/debug.rs View File

@@ -1,21 +0,0 @@
1
-extern crate spin;
2
-
3
-fn main() {
4
-    let mutex = spin::Mutex::new(42);
5
-    println!("{:?}", mutex);
6
-    {
7
-        let x = mutex.lock();
8
-        println!("{:?}, {:?}", mutex, *x);
9
-    }
10
-
11
-    let rwlock = spin::RwLock::new(42);
12
-    println!("{:?}", rwlock);
13
-    {
14
-        let x = rwlock.read();
15
-        println!("{:?}, {:?}", rwlock, *x);
16
-    }
17
-    {
18
-        let x = rwlock.write();
19
-        println!("{:?}, {:?}", rwlock, *x);
20
-    }
21
-}

+ 0
- 3
qadapt-spin/script/doc-upload.cfg View File

@@ -1,3 +0,0 @@
1
-PROJECT_NAME=spin-rs
2
-DOCS_REPO=mvdnes/rust-docs.git
3
-DOC_RUST_VERSION=nightly

+ 0
- 18
qadapt-spin/src/lib.rs View File

@@ -1,18 +0,0 @@
1
-#![crate_type = "lib"]
2
-#![warn(missing_docs)]
3
-
4
-//! Synchronization primitives based on spinning
5
-
6
-#![no_std]
7
-
8
-#[cfg(test)]
9
-#[macro_use]
10
-extern crate std;
11
-
12
-pub use mutex::*;
13
-pub use once::*;
14
-pub use rw_lock::*;
15
-
16
-mod mutex;
17
-mod once;
18
-mod rw_lock;

+ 0
- 375
qadapt-spin/src/mutex.rs View File

@@ -1,375 +0,0 @@
1
-use core::cell::UnsafeCell;
2
-use core::default::Default;
3
-use core::fmt;
4
-use core::marker::Sync;
5
-use core::ops::{Deref, DerefMut, Drop};
6
-use core::option::Option::{self, None, Some};
7
-use core::sync::atomic::{spin_loop_hint as cpu_relax, AtomicBool, Ordering, ATOMIC_BOOL_INIT};
8
-
9
-/// This type provides MUTual EXclusion based on spinning.
10
-///
11
-/// # Description
12
-///
13
-/// The behaviour of these lock is similar to their namesakes in `std::sync`. they
14
-/// differ on the following:
15
-///
16
-/// - The lock will not be poisoned in case of failure;
17
-///
18
-/// # Simple examples
19
-///
20
-/// ```
21
-/// use spin;
22
-/// let spin_mutex = spin::Mutex::new(0);
23
-///
24
-/// // Modify the data
25
-/// {
26
-///     let mut data = spin_mutex.lock();
27
-///     *data = 2;
28
-/// }
29
-///
30
-/// // Read the data
31
-/// let answer =
32
-/// {
33
-///     let data = spin_mutex.lock();
34
-///     *data
35
-/// };
36
-///
37
-/// assert_eq!(answer, 2);
38
-/// ```
39
-///
40
-/// # Thread-safety example
41
-///
42
-/// ```
43
-/// use spin;
44
-/// use std::sync::{Arc, Barrier};
45
-///
46
-/// let numthreads = 1000;
47
-/// let spin_mutex = Arc::new(spin::Mutex::new(0));
48
-///
49
-/// // We use a barrier to ensure the readout happens after all writing
50
-/// let barrier = Arc::new(Barrier::new(numthreads + 1));
51
-///
52
-/// for _ in (0..numthreads)
53
-/// {
54
-///     let my_barrier = barrier.clone();
55
-///     let my_lock = spin_mutex.clone();
56
-///     std::thread::spawn(move||
57
-///     {
58
-///         let mut guard = my_lock.lock();
59
-///         *guard += 1;
60
-///
61
-///         // Release the lock to prevent a deadlock
62
-///         drop(guard);
63
-///         my_barrier.wait();
64
-///     });
65
-/// }
66
-///
67
-/// barrier.wait();
68
-///
69
-/// let answer = { *spin_mutex.lock() };
70
-/// assert_eq!(answer, numthreads);
71
-/// ```
72
-pub struct Mutex<T: ?Sized> {
73
-    lock: AtomicBool,
74
-    data: UnsafeCell<T>,
75
-}
76
-
77
-/// A guard to which the protected data can be accessed
78
-///
79
-/// When the guard falls out of scope it will release the lock.
80
-#[derive(Debug)]
81
-pub struct MutexGuard<'a, T: ?Sized + 'a> {
82
-    lock: &'a AtomicBool,
83
-    data: &'a mut T,
84
-}
85
-
86
-// Same unsafe impls as `std::sync::Mutex`
87
-unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
88
-unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
89
-
90
-impl<T> Mutex<T> {
91
-    /// Creates a new spinlock wrapping the supplied data.
92
-    ///
93
-    /// May be used statically:
94
-    ///
95
-    /// ```
96
-    /// use spin;
97
-    ///
98
-    /// static MUTEX: spin::Mutex<()> = spin::Mutex::new(());
99
-    ///
100
-    /// fn demo() {
101
-    ///     let lock = MUTEX.lock();
102
-    ///     // do something with lock
103
-    ///     drop(lock);
104
-    /// }
105
-    /// ```
106
-    pub const fn new(user_data: T) -> Mutex<T> {
107
-        Mutex {
108
-            lock: ATOMIC_BOOL_INIT,
109
-            data: UnsafeCell::new(user_data),
110
-        }
111
-    }
112
-
113
-    /// Consumes this mutex, returning the underlying data.
114
-    pub fn into_inner(self) -> T {
115
-        // We know statically that there are no outstanding references to
116
-        // `self` so there's no need to lock.
117
-        let Mutex { data, .. } = self;
118
-        data.into_inner()
119
-    }
120
-}
121
-
122
-impl<T: ?Sized> Mutex<T> {
123
-    fn obtain_lock(&self) {
124
-        while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false {
125
-            // Wait until the lock looks unlocked before retrying
126
-            while self.lock.load(Ordering::Relaxed) {
127
-                cpu_relax();
128
-            }
129
-        }
130
-    }
131
-
132
-    /// Locks the spinlock and returns a guard.
133
-    ///
134
-    /// The returned value may be dereferenced for data access
135
-    /// and the lock will be dropped when the guard falls out of scope.
136
-    ///
137
-    /// ```
138
-    /// let mylock = spin::Mutex::new(0);
139
-    /// {
140
-    ///     let mut data = mylock.lock();
141
-    ///     // The lock is now locked and the data can be accessed
142
-    ///     *data += 1;
143
-    ///     // The lock is implicitly dropped
144
-    /// }
145
-    ///
146
-    /// ```
147
-    pub fn lock(&self) -> MutexGuard<T> {
148
-        self.obtain_lock();
149
-        MutexGuard {
150
-            lock: &self.lock,
151
-            data: unsafe { &mut *self.data.get() },
152
-        }
153
-    }
154
-
155
-    /// Force unlock the spinlock.
156
-    ///
157
-    /// This is *extremely* unsafe if the lock is not held by the current
158
-    /// thread. However, this can be useful in some instances for exposing the
159
-    /// lock to FFI that doesn't know how to deal with RAII.
160
-    ///
161
-    /// If the lock isn't held, this is a no-op.
162
-    pub unsafe fn force_unlock(&self) {
163
-        self.lock.store(false, Ordering::Release);
164
-    }
165
-
166
-    /// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns
167
-    /// a guard within Some.
168
-    pub fn try_lock(&self) -> Option<MutexGuard<T>> {
169
-        if self.lock.compare_and_swap(false, true, Ordering::Acquire) == false {
170
-            Some(MutexGuard {
171
-                lock: &self.lock,
172
-                data: unsafe { &mut *self.data.get() },
173
-            })
174
-        } else {
175
-            None
176
-        }
177
-    }
178
-}
179
-
180
-impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
181
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182
-        match self.try_lock() {
183
-            Some(guard) => write!(f, "Mutex {{ data: ")
184
-                .and_then(|()| (&*guard).fmt(f))
185
-                .and_then(|()| write!(f, "}}")),
186
-            None => write!(f, "Mutex {{ <locked> }}"),
187
-        }
188
-    }
189
-}
190
-
191
-impl<T: ?Sized + Default> Default for Mutex<T> {
192
-    fn default() -> Mutex<T> {
193
-        Mutex::new(Default::default())
194
-    }
195
-}
196
-
197
-impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
198
-    type Target = T;
199
-    fn deref<'b>(&'b self) -> &'b T {
200
-        &*self.data
201
-    }
202
-}
203
-
204
-impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
205
-    fn deref_mut<'b>(&'b mut self) -> &'b mut T {
206
-        &mut *self.data
207
-    }
208
-}
209
-
210
-impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
211
-    /// The dropping of the MutexGuard will release the lock it was created from.
212
-    fn drop(&mut self) {
213
-        self.lock.store(false, Ordering::Release);
214
-    }
215
-}
216
-
217
-#[cfg(test)]
218
-mod tests {
219
-    use std::prelude::v1::*;
220
-
221
-    use std::sync::atomic::{AtomicUsize, Ordering};
222
-    use std::sync::mpsc::channel;
223
-    use std::sync::Arc;
224
-    use std::thread;
225
-
226
-    use super::*;
227
-
228
-    #[derive(Eq, PartialEq, Debug)]
229
-    struct NonCopy(i32);
230
-
231
-    #[test]
232
-    fn smoke() {
233
-        let m = Mutex::new(());
234
-        drop(m.lock());
235
-        drop(m.lock());
236
-    }
237
-
238
-    #[test]
239
-    fn lots_and_lots() {
240
-        static M: Mutex<()> = Mutex::new(());
241
-        static mut CNT: u32 = 0;
242
-        const J: u32 = 1000;
243
-        const K: u32 = 3;
244
-
245
-        fn inc() {
246
-            for _ in 0..J {
247
-                unsafe {
248
-                    let _g = M.lock();
249
-                    CNT += 1;
250
-                }
251
-            }
252
-        }
253
-
254
-        let (tx, rx) = channel();
255
-        for _ in 0..K {
256
-            let tx2 = tx.clone();
257
-            thread::spawn(move || {
258
-                inc();
259
-                tx2.send(()).unwrap();
260
-            });
261
-            let tx2 = tx.clone();
262
-            thread::spawn(move || {
263
-                inc();
264
-                tx2.send(()).unwrap();
265
-            });
266
-        }
267
-
268
-        drop(tx);
269
-        for _ in 0..2 * K {
270
-            rx.recv().unwrap();
271
-        }
272
-        assert_eq!(unsafe { CNT }, J * K * 2);
273
-    }
274
-
275
-    #[test]
276
-    fn try_lock() {
277
-        let mutex = Mutex::new(42);
278
-
279
-        // First lock succeeds
280
-        let a = mutex.try_lock();
281
-        assert_eq!(a.as_ref().map(|r| **r), Some(42));
282
-
283
-        // Additional lock failes
284
-        let b = mutex.try_lock();
285
-        assert!(b.is_none());
286
-
287
-        // After dropping lock, it succeeds again
288
-        ::core::mem::drop(a);
289
-        let c = mutex.try_lock();
290
-        assert_eq!(c.as_ref().map(|r| **r), Some(42));
291
-    }
292
-
293
-    #[test]
294
-    fn test_into_inner() {
295
-        let m = Mutex::new(NonCopy(10));
296
-        assert_eq!(m.into_inner(), NonCopy(10));
297
-    }
298
-
299
-    #[test]
300
-    fn test_into_inner_drop() {
301
-        struct Foo(Arc<AtomicUsize>);
302
-        impl Drop for Foo {
303
-            fn drop(&mut self) {
304
-                self.0.fetch_add(1, Ordering::SeqCst);
305
-            }
306
-        }
307
-        let num_drops = Arc::new(AtomicUsize::new(0));
308
-        let m = Mutex::new(Foo(num_drops.clone()));
309
-        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
310
-        {
311
-            let _inner = m.into_inner();
312
-            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
313
-        }
314
-        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
315
-    }
316
-
317
-    #[test]
318
-    fn test_mutex_arc_nested() {
319
-        // Tests nested mutexes and access
320
-        // to underlying data.
321
-        let arc = Arc::new(Mutex::new(1));
322
-        let arc2 = Arc::new(Mutex::new(arc));
323
-        let (tx, rx) = channel();
324
-        let _t = thread::spawn(move || {
325
-            let lock = arc2.lock();
326
-            let lock2 = lock.lock();
327
-            assert_eq!(*lock2, 1);
328
-            tx.send(()).unwrap();
329
-        });
330
-        rx.recv().unwrap();
331
-    }
332
-
333
-    #[test]
334
-    fn test_mutex_arc_access_in_unwind() {
335
-        let arc = Arc::new(Mutex::new(1));
336
-        let arc2 = arc.clone();
337
-        let _ = thread::spawn(move || -> () {
338
-            struct Unwinder {
339
-                i: Arc<Mutex<i32>>,
340
-            }
341
-            impl Drop for Unwinder {
342
-                fn drop(&mut self) {
343
-                    *self.i.lock() += 1;
344
-                }
345
-            }
346
-            let _u = Unwinder { i: arc2 };
347
-            panic!();
348
-        })
349
-        .join();
350
-        let lock = arc.lock();
351
-        assert_eq!(*lock, 2);
352
-    }
353
-
354
-    #[test]
355
-    fn test_mutex_unsized() {
356
-        let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
357
-        {
358
-            let b = &mut *mutex.lock();
359
-            b[0] = 4;
360
-            b[2] = 5;
361
-        }
362
-        let comp: &[i32] = &[4, 2, 5];
363
-        assert_eq!(&*mutex.lock(), comp);
364
-    }
365
-
366
-    #[test]
367
-    fn test_mutex_force_lock() {
368
-        let lock = Mutex::new(());
369
-        ::std::mem::forget(lock.lock());
370
-        unsafe {
371
-            lock.force_unlock();
372
-        }
373
-        assert!(lock.try_lock().is_some());
374
-    }
375
-}

+ 0
- 297
qadapt-spin/src/once.rs View File

@@ -1,297 +0,0 @@
1
-use core::cell::UnsafeCell;
2
-use core::fmt;
3
-use core::sync::atomic::{spin_loop_hint as cpu_relax, AtomicUsize, Ordering};
4
-
5
-/// A synchronization primitive which can be used to run a one-time global
6
-/// initialization. Unlike its std equivalent, this is generalized so that The
7
-/// closure returns a value and it is stored. Once therefore acts something like
8
-/// 1a future, too.
9
-///
10
-/// # Examples
11
-///
12
-/// ```
13
-/// use spin;
14
-///
15
-/// static START: spin::Once<()> = spin::Once::new();
16
-///
17
-/// START.call_once(|| {
18
-///     // run initialization here
19
-/// });
20
-/// ```
21
-pub struct Once<T> {
22
-    state: AtomicUsize,
23
-    data: UnsafeCell<Option<T>>, // TODO remove option and use mem::uninitialized
24
-}
25
-
26
-impl<T: fmt::Debug> fmt::Debug for Once<T> {
27
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28
-        match self.try() {
29
-            Some(s) => write!(f, "Once {{ data: ")
30
-                .and_then(|()| s.fmt(f))
31
-                .and_then(|()| write!(f, "}}")),
32
-            None => write!(f, "Once {{ <uninitialized> }}"),
33
-        }
34
-    }
35
-}
36
-
37
-// Same unsafe impls as `std::sync::RwLock`, because this also allows for
38
-// concurrent reads.
39
-unsafe impl<T: Send + Sync> Sync for Once<T> {}
40
-unsafe impl<T: Send> Send for Once<T> {}
41
-
42
-// Four states that a Once can be in, encoded into the lower bits of `state` in
43
-// the Once structure.
44
-const INCOMPLETE: usize = 0x0;
45
-const RUNNING: usize = 0x1;
46
-const COMPLETE: usize = 0x2;
47
-const PANICKED: usize = 0x3;
48
-
49
-use core::hint::unreachable_unchecked as unreachable;
50
-
51
-impl<T> Once<T> {
52
-    /// Initialization constant of `Once`.
53
-    pub const INIT: Self = Once {
54
-        state: AtomicUsize::new(INCOMPLETE),
55
-        data: UnsafeCell::new(None),
56
-    };
57
-
58
-    /// Creates a new `Once` value.
59
-    pub const fn new() -> Once<T> {
60
-        Self::INIT
61
-    }
62
-
63
-    fn force_get<'a>(&'a self) -> &'a T {
64
-        match unsafe { &*self.data.get() }.as_ref() {
65
-            None => unsafe { unreachable() },
66
-            Some(p) => p,
67
-        }
68
-    }
69
-
70
-    /// Performs an initialization routine once and only once. The given closure
71
-    /// will be executed if this is the first time `call_once` has been called,
72
-    /// and otherwise the routine will *not* be invoked.
73
-    ///
74
-    /// This method will block the calling thread if another initialization
75
-    /// routine is currently running.
76
-    ///
77
-    /// When this function returns, it is guaranteed that some initialization
78
-    /// has run and completed (it may not be the closure specified). The
79
-    /// returned pointer will point to the result from the closure that was
80
-    /// ran.
81
-    ///
82
-    /// # Examples
83
-    ///
84
-    /// ```
85
-    /// use spin;
86
-    ///
87
-    /// static INIT: spin::Once<usize> = spin::Once::new();
88
-    ///
89
-    /// fn get_cached_val() -> usize {
90
-    ///     *INIT.call_once(expensive_computation)
91
-    /// }
92
-    ///
93
-    /// fn expensive_computation() -> usize {
94
-    ///     // ...
95
-    /// # 2
96
-    /// }
97
-    /// ```
98
-    pub fn call_once<'a, F>(&'a self, builder: F) -> &'a T
99
-    where
100
-        F: FnOnce() -> T,
101
-    {
102
-        let mut status = self.state.load(Ordering::SeqCst);
103
-
104
-        if status == INCOMPLETE {
105
-            status = self
106
-                .state
107
-                .compare_and_swap(INCOMPLETE, RUNNING, Ordering::SeqCst);
108
-            if status == INCOMPLETE {
109
-                // We init
110
-                // We use a guard (Finish) to catch panics caused by builder
111
-                let mut finish = Finish {
112
-                    state: &self.state,
113
-                    panicked: true,
114
-                };
115
-                unsafe { *self.data.get() = Some(builder()) };
116
-                finish.panicked = false;
117
-
118
-                status = COMPLETE;
119
-                self.state.store(status, Ordering::SeqCst);
120
-
121
-                // This next line is strictly an optomization
122
-                return self.force_get();
123
-            }
124
-        }
125
-
126
-        loop {
127
-            match status {
128
-                INCOMPLETE => unreachable!(),
129
-                RUNNING => {
130
-                    // We spin
131
-                    cpu_relax();
132
-                    status = self.state.load(Ordering::SeqCst)
133
-                }
134
-                PANICKED => panic!("Once has panicked"),
135
-                COMPLETE => return self.force_get(),
136
-                _ => unsafe { unreachable() },
137
-            }
138
-        }
139
-    }
140
-
141
-    /// Returns a pointer iff the `Once` was previously initialized
142
-    pub fn try<'a>(&'a self) -> Option<&'a T> {
143
-        match self.state.load(Ordering::SeqCst) {
144
-            COMPLETE => Some(self.force_get()),
145
-            _ => None,
146
-        }
147
-    }
148
-
149
-    /// Like try, but will spin if the `Once` is in the process of being
150
-    /// initialized
151
-    pub fn wait<'a>(&'a self) -> Option<&'a T> {
152
-        loop {
153
-            match self.state.load(Ordering::SeqCst) {
154
-                INCOMPLETE => return None,
155
-                RUNNING => cpu_relax(), // We spin
156
-                COMPLETE => return Some(self.force_get()),
157
-                PANICKED => panic!("Once has panicked"),
158
-                _ => unsafe { unreachable() },
159
-            }
160
-        }
161
-    }
162
-}
163
-
164
-struct Finish<'a> {
165
-    state: &'a AtomicUsize,
166
-    panicked: bool,
167
-}
168
-
169
-impl<'a> Drop for Finish<'a> {
170
-    fn drop(&mut self) {
171
-        if self.panicked {
172
-            self.state.store(PANICKED, Ordering::SeqCst);
173
-        }
174
-    }
175
-}
176
-
177
-#[cfg(test)]
178
-mod tests {
179
-    use std::prelude::v1::*;
180
-
181
-    use super::Once;
182
-    use std::sync::mpsc::channel;
183
-    use std::thread;
184
-
185
-    #[test]
186
-    fn smoke_once() {
187
-        static O: Once<()> = Once::new();
188
-        let mut a = 0;
189
-        O.call_once(|| a += 1);
190
-        assert_eq!(a, 1);
191
-        O.call_once(|| a += 1);
192
-        assert_eq!(a, 1);
193
-    }
194
-
195
-    #[test]
196
-    fn smoke_once_value() {
197
-        static O: Once<usize> = Once::new();
198
-        let a = O.call_once(|| 1);
199
-        assert_eq!(*a, 1);
200
-        let b = O.call_once(|| 2);
201
-        assert_eq!(*b, 1);
202
-    }
203
-
204
-    #[test]
205
-    fn stampede_once() {
206
-        static O: Once<()> = Once::new();
207
-        static mut RUN: bool = false;
208
-
209
-        let (tx, rx) = channel();
210
-        for _ in 0..10 {
211
-            let tx = tx.clone();
212
-            thread::spawn(move || {
213
-                for _ in 0..4 {
214
-                    thread::yield_now()
215
-                }
216
-                unsafe {
217
-                    O.call_once(|| {
218
-                        assert!(!RUN);
219
-                        RUN = true;
220
-                    });
221
-                    assert!(RUN);
222
-                }
223
-                tx.send(()).unwrap();
224
-            });
225
-        }
226
-
227
-        unsafe {
228
-            O.call_once(|| {
229
-                assert!(!RUN);
230
-                RUN = true;
231
-            });
232
-            assert!(RUN);
233
-        }
234
-
235
-        for _ in 0..10 {
236
-            rx.recv().unwrap();
237
-        }
238
-    }
239
-
240
-    #[test]
241
-    fn try() {
242
-        static INIT: Once<usize> = Once::new();
243
-
244
-        assert!(INIT.try().is_none());
245
-        INIT.call_once(|| 2);
246
-        assert_eq!(INIT.try().map(|r| *r), Some(2));
247
-    }
248
-
249
-    #[test]
250
-    fn try_no_wait() {
251
-        static INIT: Once<usize> = Once::new();
252
-
253
-        assert!(INIT.try().is_none());
254
-        thread::spawn(move || {
255
-            INIT.call_once(|| loop {});
256
-        });
257
-        assert!(INIT.try().is_none());
258
-    }
259
-
260
-    #[test]
261
-    fn wait() {
262
-        static INIT: Once<usize> = Once::new();
263
-
264
-        assert!(INIT.wait().is_none());
265
-        INIT.call_once(|| 3);
266
-        assert_eq!(INIT.wait().map(|r| *r), Some(3));
267
-    }
268
-
269
-    #[test]
270
-    fn panic() {
271
-        use std::panic;
272
-
273
-        static INIT: Once<()> = Once::new();
274
-
275
-        // poison the once
276
-        let t = panic::catch_unwind(|| {
277
-            INIT.call_once(|| panic!());
278
-        });
279
-        assert!(t.is_err());
280
-
281
-        // poisoning propagates
282
-        let t = panic::catch_unwind(|| {
283
-            INIT.call_once(|| {});
284
-        });
285
-        assert!(t.is_err());
286
-    }
287
-
288
-    #[test]
289
-    fn init_constant() {
290
-        static O: Once<()> = Once::INIT;
291
-        let mut a = 0;
292
-        O.call_once(|| a += 1);
293
-        assert_eq!(a, 1);
294
-        O.call_once(|| a += 1);
295
-        assert_eq!(a, 1);
296
-    }
297
-}

+ 0
- 539
qadapt-spin/src/rw_lock.rs View File

@@ -1,539 +0,0 @@
1
-use core::cell::UnsafeCell;
2
-use core::default::Default;
3
-use core::fmt;
4
-use core::ops::{Deref, DerefMut};
5
-use core::sync::atomic::{spin_loop_hint as cpu_relax, AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
6
-
7
-/// A reader-writer lock
8
-///
9
-/// This type of lock allows a number of readers or at most one writer at any
10
-/// point in time. The write portion of this lock typically allows modification
11
-/// of the underlying data (exclusive access) and the read portion of this lock
12
-/// typically allows for read-only access (shared access).
13
-///
14
-/// The type parameter `T` represents the data that this lock protects. It is
15
-/// required that `T` satisfies `Send` to be shared across tasks and `Sync` to
16
-/// allow concurrent access through readers. The RAII guards returned from the
17
-/// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
18
-/// to allow access to the contained of the lock.
19
-///
20
-/// Based on
21
-/// <https://jfdube.wordpress.com/2014/01/03/implementing-a-recursive-read-write-spinlock/>
22
-///
23
-/// # Examples
24
-///
25
-/// ```
26
-/// use spin;
27
-///
28
-/// let lock = spin::RwLock::new(5);
29
-///
30
-/// // many reader locks can be held at once
31
-/// {
32
-///     let r1 = lock.read();
33
-///     let r2 = lock.read();
34
-///     assert_eq!(*r1, 5);
35
-///     assert_eq!(*r2, 5);
36
-/// } // read locks are dropped at this point
37
-///
38
-/// // only one write lock may be held, however
39
-/// {
40
-///     let mut w = lock.write();
41
-///     *w += 1;
42
-///     assert_eq!(*w, 6);
43
-/// } // write lock is dropped here
44
-/// ```
45
-pub struct RwLock<T: ?Sized> {
46
-    lock: AtomicUsize,
47
-    data: UnsafeCell<T>,
48
-}
49
-
50
-/// A guard to which the protected data can be read
51
-///
52
-/// When the guard falls out of scope it will decrement the read count,
53
-/// potentially releasing the lock.
54
-#[derive(Debug)]
55
-pub struct RwLockReadGuard<'a, T: 'a + ?Sized> {
56
-    lock: &'a AtomicUsize,
57
-    data: &'a T,
58
-}
59
-
60
-/// A guard to which the protected data can be written
61
-///
62
-/// When the guard falls out of scope it will release the lock.
63
-#[derive(Debug)]
64
-pub struct RwLockWriteGuard<'a, T: 'a + ?Sized> {
65
-    lock: &'a AtomicUsize,
66
-    data: &'a mut T,
67
-}
68
-
69
-// Same unsafe impls as `std::sync::RwLock`
70
-unsafe impl<T: ?Sized + Send> Send for RwLock<T> {}
71
-unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
72
-
73
-const USIZE_MSB: usize = ::core::isize::MIN as usize;
74
-
75
-impl<T> RwLock<T> {
76
-    /// Creates a new spinlock wrapping the supplied data.
77
-    ///
78
-    /// May be used statically:
79
-    ///
80
-    /// ```
81
-    /// use spin;
82
-    ///
83
-    /// static RW_LOCK: spin::RwLock<()> = spin::RwLock::new(());
84
-    ///
85
-    /// fn demo() {
86
-    ///     let lock = RW_LOCK.read();
87
-    ///     // do something with lock
88
-    ///     drop(lock);
89
-    /// }
90
-    /// ```
91
-    #[inline]
92
-    pub const fn new(user_data: T) -> RwLock<T> {
93
-        RwLock {
94
-            lock: ATOMIC_USIZE_INIT,
95
-            data: UnsafeCell::new(user_data),
96
-        }
97
-    }
98
-
99
-    /// Consumes this `RwLock`, returning the underlying data.
100
-    pub fn into_inner(self) -> T {
101
-        // We know statically that there are no outstanding references to
102
-        // `self` so there's no need to lock.
103
-        let RwLock { data, .. } = self;
104
-        data.into_inner()
105
-    }
106
-}
107
-
108
-impl<T: ?Sized> RwLock<T> {
109
-    /// Locks this rwlock with shared read access, blocking the current thread
110
-    /// until it can be acquired.
111
-    ///
112
-    /// The calling thread will be blocked until there are no more writers which
113
-    /// hold the lock. There may be other readers currently inside the lock when
114
-    /// this method returns. This method does not provide any guarantees with
115
-    /// respect to the ordering of whether contentious readers or writers will
116
-    /// acquire the lock first.
117
-    ///
118
-    /// Returns an RAII guard which will release this thread's shared access
119
-    /// once it is dropped.
120
-    ///
121
-    /// ```
122
-    /// let mylock = spin::RwLock::new(0);
123
-    /// {
124
-    ///     let mut data = mylock.read();
125
-    ///     // The lock is now locked and the data can be read
126
-    ///     println!("{}", *data);
127
-    ///     // The lock is dropped
128
-    /// }
129
-    /// ```
130
-    #[inline]
131
-    pub fn read<'a>(&'a self) -> RwLockReadGuard<'a, T> {
132
-        // (funny do-while loop)
133
-        while {
134
-            // Old value, with write bit unset
135
-            let mut old;
136
-
137
-            // Wait for for writer to go away before doing expensive atomic ops
138
-            // (funny do-while loop)
139
-            while {
140
-                old = self.lock.load(Ordering::Relaxed);
141
-                old & USIZE_MSB != 0
142
-            } {
143
-                cpu_relax();
144
-            }
145
-
146
-            // unset write bit
147
-            old &= !USIZE_MSB;
148
-
149
-            let new = old + 1;
150
-            debug_assert!(new != (!USIZE_MSB) & (!0));
151
-
152
-            self.lock.compare_and_swap(old, new, Ordering::SeqCst) != old
153
-        } {
154
-            cpu_relax();
155
-        }
156
-        RwLockReadGuard {
157
-            lock: &self.lock,
158
-            data: unsafe { &*self.data.get() },
159
-        }
160
-    }
161
-
162
-    /// Attempt to acquire this lock with shared read access.
163
-    ///
164
-    /// This function will never block and will return immediately if `read`
165
-    /// would otherwise succeed. Returns `Some` of an RAII guard which will
166
-    /// release the shared access of this thread when dropped, or `None` if the
167
-    /// access could not be granted. This method does not provide any
168
-    /// guarantees with respect to the ordering of whether contentious readers
169
-    /// or writers will acquire the lock first.
170
-    ///
171
-    /// ```
172
-    /// let mylock = spin::RwLock::new(0);
173
-    /// {
174
-    ///     match mylock.try_read() {
175
-    ///         Some(data) => {
176
-    ///             // The lock is now locked and the data can be read
177
-    ///             println!("{}", *data);
178
-    ///             // The lock is dropped
179
-    ///         },
180
-    ///         None => (), // no cigar
181
-    ///     };
182
-    /// }
183
-    /// ```
184
-    #[inline]
185
-    pub fn try_read(&self) -> Option<RwLockReadGuard<T>> {
186
-        // Old value, with write bit unset
187
-        let old = (!USIZE_MSB) & self.lock.load(Ordering::Relaxed);
188
-
189
-        let new = old + 1;
190
-        debug_assert!(new != (!USIZE_MSB) & (!0));
191
-        if self.lock.compare_and_swap(old, new, Ordering::SeqCst) == old {
192
-            Some(RwLockReadGuard {
193
-                lock: &self.lock,
194
-                data: unsafe { &*self.data.get() },
195
-            })
196
-        } else {
197
-            None
198
-        }
199
-    }
200
-
201
-    /// Force decrement the reader count.
202
-    ///
203
-    /// This is *extremely* unsafe if there are outstanding `RwLockReadGuard`s
204
-    /// live, or if called more times than `read` has been called, but can be
205
-    /// useful in FFI contexts where the caller doesn't know how to deal with
206
-    /// RAII.
207
-    pub unsafe fn force_read_decrement(&self) {
208
-        debug_assert!(self.lock.load(Ordering::Relaxed) & (!USIZE_MSB) > 0);
209
-        self.lock.fetch_sub(1, Ordering::SeqCst);
210
-    }
211
-
212
-    /// Force unlock exclusive write access.
213
-    ///
214
-    /// This is *extremely* unsafe if there are outstanding `RwLockWriteGuard`s
215
-    /// live, or if called when there are current readers, but can be useful in
216
-    /// FFI contexts where the caller doesn't know how to deal with RAII.
217
-    pub unsafe fn force_write_unlock(&self) {
218
-        debug_assert_eq!(self.lock.load(Ordering::Relaxed), USIZE_MSB);
219
-        self.lock.store(0, Ordering::Relaxed);
220
-    }
221
-
222
-    /// Lock this rwlock with exclusive write access, blocking the current
223
-    /// thread until it can be acquired.
224
-    ///
225
-    /// This function will not return while other writers or other readers
226
-    /// currently have access to the lock.
227
-    ///
228
-    /// Returns an RAII guard which will drop the write access of this rwlock
229
-    /// when dropped.
230
-    ///
231
-    /// ```
232
-    /// let mylock = spin::RwLock::new(0);
233
-    /// {
234
-    ///     let mut data = mylock.write();
235
-    ///     // The lock is now locked and the data can be written
236
-    ///     *data += 1;
237
-    ///     // The lock is dropped
238
-    /// }
239
-    /// ```
240
-    #[inline]
241
-    pub fn write<'a>(&'a self) -> RwLockWriteGuard<'a, T> {
242
-        loop {
243
-            // Old value, with write bit unset.
244
-            let old = (!USIZE_MSB) & self.lock.load(Ordering::Relaxed);
245
-            // Old value, with write bit set.
246
-            let new = USIZE_MSB | old;
247
-            if self.lock.compare_and_swap(old, new, Ordering::SeqCst) == old {
248
-                // Wait for readers to go away, then lock is ours.
249
-                while self.lock.load(Ordering::Relaxed) != USIZE_MSB {
250
-                    cpu_relax();
251
-                }
252
-                break;
253
-            }
254
-        }
255
-        RwLockWriteGuard {
256
-            lock: &self.lock,
257
-            data: unsafe { &mut *self.data.get() },
258
-        }
259
-    }
260
-
261
-    /// Attempt to lock this rwlock with exclusive write access.
262
-    ///
263
-    /// This function does not ever block, and it will return `None` if a call
264
-    /// to `write` would otherwise block. If successful, an RAII guard is
265
-    /// returned.
266
-    ///
267
-    /// ```
268
-    /// let mylock = spin::RwLock::new(0);
269
-    /// {
270
-    ///     match mylock.try_write() {
271
-    ///         Some(mut data) => {
272
-    ///             // The lock is now locked and the data can be written
273
-    ///             *data += 1;
274
-    ///             // The lock is implicitly dropped
275
-    ///         },
276
-    ///         None => (), // no cigar
277
-    ///     };
278
-    /// }
279
-    /// ```
280
-    #[inline]
281
-    pub fn try_write(&self) -> Option<RwLockWriteGuard<T>> {
282
-        if self.lock.compare_and_swap(0, USIZE_MSB, Ordering::SeqCst) == 0 {
283
-            Some(RwLockWriteGuard {
284
-                lock: &self.lock,
285
-                data: unsafe { &mut *self.data.get() },
286
-            })
287
-        } else {
288
-            None
289
-        }
290
-    }
291
-}
292
-
293
-impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
294
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
295
-        match self.try_read() {
296
-            Some(guard) => write!(f, "RwLock {{ data: ")
297
-                .and_then(|()| (&*guard).fmt(f))
298
-                .and_then(|()| write!(f, "}}")),
299
-            None => write!(f, "RwLock {{ <locked> }}"),
300
-        }
301
-    }
302
-}
303
-
304
-impl<T: ?Sized + Default> Default for RwLock<T> {
305
-    fn default() -> RwLock<T> {
306
-        RwLock::new(Default::default())
307
-    }
308
-}
309
-
310
-impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> {
311
-    type Target = T;
312
-
313
-    fn deref(&self) -> &T {
314
-        self.data
315
-    }
316
-}
317
-
318
-impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> {
319
-    type Target = T;
320
-
321
-    fn deref(&self) -> &T {
322
-        self.data
323
-    }
324
-}
325
-
326
-impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> {
327
-    fn deref_mut(&mut self) -> &mut T {
328
-        self.data
329
-    }
330
-}
331
-
332
-impl<'rwlock, T: ?Sized> Drop for RwLockReadGuard<'rwlock, T> {
333
-    fn drop(&mut self) {
334
-        debug_assert!(self.lock.load(Ordering::Relaxed) & (!USIZE_MSB) > 0);
335
-        self.lock.fetch_sub(1, Ordering::SeqCst);
336
-    }
337
-}
338
-
339
-impl<'rwlock, T: ?Sized> Drop for RwLockWriteGuard<'rwlock, T> {
340
-    fn drop(&mut self) {
341
-        debug_assert_eq!(self.lock.load(Ordering::Relaxed), USIZE_MSB);
342
-        self.lock.store(0, Ordering::Relaxed);
343
-    }
344
-}
345
-
346
-#[cfg(test)]
347
-mod tests {
348
-    use std::prelude::v1::*;
349
-
350
-    use std::sync::atomic::{AtomicUsize, Ordering};
351
-    use std::sync::mpsc::channel;
352
-    use std::sync::Arc;
353
-    use std::thread;
354
-
355
-    use super::*;
356
-
357
-    #[derive(Eq, PartialEq, Debug)]
358
-    struct NonCopy(i32);
359
-
360
-    #[test]
361
-    fn smoke() {
362
-        let l = RwLock::new(());
363
-        drop(l.read());
364
-        drop(l.write());
365
-        drop((l.read(), l.read()));
366
-        drop(l.write());
367
-    }
368
-
369
-    // TODO: needs RNG
370
-    //#[test]
371
-    //fn frob() {
372
-    //    static R: RwLock = RwLock::new();
373
-    //    const N: usize = 10;
374
-    //    const M: usize = 1000;
375
-    //
376
-    //    let (tx, rx) = channel::<()>();
377
-    //    for _ in 0..N {
378
-    //        let tx = tx.clone();
379
-    //        thread::spawn(move|| {
380
-    //            let mut rng = rand::thread_rng();
381
-    //            for _ in 0..M {
382
-    //                if rng.gen_weighted_bool(N) {
383
-    //                    drop(R.write());
384
-    //                } else {
385
-    //                    drop(R.read());
386
-    //                }
387
-    //            }
388
-    //            drop(tx);
389
-    //        });
390
-    //    }
391
-    //    drop(tx);
392
-    //    let _ = rx.recv();
393
-    //    unsafe { R.destroy(); }
394
-    //}
395
-
396
-    #[test]
397
-    fn test_rw_arc() {
398
-        let arc = Arc::new(RwLock::new(0));
399
-        let arc2 = arc.clone();
400
-        let (tx, rx) = channel();
401
-
402
-        thread::spawn(move || {
403
-            let mut lock = arc2.write();
404
-            for _ in 0..10 {
405
-                let tmp = *lock;
406
-                *lock = -1;
407
-                thread::yield_now();
408
-                *lock = tmp + 1;
409
-            }
410
-            tx.send(()).unwrap();
411
-        });
412
-
413
-        // Readers try to catch the writer in the act
414
-        let mut children = Vec::new();
415
-        for _ in 0..5 {
416
-            let arc3 = arc.clone();
417
-            children.push(thread::spawn(move || {
418
-                let lock = arc3.read();
419
-                assert!(*lock >= 0);
420
-            }));
421
-        }
422
-
423
-        // Wait for children to pass their asserts
424
-        for r in children {
425
-            assert!(r.join().is_ok());
426
-        }
427
-
428
-        // Wait for writer to finish
429
-        rx.recv().unwrap();
430
-        let lock = arc.read();
431
-        assert_eq!(*lock, 10);
432
-    }
433
-
434
-    #[test]
435
-    fn test_rw_arc_access_in_unwind() {
436
-        let arc = Arc::new(RwLock::new(1));
437
-        let arc2 = arc.clone();
438
-        let _ = thread::spawn(move || -> () {
439
-            struct Unwinder {
440
-                i: Arc<RwLock<isize>>,
441
-            }
442
-            impl Drop for Unwinder {
443
-                fn drop(&mut self) {
444
-                    let mut lock = self.i.write();
445
-                    *lock += 1;
446
-                }
447
-            }
448
-            let _u = Unwinder { i: arc2 };
449
-            panic!();
450
-        })
451
-        .join();
452
-        let lock = arc.read();
453
-        assert_eq!(*lock, 2);
454
-    }
455
-
456
-    #[test]
457
-    fn test_rwlock_unsized() {
458
-        let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
459
-        {
460
-            let b = &mut *rw.write();
461
-            b[0] = 4;
462
-            b[2] = 5;
463
-        }
464
-        let comp: &[i32] = &[4, 2, 5];
465
-        assert_eq!(&*rw.read(), comp);
466
-    }
467
-
468
-    #[test]
469
-    fn test_rwlock_try_write() {
470
-        use std::mem::drop;
471
-
472
-        let lock = RwLock::new(0isize);
473
-        let read_guard = lock.read();
474
-
475
-        let write_result = lock.try_write();
476
-        match write_result {
477
-            None => (),
478
-            Some(_) => assert!(
479
-                false,
480
-                "try_write should not succeed while read_guard is in scope"
481
-            ),
482
-        }
483
-
484
-        drop(read_guard);
485
-    }
486
-
487
-    #[test]
488
-    fn test_into_inner() {
489
-        let m = RwLock::new(NonCopy(10));
490
-        assert_eq!(m.into_inner(), NonCopy(10));
491
-    }
492
-
493
-    #[test]
494
-    fn test_into_inner_drop() {
495
-        struct Foo(Arc<AtomicUsize>);
496
-        impl Drop for Foo {
497
-            fn drop(&mut self) {
498
-                self.0.fetch_add(1, Ordering::SeqCst);
499
-            }
500
-        }
501
-        let num_drops = Arc::new(AtomicUsize::new(0));
502
-        let m = RwLock::new(Foo(num_drops.clone()));
503
-        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
504
-        {
505
-            let _inner = m.into_inner();
506
-            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
507
-        }
508
-        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
509
-    }
510
-
511
-    #[test]
512
-    fn test_force_read_decrement() {
513
-        let m = RwLock::new(());
514
-        ::std::mem::forget(m.read());
515
-        ::std::mem::forget(m.read());
516
-        ::std::mem::forget(m.read());
517
-        assert!(m.try_write().is_none());
518
-        unsafe {
519
-            m.force_read_decrement();
520
-            m.force_read_decrement();
521
-        }
522
-        assert!(m.try_write().is_none());
523
-        unsafe {
524
-            m.force_read_decrement();
525
-        }
526
-        assert!(m.try_write().is_some());
527
-    }
528
-
529
-    #[test]
530
-    fn test_force_write_unlock() {
531
-        let m = RwLock::new(());
532
-        ::std::mem::forget(m.write());
533
-        assert!(m.try_read().is_none());
534
-        unsafe {
535
-            m.force_write_unlock();
536
-        }
537
-        assert!(m.try_read().is_some());
538
-    }
539
-}

+ 1
- 1
src/lib.rs View File

@@ -69,7 +69,7 @@ use thread_id;
69 69
 // Re-export the proc macros to use by other code
70 70
 pub use qadapt_macro::*;
71 71
 
72
-use qadapt_spin::RwLock;
72
+use spin::RwLock;
73 73
 use std::alloc::GlobalAlloc;
74 74
 use std::alloc::Layout;
75 75
 use std::alloc::System;

Loading…
Cancel
Save