Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/libcfa/concurrency/monitor.c

    rcb0e6de r5ea06d6  
    1818
    1919#include "kernel_private.h"
     20#include "libhdr.h"
     21
     22void set_owner( monitor_desc * this, thread_desc * owner ) {
     23        //Pass the monitor appropriately
     24        this->owner = owner;
     25
     26        //We are passing the monitor to someone else, which means recursion level is not 0
     27        this->recursion = owner ? 1 : 0;
     28}
    2029
    2130extern "C" {
    22         void __enter_monitor_desc(monitor_desc * this) {
     31        void __enter_monitor_desc(monitor_desc * this, monitor_desc * leader) {
    2332                lock( &this->lock );
    2433                thread_desc * thrd = this_thread();
     34
     35                //Update the stack owner
     36                this->stack_owner = leader;
    2537
    2638                if( !this->owner ) {
     
    4456
    4557                unlock( &this->lock );
    46         }
    47 
    48         void __leave_monitor_desc(monitor_desc * this) {
     58                return;
     59        }
     60
     61        // leave pseudo code :
     62        //      decrement level
     63        //      leve == 0 ?
     64        //              no : done
     65        //              yes :
     66        //                      signal stack empty ?
     67        //                              has leader :
     68        //                                      bulk acquiring means we don't own the signal stack
     69        //                                      ignore it but don't release the monitor
     70        //                              yes :
     71        //                                      next in entry queue is new owner
     72        //                              no :
     73        //                                      top of the signal stack is the owner
     74        //                                      context switch to him right away
     75        //
     76        void __leave_monitor_desc(monitor_desc * this, monitor_desc * leader) {
    4977                lock( &this->lock );
    5078
    5179                thread_desc * thrd = this_thread();
    52                 assert( thrd == this->owner );
     80                assert( thrd == this->owner || this->stack_owner );
    5381
    5482                //Leaving a recursion level, decrement the counter
    5583                this->recursion -= 1;
    5684
    57                 //If we left the last level of recursion it means we are changing who owns the monitor
     85                //If we haven't left the last level of recursion
     86                //it means we don't need to do anything
     87                if( this->recursion != 0) {
     88                        this->stack_owner = leader;
     89                        unlock( &this->lock );
     90                        return;
     91                }
     92                       
     93                //If we don't own the signal stack then just leave it to the owner
     94                if( this->stack_owner ) {
     95                        this->stack_owner = leader;
     96                        unlock( &this->lock );
     97                        return;
     98                }
     99
     100                //We are the stack owner and have left the last recursion level.
     101                //We are in charge of passing the monitor
    58102                thread_desc * new_owner = 0;
    59                 if( this->recursion == 0) {
    60                         //Get the next thread in the list
    61                         new_owner = this->owner = pop_head( &this->entry_queue );
    62 
    63                         //We are passing the monitor to someone else, which means recursion level is not 0
    64                         this->recursion = new_owner ? 1 : 0;
    65                 }       
    66 
     103
     104                //Check the signaller stack
     105                new_owner = pop( &this->signal_stack );
     106                if( new_owner ) {
     107                        //The signaller stack is not empty,
     108                        //transfer control immediately
     109                        set_owner( this, new_owner );
     110                        this->stack_owner = leader;
     111                        ScheduleInternal( &this->lock, new_owner );
     112                        return;
     113                }
     114               
     115                // No signaller thread
     116                // Get the next thread in the entry_queue
     117                new_owner = pop_head( &this->entry_queue );
     118                set_owner( this, new_owner );
     119
     120                //Update the stack owner
     121                this->stack_owner = leader;
     122
     123                //We can now let other threads in safely
    67124                unlock( &this->lock );
    68125
    69                 //If we have a new owner, we need to wake-up the thread
    70                 if( new_owner ) {
    71                         ScheduleThread( new_owner );
    72                 }
    73         }
    74 }
    75 
    76 void enter(monitor_desc ** monitors, int count) {
    77         for(int i = 0; i < count; i++) {
    78                 __enter_monitor_desc( monitors[i] );
    79         }
    80 }
    81 
    82 void leave(monitor_desc ** monitors, int count) {
     126                //We need to wake-up the thread
     127                ScheduleThread( new_owner );
     128        }
     129}
     130
     131static inline void enter(monitor_desc ** monitors, int count) {
     132        __enter_monitor_desc( monitors[0], NULL );
     133        for(int i = 1; i < count; i++) {
     134                __enter_monitor_desc( monitors[i], monitors[0] );
     135        }
     136}
     137
     138static inline void leave(monitor_desc ** monitors, int count) {
     139        __leave_monitor_desc( monitors[0], NULL );
    83140        for(int i = count - 1; i >= 0; i--) {
    84                 __leave_monitor_desc( monitors[i] );
    85         }
    86 }
     141                __leave_monitor_desc( monitors[i], monitors[0] );
     142        }
     143}
     144
     145void ?{}( monitor_guard_t * this, monitor_desc ** m, int count ) {
     146        this->m = m;
     147        this->count = count;
     148        qsort(this->m, count);
     149        enter( this->m, this->count );
     150
     151        this->prev_mntrs = this_thread()->current_monitors;
     152        this->prev_count = this_thread()->current_monitor_count;
     153
     154        this_thread()->current_monitors      = m;
     155        this_thread()->current_monitor_count = count;
     156}
     157
     158void ^?{}( monitor_guard_t * this ) {
     159        leave( this->m, this->count );
     160
     161        this_thread()->current_monitors      = this->prev_mntrs;
     162        this_thread()->current_monitor_count = this->prev_count;
     163}
     164
     165//-----------------------------------------------------------------------------
     166// Internal scheduling
     167void wait( condition * this ) {
     168        // LIB_DEBUG_FPRINTF("Waiting\n");
     169        thread_desc * this_thrd = this_thread();
     170
     171        if( !this->monitors ) {
     172                this->monitors = this_thrd->current_monitors;
     173                this->monitor_count = this_thrd->current_monitor_count;
     174        }
     175
     176        unsigned short count = this->monitor_count;
     177
     178        //Check that everything is as expected
     179        assert( this->monitors != NULL );
     180        assert( this->monitor_count != 0 );
     181
     182        unsigned int recursions[ count ];               //Save the current recursion levels to restore them later
     183        spinlock *   locks     [ count ];               //We need to pass-in an array of locks to ScheduleInternal
     184
     185        // LIB_DEBUG_FPRINTF("Getting ready to wait\n");
     186
     187        //Loop on all the monitors and release the owner
     188        for( unsigned int i = 0; i < count; i++ ) {
     189                monitor_desc * cur = this->monitors[i];
     190
     191                assert( cur );
     192
     193                // LIB_DEBUG_FPRINTF("cur %p lock %p\n", cur, &cur->lock);
     194
     195                //Store the locks for later
     196                locks[i] = &cur->lock;
     197
     198                //Protect the monitors
     199                lock( locks[i] );
     200                {               
     201                        //Save the recursion levels
     202                        recursions[i] = cur->recursion;
     203
     204                        //Release the owner
     205                        cur->recursion = 0;
     206                        cur->owner = NULL;
     207                }
     208                //Release the monitor
     209                unlock( locks[i] );
     210        }
     211
     212        // LIB_DEBUG_FPRINTF("Waiting now\n");
     213
     214        //Everything is ready to go to sleep
     215        ScheduleInternal( locks, count );
     216
     217
     218        //WE WOKE UP
     219
     220
     221        //We are back, restore the owners and recursions
     222        for( unsigned int i = 0; i < count; i++ ) {
     223                monitor_desc * cur = this->monitors[i];
     224
     225                //Protect the monitors
     226                lock( locks[i] );
     227                {
     228                        //Release the owner
     229                        cur->owner = this_thrd;
     230                        cur->recursion = recursions[i];
     231                }
     232                //Release the monitor
     233                unlock( locks[i] );
     234        }
     235}
     236
     237static void __signal_internal( condition * this ) {
     238        if( !this->blocked.head ) return;
     239
     240        //Check that everything is as expected
     241        assert( this->monitors );
     242        assert( this->monitor_count != 0 );
     243       
     244        LIB_DEBUG_DO(
     245                if ( this->monitors != this_thread()->current_monitors ) {
     246                        abortf( "Signal on condition %p made outside of the correct monitor(s)", this );
     247                } // if
     248        );
     249
     250        monitor_desc * owner = this->monitors[0];
     251        lock( &owner->lock );
     252        {
     253                thread_desc * unblock = pop_head( &this->blocked );
     254                push( &owner->signal_stack, unblock );
     255        }
     256        unlock( &owner->lock );
     257}
     258
     259void signal( condition * this ) {
     260        __signal_internal( this );
     261}
Note: See TracChangeset for help on using the changeset viewer.