Changes in / [8731d8c:4be3669]


Ignore:
Files:
1 deleted
7 edited

Legend:

Unmodified
Added
Removed
  • doc/proposals/concurrency/thePlan.md

    r8731d8c r4be3669  
    1010done - Multi monitors calls,
    1111done - Monitors as a language feature (not calling enter/leave by hand)
     12Internal scheduling
    1213
    13 _Phase 3_ : Monitor features
    14 Internal scheduling
    15 External scheduling
    16 
    17 _Phase 4_ : Kernel features
     14_Phase 3_ : Kernel features
    1815Preemption
    1916Detach thread
    2017Cluster migration
     18
     19_Phase 4_ : Monitor features
     20External scheduling
    2121
    2222_Phase 5_ : Performance
  • src/libcfa/concurrency/invoke.h

    r8731d8c r4be3669  
    3333      };
    3434
    35       struct __thread_queue_t {
     35      struct simple_thread_list {
    3636            struct thread_desc * head;
    3737            struct thread_desc ** tail;
    3838      };
    3939
    40       struct __thread_stack_t {
    41             struct thread_desc * top;
    42       };
    43 
    4440      #ifdef __CFORALL__
    4541      extern "Cforall" {
    46             void ?{}( struct __thread_queue_t * );
    47             void append( struct __thread_queue_t *, struct thread_desc * );
    48             struct thread_desc * pop_head( struct __thread_queue_t * );
    49 
    50             void ?{}( struct __thread_stack_t * );
    51             void push( struct __thread_stack_t *, struct thread_desc * );           
    52             struct thread_desc * pop( struct __thread_stack_t * );
     42            void ?{}( struct simple_thread_list * );
     43            void append( struct simple_thread_list *, struct thread_desc * );
     44            struct thread_desc * pop_head( struct simple_thread_list * );
    5345
    5446            void ?{}(spinlock * this);
     
    5850
    5951      struct coStack_t {
    60             unsigned int size;                        // size of stack
    61             void *storage;                            // pointer to stack
    62             void *limit;                              // stack grows towards stack limit
    63             void *base;                               // base of stack
    64             void *context;                            // address of cfa_context_t
    65             void *top;                                // address of top of storage
    66             bool userStack;                           // whether or not the user allocated the stack
     52            unsigned int size;                  // size of stack
     53            void *storage;                      // pointer to stack
     54            void *limit;                        // stack grows towards stack limit
     55            void *base;                         // base of stack
     56            void *context;                      // address of cfa_context_t
     57            void *top;                          // address of top of storage
     58            bool userStack;                     // whether or not the user allocated the stack
    6759      };
    6860
     
    7062
    7163      struct coroutine_desc {
    72             struct coStack_t stack;                   // stack information of the coroutine
    73             const char *name;                         // textual name for coroutine/task, initialized by uC++ generated code
    74             int errno_;                               // copy of global UNIX variable errno
    75             enum coroutine_state state;               // current execution status for coroutine
    76             struct coroutine_desc *starter;           // first coroutine to resume this one
    77             struct coroutine_desc *last;                    // last coroutine to resume this one
     64            struct coStack_t stack;             // stack information of the coroutine
     65            const char *name;                   // textual name for coroutine/task, initialized by uC++ generated code
     66            int errno_;                         // copy of global UNIX variable errno
     67            enum coroutine_state state;         // current execution status for coroutine
     68            struct coroutine_desc *starter;     // first coroutine to resume this one
     69            struct coroutine_desc *last;              // last coroutine to resume this one
    7870      };
    7971
    8072      struct monitor_desc {
    81             struct spinlock lock;                     // spinlock to protect internal data
    82             struct thread_desc * owner;               // current owner of the monitor
    83             struct __thread_queue_t entry_queue;      // queue of threads that are blocked waiting for the monitor
    84             struct __thread_stack_t signal_stack;     // stack of threads to run next once we exit the monitor
    85             struct monitor_desc * stack_owner;        // if bulk acquiring was used we need to synchronize signals with an other monitor
    86             unsigned int recursion;                   // monitor routines can be called recursively, we need to keep track of that
     73            struct spinlock lock;
     74            struct thread_desc * owner;
     75            struct simple_thread_list entry_queue;
     76            unsigned int recursion;
    8777      };
    8878
    8979      struct thread_desc {
    90             struct coroutine_desc cor;                // coroutine body used to store context
    91             struct monitor_desc mon;                  // monitor body used for mutual exclusion
    92             struct thread_desc * next;                // instrusive link field for threads
    93             struct monitor_desc ** current_monitors;  // currently held monitors
    94             unsigned short current_monitor_count;     // number of currently held monitors
     80            struct coroutine_desc cor;          // coroutine body used to store context
     81            struct monitor_desc mon;            // monitor body used for mutual exclusion
     82            struct thread_desc * next;          // instrusive link field for threads
    9583      };
    9684
  • src/libcfa/concurrency/kernel

    r8731d8c r4be3669  
    3232
    3333struct signal_once {
    34         volatile bool cond;
     34        volatile bool condition;
    3535        struct spinlock lock;
    36         struct __thread_queue_t blocked;
     36        struct simple_thread_list blocked;
    3737};
    3838
     
    4646// Cluster
    4747struct cluster {
    48         __thread_queue_t ready_queue;
     48        simple_thread_list ready_queue;
    4949        spinlock lock;
    5050};
  • src/libcfa/concurrency/kernel.c

    r8731d8c r4be3669  
    299299// Scheduler routines
    300300void ScheduleThread( thread_desc * thrd ) {
    301         if( !thrd ) return;
    302 
    303301        assertf( thrd->next == NULL, "Expected null got %p", thrd->next );
    304302       
     
    475473
    476474void ?{}( signal_once * this ) {
    477         this->cond = false;
     475        this->condition = false;
    478476}
    479477void ^?{}( signal_once * this ) {
     
    483481void wait( signal_once * this ) {
    484482        lock( &this->lock );
    485         if( !this->cond ) {
     483        if( !this->condition ) {
    486484                append( &this->blocked, this_thread() );
    487485                ScheduleInternal( &this->lock );
     
    494492        lock( &this->lock );
    495493        {
    496                 this->cond = true;
     494                this->condition = true;
    497495
    498496                thread_desc * it;
     
    506504//-----------------------------------------------------------------------------
    507505// Queues
    508 void ?{}( __thread_queue_t * this ) {
     506void ?{}( simple_thread_list * this ) {
    509507        this->head = NULL;
    510508        this->tail = &this->head;
    511509}
    512510
    513 void append( __thread_queue_t * this, thread_desc * t ) {
     511void append( simple_thread_list * this, thread_desc * t ) {
    514512        assert(this->tail != NULL);
    515513        *this->tail = t;
     
    517515}
    518516
    519 thread_desc * pop_head( __thread_queue_t * this ) {
     517thread_desc * pop_head( simple_thread_list * this ) {
    520518        thread_desc * head = this->head;
    521519        if( head ) {
     
    528526        return head;
    529527}
    530 
    531 void ?{}( __thread_stack_t * this ) {
    532         this->top = NULL;
    533 }
    534 
    535 void push( __thread_stack_t * this, thread_desc * t ) {
    536         assert(t->next != NULL);
    537         t->next = this->top;
    538         this->top = t;
    539 }
    540 
    541 thread_desc * pop( __thread_stack_t * this ) {
    542         thread_desc * top = this->top;
    543         if( top ) {
    544                 this->top = top->next;
    545                 top->next = NULL;
    546         }       
    547         return top;
    548 }
    549528// Local Variables: //
    550529// mode: c //
  • src/libcfa/concurrency/monitor

    r8731d8c r4be3669  
    1818#define MONITOR_H
    1919
    20 #include <stddef.h>
    21 
    2220#include "assert"
    2321#include "invoke.h"
     
    2523
    2624static inline void ?{}(monitor_desc * this) {
    27         this->owner = NULL;
    28       this->stack_owner = NULL;
     25        this->owner = 0;
    2926        this->recursion = 0;
    3027}
     28
     29//Array entering routine
     30void enter(monitor_desc **, int count);
     31void leave(monitor_desc **, int count);
    3132
    3233struct monitor_guard_t {
    3334        monitor_desc ** m;
    3435        int count;
    35       monitor_desc ** prev_mntrs;
    36       unsigned short  prev_count;
    3736};
    3837
     
    4140}
    4241
    43 void ?{}( monitor_guard_t * this, monitor_desc ** m, int count );
    44 void ^?{}( monitor_guard_t * this );
    45 
    46 //-----------------------------------------------------------------------------
    47 // Internal scheduling
    48 struct condition {
    49         __thread_queue_t blocked;
    50         monitor_desc ** monitors;
    51         unsigned short monitor_count;
    52 };
    53 
    54 static inline void ?{}( condition * this ) {
    55         this->monitors = NULL;
    56         this->monitor_count = 0;
     42static inline void ?{}( monitor_guard_t * this, monitor_desc ** m, int count ) {
     43        this->m = m;
     44        this->count = count;
     45        qsort(this->m, count);
     46        enter( this->m, this->count );
    5747}
    5848
    59 void wait( condition * this );
    60 void signal( condition * this );
     49static inline void ^?{}( monitor_guard_t * this ) {
     50        leave( this->m, this->count );
     51}
     52
     53
    6154#endif //MONITOR_H
  • src/libcfa/concurrency/monitor.c

    r8731d8c r4be3669  
    1818
    1919#include "kernel_private.h"
    20 #include "libhdr.h"
    21 
    22 void 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 }
    2920
    3021extern "C" {
    31         void __enter_monitor_desc(monitor_desc * this, monitor_desc * leader) {
     22        void __enter_monitor_desc(monitor_desc * this) {
    3223                lock( &this->lock );
    3324                thread_desc * thrd = this_thread();
    3425
    35                 // //Update the stack owner
    36                 // this->stack_owner = leader;
    37 
    38                 LIB_DEBUG_PRINT_SAFE("Entering %p (o: %p, r: %i)\n", this, this->owner, this->recursion);
    39 
    4026                if( !this->owner ) {
    4127                        //No one has the monitor, just take it
    42                         set_owner( this, thrd );
     28                        this->owner = thrd;
     29                        this->recursion = 1;
    4330                }
    4431                else if( this->owner == thrd) {
     
    5744
    5845                unlock( &this->lock );
    59                 return;
    6046        }
    6147
    62         // leave pseudo code :
    63         //      decrement level
    64         //      leve == 0 ?
    65         //              no : done
    66         //              yes :
    67         //                      signal stack empty ?
    68         //                              has leader :
    69         //                                      bulk acquiring means we don't own the signal stack
    70         //                                      ignore it but don't release the monitor
    71         //                              yes :
    72         //                                      next in entry queue is new owner
    73         //                              no :
    74         //                                      top of the signal stack is the owner
    75         //                                      context switch to him right away
    76         //
    77         void __leave_monitor_desc(monitor_desc * this, monitor_desc * leader) {
     48        void __leave_monitor_desc(monitor_desc * this) {
    7849                lock( &this->lock );
    7950
    80                 LIB_DEBUG_PRINT_SAFE("Leaving %p (o: %p, r: %i)\n", this, this->owner, this->recursion);
    81 
    8251                thread_desc * thrd = this_thread();
    83                 assertf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i)", this->owner, thrd, this->recursion );
     52                assert( thrd == this->owner );
    8453
    8554                //Leaving a recursion level, decrement the counter
    8655                this->recursion -= 1;
    8756
    88                 //If we haven't left the last level of recursion
    89                 //it means we don't need to do anything
    90                 if( this->recursion != 0) {
    91                         // this->stack_owner = leader;
    92                         unlock( &this->lock );
    93                         return;
    94                 }
    95                        
    96                 // //If we don't own the signal stack then just leave it to the owner
    97                 // if( this->stack_owner ) {
    98                 //      this->stack_owner = leader;
    99                 //      unlock( &this->lock );
    100                 //      return;
    101                 // }
     57                //If we left the last level of recursion it means we are changing who owns the monitor
     58                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 );
    10262
    103                 //We are the stack owner and have left the last recursion level.
    104                 //We are in charge of passing the monitor
    105                 thread_desc * new_owner = 0;
     63                        //We are passing the monitor to someone else, which means recursion level is not 0
     64                        this->recursion = new_owner ? 1 : 0;
     65                }       
    10666
    107                 //Check the signaller stack
    108                 new_owner = pop( &this->signal_stack );
    109                 if( new_owner ) {
    110                         //The signaller stack is not empty,
    111                         //transfer control immediately
    112                         set_owner( this, new_owner );
    113                         // this->stack_owner = leader;
    114                         ScheduleInternal( &this->lock, new_owner );
    115                         return;
    116                 }
    117                
    118                 // No signaller thread
    119                 // Get the next thread in the entry_queue
    120                 new_owner = pop_head( &this->entry_queue );
    121                 set_owner( this, new_owner );
    122 
    123                 // //Update the stack owner
    124                 // this->stack_owner = leader;
    125 
    126                 //We can now let other threads in safely
    12767                unlock( &this->lock );
    12868
    129                 //We need to wake-up the thread
    130                 ScheduleThread( new_owner );
     69                //If we have a new owner, we need to wake-up the thread
     70                if( new_owner ) {
     71                        ScheduleThread( new_owner );
     72                }
    13173        }
    13274}
    13375
    134 static inline void enter(monitor_desc ** monitors, int count) {
    135         __enter_monitor_desc( monitors[0], NULL );
    136         for(int i = 1; i < count; i++) {
    137                 __enter_monitor_desc( monitors[i], monitors[0] );
     76void enter(monitor_desc ** monitors, int count) {
     77        for(int i = 0; i < count; i++) {
     78                __enter_monitor_desc( monitors[i] );
    13879        }
    13980}
    14081
    141 static inline void leave(monitor_desc ** monitors, int count) {
    142         __leave_monitor_desc( monitors[0], NULL );
    143         for(int i = count - 1; i >= 1; i--) {
    144                 __leave_monitor_desc( monitors[i], monitors[0] );
     82void leave(monitor_desc ** monitors, int count) {
     83        for(int i = count - 1; i >= 0; i--) {
     84                __leave_monitor_desc( monitors[i] );
    14585        }
    14686}
    147 
    148 void ?{}( monitor_guard_t * this, monitor_desc ** m, int count ) {
    149         this->m = m;
    150         this->count = count;
    151         qsort(this->m, count);
    152         enter( this->m, this->count );
    153 
    154         this->prev_mntrs = this_thread()->current_monitors;
    155         this->prev_count = this_thread()->current_monitor_count;
    156 
    157         this_thread()->current_monitors      = m;
    158         this_thread()->current_monitor_count = count;
    159 }
    160 
    161 void ^?{}( monitor_guard_t * this ) {
    162         leave( this->m, this->count );
    163 
    164         this_thread()->current_monitors      = this->prev_mntrs;
    165         this_thread()->current_monitor_count = this->prev_count;
    166 }
    167 
    168 //-----------------------------------------------------------------------------
    169 // Internal scheduling
    170 void wait( condition * this ) {
    171         assertf(false, "NO SUPPORTED");
    172         // LIB_DEBUG_FPRINTF("Waiting\n");
    173         thread_desc * this_thrd = this_thread();
    174 
    175         if( !this->monitors ) {
    176                 this->monitors = this_thrd->current_monitors;
    177                 this->monitor_count = this_thrd->current_monitor_count;
    178         }
    179 
    180         unsigned short count = this->monitor_count;
    181 
    182         //Check that everything is as expected
    183         assert( this->monitors != NULL );
    184         assert( this->monitor_count != 0 );
    185 
    186         unsigned int recursions[ count ];               //Save the current recursion levels to restore them later
    187         spinlock *   locks     [ count ];               //We need to pass-in an array of locks to ScheduleInternal
    188 
    189         // LIB_DEBUG_FPRINTF("Getting ready to wait\n");
    190 
    191         //Loop on all the monitors and release the owner
    192         for( unsigned int i = 0; i < count; i++ ) {
    193                 monitor_desc * cur = this->monitors[i];
    194 
    195                 assert( cur );
    196 
    197                 // LIB_DEBUG_FPRINTF("cur %p lock %p\n", cur, &cur->lock);
    198 
    199                 //Store the locks for later
    200                 locks[i] = &cur->lock;
    201 
    202                 //Protect the monitors
    203                 lock( locks[i] );
    204                 {               
    205                         //Save the recursion levels
    206                         recursions[i] = cur->recursion;
    207 
    208                         //Release the owner
    209                         cur->recursion = 0;
    210                         cur->owner = NULL;
    211                 }
    212                 //Release the monitor
    213                 unlock( locks[i] );
    214         }
    215 
    216         // LIB_DEBUG_FPRINTF("Waiting now\n");
    217 
    218         //Everything is ready to go to sleep
    219         ScheduleInternal( locks, count );
    220 
    221 
    222         //WE WOKE UP
    223 
    224 
    225         //We are back, restore the owners and recursions
    226         for( unsigned int i = 0; i < count; i++ ) {
    227                 monitor_desc * cur = this->monitors[i];
    228 
    229                 //Protect the monitors
    230                 lock( locks[i] );
    231                 {
    232                         //Release the owner
    233                         cur->owner = this_thrd;
    234                         cur->recursion = recursions[i];
    235                 }
    236                 //Release the monitor
    237                 unlock( locks[i] );
    238         }
    239 }
    240 
    241 static void __signal_internal( condition * this ) {
    242         assertf(false, "NO SUPPORTED");
    243         if( !this->blocked.head ) return;
    244 
    245         //Check that everything is as expected
    246         assert( this->monitors );
    247         assert( this->monitor_count != 0 );
    248        
    249         LIB_DEBUG_DO(
    250                 if ( this->monitors != this_thread()->current_monitors ) {
    251                         abortf( "Signal on condition %p made outside of the correct monitor(s)", this );
    252                 } // if
    253         );
    254 
    255         monitor_desc * owner = this->monitors[0];
    256         lock( &owner->lock );
    257         {
    258                 thread_desc * unblock = pop_head( &this->blocked );
    259                 push( &owner->signal_stack, unblock );
    260         }
    261         unlock( &owner->lock );
    262 }
    263 
    264 void signal( condition * this ) {
    265         __signal_internal( this );
    266 }
  • src/libcfa/concurrency/thread.c

    r8731d8c r4be3669  
    3939        this->mon.recursion = 1;
    4040        this->next = NULL;
    41 
    42         this->current_monitors      = NULL;
    43         this->current_monitor_count = 0;
    4441}
    4542
Note: See TracChangeset for help on using the changeset viewer.