Ignore:
Timestamp:
Apr 29, 2021, 4:26:25 PM (17 months ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
arm-eh, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
3eb55f98
Parents:
b2fc7ad9
Message:

Changed RW lock to avoid hitting the global array on schedule.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/ready_queue.cfa

    rb2fc7ad9 rc993b15  
    9393        this.alloc = 0;
    9494        this.ready = 0;
    95         this.lock  = false;
    9695        this.data  = alloc(this.max);
    97 
    98         /*paranoid*/ verify( 0 == (((uintptr_t)(this.data    )) % 64) );
    99         /*paranoid*/ verify( 0 == (((uintptr_t)(this.data + 1)) % 64) );
     96        this.write_lock  = false;
     97
    10098        /*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.alloc), &this.alloc));
    10199        /*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.ready), &this.ready));
     
    106104}
    107105
    108 void ?{}( __scheduler_lock_id_t & this, __processor_id_t * proc ) {
    109         this.handle = proc;
    110         this.lock   = false;
    111         #ifdef __CFA_WITH_VERIFY__
    112                 this.owned  = false;
    113         #endif
    114 }
    115106
    116107//=======================================================================
    117108// Lock-Free registering/unregistering of threads
    118 void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     109unsigned register_proc_id( void ) with(*__scheduler_lock) {
    119110        __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc);
     111        bool * handle = (bool *)&kernelTLS().sched_lock;
    120112
    121113        // Step - 1 : check if there is already space in the data
     
    124116        // Check among all the ready
    125117        for(uint_fast32_t i = 0; i < s; i++) {
    126                 __processor_id_t * null = 0p; // Re-write every loop since compare thrashes it
    127                 if( __atomic_load_n(&data[i].handle, (int)__ATOMIC_RELAXED) == null
    128                         && __atomic_compare_exchange_n( &data[i].handle, &null, proc, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    129                         /*paranoid*/ verify(i < ready);
    130                         /*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size));
    131                         /*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0);
    132                         proc->id = i;
    133                         return;
     118                bool * volatile * cell = (bool * volatile *)&data[i]; // Cforall is bugged and the double volatiles causes problems
     119                /* paranoid */ verify( handle != *cell );
     120
     121                bool * null = 0p; // Re-write every loop since compare thrashes it
     122                if( __atomic_load_n(cell, (int)__ATOMIC_RELAXED) == null
     123                        && __atomic_compare_exchange_n( cell, &null, handle, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     124                        /* paranoid */ verify(i < ready);
     125                        /* paranoid */ verify( (kernelTLS().sched_id = i, true) );
     126                        return i;
    134127                }
    135128        }
     
    142135
    143136        // Step - 3 : Mark space as used and then publish it.
    144         __scheduler_lock_id_t * storage = (__scheduler_lock_id_t *)&data[n];
    145         (*storage){ proc };
     137        data[n] = handle;
    146138        while() {
    147139                unsigned copy = n;
     
    155147
    156148        // Return new spot.
    157         /*paranoid*/ verify(n < ready);
    158         /*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size));
    159         /*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0);
    160         proc->id = n;
    161 }
    162 
    163 void unregister_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
    164         unsigned id = proc->id;
    165         /*paranoid*/ verify(id < ready);
    166         /*paranoid*/ verify(proc == __atomic_load_n(&data[id].handle, __ATOMIC_RELAXED));
    167         __atomic_store_n(&data[id].handle, 0p, __ATOMIC_RELEASE);
     149        /* paranoid */ verify(n < ready);
     150        /* paranoid */ verify( (kernelTLS().sched_id = n, true) );
     151        return n;
     152}
     153
     154void unregister_proc_id( unsigned id ) with(*__scheduler_lock) {
     155        /* paranoid */ verify(id < ready);
     156        /* paranoid */ verify(id == kernelTLS().sched_id);
     157        /* paranoid */ verify(data[id] == &kernelTLS().sched_lock);
     158
     159        bool * volatile * cell = (bool * volatile *)&data[id]; // Cforall is bugged and the double volatiles causes problems
     160
     161        __atomic_store_n(cell, 0p, __ATOMIC_RELEASE);
    168162
    169163        __cfadbg_print_safe(ready_queue, "Kernel : Unregister proc %p\n", proc);
     
    175169uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
    176170        /* paranoid */ verify( ! __preemption_enabled() );
     171        /* paranoid */ verify( ! kernelTLS().sched_lock );
    177172
    178173        // Step 1 : lock global lock
    179174        // It is needed to avoid processors that register mid Critical-Section
    180175        //   to simply lock their own lock and enter.
    181         __atomic_acquire( &lock );
     176        __atomic_acquire( &write_lock );
    182177
    183178        // Step 2 : lock per-proc lock
     
    187182        uint_fast32_t s = ready;
    188183        for(uint_fast32_t i = 0; i < s; i++) {
    189                 __atomic_acquire( &data[i].lock );
     184                volatile bool * llock = data[i];
     185                if(llock) __atomic_acquire( llock );
    190186        }
    191187
     
    204200        // Alternative solution : return s in write_lock and pass it to write_unlock
    205201        for(uint_fast32_t i = 0; i < last_s; i++) {
    206                 verify(data[i].lock);
    207                 __atomic_store_n(&data[i].lock, (bool)false, __ATOMIC_RELEASE);
     202                volatile bool * llock = data[i];
     203                if(llock) __atomic_store_n(llock, (bool)false, __ATOMIC_RELEASE);
    208204        }
    209205
    210206        // Step 2 : release global lock
    211         /*paranoid*/ assert(true == lock);
    212         __atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE);
     207        /*paranoid*/ assert(true == write_lock);
     208        __atomic_store_n(&write_lock, (bool)false, __ATOMIC_RELEASE);
    213209
    214210        /* paranoid */ verify( ! __preemption_enabled() );
Note: See TracChangeset for help on using the changeset viewer.