rwlock.c 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. #include "config.h"
  2. #include "rwlock.h"
  3. #include "bool.h"
  4. #include "atomic.h"
  5. #include "threads.h"
  6. /* A simple spinlock. Yield the thread while the given integer is set by
  7. * another. Could probably be improved... */
  8. #define LOCK(l) do { \
  9. while(ATOMIC_FLAG_TEST_AND_SET(&(l), almemory_order_acq_rel) == true) \
  10. althrd_yield(); \
  11. } while(0)
  12. #define UNLOCK(l) ATOMIC_FLAG_CLEAR(&(l), almemory_order_release)
  13. void RWLockInit(RWLock *lock)
  14. {
  15. InitRef(&lock->read_count, 0);
  16. InitRef(&lock->write_count, 0);
  17. ATOMIC_FLAG_CLEAR(&lock->read_lock, almemory_order_relaxed);
  18. ATOMIC_FLAG_CLEAR(&lock->read_entry_lock, almemory_order_relaxed);
  19. ATOMIC_FLAG_CLEAR(&lock->write_lock, almemory_order_relaxed);
  20. }
  21. void ReadLock(RWLock *lock)
  22. {
  23. LOCK(lock->read_entry_lock);
  24. LOCK(lock->read_lock);
  25. /* NOTE: ATOMIC_ADD returns the *old* value! */
  26. if(ATOMIC_ADD(&lock->read_count, 1, almemory_order_acq_rel) == 0)
  27. LOCK(lock->write_lock);
  28. UNLOCK(lock->read_lock);
  29. UNLOCK(lock->read_entry_lock);
  30. }
  31. void ReadUnlock(RWLock *lock)
  32. {
  33. /* NOTE: ATOMIC_SUB returns the *old* value! */
  34. if(ATOMIC_SUB(&lock->read_count, 1, almemory_order_acq_rel) == 1)
  35. UNLOCK(lock->write_lock);
  36. }
  37. void WriteLock(RWLock *lock)
  38. {
  39. if(ATOMIC_ADD(&lock->write_count, 1, almemory_order_acq_rel) == 0)
  40. LOCK(lock->read_lock);
  41. LOCK(lock->write_lock);
  42. }
  43. void WriteUnlock(RWLock *lock)
  44. {
  45. UNLOCK(lock->write_lock);
  46. if(ATOMIC_SUB(&lock->write_count, 1, almemory_order_acq_rel) == 1)
  47. UNLOCK(lock->read_lock);
  48. }