Ignore:
Timestamp:
May 15, 2018, 4:17:15 PM (7 years ago)
Author:
Rob Schluntz <rschlunt@…>
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, with_gc
Children:
2e5fa345
Parents:
7d0a3ba (diff), a61fa0bb (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:/u/cforall/software/cfa/cfa-cc

Location:
src/libcfa/concurrency
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • src/libcfa/concurrency/coroutine

    r7d0a3ba r358cba0  
    7272// Suspend implementation inlined for performance
    7373static inline void suspend() {
    74         coroutine_desc * src = TL_GET( this_coroutine );                        // optimization
     74        // optimization : read TLS once and reuse it
     75        // Safety note: this is preemption safe since if
     76        // preemption occurs after this line, the pointer
     77        // will also migrate which means this value will
     78        // stay in syn with the TLS
     79        coroutine_desc * src = TL_GET( this_coroutine );
    7580
    7681        assertf( src->last != 0,
     
    8994forall(dtype T | is_coroutine(T))
    9095static inline void resume(T & cor) {
    91         coroutine_desc * src = TL_GET( this_coroutine );                        // optimization
     96        // optimization : read TLS once and reuse it
     97        // Safety note: this is preemption safe since if
     98        // preemption occurs after this line, the pointer
     99        // will also migrate which means this value will
     100        // stay in syn with the TLS
     101        coroutine_desc * src = TL_GET( this_coroutine );
    92102        coroutine_desc * dst = get_coroutine(cor);
    93103
     
    107117                dst->last = src;
    108118                dst->starter = dst->starter ? dst->starter : src;
    109         } // if
     119        }
    110120
    111121        // always done for performance testing
     
    114124
    115125static inline void resume(coroutine_desc * dst) {
    116         coroutine_desc * src = TL_GET( this_coroutine );                        // optimization
     126        // optimization : read TLS once and reuse it
     127        // Safety note: this is preemption safe since if
     128        // preemption occurs after this line, the pointer
     129        // will also migrate which means this value will
     130        // stay in syn with the TLS
     131        coroutine_desc * src = TL_GET( this_coroutine );
    117132
    118133        // not resuming self ?
     
    125140                // set last resumer
    126141                dst->last = src;
    127         } // if
     142        }
    128143
    129144        // always done for performance testing
  • src/libcfa/concurrency/coroutine.c

    r7d0a3ba r358cba0  
    8484// Wrapper for co
    8585void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    86       verify( TL_GET( preemption_state ).enabled || TL_GET( this_processor )->do_terminate );
     86      // Safety note : This could cause some false positives due to preemption
     87      verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
    8788      disable_interrupts();
    8889
     
    9192
    9293      // set new coroutine that task is executing
    93       TL_SET( this_coroutine, dst );
     94      kernelTLS.this_coroutine = dst;
    9495
    9596      // context switch to specified coroutine
     
    102103
    103104      enable_interrupts( __cfaabi_dbg_ctx );
    104       verify( TL_GET( preemption_state ).enabled || TL_GET( this_processor )->do_terminate );
     105      // Safety note : This could cause some false positives due to preemption
     106      verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
    105107} //ctxSwitchDirect
    106108
  • src/libcfa/concurrency/invoke.c

    r7d0a3ba r358cba0  
    6969        // Fetch the thread handle from the user defined thread structure
    7070        struct thread_desc* thrd = get_thread( this );
     71        thrd->self_cor.last = NULL;
    7172
    7273        // Officially start the thread by enabling preemption
  • src/libcfa/concurrency/invoke.h

    r7d0a3ba r358cba0  
    1818#include "bits/locks.h"
    1919
    20 #define TL_GET( member ) kernelThreadData.member
    21 #define TL_SET( member, value ) kernelThreadData.member = value;
     20#define TL_GET( member ) kernelTLS.member
     21#define TL_SET( member, value ) kernelTLS.member = value;
    2222
    2323#ifdef __cforall
     
    4444                                volatile bool in_progress;
    4545                        } preemption_state;
    46                 } kernelThreadData;
     46                } kernelTLS;
    4747        }
    4848
    4949        static inline struct coroutine_desc * volatile active_coroutine() { return TL_GET( this_coroutine ); }
    50         static inline struct thread_desc * volatile active_thread() { return TL_GET( this_thread ); }
    51         static inline struct processor * volatile active_processor() { return TL_GET( this_processor ); }
     50        static inline struct thread_desc    * volatile active_thread   () { return TL_GET( this_thread    ); }
     51        static inline struct processor      * volatile active_processor() { return TL_GET( this_processor ); } // UNSAFE
    5252        #endif
    5353
     
    136136                struct thread_desc * next;
    137137
    138                 __cfaabi_dbg_debug_do(
    139                         // instrusive link field for debugging
    140                         struct thread_desc * dbg_next;
    141                         struct thread_desc * dbg_prev;
    142                 )
     138                struct {
     139                        struct thread_desc * next;
     140                        struct thread_desc * prev;
     141                } node;
    143142     };
    144143
     
    147146                static inline thread_desc * & get_next( thread_desc & this ) {
    148147                        return this.next;
     148                }
     149
     150                static inline [thread_desc *&, thread_desc *& ] __get( thread_desc & this ) {
     151                        return this.node.[next, prev];
    149152                }
    150153
  • src/libcfa/concurrency/kernel

    r7d0a3ba r358cba0  
    4040
    4141//-----------------------------------------------------------------------------
    42 // Cluster
    43 struct cluster {
    44         // Ready queue locks
    45         __spinlock_t ready_queue_lock;
     42// Processor
     43extern struct cluster * mainCluster;
    4644
    47         // Ready queue for threads
    48         __queue_t(thread_desc) ready_queue;
    49 
    50         // Name of the cluster
    51         const char * name;
    52 
    53         // Preemption rate on this cluster
    54         Duration preemption_rate;
    55 };
    56 
    57 extern struct cluster * mainCluster;
    58 extern Duration default_preemption();
    59 
    60 void ?{} (cluster & this, const char * name, Duration preemption_rate);
    61 void ^?{}(cluster & this);
    62 
    63 static inline void ?{} (cluster & this)                           { this{"Anonymous Cluster", default_preemption()}; }
    64 static inline void ?{} (cluster & this, Duration preemption_rate) { this{"Anonymous Cluster", preemption_rate}; }
    65 static inline void ?{} (cluster & this, const char * name)        { this{name, default_preemption()}; }
    66 
    67 //-----------------------------------------------------------------------------
    68 // Processor
    6945enum FinishOpCode { No_Action, Release, Schedule, Release_Schedule, Release_Multi, Release_Multi_Schedule };
    7046
     
    9874
    9975        // Cluster from which to get threads
    100         cluster * cltr;
     76        struct cluster * cltr;
    10177
    10278        // Name of the processor
     
    124100        bool pending_preemption;
    125101
     102        // Idle lock
     103
     104        // Link lists fields
     105        struct {
     106                struct processor * next;
     107                struct processor * prev;
     108        } node;
     109
    126110#ifdef __CFA_DEBUG__
    127111        // Last function to enable preemption on this processor
     
    130114};
    131115
    132 void  ?{}(processor & this, const char * name, cluster & cltr);
     116void  ?{}(processor & this, const char * name, struct cluster & cltr);
    133117void ^?{}(processor & this);
    134118
    135119static inline void  ?{}(processor & this)                    { this{ "Anonymous Processor", *mainCluster}; }
    136 static inline void  ?{}(processor & this, cluster & cltr)    { this{ "Anonymous Processor", cltr}; }
     120static inline void  ?{}(processor & this, struct cluster & cltr)    { this{ "Anonymous Processor", cltr}; }
    137121static inline void  ?{}(processor & this, const char * name) { this{name, *mainCluster }; }
     122
     123static inline [processor *&, processor *& ] __get( processor & this ) {
     124        return this.node.[next, prev];
     125}
     126
     127//-----------------------------------------------------------------------------
     128// Cluster
     129struct cluster {
     130        // Ready queue locks
     131        __spinlock_t ready_queue_lock;
     132
     133        // Ready queue for threads
     134        __queue_t(thread_desc) ready_queue;
     135
     136        // Name of the cluster
     137        const char * name;
     138
     139        // Preemption rate on this cluster
     140        Duration preemption_rate;
     141
     142        // List of processors
     143        __spinlock_t proc_list_lock;
     144        __dllist_t(struct processor) procs;
     145        __dllist_t(struct processor) idles;
     146
     147        // Link lists fields
     148        struct {
     149                cluster * next;
     150                cluster * prev;
     151        } node;
     152};
     153extern Duration default_preemption();
     154
     155void ?{} (cluster & this, const char * name, Duration preemption_rate);
     156void ^?{}(cluster & this);
     157
     158static inline void ?{} (cluster & this)                           { this{"Anonymous Cluster", default_preemption()}; }
     159static inline void ?{} (cluster & this, Duration preemption_rate) { this{"Anonymous Cluster", preemption_rate}; }
     160static inline void ?{} (cluster & this, const char * name)        { this{name, default_preemption()}; }
     161
     162static inline [cluster *&, cluster *& ] __get( cluster & this ) {
     163        return this.node.[next, prev];
     164}
    138165
    139166// Local Variables: //
  • src/libcfa/concurrency/kernel.c

    r7d0a3ba r358cba0  
    4949thread_desc * mainThread;
    5050
     51struct { __dllist_t(thread_desc) list; __spinlock_t lock; } global_threads ;
     52struct { __dllist_t(cluster    ) list; __spinlock_t lock; } global_clusters;
     53
    5154//-----------------------------------------------------------------------------
    5255// Global state
     
    5659// volatile thread_local unsigned short disable_preempt_count = 1;
    5760
    58 thread_local struct KernelThreadData kernelThreadData = {
     61thread_local struct KernelThreadData kernelTLS = {
    5962        NULL,
    6063        NULL,
     
    117120        self_mon_p = &self_mon;
    118121        next = NULL;
    119         __cfaabi_dbg_debug_do(
    120                 dbg_next = NULL;
    121                 dbg_prev = NULL;
    122                 __cfaabi_dbg_thread_register(&this);
    123         )
     122
     123        node.next = NULL;
     124        node.prev = NULL;
     125        doregister(this);
    124126
    125127        monitors{ &self_mon_p, 1, (fptr_t)0 };
     
    155157                terminate(&this);
    156158                verify(this.do_terminate);
    157                 verify(TL_GET( this_processor ) != &this);
     159                verify( kernelTLS.this_processor != &this);
    158160                P( terminated );
    159                 verify(TL_GET( this_processor ) != &this);
     161                verify( kernelTLS.this_processor != &this);
    160162                pthread_join( kernel_thread, NULL );
    161163        }
     
    167169        ready_queue{};
    168170        ready_queue_lock{};
     171
     172        procs{ __get };
     173        idles{ __get };
     174
     175        doregister(this);
    169176}
    170177
    171178void ^?{}(cluster & this) {
    172 
     179        unregister(this);
    173180}
    174181
     
    183190        __cfaabi_dbg_print_safe("Kernel : core %p starting\n", this);
    184191
     192        doregister(this->cltr, this);
     193
    185194        {
    186195                // Setup preemption data
     
    196205                        if(readyThread)
    197206                        {
    198                                 verify( ! TL_GET( preemption_state ).enabled );
     207                                verify( ! kernelTLS.preemption_state.enabled );
    199208
    200209                                runThread(this, readyThread);
    201210
    202                                 verify( ! TL_GET( preemption_state ).enabled );
     211                                verify( ! kernelTLS.preemption_state.enabled );
    203212
    204213                                //Some actions need to be taken from the kernel
     
    216225        }
    217226
     227        unregister(this->cltr, this);
     228
    218229        V( this->terminated );
    219230
     
    221232}
    222233
     234// KERNEL ONLY
    223235// runThread runs a thread by context switching
    224236// from the processor coroutine to the target thread
     
    228240        coroutine_desc * thrd_cor = dst->curr_cor;
    229241
    230         //Reset the terminating actions here
     242        // Reset the terminating actions here
    231243        this->finish.action_code = No_Action;
    232244
    233         //Update global state
    234         TL_SET( this_thread, dst );
     245        // Update global state
     246        kernelTLS.this_thread = dst;
    235247
    236248        // Context Switch to the thread
     
    239251}
    240252
     253// KERNEL_ONLY
    241254void returnToKernel() {
    242         coroutine_desc * proc_cor = get_coroutine(TL_GET( this_processor )->runner);
    243         coroutine_desc * thrd_cor = TL_GET( this_thread )->curr_cor = TL_GET( this_coroutine );
     255        coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
     256        coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine;
    244257        ThreadCtxSwitch(thrd_cor, proc_cor);
    245258}
    246259
     260// KERNEL_ONLY
    247261// Once a thread has finished running, some of
    248262// its final actions must be executed from the kernel
    249263void finishRunning(processor * this) with( this->finish ) {
    250264        if( action_code == Release ) {
    251                 verify( ! TL_GET( preemption_state ).enabled );
     265                verify( ! kernelTLS.preemption_state.enabled );
    252266                unlock( *lock );
    253267        }
     
    256270        }
    257271        else if( action_code == Release_Schedule ) {
    258                 verify( ! TL_GET( preemption_state ).enabled );
     272                verify( ! kernelTLS.preemption_state.enabled );
    259273                unlock( *lock );
    260274                ScheduleThread( thrd );
    261275        }
    262276        else if( action_code == Release_Multi ) {
    263                 verify( ! TL_GET( preemption_state ).enabled );
     277                verify( ! kernelTLS.preemption_state.enabled );
    264278                for(int i = 0; i < lock_count; i++) {
    265279                        unlock( *locks[i] );
     
    285299}
    286300
     301// KERNEL_ONLY
    287302// Context invoker for processors
    288303// This is the entry point for processors (kernel threads)
     
    290305void * CtxInvokeProcessor(void * arg) {
    291306        processor * proc = (processor *) arg;
    292         TL_SET( this_processor, proc );
    293         TL_SET( this_coroutine, NULL );
    294         TL_SET( this_thread, NULL );
    295         TL_GET( preemption_state ).[enabled, disable_count] = [false, 1];
     307        kernelTLS.this_processor = proc;
     308        kernelTLS.this_coroutine = NULL;
     309        kernelTLS.this_thread    = NULL;
     310        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
    296311        // SKULLDUGGERY: We want to create a context for the processor coroutine
    297312        // which is needed for the 2-step context switch. However, there is no reason
     
    305320
    306321        //Set global state
    307         TL_SET( this_coroutine, get_coroutine(proc->runner) );
    308         TL_SET( this_thread, NULL );
     322        kernelTLS.this_coroutine = get_coroutine(proc->runner);
     323        kernelTLS.this_thread    = NULL;
    309324
    310325        //We now have a proper context from which to schedule threads
     
    333348}
    334349
     350// KERNEL_ONLY
    335351void kernel_first_resume(processor * this) {
    336         coroutine_desc * src = TL_GET( this_coroutine );
     352        coroutine_desc * src = kernelTLS.this_coroutine;
    337353        coroutine_desc * dst = get_coroutine(this->runner);
    338354
    339         verify( ! TL_GET( preemption_state ).enabled );
     355        verify( ! kernelTLS.preemption_state.enabled );
    340356
    341357        create_stack(&dst->stack, dst->stack.size);
    342358        CtxStart(&this->runner, CtxInvokeCoroutine);
    343359
    344         verify( ! TL_GET( preemption_state ).enabled );
     360        verify( ! kernelTLS.preemption_state.enabled );
    345361
    346362        dst->last = src;
     
    351367
    352368        // set new coroutine that task is executing
    353         TL_SET( this_coroutine, dst );
     369        kernelTLS.this_coroutine = dst;
    354370
    355371        // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch.
     
    368384        src->state = Active;
    369385
    370         verify( ! TL_GET( preemption_state ).enabled );
     386        verify( ! kernelTLS.preemption_state.enabled );
    371387}
    372388
    373389//-----------------------------------------------------------------------------
    374390// Scheduler routines
     391
     392// KERNEL ONLY
    375393void ScheduleThread( thread_desc * thrd ) {
    376         // if( ! thrd ) return;
    377394        verify( thrd );
    378395        verify( thrd->self_cor.state != Halted );
    379396
    380         verify( ! TL_GET( preemption_state ).enabled );
     397        verify( ! kernelTLS.preemption_state.enabled );
    381398
    382399        verifyf( thrd->next == NULL, "Expected null got %p", thrd->next );
     
    388405        }
    389406
    390         verify( ! TL_GET( preemption_state ).enabled );
    391 }
    392 
     407        verify( ! kernelTLS.preemption_state.enabled );
     408}
     409
     410// KERNEL ONLY
    393411thread_desc * nextThread(cluster * this) with( *this ) {
    394         verify( ! TL_GET( preemption_state ).enabled );
     412        verify( ! kernelTLS.preemption_state.enabled );
    395413        lock( ready_queue_lock __cfaabi_dbg_ctx2 );
    396414        thread_desc * head = pop_head( ready_queue );
    397415        unlock( ready_queue_lock );
    398         verify( ! TL_GET( preemption_state ).enabled );
     416        verify( ! kernelTLS.preemption_state.enabled );
    399417        return head;
    400418}
     
    402420void BlockInternal() {
    403421        disable_interrupts();
    404         verify( ! TL_GET( preemption_state ).enabled );
     422        verify( ! kernelTLS.preemption_state.enabled );
    405423        returnToKernel();
    406         verify( ! TL_GET( preemption_state ).enabled );
     424        verify( ! kernelTLS.preemption_state.enabled );
    407425        enable_interrupts( __cfaabi_dbg_ctx );
    408426}
     
    410428void BlockInternal( __spinlock_t * lock ) {
    411429        disable_interrupts();
    412         with( *TL_GET( this_processor ) ) {
     430        with( *kernelTLS.this_processor ) {
    413431                finish.action_code = Release;
    414432                finish.lock        = lock;
    415433        }
    416434
    417         verify( ! TL_GET( preemption_state ).enabled );
     435        verify( ! kernelTLS.preemption_state.enabled );
    418436        returnToKernel();
    419         verify( ! TL_GET( preemption_state ).enabled );
     437        verify( ! kernelTLS.preemption_state.enabled );
    420438
    421439        enable_interrupts( __cfaabi_dbg_ctx );
     
    424442void BlockInternal( thread_desc * thrd ) {
    425443        disable_interrupts();
    426         with( *TL_GET( this_processor ) ) {
     444        with( * kernelTLS.this_processor ) {
    427445                finish.action_code = Schedule;
    428446                finish.thrd        = thrd;
    429447        }
    430448
    431         verify( ! TL_GET( preemption_state ).enabled );
     449        verify( ! kernelTLS.preemption_state.enabled );
    432450        returnToKernel();
    433         verify( ! TL_GET( preemption_state ).enabled );
     451        verify( ! kernelTLS.preemption_state.enabled );
    434452
    435453        enable_interrupts( __cfaabi_dbg_ctx );
     
    439457        assert(thrd);
    440458        disable_interrupts();
    441         with( *TL_GET( this_processor ) ) {
     459        with( * kernelTLS.this_processor ) {
    442460                finish.action_code = Release_Schedule;
    443461                finish.lock        = lock;
     
    445463        }
    446464
    447         verify( ! TL_GET( preemption_state ).enabled );
     465        verify( ! kernelTLS.preemption_state.enabled );
    448466        returnToKernel();
    449         verify( ! TL_GET( preemption_state ).enabled );
     467        verify( ! kernelTLS.preemption_state.enabled );
    450468
    451469        enable_interrupts( __cfaabi_dbg_ctx );
     
    454472void BlockInternal(__spinlock_t * locks [], unsigned short count) {
    455473        disable_interrupts();
    456         with( *TL_GET( this_processor ) ) {
     474        with( * kernelTLS.this_processor ) {
    457475                finish.action_code = Release_Multi;
    458476                finish.locks       = locks;
     
    460478        }
    461479
    462         verify( ! TL_GET( preemption_state ).enabled );
     480        verify( ! kernelTLS.preemption_state.enabled );
    463481        returnToKernel();
    464         verify( ! TL_GET( preemption_state ).enabled );
     482        verify( ! kernelTLS.preemption_state.enabled );
    465483
    466484        enable_interrupts( __cfaabi_dbg_ctx );
     
    469487void BlockInternal(__spinlock_t * locks [], unsigned short lock_count, thread_desc * thrds [], unsigned short thrd_count) {
    470488        disable_interrupts();
    471         with( *TL_GET( this_processor ) ) {
     489        with( *kernelTLS.this_processor ) {
    472490                finish.action_code = Release_Multi_Schedule;
    473491                finish.locks       = locks;
     
    477495        }
    478496
    479         verify( ! TL_GET( preemption_state ).enabled );
     497        verify( ! kernelTLS.preemption_state.enabled );
    480498        returnToKernel();
    481         verify( ! TL_GET( preemption_state ).enabled );
     499        verify( ! kernelTLS.preemption_state.enabled );
    482500
    483501        enable_interrupts( __cfaabi_dbg_ctx );
    484502}
    485503
     504// KERNEL ONLY
    486505void LeaveThread(__spinlock_t * lock, thread_desc * thrd) {
    487         verify( ! TL_GET( preemption_state ).enabled );
    488         with( *TL_GET( this_processor ) ) {
     506        verify( ! kernelTLS.preemption_state.enabled );
     507        with( * kernelTLS.this_processor ) {
    489508                finish.action_code = thrd ? Release_Schedule : Release;
    490509                finish.lock        = lock;
     
    501520// Kernel boot procedures
    502521void kernel_startup(void) {
    503         verify( ! TL_GET( preemption_state ).enabled );
     522        verify( ! kernelTLS.preemption_state.enabled );
    504523        __cfaabi_dbg_print_safe("Kernel : Starting\n");
     524
     525        global_threads. list{ __get };
     526        global_threads. lock{};
     527        global_clusters.list{ __get };
     528        global_clusters.lock{};
    505529
    506530        // Initialize the main cluster
     
    547571
    548572        //initialize the global state variables
    549         TL_SET( this_processor, mainProcessor );
    550         TL_SET( this_thread, mainThread );
    551         TL_SET( this_coroutine, &mainThread->self_cor );
     573        kernelTLS.this_processor = mainProcessor;
     574        kernelTLS.this_thread    = mainThread;
     575        kernelTLS.this_coroutine = &mainThread->self_cor;
    552576
    553577        // Enable preemption
     
    561585        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
    562586        // mainThread is on the ready queue when this call is made.
    563         kernel_first_resume( TL_GET( this_processor ) );
     587        kernel_first_resume( kernelTLS.this_processor );
    564588
    565589
     
    568592        __cfaabi_dbg_print_safe("Kernel : Started\n--------------------------------------------------\n\n");
    569593
    570         verify( ! TL_GET( preemption_state ).enabled );
     594        verify( ! kernelTLS.preemption_state.enabled );
    571595        enable_interrupts( __cfaabi_dbg_ctx );
    572         verify( TL_GET( preemption_state ).enabled );
     596        verify( TL_GET( preemption_state.enabled ) );
    573597}
    574598
     
    576600        __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
    577601
    578         verify( TL_GET( preemption_state ).enabled );
     602        verify( TL_GET( preemption_state.enabled ) );
    579603        disable_interrupts();
    580         verify( ! TL_GET( preemption_state ).enabled );
     604        verify( ! kernelTLS.preemption_state.enabled );
    581605
    582606        // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
     
    604628
    605629//=============================================================================================
     630// Kernel Quiescing
     631//=============================================================================================
     632
     633// void halt(processor * this) with( this ) {
     634//      pthread_mutex_lock( &idle.lock );
     635
     636
     637
     638//      // SKULLDUGGERY: Even if spurious wake-up is a thing
     639//      // spuriously waking up a kernel thread is not a big deal
     640//      // if it is very rare.
     641//      pthread_cond_wait( &idle.cond, &idle.lock);
     642//      pthread_mutex_unlock( &idle.lock );
     643// }
     644
     645// void wake(processor * this) with( this ) {
     646//      pthread_mutex_lock  (&idle.lock);
     647//      pthread_cond_signal (&idle.cond);
     648//      pthread_mutex_unlock(&idle.lock);
     649// }
     650
     651//=============================================================================================
    606652// Unexpected Terminating logic
    607653//=============================================================================================
     
    609655
    610656static __spinlock_t kernel_abort_lock;
    611 static __spinlock_t kernel_debug_lock;
    612657static bool kernel_abort_called = false;
    613658
    614 void * kernel_abort    (void) __attribute__ ((__nothrow__)) {
     659void * kernel_abort(void) __attribute__ ((__nothrow__)) {
    615660        // abort cannot be recursively entered by the same or different processors because all signal handlers return when
    616661        // the globalAbort flag is true.
     
    618663
    619664        // first task to abort ?
    620         if ( ! kernel_abort_called ) {                  // not first task to abort ?
     665        if ( kernel_abort_called ) {                    // not first task to abort ?
     666                unlock( kernel_abort_lock );
     667
     668                sigset_t mask;
     669                sigemptyset( &mask );
     670                sigaddset( &mask, SIGALRM );            // block SIGALRM signals
     671                sigsuspend( &mask );                    // block the processor to prevent further damage during abort
     672                _exit( EXIT_FAILURE );                  // if processor unblocks before it is killed, terminate it
     673        }
     674        else {
    621675                kernel_abort_called = true;
    622676                unlock( kernel_abort_lock );
    623677        }
    624         else {
    625                 unlock( kernel_abort_lock );
    626 
    627                 sigset_t mask;
    628                 sigemptyset( &mask );
    629                 sigaddset( &mask, SIGALRM );                    // block SIGALRM signals
    630                 sigaddset( &mask, SIGUSR1 );                    // block SIGUSR1 signals
    631                 sigsuspend( &mask );                            // block the processor to prevent further damage during abort
    632                 _exit( EXIT_FAILURE );                          // if processor unblocks before it is killed, terminate it
    633         }
    634 
    635         return TL_GET( this_thread );
     678
     679        return kernelTLS.this_thread;
    636680}
    637681
     
    639683        thread_desc * thrd = kernel_data;
    640684
    641         int len = snprintf( abort_text, abort_text_size, "Error occurred while executing task %.256s (%p)", thrd->self_cor.name, thrd );
    642         __cfaabi_dbg_bits_write( abort_text, len );
    643 
    644         if ( get_coroutine(thrd) != TL_GET( this_coroutine ) ) {
    645                 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", TL_GET( this_coroutine )->name, TL_GET( this_coroutine ) );
     685        if(thrd) {
     686                int len = snprintf( abort_text, abort_text_size, "Error occurred while executing thread %.256s (%p)", thrd->self_cor.name, thrd );
    646687                __cfaabi_dbg_bits_write( abort_text, len );
     688
     689                if ( get_coroutine(thrd) != kernelTLS.this_coroutine ) {
     690                        len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", kernelTLS.this_coroutine->name, kernelTLS.this_coroutine );
     691                        __cfaabi_dbg_bits_write( abort_text, len );
     692                }
     693                else {
     694                        __cfaabi_dbg_bits_write( ".\n", 2 );
     695                }
    647696        }
    648697        else {
    649                 __cfaabi_dbg_bits_write( ".\n", 2 );
     698                int len = snprintf( abort_text, abort_text_size, "Error occurred outside of any thread.\n" );
    650699        }
    651700}
    652701
    653702int kernel_abort_lastframe( void ) __attribute__ ((__nothrow__)) {
    654         return get_coroutine(TL_GET( this_thread )) == get_coroutine(mainThread) ? 4 : 2;
    655 }
     703        return get_coroutine(kernelTLS.this_thread) == get_coroutine(mainThread) ? 4 : 2;
     704}
     705
     706static __spinlock_t kernel_debug_lock;
    656707
    657708extern "C" {
     
    682733        if ( count < 0 ) {
    683734                // queue current task
    684                 append( waiting, (thread_desc *)TL_GET( this_thread ) );
     735                append( waiting, kernelTLS.this_thread );
    685736
    686737                // atomically release spin lock and block
     
    708759
    709760//-----------------------------------------------------------------------------
     761// Global Queues
     762void doregister( thread_desc & thrd ) {
     763        // lock      ( global_thread.lock );
     764        // push_front( global_thread.list, thrd );
     765        // unlock    ( global_thread.lock );
     766}
     767
     768void unregister( thread_desc & thrd ) {
     769        // lock  ( global_thread.lock );
     770        // remove( global_thread.list, thrd );
     771        // unlock( global_thread.lock );
     772}
     773
     774void doregister( cluster     & cltr ) {
     775        // lock      ( global_cluster.lock );
     776        // push_front( global_cluster.list, cltr );
     777        // unlock    ( global_cluster.lock );
     778}
     779
     780void unregister( cluster     & cltr ) {
     781        // lock  ( global_cluster.lock );
     782        // remove( global_cluster.list, cltr );
     783        // unlock( global_cluster.lock );
     784}
     785
     786
     787void doregister( cluster * cltr, processor * proc ) {
     788        // lock      (cltr->proc_list_lock __cfaabi_dbg_ctx2);
     789        // push_front(cltr->procs, *proc);
     790        // unlock    (cltr->proc_list_lock);
     791}
     792
     793void unregister( cluster * cltr, processor * proc ) {
     794        // lock  (cltr->proc_list_lock __cfaabi_dbg_ctx2);
     795        // remove(cltr->procs, *proc );
     796        // unlock(cltr->proc_list_lock);
     797}
     798
     799//-----------------------------------------------------------------------------
    710800// Debug
    711801__cfaabi_dbg_debug_do(
    712         struct {
    713                 thread_desc * tail;
    714         } __cfaabi_dbg_thread_list = { NULL };
    715 
    716         void __cfaabi_dbg_thread_register( thread_desc * thrd ) {
    717                 if( !__cfaabi_dbg_thread_list.tail ) {
    718                         __cfaabi_dbg_thread_list.tail = thrd;
    719                         return;
    720                 }
    721                 __cfaabi_dbg_thread_list.tail->dbg_next = thrd;
    722                 thrd->dbg_prev = __cfaabi_dbg_thread_list.tail;
    723                 __cfaabi_dbg_thread_list.tail = thrd;
    724         }
    725 
    726         void __cfaabi_dbg_thread_unregister( thread_desc * thrd ) {
    727                 thread_desc * prev = thrd->dbg_prev;
    728                 thread_desc * next = thrd->dbg_next;
    729 
    730                 if( next ) { next->dbg_prev = prev; }
    731                 else       {
    732                         assert( __cfaabi_dbg_thread_list.tail == thrd );
    733                         __cfaabi_dbg_thread_list.tail = prev;
    734                 }
    735 
    736                 if( prev ) { prev->dbg_next = next; }
    737 
    738                 thrd->dbg_prev = NULL;
    739                 thrd->dbg_next = NULL;
    740         }
    741 
    742802        void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) {
    743803                this.prev_name = prev_name;
    744                 this.prev_thrd = TL_GET( this_thread );
     804                this.prev_thrd = kernelTLS.this_thread;
    745805        }
    746806)
  • src/libcfa/concurrency/kernel_private.h

    r7d0a3ba r358cba0  
    100100#define KERNEL_STORAGE(T,X) static char storage_##X[sizeof(T)]
    101101
     102
     103void doregister( struct thread_desc & thrd );
     104void unregister( struct thread_desc & thrd );
     105
     106void doregister( struct cluster     & cltr );
     107void unregister( struct cluster     & cltr );
     108
     109void doregister( struct cluster * cltr, struct processor * proc );
     110void unregister( struct cluster * cltr, struct processor * proc );
     111
    102112// Local Variables: //
    103113// mode: c //
  • src/libcfa/concurrency/monitor.c

    r7d0a3ba r358cba0  
    8585                // Lock the monitor spinlock
    8686                lock( this->lock __cfaabi_dbg_ctx2 );
    87                 thread_desc * thrd = TL_GET( this_thread );
     87                // Interrupts disable inside critical section
     88                thread_desc * thrd = kernelTLS.this_thread;
    8889
    8990                __cfaabi_dbg_print_safe( "Kernel : %10p Entering mon %p (%p)\n", thrd, this, this->owner);
     
    134135                // Lock the monitor spinlock
    135136                lock( this->lock __cfaabi_dbg_ctx2 );
    136                 thread_desc * thrd = TL_GET( this_thread );
     137                // Interrupts disable inside critical section
     138                thread_desc * thrd = kernelTLS.this_thread;
    137139
    138140                __cfaabi_dbg_print_safe( "Kernel : %10p Entering dtor for mon %p (%p)\n", thrd, this, this->owner);
     
    168170
    169171                        // Create the node specific to this wait operation
    170                         wait_ctx_primed( TL_GET( this_thread ), 0 )
     172                        wait_ctx_primed( thrd, 0 )
    171173
    172174                        // Some one else has the monitor, wait for him to finish and then run
     
    179181                        __cfaabi_dbg_print_safe( "Kernel :  blocking \n" );
    180182
    181                         wait_ctx( TL_GET( this_thread ), 0 )
     183                        wait_ctx( thrd, 0 )
    182184                        this->dtor_node = &waiter;
    183185
     
    199201                lock( this->lock __cfaabi_dbg_ctx2 );
    200202
    201                 __cfaabi_dbg_print_safe( "Kernel : %10p Leaving mon %p (%p)\n", TL_GET( this_thread ), this, this->owner);
    202 
    203                 verifyf( TL_GET( this_thread ) == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", TL_GET( this_thread ), this->owner, this->recursion, this );
     203                __cfaabi_dbg_print_safe( "Kernel : %10p Leaving mon %p (%p)\n", kernelTLS.this_thread, this, this->owner);
     204
     205                verifyf( kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    204206
    205207                // Leaving a recursion level, decrement the counter
     
    289291// Sorts monitors before entering
    290292void ?{}( monitor_guard_t & this, monitor_desc * m [], __lock_size_t count, fptr_t func ) {
     293        thread_desc * thrd = TL_GET( this_thread );
     294
    291295        // Store current array
    292296        this.m = m;
     
    297301
    298302        // Save previous thread context
    299         this.prev = TL_GET( this_thread )->monitors;
     303        this.prev = thrd->monitors;
    300304
    301305        // Update thread context (needed for conditions)
    302         (TL_GET( this_thread )->monitors){m, count, func};
     306        (thrd->monitors){m, count, func};
    303307
    304308        // __cfaabi_dbg_print_safe( "MGUARD : enter %d\n", count);
     
    328332// Sorts monitors before entering
    329333void ?{}( monitor_dtor_guard_t & this, monitor_desc * m [], fptr_t func ) {
     334        // optimization
     335        thread_desc * thrd = TL_GET( this_thread );
     336
    330337        // Store current array
    331338        this.m = *m;
    332339
    333340        // Save previous thread context
    334         this.prev = TL_GET( this_thread )->monitors;
     341        this.prev = thrd->monitors;
    335342
    336343        // Update thread context (needed for conditions)
    337         (TL_GET( this_thread )->monitors){m, 1, func};
     344        (thrd->monitors){m, 1, func};
    338345
    339346        __enter_monitor_dtor( this.m, func );
     
    473480
    474481        // Create the node specific to this wait operation
    475         wait_ctx_primed( TL_GET( this_thread ), 0 )
     482        wait_ctx_primed( kernelTLS.this_thread, 0 )
    476483
    477484        //save contexts
     
    566573
    567574                                // Create the node specific to this wait operation
    568                                 wait_ctx_primed( TL_GET( this_thread ), 0 );
     575                                wait_ctx_primed( kernelTLS.this_thread, 0 );
    569576
    570577                                // Save monitor states
     
    612619
    613620        // Create the node specific to this wait operation
    614         wait_ctx_primed( TL_GET( this_thread ), 0 );
     621        wait_ctx_primed( kernelTLS.this_thread, 0 );
    615622
    616623        monitor_save;
     
    618625
    619626        for( __lock_size_t i = 0; i < count; i++) {
    620                 verify( monitors[i]->owner == TL_GET( this_thread ) );
     627                verify( monitors[i]->owner == kernelTLS.this_thread );
    621628        }
    622629
  • src/libcfa/concurrency/preemption.c

    r7d0a3ba r358cba0  
    149149        // Disable interrupts by incrementing the counter
    150150        void disable_interrupts() {
    151                 with( TL_GET( preemption_state ) ) {
     151                with( kernelTLS.preemption_state ) {
    152152                        enabled = false;
    153153                        __attribute__((unused)) unsigned short new_val = disable_count + 1;
     
    160160        // If counter reaches 0, execute any pending CtxSwitch
    161161        void enable_interrupts( __cfaabi_dbg_ctx_param ) {
    162                 processor   * proc = TL_GET( this_processor ); // Cache the processor now since interrupts can start happening after the atomic add
    163                 thread_desc * thrd = TL_GET( this_thread );       // Cache the thread now since interrupts can start happening after the atomic add
    164 
    165                 with( TL_GET( preemption_state ) ){
     162                processor   * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic add
     163                thread_desc * thrd = kernelTLS.this_thread;       // Cache the thread now since interrupts can start happening after the atomic add
     164
     165                with( kernelTLS.preemption_state ){
    166166                        unsigned short prev = disable_count;
    167167                        disable_count -= 1;
     
    185185        // Don't execute any pending CtxSwitch even if counter reaches 0
    186186        void enable_interrupts_noPoll() {
    187                 unsigned short prev = TL_GET( preemption_state ).disable_count;
    188                 TL_GET( preemption_state ).disable_count -= 1;
     187                unsigned short prev = kernelTLS.preemption_state.disable_count;
     188                kernelTLS.preemption_state.disable_count -= 1;
    189189                verifyf( prev != 0u, "Incremented from %u\n", prev );                     // If this triggers someone is enabled already enabled interrupts
    190190                if( prev == 1 ) {
    191                         TL_GET( preemption_state ).enabled = true;
     191                        kernelTLS.preemption_state.enabled = true;
    192192                }
    193193        }
     
    234234}
    235235
    236 
     236// KERNEL ONLY
    237237// Check if a CtxSwitch signal handler shoud defer
    238238// If true  : preemption is safe
    239239// If false : preemption is unsafe and marked as pending
    240240static inline bool preemption_ready() {
    241         bool ready = TL_GET( preemption_state ).enabled && !TL_GET( preemption_state ).in_progress; // Check if preemption is safe
    242         TL_GET( this_processor )->pending_preemption = !ready;                  // Adjust the pending flag accordingly
     241        // Check if preemption is safe
     242        bool ready = kernelTLS.preemption_state.enabled && ! kernelTLS.preemption_state.in_progress;
     243
     244        // Adjust the pending flag accordingly
     245        kernelTLS.this_processor->pending_preemption = !ready;
    243246        return ready;
    244247}
     
    254257
    255258        // Start with preemption disabled until ready
    256         TL_GET( preemption_state ).enabled = false;
    257         TL_GET( preemption_state ).disable_count = 1;
     259        kernelTLS.preemption_state.enabled = false;
     260        kernelTLS.preemption_state.disable_count = 1;
    258261
    259262        // Initialize the event kernel
     
    320323        // before the kernel thread has even started running. When that happens an iterrupt
    321324        // we a null 'this_processor' will be caught, just ignore it.
    322         if(!TL_GET( this_processor )) return;
     325        if(! kernelTLS.this_processor ) return;
    323326
    324327        choose(sfp->si_value.sival_int) {
    325328                case PREEMPT_NORMAL   : ;// Normal case, nothing to do here
    326                 case PREEMPT_TERMINATE: verify(TL_GET( this_processor )->do_terminate);
     329                case PREEMPT_TERMINATE: verify( kernelTLS.this_processor->do_terminate);
    327330                default:
    328331                        abort( "internal error, signal value is %d", sfp->si_value.sival_int );
     
    332335        if( !preemption_ready() ) { return; }
    333336
    334         __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p).\n", TL_GET( this_processor ), TL_GET( this_thread ) );
    335 
    336         TL_GET( preemption_state ).in_progress = true;  // Sync flag : prevent recursive calls to the signal handler
    337         signal_unblock( SIGUSR1 );                          // We are about to CtxSwitch out of the signal handler, let other handlers in
    338         TL_GET( preemption_state ).in_progress = false; // Clear the in progress flag
     337        __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p).\n", kernelTLS.this_processor, kernelTLS.this_thread );
     338
     339        // Sync flag : prevent recursive calls to the signal handler
     340        kernelTLS.preemption_state.in_progress = true;
     341
     342        // We are about to CtxSwitch out of the signal handler, let other handlers in
     343        signal_unblock( SIGUSR1 );
     344
     345        // TODO: this should go in finish action
     346        // Clear the in progress flag
     347        kernelTLS.preemption_state.in_progress = false;
    339348
    340349        // Preemption can occur here
    341350
    342         BlockInternal( (thread_desc*)TL_GET( this_thread ) ); // Do the actual CtxSwitch
     351        BlockInternal( kernelTLS.this_thread ); // Do the actual CtxSwitch
    343352}
    344353
     
    348357        // Block sigalrms to control when they arrive
    349358        sigset_t mask;
     359        sigfillset(&mask);
     360        if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) {
     361            abort( "internal error, pthread_sigmask" );
     362        }
     363
    350364        sigemptyset( &mask );
    351365        sigaddset( &mask, SIGALRM );
    352 
    353         if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) {
    354             abort( "internal error, pthread_sigmask" );
    355         }
    356366
    357367        // Main loop
     
    409419
    410420void __cfaabi_check_preemption() {
    411         bool ready = TL_GET( preemption_state ).enabled;
     421        bool ready = kernelTLS.preemption_state.enabled;
    412422        if(!ready) { abort("Preemption should be ready"); }
    413423
  • src/libcfa/concurrency/thread.c

    r7d0a3ba r358cba0  
    3939        curr_cluster = &cl;
    4040        next = NULL;
    41         __cfaabi_dbg_debug_do(
    42                 dbg_next = NULL;
    43                 dbg_prev = NULL;
    44                 __cfaabi_dbg_thread_register(&this);
    45         )
     41
     42        node.next = NULL;
     43        node.prev = NULL;
     44        doregister(this);
    4645
    4746        monitors{ &self_mon_p, 1, (fptr_t)0 };
     
    4948
    5049void ^?{}(thread_desc& this) with( this ) {
     50        unregister(this);
    5151        ^self_cor{};
    5252}
     
    8181        disable_interrupts();
    8282        create_stack(&thrd_c->stack, thrd_c->stack.size);
    83         TL_SET( this_coroutine, thrd_c );
     83        kernelTLS.this_coroutine = thrd_c;
    8484        CtxStart(&this, CtxInvokeThread);
    8585        assert( thrd_c->last->stack.context );
     
    9191
    9292extern "C" {
     93        // KERNEL ONLY
    9394        void __finish_creation(void) {
    94                 coroutine_desc* thrd_c = TL_GET( this_coroutine );
     95                coroutine_desc* thrd_c = kernelTLS.this_coroutine;
    9596                ThreadCtxSwitch( thrd_c, thrd_c->last );
    9697        }
     
    9899
    99100void yield( void ) {
    100         verify( TL_GET( preemption_state ).enabled );
     101        // Safety note : This could cause some false positives due to preemption
     102      verify( TL_GET( preemption_state.enabled ) );
    101103        BlockInternal( TL_GET( this_thread ) );
    102         verify( TL_GET( preemption_state ).enabled );
     104        // Safety note : This could cause some false positives due to preemption
     105      verify( TL_GET( preemption_state.enabled ) );
    103106}
    104107
     
    109112}
    110113
     114// KERNEL ONLY
    111115void ThreadCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    112116        // set state of current coroutine to inactive
     
    116120        // set new coroutine that the processor is executing
    117121        // and context switch to it
    118         TL_SET( this_coroutine, dst );
     122        kernelTLS.this_coroutine = dst;
    119123        assert( src->stack.context );
    120124        CtxSwitch( src->stack.context, dst->stack.context );
    121         TL_SET( this_coroutine, src );
     125        kernelTLS.this_coroutine = src;
    122126
    123127        // set state of new coroutine to active
Note: See TracChangeset for help on using the changeset viewer.