Changeset 5ea06d6


Ignore:
Timestamp:
Mar 31, 2017, 1:04:21 PM (7 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
23063ea
Parents:
78d3dd5
Message:

Prototype of multi monitor internal scheduling

Location:
src
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • src/libcfa/concurrency/invoke.h

    r78d3dd5 r5ea06d6  
    3333      };
    3434
    35       struct simple_thread_list {
     35      struct __thread_queue_t {
    3636            struct thread_desc * head;
    3737            struct thread_desc ** tail;
    3838      };
    3939
    40       struct simple_thread_stack {
     40      struct __thread_stack_t {
    4141            struct thread_desc * top;
    4242      };
     
    4444      #ifdef __CFORALL__
    4545      extern "Cforall" {
    46             void ?{}( struct simple_thread_list * );
    47             void append( struct simple_thread_list *, struct thread_desc * );
    48             struct thread_desc * pop_head( struct simple_thread_list * );
     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 * );
    4949
    50             void ?{}( struct simple_thread_stack * );
    51             void push( struct simple_thread_stack *, struct thread_desc * );           
    52             struct thread_desc * pop( struct simple_thread_stack * );
     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 * );
    5353
    5454            void ?{}(spinlock * this);
     
    5858
    5959      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
     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
    6767      };
    6868
     
    7070
    7171      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
     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
    7878      };
    7979
    8080      struct monitor_desc {
    81             struct spinlock lock;
    82             struct thread_desc * owner;
    83             struct simple_thread_list entry_queue;
    84             struct simple_thread_stack signal_stack;
    85             struct monitor_desc * stack_owner;
    86             unsigned int recursion;
     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
    8787      };
    8888
    8989      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
     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
    9395      };
    9496
  • src/libcfa/concurrency/kernel

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

    r78d3dd5 r5ea06d6  
    475475
    476476void ?{}( signal_once * this ) {
    477         this->condition = false;
     477        this->cond = false;
    478478}
    479479void ^?{}( signal_once * this ) {
     
    483483void wait( signal_once * this ) {
    484484        lock( &this->lock );
    485         if( !this->condition ) {
     485        if( !this->cond ) {
    486486                append( &this->blocked, this_thread() );
    487487                ScheduleInternal( &this->lock );
     
    494494        lock( &this->lock );
    495495        {
    496                 this->condition = true;
     496                this->cond = true;
    497497
    498498                thread_desc * it;
     
    506506//-----------------------------------------------------------------------------
    507507// Queues
    508 void ?{}( simple_thread_list * this ) {
     508void ?{}( __thread_queue_t * this ) {
    509509        this->head = NULL;
    510510        this->tail = &this->head;
    511511}
    512512
    513 void append( simple_thread_list * this, thread_desc * t ) {
     513void append( __thread_queue_t * this, thread_desc * t ) {
    514514        assert(this->tail != NULL);
    515515        *this->tail = t;
     
    517517}
    518518
    519 thread_desc * pop_head( simple_thread_list * this ) {
     519thread_desc * pop_head( __thread_queue_t * this ) {
    520520        thread_desc * head = this->head;
    521521        if( head ) {
     
    529529}
    530530
    531 void ?{}( simple_thread_stack * this ) {
     531void ?{}( __thread_stack_t * this ) {
    532532        this->top = NULL;
    533533}
    534534
    535 void push( simple_thread_stack * this, thread_desc * t ) {
     535void push( __thread_stack_t * this, thread_desc * t ) {
    536536        assert(t->next != NULL);
    537537        t->next = this->top;
     
    539539}
    540540
    541 thread_desc * pop( simple_thread_stack * this ) {
     541thread_desc * pop( __thread_stack_t * this ) {
    542542        thread_desc * top = this->top;
    543543        if( top ) {
  • src/libcfa/concurrency/monitor

    r78d3dd5 r5ea06d6  
    3030}
    3131
    32 //Array entering routine
    33 void enter(monitor_desc **, int count);
    34 void leave(monitor_desc **, int count);
    35 
    3632struct monitor_guard_t {
    3733        monitor_desc ** m;
    3834        int count;
     35      monitor_desc ** prev_mntrs;
     36      unsigned short  prev_count;
    3937};
    4038
     
    4341}
    4442
    45 static inline void ?{}( monitor_guard_t * this, monitor_desc ** m, int count ) {
    46         this->m = m;
    47         this->count = count;
    48         qsort(this->m, count);
    49         enter( this->m, this->count );
     43void ?{}( monitor_guard_t * this, monitor_desc ** m, int count );
     44void ^?{}( monitor_guard_t * this );
     45
     46//-----------------------------------------------------------------------------
     47// Internal scheduling
     48struct condition {
     49        __thread_queue_t blocked;
     50        monitor_desc ** monitors;
     51        unsigned short monitor_count;
     52};
     53
     54static inline void ?{}( condition * this ) {
     55        this->monitors = NULL;
     56        this->monitor_count = 0;
    5057}
    5158
    52 static inline void ^?{}( monitor_guard_t * this ) {
    53         leave( this->m, this->count );
    54 }
    55 
    56 
     59void wait( condition * this );
     60void signal( condition * this );
    5761#endif //MONITOR_H
  • src/libcfa/concurrency/monitor.c

    r78d3dd5 r5ea06d6  
    1818
    1919#include "kernel_private.h"
     20#include "libhdr.h"
    2021
    2122void set_owner( monitor_desc * this, thread_desc * owner ) {
     
    2829
    2930extern "C" {
    30         void __enter_monitor_desc(monitor_desc * this) {
     31        void __enter_monitor_desc(monitor_desc * this, monitor_desc * leader) {
    3132                lock( &this->lock );
    3233                thread_desc * thrd = this_thread();
     34
     35                //Update the stack owner
     36                this->stack_owner = leader;
    3337
    3438                if( !this->owner ) {
     
    5256
    5357                unlock( &this->lock );
     58                return;
    5459        }
    5560
     
    6974        //                                      context switch to him right away
    7075        //
    71         void __leave_monitor_desc(monitor_desc * this) {
     76        void __leave_monitor_desc(monitor_desc * this, monitor_desc * leader) {
    7277                lock( &this->lock );
    7378
    7479                thread_desc * thrd = this_thread();
    75                 assert( thrd == this->owner );
     80                assert( thrd == this->owner || this->stack_owner );
    7681
    7782                //Leaving a recursion level, decrement the counter
     
    8186                //it means we don't need to do anything
    8287                if( this->recursion != 0) {
     88                        this->stack_owner = leader;
    8389                        unlock( &this->lock );
    8490                        return;
     
    8793                //If we don't own the signal stack then just leave it to the owner
    8894                if( this->stack_owner ) {
    89                         assert( this->owner == this->stack_owner );
     95                        this->stack_owner = leader;
    9096                        unlock( &this->lock );
    9197                        return;
     
    102108                        //transfer control immediately
    103109                        set_owner( this, new_owner );
     110                        this->stack_owner = leader;
    104111                        ScheduleInternal( &this->lock, new_owner );
    105112                        return;
     
    111118                set_owner( this, new_owner );
    112119
     120                //Update the stack owner
     121                this->stack_owner = leader;
     122
    113123                //We can now let other threads in safely
    114124                unlock( &this->lock );
     
    119129}
    120130
    121 void enter(monitor_desc ** monitors, int count) {
    122         for(int i = 0; i < count; i++) {
    123                 __enter_monitor_desc( monitors[i] );
    124         }
    125 }
    126 
    127 void leave(monitor_desc ** monitors, int count) {
     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 );
    128140        for(int i = count - 1; i >= 0; i--) {
    129                 __leave_monitor_desc( monitors[i] );
    130         }
    131 }
     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}
  • src/libcfa/concurrency/thread.c

    r78d3dd5 r5ea06d6  
    3939        this->mon.recursion = 1;
    4040        this->next = NULL;
     41
     42        this->current_monitors      = NULL;
     43        this->current_monitor_count = 0;
    4144}
    4245
Note: See TracChangeset for help on using the changeset viewer.