Ignore:
File:
1 edited

Legend:

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

    rc84e80a re15df4c  
    2020//C Includes
    2121#include <stddef.h>
     22extern "C" {
     23#include <sys/resource.h>
     24}
    2225
    2326//CFA Includes
     
    2932#include "invoke.h"
    3033
    31 processor systemProcessorStorage = {};
    32 processor * systemProcessor = &systemProcessorStorage;
    33 
    34 void ?{}(processor * this) {
    35         this->cor = NULL;
    36         this->thread_index = 0;
    37         this->thread_count = 10;
    38         this->terminated = false;
    39 
    40         for(int i = 0; i < 10; i++) {
    41                 this->threads[i] = NULL;
    42         }
    43 
    44         LIB_DEBUG_PRINTF("Processor : ctor for core %p (core spots %d)\n", this, this->thread_count);
    45 }
    46 
    47 void ^?{}(processor * this) {
    48 
    49 }
    50 
    51 //-----------------------------------------------------------------------------
    52 // Processor coroutine
    53 struct proc_coroutine {
     34//-----------------------------------------------------------------------------
     35// Kernel storage
     36struct processorCtx_t {
    5437        processor * proc;
    5538        coroutine c;
    5639};
    5740
    58 void ?{}(coroutine * this, processor * proc) {
    59         this{};
    60 }
    61 
    62 DECL_COROUTINE(proc_coroutine)
    63 
    64 void ?{}(proc_coroutine * this, processor * proc) {
    65         (&this->c){proc};
     41DECL_COROUTINE(processorCtx_t)
     42
     43#define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
     44
     45KERNEL_STORAGE(processorCtx_t, systemProcessorCtx);
     46KERNEL_STORAGE(cluster, systemCluster);
     47KERNEL_STORAGE(processor, systemProcessor);
     48KERNEL_STORAGE(thread, mainThread);
     49KERNEL_STORAGE(machine_context_t, mainThread_context);
     50
     51cluster * systemCluster;
     52processor * systemProcessor;
     53thread * mainThread;
     54
     55void kernel_startup(void)  __attribute__((constructor(101)));
     56void kernel_shutdown(void) __attribute__((destructor(101)));
     57
     58//-----------------------------------------------------------------------------
     59// Global state
     60
     61thread_local processor * this_processor;
     62
     63processor * get_this_processor() {
     64        return this_processor;
     65}
     66
     67coroutine * this_coroutine(void) {
     68        return this_processor->current_coroutine;
     69}
     70
     71thread * this_thread(void) {
     72        return this_processor->current_thread;
     73}
     74
     75//-----------------------------------------------------------------------------
     76// Main thread construction
     77struct current_stack_info_t {
     78        machine_context_t ctx; 
     79        unsigned int size;              // size of stack
     80        void *base;                             // base of stack
     81        void *storage;                  // pointer to stack
     82        void *limit;                    // stack grows towards stack limit
     83        void *context;                  // address of cfa_context_t
     84        void *top;                              // address of top of storage
     85};
     86
     87void ?{}( current_stack_info_t * this ) {
     88        CtxGet( &this->ctx );
     89        this->base = this->ctx.FP;
     90        this->storage = this->ctx.SP;
     91
     92        rlimit r;
     93        int ret = getrlimit( RLIMIT_STACK, &r);
     94        this->size = r.rlim_cur;
     95
     96        this->limit = (void *)(((intptr_t)this->base) - this->size);
     97        this->context = &mainThread_context_storage;
     98        this->top = this->base;
     99}
     100
     101void ?{}( coStack_t * this, current_stack_info_t * info) {
     102        this->size = info->size;
     103        this->storage = info->storage;
     104        this->limit = info->limit;
     105        this->base = info->base;
     106        this->context = info->context;
     107        this->top = info->top;
     108        this->userStack = true;
     109}
     110
     111void ?{}( coroutine * this, current_stack_info_t * info) {
     112        (&this->stack){ info };
     113        this->name = "Main Thread";
     114        this->errno_ = 0;
     115        this->state = Inactive;
     116        this->notHalted = true;
     117}
     118
     119void ?{}( thread * this, current_stack_info_t * info) {
     120        (&this->c){ info };
     121}
     122
     123//-----------------------------------------------------------------------------
     124// Processor coroutine
     125void ?{}(processorCtx_t * this, processor * proc) {
     126        (&this->c){};
    66127        this->proc = proc;
    67         proc->cor = this;
    68 }
    69 
    70 void ^?{}(proc_coroutine * this) {
    71         ^(&this->c){};
    72 }
    73 
    74 void CtxInvokeProcessor(processor * proc) {
    75         proc_coroutine proc_cor_storage = {proc};
    76         resume( &proc_cor_storage );
     128        proc->ctx = this;
     129}
     130
     131void ?{}(processorCtx_t * this, processor * proc, current_stack_info_t * info) {
     132        (&this->c){ info };
     133        this->proc = proc;
     134        proc->ctx = this;
     135}
     136
     137void start(processor * this);
     138
     139void ?{}(processor * this) {
     140        this{ systemCluster };
     141}
     142
     143void ?{}(processor * this, cluster * cltr) {
     144        this->cltr = cltr;
     145        this->current_coroutine = NULL;
     146        this->current_thread = NULL;
     147        (&this->lock){};
     148        this->terminated = false;
     149
     150        start( this );
     151}
     152
     153void ?{}(processor * this, cluster * cltr, processorCtx_t * ctx) {
     154        this->cltr = cltr;
     155        this->current_coroutine = NULL;
     156        this->current_thread = NULL;
     157        (&this->lock){};
     158        this->terminated = false;
     159
     160        this->ctx = ctx;
     161        LIB_DEBUG_PRINTF("Kernel : constructing processor context %p\n", ctx);
     162        ctx{ this };
     163}
     164
     165void ^?{}(processor * this) {
     166        if( ! this->terminated ) {
     167                LIB_DEBUG_PRINTF("Kernel : core %p signaling termination\n", this);
     168                this->terminated = true;
     169                lock( &this->lock );
     170        }
     171}
     172
     173void ?{}(cluster * this) {
     174        ( &this->ready_queue ){};
     175        pthread_spin_init( &this->lock, PTHREAD_PROCESS_PRIVATE );
     176}
     177
     178void ^?{}(cluster * this) {
     179        pthread_spin_destroy( &this->lock );
    77180}
    78181
    79182//-----------------------------------------------------------------------------
    80183// Processor running routines
    81 void main(proc_coroutine * cor);
    82 thread_h * nextThread(processor * this);
    83 void runThread(processor * this, thread_h * dst);
     184void main(processorCtx_t * ctx);
     185thread * nextThread(cluster * this);
     186void runThread(processor * this, thread * dst);
    84187void spin(processor * this, unsigned int * spin_count);
    85188
    86 void main(proc_coroutine * cor) {
    87         processor * this;
    88         this = cor->proc;
    89 
    90         thread_h * readyThread = NULL;
     189void main(processorCtx_t * ctx) {
     190        processor * this = ctx->proc;
     191        LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this);
     192
     193        thread * readyThread = NULL;
    91194        for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) {
    92195               
    93                 readyThread = nextThread(this);
     196                readyThread = nextThread( this->cltr );
    94197
    95198                if(readyThread) {
     
    101204        }
    102205
     206        LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this);
     207        unlock( &this->lock );
    103208        LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this);
    104209}
    105210
    106 thread_h * nextThread(processor * this) {
    107         for(int i = 0; i < this->thread_count; i++) {
    108                 this->thread_index = (this->thread_index + 1) % this->thread_count;     
    109                
    110                 thread_h * thrd = this->threads[this->thread_index];
    111                 if(thrd) return thrd;
    112         }
    113 
    114         return NULL;
    115 }
    116 
    117 void runThread(processor * this, thread_h * dst) {
    118         coroutine * proc_ctx = get_coroutine(this->cor);
     211void runThread(processor * this, thread * dst) {
     212        coroutine * proc_ctx = get_coroutine(this->ctx);
    119213        coroutine * thrd_ctx = get_coroutine(dst);
    120214        thrd_ctx->last = proc_ctx;
     
    122216        // context switch to specified coroutine
    123217        // Which is now the current_coroutine
    124         LIB_DEBUG_PRINTF("Kernel : switching to ctx %p (from %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
    125         current_coroutine = thrd_ctx;
     218        // LIB_DEBUG_PRINTF("Kernel : switching to ctx %p (from %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
     219        this->current_thread = dst;
     220        this->current_coroutine = thrd_ctx;
    126221        CtxSwitch( proc_ctx->stack.context, thrd_ctx->stack.context );
    127         current_coroutine = proc_ctx;
    128         LIB_DEBUG_PRINTF("Kernel : returned from ctx %p (to %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
     222        this->current_coroutine = proc_ctx;
     223        // LIB_DEBUG_PRINTF("Kernel : returned from ctx %p (to %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
    129224
    130225        // when CtxSwitch returns we are back in the processor coroutine
     
    135230}
    136231
    137 //-----------------------------------------------------------------------------
    138 // Kernel runner (Temporary)
    139 
    140 void scheduler_add( struct thread_h * thrd ) {
    141         LIB_DEBUG_PRINTF("Kernel : scheduling %p on core %p (%d spots)\n", thrd, systemProcessor, systemProcessor->thread_count);
    142         for(int i = 0; i < systemProcessor->thread_count; i++) {
    143                 if(systemProcessor->threads[i] == NULL) {
    144                         systemProcessor->threads[i] = thrd;
    145                         return;
     232void * CtxInvokeProcessor(void * arg) {
     233        processor * proc = (processor *) arg;
     234        this_processor = proc;
     235        // SKULLDUGGERY: We want to create a context for the processor coroutine
     236        // which is needed for the 2-step context switch. However, there is no reason
     237        // to waste the perfectly valid stack create by pthread.
     238        current_stack_info_t info;
     239        machine_context_t ctx;
     240        info.context = &ctx;
     241        processorCtx_t proc_cor_storage = { proc, &info };
     242
     243        proc->current_coroutine = &proc->ctx->c;
     244        proc->current_thread = NULL;
     245
     246        LIB_DEBUG_PRINTF("Kernel : core %p created (%p)\n", proc, proc->ctx);
     247
     248        // LIB_DEBUG_PRINTF("Kernel : core    base : %p \n", info.base );
     249        // LIB_DEBUG_PRINTF("Kernel : core storage : %p \n", info.storage );
     250        // LIB_DEBUG_PRINTF("Kernel : core    size : %x \n", info.size );
     251        // LIB_DEBUG_PRINTF("Kernel : core   limit : %p \n", info.limit );
     252        // LIB_DEBUG_PRINTF("Kernel : core context : %p \n", info.context );
     253        // LIB_DEBUG_PRINTF("Kernel : core     top : %p \n", info.top );
     254
     255        //We now have a proper context from which to schedule threads
     256
     257        // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
     258        // resume it to start it like it normally would, it will just context switch
     259        // back to here. Instead directly call the main since we already are on the
     260        // appropriate stack.
     261        proc_cor_storage.c.state = Active;
     262      main( &proc_cor_storage );
     263      proc_cor_storage.c.state = Halt;
     264      proc_cor_storage.c.notHalted = false;
     265
     266        LIB_DEBUG_PRINTF("Kernel : core %p main ended (%p)\n", proc, proc->ctx);       
     267
     268        return NULL;
     269}
     270
     271void start(processor * this) {
     272        LIB_DEBUG_PRINTF("Kernel : Starting core %p\n", this);
     273       
     274        pthread_attr_t attributes;
     275        pthread_attr_init( &attributes );
     276
     277        pthread_create( &this->kernel_thread, &attributes, CtxInvokeProcessor, (void*)this );
     278
     279        pthread_attr_destroy( &attributes );
     280
     281        LIB_DEBUG_PRINTF("Kernel : core %p started\n", this);   
     282}
     283
     284//-----------------------------------------------------------------------------
     285// Scheduler routines
     286void thread_schedule( thread * thrd ) {
     287        assertf( thrd->next == NULL, "Expected null got %p", thrd->next );
     288       
     289        pthread_spinlock_guard guard = { &systemProcessor->cltr->lock };
     290        append( &systemProcessor->cltr->ready_queue, thrd );
     291}
     292
     293thread * nextThread(cluster * this) {
     294        pthread_spinlock_guard guard = { &this->lock };
     295        return pop_head( &this->ready_queue );
     296}
     297
     298//-----------------------------------------------------------------------------
     299// Kernel boot procedures
     300void kernel_startup(void) {
     301
     302        // SKULLDUGGERY: the mainThread steals the process main thread
     303        // which will then be scheduled by the systemProcessor normally
     304        LIB_DEBUG_PRINTF("Kernel : Starting\n");       
     305
     306        current_stack_info_t info;
     307
     308        // LIB_DEBUG_PRINTF("Kernel : core    base : %p \n", info.base );
     309        // LIB_DEBUG_PRINTF("Kernel : core storage : %p \n", info.storage );
     310        // LIB_DEBUG_PRINTF("Kernel : core    size : %x \n", info.size );
     311        // LIB_DEBUG_PRINTF("Kernel : core   limit : %p \n", info.limit );
     312        // LIB_DEBUG_PRINTF("Kernel : core context : %p \n", info.context );
     313        // LIB_DEBUG_PRINTF("Kernel : core     top : %p \n", info.top );
     314
     315        // Start by initializing the main thread
     316        mainThread = (thread *)&mainThread_storage;
     317        mainThread{ &info };
     318
     319        // Initialize the system cluster
     320        systemCluster = (cluster *)&systemCluster_storage;
     321        systemCluster{};
     322
     323        // Initialize the system processor and the system processor ctx
     324        // (the coroutine that contains the processing control flow)
     325        systemProcessor = (processor *)&systemProcessor_storage;
     326        systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage };
     327
     328        // Add the main thread to the ready queue
     329        // once resume is called on systemProcessor->ctx the mainThread needs to be scheduled like any normal thread
     330        thread_schedule(mainThread);
     331
     332        //initialize the global state variables
     333        this_processor = systemProcessor;
     334        this_processor->current_thread = mainThread;
     335        this_processor->current_coroutine = &mainThread->c;
     336
     337        // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX
     338        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
     339        // mainThread is on the ready queue when this call is made.
     340        resume(systemProcessor->ctx);
     341
     342
     343
     344        // THE SYSTEM IS NOW COMPLETELY RUNNING
     345
     346
     347
     348        LIB_DEBUG_PRINTF("Kernel : Started\n--------------------------------------------------\n\n");
     349}
     350
     351void kernel_shutdown(void) {
     352        LIB_DEBUG_PRINTF("\n--------------------------------------------------\nKernel : Shutting down\n");
     353
     354        // SKULLDUGGERY: Notify the systemProcessor it needs to terminates.
     355        // When its coroutine terminates, it return control to the mainThread
     356        // which is currently here
     357        systemProcessor->terminated = true;
     358        suspend();
     359
     360        // THE SYSTEM IS NOW COMPLETELY STOPPED
     361
     362        // Destroy the system processor and its context in reverse order of construction
     363        // These were manually constructed so we need manually destroy them
     364        ^(systemProcessor->ctx){};
     365        ^(systemProcessor){};
     366
     367        // Final step, destroy the main thread since it is no longer needed
     368        // Since we provided a stack to this taxk it will not destroy anything
     369        ^(mainThread){};
     370
     371        LIB_DEBUG_PRINTF("Kernel : Shutdown complete\n");       
     372}
     373
     374//-----------------------------------------------------------------------------
     375// Locks
     376void ?{}( simple_lock * this ) {
     377        ( &this->blocked ){};
     378}
     379
     380void ^?{}( simple_lock * this ) {
     381
     382}
     383
     384void lock( simple_lock * this ) {
     385        {
     386                pthread_spinlock_guard guard = { &systemCluster->lock };        //HUGE TEMP HACK which only works if we have a single cluster and is stupid
     387                append( &this->blocked, this_thread() );
     388        }
     389        suspend();
     390}
     391
     392void unlock( simple_lock * this ) {
     393        thread * it;
     394        while( it = pop_head( &this->blocked) ) {
     395                thread_schedule( it );
     396        }
     397}
     398
     399//-----------------------------------------------------------------------------
     400// Queues
     401void ?{}( simple_thread_list * this ) {
     402        this->head = NULL;
     403        this->tail = &this->head;
     404}
     405
     406void append( simple_thread_list * this, thread * t ) {
     407        assert( t->next == NULL );
     408        *this->tail = t;
     409        this->tail = &t->next;
     410}
     411
     412thread * pop_head( simple_thread_list * this ) {
     413        thread * head = this->head;
     414        if( head ) {
     415                this->head = head->next;
     416                if( !head->next ) {
     417                        this->tail = &this->head;
    146418                }
    147         }
    148         assert(false);
    149 }
    150 
    151 void scheduler_remove( struct thread_h * thrd ) {
    152         LIB_DEBUG_PRINTF("Kernel : unscheduling %p from core %p\n", thrd, systemProcessor);
    153         for(int i = 0; i < systemProcessor->thread_count; i++) {
    154                 if(systemProcessor->threads[i] == thrd) {
    155                         systemProcessor->threads[i] = NULL;
    156                         break;
    157                 }
    158         }
    159         for(int i = 0; i < systemProcessor->thread_count; i++) {
    160                 if(systemProcessor->threads[i] != NULL) {
    161                         return;
    162                 }
    163         }
    164         LIB_DEBUG_PRINTF("Kernel : terminating core %p\n\n\n", systemProcessor);       
    165         systemProcessor->terminated = true;
    166 }
    167 
    168 void kernel_run( void ) {
    169         CtxInvokeProcessor(systemProcessor);
    170 }
    171 
     419                head->next = NULL;
     420        }       
     421       
     422        return head;
     423}
    172424// Local Variables: //
    173425// mode: c //
Note: See TracChangeset for help on using the changeset viewer.