Changeset 563 for trunk/kernel/libk/rwlock.c
- Timestamp:
- Oct 4, 2018, 11:16:13 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kernel/libk/rwlock.c
r457 r563 1 1 /* 2 * rwlock.c - kernel read/write lock synchronization.2 * rwlock.c - kernel local read/write lock implementation. 3 3 * 4 4 * Author Alain Greiner (2016,2017,2018) … … 31 31 #include <rwlock.h> 32 32 33 /////////////////////////////////////// 34 void rwlock_init( rwlock_t * lock ) 33 ////////////////////////////////////////////////////////////////////////////// 34 // Extern global variables 35 ////////////////////////////////////////////////////////////////////////////// 36 37 extern char * lock_type_str[]; // allocated in kernel_init.c 38 39 40 ////////////////////////////////// 41 void rwlock_init( rwlock_t * lock, 42 uint32_t type ) 35 43 { 36 lock->ticket = 0; 37 lock->current = 0; 44 lock->taken = 0; 38 45 lock->count = 0; 39 46 40 #if DEBUG_RWLOCKS 41 lock->owner = NULL; 42 list_entry_init( &lock->list ); 43 #endif 44 45 } 46 47 ////////////////////////////////////// 48 void rwlock_rd_lock( rwlock_t * lock ) 49 { 50 reg_t mode; 51 uint32_t ticket; 52 thread_t * this = CURRENT_THREAD; 53 54 // disable IRQs 55 hal_disable_irq( &mode ); 56 57 // get next free ticket 58 ticket = hal_atomic_add( &lock->ticket , 1 ); 59 60 // poll the current ticket value 61 while( lock->current != ticket ) 62 { 63 hal_fixed_delay( CONFIG_RWLOCK_DELAY ); 64 } 65 66 ////////// From here we have the lock //////////// 47 list_root_init( &lock->rd_root ); 48 list_root_init( &lock->wr_root ); 49 50 busylock_init( &lock->lock , type ); 51 } 52 53 ///////////////////////////////////////// 54 void rwlock_rd_acquire( rwlock_t * lock ) 55 { 56 thread_t * this = CURRENT_THREAD; 57 58 // check calling thread can yield 59 thread_assert_can_yield( this , __FUNCTION__ ); 60 61 // get busylock 62 busylock_acquire( &lock->lock ); 63 64 // block and deschedule if lock already taken 65 while( lock->taken ) 66 { 67 68 #if DEBUG_RWLOCK 69 if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() ) 70 { 71 printk("\n[DBG] %s : thread %x in process %x READ BLOCK on rwlock %s [%x,%x]\n", 72 __FUNCTION__, this->trdid, this->process->pid, 73 lock_type_str[lock->lock.type], local_cxy, lock ); 74 } 75 #endif 76 // get pointer on calling thread 77 thread_t * this = CURRENT_THREAD; 78 79 // register reader thread in waiting queue 80 list_add_last( &lock->rd_root , &this->wait_list ); 81 82 // block reader thread 83 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK ); 84 85 // release busylock 86 busylock_release( &lock->lock ); 87 88 // deschedule 89 sched_yield("reader wait rwlock"); 90 91 // get busylock 92 busylock_acquire( &lock->lock ); 93 } 94 95 #if DEBUG_RWLOCK 96 if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() ) 97 { 98 printk("\n[DBG] %s : thread %x in process READ ACQUIRE on rwlock %s [%x,%x]\n", 99 __FUNCTION__, this->trdid, this->process->pid, 100 lock_type_str[lock->lock.type], local_cxy, lock ); 101 } 102 #endif 67 103 68 104 // increment number of readers 69 105 lock->count++; 70 this->local_locks++; 71 72 #if DEBUG_RWLOCKS 73 list_add_first( &this->locks_root , &lock->list ); 74 #endif 75 76 // consistency 106 107 // release busylock 108 busylock_release( &lock->lock ); 109 110 } // end rwlock_rd_acquire() 111 112 ///////////////////////////////////////// 113 void rwlock_wr_acquire( rwlock_t * lock ) 114 { 115 thread_t * this = CURRENT_THREAD; 116 117 // check calling thread can yield 118 thread_assert_can_yield( this , __FUNCTION__ ); 119 120 // get busylock 121 busylock_acquire( &lock->lock ); 122 123 // block and deschedule if lock already taken or existing read access 124 while( lock->taken || lock->count ) 125 { 126 127 #if DEBUG_RWLOCK 128 if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() ) 129 { 130 printk("\n[DBG] %s : thread %x in process WRITE BLOCK on rwlock %s [%x,%x]\n", 131 __FUNCTION__, this->trdid, this->process->pid, 132 lock_type_str[lock->lock.type], local_cxy, lock ); 133 } 134 #endif 135 // get pointer on calling thread 136 thread_t * this = CURRENT_THREAD; 137 138 // register writer in waiting queue 139 list_add_last( &lock->wr_root , &this->wait_list ); 140 141 // block reader thread 142 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_LOCK ); 143 144 // release busylock 145 busylock_release( &lock->lock ); 146 147 // deschedule 148 sched_yield("writer wait rwlock"); 149 150 // get busylock 151 busylock_acquire( &lock->lock ); 152 } 153 154 #if DEBUG_RWLOCK 155 if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() ) 156 { 157 printk("\n[DBG] %s : thread %x in process WRITE ACQUIRE on rwlock %s [%x,%x]\n", 158 __FUNCTION__, this->trdid, this->process->pid, 159 lock_type_str[lock->lock.type], local_cxy, lock ); 160 } 161 #endif 162 163 // take the rwlock 164 lock->taken = 1; 165 166 // release busylock 167 busylock_release( &lock->lock ); 168 169 } // end rwlock_wr_acquire() 170 171 ///////////////////////////////////////// 172 void rwlock_rd_release( rwlock_t * lock ) 173 { 174 // synchronize memory before lock release 77 175 hal_fence(); 78 176 79 // release the lock to allow several simultaneous readers 80 lock->current++; 81 82 // enable IRQs 83 hal_restore_irq( mode ); 84 85 } // end rwlock_rd_lock() 86 87 //////////////////////////////////////// 88 void rwlock_rd_unlock( rwlock_t * lock ) 89 { 90 reg_t mode; 91 thread_t * this = CURRENT_THREAD; 92 93 // disable IRQs 94 hal_disable_irq( &mode ); 95 177 // get busylock 178 busylock_acquire( &lock->lock ); 179 180 #if DEBUG_RWLOCK 181 if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() ) 182 { 183 thread_t * this = CURRENT_THREAD; 184 printk("\n[DBG] %s : thread %x in process READ RELEASE on rwlock %s [%x,%x]\n", 185 __FUNCTION__, this->trdid, this->process->pid, 186 lock_type_str[lock->lock.type], local_cxy, lock ); 187 } 188 #endif 189 96 190 // decrement number of readers 97 hal_atomic_add( &lock->count , -1 ); 98 this->local_locks--; 99 100 #if DEBUG_RWLOCKS 101 list_unlink( &lock->list ); 102 #endif 103 104 // enable IRQs 105 hal_restore_irq( mode ); 106 107 // deschedule if pending request 108 thread_check_sched(); 109 } 110 111 ////////////////////////////////////// 112 void rwlock_wr_lock( rwlock_t * lock ) 113 { 114 reg_t mode; 115 uint32_t ticket; 116 thread_t * this = CURRENT_THREAD; 117 118 // disable IRQs 119 hal_disable_irq( &mode ); 120 121 // get next free ticket 122 ticket = hal_atomic_add( &lock->ticket , 1 ); 123 124 // poll the current ticket value 125 while( lock->current != ticket ) 126 { 127 hal_fixed_delay( CONFIG_RWLOCK_DELAY ); 128 } 129 130 ////////// From here we have the lock //////////// 131 132 // wait completion of existing read access 133 while( lock->count != 0 ) 134 { 135 hal_fixed_delay( CONFIG_RWLOCK_DELAY ); 136 } 137 138 this->local_locks++; 139 140 #if DEBUG_RWLOCKS 141 lock->owner = this; 142 list_add_first( &this->locks_root , &lock->list ); 143 #endif 144 145 // enable IRQs 146 hal_restore_irq( mode ); 147 148 } // end rwlock_wr_lock() 149 150 //////////////////////////////////////////// 151 void rwlock_wr_unlock( rwlock_t * lock ) 152 { 153 reg_t mode; 154 thread_t * this = CURRENT_THREAD; 155 156 // disable IRQs 157 hal_disable_irq( &mode ); 158 159 #if DEBUG_RWLOCKS 160 lock->owner = NULL; 161 list_unlink( &lock->list ); 162 #endif 163 164 // release lock 165 lock->current++; 166 this->local_locks--; 167 168 // enable IRQs 169 hal_restore_irq( mode ); 170 171 // deschedule if pending request 172 thread_check_sched(); 173 } 174 191 lock->count--; 192 193 // release first writer in waiting queue if no current readers 194 // and writers waiting queue non empty 195 if( (lock->count == 0) && (list_is_empty( &lock->wr_root ) == false) ) 196 { 197 // get first writer thread 198 thread_t * thread = LIST_FIRST( &lock->wr_root , thread_t , wait_list ); 199 200 #if DEBUG_RWLOCK 201 if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() ) 202 { 203 thread_t * this = CURRENT_THREAD; 204 printk("\n[DBG] %s : thread %x in process %x UNBLOCK thread %x in process %d" 205 " / rwlock %s [%x,%x]\n", 206 __FUNCTION__, this->trdid, this->process->pid, thread->trdid, thread->process->pid, 207 lock_type_str[lock->lock.type], local_cxy, lock ); 208 } 209 #endif 210 211 // remove this waiting thread from waiting list 212 list_unlink( &thread->wait_list ); 213 214 // unblock this waiting thread 215 thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK ); 216 } 217 // release all readers in waiting queue if writers waiting queue empty 218 // and readers waiting queue non empty 219 else if( list_is_empty( &lock->wr_root ) && (list_is_empty( &lock->rd_root ) == false) ) 220 { 221 while( list_is_empty( &lock->rd_root ) == false ) 222 { 223 // get first reader thread 224 thread_t * thread = LIST_FIRST( &lock->wr_root , thread_t , wait_list ); 225 226 #if DEBUG_RWLOCK 227 if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() ) 228 { 229 thread_t * this = CURRENT_THREAD; 230 printk("\n[DBG] %s : thread %x in process %x UNBLOCK thread %x in process %d" 231 " / rwlock %s [%x,%x]\n", 232 __FUNCTION__, this->trdid, this->process->pid, thread->trdid, thread->process->pid, 233 lock_type_str[lock->lock.type], local_cxy, lock ); 234 } 235 #endif 236 237 // remove this waiting thread from waiting list 238 list_unlink( &thread->wait_list ); 239 240 // unblock this waiting thread 241 thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK ); 242 } 243 } 244 245 // release busylock 246 busylock_release( &lock->lock ); 247 248 } // end rwlock_rd_release() 249 250 ///////////////////////////////////////// 251 void rwlock_wr_release( rwlock_t * lock ) 252 { 253 // synchronize memory before lock release 254 hal_fence(); 255 256 // get busylock 257 busylock_acquire( &lock->lock ); 258 259 #if DEBUG_RWLOCK 260 if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() ) 261 { 262 thread_t * this = CURRENT_THREAD; 263 printk("\n[DBG] %s : thread %x in process WRITE RELEASE on rwlock %s [%x,%x]\n", 264 __FUNCTION__, this->trdid, this->process->pid, 265 lock_type_str[lock->lock.type], local_cxy, lock ); 266 } 267 #endif 268 269 // release the rwlock 270 lock->taken = 0; 271 272 // release first waiting writer thread if writers waiting queue non empty 273 if( list_is_empty( &lock->wr_root ) == false ) 274 { 275 // get first writer thread 276 thread_t * thread = LIST_FIRST( &lock->wr_root , thread_t , wait_list ); 277 278 #if DEBUG_RWLOCK 279 if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() ) 280 { 281 thread_t * this = CURRENT_THREAD; 282 printk("\n[DBG] %s : thread %x in process %x UNBLOCK thread %x in process %d" 283 " / rwlock %s [%x,%x]\n", 284 __FUNCTION__, this->trdid, this->process->pid, thread->trdid, thread->process->pid, 285 lock_type_str[lock->lock.type], local_cxy, lock ); 286 } 287 #endif 288 // remove this waiting thread from waiting list 289 list_unlink( &thread->wait_list ); 290 291 // unblock this waiting thread 292 thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK ); 293 } 294 295 // check readers waiting queue and release all if writers waiting queue empty 296 else 297 { 298 while( list_is_empty( &lock->rd_root ) == false ) 299 { 300 // get first reader thread 301 thread_t * thread = LIST_FIRST( &lock->rd_root , thread_t , wait_list ); 302 303 #if DEBUG_RWLOCK 304 if( DEBUG_RWLOCK < (uint32_t)hal_get_cycles() ) 305 { 306 thread_t * this = CURRENT_THREAD; 307 printk("\n[DBG] %s : thread %x in process %x UNBLOCK thread %x in process %d" 308 " / rwlock %s [%x,%x]\n", 309 __FUNCTION__, this->trdid, this->process->pid, thread->trdid, thread->process->pid, 310 lock_type_str[lock->lock.type], local_cxy, lock ); 311 } 312 #endif 313 // remove this waiting thread from waiting list 314 list_unlink( &thread->wait_list ); 315 316 // unblock this waiting thread 317 thread_unblock( XPTR( local_cxy , thread ) , THREAD_BLOCKED_LOCK ); 318 } 319 } 320 321 // release busylock 322 busylock_release( &lock->lock ); 323 324 } // end rwlock_wr_release() 325 326
Note: See TracChangeset
for help on using the changeset viewer.