Ignore:
Timestamp:
Oct 29, 2019, 4:01:24 PM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
773db65, 9421f3d8
Parents:
7951100 (diff), 8364209 (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:software/cfa/cfa-cc

File:
1 moved

Legend:

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

    r7951100 rb067d9b  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr  9 16:11:46 2018
    13 // Update Count     : 24
     12// Last Modified On : Thu Jun 20 17:21:23 2019
     13// Update Count     : 25
    1414//
     15
     16#define __cforall_thread__
    1517
    1618//C Includes
     
    2729
    2830//CFA Includes
    29 #include "time"
    30 #include "kernel_private.h"
    31 #include "preemption.h"
    32 #include "startup.h"
     31#include "time.hfa"
     32#include "kernel_private.hfa"
     33#include "preemption.hfa"
     34#include "startup.hfa"
    3335
    3436//Private includes
     
    3638#include "invoke.h"
    3739
     40//-----------------------------------------------------------------------------
     41// Some assembly required
     42#if   defined( __i386 )
     43        #define CtxGet( ctx )        \
     44                __asm__ volatile (     \
     45                        "movl %%esp,%0\n"\
     46                        "movl %%ebp,%1\n"\
     47                        : "=rm" (ctx.SP),\
     48                                "=rm" (ctx.FP) \
     49                )
     50
     51        // mxcr : SSE Status and Control bits (control bits are preserved across function calls)
     52        // fcw  : X87 FPU control word (preserved across function calls)
     53        #define __x87_store         \
     54                uint32_t __mxcr;      \
     55                uint16_t __fcw;       \
     56                __asm__ volatile (    \
     57                        "stmxcsr %0\n"  \
     58                        "fnstcw  %1\n"  \
     59                        : "=m" (__mxcr),\
     60                                "=m" (__fcw)  \
     61                )
     62
     63        #define __x87_load         \
     64                __asm__ volatile (   \
     65                        "fldcw  %1\n"  \
     66                        "ldmxcsr %0\n" \
     67                        ::"m" (__mxcr),\
     68                                "m" (__fcw)  \
     69                )
     70
     71#elif defined( __x86_64 )
     72        #define CtxGet( ctx )        \
     73                __asm__ volatile (     \
     74                        "movq %%rsp,%0\n"\
     75                        "movq %%rbp,%1\n"\
     76                        : "=rm" (ctx.SP),\
     77                                "=rm" (ctx.FP) \
     78                )
     79
     80        #define __x87_store         \
     81                uint32_t __mxcr;      \
     82                uint16_t __fcw;       \
     83                __asm__ volatile (    \
     84                        "stmxcsr %0\n"  \
     85                        "fnstcw  %1\n"  \
     86                        : "=m" (__mxcr),\
     87                                "=m" (__fcw)  \
     88                )
     89
     90        #define __x87_load          \
     91                __asm__ volatile (    \
     92                        "fldcw  %1\n"   \
     93                        "ldmxcsr %0\n"  \
     94                        :: "m" (__mxcr),\
     95                                "m" (__fcw)  \
     96                )
     97
     98
     99#elif defined( __ARM_ARCH )
     100#define CtxGet( ctx ) __asm__ ( \
     101                "mov %0,%%sp\n"   \
     102                "mov %1,%%r11\n"   \
     103        : "=rm" (ctx.SP), "=rm" (ctx.FP) )
     104#else
     105        #error unknown hardware architecture
     106#endif
     107
     108//-----------------------------------------------------------------------------
    38109//Start and stop routine for the kernel, declared first to make sure they run first
    39 void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
    40 void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
     110static void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
     111static void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
    41112
    42113//-----------------------------------------------------------------------------
    43114// Kernel storage
    44 KERNEL_STORAGE(cluster,           mainCluster);
    45 KERNEL_STORAGE(processor,         mainProcessor);
    46 KERNEL_STORAGE(thread_desc,       mainThread);
    47 KERNEL_STORAGE(machine_context_t, mainThreadCtx);
     115KERNEL_STORAGE(cluster,         mainCluster);
     116KERNEL_STORAGE(processor,       mainProcessor);
     117KERNEL_STORAGE(thread_desc,     mainThread);
     118KERNEL_STORAGE(__stack_t,       mainThreadCtx);
    48119
    49120cluster     * mainCluster;
     
    55126}
    56127
     128size_t __page_size = 0;
     129
    57130//-----------------------------------------------------------------------------
    58131// Global state
    59 thread_local struct KernelThreadData kernelTLS = {
    60         NULL,
     132thread_local struct KernelThreadData kernelTLS __attribute__ ((tls_model ( "initial-exec" ))) = {
    61133        NULL,
    62134        NULL,
     
    67139// Struct to steal stack
    68140struct current_stack_info_t {
    69         machine_context_t ctx;
    70         unsigned int size;              // size of stack
     141        __stack_t * storage;            // pointer to stack object
    71142        void *base;                             // base of stack
    72         void *storage;                  // pointer to stack
    73143        void *limit;                    // stack grows towards stack limit
    74144        void *context;                  // address of cfa_context_t
    75         void *top;                              // address of top of storage
    76145};
    77146
    78147void ?{}( current_stack_info_t & this ) {
    79         CtxGet( this.ctx );
    80         this.base = this.ctx.FP;
    81         this.storage = this.ctx.SP;
     148        __stack_context_t ctx;
     149        CtxGet( ctx );
     150        this.base = ctx.FP;
    82151
    83152        rlimit r;
    84153        getrlimit( RLIMIT_STACK, &r);
    85         this.size = r.rlim_cur;
    86 
    87         this.limit = (void *)(((intptr_t)this.base) - this.size);
     154        size_t size = r.rlim_cur;
     155
     156        this.limit = (void *)(((intptr_t)this.base) - size);
    88157        this.context = &storage_mainThreadCtx;
    89         this.top = this.base;
    90158}
    91159
    92160//-----------------------------------------------------------------------------
    93161// Main thread construction
    94 void ?{}( coStack_t & this, current_stack_info_t * info) with( this ) {
    95         size      = info->size;
    96         storage   = info->storage;
    97         limit     = info->limit;
    98         base      = info->base;
    99         context   = info->context;
    100         top       = info->top;
    101         userStack = true;
    102 }
    103162
    104163void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) {
    105         stack{ info };
     164        stack.storage = info->storage;
     165        with(*stack.storage) {
     166                limit     = info->limit;
     167                base      = info->base;
     168        }
     169        __attribute__((may_alias)) intptr_t * istorage = (intptr_t*) &stack.storage;
     170        *istorage |= 0x1;
    106171        name = "Main Thread";
    107         errno_ = 0;
    108172        state = Start;
    109173        starter = NULL;
     174        last = NULL;
     175        cancellation = NULL;
    110176}
    111177
    112178void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) {
     179        state = Start;
    113180        self_cor{ info };
    114181        curr_cor = &self_cor;
     
    133200
    134201// Construct the processor context of non-main processors
    135 void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {
     202static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {
    136203        (this.__cor){ info };
    137204        this.proc = proc;
    138205}
    139206
     207static void start(processor * this);
    140208void ?{}(processor & this, const char * name, cluster & cltr) with( this ) {
    141209        this.name = name;
     
    147215        runner.proc = &this;
    148216
    149         sem_init(&idleLock, 0, 0);
     217        idleLock{};
    150218
    151219        start( &this );
     
    155223        if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) {
    156224                __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);
    157                 terminate(&this);
    158                 verify( __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
    159                 verify( kernelTLS.this_processor != &this);
     225
     226                __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED);
     227                wake( &this );
     228
    160229                P( terminated );
    161230                verify( kernelTLS.this_processor != &this);
    162                 pthread_join( kernel_thread, NULL );
    163         }
    164 
    165         sem_destroy(&idleLock);
     231        }
     232
     233        pthread_join( kernel_thread, NULL );
    166234}
    167235
     
    186254// Kernel Scheduling logic
    187255//=============================================================================================
     256static void runThread(processor * this, thread_desc * dst);
     257static void finishRunning(processor * this);
     258static void halt(processor * this);
     259
    188260//Main of the processor contexts
    189261void main(processorCtx_t & runner) {
     
    236308}
    237309
     310static int * __volatile_errno() __attribute__((noinline));
     311static int * __volatile_errno() { asm(""); return &errno; }
     312
    238313// KERNEL ONLY
    239314// runThread runs a thread by context switching
    240315// from the processor coroutine to the target thread
    241 void runThread(processor * this, thread_desc * dst) {
    242         assert(dst->curr_cor);
     316static void runThread(processor * this, thread_desc * thrd_dst) {
    243317        coroutine_desc * proc_cor = get_coroutine(this->runner);
    244         coroutine_desc * thrd_cor = dst->curr_cor;
    245318
    246319        // Reset the terminating actions here
     
    248321
    249322        // Update global state
    250         kernelTLS.this_thread = dst;
    251 
    252         // Context Switch to the thread
    253         ThreadCtxSwitch(proc_cor, thrd_cor);
    254         // when ThreadCtxSwitch returns we are back in the processor coroutine
     323        kernelTLS.this_thread = thrd_dst;
     324
     325        // set state of processor coroutine to inactive and the thread to active
     326        proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
     327        thrd_dst->state = Active;
     328
     329        // set context switch to the thread that the processor is executing
     330        verify( thrd_dst->context.SP );
     331        CtxSwitch( &proc_cor->context, &thrd_dst->context );
     332        // when CtxSwitch returns we are back in the processor coroutine
     333
     334        // set state of processor coroutine to active and the thread to inactive
     335        thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive;
     336        proc_cor->state = Active;
    255337}
    256338
    257339// KERNEL_ONLY
    258 void returnToKernel() {
     340static void returnToKernel() {
    259341        coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
    260         coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine;
    261         ThreadCtxSwitch(thrd_cor, proc_cor);
     342        thread_desc * thrd_src = kernelTLS.this_thread;
     343
     344        // set state of current coroutine to inactive
     345        thrd_src->state = thrd_src->state == Halted ? Halted : Inactive;
     346        proc_cor->state = Active;
     347        int local_errno = *__volatile_errno();
     348        #if defined( __i386 ) || defined( __x86_64 )
     349                __x87_store;
     350        #endif
     351
     352        // set new coroutine that the processor is executing
     353        // and context switch to it
     354        verify( proc_cor->context.SP );
     355        CtxSwitch( &thrd_src->context, &proc_cor->context );
     356
     357        // set state of new coroutine to active
     358        proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
     359        thrd_src->state = Active;
     360
     361        #if defined( __i386 ) || defined( __x86_64 )
     362                __x87_load;
     363        #endif
     364        *__volatile_errno() = local_errno;
    262365}
    263366
     
    265368// Once a thread has finished running, some of
    266369// its final actions must be executed from the kernel
    267 void finishRunning(processor * this) with( this->finish ) {
     370static void finishRunning(processor * this) with( this->finish ) {
    268371        verify( ! kernelTLS.preemption_state.enabled );
    269372        choose( action_code ) {
     
    295398}
    296399
    297 // Handles spinning logic
    298 // TODO : find some strategy to put cores to sleep after some time
    299 void spin(processor * this, unsigned int * spin_count) {
    300         // (*spin_count)++;
    301         halt(this);
    302 }
    303 
    304400// KERNEL_ONLY
    305401// Context invoker for processors
    306402// This is the entry point for processors (kernel threads)
    307403// It effectively constructs a coroutine by stealing the pthread stack
    308 void * CtxInvokeProcessor(void * arg) {
     404static void * CtxInvokeProcessor(void * arg) {
    309405        processor * proc = (processor *) arg;
    310406        kernelTLS.this_processor = proc;
    311         kernelTLS.this_coroutine = NULL;
    312407        kernelTLS.this_thread    = NULL;
    313408        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
     
    316411        // to waste the perfectly valid stack create by pthread.
    317412        current_stack_info_t info;
    318         machine_context_t ctx;
    319         info.context = &ctx;
     413        __stack_t ctx;
     414        info.storage = &ctx;
    320415        (proc->runner){ proc, &info };
    321416
    322         __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.base);
     417        __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);
    323418
    324419        //Set global state
    325         kernelTLS.this_coroutine = get_coroutine(proc->runner);
    326420        kernelTLS.this_thread    = NULL;
    327421
     
    343437}
    344438
    345 void start(processor * this) {
     439static void start(processor * this) {
    346440        __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this);
    347441
     
    352446
    353447// KERNEL_ONLY
    354 void kernel_first_resume(processor * this) {
    355         coroutine_desc * src = kernelTLS.this_coroutine;
     448void kernel_first_resume( processor * this ) {
     449        thread_desc * src = mainThread;
    356450        coroutine_desc * dst = get_coroutine(this->runner);
    357451
    358452        verify( ! kernelTLS.preemption_state.enabled );
    359453
    360         create_stack(&dst->stack, dst->stack.size);
     454        __stack_prepare( &dst->stack, 65000 );
    361455        CtxStart(&this->runner, CtxInvokeCoroutine);
    362456
    363457        verify( ! kernelTLS.preemption_state.enabled );
    364458
    365         dst->last = src;
    366         dst->starter = dst->starter ? dst->starter : src;
     459        dst->last = &src->self_cor;
     460        dst->starter = dst->starter ? dst->starter : &src->self_cor;
    367461
    368462        // set state of current coroutine to inactive
    369463        src->state = src->state == Halted ? Halted : Inactive;
    370464
    371         // set new coroutine that task is executing
    372         kernelTLS.this_coroutine = dst;
    373 
    374         // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch.
    375         // Therefore, when first creating a coroutine, interrupts are enable before calling the main.
    376         // This is consistent with thread creation. However, when creating the main processor coroutine,
    377         // we wan't interrupts to be disabled. Therefore, we double-disable interrupts here so they will
    378         // stay disabled.
    379         disable_interrupts();
    380 
    381465        // context switch to specified coroutine
    382         assert( src->stack.context );
    383         CtxSwitch( src->stack.context, dst->stack.context );
     466        verify( dst->context.SP );
     467        CtxSwitch( &src->context, &dst->context );
    384468        // when CtxSwitch returns we are back in the src coroutine
    385469
     
    388472
    389473        verify( ! kernelTLS.preemption_state.enabled );
     474}
     475
     476// KERNEL_ONLY
     477void kernel_last_resume( processor * this ) {
     478        coroutine_desc * src = &mainThread->self_cor;
     479        coroutine_desc * dst = get_coroutine(this->runner);
     480
     481        verify( ! kernelTLS.preemption_state.enabled );
     482        verify( dst->starter == src );
     483        verify( dst->context.SP );
     484
     485        // context switch to the processor
     486        CtxSwitch( &src->context, &dst->context );
    390487}
    391488
     
    396493void ScheduleThread( thread_desc * thrd ) {
    397494        verify( thrd );
    398         verify( thrd->self_cor.state != Halted );
     495        verify( thrd->state != Halted );
    399496
    400497        verify( ! kernelTLS.preemption_state.enabled );
     
    408505                unlock( ready_queue_lock );
    409506
    410                 if( was_empty ) {
     507                if(was_empty) {
    411508                        lock      (proc_list_lock __cfaabi_dbg_ctx2);
    412509                        if(idles) {
    413                                 wake(idles.head);
     510                                wake_fast(idles.head);
    414511                        }
    415512                        unlock    (proc_list_lock);
    416513                }
     514                else if( struct processor * idle = idles.head ) {
     515                        wake_fast(idle);
     516                }
     517
    417518        }
    418519
     
    545646//-----------------------------------------------------------------------------
    546647// Kernel boot procedures
    547 void kernel_startup(void) {
     648static void kernel_startup(void) {
    548649        verify( ! kernelTLS.preemption_state.enabled );
    549650        __cfaabi_dbg_print_safe("Kernel : Starting\n");
     651
     652        __page_size = sysconf( _SC_PAGESIZE );
    550653
    551654        __cfa_dbg_global_clusters.list{ __get };
     
    563666        mainThread = (thread_desc *)&storage_mainThread;
    564667        current_stack_info_t info;
     668        info.storage = (__stack_t*)&storage_mainThreadCtx;
    565669        (*mainThread){ &info };
    566670
     
    597701        kernelTLS.this_processor = mainProcessor;
    598702        kernelTLS.this_thread    = mainThread;
    599         kernelTLS.this_coroutine = &mainThread->self_cor;
    600703
    601704        // Enable preemption
     
    621724}
    622725
    623 void kernel_shutdown(void) {
     726static void kernel_shutdown(void) {
    624727        __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
    625728
     
    632735        // which is currently here
    633736        __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);
    634         returnToKernel();
     737        kernel_last_resume( kernelTLS.this_processor );
    635738        mainThread->self_cor.state = Halted;
    636739
     
    658761// Kernel Quiescing
    659762//=============================================================================================
    660 
    661 void halt(processor * this) with( *this ) {
    662         verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
     763static void halt(processor * this) with( *this ) {
     764        // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
    663765
    664766        with( *cltr ) {
     
    671773        __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);
    672774
    673         // #ifdef __CFA_WITH_VERIFY__
    674         //      int sval = 0;
    675         //      sem_getvalue(&this->idleLock, &sval);
    676         //      verifyf(sval < 200, "Binary semaphore reached value %d : \n", sval);
    677         // #endif
    678 
    679         verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
    680         int __attribute__((unused)) ret = sem_wait(&idleLock);
    681         // verifyf(ret >= 0 || errno == EINTR, "Sem_wait returned %d (errno %d : %s\n", ret, errno, strerror(errno));
    682 
    683         // wait( idleLock );
     775        wait( idleLock );
    684776
    685777        __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);
     
    693785}
    694786
    695 void wake(processor * this) {
    696         __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this);
    697         int __attribute__((unused)) ret = sem_post(&this->idleLock);
    698         // verifyf(ret >= 0 || errno == EINTR, "Sem_post returned %d (errno %d : %s\n", ret, errno, strerror(errno));
    699 
    700         // #ifdef __CFA_WITH_VERIFY__
    701         //      int sval = 0;
    702         //      sem_getvalue(&this->idleLock, &sval);
    703         //      verifyf(sval < 200, "Binary semaphore reached value %d\n", sval);
    704         // #endif
    705 
    706         // post( this->idleLock );
    707 }
    708 
    709787//=============================================================================================
    710788// Unexpected Terminating logic
    711789//=============================================================================================
    712 
    713 
    714790static __spinlock_t kernel_abort_lock;
    715791static bool kernel_abort_called = false;
     
    745821                __cfaabi_dbg_bits_write( abort_text, len );
    746822
    747                 if ( get_coroutine(thrd) != kernelTLS.this_coroutine ) {
    748                         len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", kernelTLS.this_coroutine->name, kernelTLS.this_coroutine );
     823                if ( &thrd->self_cor != thrd->curr_cor ) {
     824                        len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor );
    749825                        __cfaabi_dbg_bits_write( abort_text, len );
    750826                }
     
    833909void doregister( cluster * cltr, thread_desc & thrd ) {
    834910        lock      (cltr->thread_list_lock __cfaabi_dbg_ctx2);
     911        cltr->nthreads += 1;
    835912        push_front(cltr->threads, thrd);
    836913        unlock    (cltr->thread_list_lock);
     
    840917        lock  (cltr->thread_list_lock __cfaabi_dbg_ctx2);
    841918        remove(cltr->threads, thrd );
     919        cltr->nthreads -= 1;
    842920        unlock(cltr->thread_list_lock);
    843921}
     
    845923void doregister( cluster * cltr, processor * proc ) {
    846924        lock      (cltr->proc_list_lock __cfaabi_dbg_ctx2);
     925        cltr->nprocessors += 1;
    847926        push_front(cltr->procs, *proc);
    848927        unlock    (cltr->proc_list_lock);
     
    852931        lock  (cltr->proc_list_lock __cfaabi_dbg_ctx2);
    853932        remove(cltr->procs, *proc );
     933        cltr->nprocessors -= 1;
    854934        unlock(cltr->proc_list_lock);
    855935}
     
    858938// Debug
    859939__cfaabi_dbg_debug_do(
    860         void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) {
    861                 this.prev_name = prev_name;
    862                 this.prev_thrd = kernelTLS.this_thread;
     940        extern "C" {
     941                void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) {
     942                        this.prev_name = prev_name;
     943                        this.prev_thrd = kernelTLS.this_thread;
     944                }
    863945        }
    864946)
     947
     948//-----------------------------------------------------------------------------
     949// Debug
     950bool threading_enabled(void) {
     951        return true;
     952}
    865953// Local Variables: //
    866954// mode: c //
Note: See TracChangeset for help on using the changeset viewer.