struct mutex { int ftx; }; enum { UNLOCKED, LOCKED, CONTESTED }; void mutex_init(struct mutex *mtx) { mtx->ftx = UNLOCKED; } voidbool mutex_lockmutex_trylock(struct mutex *mtx) { ifreturn (atomic_cmpxchg(&mtx->ftx, UNLOCKED, LOCKED) == UNLOCKEDUNLOCKED; } void mutex_lock(struct mutex *mtx) { if (mutex_trylock(mtx)) return; while (atomic_xchg(&mtx->ftx, CONTESTED) != UNLOCKED) futex_wait(&mtx->ftx, CONTESTED); } void mutex_unlock(struct mutex *mtx) { if (atomic_xchg(&mtx->ftx, UNLOCKED) == CONTESTED) futex_wake(&mtx->ftx, 1); }
struct sema { int ftx; int waiters; }; enum { LOCKED = 0, CONTESTED = -1 }; void sema_init(struct sema *sem) { sem->ftx = 0;LOCKED; sem->waiters = 0; } bool sema_trywait(struct sema *sem) { int val = atomic_load(&sem->ftx); do { if (val ==<= 0LOCKED) return false; } while ((val = atomic_cmpxchg(&sem->ftx, val, val - 1)) != val); return true; } void sema_wait(struct sema *sem) { if (sema_trywait(sem)) return; atomic_add(&sem->waiters, 1); do { atomic_cmpxchg(&sem->ftx, LOCKED, CONTESTED); futex_wait(&sem->ftx, 0CONTESTED); } while (!sema_trywait(sem)); atomic_sub(&sem->waiters, 1); } void sema_post(struct sema *sem, int n) { atomic_addint new, waiters, val = atomic_load(&sem->ftx, n); //do This{ accesses semaphore after unlocking. What if it waswaiters destroyed?= atomic_load(&sem->waiters); // You can try tonew think= about(int) how((unsigned thisint) canval be+ fixed.n + (val < LOCKED)); /} while (!atomic_cmpxchg(&sem->ftx, &val, new)); /* IThe won'tsemaphore puthas correctbeen implementationunlocked hereand duecould tobe higherdeallocated, complexity. * so it must not be touch - hence the extra CONTESTED state */ if (atomic_load(&sem->waiters)val !=< 0LOCKED || waiters) futex_wake(&sem->ftx, n); // no point in waking more than 'n' }