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