Remove the NO_CAS version of spin_pdr locks
[akaros.git] / user / parlib / spinlock.c
1 /* Copyright (c) 2013 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * Kevin Klues <klueska@cs.berkeley.edu>
4  *
5  * See LICENSE for details. */
6
7 #include <stdlib.h>
8 #include <errno.h>
9 #include <parlib/assert.h>
10
11 #include <parlib/spinlock.h>
12 #include <parlib/vcore.h>
13 #include <parlib/uthread.h>
14
15 void spinlock_init(spinlock_t *lock)
16 {
17         lock->lock = 0;
18 }
19
20 int spinlock_trylock(spinlock_t *lock) 
21 {
22         if (lock->lock)
23                 return EBUSY;
24         return __sync_lock_test_and_set(&lock->lock, EBUSY);
25 }
26
27 void spinlock_lock(spinlock_t *lock) 
28 {
29         while (spinlock_trylock(lock))
30                 cpu_relax();
31 }
32
33 void spinlock_unlock(spinlock_t *lock) 
34 {
35         __sync_lock_release(&lock->lock, 0);
36 }
37
38 bool spinlock_locked(spinlock_t *lock)
39 {
40         return lock->lock != 0;
41 }
42
43 /* Spin-PRD locks (preemption detection/recovery).  Idea is to CAS and put the
44  * lockholder's vcoreid in the lock, and all spinners ensure that vcore runs. */
45 void spin_pdr_init(struct spin_pdr_lock *pdr_lock)
46 {
47         pdr_lock->lock = SPINPDR_UNLOCKED;
48 }
49
50 /* Internal version of the locking func, doesn't care if notifs are disabled */
51 void __spin_pdr_lock(struct spin_pdr_lock *pdr_lock)
52 {
53         uint32_t vcoreid = vcore_id();
54         uint32_t lock_val;
55         do {
56                 while ((lock_val = pdr_lock->lock) != SPINPDR_UNLOCKED) {
57                         ensure_vcore_runs(lock_val);
58                         cmb();
59                 }
60         } while (!atomic_cas_u32(&pdr_lock->lock, lock_val, vcoreid));
61         cmb();  /* just need a cmb, the CAS handles the CPU wmb/wrmb() */
62 }
63
64 void __spin_pdr_unlock(struct spin_pdr_lock *pdr_lock)
65 {
66         /* could make an arch-dependent 'release barrier' out of these */
67         wmb();  /* Need to prevent the compiler from reordering older stores. */
68         rwmb(); /* And no old reads passing either.   x86 makes both mbs a cmb() */
69         pdr_lock->lock = SPINPDR_UNLOCKED;
70 }
71
72 bool spin_pdr_locked(struct spin_pdr_lock *pdr_lock)
73 {
74         return pdr_lock->lock != SPINPDR_UNLOCKED;
75 }
76
77 void spin_pdr_lock(struct spin_pdr_lock *pdr_lock)
78 {
79         /* Disable notifs, if we're an _M uthread */
80         uth_disable_notifs();
81         __spin_pdr_lock(pdr_lock);
82 }
83
84 void spin_pdr_unlock(struct spin_pdr_lock *pdr_lock)
85 {
86         __spin_pdr_unlock(pdr_lock);
87         /* Enable notifs, if we're an _M uthread */
88         uth_enable_notifs();
89 }