1 #ifndef LOCKS_H 2 #define LOCKS_H 3 4 #include <limits.h> 5 #include <pthread.h> 6 #include <stdbool.h> 7 8 #include "assume.h" 9 #include "bug_on.h" 10 #include "preempt.h" 11 12 int nondet_int(void); 13 14 #define __acquire(x) 15 #define __acquires(x) 16 #define __release(x) 17 #define __releases(x) 18 19 /* Only use one lock mechanism. Select which one. */ 20 #ifdef PTHREAD_LOCK 21 struct lock_impl { 22 pthread_mutex_t mutex; 23 }; 24 25 static inline void lock_impl_lock(struct lock_impl *lock) 26 { 27 BUG_ON(pthread_mutex_lock(&lock->mutex)); 28 } 29 30 static inline void lock_impl_unlock(struct lock_impl *lock) 31 { 32 BUG_ON(pthread_mutex_unlock(&lock->mutex)); 33 } 34 35 static inline bool lock_impl_trylock(struct lock_impl *lock) 36 { 37 int err = pthread_mutex_trylock(&lock->mutex); 38 39 if (!err) 40 return true; 41 else if (err == EBUSY) 42 return false; 43 BUG(); 44 } 45 46 static inline void lock_impl_init(struct lock_impl *lock) 47 { 48 pthread_mutex_init(&lock->mutex, NULL); 49 } 50 51 #define LOCK_IMPL_INITIALIZER {.mutex = PTHREAD_MUTEX_INITIALIZER} 52 53 #else /* !defined(PTHREAD_LOCK) */ 54 /* Spinlock that assumes that it always gets the lock immediately. */ 55 56 struct lock_impl { 57 bool locked; 58 }; 59 60 static inline bool lock_impl_trylock(struct lock_impl *lock) 61 { 62 #ifdef RUN 63 /* TODO: Should this be a test and set? */ 64 return __sync_bool_compare_and_swap(&lock->locked, false, true); 65 #else 66 __CPROVER_atomic_begin(); 67 bool old_locked = lock->locked; 68 lock->locked = true; 69 __CPROVER_atomic_end(); 70 71 /* Minimal barrier to prevent accesses leaking out of lock. */ 72 __CPROVER_fence("RRfence", "RWfence"); 73 74 return !old_locked; 75 #endif 76 } 77 78 static inline void lock_impl_lock(struct lock_impl *lock) 79 { 80 /* 81 * CBMC doesn't support busy waiting, so just assume that the 82 * lock is available. 83 */ 84 assume(lock_impl_trylock(lock)); 85 86 /* 87 * If the lock was already held by this thread then the assumption 88 * is unsatisfiable (deadlock). 89 */ 90 } 91 92 static inline void lock_impl_unlock(struct lock_impl *lock) 93 { 94 #ifdef RUN 95 BUG_ON(!__sync_bool_compare_and_swap(&lock->locked, true, false)); 96 #else 97 /* Minimal barrier to prevent accesses leaking out of lock. */ 98 __CPROVER_fence("RWfence", "WWfence"); 99 100 __CPROVER_atomic_begin(); 101 bool old_locked = lock->locked; 102 lock->locked = false; 103 __CPROVER_atomic_end(); 104 105 BUG_ON(!old_locked); 106 #endif 107 } 108 109 static inline void lock_impl_init(struct lock_impl *lock) 110 { 111 lock->locked = false; 112 } 113 114 #define LOCK_IMPL_INITIALIZER {.locked = false} 115 116 #endif /* !defined(PTHREAD_LOCK) */ 117 118 /* 119 * Implement spinlocks using the lock mechanism. Wrap the lock to prevent mixing 120 * locks of different types. 121 */ 122 typedef struct { 123 struct lock_impl internal_lock; 124 } spinlock_t; 125 126 #define SPIN_LOCK_UNLOCKED {.internal_lock = LOCK_IMPL_INITIALIZER} 127 #define __SPIN_LOCK_UNLOCKED(x) SPIN_LOCK_UNLOCKED 128 #define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED 129 130 static inline void spin_lock_init(spinlock_t *lock) 131 { 132 lock_impl_init(&lock->internal_lock); 133 } 134 135 static inline void spin_lock(spinlock_t *lock) 136 { 137 /* 138 * Spin locks also need to be removed in order to eliminate all 139 * memory barriers. They are only used by the write side anyway. 140 */ 141 #ifndef NO_SYNC_SMP_MB 142 preempt_disable(); 143 lock_impl_lock(&lock->internal_lock); 144 #endif 145 } 146 147 static inline void spin_unlock(spinlock_t *lock) 148 { 149 #ifndef NO_SYNC_SMP_MB 150 lock_impl_unlock(&lock->internal_lock); 151 preempt_enable(); 152 #endif 153 } 154 155 /* Don't bother with interrupts */ 156 #define spin_lock_irq(lock) spin_lock(lock) 157 #define spin_unlock_irq(lock) spin_unlock(lock) 158 #define spin_lock_irqsave(lock, flags) spin_lock(lock) 159 #define spin_unlock_irqrestore(lock, flags) spin_unlock(lock) 160 161 /* 162 * This is supposed to return an int, but I think that a bool should work as 163 * well. 164 */ 165 static inline bool spin_trylock(spinlock_t *lock) 166 { 167 #ifndef NO_SYNC_SMP_MB 168 preempt_disable(); 169 return lock_impl_trylock(&lock->internal_lock); 170 #else 171 return true; 172 #endif 173 } 174 175 struct completion { 176 /* Hopefuly this won't overflow. */ 177 unsigned int count; 178 }; 179 180 #define COMPLETION_INITIALIZER(x) {.count = 0} 181 #define DECLARE_COMPLETION(x) struct completion x = COMPLETION_INITIALIZER(x) 182 #define DECLARE_COMPLETION_ONSTACK(x) DECLARE_COMPLETION(x) 183 184 static inline void init_completion(struct completion *c) 185 { 186 c->count = 0; 187 } 188 189 static inline void wait_for_completion(struct completion *c) 190 { 191 unsigned int prev_count = __sync_fetch_and_sub(&c->count, 1); 192 193 assume(prev_count); 194 } 195 196 static inline void complete(struct completion *c) 197 { 198 unsigned int prev_count = __sync_fetch_and_add(&c->count, 1); 199 200 BUG_ON(prev_count == UINT_MAX); 201 } 202 203 /* This function probably isn't very useful for CBMC. */ 204 static inline bool try_wait_for_completion(struct completion *c) 205 { 206 BUG(); 207 } 208 209 static inline bool completion_done(struct completion *c) 210 { 211 return c->count; 212 } 213 214 /* TODO: Implement complete_all */ 215 static inline void complete_all(struct completion *c) 216 { 217 BUG(); 218 } 219 220 #endif 221