Ignore:
File:
1 edited

Legend:

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

    r4aa2fb2 rbdeba0b  
    1515//
    1616
    17 #include "startup.h"
    18 
    19 //Start and stop routine for the kernel, declared first to make sure they run first
    20 void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
    21 void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
    22 
    23 //Header
    24 #include "kernel_private.h"
     17#include "libhdr.h"
    2518
    2619//C Includes
     
    3528
    3629//CFA Includes
    37 #include "libhdr.h"
     30#include "kernel_private.h"
    3831#include "preemption.h"
     32#include "startup.h"
    3933
    4034//Private includes
    4135#define __CFA_INVOKE_PRIVATE__
    4236#include "invoke.h"
     37
     38//Start and stop routine for the kernel, declared first to make sure they run first
     39void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
     40void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
    4341
    4442//-----------------------------------------------------------------------------
     
    5957// Global state
    6058
    61 thread_local processor * this_processor;
    62 
    63 coroutine_desc * this_coroutine(void) {
    64         return this_processor->current_coroutine;
    65 }
    66 
    67 thread_desc * this_thread(void) {
    68         return this_processor->current_thread;
    69 }
     59volatile thread_local processor * this_processor;
     60volatile thread_local coroutine_desc * this_coroutine;
     61volatile thread_local thread_desc * this_thread;
     62volatile thread_local unsigned short disable_preempt_count = 1;
    7063
    7164//-----------------------------------------------------------------------------
    7265// Main thread construction
    7366struct current_stack_info_t {
    74         machine_context_t ctx; 
     67        machine_context_t ctx;
    7568        unsigned int size;              // size of stack
    7669        void *base;                             // base of stack
     
    10699
    107100void ?{}( coroutine_desc * this, current_stack_info_t * info) {
    108         (&this->stack){ info }; 
     101        (&this->stack){ info };
    109102        this->name = "Main Thread";
    110103        this->errno_ = 0;
     
    136129void ?{}(processor * this, cluster * cltr) {
    137130        this->cltr = cltr;
    138         this->current_coroutine = NULL;
    139         this->current_thread = NULL;
    140         (&this->terminated){};
     131        (&this->terminated){ 0 };
    141132        this->is_terminated = false;
    142133        this->preemption_alarm = NULL;
    143134        this->preemption = default_preemption();
    144         this->disable_preempt_count = 1;                //Start with interrupts disabled
    145135        this->pending_preemption = false;
    146136
     
    150140void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) {
    151141        this->cltr = cltr;
    152         this->current_coroutine = NULL;
    153         this->current_thread = NULL;
    154         (&this->terminated){};
     142        (&this->terminated){ 0 };
    155143        this->is_terminated = false;
    156         this->disable_preempt_count = 0;
     144        this->preemption_alarm = NULL;
     145        this->preemption = default_preemption();
    157146        this->pending_preemption = false;
     147        this->kernel_thread = pthread_self();
    158148
    159149        this->runner = runner;
    160         LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner);
     150        LIB_DEBUG_PRINT_SAFE("Kernel : constructing system processor context %p\n", runner);
    161151        runner{ this };
    162152}
     153
     154LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )
    163155
    164156void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) {
     
    168160
    169161        (&this->proc){ cltr, runner };
     162
     163        verify( validate( &this->alarms ) );
    170164}
    171165
     
    174168                LIB_DEBUG_PRINT_SAFE("Kernel : core %p signaling termination\n", this);
    175169                this->is_terminated = true;
    176                 wait( &this->terminated );
     170                P( &this->terminated );
     171                pthread_join( this->kernel_thread, NULL );
    177172        }
    178173}
     
    184179
    185180void ^?{}(cluster * this) {
    186        
     181
    187182}
    188183
     
    203198
    204199                thread_desc * readyThread = NULL;
    205                 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 
     200                for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ )
    206201                {
    207202                        readyThread = nextThread( this->cltr );
     
    209204                        if(readyThread)
    210205                        {
     206                                verify( disable_preempt_count > 0 );
     207
    211208                                runThread(this, readyThread);
     209
     210                                verify( disable_preempt_count > 0 );
    212211
    213212                                //Some actions need to be taken from the kernel
     
    225224        }
    226225
    227         signal( &this->terminated );
     226        V( &this->terminated );
     227
    228228        LIB_DEBUG_PRINT_SAFE("Kernel : core %p terminated\n", this);
    229229}
    230230
    231 // runThread runs a thread by context switching 
    232 // 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
    233233void runThread(processor * this, thread_desc * dst) {
    234234        coroutine_desc * proc_cor = get_coroutine(this->runner);
    235235        coroutine_desc * thrd_cor = get_coroutine(dst);
    236        
     236
    237237        //Reset the terminating actions here
    238238        this->finish.action_code = No_Action;
    239239
    240240        //Update global state
    241         this->current_thread = dst;
     241        this_thread = dst;
    242242
    243243        // Context Switch to the thread
     
    246246}
    247247
    248 // Once a thread has finished running, some of 
     248// Once a thread has finished running, some of
    249249// its final actions must be executed from the kernel
    250250void finishRunning(processor * this) {
     
    256256        }
    257257        else if( this->finish.action_code == Release_Schedule ) {
    258                 unlock( this->finish.lock );           
     258                unlock( this->finish.lock );
    259259                ScheduleThread( this->finish.thrd );
    260260        }
     
    289289        processor * proc = (processor *) arg;
    290290        this_processor = proc;
     291        this_coroutine = NULL;
     292        this_thread = NULL;
     293        disable_preempt_count = 1;
    291294        // SKULLDUGGERY: We want to create a context for the processor coroutine
    292295        // which is needed for the 2-step context switch. However, there is no reason
    293         // to waste the perfectly valid stack create by pthread. 
     296        // to waste the perfectly valid stack create by pthread.
    294297        current_stack_info_t info;
    295298        machine_context_t ctx;
     
    300303
    301304        //Set global state
    302         proc->current_coroutine = &proc->runner->__cor;
    303         proc->current_thread = NULL;
     305        this_coroutine = &proc->runner->__cor;
     306        this_thread = NULL;
    304307
    305308        //We now have a proper context from which to schedule threads
    306309        LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx);
    307310
    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 
     311        // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
     312        // resume it to start it like it normally would, it will just context switch
     313        // back to here. Instead directly call the main since we already are on the
    311314        // appropriate stack.
    312315        proc_cor_storage.__cor.state = Active;
     
    315318
    316319        // Main routine of the core returned, the core is now fully terminated
    317         LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 
     320        LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner);
    318321
    319322        return NULL;
     
    322325void start(processor * this) {
    323326        LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this);
    324        
     327
    325328        pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this );
    326329
    327         LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this);       
     330        LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this);
    328331}
    329332
     
    331334// Scheduler routines
    332335void ScheduleThread( thread_desc * thrd ) {
    333         if( !thrd ) return;
     336        // if( !thrd ) return;
     337        assert( thrd );
     338        assert( thrd->cor.state != Halted );
     339
     340        verify( disable_preempt_count > 0 );
    334341
    335342        verifyf( thrd->next == NULL, "Expected null got %p", thrd->next );
    336        
    337         lock( &systemProcessor->proc.cltr->lock );
     343
     344        lock( &systemProcessor->proc.cltr->lock DEBUG_CTX2 );
    338345        append( &systemProcessor->proc.cltr->ready_queue, thrd );
    339346        unlock( &systemProcessor->proc.cltr->lock );
     347
     348        verify( disable_preempt_count > 0 );
    340349}
    341350
    342351thread_desc * nextThread(cluster * this) {
    343         lock( &this->lock );
     352        verify( disable_preempt_count > 0 );
     353        lock( &this->lock DEBUG_CTX2 );
    344354        thread_desc * head = pop_head( &this->ready_queue );
    345355        unlock( &this->lock );
     356        verify( disable_preempt_count > 0 );
    346357        return head;
    347358}
    348359
    349 void ScheduleInternal() {
     360void BlockInternal() {
     361        disable_interrupts();
     362        verify( disable_preempt_count > 0 );
    350363        suspend();
    351 }
    352 
    353 void ScheduleInternal( spinlock * lock ) {
     364        verify( disable_preempt_count > 0 );
     365        enable_interrupts( DEBUG_CTX );
     366}
     367
     368void BlockInternal( spinlock * lock ) {
     369        disable_interrupts();
    354370        this_processor->finish.action_code = Release;
    355371        this_processor->finish.lock = lock;
     372
     373        verify( disable_preempt_count > 0 );
    356374        suspend();
    357 }
    358 
    359 void ScheduleInternal( thread_desc * thrd ) {
     375        verify( disable_preempt_count > 0 );
     376
     377        enable_interrupts( DEBUG_CTX );
     378}
     379
     380void BlockInternal( thread_desc * thrd ) {
     381        disable_interrupts();
     382        assert( thrd->cor.state != Halted );
    360383        this_processor->finish.action_code = Schedule;
    361384        this_processor->finish.thrd = thrd;
     385
     386        verify( disable_preempt_count > 0 );
    362387        suspend();
    363 }
    364 
    365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) {
     388        verify( disable_preempt_count > 0 );
     389
     390        enable_interrupts( DEBUG_CTX );
     391}
     392
     393void BlockInternal( spinlock * lock, thread_desc * thrd ) {
     394        disable_interrupts();
    366395        this_processor->finish.action_code = Release_Schedule;
    367396        this_processor->finish.lock = lock;
    368397        this_processor->finish.thrd = thrd;
     398
     399        verify( disable_preempt_count > 0 );
    369400        suspend();
    370 }
    371 
    372 void ScheduleInternal(spinlock ** locks, unsigned short count) {
     401        verify( disable_preempt_count > 0 );
     402
     403        enable_interrupts( DEBUG_CTX );
     404}
     405
     406void BlockInternal(spinlock ** locks, unsigned short count) {
     407        disable_interrupts();
    373408        this_processor->finish.action_code = Release_Multi;
    374409        this_processor->finish.locks = locks;
    375410        this_processor->finish.lock_count = count;
     411
     412        verify( disable_preempt_count > 0 );
    376413        suspend();
    377 }
    378 
    379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) {
     414        verify( disable_preempt_count > 0 );
     415
     416        enable_interrupts( DEBUG_CTX );
     417}
     418
     419void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) {
     420        disable_interrupts();
    380421        this_processor->finish.action_code = Release_Multi_Schedule;
    381422        this_processor->finish.locks = locks;
     
    383424        this_processor->finish.thrds = thrds;
    384425        this_processor->finish.thrd_count = thrd_count;
     426
     427        verify( disable_preempt_count > 0 );
    385428        suspend();
     429        verify( disable_preempt_count > 0 );
     430
     431        enable_interrupts( DEBUG_CTX );
    386432}
    387433
     
    392438// Kernel boot procedures
    393439void kernel_startup(void) {
    394         LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n");   
     440        LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n");
    395441
    396442        // Start by initializing the main thread
    397         // SKULLDUGGERY: the mainThread steals the process main thread 
     443        // SKULLDUGGERY: the mainThread steals the process main thread
    398444        // which will then be scheduled by the systemProcessor normally
    399445        mainThread = (thread_desc *)&mainThread_storage;
     
    403449        LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n");
    404450
    405         // Enable preemption
    406         kernel_start_preemption();
    407 
    408451        // Initialize the system cluster
    409452        systemCluster = (cluster *)&systemCluster_storage;
     
    417460        systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage };
    418461
    419         // Add the main thread to the ready queue 
     462        // Add the main thread to the ready queue
    420463        // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread
    421464        ScheduleThread(mainThread);
     
    423466        //initialize the global state variables
    424467        this_processor = &systemProcessor->proc;
    425         this_processor->current_thread = mainThread;
    426         this_processor->current_coroutine = &mainThread->cor;
     468        this_thread = mainThread;
     469        this_coroutine = &mainThread->cor;
     470        disable_preempt_count = 1;
     471
     472        // Enable preemption
     473        kernel_start_preemption();
    427474
    428475        // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX
    429476        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
    430         // mainThread is on the ready queue when this call is made. 
     477        // mainThread is on the ready queue when this call is made.
    431478        resume( systemProcessor->proc.runner );
    432479
     
    435482        // THE SYSTEM IS NOW COMPLETELY RUNNING
    436483        LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n");
     484
     485        enable_interrupts( DEBUG_CTX );
    437486}
    438487
    439488void kernel_shutdown(void) {
    440489        LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n");
     490
     491        disable_interrupts();
    441492
    442493        // SKULLDUGGERY: Notify the systemProcessor it needs to terminates.
     
    448499        // THE SYSTEM IS NOW COMPLETELY STOPPED
    449500
     501        // Disable preemption
     502        kernel_stop_preemption();
     503
    450504        // Destroy the system processor and its context in reverse order of construction
    451505        // These were manually constructed so we need manually destroy them
     
    457511        ^(mainThread){};
    458512
    459         LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n");   
     513        LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n");
    460514}
    461515
     
    467521        // abort cannot be recursively entered by the same or different processors because all signal handlers return when
    468522        // the globalAbort flag is true.
    469         lock( &kernel_abort_lock );
     523        lock( &kernel_abort_lock DEBUG_CTX2 );
    470524
    471525        // first task to abort ?
     
    473527                kernel_abort_called = true;
    474528                unlock( &kernel_abort_lock );
    475         } 
     529        }
    476530        else {
    477531                unlock( &kernel_abort_lock );
    478                
     532
    479533                sigset_t mask;
    480534                sigemptyset( &mask );
     
    482536                sigaddset( &mask, SIGUSR1 );                    // block SIGUSR1 signals
    483537                sigsuspend( &mask );                            // block the processor to prevent further damage during abort
    484                 _exit( EXIT_FAILURE );                          // if processor unblocks before it is killed, terminate it             
    485         }
    486 
    487         return this_thread();
     538                _exit( EXIT_FAILURE );                          // if processor unblocks before it is killed, terminate it
     539        }
     540
     541        return this_thread;
    488542}
    489543
     
    494548        __lib_debug_write( STDERR_FILENO, abort_text, len );
    495549
    496         if ( thrd != this_coroutine() ) {
    497                 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine()->name, this_coroutine() );
     550        if ( thrd != this_coroutine ) {
     551                len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine->name, this_coroutine );
    498552                __lib_debug_write( STDERR_FILENO, abort_text, len );
    499         } 
     553        }
    500554        else {
    501555                __lib_debug_write( STDERR_FILENO, ".\n", 2 );
     
    505559extern "C" {
    506560        void __lib_debug_acquire() {
    507                 lock(&kernel_debug_lock);
     561                lock( &kernel_debug_lock DEBUG_CTX2 );
    508562        }
    509563
    510564        void __lib_debug_release() {
    511                 unlock(&kernel_debug_lock);
     565                unlock( &kernel_debug_lock );
    512566        }
    513567}
     
    525579}
    526580
    527 bool try_lock( spinlock * this ) {
     581bool try_lock( spinlock * this DEBUG_CTX_PARAM2 ) {
    528582        return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0;
    529583}
    530584
    531 void lock( spinlock * this ) {
     585void lock( spinlock * this DEBUG_CTX_PARAM2 ) {
    532586        for ( unsigned int i = 1;; i += 1 ) {
    533                 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break;
    534         }
    535 }
     587                if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; }
     588        }
     589        LIB_DEBUG_DO(
     590                this->prev_name = caller;
     591                this->prev_thrd = this_thread;
     592        )
     593}
     594
     595void lock_yield( spinlock * this DEBUG_CTX_PARAM2 ) {
     596        for ( unsigned int i = 1;; i += 1 ) {
     597                if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; }
     598                yield();
     599        }
     600        LIB_DEBUG_DO(
     601                this->prev_name = caller;
     602                this->prev_thrd = this_thread;
     603        )
     604}
     605
    536606
    537607void unlock( spinlock * this ) {
     
    539609}
    540610
    541 void ?{}( signal_once * this ) {
    542         this->cond = false;
    543 }
    544 void ^?{}( signal_once * this ) {
    545 
    546 }
    547 
    548 void 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         }
     611void  ?{}( semaphore * this, int count = 1 ) {
     612        (&this->lock){};
     613        this->count = count;
     614        (&this->waiting){};
     615}
     616void ^?{}(semaphore * this) {}
     617
     618void P(semaphore * this) {
     619        lock( &this->lock DEBUG_CTX2 );
     620        this->count -= 1;
     621        if ( this->count < 0 ) {
     622                // queue current task
     623                append( &this->waiting, (thread_desc *)this_thread );
     624
     625                // atomically release spin lock and block
     626                BlockInternal( &this->lock );
     627        }
     628        else {
     629            unlock( &this->lock );
     630        }
     631}
     632
     633void V(semaphore * this) {
     634        thread_desc * thrd = NULL;
     635        lock( &this->lock DEBUG_CTX2 );
     636        this->count += 1;
     637        if ( this->count <= 0 ) {
     638                // remove task at head of waiting list
     639                thrd = pop_head( &this->waiting );
     640        }
     641
    555642        unlock( &this->lock );
    556 }
    557 
    558 void 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 );
     643
     644        // make new owner
     645        WakeThread( thrd );
    569646}
    570647
     
    590667                }
    591668                head->next = NULL;
    592         }       
     669        }
    593670        return head;
    594671}
     
    609686                this->top = top->next;
    610687                top->next = NULL;
    611         }       
     688        }
    612689        return top;
    613690}
Note: See TracChangeset for help on using the changeset viewer.