Ignore:
Timestamp:
Oct 4, 2018, 11:16:13 PM (3 years ago)
Author:
alain
Message:

Complete restructuration of kernel spinlocks.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/kernel/libk/rwlock.c

    r457 r563  
    11/*
    2  * rwlock.c - kernel read/write lock synchronization.
     2 * rwlock.c - kernel local read/write lock implementation.
    33 *
    44 * Author  Alain Greiner     (2016,2017,2018)
     
    3131#include <rwlock.h>
    3232
    33 ///////////////////////////////////////
    34 void rwlock_init( rwlock_t * lock )
     33//////////////////////////////////////////////////////////////////////////////
     34//                Extern global variables
     35//////////////////////////////////////////////////////////////////////////////
     36
     37extern char * lock_type_str[];          // allocated in kernel_init.c
     38
     39
     40//////////////////////////////////
     41void rwlock_init( rwlock_t * lock,
     42                  uint32_t   type )
    3543
    36         lock->ticket  = 0;
    37     lock->current = 0;
     44        lock->taken   = 0;
    3845    lock->count   = 0;
    3946
    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/////////////////////////////////////////
     54void 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
     69if( 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
     96if( 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
    67103
    68104    // increment number of readers
    69105    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/////////////////////////////////////////
     113void 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
     128if( 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
     155if( 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/////////////////////////////////////////
     172void rwlock_rd_release( rwlock_t * lock )
     173{
     174    // synchronize memory before lock release
    77175    hal_fence();
    78176
    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
     181if( 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
    96190    // 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
     201if( 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
     227if( 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/////////////////////////////////////////
     251void 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
     260if( 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
     279if( 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
     304if( 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.