Ignore:
File:
1 edited

Legend:

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

    r8def349 rbd98b58  
    3232#include "invoke.h"
    3333
    34 //-----------------------------------------------------------------------------
    35 // Kernel storage
     34cluster * systemCluster;
     35processor * systemProcessor;
     36thread_h * mainThread;
     37
     38void kernel_startup(void)  __attribute__((constructor(101)));
     39void kernel_shutdown(void) __attribute__((destructor(101)));
     40
     41void ?{}(processor * this, cluster * cltr) {
     42        this->ctx = NULL;
     43        this->cltr = cltr;
     44        this->terminated = false;
     45}
     46
     47void ^?{}(processor * this) {}
     48
     49void ?{}(cluster * this) {
     50        ( &this->ready_queue ){};
     51}
     52
     53void ^?{}(cluster * this) {}
     54
     55//-----------------------------------------------------------------------------
     56// Global state
     57
     58/*thread_local*/ processor * this_processor;
     59
     60coroutine * this_coroutine(void) {
     61        return this_processor->current_coroutine;
     62}
     63
     64thread_h * this_thread(void) {
     65        return this_processor->current_thread;
     66}
     67
     68//-----------------------------------------------------------------------------
     69// Processor coroutine
    3670struct processorCtx_t {
    3771        processor * proc;
     
    4175DECL_COROUTINE(processorCtx_t)
    4276
     77void ?{}(processorCtx_t * this, processor * proc) {
     78        (&this->c){};
     79        this->proc = proc;
     80}
     81
     82void CtxInvokeProcessor(processor * proc) {
     83        processorCtx_t proc_cor_storage = {proc};
     84        resume( &proc_cor_storage );
     85}
     86
     87//-----------------------------------------------------------------------------
     88// Processor running routines
     89void main(processorCtx_t * ctx);
     90thread_h * nextThread(cluster * this);
     91void runThread(processor * this, thread_h * dst);
     92void spin(processor * this, unsigned int * spin_count);
     93
     94void main(processorCtx_t * ctx) {
     95        processor * this = ctx->proc;
     96        LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this);
     97
     98        thread_h * readyThread = NULL;
     99        for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) {
     100               
     101                readyThread = nextThread( this->cltr );
     102
     103                if(readyThread) {
     104                        runThread(this, readyThread);
     105                        spin_count = 0;
     106                } else {
     107                        spin(this, &spin_count);
     108                }               
     109        }
     110
     111        LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this);
     112}
     113
     114void runThread(processor * this, thread_h * dst) {
     115        coroutine * proc_ctx = get_coroutine(this->ctx);
     116        coroutine * thrd_ctx = get_coroutine(dst);
     117        thrd_ctx->last = proc_ctx;
     118
     119        // context switch to specified coroutine
     120        // Which is now the current_coroutine
     121        // LIB_DEBUG_PRINTF("Kernel : switching to ctx %p (from %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
     122        this->current_thread = dst;
     123        this->current_coroutine = thrd_ctx;
     124        CtxSwitch( proc_ctx->stack.context, thrd_ctx->stack.context );
     125        this->current_coroutine = proc_ctx;
     126        // LIB_DEBUG_PRINTF("Kernel : returned from ctx %p (to %p, current %p)\n", thrd_ctx, proc_ctx, current_coroutine);
     127
     128        // when CtxSwitch returns we are back in the processor coroutine
     129}
     130
     131void spin(processor * this, unsigned int * spin_count) {
     132        (*spin_count)++;
     133}
     134
     135//-----------------------------------------------------------------------------
     136// Scheduler routines
     137void thread_schedule( thread_h * thrd ) {
     138        assertf( thrd->next == NULL, "Expected null got %p", thrd->next );
     139        append( &systemProcessor->cltr->ready_queue, thrd );
     140}
     141
     142thread_h * nextThread(cluster * this) {
     143        return pop_head( &this->ready_queue );
     144}
     145
     146//-----------------------------------------------------------------------------
     147// Kernel storage
    43148#define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)]
    44149
     
    49154KERNEL_STORAGE(machine_context_t, mainThread_context);
    50155
    51 cluster * systemCluster;
    52 processor * systemProcessor;
    53 thread_h * mainThread;
    54 
    55 void kernel_startup(void)  __attribute__((constructor(101)));
    56 void kernel_shutdown(void) __attribute__((destructor(101)));
    57 
    58 //-----------------------------------------------------------------------------
    59 // Global state
    60 
    61 thread_local processor * this_processor;
    62 
    63 processor * get_this_processor() {
    64         return this_processor;
    65 }
    66 
    67 coroutine * this_coroutine(void) {
    68         return this_processor->current_coroutine;
    69 }
    70 
    71 thread_h * this_thread(void) {
    72         return this_processor->current_thread;
    73 }
    74 
    75156//-----------------------------------------------------------------------------
    76157// Main thread construction
    77 struct current_stack_info_t {
     158struct mainThread_info_t {
    78159        machine_context_t ctx; 
    79160        unsigned int size;              // size of stack
     
    85166};
    86167
    87 void ?{}( current_stack_info_t * this ) {
     168void ?{}( mainThread_info_t * this ) {
    88169        CtxGet( &this->ctx );
    89170        this->base = this->ctx.FP;
     
    99180}
    100181
    101 void ?{}( coStack_t * this, current_stack_info_t * info) {
     182void ?{}( coStack_t * this, mainThread_info_t * info) {
    102183        this->size = info->size;
    103184        this->storage = info->storage;
     
    109190}
    110191
    111 void ?{}( coroutine * this, current_stack_info_t * info) {
     192void ?{}( coroutine * this, mainThread_info_t * info) {
    112193        (&this->stack){ info };
    113194        this->name = "Main Thread";
     
    117198}
    118199
    119 void ?{}( thread_h * this, current_stack_info_t * info) {
     200void ?{}( thread_h * this, mainThread_info_t * info) {
    120201        (&this->c){ info };
    121 }
    122 
    123 //-----------------------------------------------------------------------------
    124 // Processor coroutine
    125 void ?{}(processorCtx_t * this, processor * proc) {
    126         (&this->c){};
    127         this->proc = proc;
    128         proc->ctx = this;
    129 }
    130 
    131 void ?{}(processorCtx_t * this, processor * proc, current_stack_info_t * info) {
    132         (&this->c){ info };
    133         this->proc = proc;
    134         proc->ctx = this;
    135 }
    136 
    137 void start(processor * this);
    138 
    139 void ?{}(processor * this) {
    140         this{ systemCluster };
    141 }
    142 
    143 void ?{}(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 
    153 void ?{}(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 
    165 void ^?{}(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 
    173 void ?{}(cluster * this) {
    174         ( &this->ready_queue ){};
    175         pthread_spin_init( &this->lock, PTHREAD_PROCESS_PRIVATE );
    176 }
    177 
    178 void ^?{}(cluster * this) {
    179         pthread_spin_destroy( &this->lock );
    180 }
    181 
    182 //-----------------------------------------------------------------------------
    183 // Processor running routines
    184 void main(processorCtx_t * ctx);
    185 thread_h * nextThread(cluster * this);
    186 void runThread(processor * this, thread_h * dst);
    187 void spin(processor * this, unsigned int * spin_count);
    188 
    189 void main(processorCtx_t * ctx) {
    190         processor * this = ctx->proc;
    191         LIB_DEBUG_PRINTF("Kernel : core %p starting\n", this);
    192 
    193         thread_h * readyThread = NULL;
    194         for( unsigned int spin_count = 0; ! this->terminated; spin_count++ ) {
    195                
    196                 readyThread = nextThread( this->cltr );
    197 
    198                 if(readyThread) {
    199                         runThread(this, readyThread);
    200                         spin_count = 0;
    201                 } else {
    202                         spin(this, &spin_count);
    203                 }               
    204         }
    205 
    206         LIB_DEBUG_PRINTF("Kernel : core %p unlocking thread\n", this);
    207         unlock( &this->lock );
    208         LIB_DEBUG_PRINTF("Kernel : core %p terminated\n", this);
    209 }
    210 
    211 void runThread(processor * this, thread_h * dst) {
    212         coroutine * proc_ctx = get_coroutine(this->ctx);
    213         coroutine * thrd_ctx = get_coroutine(dst);
    214         thrd_ctx->last = proc_ctx;
    215 
    216         // context switch to specified coroutine
    217         // Which is now the current_coroutine
    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;
    221         CtxSwitch( proc_ctx->stack.context, thrd_ctx->stack.context );
    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);
    224 
    225         // when CtxSwitch returns we are back in the processor coroutine
    226 }
    227 
    228 void spin(processor * this, unsigned int * spin_count) {
    229         (*spin_count)++;
    230 }
    231 
    232 void * 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 
    271 void 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
    286 void thread_schedule( thread_h * 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 
    293 thread_h * nextThread(cluster * this) {
    294         pthread_spinlock_guard guard = { &this->lock };
    295         return pop_head( &this->ready_queue );
    296202}
    297203
     
    304210        LIB_DEBUG_PRINTF("Kernel : Starting\n");       
    305211
    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 );
     212        mainThread_info_t ctx;
    314213
    315214        // Start by initializing the main thread
    316215        mainThread = (thread_h *)&mainThread_storage;
    317         mainThread{ &info };
     216        mainThread{ &ctx };
    318217
    319218        // Initialize the system cluster
     
    321220        systemCluster{};
    322221
    323         // Initialize the system processor and the system processor ctx
     222        // Initialize the system processor
     223        systemProcessor = (processor *)&systemProcessor_storage;
     224        systemProcessor{ systemCluster };
     225
     226        // Initialize the system processor ctx
    324227        // (the coroutine that contains the processing control flow)
    325         systemProcessor = (processor *)&systemProcessor_storage;
    326         systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage };
     228        systemProcessor->ctx = (processorCtx_t *)&systemProcessorCtx_storage;
     229        systemProcessor->ctx{ systemProcessor };
    327230
    328231        // Add the main thread to the ready queue
     
    383286
    384287void 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         }
     288        append( &this->blocked, this_thread() );
    389289        suspend();
    390290}
Note: See TracChangeset for help on using the changeset viewer.