voron

experimental ARM OS
git clone git://git.2f30.org/voron
Log | Files | Refs | README | LICENSE

rwlock.h (3586B)


      1 #ifndef __RWLOCK_H
      2 #define __RWLOCK_H
      3 
      4 #include <inttypes.h>
      5 #include <semaphore.h>
      6 
      7 /* Readers-Writer lock
      8  * Implemented with 'Passing the Baton' locking technique.
      9  *
     10  * Priority rules:
     11  * 1) if we have an awakened writer or writers in the waiting queue
     12  *    then a new reader will be added in readers' waiting queue.
     13  * 2) if all awakened readers are released then we awake a writer,
     14  *    even if readers are waiting in the queue.
     15  * 3) if the awakened writer and all writers in the waiting queue are
     16  *    released then we awake all the readers. */
     17 typedef struct {
     18 	mutex_t lock;
     19 	mutex_t writer_wait;
     20 	mutex_t reader_wait;
     21 	u32 nr_writers;
     22 	u32 nr_readers;
     23 	u32 nr_writers_queue;
     24 	u32 nr_readers_queue;
     25 } rwlock_t;
     26 
     27 #define RWLOCK_INIT {				\
     28 	MUTEX_INIT,				\
     29 	MUTEX_INIT_LOCKED,			\
     30 	MUTEX_INIT_LOCKED,			\
     31 	0,					\
     32 	0,					\
     33 	0,					\
     34 	0					\
     35 }
     36 
     37 static inline void
     38 rwlock_init(rwlock_t *rwl)
     39 {
     40 	mutex_init(&rwl->lock);
     41 	mutex_init(&rwl->writer_wait);
     42 	mutex_lock(&rwl->writer_wait);
     43 	mutex_init(&rwl->reader_wait);
     44 	mutex_lock(&rwl->reader_wait);
     45 	rwl->nr_writers = 0;
     46 	rwl->nr_readers = 0;
     47 	rwl->nr_writers_queue = 0;
     48 	rwl->nr_readers_queue = 0;
     49 }
     50 
     51 static inline void
     52 rwlock_rdlock(rwlock_t *rwl)
     53 {
     54 	mutex_lock(&rwl->lock);
     55 	/* if we have awakened writer or writers in the queue then wait */
     56 	if (rwl->nr_writers > 0 || rwl->nr_writers_queue > 0) {
     57 		rwl->nr_readers_queue++;
     58 		mutex_unlock(&rwl->lock);
     59 		/* wait */
     60 		mutex_lock(&rwl->reader_wait);
     61 	}
     62 
     63 	rwl->nr_readers++;
     64 
     65 	/* if there is at least one reader in the queue,
     66 	 * awake it (i.e. awake the next reader) */
     67 	if (rwl->nr_readers_queue > 0) {
     68 		rwl->nr_readers_queue--;
     69 		mutex_unlock(&rwl->reader_wait);
     70 	} else {
     71 		mutex_unlock(&rwl->lock);
     72 	}
     73 }
     74 
     75 /* returns 1 if managed to lock
     76  * returns 0 if not */
     77 static inline int
     78 rwlock_tryrdlock(rwlock_t *rwl)
     79 {
     80 	mutex_lock(&rwl->lock);
     81 	/* if we have awakened writer or writers in the queue then we can't lock */
     82 	if (rwl->nr_writers > 0 || rwl->nr_writers_queue > 0) {
     83 		mutex_unlock(&rwl->lock);
     84 		return 0;
     85 	}
     86 
     87 	rwl->nr_readers++;
     88 	mutex_unlock(&rwl->lock);
     89 	return 1;
     90 }
     91 
     92 static inline void
     93 rwlock_wrlock(rwlock_t *rwl)
     94 {
     95 	mutex_lock(&rwl->lock);
     96 	/* if we have an awakened writer or awakened readers then wait */
     97 	if (rwl->nr_writers > 0 || rwl->nr_readers > 0) {
     98 		rwl->nr_writers_queue++;
     99 		mutex_unlock(&rwl->lock);
    100 		/* wait */
    101 		mutex_lock(&rwl->writer_wait);
    102 	}
    103 
    104 	rwl->nr_writers++;
    105 	mutex_unlock(&rwl->lock);
    106 }
    107 
    108 /* returns 1 if managed to lock
    109  * returns 0 if not */
    110 static inline int
    111 rwlock_trywrlock(rwlock_t *rwl)
    112 {
    113 	mutex_lock(&rwl->lock);
    114 	/* if we have an awakened writer or awakened readers then we can't lock */
    115 	if (rwl->nr_writers > 0 || rwl->nr_readers > 0) {
    116 		mutex_unlock(&rwl->lock);
    117 		return 0;
    118 	}
    119 
    120 	rwl->nr_writers++;
    121 	mutex_unlock(&rwl->lock);
    122 	return 1;
    123 }
    124 
    125 static inline void
    126 rwlock_unlock(rwlock_t *rwl)
    127 {
    128 	mutex_lock(&rwl->lock);
    129 
    130 	/* release reader */
    131 	if (rwl->nr_readers > 0) {
    132 		rwl->nr_readers--;
    133 	/* release writer */
    134 	} else if (rwl->nr_writers > 0) {
    135 		rwl->nr_writers--;
    136 	}
    137 
    138 	/* if all awakened readers are released and we have writers in the queue
    139 	 * then awake a writer */
    140 	if (rwl->nr_readers == 0 && rwl->nr_writers_queue > 0) {
    141 		rwl->nr_writers_queue--;
    142 		mutex_unlock(&rwl->writer_wait);
    143 	/* if the awakened writer and all writers from the queue are released
    144 	 * then awake a reader */
    145 	} else if (rwl->nr_writers == 0 && rwl->nr_writers_queue == 0 &&
    146 		   rwl->nr_readers_queue > 0) {
    147 		rwl->nr_readers_queue--;
    148 		mutex_unlock(&rwl->reader_wait);
    149 	} else {
    150 		mutex_unlock(&rwl->lock);
    151 	}
    152 }
    153 
    154 #endif	/* __RWLOCK_H */