Changeset 22f94a4 for libcfa/src/concurrency/kernel.cfa
- Timestamp:
- Aug 11, 2020, 4:40:15 PM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 0d070ca
- Parents:
- 07d867b (diff), 129674b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - File:
-
- 1 edited
-
libcfa/src/concurrency/kernel.cfa (modified) (27 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/kernel.cfa
r07d867b r22f94a4 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Feb 4 13:03:15202013 // Update Count : 5812 // Last Modified On : Thu Jul 9 06:22:54 2020 13 // Update Count : 66 14 14 // 15 15 … … 18 18 19 19 //C Includes 20 #include <stddef.h>21 20 #include <errno.h> 22 #include <string.h>23 extern "C" {24 21 #include <stdio.h> 25 #include <fenv.h>26 #include <sys/resource.h>27 22 #include <signal.h> 28 23 #include <unistd.h> 29 #include <limits.h> // PTHREAD_STACK_MIN30 #include <sys/mman.h> // mprotect31 }32 24 33 25 //CFA Includes 34 #include "time.hfa"35 26 #include "kernel_private.hfa" 36 27 #include "preemption.hfa" 37 #include "startup.hfa"38 28 39 29 //Private includes … … 45 35 // Some assembly required 46 36 #if defined( __i386 ) 47 #define CtxGet( ctx ) \48 __asm__ volatile ( \49 "movl %%esp,%0\n"\50 "movl %%ebp,%1\n"\51 : "=rm" (ctx.SP),\52 "=rm" (ctx.FP) \53 )54 55 37 // mxcr : SSE Status and Control bits (control bits are preserved across function calls) 56 38 // fcw : X87 FPU control word (preserved across function calls) … … 74 56 75 57 #elif defined( __x86_64 ) 76 #define CtxGet( ctx ) \77 __asm__ volatile ( \78 "movq %%rsp,%0\n"\79 "movq %%rbp,%1\n"\80 : "=rm" (ctx.SP),\81 "=rm" (ctx.FP) \82 )83 84 58 #define __x87_store \ 85 59 uint32_t __mxcr; \ … … 102 76 103 77 #elif defined( __ARM_ARCH ) 104 #define CtxGet( ctx ) __asm__ ( \105 "mov %0,%%sp\n" \106 "mov %1,%%r11\n" \107 : "=rm" (ctx.SP), "=rm" (ctx.FP) )108 78 #else 109 79 #error unknown hardware architecture 110 80 #endif 111 81 112 //----------------------------------------------------------------------------- 113 //Start and stop routine for the kernel, declared first to make sure they run first 114 static void __kernel_startup (void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); 115 static void __kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) )); 82 extern $thread * mainThread; 83 extern processor * mainProcessor; 116 84 117 85 //----------------------------------------------------------------------------- 118 86 // Kernel Scheduling logic 119 87 static $thread * __next_thread(cluster * this); 88 static $thread * __next_thread_slow(cluster * this); 120 89 static void __run_thread(processor * this, $thread * dst); 121 static $thread * __halt(processor * this); 122 static bool __wake_one(cluster * cltr, bool was_empty); 123 static bool __wake_proc(processor *); 124 125 //----------------------------------------------------------------------------- 126 // Kernel storage 127 KERNEL_STORAGE(cluster, mainCluster); 128 KERNEL_STORAGE(processor, mainProcessor); 129 KERNEL_STORAGE($thread, mainThread); 130 KERNEL_STORAGE(__stack_t, mainThreadCtx); 131 132 cluster * mainCluster; 133 processor * mainProcessor; 134 $thread * mainThread; 135 136 extern "C" { 137 struct { __dllist_t(cluster) list; __spinlock_t lock; } __cfa_dbg_global_clusters; 138 } 139 140 size_t __page_size = 0; 141 142 //----------------------------------------------------------------------------- 143 // Global state 144 thread_local struct KernelThreadData kernelTLS __attribute__ ((tls_model ( "initial-exec" ))) = { 145 NULL, // cannot use 0p 146 NULL, 147 { 1, false, false }, 148 6u //this should be seeded better but due to a bug calling rdtsc doesn't work 149 }; 150 151 //----------------------------------------------------------------------------- 152 // Struct to steal stack 153 struct current_stack_info_t { 154 __stack_t * storage; // pointer to stack object 155 void * base; // base of stack 156 void * limit; // stack grows towards stack limit 157 void * context; // address of cfa_context_t 158 }; 159 160 void ?{}( current_stack_info_t & this ) { 161 __stack_context_t ctx; 162 CtxGet( ctx ); 163 this.base = ctx.FP; 164 165 rlimit r; 166 getrlimit( RLIMIT_STACK, &r); 167 size_t size = r.rlim_cur; 168 169 this.limit = (void *)(((intptr_t)this.base) - size); 170 this.context = &storage_mainThreadCtx; 171 } 172 173 //----------------------------------------------------------------------------- 174 // Main thread construction 175 176 void ?{}( $coroutine & this, current_stack_info_t * info) with( this ) { 177 stack.storage = info->storage; 178 with(*stack.storage) { 179 limit = info->limit; 180 base = info->base; 181 } 182 __attribute__((may_alias)) intptr_t * istorage = (intptr_t*) &stack.storage; 183 *istorage |= 0x1; 184 name = "Main Thread"; 185 state = Start; 186 starter = 0p; 187 last = 0p; 188 cancellation = 0p; 189 } 190 191 void ?{}( $thread & this, current_stack_info_t * info) with( this ) { 192 state = Start; 193 self_cor{ info }; 194 curr_cor = &self_cor; 195 curr_cluster = mainCluster; 196 self_mon.owner = &this; 197 self_mon.recursion = 1; 198 self_mon_p = &self_mon; 199 next = 0p; 200 201 node.next = 0p; 202 node.prev = 0p; 203 doregister(curr_cluster, this); 204 205 monitors{ &self_mon_p, 1, (fptr_t)0 }; 206 } 207 208 //----------------------------------------------------------------------------- 209 // Processor coroutine 210 void ?{}(processorCtx_t & this) { 211 212 } 213 214 // Construct the processor context of non-main processors 215 static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) { 216 (this.__cor){ info }; 217 this.proc = proc; 218 } 219 220 static void * __invoke_processor(void * arg); 221 222 void ?{}(processor & this, const char name[], cluster & cltr) with( this ) { 223 this.name = name; 224 this.cltr = &cltr; 225 terminated{ 0 }; 226 destroyer = 0p; 227 do_terminate = false; 228 preemption_alarm = 0p; 229 pending_preemption = false; 230 runner.proc = &this; 231 232 idle{}; 233 234 __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this); 235 236 this.stack = __create_pthread( &this.kernel_thread, __invoke_processor, (void *)&this ); 237 238 __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this); 239 } 240 241 void ^?{}(processor & this) with( this ){ 242 if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) { 243 __cfadbg_print_safe(runtime_core, "Kernel : core %p signaling termination\n", &this); 244 245 __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED); 246 __wake_proc( &this ); 247 248 P( terminated ); 249 verify( kernelTLS.this_processor != &this); 250 } 251 252 int err = pthread_join( kernel_thread, 0p ); 253 if( err != 0 ) abort("KERNEL ERROR: joining processor %p caused error %s\n", &this, strerror(err)); 254 255 free( this.stack ); 256 } 257 258 void ?{}(cluster & this, const char name[], Duration preemption_rate, int io_flags) with( this ) { 259 this.name = name; 260 this.preemption_rate = preemption_rate; 261 ready_queue{}; 262 ready_queue_lock{}; 263 264 #if !defined(__CFA_NO_STATISTICS__) 265 print_stats = false; 266 #endif 267 268 procs{ __get }; 269 idles{ __get }; 270 threads{ __get }; 271 272 __kernel_io_startup( this, io_flags, &this == mainCluster ); 273 274 doregister(this); 275 } 276 277 void ^?{}(cluster & this) { 278 __kernel_io_shutdown( this, &this == mainCluster ); 279 280 unregister(this); 281 } 90 static void __wake_one(struct __processor_id_t * id, cluster * cltr); 91 92 static void push (__cluster_idles & idles, processor & proc); 93 static void remove(__cluster_idles & idles, processor & proc); 94 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles ); 95 282 96 283 97 //============================================================================================= … … 294 108 295 109 __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this); 296 297 doregister(this->cltr, this); 110 #if !defined(__CFA_NO_STATISTICS__) 111 if( this->print_halts ) { 112 __cfaabi_bits_print_safe( STDOUT_FILENO, "Processor : %d - %s (%p)\n", this->id, this->name, (void*)this); 113 } 114 #endif 298 115 299 116 { … … 304 121 305 122 $thread * readyThread = 0p; 306 for( unsigned int spin_count = 0; ! __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST); spin_count++ ) { 123 MAIN_LOOP: 124 for() { 307 125 // Try to get the next thread 308 126 readyThread = __next_thread( this->cltr ); 309 127 310 // If no ready thread 311 if( readyThread == 0p ) { 312 // Block until a thread is ready 313 readyThread = __halt(this); 128 if( !readyThread ) { 129 readyThread = __next_thread_slow( this->cltr ); 314 130 } 315 131 316 // Check if we actually found a thread 317 if( readyThread ) { 318 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 319 /* paranoid */ verifyf( readyThread->state == Ready || readyThread->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", readyThread->state, readyThread->preempted); 320 /* paranoid */ verifyf( readyThread->next == 0p, "Expected null got %p", readyThread->next ); 321 322 // We found a thread run it 323 __run_thread(this, readyThread); 324 325 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 132 HALT: 133 if( !readyThread ) { 134 // Don't block if we are done 135 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 136 137 #if !defined(__CFA_NO_STATISTICS__) 138 __tls_stats()->ready.sleep.halts++; 139 #endif 140 141 // Push self to idle stack 142 push(this->cltr->idles, * this); 143 144 // Confirm the ready-queue is empty 145 readyThread = __next_thread_slow( this->cltr ); 146 if( readyThread ) { 147 // A thread was found, cancel the halt 148 remove(this->cltr->idles, * this); 149 150 #if !defined(__CFA_NO_STATISTICS__) 151 __tls_stats()->ready.sleep.cancels++; 152 #endif 153 154 // continue the mai loop 155 break HALT; 156 } 157 158 #if !defined(__CFA_NO_STATISTICS__) 159 if(this->print_halts) { 160 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); 161 } 162 #endif 163 164 wait( this->idle ); 165 166 #if !defined(__CFA_NO_STATISTICS__) 167 if(this->print_halts) { 168 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); 169 } 170 #endif 171 172 // We were woken up, remove self from idle 173 remove(this->cltr->idles, * this); 174 175 // DON'T just proceed, start looking again 176 continue MAIN_LOOP; 326 177 } 178 179 /* paranoid */ verify( readyThread ); 180 181 // We found a thread run it 182 __run_thread(this, readyThread); 183 184 // Are we done? 185 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 327 186 } 328 187 … … 330 189 } 331 190 332 unregister(this->cltr, this);333 334 191 V( this->terminated ); 335 192 193 if(this == mainProcessor) { 194 // HACK : the coroutine context switch expects this_thread to be set 195 // and it make sense for it to be set in all other cases except here 196 // fake it 197 kernelTLS.this_thread = mainThread; 198 } 199 336 200 __cfadbg_print_safe(runtime_core, "Kernel : core %p terminated\n", this); 337 338 // HACK : the coroutine context switch expects this_thread to be set339 // and it make sense for it to be set in all other cases except here340 // fake it341 if( this == mainProcessor ) kernelTLS.this_thread = mainThread;342 201 } 343 202 … … 349 208 // from the processor coroutine to the target thread 350 209 static void __run_thread(processor * this, $thread * thrd_dst) { 210 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 211 /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted); 212 /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next ); 213 __builtin_prefetch( thrd_dst->context.SP ); 214 351 215 $coroutine * proc_cor = get_coroutine(this->runner); 352 216 … … 360 224 // Actually run the thread 361 225 RUNNING: while(true) { 362 if(unlikely(thrd_dst->preempted)) { 363 thrd_dst->preempted = __NO_PREEMPTION; 364 verify(thrd_dst->state == Active || thrd_dst->state == Rerun); 365 } else { 366 verify(thrd_dst->state == Blocked || thrd_dst->state == Ready); // Ready means scheduled normally, blocked means rerun 367 thrd_dst->state = Active; 368 } 226 thrd_dst->preempted = __NO_PREEMPTION; 227 thrd_dst->state = Active; 369 228 370 229 __cfaabi_dbg_debug_do( … … 374 233 375 234 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 235 /* paranoid */ verify( kernelTLS.this_thread == thrd_dst ); 376 236 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor 377 237 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor, "ERROR : Destination $thread %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor … … 384 244 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit), "ERROR : Destination $thread %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); 385 245 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ), "ERROR : Destination $thread %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); 246 /* paranoid */ verify( kernelTLS.this_thread == thrd_dst ); 386 247 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 387 248 … … 396 257 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) { 397 258 // The thread was preempted, reschedule it and reset the flag 398 __schedule_thread( thrd_dst );259 __schedule_thread( (__processor_id_t*)this, thrd_dst ); 399 260 break RUNNING; 400 261 } 401 262 263 if(unlikely(thrd_dst->state == Halted)) { 264 // The thread has halted, it should never be scheduled/run again 265 // We may need to wake someone up here since 266 unpark( this->destroyer __cfaabi_dbg_ctx2 ); 267 this->destroyer = 0p; 268 break RUNNING; 269 } 270 271 /* paranoid */ verify( thrd_dst->state == Active ); 272 thrd_dst->state = Blocked; 273 402 274 // set state of processor coroutine to active and the thread to inactive 403 static_assert(sizeof(thrd_dst->state) == sizeof(int)); 404 enum coroutine_state old_state = __atomic_exchange_n(&thrd_dst->state, Blocked, __ATOMIC_SEQ_CST); 405 __cfaabi_dbg_debug_do( thrd_dst->park_result = old_state; ) 406 switch(old_state) { 407 case Halted: 408 // The thread has halted, it should never be scheduled/run again, leave it back to Halted and move on 409 thrd_dst->state = Halted; 410 411 // We may need to wake someone up here since 412 unpark( this->destroyer __cfaabi_dbg_ctx2 ); 413 this->destroyer = 0p; 414 break RUNNING; 415 case Active: 275 int old_ticket = __atomic_fetch_sub(&thrd_dst->ticket, 1, __ATOMIC_SEQ_CST); 276 __cfaabi_dbg_debug_do( thrd_dst->park_result = old_ticket; ) 277 switch(old_ticket) { 278 case 1: 416 279 // This is case 1, the regular case, nothing more is needed 417 280 break RUNNING; 418 case Rerun:281 case 2: 419 282 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 420 283 // In this case, just run it again. … … 422 285 default: 423 286 // This makes no sense, something is wrong abort 424 abort( "Finished running a thread that was Blocked/Start/Primed %d\n", old_state);287 abort(); 425 288 } 426 289 } … … 429 292 proc_cor->state = Active; 430 293 kernelTLS.this_thread = 0p; 294 295 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 431 296 } 432 297 … … 436 301 $coroutine * proc_cor = get_coroutine(kernelTLS.this_processor->runner); 437 302 $thread * thrd_src = kernelTLS.this_thread; 303 304 #if !defined(__CFA_NO_STATISTICS__) 305 struct processor * last_proc = kernelTLS.this_processor; 306 #endif 438 307 439 308 // Run the thread on this processor … … 451 320 } 452 321 322 #if !defined(__CFA_NO_STATISTICS__) 323 if(last_proc != kernelTLS.this_processor) { 324 __tls_stats()->ready.threads.migration++; 325 } 326 #endif 327 453 328 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 454 329 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) < ((uintptr_t)__get_stack(thrd_src->curr_cor)->base ), "ERROR : Returning $thread %p has been corrupted.\n StackPointer too small.\n", thrd_src ); 455 330 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) > ((uintptr_t)__get_stack(thrd_src->curr_cor)->limit), "ERROR : Returning $thread %p has been corrupted.\n StackPointer too large.\n", thrd_src ); 456 }457 458 // KERNEL_ONLY459 // Context invoker for processors460 // This is the entry point for processors (kernel threads)461 // It effectively constructs a coroutine by stealing the pthread stack462 static void * __invoke_processor(void * arg) {463 processor * proc = (processor *) arg;464 kernelTLS.this_processor = proc;465 kernelTLS.this_thread = 0p;466 kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];467 // SKULLDUGGERY: We want to create a context for the processor coroutine468 // which is needed for the 2-step context switch. However, there is no reason469 // to waste the perfectly valid stack create by pthread.470 current_stack_info_t info;471 __stack_t ctx;472 info.storage = &ctx;473 (proc->runner){ proc, &info };474 475 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage);476 477 //Set global state478 kernelTLS.this_thread = 0p;479 480 //We now have a proper context from which to schedule threads481 __cfadbg_print_safe(runtime_core, "Kernel : core %p created (%p, %p)\n", proc, &proc->runner, &ctx);482 483 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't484 // resume it to start it like it normally would, it will just context switch485 // back to here. Instead directly call the main since we already are on the486 // appropriate stack.487 get_coroutine(proc->runner)->state = Active;488 main( proc->runner );489 get_coroutine(proc->runner)->state = Halted;490 491 // Main routine of the core returned, the core is now fully terminated492 __cfadbg_print_safe(runtime_core, "Kernel : core %p main ended (%p)\n", proc, &proc->runner);493 494 return 0p;495 }496 497 static void Abort( int ret, const char func[] ) {498 if ( ret ) { // pthread routines return errno values499 abort( "%s : internal error, error(%d) %s.", func, ret, strerror( ret ) );500 } // if501 } // Abort502 503 void * __create_pthread( pthread_t * pthread, void * (*start)(void *), void * arg ) {504 pthread_attr_t attr;505 506 Abort( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute507 508 size_t stacksize;509 // default stack size, normally defined by shell limit510 Abort( pthread_attr_getstacksize( &attr, &stacksize ), "pthread_attr_getstacksize" );511 assert( stacksize >= PTHREAD_STACK_MIN );512 513 void * stack;514 __cfaabi_dbg_debug_do(515 stack = memalign( __page_size, stacksize + __page_size );516 // pthread has no mechanism to create the guard page in user supplied stack.517 if ( mprotect( stack, __page_size, PROT_NONE ) == -1 ) {518 abort( "mprotect : internal error, mprotect failure, error(%d) %s.", errno, strerror( errno ) );519 } // if520 );521 __cfaabi_dbg_no_debug_do(522 stack = malloc( stacksize );523 );524 525 Abort( pthread_attr_setstack( &attr, stack, stacksize ), "pthread_attr_setstack" );526 527 Abort( pthread_create( pthread, &attr, start, arg ), "pthread_create" );528 return stack;529 }530 531 // KERNEL_ONLY532 static void __kernel_first_resume( processor * this ) {533 $thread * src = mainThread;534 $coroutine * dst = get_coroutine(this->runner);535 536 verify( ! kernelTLS.preemption_state.enabled );537 538 kernelTLS.this_thread->curr_cor = dst;539 __stack_prepare( &dst->stack, 65000 );540 __cfactx_start(main, dst, this->runner, __cfactx_invoke_coroutine);541 542 verify( ! kernelTLS.preemption_state.enabled );543 544 dst->last = &src->self_cor;545 dst->starter = dst->starter ? dst->starter : &src->self_cor;546 547 // make sure the current state is still correct548 /* paranoid */ verify(src->state == Ready);549 550 // context switch to specified coroutine551 verify( dst->context.SP );552 __cfactx_switch( &src->context, &dst->context );553 // when __cfactx_switch returns we are back in the src coroutine554 555 mainThread->curr_cor = &mainThread->self_cor;556 557 // make sure the current state has been update558 /* paranoid */ verify(src->state == Active);559 560 verify( ! kernelTLS.preemption_state.enabled );561 }562 563 // KERNEL_ONLY564 static void __kernel_last_resume( processor * this ) {565 $coroutine * src = &mainThread->self_cor;566 $coroutine * dst = get_coroutine(this->runner);567 568 verify( ! kernelTLS.preemption_state.enabled );569 verify( dst->starter == src );570 verify( dst->context.SP );571 572 // SKULLDUGGERY in debug the processors check that the573 // stack is still within the limit of the stack limits after running a thread.574 // that check doesn't make sense if we context switch to the processor using the575 // coroutine semantics. Since this is a special case, use the current context576 // info to populate these fields.577 __cfaabi_dbg_debug_do(578 __stack_context_t ctx;579 CtxGet( ctx );580 mainThread->context.SP = ctx.SP;581 mainThread->context.FP = ctx.FP;582 )583 584 // context switch to the processor585 __cfactx_switch( &src->context, &dst->context );586 331 } 587 332 … … 589 334 // Scheduler routines 590 335 // KERNEL ONLY 591 void __schedule_thread( $thread * thrd ) with( *thrd->curr_cluster ) { 336 void __schedule_thread( struct __processor_id_t * id, $thread * thrd ) { 337 /* paranoid */ verify( thrd ); 338 /* paranoid */ verify( thrd->state != Halted ); 592 339 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 593 340 /* paranoid */ #if defined( __CFA_WITH_VERIFY__ ) 594 /* paranoid */ if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION,595 "Error inactive thread marked as preempted, state %d, preemption %d\n", thrd->state, thrd->preempted );596 /* paranoid */ if( thrd->preempted != __NO_PREEMPTION ) assertf(thrd->state == Active || thrd->state == Rerun,597 "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted );341 /* paranoid */ if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION, 342 "Error inactive thread marked as preempted, state %d, preemption %d\n", thrd->state, thrd->preempted ); 343 /* paranoid */ if( thrd->preempted != __NO_PREEMPTION ) assertf(thrd->state == Active, 344 "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted ); 598 345 /* paranoid */ #endif 599 /* paranoid */ verifyf( thrd-> next == 0p, "Expected null got %p", thrd->next );346 /* paranoid */ verifyf( thrd->link.next == 0p, "Expected null got %p", thrd->link.next ); 600 347 601 348 if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready; 602 349 603 lock ( ready_queue_lock __cfaabi_dbg_ctx2 ); 604 bool was_empty = !(ready_queue != 0); 605 append( ready_queue, thrd ); 606 unlock( ready_queue_lock ); 607 608 __wake_one(thrd->curr_cluster, was_empty); 350 ready_schedule_lock ( id ); 351 push( thrd->curr_cluster, thrd ); 352 __wake_one(id, thrd->curr_cluster); 353 ready_schedule_unlock( id ); 609 354 610 355 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); … … 612 357 613 358 // KERNEL ONLY 614 static $thread * __next_thread(cluster * this) with( *this ) { 615 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 616 617 lock( ready_queue_lock __cfaabi_dbg_ctx2 ); 618 $thread * head = pop_head( ready_queue ); 619 unlock( ready_queue_lock ); 620 621 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 622 return head; 359 static inline $thread * __next_thread(cluster * this) with( *this ) { 360 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 361 362 ready_schedule_lock ( (__processor_id_t*)kernelTLS.this_processor ); 363 $thread * thrd = pop( this ); 364 ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor ); 365 366 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 367 return thrd; 368 } 369 370 // KERNEL ONLY 371 static inline $thread * __next_thread_slow(cluster * this) with( *this ) { 372 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 373 374 ready_schedule_lock ( (__processor_id_t*)kernelTLS.this_processor ); 375 $thread * thrd = pop_slow( this ); 376 ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor ); 377 378 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 379 return thrd; 623 380 } 624 381 625 382 // KERNEL ONLY unpark with out disabling interrupts 626 void __unpark( $thread * thrd __cfaabi_dbg_ctx_param2 ) { 627 static_assert(sizeof(thrd->state) == sizeof(int)); 628 383 void __unpark( struct __processor_id_t * id, $thread * thrd __cfaabi_dbg_ctx_param2 ) { 629 384 // record activity 630 385 __cfaabi_dbg_record_thrd( *thrd, false, caller ); 631 386 632 enum coroutine_state old_state = __atomic_exchange_n(&thrd->state, Rerun, __ATOMIC_SEQ_CST);633 __cfaabi_dbg_debug_do( thrd->unpark_result = old_ state; )634 switch(old_ state) {635 case Active:387 int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST); 388 __cfaabi_dbg_debug_do( thrd->unpark_result = old_ticket; thrd->unpark_state = thrd->state; ) 389 switch(old_ticket) { 390 case 1: 636 391 // Wake won the race, the thread will reschedule/rerun itself 637 392 break; 638 case Blocked:393 case 0: 639 394 /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION ); 395 /* paranoid */ verify( thrd->state == Blocked ); 640 396 641 397 // Wake lost the race, 642 thrd->state = Blocked; 643 __schedule_thread( thrd ); 398 __schedule_thread( id, thrd ); 644 399 break; 645 case Rerun:646 abort("More than one thread attempted to schedule thread %p\n", thrd);647 break;648 case Halted:649 case Start:650 case Primed:651 400 default: 652 401 // This makes no sense, something is wrong abort … … 659 408 660 409 disable_interrupts(); 661 __unpark( thrd __cfaabi_dbg_ctx_fwd2 );410 __unpark( (__processor_id_t*)kernelTLS.this_processor, thrd __cfaabi_dbg_ctx_fwd2 ); 662 411 enable_interrupts( __cfaabi_dbg_ctx ); 663 412 } … … 694 443 695 444 $thread * thrd = kernelTLS.this_thread; 696 /* paranoid */ verify(thrd->state == Active || thrd->state == Rerun);445 /* paranoid */ verify(thrd->state == Active); 697 446 698 447 // SKULLDUGGERY: It is possible that we are preempting this thread just before … … 701 450 // If that is the case, abandon the preemption. 702 451 bool preempted = false; 703 if(thrd-> next == 0p) {452 if(thrd->link.next == 0p) { 704 453 preempted = true; 705 454 thrd->preempted = reason; … … 715 464 716 465 //============================================================================================= 717 // Kernel Setup logic718 //=============================================================================================719 //-----------------------------------------------------------------------------720 // Kernel boot procedures721 static void __kernel_startup(void) {722 verify( ! kernelTLS.preemption_state.enabled );723 __cfadbg_print_safe(runtime_core, "Kernel : Starting\n");724 725 __page_size = sysconf( _SC_PAGESIZE );726 727 __cfa_dbg_global_clusters.list{ __get };728 __cfa_dbg_global_clusters.lock{};729 730 // Initialize the main cluster731 mainCluster = (cluster *)&storage_mainCluster;732 (*mainCluster){"Main Cluster"};733 734 __cfadbg_print_safe(runtime_core, "Kernel : Main cluster ready\n");735 736 // Start by initializing the main thread737 // SKULLDUGGERY: the mainThread steals the process main thread738 // which will then be scheduled by the mainProcessor normally739 mainThread = ($thread *)&storage_mainThread;740 current_stack_info_t info;741 info.storage = (__stack_t*)&storage_mainThreadCtx;742 (*mainThread){ &info };743 744 __cfadbg_print_safe(runtime_core, "Kernel : Main thread ready\n");745 746 747 748 // Construct the processor context of the main processor749 void ?{}(processorCtx_t & this, processor * proc) {750 (this.__cor){ "Processor" };751 this.__cor.starter = 0p;752 this.proc = proc;753 }754 755 void ?{}(processor & this) with( this ) {756 name = "Main Processor";757 cltr = mainCluster;758 terminated{ 0 };759 do_terminate = false;760 preemption_alarm = 0p;761 pending_preemption = false;762 kernel_thread = pthread_self();763 764 runner{ &this };765 __cfadbg_print_safe(runtime_core, "Kernel : constructed main processor context %p\n", &runner);766 }767 768 // Initialize the main processor and the main processor ctx769 // (the coroutine that contains the processing control flow)770 mainProcessor = (processor *)&storage_mainProcessor;771 (*mainProcessor){};772 773 //initialize the global state variables774 kernelTLS.this_processor = mainProcessor;775 kernelTLS.this_thread = mainThread;776 777 // Enable preemption778 kernel_start_preemption();779 780 // Add the main thread to the ready queue781 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread782 __schedule_thread(mainThread);783 784 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX785 // context. Hence, the main thread does not begin through __cfactx_invoke_thread, like all other threads. The trick here is that786 // mainThread is on the ready queue when this call is made.787 __kernel_first_resume( kernelTLS.this_processor );788 789 790 // THE SYSTEM IS NOW COMPLETELY RUNNING791 792 793 // Now that the system is up, finish creating systems that need threading794 __kernel_io_finish_start( *mainCluster );795 796 797 __cfadbg_print_safe(runtime_core, "Kernel : Started\n--------------------------------------------------\n\n");798 799 verify( ! kernelTLS.preemption_state.enabled );800 enable_interrupts( __cfaabi_dbg_ctx );801 verify( TL_GET( preemption_state.enabled ) );802 }803 804 static void __kernel_shutdown(void) {805 //Before we start shutting things down, wait for systems that need threading to shutdown806 __kernel_io_prepare_stop( *mainCluster );807 808 /* paranoid */ verify( TL_GET( preemption_state.enabled ) );809 disable_interrupts();810 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );811 812 __cfadbg_print_safe(runtime_core, "\n--------------------------------------------------\nKernel : Shutting down\n");813 814 // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.815 // When its coroutine terminates, it return control to the mainThread816 // which is currently here817 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE);818 __kernel_last_resume( kernelTLS.this_processor );819 mainThread->self_cor.state = Halted;820 821 // THE SYSTEM IS NOW COMPLETELY STOPPED822 823 // Disable preemption824 kernel_stop_preemption();825 826 // Destroy the main processor and its context in reverse order of construction827 // These were manually constructed so we need manually destroy them828 void ^?{}(processor & this) with( this ){829 /* paranoid */ verify( this.do_terminate == true );830 }831 832 ^(*mainProcessor){};833 834 // Final step, destroy the main thread since it is no longer needed835 // Since we provided a stack to this taxk it will not destroy anything836 /* paranoid */ verify(mainThread->self_cor.stack.storage == (__stack_t*)(((uintptr_t)&storage_mainThreadCtx)| 0x1));837 ^(*mainThread){};838 839 ^(*mainCluster){};840 841 ^(__cfa_dbg_global_clusters.list){};842 ^(__cfa_dbg_global_clusters.lock){};843 844 __cfadbg_print_safe(runtime_core, "Kernel : Shutdown complete\n");845 }846 847 //=============================================================================================848 466 // Kernel Idle Sleep 849 467 //============================================================================================= 850 static $thread * __halt(processor * this) with( *this ) {851 if( do_terminate ) return 0p;852 853 // First, lock the cluster idle854 lock( cltr->idle_lock __cfaabi_dbg_ctx2 );855 856 // Check if we can find a thread857 if( $thread * found = __next_thread( cltr ) ) {858 unlock( cltr->idle_lock );859 return found;860 }861 862 // Move this processor from the active list to the idle list863 move_to_front(cltr->procs, cltr->idles, *this);864 865 // Unlock the idle lock so we don't go to sleep with a lock866 unlock (cltr->idle_lock);867 868 // We are ready to sleep869 __cfadbg_print_safe(runtime_core, "Kernel : Processor %p ready to sleep\n", this);870 wait( idle );871 872 // We have woken up873 __cfadbg_print_safe(runtime_core, "Kernel : Processor %p woke up and ready to run\n", this);874 875 // Get ourself off the idle list876 with( *cltr ) {877 lock (idle_lock __cfaabi_dbg_ctx2);878 move_to_front(idles, procs, *this);879 unlock(idle_lock);880 }881 882 // Don't check the ready queue again, we may not be in a position to run a thread883 return 0p;884 }885 886 468 // Wake a thread from the front if there are any 887 static bool __wake_one(cluster * this, __attribute__((unused)) bool force) { 888 // if we don't want to force check if we know it's false 889 // if( !this->idles.head && !force ) return false; 890 891 // First, lock the cluster idle 892 lock( this->idle_lock __cfaabi_dbg_ctx2 ); 893 894 // Check if there is someone to wake up 895 if( !this->idles.head ) { 896 // Nope unlock and return false 897 unlock( this->idle_lock ); 898 return false; 899 } 900 901 // Wake them up 902 __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this->idles.head); 903 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 904 post( this->idles.head->idle ); 905 906 // Unlock and return true 907 unlock( this->idle_lock ); 908 return true; 469 static void __wake_one(struct __processor_id_t * id, cluster * this) { 470 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 471 /* paranoid */ verify( ready_schedule_islocked( id ) ); 472 473 // Check if there is a sleeping processor 474 processor * p; 475 unsigned idle; 476 unsigned total; 477 [idle, total, p] = query(this->idles); 478 479 // If no one is sleeping, we are done 480 if( idle == 0 ) return; 481 482 // We found a processor, wake it up 483 post( p->idle ); 484 485 #if !defined(__CFA_NO_STATISTICS__) 486 __tls_stats()->ready.sleep.wakes++; 487 #endif 488 489 /* paranoid */ verify( ready_schedule_islocked( id ) ); 490 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 491 492 return; 909 493 } 910 494 911 495 // Unconditionnaly wake a thread 912 static bool__wake_proc(processor * this) {496 void __wake_proc(processor * this) { 913 497 __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this); 914 498 … … 917 501 bool ret = post( this->idle ); 918 502 enable_interrupts( __cfaabi_dbg_ctx ); 919 920 return ret; 503 } 504 505 static void push (__cluster_idles & this, processor & proc) { 506 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 507 lock( this ); 508 this.idle++; 509 /* paranoid */ verify( this.idle <= this.total ); 510 511 insert_first(this.list, proc); 512 unlock( this ); 513 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 514 } 515 516 static void remove(__cluster_idles & this, processor & proc) { 517 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 518 lock( this ); 519 this.idle--; 520 /* paranoid */ verify( this.idle >= 0 ); 521 522 remove(proc); 523 unlock( this ); 524 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 525 } 526 527 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) { 528 for() { 529 uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST); 530 if( 1 == (l % 2) ) { Pause(); continue; } 531 unsigned idle = this.idle; 532 unsigned total = this.total; 533 processor * proc = &this.list`first; 534 if(l != __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST)) { Pause(); continue; } 535 return [idle, total, proc]; 536 } 921 537 } 922 538 … … 952 568 953 569 void kernel_abort_msg( void * kernel_data, char * abort_text, int abort_text_size ) { 954 $thread * thrd = kernel_data;570 $thread * thrd = ( $thread * ) kernel_data; 955 571 956 572 if(thrd) { … … 1050 666 1051 667 //----------------------------------------------------------------------------- 1052 // Global Queues1053 void doregister( cluster & cltr ) {1054 lock ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2);1055 push_front( __cfa_dbg_global_clusters.list, cltr );1056 unlock ( __cfa_dbg_global_clusters.lock );1057 }1058 1059 void unregister( cluster & cltr ) {1060 lock ( __cfa_dbg_global_clusters.lock __cfaabi_dbg_ctx2);1061 remove( __cfa_dbg_global_clusters.list, cltr );1062 unlock( __cfa_dbg_global_clusters.lock );1063 }1064 1065 void doregister( cluster * cltr, $thread & thrd ) {1066 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2);1067 cltr->nthreads += 1;1068 push_front(cltr->threads, thrd);1069 unlock (cltr->thread_list_lock);1070 }1071 1072 void unregister( cluster * cltr, $thread & thrd ) {1073 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2);1074 remove(cltr->threads, thrd );1075 cltr->nthreads -= 1;1076 unlock(cltr->thread_list_lock);1077 }1078 1079 void doregister( cluster * cltr, processor * proc ) {1080 lock (cltr->idle_lock __cfaabi_dbg_ctx2);1081 cltr->nprocessors += 1;1082 push_front(cltr->procs, *proc);1083 unlock (cltr->idle_lock);1084 }1085 1086 void unregister( cluster * cltr, processor * proc ) {1087 lock (cltr->idle_lock __cfaabi_dbg_ctx2);1088 remove(cltr->procs, *proc );1089 cltr->nprocessors -= 1;1090 unlock(cltr->idle_lock);1091 }1092 1093 //-----------------------------------------------------------------------------1094 668 // Debug 1095 669 __cfaabi_dbg_debug_do( … … 1118 692 return true; 1119 693 } 694 695 //----------------------------------------------------------------------------- 696 // Statistics 697 #if !defined(__CFA_NO_STATISTICS__) 698 void print_halts( processor & this ) { 699 this.print_halts = true; 700 } 701 #endif 1120 702 // Local Variables: // 1121 703 // mode: c //
Note:
See TracChangeset
for help on using the changeset viewer.