source: libcfa/src/concurrency/kernel.cfa @ 1805b1b

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 1805b1b was 1805b1b, checked in by Peter A. Buhr <pabuhr@…>, 5 years ago

refactor pthread_create into create_pthread, change NULL to 0p

  • Property mode set to 100644
File size: 27.7 KB
RevLine 
[8118303]1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// kernel.c --
8//
9// Author           : Thierry Delisle
[75f3522]10// Created On       : Tue Jan 17 12:27:26 2017
[6b0b624]11// Last Modified By : Peter A. Buhr
[1805b1b]12// Last Modified On : Sun Dec  1 17:52:57 2019
13// Update Count     : 45
[8118303]14//
15
[2026bb6]16#define __cforall_thread__
17
[8118303]18//C Includes
[c84e80a]19#include <stddef.h>
[214e8da]20#include <errno.h>
[ea8b2f7]21#include <string.h>
[eb2e723]22extern "C" {
[9d944b2]23#include <stdio.h>
[8fcbb4c]24#include <fenv.h>
[eb2e723]25#include <sys/resource.h>
[58b6d1b]26#include <signal.h>
[9d944b2]27#include <unistd.h>
[27f5f71]28#include <limits.h>                                                                             // PTHREAD_STACK_MIN
[eb2e723]29}
[8118303]30
31//CFA Includes
[58b6d1b]32#include "time.hfa"
[73abe95]33#include "kernel_private.hfa"
34#include "preemption.hfa"
35#include "startup.hfa"
[8118303]36
37//Private includes
38#define __CFA_INVOKE_PRIVATE__
39#include "invoke.h"
40
[deca0f5]41//-----------------------------------------------------------------------------
42// Some assembly required
[1805b1b]43#if defined( __i386 )
[deca0f5]44        #define CtxGet( ctx )        \
45                __asm__ volatile (     \
46                        "movl %%esp,%0\n"\
47                        "movl %%ebp,%1\n"\
48                        : "=rm" (ctx.SP),\
49                                "=rm" (ctx.FP) \
50                )
51
52        // mxcr : SSE Status and Control bits (control bits are preserved across function calls)
53        // fcw  : X87 FPU control word (preserved across function calls)
54        #define __x87_store         \
55                uint32_t __mxcr;      \
56                uint16_t __fcw;       \
57                __asm__ volatile (    \
58                        "stmxcsr %0\n"  \
59                        "fnstcw  %1\n"  \
60                        : "=m" (__mxcr),\
61                                "=m" (__fcw)  \
62                )
63
64        #define __x87_load         \
65                __asm__ volatile (   \
66                        "fldcw  %1\n"  \
67                        "ldmxcsr %0\n" \
68                        ::"m" (__mxcr),\
69                                "m" (__fcw)  \
70                )
71
72#elif defined( __x86_64 )
73        #define CtxGet( ctx )        \
74                __asm__ volatile (     \
75                        "movq %%rsp,%0\n"\
76                        "movq %%rbp,%1\n"\
77                        : "=rm" (ctx.SP),\
78                                "=rm" (ctx.FP) \
79                )
80
81        #define __x87_store         \
82                uint32_t __mxcr;      \
83                uint16_t __fcw;       \
84                __asm__ volatile (    \
85                        "stmxcsr %0\n"  \
86                        "fnstcw  %1\n"  \
87                        : "=m" (__mxcr),\
88                                "=m" (__fcw)  \
89                )
90
91        #define __x87_load          \
92                __asm__ volatile (    \
93                        "fldcw  %1\n"   \
94                        "ldmxcsr %0\n"  \
95                        :: "m" (__mxcr),\
96                                "m" (__fcw)  \
97                )
98
99
100#elif defined( __ARM_ARCH )
101#define CtxGet( ctx ) __asm__ ( \
102                "mov %0,%%sp\n"   \
103                "mov %1,%%r11\n"   \
104        : "=rm" (ctx.SP), "=rm" (ctx.FP) )
105#else
106        #error unknown hardware architecture
107#endif
108
109//-----------------------------------------------------------------------------
[2ac095d]110//Start and stop routine for the kernel, declared first to make sure they run first
[c29c342]111static void kernel_startup(void)  __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));
112static void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));
[2ac095d]113
[8def349]114//-----------------------------------------------------------------------------
115// Kernel storage
[b2f6113]116KERNEL_STORAGE(cluster,         mainCluster);
117KERNEL_STORAGE(processor,       mainProcessor);
118KERNEL_STORAGE(thread_desc,     mainThread);
119KERNEL_STORAGE(__stack_t,       mainThreadCtx);
[8def349]120
[de6319f]121cluster     * mainCluster;
122processor   * mainProcessor;
[348006f]123thread_desc * mainThread;
[eb2e723]124
[ea8b2f7]125extern "C" {
[1805b1b]126        struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters;
[ea8b2f7]127}
[de94a60]128
[b2f6113]129size_t __page_size = 0;
130
[bd98b58]131//-----------------------------------------------------------------------------
132// Global state
[afc2427]133thread_local struct KernelThreadData kernelTLS __attribute__ ((tls_model ( "initial-exec" ))) = {
[1805b1b]134        NULL,                                                                                           // cannot use 0p
[b10affd]135        NULL,
[27f5f71]136        { NULL, 1, false, false },
[21184e3]137        6u //this should be seeded better but due to a bug calling rdtsc doesn't work
[b10affd]138};
[c84e80a]139
140//-----------------------------------------------------------------------------
[de6319f]141// Struct to steal stack
[8def349]142struct current_stack_info_t {
[1805b1b]143        __stack_t * storage;                                                            // pointer to stack object
144        void * base;                                                                            // base of stack
145        void * limit;                                                                           // stack grows towards stack limit
146        void * context;                                                                         // address of cfa_context_t
[c84e80a]147};
148
[242a902]149void ?{}( current_stack_info_t & this ) {
[b2f6113]150        __stack_context_t ctx;
151        CtxGet( ctx );
152        this.base = ctx.FP;
[8def349]153
154        rlimit r;
[132fad4]155        getrlimit( RLIMIT_STACK, &r);
[69a61d2]156        size_t size = r.rlim_cur;
[8def349]157
[69a61d2]158        this.limit = (void *)(((intptr_t)this.base) - size);
[9236060]159        this.context = &storage_mainThreadCtx;
[8def349]160}
161
[de6319f]162//-----------------------------------------------------------------------------
163// Main thread construction
[8def349]164
[65deb18]165void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) {
[b2f6113]166        stack.storage = info->storage;
167        with(*stack.storage) {
168                limit     = info->limit;
169                base      = info->base;
170        }
[ffe2fad]171        __attribute__((may_alias)) intptr_t * istorage = (intptr_t*) &stack.storage;
172        *istorage |= 0x1;
[65deb18]173        name = "Main Thread";
174        state = Start;
[1805b1b]175        starter = 0p;
176        last = 0p;
177        cancellation = 0p;
[8def349]178}
179
[65deb18]180void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) {
[e8e457e]181        state = Start;
[65deb18]182        self_cor{ info };
[82c948c]183        curr_cor = &self_cor;
[de6319f]184        curr_cluster = mainCluster;
[82c948c]185        self_mon.owner = &this;
186        self_mon.recursion = 1;
187        self_mon_p = &self_mon;
[1805b1b]188        next = 0p;
[de94a60]189
[1805b1b]190        node.next = 0p;
191        node.prev = 0p;
[a1a17a74]192        doregister(curr_cluster, this);
[82c948c]193
194        monitors{ &self_mon_p, 1, (fptr_t)0 };
[8def349]195}
[c84e80a]196
[8def349]197//-----------------------------------------------------------------------------
198// Processor coroutine
[de6319f]199void ?{}(processorCtx_t & this) {
[39fea2f]200
[8def349]201}
202
[39fea2f]203// Construct the processor context of non-main processors
[c29c342]204static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {
[242a902]205        (this.__cor){ info };
206        this.proc = proc;
[8def349]207}
208
[c29c342]209static void start(processor * this);
[de6319f]210void ?{}(processor & this, const char * name, cluster & cltr) with( this ) {
211        this.name = name;
212        this.cltr = &cltr;
[c40e7c5]213        terminated{ 0 };
214        do_terminate = false;
[1805b1b]215        preemption_alarm = 0p;
[c40e7c5]216        pending_preemption = false;
[094476d]217        runner.proc = &this;
[8def349]218
[85b1deb]219        idleLock{};
[6b4cdd3]220
[242a902]221        start( &this );
[c84e80a]222}
223
[65deb18]224void ^?{}(processor & this) with( this ){
[ea8b2f7]225        if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) {
[36982fc]226                __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);
[85b1deb]227
228                __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED);
229                wake( &this );
230
[65deb18]231                P( terminated );
[14a61b5]232                verify( kernelTLS.this_processor != &this);
[8def349]233        }
[6b4cdd3]234
[1805b1b]235        pthread_join( kernel_thread, 0p );
[27f5f71]236        free( this.stack );
[8def349]237}
238
[de6319f]239void ?{}(cluster & this, const char * name, Duration preemption_rate) with( this ) {
240        this.name = name;
241        this.preemption_rate = preemption_rate;
[65deb18]242        ready_queue{};
243        ready_queue_lock{};
[de94a60]244
245        procs{ __get };
246        idles{ __get };
[a1a17a74]247        threads{ __get };
[de94a60]248
249        doregister(this);
[8def349]250}
251
[242a902]252void ^?{}(cluster & this) {
[de94a60]253        unregister(this);
[c84e80a]254}
255
[75f3522]256//=============================================================================================
257// Kernel Scheduling logic
258//=============================================================================================
[c29c342]259static void runThread(processor * this, thread_desc * dst);
260static void finishRunning(processor * this);
261static void halt(processor * this);
262
[8fcbb4c]263//Main of the processor contexts
[83a071f9]264void main(processorCtx_t & runner) {
[21184e3]265        // Because of a bug, we couldn't initialized the seed on construction
266        // Do it here
[57c764c]267        kernelTLS.rand_seed ^= rdtscl();
[21184e3]268
[83a071f9]269        processor * this = runner.proc;
[094476d]270        verify(this);
[c81ebf9]271
[36982fc]272        __cfaabi_dbg_print_safe("Kernel : core %p starting\n", this);
[8118303]273
[de94a60]274        doregister(this->cltr, this);
275
[75f3522]276        {
[c81ebf9]277                // Setup preemption data
278                preemption_scope scope = { this };
279
[36982fc]280                __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
[8118303]281
[1805b1b]282                thread_desc * readyThread = 0p;
[ea8b2f7]283                for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ )
[75f3522]284                {
[c81ebf9]285                        readyThread = nextThread( this->cltr );
[75f3522]286
[c81ebf9]287                        if(readyThread)
288                        {
[14a61b5]289                                verify( ! kernelTLS.preemption_state.enabled );
[4e6fb8e]290
[c81ebf9]291                                runThread(this, readyThread);
[75f3522]292
[14a61b5]293                                verify( ! kernelTLS.preemption_state.enabled );
[4e6fb8e]294
[c81ebf9]295                                //Some actions need to be taken from the kernel
296                                finishRunning(this);
297
298                                spin_count = 0;
299                        }
300                        else
301                        {
[ea8b2f7]302                                // spin(this, &spin_count);
303                                halt(this);
[c81ebf9]304                        }
305                }
306
[36982fc]307                __cfaabi_dbg_print_safe("Kernel : core %p stopping\n", this);
[c84e80a]308        }
[8118303]309
[de94a60]310        unregister(this->cltr, this);
311
[4cedd9f]312        V( this->terminated );
[bdeba0b]313
[36982fc]314        __cfaabi_dbg_print_safe("Kernel : core %p terminated\n", this);
[c84e80a]315}
316
[5c1a531]317static int * __volatile_errno() __attribute__((noinline));
318static int * __volatile_errno() { asm(""); return &errno; }
319
[14a61b5]320// KERNEL ONLY
[1c273d0]321// runThread runs a thread by context switching
322// from the processor coroutine to the target thread
[e8e457e]323static void runThread(processor * this, thread_desc * thrd_dst) {
[094476d]324        coroutine_desc * proc_cor = get_coroutine(this->runner);
[1c273d0]325
[14a61b5]326        // Reset the terminating actions here
[db6f06a]327        this->finish.action_code = No_Action;
[8fcbb4c]328
[14a61b5]329        // Update global state
[e8e457e]330        kernelTLS.this_thread = thrd_dst;
331
332        // set state of processor coroutine to inactive and the thread to active
333        proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
334        thrd_dst->state = Active;
335
336        // set context switch to the thread that the processor is executing
337        verify( thrd_dst->context.SP );
338        CtxSwitch( &proc_cor->context, &thrd_dst->context );
339        // when CtxSwitch returns we are back in the processor coroutine
[75f3522]340
[e8e457e]341        // set state of processor coroutine to active and the thread to inactive
342        thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive;
343        proc_cor->state = Active;
[75f3522]344}
345
[14a61b5]346// KERNEL_ONLY
[c29c342]347static void returnToKernel() {
[14a61b5]348        coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
[e8e457e]349        thread_desc * thrd_src = kernelTLS.this_thread;
350
351        // set state of current coroutine to inactive
352        thrd_src->state = thrd_src->state == Halted ? Halted : Inactive;
353        proc_cor->state = Active;
[5c1a531]354        int local_errno = *__volatile_errno();
[deca0f5]355        #if defined( __i386 ) || defined( __x86_64 )
356                __x87_store;
357        #endif
[e8e457e]358
359        // set new coroutine that the processor is executing
360        // and context switch to it
361        verify( proc_cor->context.SP );
362        CtxSwitch( &thrd_src->context, &proc_cor->context );
363
364        // set state of new coroutine to active
365        proc_cor->state = proc_cor->state == Halted ? Halted : Inactive;
366        thrd_src->state = Active;
[deca0f5]367
368        #if defined( __i386 ) || defined( __x86_64 )
369                __x87_load;
370        #endif
[5c1a531]371        *__volatile_errno() = local_errno;
[82c948c]372}
373
[14a61b5]374// KERNEL_ONLY
[1c273d0]375// Once a thread has finished running, some of
[75f3522]376// its final actions must be executed from the kernel
[c29c342]377static void finishRunning(processor * this) with( this->finish ) {
[09800e9]378        verify( ! kernelTLS.preemption_state.enabled );
379        choose( action_code ) {
380        case No_Action:
381                break;
382        case Release:
[65deb18]383                unlock( *lock );
[09800e9]384        case Schedule:
[65deb18]385                ScheduleThread( thrd );
[09800e9]386        case Release_Schedule:
[65deb18]387                unlock( *lock );
388                ScheduleThread( thrd );
[09800e9]389        case Release_Multi:
[65deb18]390                for(int i = 0; i < lock_count; i++) {
391                        unlock( *locks[i] );
[0c78741]392                }
[09800e9]393        case Release_Multi_Schedule:
[65deb18]394                for(int i = 0; i < lock_count; i++) {
395                        unlock( *locks[i] );
[0c78741]396                }
[65deb18]397                for(int i = 0; i < thrd_count; i++) {
398                        ScheduleThread( thrds[i] );
[0c78741]399                }
[09800e9]400        case Callback:
401                callback();
402        default:
403                abort("KERNEL ERROR: Unexpected action to run after thread");
[8fcbb4c]404        }
[c84e80a]405}
406
[14a61b5]407// KERNEL_ONLY
[0c92c9f]408// Context invoker for processors
409// This is the entry point for processors (kernel threads)
410// It effectively constructs a coroutine by stealing the pthread stack
[c29c342]411static void * CtxInvokeProcessor(void * arg) {
[8def349]412        processor * proc = (processor *) arg;
[14a61b5]413        kernelTLS.this_processor = proc;
[1805b1b]414        kernelTLS.this_thread    = 0p;
[14a61b5]415        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
[8def349]416        // SKULLDUGGERY: We want to create a context for the processor coroutine
417        // which is needed for the 2-step context switch. However, there is no reason
[1c273d0]418        // to waste the perfectly valid stack create by pthread.
[8def349]419        current_stack_info_t info;
[b2f6113]420        __stack_t ctx;
421        info.storage = &ctx;
[094476d]422        (proc->runner){ proc, &info };
[8def349]423
[b2f6113]424        __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);
[8fcbb4c]425
[0c92c9f]426        //Set global state
[1805b1b]427        kernelTLS.this_thread = 0p;
[8def349]428
429        //We now have a proper context from which to schedule threads
[094476d]430        __cfaabi_dbg_print_safe("Kernel : core %p created (%p, %p)\n", proc, &proc->runner, &ctx);
[8def349]431
[1c273d0]432        // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
433        // resume it to start it like it normally would, it will just context switch
434        // back to here. Instead directly call the main since we already are on the
[8def349]435        // appropriate stack.
[094476d]436        get_coroutine(proc->runner)->state = Active;
437        main( proc->runner );
438        get_coroutine(proc->runner)->state = Halted;
[8def349]439
[0c92c9f]440        // Main routine of the core returned, the core is now fully terminated
[094476d]441        __cfaabi_dbg_print_safe("Kernel : core %p main ended (%p)\n", proc, &proc->runner);
[8def349]442
[1805b1b]443        return 0p;
[c84e80a]444}
445
[1805b1b]446static void Abort( int ret, const char * func ) {
[27f5f71]447        if ( ret ) {
[1805b1b]448                abort( "%s : internal error, error(%d) %s.", func, ret, strerror( ret ) );
[27f5f71]449        } // if
[1805b1b]450} // Abort
451
452void * create_pthread( pthread_t * pthread, void * (*start)(void *), void * arg ) {
453        pthread_attr_t attr;
454
455        Abort( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
456
457#ifdef __CFA_DEBUG__
458        size_t guardsize;
459        Abort( pthread_attr_getguardsize( &attr, &guardsize ), "pthread_attr_getguardsize" );
460        Abort( pthread_attr_setguardsize( &attr, guardsize ), "pthread_attr_setguardsize" );
461#endif
[27f5f71]462
463        size_t stacksize;
[1805b1b]464        Abort( pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" ); // default stack size, normally defined by shell limit
[27f5f71]465        assert( stacksize >= PTHREAD_STACK_MIN );
[1805b1b]466        void * stack = malloc( stacksize );
467        Abort( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );
[27f5f71]468
[1805b1b]469        Abort( pthread_create( pthread, &attr, start, arg ), "pthread_create" );
470        return stack;
471}
[27f5f71]472
[1805b1b]473static void start(processor * this) {
474        __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this);
475
476        this->stack = create_pthread( &this->kernel_thread, CtxInvokeProcessor, (void *)this );
[eb2e723]477
[36982fc]478        __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
[eb2e723]479}
480
[14a61b5]481// KERNEL_ONLY
[e8e457e]482void kernel_first_resume( processor * this ) {
483        thread_desc * src = mainThread;
[094476d]484        coroutine_desc * dst = get_coroutine(this->runner);
[b69ea6b]485
[14a61b5]486        verify( ! kernelTLS.preemption_state.enabled );
[b69ea6b]487
[b2f6113]488        __stack_prepare( &dst->stack, 65000 );
[094476d]489        CtxStart(&this->runner, CtxInvokeCoroutine);
[b69ea6b]490
[14a61b5]491        verify( ! kernelTLS.preemption_state.enabled );
[b69ea6b]492
[e8e457e]493        dst->last = &src->self_cor;
494        dst->starter = dst->starter ? dst->starter : &src->self_cor;
[b69ea6b]495
496        // set state of current coroutine to inactive
497        src->state = src->state == Halted ? Halted : Inactive;
498
499        // context switch to specified coroutine
[69a61d2]500        verify( dst->context.SP );
[b2f6113]501        CtxSwitch( &src->context, &dst->context );
[b69ea6b]502        // when CtxSwitch returns we are back in the src coroutine
503
504        // set state of new coroutine to active
505        src->state = Active;
506
[14a61b5]507        verify( ! kernelTLS.preemption_state.enabled );
[b69ea6b]508}
509
[e8e457e]510// KERNEL_ONLY
511void kernel_last_resume( processor * this ) {
512        coroutine_desc * src = &mainThread->self_cor;
513        coroutine_desc * dst = get_coroutine(this->runner);
514
515        verify( ! kernelTLS.preemption_state.enabled );
516        verify( dst->starter == src );
517        verify( dst->context.SP );
518
519        // context switch to the processor
520        CtxSwitch( &src->context, &dst->context );
521}
522
[8def349]523//-----------------------------------------------------------------------------
524// Scheduler routines
[14a61b5]525
526// KERNEL ONLY
[348006f]527void ScheduleThread( thread_desc * thrd ) {
[135b431]528        verify( thrd );
[e8e457e]529        verify( thrd->state != Halted );
[1c273d0]530
[14a61b5]531        verify( ! kernelTLS.preemption_state.enabled );
[690f13c]532
[1805b1b]533        verifyf( thrd->next == 0p, "Expected null got %p", thrd->next );
[1c273d0]534
[de6319f]535        with( *thrd->curr_cluster ) {
[65deb18]536                lock  ( ready_queue_lock __cfaabi_dbg_ctx2 );
[6b4cdd3]537                bool was_empty = !(ready_queue != 0);
[65deb18]538                append( ready_queue, thrd );
539                unlock( ready_queue_lock );
[6b4cdd3]540
[85b1deb]541                if(was_empty) {
[6b4cdd3]542                        lock      (proc_list_lock __cfaabi_dbg_ctx2);
543                        if(idles) {
[85b1deb]544                                wake_fast(idles.head);
[6b4cdd3]545                        }
546                        unlock    (proc_list_lock);
547                }
[85b1deb]548                else if( struct processor * idle = idles.head ) {
549                        wake_fast(idle);
550                }
551
[65deb18]552        }
[1c273d0]553
[14a61b5]554        verify( ! kernelTLS.preemption_state.enabled );
[db6f06a]555}
556
[14a61b5]557// KERNEL ONLY
[65deb18]558thread_desc * nextThread(cluster * this) with( *this ) {
[14a61b5]559        verify( ! kernelTLS.preemption_state.enabled );
[65deb18]560        lock( ready_queue_lock __cfaabi_dbg_ctx2 );
561        thread_desc * head = pop_head( ready_queue );
562        unlock( ready_queue_lock );
[14a61b5]563        verify( ! kernelTLS.preemption_state.enabled );
[db6f06a]564        return head;
[eb2e723]565}
566
[82ff5845]567void BlockInternal() {
568        disable_interrupts();
[14a61b5]569        verify( ! kernelTLS.preemption_state.enabled );
[82c948c]570        returnToKernel();
[14a61b5]571        verify( ! kernelTLS.preemption_state.enabled );
[36982fc]572        enable_interrupts( __cfaabi_dbg_ctx );
[75f3522]573}
574
[ea7d2b0]575void BlockInternal( __spinlock_t * lock ) {
[82ff5845]576        disable_interrupts();
[14a61b5]577        with( *kernelTLS.this_processor ) {
[de6319f]578                finish.action_code = Release;
579                finish.lock        = lock;
580        }
[0b33412]581
[afd550c]582        verify( ! kernelTLS.preemption_state.enabled );
[82c948c]583        returnToKernel();
[afd550c]584        verify( ! kernelTLS.preemption_state.enabled );
[0b33412]585
[36982fc]586        enable_interrupts( __cfaabi_dbg_ctx );
[db6f06a]587}
588
[82ff5845]589void BlockInternal( thread_desc * thrd ) {
590        disable_interrupts();
[14a61b5]591        with( * kernelTLS.this_processor ) {
[de6319f]592                finish.action_code = Schedule;
593                finish.thrd        = thrd;
594        }
[0b33412]595
[14a61b5]596        verify( ! kernelTLS.preemption_state.enabled );
[82c948c]597        returnToKernel();
[14a61b5]598        verify( ! kernelTLS.preemption_state.enabled );
[0b33412]599
[36982fc]600        enable_interrupts( __cfaabi_dbg_ctx );
[db6f06a]601}
602
[ea7d2b0]603void BlockInternal( __spinlock_t * lock, thread_desc * thrd ) {
[97e3296]604        assert(thrd);
[82ff5845]605        disable_interrupts();
[14a61b5]606        with( * kernelTLS.this_processor ) {
[de6319f]607                finish.action_code = Release_Schedule;
608                finish.lock        = lock;
609                finish.thrd        = thrd;
610        }
[0b33412]611
[14a61b5]612        verify( ! kernelTLS.preemption_state.enabled );
[82c948c]613        returnToKernel();
[14a61b5]614        verify( ! kernelTLS.preemption_state.enabled );
[0b33412]615
[36982fc]616        enable_interrupts( __cfaabi_dbg_ctx );
[eb2e723]617}
618
[ea7d2b0]619void BlockInternal(__spinlock_t * locks [], unsigned short count) {
[82ff5845]620        disable_interrupts();
[14a61b5]621        with( * kernelTLS.this_processor ) {
[de6319f]622                finish.action_code = Release_Multi;
623                finish.locks       = locks;
624                finish.lock_count  = count;
625        }
[0b33412]626
[14a61b5]627        verify( ! kernelTLS.preemption_state.enabled );
[82c948c]628        returnToKernel();
[14a61b5]629        verify( ! kernelTLS.preemption_state.enabled );
[0b33412]630
[36982fc]631        enable_interrupts( __cfaabi_dbg_ctx );
[0c78741]632}
633
[ea7d2b0]634void BlockInternal(__spinlock_t * locks [], unsigned short lock_count, thread_desc * thrds [], unsigned short thrd_count) {
[82ff5845]635        disable_interrupts();
[14a61b5]636        with( *kernelTLS.this_processor ) {
[de6319f]637                finish.action_code = Release_Multi_Schedule;
638                finish.locks       = locks;
639                finish.lock_count  = lock_count;
640                finish.thrds       = thrds;
641                finish.thrd_count  = thrd_count;
642        }
[0b33412]643
[14a61b5]644        verify( ! kernelTLS.preemption_state.enabled );
[82c948c]645        returnToKernel();
[14a61b5]646        verify( ! kernelTLS.preemption_state.enabled );
[0b33412]647
[36982fc]648        enable_interrupts( __cfaabi_dbg_ctx );
[0c78741]649}
650
[09800e9]651void BlockInternal(__finish_callback_fptr_t callback) {
652        disable_interrupts();
653        with( *kernelTLS.this_processor ) {
654                finish.action_code = Callback;
655                finish.callback    = callback;
656        }
657
658        verify( ! kernelTLS.preemption_state.enabled );
659        returnToKernel();
660        verify( ! kernelTLS.preemption_state.enabled );
661
662        enable_interrupts( __cfaabi_dbg_ctx );
663}
664
[14a61b5]665// KERNEL ONLY
[ea7d2b0]666void LeaveThread(__spinlock_t * lock, thread_desc * thrd) {
[14a61b5]667        verify( ! kernelTLS.preemption_state.enabled );
668        with( * kernelTLS.this_processor ) {
[de6319f]669                finish.action_code = thrd ? Release_Schedule : Release;
670                finish.lock        = lock;
671                finish.thrd        = thrd;
672        }
[f2b12406]673
[82c948c]674        returnToKernel();
[f2b12406]675}
676
[fa21ac9]677//=============================================================================================
678// Kernel Setup logic
679//=============================================================================================
[eb2e723]680//-----------------------------------------------------------------------------
681// Kernel boot procedures
[c29c342]682static void kernel_startup(void) {
[14a61b5]683        verify( ! kernelTLS.preemption_state.enabled );
[36982fc]684        __cfaabi_dbg_print_safe("Kernel : Starting\n");
[eb2e723]685
[b2f6113]686        __page_size = sysconf( _SC_PAGESIZE );
687
[ea8b2f7]688        __cfa_dbg_global_clusters.list{ __get };
689        __cfa_dbg_global_clusters.lock{};
[de94a60]690
[de6319f]691        // Initialize the main cluster
692        mainCluster = (cluster *)&storage_mainCluster;
693        (*mainCluster){"Main Cluster"};
694
695        __cfaabi_dbg_print_safe("Kernel : Main cluster ready\n");
696
[eb2e723]697        // Start by initializing the main thread
[1c273d0]698        // SKULLDUGGERY: the mainThread steals the process main thread
[969b3fe]699        // which will then be scheduled by the mainProcessor normally
700        mainThread = (thread_desc *)&storage_mainThread;
[8fcbb4c]701        current_stack_info_t info;
[b2f6113]702        info.storage = (__stack_t*)&storage_mainThreadCtx;
[83a071f9]703        (*mainThread){ &info };
[eb2e723]704
[36982fc]705        __cfaabi_dbg_print_safe("Kernel : Main thread ready\n");
[fa21ac9]706
[bd98b58]707
[de6319f]708
709        // Construct the processor context of the main processor
710        void ?{}(processorCtx_t & this, processor * proc) {
711                (this.__cor){ "Processor" };
[1805b1b]712                this.__cor.starter = 0p;
[de6319f]713                this.proc = proc;
714        }
715
716        void ?{}(processor & this) with( this ) {
717                name = "Main Processor";
718                cltr = mainCluster;
719                terminated{ 0 };
720                do_terminate = false;
[1805b1b]721                preemption_alarm = 0p;
[de6319f]722                pending_preemption = false;
723                kernel_thread = pthread_self();
724
725                runner{ &this };
726                __cfaabi_dbg_print_safe("Kernel : constructed main processor context %p\n", &runner);
727        }
[fa21ac9]728
[969b3fe]729        // Initialize the main processor and the main processor ctx
[eb2e723]730        // (the coroutine that contains the processing control flow)
[969b3fe]731        mainProcessor = (processor *)&storage_mainProcessor;
[de6319f]732        (*mainProcessor){};
[eb2e723]733
[dcb42b8]734        //initialize the global state variables
[14a61b5]735        kernelTLS.this_processor = mainProcessor;
736        kernelTLS.this_thread    = mainThread;
[eb2e723]737
[82ff5845]738        // Enable preemption
739        kernel_start_preemption();
740
[969b3fe]741        // Add the main thread to the ready queue
742        // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
743        ScheduleThread(mainThread);
744
745        // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
[dcb42b8]746        // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that
[1c273d0]747        // mainThread is on the ready queue when this call is made.
[14a61b5]748        kernel_first_resume( kernelTLS.this_processor );
[eb2e723]749
[dcb42b8]750
751
752        // THE SYSTEM IS NOW COMPLETELY RUNNING
[36982fc]753        __cfaabi_dbg_print_safe("Kernel : Started\n--------------------------------------------------\n\n");
[82ff5845]754
[14a61b5]755        verify( ! kernelTLS.preemption_state.enabled );
[36982fc]756        enable_interrupts( __cfaabi_dbg_ctx );
[afd550c]757        verify( TL_GET( preemption_state.enabled ) );
[eb2e723]758}
759
[c29c342]760static void kernel_shutdown(void) {
[36982fc]761        __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
[eb2e723]762
[afd550c]763        verify( TL_GET( preemption_state.enabled ) );
[4e6fb8e]764        disable_interrupts();
[14a61b5]765        verify( ! kernelTLS.preemption_state.enabled );
[4e6fb8e]766
[969b3fe]767        // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
[dcb42b8]768        // When its coroutine terminates, it return control to the mainThread
769        // which is currently here
[ea8b2f7]770        __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);
[e8e457e]771        kernel_last_resume( kernelTLS.this_processor );
[ea8b2f7]772        mainThread->self_cor.state = Halted;
[eb2e723]773
[dcb42b8]774        // THE SYSTEM IS NOW COMPLETELY STOPPED
[eb2e723]775
[82ff5845]776        // Disable preemption
777        kernel_stop_preemption();
778
[969b3fe]779        // Destroy the main processor and its context in reverse order of construction
[dcb42b8]780        // These were manually constructed so we need manually destroy them
[094476d]781        ^(mainProcessor->runner){};
[969b3fe]782        ^(mainProcessor){};
[eb2e723]783
[dcb42b8]784        // Final step, destroy the main thread since it is no longer needed
785        // Since we provided a stack to this taxk it will not destroy anything
[eb2e723]786        ^(mainThread){};
787
[ea8b2f7]788        ^(__cfa_dbg_global_clusters.list){};
789        ^(__cfa_dbg_global_clusters.lock){};
[a1a17a74]790
[36982fc]791        __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n");
[9d944b2]792}
793
[14a61b5]794//=============================================================================================
795// Kernel Quiescing
796//=============================================================================================
[c29c342]797static void halt(processor * this) with( *this ) {
[85b1deb]798        // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) );
[ea8b2f7]799
[6b4cdd3]800        with( *cltr ) {
801                lock      (proc_list_lock __cfaabi_dbg_ctx2);
802                remove    (procs, *this);
803                push_front(idles, *this);
804                unlock    (proc_list_lock);
805        }
[14a61b5]806
[6b4cdd3]807        __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);
[14a61b5]808
[85b1deb]809        wait( idleLock );
[14a61b5]810
[6b4cdd3]811        __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);
[14a61b5]812
[6b4cdd3]813        with( *cltr ) {
814                lock      (proc_list_lock __cfaabi_dbg_ctx2);
815                remove    (idles, *this);
816                push_front(procs, *this);
817                unlock    (proc_list_lock);
818        }
819}
820
[dbe9b08]821//=============================================================================================
822// Unexpected Terminating logic
823//=============================================================================================
[ea7d2b0]824static __spinlock_t kernel_abort_lock;
[9d944b2]825static bool kernel_abort_called = false;
826
[afd550c]827void * kernel_abort(void) __attribute__ ((__nothrow__)) {
[9d944b2]828        // abort cannot be recursively entered by the same or different processors because all signal handlers return when
829        // the globalAbort flag is true.
[36982fc]830        lock( kernel_abort_lock __cfaabi_dbg_ctx2 );
[9d944b2]831
832        // first task to abort ?
[de94a60]833        if ( kernel_abort_called ) {                    // not first task to abort ?
[ea7d2b0]834                unlock( kernel_abort_lock );
[1c273d0]835
[9d944b2]836                sigset_t mask;
837                sigemptyset( &mask );
[de94a60]838                sigaddset( &mask, SIGALRM );            // block SIGALRM signals
839                sigsuspend( &mask );                    // block the processor to prevent further damage during abort
840                _exit( EXIT_FAILURE );                  // if processor unblocks before it is killed, terminate it
841        }
842        else {
843                kernel_abort_called = true;
844                unlock( kernel_abort_lock );
[9d944b2]845        }
846
[14a61b5]847        return kernelTLS.this_thread;
[9d944b2]848}
849
850void kernel_abort_msg( void * kernel_data, char * abort_text, int abort_text_size ) {
851        thread_desc * thrd = kernel_data;
852
[de94a60]853        if(thrd) {
854                int len = snprintf( abort_text, abort_text_size, "Error occurred while executing thread %.256s (%p)", thrd->self_cor.name, thrd );
[1c40091]855                __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
[de94a60]856
[212c2187]857                if ( &thrd->self_cor != thrd->curr_cor ) {
858                        len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor );
[1c40091]859                        __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
[de94a60]860                }
861                else {
[1c40091]862                        __cfaabi_bits_write( STDERR_FILENO, ".\n", 2 );
[de94a60]863                }
[1c273d0]864        }
[9d944b2]865        else {
[de94a60]866                int len = snprintf( abort_text, abort_text_size, "Error occurred outside of any thread.\n" );
[1c40091]867                __cfaabi_bits_write( STDERR_FILENO, abort_text, len );
[9d944b2]868        }
869}
870
[2b8bc41]871int kernel_abort_lastframe( void ) __attribute__ ((__nothrow__)) {
[14a61b5]872        return get_coroutine(kernelTLS.this_thread) == get_coroutine(mainThread) ? 4 : 2;
[2b8bc41]873}
874
[de94a60]875static __spinlock_t kernel_debug_lock;
876
[9d944b2]877extern "C" {
[1c40091]878        void __cfaabi_bits_acquire() {
[36982fc]879                lock( kernel_debug_lock __cfaabi_dbg_ctx2 );
[9d944b2]880        }
881
[1c40091]882        void __cfaabi_bits_release() {
[ea7d2b0]883                unlock( kernel_debug_lock );
[9d944b2]884        }
[8118303]885}
886
[fa21ac9]887//=============================================================================================
888// Kernel Utilities
889//=============================================================================================
[bd98b58]890//-----------------------------------------------------------------------------
891// Locks
[242a902]892void  ?{}( semaphore & this, int count = 1 ) {
893        (this.lock){};
894        this.count = count;
895        (this.waiting){};
[db6f06a]896}
[242a902]897void ^?{}(semaphore & this) {}
[db6f06a]898
[65deb18]899void P(semaphore & this) with( this ){
900        lock( lock __cfaabi_dbg_ctx2 );
901        count -= 1;
902        if ( count < 0 ) {
[bdeba0b]903                // queue current task
[14a61b5]904                append( waiting, kernelTLS.this_thread );
[bdeba0b]905
906                // atomically release spin lock and block
[65deb18]907                BlockInternal( &lock );
[8def349]908        }
[4e6fb8e]909        else {
[65deb18]910            unlock( lock );
[4e6fb8e]911        }
[bd98b58]912}
913
[65deb18]914void V(semaphore & this) with( this ) {
[1805b1b]915        thread_desc * thrd = 0p;
[65deb18]916        lock( lock __cfaabi_dbg_ctx2 );
917        count += 1;
918        if ( count <= 0 ) {
[bdeba0b]919                // remove task at head of waiting list
[65deb18]920                thrd = pop_head( waiting );
[bd98b58]921        }
[bdeba0b]922
[65deb18]923        unlock( lock );
[bdeba0b]924
925        // make new owner
926        WakeThread( thrd );
[bd98b58]927}
928
[f7d6bb0]929//-----------------------------------------------------------------------------
[de94a60]930// Global Queues
931void doregister( cluster     & cltr ) {
[ea8b2f7]932        lock      ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2);
933        push_front( __cfa_dbg_global_clusters.list, cltr );
934        unlock    ( __cfa_dbg_global_clusters.lock );
[de94a60]935}
[f7d6bb0]936
[de94a60]937void unregister( cluster     & cltr ) {
[ea8b2f7]938        lock  ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2);
939        remove( __cfa_dbg_global_clusters.list, cltr );
940        unlock( __cfa_dbg_global_clusters.lock );
[de94a60]941}
[f7d6bb0]942
[a1a17a74]943void doregister( cluster * cltr, thread_desc & thrd ) {
944        lock      (cltr->thread_list_lock __cfaabi_dbg_ctx2);
[d4e68a6]945        cltr->nthreads += 1;
[a1a17a74]946        push_front(cltr->threads, thrd);
947        unlock    (cltr->thread_list_lock);
948}
949
950void unregister( cluster * cltr, thread_desc & thrd ) {
951        lock  (cltr->thread_list_lock __cfaabi_dbg_ctx2);
952        remove(cltr->threads, thrd );
[d4e68a6]953        cltr->nthreads -= 1;
[a1a17a74]954        unlock(cltr->thread_list_lock);
955}
[9181f1d]956
[de94a60]957void doregister( cluster * cltr, processor * proc ) {
[639991a]958        lock      (cltr->proc_list_lock __cfaabi_dbg_ctx2);
[d4e68a6]959        cltr->nprocessors += 1;
[639991a]960        push_front(cltr->procs, *proc);
961        unlock    (cltr->proc_list_lock);
[de94a60]962}
963
964void unregister( cluster * cltr, processor * proc ) {
[639991a]965        lock  (cltr->proc_list_lock __cfaabi_dbg_ctx2);
966        remove(cltr->procs, *proc );
[d4e68a6]967        cltr->nprocessors -= 1;
[639991a]968        unlock(cltr->proc_list_lock);
[de94a60]969}
970
971//-----------------------------------------------------------------------------
972// Debug
973__cfaabi_dbg_debug_do(
[1997b4e]974        extern "C" {
975                void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) {
976                        this.prev_name = prev_name;
977                        this.prev_thrd = kernelTLS.this_thread;
978                }
[9181f1d]979        }
[f7d6bb0]980)
[2026bb6]981
982//-----------------------------------------------------------------------------
983// Debug
984bool threading_enabled(void) {
985        return true;
986}
[8118303]987// Local Variables: //
988// mode: c //
989// tab-width: 4 //
990// End: //
Note: See TracBrowser for help on using the repository browser.