Ignore:
File:
1 edited

Legend:

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

    rd6ff3ff r4aa2fb2  
    1515//
    1616
    17 #include "libhdr.h"
     17#include "startup.h"
     18
     19//Start and stop routine for the kernel, declared first to make sure they run first
     20void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
     21void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
     22
     23//Header
     24#include "kernel_private.h"
    1825
    1926//C Includes
     
    2835
    2936//CFA Includes
    30 #include "kernel_private.h"
     37#include "libhdr.h"
    3138#include "preemption.h"
    32 #include "startup.h"
    3339
    3440//Private includes
     
    3642#include "invoke.h"
    3743
    38 //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 ) ));
    41 
    4244//-----------------------------------------------------------------------------
    4345// Kernel storage
    44 #define KERNEL_STORAGE(T,X) static char X##Storage[sizeof(T)]
     46#define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
    4547
    4648KERNEL_STORAGE(processorCtx_t, systemProcessorCtx);
     
    4850KERNEL_STORAGE(system_proc_t, systemProcessor);
    4951KERNEL_STORAGE(thread_desc, mainThread);
    50 KERNEL_STORAGE(machine_context_t, mainThreadCtx);
     52KERNEL_STORAGE(machine_context_t, mainThread_context);
    5153
    5254cluster * systemCluster;
     
    5759// Global state
    5860
    59 volatile thread_local processor * this_processor;
    60 volatile thread_local coroutine_desc * this_coroutine;
    61 volatile thread_local thread_desc * this_thread;
    62 volatile thread_local bool preemption_in_progress = 0;
    63 volatile thread_local unsigned short disable_preempt_count = 1;
     61thread_local processor * this_processor;
     62
     63coroutine_desc * this_coroutine(void) {
     64        return this_processor->current_coroutine;
     65}
     66
     67thread_desc * this_thread(void) {
     68        return this_processor->current_thread;
     69}
    6470
    6571//-----------------------------------------------------------------------------
    6672// Main thread construction
    6773struct current_stack_info_t {
    68         machine_context_t ctx;
     74        machine_context_t ctx; 
    6975        unsigned int size;              // size of stack
    7076        void *base;                             // base of stack
     
    7682
    7783void ?{}( current_stack_info_t * this ) {
    78         CtxGet( this->ctx );
     84        CtxGet( &this->ctx );
    7985        this->base = this->ctx.FP;
    8086        this->storage = this->ctx.SP;
     
    8591
    8692        this->limit = (void *)(((intptr_t)this->base) - this->size);
    87         this->context = &mainThreadCtxStorage;
     93        this->context = &mainThread_context_storage;
    8894        this->top = this->base;
    8995}
     
    100106
    101107void ?{}( coroutine_desc * this, current_stack_info_t * info) {
    102         (&this->stack){ info };
     108        (&this->stack){ info }; 
    103109        this->name = "Main Thread";
    104110        this->errno_ = 0;
     
    130136void ?{}(processor * this, cluster * cltr) {
    131137        this->cltr = cltr;
    132         (&this->terminated){ 0 };
     138        this->current_coroutine = NULL;
     139        this->current_thread = NULL;
     140        (&this->terminated){};
    133141        this->is_terminated = false;
    134142        this->preemption_alarm = NULL;
    135143        this->preemption = default_preemption();
     144        this->disable_preempt_count = 1;                //Start with interrupts disabled
    136145        this->pending_preemption = false;
    137146
     
    141150void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) {
    142151        this->cltr = cltr;
    143         (&this->terminated){ 0 };
     152        this->current_coroutine = NULL;
     153        this->current_thread = NULL;
     154        (&this->terminated){};
    144155        this->is_terminated = false;
    145         this->preemption_alarm = NULL;
    146         this->preemption = default_preemption();
     156        this->disable_preempt_count = 0;
    147157        this->pending_preemption = false;
    148         this->kernel_thread = pthread_self();
    149158
    150159        this->runner = runner;
    151         LIB_DEBUG_PRINT_SAFE("Kernel : constructing system processor context %p\n", runner);
     160        LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner);
    152161        runner{ this };
    153162}
    154 
    155 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )
    156163
    157164void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) {
     
    161168
    162169        (&this->proc){ cltr, runner };
    163 
    164         verify( validate( &this->alarms ) );
    165170}
    166171
     
    169174                LIB_DEBUG_PRINT_SAFE("Kernel : core %p signaling termination\n", this);
    170175                this->is_terminated = true;
    171                 P( &this->terminated );
    172                 pthread_join( this->kernel_thread, NULL );
     176                wait( &this->terminated );
    173177        }
    174178}
     
    180184
    181185void ^?{}(cluster * this) {
    182 
     186       
    183187}
    184188
     
    199203
    200204                thread_desc * readyThread = NULL;
    201                 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ )
     205                for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 
    202206                {
    203207                        readyThread = nextThread( this->cltr );
     
    205209                        if(readyThread)
    206210                        {
    207                                 verify( disable_preempt_count > 0 );
    208 
    209211                                runThread(this, readyThread);
    210 
    211                                 verify( disable_preempt_count > 0 );
    212212
    213213                                //Some actions need to be taken from the kernel
     
    225225        }
    226226
    227         V( &this->terminated );
    228 
     227        signal( &this->terminated );
    229228        LIB_DEBUG_PRINT_SAFE("Kernel : core %p terminated\n", this);
    230229}
    231230
    232 // runThread runs a thread by context switching
    233 // from the processor coroutine to the target thread
     231// runThread runs a thread by context switching 
     232// from the processor coroutine to the target thread 
    234233void runThread(processor * this, thread_desc * dst) {
    235234        coroutine_desc * proc_cor = get_coroutine(this->runner);
    236235        coroutine_desc * thrd_cor = get_coroutine(dst);
    237 
     236       
    238237        //Reset the terminating actions here
    239238        this->finish.action_code = No_Action;
    240239
    241240        //Update global state
    242         this_thread = dst;
     241        this->current_thread = dst;
    243242
    244243        // Context Switch to the thread
     
    247246}
    248247
    249 // Once a thread has finished running, some of
     248// Once a thread has finished running, some of 
    250249// its final actions must be executed from the kernel
    251250void finishRunning(processor * this) {
     
    257256        }
    258257        else if( this->finish.action_code == Release_Schedule ) {
    259                 unlock( this->finish.lock );
     258                unlock( this->finish.lock );           
    260259                ScheduleThread( this->finish.thrd );
    261260        }
     
    290289        processor * proc = (processor *) arg;
    291290        this_processor = proc;
    292         this_coroutine = NULL;
    293         this_thread = NULL;
    294         disable_preempt_count = 1;
    295291        // SKULLDUGGERY: We want to create a context for the processor coroutine
    296292        // which is needed for the 2-step context switch. However, there is no reason
    297         // to waste the perfectly valid stack create by pthread.
     293        // to waste the perfectly valid stack create by pthread. 
    298294        current_stack_info_t info;
    299295        machine_context_t ctx;
     
    304300
    305301        //Set global state
    306         this_coroutine = &proc->runner->__cor;
    307         this_thread = NULL;
     302        proc->current_coroutine = &proc->runner->__cor;
     303        proc->current_thread = NULL;
    308304
    309305        //We now have a proper context from which to schedule threads
    310306        LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx);
    311307
    312         // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
    313         // resume it to start it like it normally would, it will just context switch
    314         // back to here. Instead directly call the main since we already are on the
     308        // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't 
     309        // resume it to start it like it normally would, it will just context switch 
     310        // back to here. Instead directly call the main since we already are on the 
    315311        // appropriate stack.
    316312        proc_cor_storage.__cor.state = Active;
     
    319315
    320316        // Main routine of the core returned, the core is now fully terminated
    321         LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner);
     317        LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 
    322318
    323319        return NULL;
     
    326322void start(processor * this) {
    327323        LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this);
    328 
     324       
    329325        pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this );
    330326
    331         LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this);
     327        LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this);       
    332328}
    333329
     
    335331// Scheduler routines
    336332void ScheduleThread( thread_desc * thrd ) {
    337         // if( !thrd ) return;
    338         assert( thrd );
    339         assert( thrd->cor.state != Halted );
    340 
    341         verify( disable_preempt_count > 0 );
     333        if( !thrd ) return;
    342334
    343335        verifyf( thrd->next == NULL, "Expected null got %p", thrd->next );
    344 
    345         lock( &systemProcessor->proc.cltr->lock DEBUG_CTX2 );
     336       
     337        lock( &systemProcessor->proc.cltr->lock );
    346338        append( &systemProcessor->proc.cltr->ready_queue, thrd );
    347339        unlock( &systemProcessor->proc.cltr->lock );
    348 
    349         verify( disable_preempt_count > 0 );
    350340}
    351341
    352342thread_desc * nextThread(cluster * this) {
    353         verify( disable_preempt_count > 0 );
    354         lock( &this->lock DEBUG_CTX2 );
     343        lock( &this->lock );
    355344        thread_desc * head = pop_head( &this->ready_queue );
    356345        unlock( &this->lock );
    357         verify( disable_preempt_count > 0 );
    358346        return head;
    359347}
    360348
    361 void BlockInternal() {
    362         disable_interrupts();
    363         verify( disable_preempt_count > 0 );
     349void ScheduleInternal() {
    364350        suspend();
    365         verify( disable_preempt_count > 0 );
    366         enable_interrupts( DEBUG_CTX );
    367 }
    368 
    369 void BlockInternal( spinlock * lock ) {
    370         disable_interrupts();
     351}
     352
     353void ScheduleInternal( spinlock * lock ) {
    371354        this_processor->finish.action_code = Release;
    372355        this_processor->finish.lock = lock;
    373 
    374         verify( disable_preempt_count > 0 );
    375356        suspend();
    376         verify( disable_preempt_count > 0 );
    377 
    378         enable_interrupts( DEBUG_CTX );
    379 }
    380 
    381 void BlockInternal( thread_desc * thrd ) {
    382         disable_interrupts();
    383         assert( thrd->cor.state != Halted );
     357}
     358
     359void ScheduleInternal( thread_desc * thrd ) {
    384360        this_processor->finish.action_code = Schedule;
    385361        this_processor->finish.thrd = thrd;
    386 
    387         verify( disable_preempt_count > 0 );
    388362        suspend();
    389         verify( disable_preempt_count > 0 );
    390 
    391         enable_interrupts( DEBUG_CTX );
    392 }
    393 
    394 void BlockInternal( spinlock * lock, thread_desc * thrd ) {
    395         disable_interrupts();
     363}
     364
     365void ScheduleInternal( spinlock * lock, thread_desc * thrd ) {
    396366        this_processor->finish.action_code = Release_Schedule;
    397367        this_processor->finish.lock = lock;
    398368        this_processor->finish.thrd = thrd;
    399 
    400         verify( disable_preempt_count > 0 );
    401369        suspend();
    402         verify( disable_preempt_count > 0 );
    403 
    404         enable_interrupts( DEBUG_CTX );
    405 }
    406 
    407 void BlockInternal(spinlock ** locks, unsigned short count) {
    408         disable_interrupts();
     370}
     371
     372void ScheduleInternal(spinlock ** locks, unsigned short count) {
    409373        this_processor->finish.action_code = Release_Multi;
    410374        this_processor->finish.locks = locks;
    411375        this_processor->finish.lock_count = count;
    412 
    413         verify( disable_preempt_count > 0 );
    414376        suspend();
    415         verify( disable_preempt_count > 0 );
    416 
    417         enable_interrupts( DEBUG_CTX );
    418 }
    419 
    420 void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) {
    421         disable_interrupts();
     377}
     378
     379void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) {
    422380        this_processor->finish.action_code = Release_Multi_Schedule;
    423381        this_processor->finish.locks = locks;
     
    425383        this_processor->finish.thrds = thrds;
    426384        this_processor->finish.thrd_count = thrd_count;
    427 
    428         verify( disable_preempt_count > 0 );
    429         suspend();
    430         verify( disable_preempt_count > 0 );
    431 
    432         enable_interrupts( DEBUG_CTX );
    433 }
    434 
    435 void LeaveThread(spinlock * lock, thread_desc * thrd) {
    436         verify( disable_preempt_count > 0 );
    437         this_processor->finish.action_code = thrd ? Release_Schedule : Release;
    438         this_processor->finish.lock = lock;
    439         this_processor->finish.thrd = thrd;
    440 
    441385        suspend();
    442386}
     
    448392// Kernel boot procedures
    449393void kernel_startup(void) {
    450         LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n");
     394        LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n");   
    451395
    452396        // Start by initializing the main thread
    453         // SKULLDUGGERY: the mainThread steals the process main thread
     397        // SKULLDUGGERY: the mainThread steals the process main thread 
    454398        // which will then be scheduled by the systemProcessor normally
    455         mainThread = (thread_desc *)&mainThreadStorage;
     399        mainThread = (thread_desc *)&mainThread_storage;
    456400        current_stack_info_t info;
    457401        mainThread{ &info };
     
    459403        LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n");
    460404
     405        // Enable preemption
     406        kernel_start_preemption();
     407
    461408        // Initialize the system cluster
    462         systemCluster = (cluster *)&systemClusterStorage;
     409        systemCluster = (cluster *)&systemCluster_storage;
    463410        systemCluster{};
    464411
     
    467414        // Initialize the system processor and the system processor ctx
    468415        // (the coroutine that contains the processing control flow)
    469         systemProcessor = (system_proc_t *)&systemProcessorStorage;
    470         systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtxStorage };
    471 
    472         // Add the main thread to the ready queue
     416        systemProcessor = (system_proc_t *)&systemProcessor_storage;
     417        systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage };
     418
     419        // Add the main thread to the ready queue 
    473420        // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread
    474421        ScheduleThread(mainThread);
     
    476423        //initialize the global state variables
    477424        this_processor = &systemProcessor->proc;
    478         this_thread = mainThread;
    479         this_coroutine = &mainThread->cor;
    480         disable_preempt_count = 1;
    481 
    482         // Enable preemption
    483         kernel_start_preemption();
     425        this_processor->current_thread = mainThread;
     426        this_processor->current_coroutine = &mainThread->cor;
    484427
    485428        // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX
    486429        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
    487         // mainThread is on the ready queue when this call is made.
     430        // mainThread is on the ready queue when this call is made. 
    488431        resume( systemProcessor->proc.runner );
    489432
     
    492435        // THE SYSTEM IS NOW COMPLETELY RUNNING
    493436        LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n");
    494 
    495         enable_interrupts( DEBUG_CTX );
    496437}
    497438
    498439void kernel_shutdown(void) {
    499440        LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n");
    500 
    501         disable_interrupts();
    502441
    503442        // SKULLDUGGERY: Notify the systemProcessor it needs to terminates.
     
    509448        // THE SYSTEM IS NOW COMPLETELY STOPPED
    510449
    511         // Disable preemption
    512         kernel_stop_preemption();
    513 
    514450        // Destroy the system processor and its context in reverse order of construction
    515451        // These were manually constructed so we need manually destroy them
     
    521457        ^(mainThread){};
    522458
    523         LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n");
     459        LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n");   
    524460}
    525461
     
    531467        // abort cannot be recursively entered by the same or different processors because all signal handlers return when
    532468        // the globalAbort flag is true.
    533         lock( &kernel_abort_lock DEBUG_CTX2 );
     469        lock( &kernel_abort_lock );
    534470
    535471        // first task to abort ?
     
    537473                kernel_abort_called = true;
    538474                unlock( &kernel_abort_lock );
    539         }
     475        } 
    540476        else {
    541477                unlock( &kernel_abort_lock );
    542 
     478               
    543479                sigset_t mask;
    544480                sigemptyset( &mask );
     
    546482                sigaddset( &mask, SIGUSR1 );                    // block SIGUSR1 signals
    547483                sigsuspend( &mask );                            // block the processor to prevent further damage during abort
    548                 _exit( EXIT_FAILURE );                          // if processor unblocks before it is killed, terminate it
    549         }
    550 
    551         return this_thread;
     484                _exit( EXIT_FAILURE );                          // if processor unblocks before it is killed, terminate it             
     485        }
     486
     487        return this_thread();
    552488}
    553489
     
    558494        __lib_debug_write( STDERR_FILENO, abort_text, len );
    559495
    560         if ( thrd != this_coroutine ) {
    561                 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine->name, this_coroutine );
     496        if ( thrd != this_coroutine() ) {
     497                len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine()->name, this_coroutine() );
    562498                __lib_debug_write( STDERR_FILENO, abort_text, len );
    563         }
     499        } 
    564500        else {
    565501                __lib_debug_write( STDERR_FILENO, ".\n", 2 );
     
    569505extern "C" {
    570506        void __lib_debug_acquire() {
    571                 lock( &kernel_debug_lock DEBUG_CTX2 );
     507                lock(&kernel_debug_lock);
    572508        }
    573509
    574510        void __lib_debug_release() {
    575                 unlock( &kernel_debug_lock );
     511                unlock(&kernel_debug_lock);
    576512        }
    577513}
     
    589525}
    590526
    591 bool try_lock( spinlock * this DEBUG_CTX_PARAM2 ) {
     527bool try_lock( spinlock * this ) {
    592528        return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0;
    593529}
    594530
    595 void lock( spinlock * this DEBUG_CTX_PARAM2 ) {
     531void lock( spinlock * this ) {
    596532        for ( unsigned int i = 1;; i += 1 ) {
    597                 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; }
    598         }
    599         LIB_DEBUG_DO(
    600                 this->prev_name = caller;
    601                 this->prev_thrd = this_thread;
    602         )
    603 }
    604 
    605 void lock_yield( spinlock * this DEBUG_CTX_PARAM2 ) {
    606         for ( unsigned int i = 1;; i += 1 ) {
    607                 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; }
    608                 yield();
    609         }
    610         LIB_DEBUG_DO(
    611                 this->prev_name = caller;
    612                 this->prev_thrd = this_thread;
    613         )
    614 }
    615 
     533                if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break;
     534        }
     535}
    616536
    617537void unlock( spinlock * this ) {
     
    619539}
    620540
    621 void  ?{}( semaphore * this, int count = 1 ) {
    622         (&this->lock){};
    623         this->count = count;
    624         (&this->waiting){};
    625 }
    626 void ^?{}(semaphore * this) {}
    627 
    628 void P(semaphore * this) {
    629         lock( &this->lock DEBUG_CTX2 );
    630         this->count -= 1;
    631         if ( this->count < 0 ) {
    632                 // queue current task
    633                 append( &this->waiting, (thread_desc *)this_thread );
    634 
    635                 // atomically release spin lock and block
    636                 BlockInternal( &this->lock );
    637         }
    638         else {
    639             unlock( &this->lock );
    640         }
    641 }
    642 
    643 void V(semaphore * this) {
    644         thread_desc * thrd = NULL;
    645         lock( &this->lock DEBUG_CTX2 );
    646         this->count += 1;
    647         if ( this->count <= 0 ) {
    648                 // remove task at head of waiting list
    649                 thrd = pop_head( &this->waiting );
    650         }
    651 
     541void ?{}( signal_once * this ) {
     542        this->cond = false;
     543}
     544void ^?{}( signal_once * this ) {
     545
     546}
     547
     548void wait( signal_once * this ) {
     549        lock( &this->lock );
     550        if( !this->cond ) {
     551                append( &this->blocked, this_thread() );
     552                ScheduleInternal( &this->lock );
     553                lock( &this->lock );
     554        }
    652555        unlock( &this->lock );
    653 
    654         // make new owner
    655         WakeThread( thrd );
     556}
     557
     558void signal( signal_once * this ) {
     559        lock( &this->lock );
     560        {
     561                this->cond = true;
     562
     563                thread_desc * it;
     564                while( it = pop_head( &this->blocked) ) {
     565                        ScheduleThread( it );
     566                }
     567        }
     568        unlock( &this->lock );
    656569}
    657570
     
    677590                }
    678591                head->next = NULL;
    679         }
     592        }       
    680593        return head;
    681594}
     
    696609                this->top = top->next;
    697610                top->next = NULL;
    698         }
     611        }       
    699612        return top;
    700613}
Note: See TracChangeset for help on using the changeset viewer.