Changeset b067d9b for libcfa/src/concurrency/kernel.cfa
- Timestamp:
- Oct 29, 2019, 4:01:24 PM (6 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 773db65, 9421f3d8
- Parents:
- 7951100 (diff), 8364209 (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 moved
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/kernel.cfa
r7951100 rb067d9b 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 9 16:11:46 201813 // Update Count : 2 412 // Last Modified On : Thu Jun 20 17:21:23 2019 13 // Update Count : 25 14 14 // 15 16 #define __cforall_thread__ 15 17 16 18 //C Includes … … 27 29 28 30 //CFA Includes 29 #include "time "30 #include "kernel_private.h "31 #include "preemption.h "32 #include "startup.h "31 #include "time.hfa" 32 #include "kernel_private.hfa" 33 #include "preemption.hfa" 34 #include "startup.hfa" 33 35 34 36 //Private includes … … 36 38 #include "invoke.h" 37 39 40 //----------------------------------------------------------------------------- 41 // Some assembly required 42 #if defined( __i386 ) 43 #define CtxGet( ctx ) \ 44 __asm__ volatile ( \ 45 "movl %%esp,%0\n"\ 46 "movl %%ebp,%1\n"\ 47 : "=rm" (ctx.SP),\ 48 "=rm" (ctx.FP) \ 49 ) 50 51 // mxcr : SSE Status and Control bits (control bits are preserved across function calls) 52 // fcw : X87 FPU control word (preserved across function calls) 53 #define __x87_store \ 54 uint32_t __mxcr; \ 55 uint16_t __fcw; \ 56 __asm__ volatile ( \ 57 "stmxcsr %0\n" \ 58 "fnstcw %1\n" \ 59 : "=m" (__mxcr),\ 60 "=m" (__fcw) \ 61 ) 62 63 #define __x87_load \ 64 __asm__ volatile ( \ 65 "fldcw %1\n" \ 66 "ldmxcsr %0\n" \ 67 ::"m" (__mxcr),\ 68 "m" (__fcw) \ 69 ) 70 71 #elif defined( __x86_64 ) 72 #define CtxGet( ctx ) \ 73 __asm__ volatile ( \ 74 "movq %%rsp,%0\n"\ 75 "movq %%rbp,%1\n"\ 76 : "=rm" (ctx.SP),\ 77 "=rm" (ctx.FP) \ 78 ) 79 80 #define __x87_store \ 81 uint32_t __mxcr; \ 82 uint16_t __fcw; \ 83 __asm__ volatile ( \ 84 "stmxcsr %0\n" \ 85 "fnstcw %1\n" \ 86 : "=m" (__mxcr),\ 87 "=m" (__fcw) \ 88 ) 89 90 #define __x87_load \ 91 __asm__ volatile ( \ 92 "fldcw %1\n" \ 93 "ldmxcsr %0\n" \ 94 :: "m" (__mxcr),\ 95 "m" (__fcw) \ 96 ) 97 98 99 #elif defined( __ARM_ARCH ) 100 #define CtxGet( ctx ) __asm__ ( \ 101 "mov %0,%%sp\n" \ 102 "mov %1,%%r11\n" \ 103 : "=rm" (ctx.SP), "=rm" (ctx.FP) ) 104 #else 105 #error unknown hardware architecture 106 #endif 107 108 //----------------------------------------------------------------------------- 38 109 //Start and stop routine for the kernel, declared first to make sure they run first 39 void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));40 void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));110 static void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); 111 static void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) )); 41 112 42 113 //----------------------------------------------------------------------------- 43 114 // Kernel storage 44 KERNEL_STORAGE(cluster, 45 KERNEL_STORAGE(processor, 46 KERNEL_STORAGE(thread_desc, 47 KERNEL_STORAGE( machine_context_t,mainThreadCtx);115 KERNEL_STORAGE(cluster, mainCluster); 116 KERNEL_STORAGE(processor, mainProcessor); 117 KERNEL_STORAGE(thread_desc, mainThread); 118 KERNEL_STORAGE(__stack_t, mainThreadCtx); 48 119 49 120 cluster * mainCluster; … … 55 126 } 56 127 128 size_t __page_size = 0; 129 57 130 //----------------------------------------------------------------------------- 58 131 // Global state 59 thread_local struct KernelThreadData kernelTLS = { 60 NULL, 132 thread_local struct KernelThreadData kernelTLS __attribute__ ((tls_model ( "initial-exec" ))) = { 61 133 NULL, 62 134 NULL, … … 67 139 // Struct to steal stack 68 140 struct current_stack_info_t { 69 machine_context_t ctx; 70 unsigned int size; // size of stack 141 __stack_t * storage; // pointer to stack object 71 142 void *base; // base of stack 72 void *storage; // pointer to stack73 143 void *limit; // stack grows towards stack limit 74 144 void *context; // address of cfa_context_t 75 void *top; // address of top of storage76 145 }; 77 146 78 147 void ?{}( current_stack_info_t & this ) { 79 CtxGet( this.ctx );80 this.base = this.ctx.FP;81 this. storage = this.ctx.SP;148 __stack_context_t ctx; 149 CtxGet( ctx ); 150 this.base = ctx.FP; 82 151 83 152 rlimit r; 84 153 getrlimit( RLIMIT_STACK, &r); 85 this.size = r.rlim_cur;86 87 this.limit = (void *)(((intptr_t)this.base) - this.size);154 size_t size = r.rlim_cur; 155 156 this.limit = (void *)(((intptr_t)this.base) - size); 88 157 this.context = &storage_mainThreadCtx; 89 this.top = this.base;90 158 } 91 159 92 160 //----------------------------------------------------------------------------- 93 161 // Main thread construction 94 void ?{}( coStack_t & this, current_stack_info_t * info) with( this ) {95 size = info->size;96 storage = info->storage;97 limit = info->limit;98 base = info->base;99 context = info->context;100 top = info->top;101 userStack = true;102 }103 162 104 163 void ?{}( coroutine_desc & this, current_stack_info_t * info) with( this ) { 105 stack{ info }; 164 stack.storage = info->storage; 165 with(*stack.storage) { 166 limit = info->limit; 167 base = info->base; 168 } 169 __attribute__((may_alias)) intptr_t * istorage = (intptr_t*) &stack.storage; 170 *istorage |= 0x1; 106 171 name = "Main Thread"; 107 errno_ = 0;108 172 state = Start; 109 173 starter = NULL; 174 last = NULL; 175 cancellation = NULL; 110 176 } 111 177 112 178 void ?{}( thread_desc & this, current_stack_info_t * info) with( this ) { 179 state = Start; 113 180 self_cor{ info }; 114 181 curr_cor = &self_cor; … … 133 200 134 201 // Construct the processor context of non-main processors 135 void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) {202 static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) { 136 203 (this.__cor){ info }; 137 204 this.proc = proc; 138 205 } 139 206 207 static void start(processor * this); 140 208 void ?{}(processor & this, const char * name, cluster & cltr) with( this ) { 141 209 this.name = name; … … 147 215 runner.proc = &this; 148 216 149 sem_init(&idleLock, 0, 0);217 idleLock{}; 150 218 151 219 start( &this ); … … 155 223 if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) { 156 224 __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this); 157 terminate(&this); 158 verify( __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 159 verify( kernelTLS.this_processor != &this); 225 226 __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED); 227 wake( &this ); 228 160 229 P( terminated ); 161 230 verify( kernelTLS.this_processor != &this); 162 pthread_join( kernel_thread, NULL ); 163 } 164 165 sem_destroy(&idleLock); 231 } 232 233 pthread_join( kernel_thread, NULL ); 166 234 } 167 235 … … 186 254 // Kernel Scheduling logic 187 255 //============================================================================================= 256 static void runThread(processor * this, thread_desc * dst); 257 static void finishRunning(processor * this); 258 static void halt(processor * this); 259 188 260 //Main of the processor contexts 189 261 void main(processorCtx_t & runner) { … … 236 308 } 237 309 310 static int * __volatile_errno() __attribute__((noinline)); 311 static int * __volatile_errno() { asm(""); return &errno; } 312 238 313 // KERNEL ONLY 239 314 // runThread runs a thread by context switching 240 315 // from the processor coroutine to the target thread 241 void runThread(processor * this, thread_desc * dst) { 242 assert(dst->curr_cor); 316 static void runThread(processor * this, thread_desc * thrd_dst) { 243 317 coroutine_desc * proc_cor = get_coroutine(this->runner); 244 coroutine_desc * thrd_cor = dst->curr_cor;245 318 246 319 // Reset the terminating actions here … … 248 321 249 322 // Update global state 250 kernelTLS.this_thread = dst; 251 252 // Context Switch to the thread 253 ThreadCtxSwitch(proc_cor, thrd_cor); 254 // when ThreadCtxSwitch returns we are back in the processor coroutine 323 kernelTLS.this_thread = thrd_dst; 324 325 // set state of processor coroutine to inactive and the thread to active 326 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 327 thrd_dst->state = Active; 328 329 // set context switch to the thread that the processor is executing 330 verify( thrd_dst->context.SP ); 331 CtxSwitch( &proc_cor->context, &thrd_dst->context ); 332 // when CtxSwitch returns we are back in the processor coroutine 333 334 // set state of processor coroutine to active and the thread to inactive 335 thrd_dst->state = thrd_dst->state == Halted ? Halted : Inactive; 336 proc_cor->state = Active; 255 337 } 256 338 257 339 // KERNEL_ONLY 258 void returnToKernel() {340 static void returnToKernel() { 259 341 coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner); 260 coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine; 261 ThreadCtxSwitch(thrd_cor, proc_cor); 342 thread_desc * thrd_src = kernelTLS.this_thread; 343 344 // set state of current coroutine to inactive 345 thrd_src->state = thrd_src->state == Halted ? Halted : Inactive; 346 proc_cor->state = Active; 347 int local_errno = *__volatile_errno(); 348 #if defined( __i386 ) || defined( __x86_64 ) 349 __x87_store; 350 #endif 351 352 // set new coroutine that the processor is executing 353 // and context switch to it 354 verify( proc_cor->context.SP ); 355 CtxSwitch( &thrd_src->context, &proc_cor->context ); 356 357 // set state of new coroutine to active 358 proc_cor->state = proc_cor->state == Halted ? Halted : Inactive; 359 thrd_src->state = Active; 360 361 #if defined( __i386 ) || defined( __x86_64 ) 362 __x87_load; 363 #endif 364 *__volatile_errno() = local_errno; 262 365 } 263 366 … … 265 368 // Once a thread has finished running, some of 266 369 // its final actions must be executed from the kernel 267 void finishRunning(processor * this) with( this->finish ) {370 static void finishRunning(processor * this) with( this->finish ) { 268 371 verify( ! kernelTLS.preemption_state.enabled ); 269 372 choose( action_code ) { … … 295 398 } 296 399 297 // Handles spinning logic298 // TODO : find some strategy to put cores to sleep after some time299 void spin(processor * this, unsigned int * spin_count) {300 // (*spin_count)++;301 halt(this);302 }303 304 400 // KERNEL_ONLY 305 401 // Context invoker for processors 306 402 // This is the entry point for processors (kernel threads) 307 403 // It effectively constructs a coroutine by stealing the pthread stack 308 void * CtxInvokeProcessor(void * arg) {404 static void * CtxInvokeProcessor(void * arg) { 309 405 processor * proc = (processor *) arg; 310 406 kernelTLS.this_processor = proc; 311 kernelTLS.this_coroutine = NULL;312 407 kernelTLS.this_thread = NULL; 313 408 kernelTLS.preemption_state.[enabled, disable_count] = [false, 1]; … … 316 411 // to waste the perfectly valid stack create by pthread. 317 412 current_stack_info_t info; 318 machine_context_t ctx;319 info. context= &ctx;413 __stack_t ctx; 414 info.storage = &ctx; 320 415 (proc->runner){ proc, &info }; 321 416 322 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack. base);417 __cfaabi_dbg_print_safe("Coroutine : created stack %p\n", get_coroutine(proc->runner)->stack.storage); 323 418 324 419 //Set global state 325 kernelTLS.this_coroutine = get_coroutine(proc->runner);326 420 kernelTLS.this_thread = NULL; 327 421 … … 343 437 } 344 438 345 void start(processor * this) {439 static void start(processor * this) { 346 440 __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", this); 347 441 … … 352 446 353 447 // KERNEL_ONLY 354 void kernel_first_resume( processor * this) {355 coroutine_desc * src = kernelTLS.this_coroutine;448 void kernel_first_resume( processor * this ) { 449 thread_desc * src = mainThread; 356 450 coroutine_desc * dst = get_coroutine(this->runner); 357 451 358 452 verify( ! kernelTLS.preemption_state.enabled ); 359 453 360 create_stack(&dst->stack, dst->stack.size);454 __stack_prepare( &dst->stack, 65000 ); 361 455 CtxStart(&this->runner, CtxInvokeCoroutine); 362 456 363 457 verify( ! kernelTLS.preemption_state.enabled ); 364 458 365 dst->last = src;366 dst->starter = dst->starter ? dst->starter : src;459 dst->last = &src->self_cor; 460 dst->starter = dst->starter ? dst->starter : &src->self_cor; 367 461 368 462 // set state of current coroutine to inactive 369 463 src->state = src->state == Halted ? Halted : Inactive; 370 464 371 // set new coroutine that task is executing372 kernelTLS.this_coroutine = dst;373 374 // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch.375 // Therefore, when first creating a coroutine, interrupts are enable before calling the main.376 // This is consistent with thread creation. However, when creating the main processor coroutine,377 // we wan't interrupts to be disabled. Therefore, we double-disable interrupts here so they will378 // stay disabled.379 disable_interrupts();380 381 465 // context switch to specified coroutine 382 assert( src->stack.context);383 CtxSwitch( src->stack.context, dst->stack.context );466 verify( dst->context.SP ); 467 CtxSwitch( &src->context, &dst->context ); 384 468 // when CtxSwitch returns we are back in the src coroutine 385 469 … … 388 472 389 473 verify( ! kernelTLS.preemption_state.enabled ); 474 } 475 476 // KERNEL_ONLY 477 void kernel_last_resume( processor * this ) { 478 coroutine_desc * src = &mainThread->self_cor; 479 coroutine_desc * dst = get_coroutine(this->runner); 480 481 verify( ! kernelTLS.preemption_state.enabled ); 482 verify( dst->starter == src ); 483 verify( dst->context.SP ); 484 485 // context switch to the processor 486 CtxSwitch( &src->context, &dst->context ); 390 487 } 391 488 … … 396 493 void ScheduleThread( thread_desc * thrd ) { 397 494 verify( thrd ); 398 verify( thrd->s elf_cor.state != Halted );495 verify( thrd->state != Halted ); 399 496 400 497 verify( ! kernelTLS.preemption_state.enabled ); … … 408 505 unlock( ready_queue_lock ); 409 506 410 if( was_empty) {507 if(was_empty) { 411 508 lock (proc_list_lock __cfaabi_dbg_ctx2); 412 509 if(idles) { 413 wake (idles.head);510 wake_fast(idles.head); 414 511 } 415 512 unlock (proc_list_lock); 416 513 } 514 else if( struct processor * idle = idles.head ) { 515 wake_fast(idle); 516 } 517 417 518 } 418 519 … … 545 646 //----------------------------------------------------------------------------- 546 647 // Kernel boot procedures 547 void kernel_startup(void) {648 static void kernel_startup(void) { 548 649 verify( ! kernelTLS.preemption_state.enabled ); 549 650 __cfaabi_dbg_print_safe("Kernel : Starting\n"); 651 652 __page_size = sysconf( _SC_PAGESIZE ); 550 653 551 654 __cfa_dbg_global_clusters.list{ __get }; … … 563 666 mainThread = (thread_desc *)&storage_mainThread; 564 667 current_stack_info_t info; 668 info.storage = (__stack_t*)&storage_mainThreadCtx; 565 669 (*mainThread){ &info }; 566 670 … … 597 701 kernelTLS.this_processor = mainProcessor; 598 702 kernelTLS.this_thread = mainThread; 599 kernelTLS.this_coroutine = &mainThread->self_cor;600 703 601 704 // Enable preemption … … 621 724 } 622 725 623 void kernel_shutdown(void) {726 static void kernel_shutdown(void) { 624 727 __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n"); 625 728 … … 632 735 // which is currently here 633 736 __atomic_store_n(&mainProcessor->do_terminate, true, __ATOMIC_RELEASE); 634 returnToKernel();737 kernel_last_resume( kernelTLS.this_processor ); 635 738 mainThread->self_cor.state = Halted; 636 739 … … 658 761 // Kernel Quiescing 659 762 //============================================================================================= 660 661 void halt(processor * this) with( *this ) { 662 verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 763 static void halt(processor * this) with( *this ) { 764 // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 663 765 664 766 with( *cltr ) { … … 671 773 __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this); 672 774 673 // #ifdef __CFA_WITH_VERIFY__ 674 // int sval = 0; 675 // sem_getvalue(&this->idleLock, &sval); 676 // verifyf(sval < 200, "Binary semaphore reached value %d : \n", sval); 677 // #endif 678 679 verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 680 int __attribute__((unused)) ret = sem_wait(&idleLock); 681 // verifyf(ret >= 0 || errno == EINTR, "Sem_wait returned %d (errno %d : %s\n", ret, errno, strerror(errno)); 682 683 // wait( idleLock ); 775 wait( idleLock ); 684 776 685 777 __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this); … … 693 785 } 694 786 695 void wake(processor * this) {696 __cfaabi_dbg_print_safe("Kernel : Waking up processor %p\n", this);697 int __attribute__((unused)) ret = sem_post(&this->idleLock);698 // verifyf(ret >= 0 || errno == EINTR, "Sem_post returned %d (errno %d : %s\n", ret, errno, strerror(errno));699 700 // #ifdef __CFA_WITH_VERIFY__701 // int sval = 0;702 // sem_getvalue(&this->idleLock, &sval);703 // verifyf(sval < 200, "Binary semaphore reached value %d\n", sval);704 // #endif705 706 // post( this->idleLock );707 }708 709 787 //============================================================================================= 710 788 // Unexpected Terminating logic 711 789 //============================================================================================= 712 713 714 790 static __spinlock_t kernel_abort_lock; 715 791 static bool kernel_abort_called = false; … … 745 821 __cfaabi_dbg_bits_write( abort_text, len ); 746 822 747 if ( get_coroutine(thrd) != kernelTLS.this_coroutine) {748 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", kernelTLS.this_coroutine->name, kernelTLS.this_coroutine);823 if ( &thrd->self_cor != thrd->curr_cor ) { 824 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor ); 749 825 __cfaabi_dbg_bits_write( abort_text, len ); 750 826 } … … 833 909 void doregister( cluster * cltr, thread_desc & thrd ) { 834 910 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 911 cltr->nthreads += 1; 835 912 push_front(cltr->threads, thrd); 836 913 unlock (cltr->thread_list_lock); … … 840 917 lock (cltr->thread_list_lock __cfaabi_dbg_ctx2); 841 918 remove(cltr->threads, thrd ); 919 cltr->nthreads -= 1; 842 920 unlock(cltr->thread_list_lock); 843 921 } … … 845 923 void doregister( cluster * cltr, processor * proc ) { 846 924 lock (cltr->proc_list_lock __cfaabi_dbg_ctx2); 925 cltr->nprocessors += 1; 847 926 push_front(cltr->procs, *proc); 848 927 unlock (cltr->proc_list_lock); … … 852 931 lock (cltr->proc_list_lock __cfaabi_dbg_ctx2); 853 932 remove(cltr->procs, *proc ); 933 cltr->nprocessors -= 1; 854 934 unlock(cltr->proc_list_lock); 855 935 } … … 858 938 // Debug 859 939 __cfaabi_dbg_debug_do( 860 void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) { 861 this.prev_name = prev_name; 862 this.prev_thrd = kernelTLS.this_thread; 940 extern "C" { 941 void __cfaabi_dbg_record(__spinlock_t & this, const char * prev_name) { 942 this.prev_name = prev_name; 943 this.prev_thrd = kernelTLS.this_thread; 944 } 863 945 } 864 946 ) 947 948 //----------------------------------------------------------------------------- 949 // Debug 950 bool threading_enabled(void) { 951 return true; 952 } 865 953 // Local Variables: // 866 954 // mode: c //
Note:
See TracChangeset
for help on using the changeset viewer.