Ignore:
File:
1 edited

Legend:

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

    reafb094 r77e6fcb  
    99//
    1010// Author           : Thierry Delisle
    11 // Created On       : Tue Jan 17 12:27:26 2017
     11// Created On       : Tue Jan 17 12:27:26 2016
    1212// Last Modified By : Thierry Delisle
    1313// Last Modified On : --
     
    2020
    2121//Header
    22 #include "kernel_private.h"
     22#include "kernel"
    2323
    2424//C Includes
    2525#include <stddef.h>
    2626extern "C" {
    27 #include <fenv.h>
    2827#include <sys/resource.h>
    2928}
     
    3130//CFA Includes
    3231#include "libhdr.h"
     32#include "threads"
    3333
    3434//Private includes
     
    3838//-----------------------------------------------------------------------------
    3939// Kernel storage
     40struct processorCtx_t {
     41        processor * proc;
     42        coroutine c;
     43};
     44
     45DECL_COROUTINE(processorCtx_t);
     46
    4047#define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
    4148
     
    8592
    8693        rlimit r;
    87         getrlimit( RLIMIT_STACK, &r);
     94        int ret = getrlimit( RLIMIT_STACK, &r);
    8895        this->size = r.rlim_cur;
    8996
     
    107114        this->name = "Main Thread";
    108115        this->errno_ = 0;
    109         this->state = Start;
     116        this->state = Inactive;
     117        this->notHalted = true;
    110118}
    111119
     
    119127        (&this->c){};
    120128        this->proc = proc;
    121         proc->runner = this;
     129        proc->ctx = this;
    122130}
    123131
     
    125133        (&this->c){ info };
    126134        this->proc = proc;
    127         proc->runner = this;
    128 }
     135        proc->ctx = this;
     136}
     137
     138void start(processor * this);
    129139
    130140void ?{}(processor * this) {
     
    136146        this->current_coroutine = NULL;
    137147        this->current_thread = NULL;
    138         (&this->terminated){};
    139         this->is_terminated = false;
     148        (&this->lock){};
     149        this->terminated = false;
    140150
    141151        start( this );
    142152}
    143153
    144 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) {
     154void ?{}(processor * this, cluster * cltr, processorCtx_t * ctx) {
    145155        this->cltr = cltr;
    146156        this->current_coroutine = NULL;
    147157        this->current_thread = NULL;
    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 };
     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 };
    154164}
    155165
    156166void ^?{}(processor * this) {
    157         if( ! this->is_terminated ) {
     167        if( ! this->terminated ) {
    158168                LIB_DEBUG_PRINTF("Kernel : core %p signaling termination\n", this);
    159                 this->is_terminated = true;
    160                 wait( &this->terminated );
     169                this->terminated = true;
     170                lock( &this->lock );
    161171        }
    162172}
     
    164174void ?{}(cluster * this) {
    165175        ( &this->ready_queue ){};
    166         ( &this->lock ){};
     176        pthread_spin_init( &this->lock, PTHREAD_PROCESS_PRIVATE );
    167177}
    168178
    169179void ^?{}(cluster * this) {
    170        
    171 }
    172 
    173 //=============================================================================================
    174 // Kernel Scheduling logic
    175 //=============================================================================================
    176 //Main of the processor contexts
    177 void main(processorCtx_t * runner) {
    178         processor * this = runner->proc;
     180        pthread_spin_destroy( &this->lock );
     181}
     182
     183//-----------------------------------------------------------------------------
     184// Processor running routines
     185void main(processorCtx_t * ctx);
     186thread * nextThread(cluster * this);
     187void scheduleInternal(processor * this, thread * dst);
     188void spin(processor * this, unsigned int * spin_count);
     189
     190void main(processorCtx_t * ctx) {
     191        processor * this = ctx->proc;
    179192        LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this);
    180193
    181194        thread * readyThread = NULL;
    182         for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ )
    183         {
     195        for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) {
     196               
    184197                readyThread = nextThread( this->cltr );
    185198
    186                 if(readyThread)
    187                 {
    188                         runThread(this, readyThread);
    189 
    190                         //Some actions need to be taken from the kernel
    191                         finishRunning(this);
    192 
     199                if(readyThread) {
     200                        scheduleInternal(this, readyThread);
    193201                        spin_count = 0;
    194                 }
    195                 else
    196                 {
     202                } else {
    197203                        spin(this, &spin_count);
    198204                }               
     
    200206
    201207        LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this);
    202         signal( &this->terminated );
     208        unlock( &this->lock );
    203209        LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this);
    204210}
    205211
    206 // runThread runs a thread by context switching
     212//Declarations for scheduleInternal
     213extern void ThreadCtxSwitch(coroutine * src, coroutine * dst);
     214
     215// scheduleInternal runs a thread by context switching
    207216// from the processor coroutine to the target thread
    208 void 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
    225 void 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         }
     217void 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
    239242}
    240243
     
    259262        processorCtx_t proc_cor_storage = { proc, &info };
    260263
    261         LIB_DEBUG_PRINTF("Coroutine : created stack %p\n", proc_cor_storage.c.stack.base);
    262 
    263264        //Set global state
    264         proc->current_coroutine = &proc->runner->c;
     265        proc->current_coroutine = &proc->ctx->c;
    265266        proc->current_thread = NULL;
    266267
    267268        //We now have a proper context from which to schedule threads
    268         LIB_DEBUG_PRINTF("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx);
     269        LIB_DEBUG_PRINTF("Kernel : core %p created (%p)\n", proc, proc->ctx);
    269270
    270271        // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
     
    274275        proc_cor_storage.c.state = Active;
    275276      main( &proc_cor_storage );
    276       proc_cor_storage.c.state = Halted;
     277      proc_cor_storage.c.state = Halt;
     278      proc_cor_storage.c.notHalted = false;
    277279
    278280        // Main routine of the core returned, the core is now fully terminated
    279         LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc->runner);     
     281        LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc->ctx);       
    280282
    281283        return NULL;
     
    285287        LIB_DEBUG_PRINTF("Kernel : Starting core %p\n", this);
    286288       
    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 );
     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 );
    293295
    294296        LIB_DEBUG_PRINTF("Kernel : core %p started\n", this);   
     
    297299//-----------------------------------------------------------------------------
    298300// Scheduler routines
    299 void ScheduleThread( thread * thrd ) {
     301void thread_schedule( thread * thrd ) {
    300302        assertf( thrd->next == NULL, "Expected null got %p", thrd->next );
    301303       
    302         lock( &systemProcessor->cltr->lock );
     304        pthread_spinlock_guard guard = { &systemProcessor->cltr->lock };
    303305        append( &systemProcessor->cltr->ready_queue, thrd );
    304         unlock( &systemProcessor->cltr->lock );
    305306}
    306307
    307308thread * nextThread(cluster * this) {
    308         lock( &this->lock );
    309         thread * head = pop_head( &this->ready_queue );
    310         unlock( &this->lock );
    311         return head;
    312 }
    313 
    314 void ScheduleInternal() {
    315         suspend();
    316 }
    317 
    318 void ScheduleInternal( spinlock * lock ) {
    319         get_this_processor()->finish.action_code = Release;
    320         get_this_processor()->finish.lock = lock;
    321         suspend();
    322 }
    323 
    324 void ScheduleInternal( thread * thrd ) {
    325         get_this_processor()->finish.action_code = Schedule;
    326         get_this_processor()->finish.thrd = thrd;
    327         suspend();
    328 }
    329 
    330 void 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();
     309        pthread_spinlock_guard guard = { &this->lock };
     310        return pop_head( &this->ready_queue );
    335311}
    336312
     
    338314// Kernel boot procedures
    339315void kernel_startup(void) {
    340         LIB_DEBUG_PRINTF("Kernel : Starting\n");       
    341 
    342         // Start by initializing the main thread
     316
    343317        // SKULLDUGGERY: the mainThread steals the process main thread
    344318        // which will then be scheduled by the systemProcessor normally
     319        LIB_DEBUG_PRINTF("Kernel : Starting\n");       
     320
     321        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
    345331        mainThread = (thread *)&mainThread_storage;
    346         current_stack_info_t info;
    347332        mainThread{ &info };
    348333
     
    358343        // Add the main thread to the ready queue
    359344        // once resume is called on systemProcessor->ctx the mainThread needs to be scheduled like any normal thread
    360         ScheduleThread(mainThread);
     345        thread_schedule(mainThread);
    361346
    362347        //initialize the global state variables
     
    368353        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
    369354        // mainThread is on the ready queue when this call is made.
    370         resume(systemProcessor->runner);
     355        resume(systemProcessor->ctx);
    371356
    372357
    373358
    374359        // THE SYSTEM IS NOW COMPLETELY RUNNING
     360
     361
     362
    375363        LIB_DEBUG_PRINTF("Kernel : Started\n--------------------------------------------------\n\n");
    376364}
     
    382370        // When its coroutine terminates, it return control to the mainThread
    383371        // which is currently here
    384         systemProcessor->is_terminated = true;
     372        systemProcessor->terminated = true;
    385373        suspend();
    386374
     
    389377        // Destroy the system processor and its context in reverse order of construction
    390378        // These were manually constructed so we need manually destroy them
    391         ^(systemProcessor->runner){};
     379        ^(systemProcessor->ctx){};
    392380        ^(systemProcessor){};
    393381
     
    401389//-----------------------------------------------------------------------------
    402390// Locks
    403 void ?{}( spinlock * this ) {
    404         this->lock = 0;
    405 }
    406 void ^?{}( spinlock * this ) {
    407 
    408 }
    409 
    410 void 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;
     391void ?{}( simple_lock * this ) {
     392        ( &this->blocked ){};
     393}
     394
     395void ^?{}( simple_lock * this ) {
     396
     397}
     398
     399void lock( simple_lock * this ) {
     400        {
     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() );
    413403        }
    414 }
    415 
    416 void unlock( spinlock * this ) {
    417         __sync_lock_release_4( &this->lock );
    418 }
    419 
    420 void ?{}( signal_once * this ) {
    421         this->condition = false;
    422 }
    423 void ^?{}( signal_once * this ) {
    424 
    425 }
    426 
    427 void 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 );
     404        suspend();
     405}
     406
     407void unlock( simple_lock * this ) {
     408        thread * it;
     409        while( it = pop_head( &this->blocked) ) {
     410                thread_schedule( it );
    433411        }
    434         unlock( &this->lock );
    435 }
    436 
    437 void signal( signal_once * this ) {
    438         lock( &this->lock );
    439         {
    440                 this->condition = true;
    441 
    442                 thread * it;
    443                 while( it = pop_head( &this->blocked) ) {
    444                         ScheduleThread( it );
    445                 }
    446         }
    447         unlock( &this->lock );
    448412}
    449413
Note: See TracChangeset for help on using the changeset viewer.