Ignore:
File:
1 edited

Legend:

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

    r77e6fcb reafb094  
    99//
    1010// Author           : Thierry Delisle
    11 // Created On       : Tue Jan 17 12:27:26 2016
     11// Created On       : Tue Jan 17 12:27:26 2017
    1212// Last Modified By : Thierry Delisle
    1313// Last Modified On : --
     
    2020
    2121//Header
    22 #include "kernel"
     22#include "kernel_private.h"
    2323
    2424//C Includes
    2525#include <stddef.h>
    2626extern "C" {
     27#include <fenv.h>
    2728#include <sys/resource.h>
    2829}
     
    3031//CFA Includes
    3132#include "libhdr.h"
    32 #include "threads"
    3333
    3434//Private includes
     
    3838//-----------------------------------------------------------------------------
    3939// Kernel storage
    40 struct processorCtx_t {
    41         processor * proc;
    42         coroutine c;
    43 };
    44 
    45 DECL_COROUTINE(processorCtx_t);
    46 
    4740#define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
    4841
     
    9285
    9386        rlimit r;
    94         int ret = getrlimit( RLIMIT_STACK, &r);
     87        getrlimit( RLIMIT_STACK, &r);
    9588        this->size = r.rlim_cur;
    9689
     
    114107        this->name = "Main Thread";
    115108        this->errno_ = 0;
    116         this->state = Inactive;
    117         this->notHalted = true;
     109        this->state = Start;
    118110}
    119111
     
    127119        (&this->c){};
    128120        this->proc = proc;
    129         proc->ctx = this;
     121        proc->runner = this;
    130122}
    131123
     
    133125        (&this->c){ info };
    134126        this->proc = proc;
    135         proc->ctx = this;
    136 }
    137 
    138 void start(processor * this);
     127        proc->runner = this;
     128}
    139129
    140130void ?{}(processor * this) {
     
    146136        this->current_coroutine = NULL;
    147137        this->current_thread = NULL;
    148         (&this->lock){};
    149         this->terminated = false;
     138        (&this->terminated){};
     139        this->is_terminated = false;
    150140
    151141        start( this );
    152142}
    153143
    154 void ?{}(processor * this, cluster * cltr, processorCtx_t * ctx) {
     144void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) {
    155145        this->cltr = cltr;
    156146        this->current_coroutine = NULL;
    157147        this->current_thread = NULL;
    158         (&this->lock){};
    159         this->terminated = false;
    160 
    161         this->ctx = ctx;
    162         LIB_DEBUG_PRINTF("Kernel : constructing processor context %p\n", ctx);
    163         ctx{ this };
     148        (&this->terminated){};
     149        this->is_terminated = false;
     150
     151        this->runner = runner;
     152        LIB_DEBUG_PRINTF("Kernel : constructing processor context %p\n", runner);
     153        runner{ this };
    164154}
    165155
    166156void ^?{}(processor * this) {
    167         if( ! this->terminated ) {
     157        if( ! this->is_terminated ) {
    168158                LIB_DEBUG_PRINTF("Kernel : core %p signaling termination\n", this);
    169                 this->terminated = true;
    170                 lock( &this->lock );
     159                this->is_terminated = true;
     160                wait( &this->terminated );
    171161        }
    172162}
     
    174164void ?{}(cluster * this) {
    175165        ( &this->ready_queue ){};
    176         pthread_spin_init( &this->lock, PTHREAD_PROCESS_PRIVATE );
     166        ( &this->lock ){};
    177167}
    178168
    179169void ^?{}(cluster * this) {
    180         pthread_spin_destroy( &this->lock );
    181 }
    182 
    183 //-----------------------------------------------------------------------------
    184 // Processor running routines
    185 void main(processorCtx_t * ctx);
    186 thread * nextThread(cluster * this);
    187 void scheduleInternal(processor * this, thread * dst);
    188 void spin(processor * this, unsigned int * spin_count);
    189 
    190 void main(processorCtx_t * ctx) {
    191         processor * this = ctx->proc;
     170       
     171}
     172
     173//=============================================================================================
     174// Kernel Scheduling logic
     175//=============================================================================================
     176//Main of the processor contexts
     177void main(processorCtx_t * runner) {
     178        processor * this = runner->proc;
    192179        LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this);
    193180
    194181        thread * readyThread = NULL;
    195         for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) {
    196                
     182        for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ )
     183        {
    197184                readyThread = nextThread( this->cltr );
    198185
    199                 if(readyThread) {
    200                         scheduleInternal(this, readyThread);
     186                if(readyThread)
     187                {
     188                        runThread(this, readyThread);
     189
     190                        //Some actions need to be taken from the kernel
     191                        finishRunning(this);
     192
    201193                        spin_count = 0;
    202                 } else {
     194                }
     195                else
     196                {
    203197                        spin(this, &spin_count);
    204198                }               
     
    206200
    207201        LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this);
    208         unlock( &this->lock );
     202        signal( &this->terminated );
    209203        LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this);
    210204}
    211205
    212 //Declarations for scheduleInternal
    213 extern void ThreadCtxSwitch(coroutine * src, coroutine * dst);
    214 
    215 // scheduleInternal runs a thread by context switching
     206// runThread runs a thread by context switching
    216207// from the processor coroutine to the target thread
    217 void scheduleInternal(processor * this, thread * dst) {
    218         // coroutine * proc_ctx = get_coroutine(this->ctx);
    219         // coroutine * thrd_ctx = get_coroutine(dst);
    220 
    221         // //Update global state
    222         // this->current_thread = dst;
    223 
    224         // // Context Switch to the thread
    225         // ThreadCtxSwitch(proc_ctx, thrd_ctx);
    226         // // when ThreadCtxSwitch returns we are back in the processor coroutine
    227 
    228         coroutine * proc_ctx = get_coroutine(this->ctx);
    229         coroutine * thrd_ctx = get_coroutine(dst);
    230       thrd_ctx->last = proc_ctx;
    231  
    232       // context switch to specified coroutine
    233       // Which is now the current_coroutine
    234       LIB_DEBUG_PRINTF("Kernel : switching to ctx %p (from %p, current %p)\n", thrd_ctx, proc_ctx, this->current_coroutine);
    235       this->current_thread = dst;
    236       this->current_coroutine = thrd_ctx;
    237       CtxSwitch( proc_ctx->stack.context, thrd_ctx->stack.context );
    238       this->current_coroutine = proc_ctx;
    239       LIB_DEBUG_PRINTF("Kernel : returned from ctx %p (to %p, current %p)\n", thrd_ctx, proc_ctx, this->current_coroutine);
    240  
    241       // when CtxSwitch returns we are back in the processor coroutine
     208void runThread(processor * this, thread * dst) {
     209        coroutine * proc_cor = get_coroutine(this->runner);
     210        coroutine * thrd_cor = get_coroutine(dst);
     211       
     212        //Reset the terminating actions here
     213        this->finish.action_code = No_Action;
     214
     215        //Update global state
     216        this->current_thread = dst;
     217
     218        // Context Switch to the thread
     219        ThreadCtxSwitch(proc_cor, thrd_cor);
     220        // when ThreadCtxSwitch returns we are back in the processor coroutine
     221}
     222
     223// Once a thread has finished running, some of
     224// its final actions must be executed from the kernel
     225void finishRunning(processor * this) {
     226        if( this->finish.action_code == Release ) {
     227                unlock( this->finish.lock );
     228        }
     229        else if( this->finish.action_code == Schedule ) {
     230                ScheduleThread( this->finish.thrd );
     231        }
     232        else if( this->finish.action_code == Release_Schedule ) {
     233                unlock( this->finish.lock );           
     234                ScheduleThread( this->finish.thrd );
     235        }
     236        else {
     237                assert(this->finish.action_code == No_Action);
     238        }
    242239}
    243240
     
    262259        processorCtx_t proc_cor_storage = { proc, &info };
    263260
     261        LIB_DEBUG_PRINTF("Coroutine : created stack %p\n", proc_cor_storage.c.stack.base);
     262
    264263        //Set global state
    265         proc->current_coroutine = &proc->ctx->c;
     264        proc->current_coroutine = &proc->runner->c;
    266265        proc->current_thread = NULL;
    267266
    268267        //We now have a proper context from which to schedule threads
    269         LIB_DEBUG_PRINTF("Kernel : core %p created (%p)\n", proc, proc->ctx);
     268        LIB_DEBUG_PRINTF("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx);
    270269
    271270        // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
     
    275274        proc_cor_storage.c.state = Active;
    276275      main( &proc_cor_storage );
    277       proc_cor_storage.c.state = Halt;
    278       proc_cor_storage.c.notHalted = false;
     276      proc_cor_storage.c.state = Halted;
    279277
    280278        // Main routine of the core returned, the core is now fully terminated
    281         LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc->ctx);       
     279        LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc->runner);     
    282280
    283281        return NULL;
     
    287285        LIB_DEBUG_PRINTF("Kernel : Starting core %p\n", this);
    288286       
    289         pthread_attr_t attributes;
    290         pthread_attr_init( &attributes );
    291 
    292         pthread_create( &this->kernel_thread, &attributes, CtxInvokeProcessor, (void*)this );
    293 
    294         pthread_attr_destroy( &attributes );
     287        // pthread_attr_t attributes;
     288        // pthread_attr_init( &attributes );
     289
     290        pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this );
     291
     292        // pthread_attr_destroy( &attributes );
    295293
    296294        LIB_DEBUG_PRINTF("Kernel : core %p started\n", this);   
     
    299297//-----------------------------------------------------------------------------
    300298// Scheduler routines
    301 void thread_schedule( thread * thrd ) {
     299void ScheduleThread( thread * thrd ) {
    302300        assertf( thrd->next == NULL, "Expected null got %p", thrd->next );
    303301       
    304         pthread_spinlock_guard guard = { &systemProcessor->cltr->lock };
     302        lock( &systemProcessor->cltr->lock );
    305303        append( &systemProcessor->cltr->ready_queue, thrd );
     304        unlock( &systemProcessor->cltr->lock );
    306305}
    307306
    308307thread * nextThread(cluster * this) {
    309         pthread_spinlock_guard guard = { &this->lock };
    310         return pop_head( &this->ready_queue );
     308        lock( &this->lock );
     309        thread * head = pop_head( &this->ready_queue );
     310        unlock( &this->lock );
     311        return head;
     312}
     313
     314void ScheduleInternal() {
     315        suspend();
     316}
     317
     318void ScheduleInternal( spinlock * lock ) {
     319        get_this_processor()->finish.action_code = Release;
     320        get_this_processor()->finish.lock = lock;
     321        suspend();
     322}
     323
     324void ScheduleInternal( thread * thrd ) {
     325        get_this_processor()->finish.action_code = Schedule;
     326        get_this_processor()->finish.thrd = thrd;
     327        suspend();
     328}
     329
     330void ScheduleInternal( spinlock * lock, thread * thrd ) {
     331        get_this_processor()->finish.action_code = Release_Schedule;
     332        get_this_processor()->finish.lock = lock;
     333        get_this_processor()->finish.thrd = thrd;
     334        suspend();
    311335}
    312336
     
    314338// Kernel boot procedures
    315339void kernel_startup(void) {
    316 
     340        LIB_DEBUG_PRINTF("Kernel : Starting\n");       
     341
     342        // Start by initializing the main thread
    317343        // SKULLDUGGERY: the mainThread steals the process main thread
    318344        // which will then be scheduled by the systemProcessor normally
    319         LIB_DEBUG_PRINTF("Kernel : Starting\n");       
    320 
     345        mainThread = (thread *)&mainThread_storage;
    321346        current_stack_info_t info;
    322 
    323         // LIB_DEBUG_PRINTF("Kernel : core    base : %p \n", info.base );
    324         // LIB_DEBUG_PRINTF("Kernel : core storage : %p \n", info.storage );
    325         // LIB_DEBUG_PRINTF("Kernel : core    size : %x \n", info.size );
    326         // LIB_DEBUG_PRINTF("Kernel : core   limit : %p \n", info.limit );
    327         // LIB_DEBUG_PRINTF("Kernel : core context : %p \n", info.context );
    328         // LIB_DEBUG_PRINTF("Kernel : core     top : %p \n", info.top );
    329 
    330         // Start by initializing the main thread
    331         mainThread = (thread *)&mainThread_storage;
    332347        mainThread{ &info };
    333348
     
    343358        // Add the main thread to the ready queue
    344359        // once resume is called on systemProcessor->ctx the mainThread needs to be scheduled like any normal thread
    345         thread_schedule(mainThread);
     360        ScheduleThread(mainThread);
    346361
    347362        //initialize the global state variables
     
    353368        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
    354369        // mainThread is on the ready queue when this call is made.
    355         resume(systemProcessor->ctx);
     370        resume(systemProcessor->runner);
    356371
    357372
    358373
    359374        // THE SYSTEM IS NOW COMPLETELY RUNNING
    360 
    361 
    362 
    363375        LIB_DEBUG_PRINTF("Kernel : Started\n--------------------------------------------------\n\n");
    364376}
     
    370382        // When its coroutine terminates, it return control to the mainThread
    371383        // which is currently here
    372         systemProcessor->terminated = true;
     384        systemProcessor->is_terminated = true;
    373385        suspend();
    374386
     
    377389        // Destroy the system processor and its context in reverse order of construction
    378390        // These were manually constructed so we need manually destroy them
    379         ^(systemProcessor->ctx){};
     391        ^(systemProcessor->runner){};
    380392        ^(systemProcessor){};
    381393
     
    389401//-----------------------------------------------------------------------------
    390402// Locks
    391 void ?{}( simple_lock * this ) {
    392         ( &this->blocked ){};
    393 }
    394 
    395 void ^?{}( simple_lock * this ) {
    396 
    397 }
    398 
    399 void lock( simple_lock * this ) {
     403void ?{}( spinlock * this ) {
     404        this->lock = 0;
     405}
     406void ^?{}( spinlock * this ) {
     407
     408}
     409
     410void lock( spinlock * this ) {
     411        for ( unsigned int i = 1;; i += 1 ) {
     412                if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break;
     413        }
     414}
     415
     416void unlock( spinlock * this ) {
     417        __sync_lock_release_4( &this->lock );
     418}
     419
     420void ?{}( signal_once * this ) {
     421        this->condition = false;
     422}
     423void ^?{}( signal_once * this ) {
     424
     425}
     426
     427void wait( signal_once * this ) {
     428        lock( &this->lock );
     429        if( !this->condition ) {
     430                append( &this->blocked, this_thread() );
     431                ScheduleInternal( &this->lock );
     432                lock( &this->lock );
     433        }
     434        unlock( &this->lock );
     435}
     436
     437void signal( signal_once * this ) {
     438        lock( &this->lock );
    400439        {
    401                 pthread_spinlock_guard guard = { &systemCluster->lock };        //HUGE TEMP HACK which only works if we have a single cluster and is stupid
    402                 append( &this->blocked, this_thread() );
    403         }
    404         suspend();
    405 }
    406 
    407 void unlock( simple_lock * this ) {
    408         thread * it;
    409         while( it = pop_head( &this->blocked) ) {
    410                 thread_schedule( it );
    411         }
     440                this->condition = true;
     441
     442                thread * it;
     443                while( it = pop_head( &this->blocked) ) {
     444                        ScheduleThread( it );
     445                }
     446        }
     447        unlock( &this->lock );
    412448}
    413449
Note: See TracChangeset for help on using the changeset viewer.