Changeset 3d4b23fa for src/libcfa/concurrency/kernel.c
- Timestamp:
- Jul 13, 2017, 3:57:04 PM (8 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- 0720e049, 9a1e509
- Parents:
- 55a68c3 (diff), d6ff3ff (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
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
r55a68c3 r3d4b23fa 15 15 // 16 16 17 #include "startup.h" 18 19 //Start and stop routine for the kernel, declared first to make sure they run first 20 void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) )); 21 void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) )); 22 23 //Header 24 #include "kernel_private.h" 17 #include "libhdr.h" 25 18 26 19 //C Includes … … 35 28 36 29 //CFA Includes 37 #include " libhdr.h"30 #include "kernel_private.h" 38 31 #include "preemption.h" 32 #include "startup.h" 39 33 40 34 //Private includes … … 42 36 #include "invoke.h" 43 37 38 //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 ) )); 41 44 42 //----------------------------------------------------------------------------- 45 43 // Kernel storage 46 #define KERNEL_STORAGE(T,X) static char X## _storage[sizeof(T)]44 #define KERNEL_STORAGE(T,X) static char X##Storage[sizeof(T)] 47 45 48 46 KERNEL_STORAGE(processorCtx_t, systemProcessorCtx); … … 50 48 KERNEL_STORAGE(system_proc_t, systemProcessor); 51 49 KERNEL_STORAGE(thread_desc, mainThread); 52 KERNEL_STORAGE(machine_context_t, mainThread _context);50 KERNEL_STORAGE(machine_context_t, mainThreadCtx); 53 51 54 52 cluster * systemCluster; … … 59 57 // Global state 60 58 61 thread_local processor * this_processor; 62 63 coroutine_desc * this_coroutine(void) { 64 return this_processor->current_coroutine; 65 } 66 67 thread_desc * this_thread(void) { 68 return this_processor->current_thread; 69 } 59 volatile thread_local processor * this_processor; 60 volatile thread_local coroutine_desc * this_coroutine; 61 volatile thread_local thread_desc * this_thread; 62 volatile thread_local bool preemption_in_progress = 0; 63 volatile thread_local unsigned short disable_preempt_count = 1; 70 64 71 65 //----------------------------------------------------------------------------- 72 66 // Main thread construction 73 67 struct current_stack_info_t { 74 machine_context_t ctx; 68 machine_context_t ctx; 75 69 unsigned int size; // size of stack 76 70 void *base; // base of stack … … 82 76 83 77 void ?{}( current_stack_info_t * this ) { 84 CtxGet( &this->ctx );78 CtxGet( this->ctx ); 85 79 this->base = this->ctx.FP; 86 80 this->storage = this->ctx.SP; … … 91 85 92 86 this->limit = (void *)(((intptr_t)this->base) - this->size); 93 this->context = &mainThread _context_storage;87 this->context = &mainThreadCtxStorage; 94 88 this->top = this->base; 95 89 } … … 106 100 107 101 void ?{}( coroutine_desc * this, current_stack_info_t * info) { 108 (&this->stack){ info }; 102 (&this->stack){ info }; 109 103 this->name = "Main Thread"; 110 104 this->errno_ = 0; … … 136 130 void ?{}(processor * this, cluster * cltr) { 137 131 this->cltr = cltr; 138 this->current_coroutine = NULL; 139 this->current_thread = NULL; 140 (&this->terminated){}; 132 (&this->terminated){ 0 }; 141 133 this->is_terminated = false; 142 134 this->preemption_alarm = NULL; 143 135 this->preemption = default_preemption(); 144 this->disable_preempt_count = 1; //Start with interrupts disabled145 136 this->pending_preemption = false; 146 137 … … 150 141 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) { 151 142 this->cltr = cltr; 152 this->current_coroutine = NULL; 153 this->current_thread = NULL; 154 (&this->terminated){}; 143 (&this->terminated){ 0 }; 155 144 this->is_terminated = false; 156 this->disable_preempt_count = 0; 145 this->preemption_alarm = NULL; 146 this->preemption = default_preemption(); 157 147 this->pending_preemption = false; 148 this->kernel_thread = pthread_self(); 158 149 159 150 this->runner = runner; 160 LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner);151 LIB_DEBUG_PRINT_SAFE("Kernel : constructing system processor context %p\n", runner); 161 152 runner{ this }; 162 153 } 154 155 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); ) 163 156 164 157 void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) { … … 168 161 169 162 (&this->proc){ cltr, runner }; 163 164 verify( validate( &this->alarms ) ); 170 165 } 171 166 … … 174 169 LIB_DEBUG_PRINT_SAFE("Kernel : core %p signaling termination\n", this); 175 170 this->is_terminated = true; 176 wait( &this->terminated ); 171 P( &this->terminated ); 172 pthread_join( this->kernel_thread, NULL ); 177 173 } 178 174 } … … 184 180 185 181 void ^?{}(cluster * this) { 186 182 187 183 } 188 184 … … 203 199 204 200 thread_desc * readyThread = NULL; 205 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 201 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 206 202 { 207 203 readyThread = nextThread( this->cltr ); … … 209 205 if(readyThread) 210 206 { 207 verify( disable_preempt_count > 0 ); 208 211 209 runThread(this, readyThread); 210 211 verify( disable_preempt_count > 0 ); 212 212 213 213 //Some actions need to be taken from the kernel … … 225 225 } 226 226 227 signal( &this->terminated ); 227 V( &this->terminated ); 228 228 229 LIB_DEBUG_PRINT_SAFE("Kernel : core %p terminated\n", this); 229 230 } 230 231 231 // runThread runs a thread by context switching 232 // from the processor coroutine to the target thread 232 // runThread runs a thread by context switching 233 // from the processor coroutine to the target thread 233 234 void runThread(processor * this, thread_desc * dst) { 234 235 coroutine_desc * proc_cor = get_coroutine(this->runner); 235 236 coroutine_desc * thrd_cor = get_coroutine(dst); 236 237 237 238 //Reset the terminating actions here 238 239 this->finish.action_code = No_Action; 239 240 240 241 //Update global state 241 this ->current_thread = dst;242 this_thread = dst; 242 243 243 244 // Context Switch to the thread … … 246 247 } 247 248 248 // Once a thread has finished running, some of 249 // Once a thread has finished running, some of 249 250 // its final actions must be executed from the kernel 250 251 void finishRunning(processor * this) { … … 256 257 } 257 258 else if( this->finish.action_code == Release_Schedule ) { 258 unlock( this->finish.lock ); 259 unlock( this->finish.lock ); 259 260 ScheduleThread( this->finish.thrd ); 260 261 } … … 289 290 processor * proc = (processor *) arg; 290 291 this_processor = proc; 292 this_coroutine = NULL; 293 this_thread = NULL; 294 disable_preempt_count = 1; 291 295 // SKULLDUGGERY: We want to create a context for the processor coroutine 292 296 // which is needed for the 2-step context switch. However, there is no reason 293 // to waste the perfectly valid stack create by pthread. 297 // to waste the perfectly valid stack create by pthread. 294 298 current_stack_info_t info; 295 299 machine_context_t ctx; … … 300 304 301 305 //Set global state 302 proc->current_coroutine = &proc->runner->__cor;303 proc->current_thread = NULL;306 this_coroutine = &proc->runner->__cor; 307 this_thread = NULL; 304 308 305 309 //We now have a proper context from which to schedule threads 306 310 LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx); 307 311 308 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't 309 // resume it to start it like it normally would, it will just context switch 310 // back to here. Instead directly call the main since we already are on the 312 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't 313 // resume it to start it like it normally would, it will just context switch 314 // back to here. Instead directly call the main since we already are on the 311 315 // appropriate stack. 312 316 proc_cor_storage.__cor.state = Active; … … 315 319 316 320 // Main routine of the core returned, the core is now fully terminated 317 LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 321 LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 318 322 319 323 return NULL; … … 322 326 void start(processor * this) { 323 327 LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this); 324 328 325 329 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 326 330 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 331 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 328 332 } 329 333 … … 331 335 // Scheduler routines 332 336 void ScheduleThread( thread_desc * thrd ) { 333 if( !thrd ) return; 337 // if( !thrd ) return; 338 assert( thrd ); 339 assert( thrd->cor.state != Halted ); 340 341 verify( disable_preempt_count > 0 ); 334 342 335 343 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 336 337 lock( &systemProcessor->proc.cltr->lock );344 345 lock( &systemProcessor->proc.cltr->lock DEBUG_CTX2 ); 338 346 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 339 347 unlock( &systemProcessor->proc.cltr->lock ); 348 349 verify( disable_preempt_count > 0 ); 340 350 } 341 351 342 352 thread_desc * nextThread(cluster * this) { 343 lock( &this->lock ); 353 verify( disable_preempt_count > 0 ); 354 lock( &this->lock DEBUG_CTX2 ); 344 355 thread_desc * head = pop_head( &this->ready_queue ); 345 356 unlock( &this->lock ); 357 verify( disable_preempt_count > 0 ); 346 358 return head; 347 359 } 348 360 349 void ScheduleInternal() { 361 void BlockInternal() { 362 disable_interrupts(); 363 verify( disable_preempt_count > 0 ); 350 364 suspend(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 365 verify( disable_preempt_count > 0 ); 366 enable_interrupts( DEBUG_CTX ); 367 } 368 369 void BlockInternal( spinlock * lock ) { 370 disable_interrupts(); 354 371 this_processor->finish.action_code = Release; 355 372 this_processor->finish.lock = lock; 373 374 verify( disable_preempt_count > 0 ); 356 375 suspend(); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 376 verify( disable_preempt_count > 0 ); 377 378 enable_interrupts( DEBUG_CTX ); 379 } 380 381 void BlockInternal( thread_desc * thrd ) { 382 disable_interrupts(); 383 assert( thrd->cor.state != Halted ); 360 384 this_processor->finish.action_code = Schedule; 361 385 this_processor->finish.thrd = thrd; 386 387 verify( disable_preempt_count > 0 ); 362 388 suspend(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 389 verify( disable_preempt_count > 0 ); 390 391 enable_interrupts( DEBUG_CTX ); 392 } 393 394 void BlockInternal( spinlock * lock, thread_desc * thrd ) { 395 disable_interrupts(); 366 396 this_processor->finish.action_code = Release_Schedule; 367 397 this_processor->finish.lock = lock; 368 398 this_processor->finish.thrd = thrd; 399 400 verify( disable_preempt_count > 0 ); 369 401 suspend(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 402 verify( disable_preempt_count > 0 ); 403 404 enable_interrupts( DEBUG_CTX ); 405 } 406 407 void BlockInternal(spinlock ** locks, unsigned short count) { 408 disable_interrupts(); 373 409 this_processor->finish.action_code = Release_Multi; 374 410 this_processor->finish.locks = locks; 375 411 this_processor->finish.lock_count = count; 412 413 verify( disable_preempt_count > 0 ); 376 414 suspend(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 415 verify( disable_preempt_count > 0 ); 416 417 enable_interrupts( DEBUG_CTX ); 418 } 419 420 void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 421 disable_interrupts(); 380 422 this_processor->finish.action_code = Release_Multi_Schedule; 381 423 this_processor->finish.locks = locks; … … 383 425 this_processor->finish.thrds = thrds; 384 426 this_processor->finish.thrd_count = thrd_count; 427 428 verify( disable_preempt_count > 0 ); 429 suspend(); 430 verify( disable_preempt_count > 0 ); 431 432 enable_interrupts( DEBUG_CTX ); 433 } 434 435 void LeaveThread(spinlock * lock, thread_desc * thrd) { 436 verify( disable_preempt_count > 0 ); 437 this_processor->finish.action_code = thrd ? Release_Schedule : Release; 438 this_processor->finish.lock = lock; 439 this_processor->finish.thrd = thrd; 440 385 441 suspend(); 386 442 } … … 392 448 // Kernel boot procedures 393 449 void kernel_startup(void) { 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 450 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 395 451 396 452 // Start by initializing the main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 453 // SKULLDUGGERY: the mainThread steals the process main thread 398 454 // which will then be scheduled by the systemProcessor normally 399 mainThread = (thread_desc *)&mainThread _storage;455 mainThread = (thread_desc *)&mainThreadStorage; 400 456 current_stack_info_t info; 401 457 mainThread{ &info }; … … 403 459 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 404 460 461 // Initialize the system cluster 462 systemCluster = (cluster *)&systemClusterStorage; 463 systemCluster{}; 464 465 LIB_DEBUG_PRINT_SAFE("Kernel : System cluster ready\n"); 466 467 // Initialize the system processor and the system processor ctx 468 // (the coroutine that contains the processing control flow) 469 systemProcessor = (system_proc_t *)&systemProcessorStorage; 470 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtxStorage }; 471 472 // Add the main thread to the ready queue 473 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 474 ScheduleThread(mainThread); 475 476 //initialize the global state variables 477 this_processor = &systemProcessor->proc; 478 this_thread = mainThread; 479 this_coroutine = &mainThread->cor; 480 disable_preempt_count = 1; 481 405 482 // Enable preemption 406 483 kernel_start_preemption(); 407 484 408 // Initialize the system cluster409 systemCluster = (cluster *)&systemCluster_storage;410 systemCluster{};411 412 LIB_DEBUG_PRINT_SAFE("Kernel : System cluster ready\n");413 414 // Initialize the system processor and the system processor ctx415 // (the coroutine that contains the processing control flow)416 systemProcessor = (system_proc_t *)&systemProcessor_storage;417 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage };418 419 // Add the main thread to the ready queue420 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread421 ScheduleThread(mainThread);422 423 //initialize the global state variables424 this_processor = &systemProcessor->proc;425 this_processor->current_thread = mainThread;426 this_processor->current_coroutine = &mainThread->cor;427 428 485 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 429 486 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 430 // mainThread is on the ready queue when this call is made. 487 // mainThread is on the ready queue when this call is made. 431 488 resume( systemProcessor->proc.runner ); 432 489 … … 435 492 // THE SYSTEM IS NOW COMPLETELY RUNNING 436 493 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 494 495 enable_interrupts( DEBUG_CTX ); 437 496 } 438 497 439 498 void kernel_shutdown(void) { 440 499 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 500 501 disable_interrupts(); 441 502 442 503 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 448 509 // THE SYSTEM IS NOW COMPLETELY STOPPED 449 510 511 // Disable preemption 512 kernel_stop_preemption(); 513 450 514 // Destroy the system processor and its context in reverse order of construction 451 515 // These were manually constructed so we need manually destroy them … … 457 521 ^(mainThread){}; 458 522 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 523 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 460 524 } 461 525 … … 467 531 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 468 532 // the globalAbort flag is true. 469 lock( &kernel_abort_lock );533 lock( &kernel_abort_lock DEBUG_CTX2 ); 470 534 471 535 // first task to abort ? … … 473 537 kernel_abort_called = true; 474 538 unlock( &kernel_abort_lock ); 475 } 539 } 476 540 else { 477 541 unlock( &kernel_abort_lock ); 478 542 479 543 sigset_t mask; 480 544 sigemptyset( &mask ); … … 482 546 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 483 547 sigsuspend( &mask ); // block the processor to prevent further damage during abort 484 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 485 } 486 487 return this_thread ();548 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 549 } 550 551 return this_thread; 488 552 } 489 553 … … 494 558 __lib_debug_write( STDERR_FILENO, abort_text, len ); 495 559 496 if ( thrd != this_coroutine ()) {497 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine ()->name, this_coroutine());560 if ( thrd != this_coroutine ) { 561 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine->name, this_coroutine ); 498 562 __lib_debug_write( STDERR_FILENO, abort_text, len ); 499 } 563 } 500 564 else { 501 565 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 505 569 extern "C" { 506 570 void __lib_debug_acquire() { 507 lock( &kernel_debug_lock);571 lock( &kernel_debug_lock DEBUG_CTX2 ); 508 572 } 509 573 510 574 void __lib_debug_release() { 511 unlock( &kernel_debug_lock);575 unlock( &kernel_debug_lock ); 512 576 } 513 577 } … … 525 589 } 526 590 527 bool try_lock( spinlock * this ) {591 bool try_lock( spinlock * this DEBUG_CTX_PARAM2 ) { 528 592 return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 529 593 } 530 594 531 void lock( spinlock * this ) {595 void lock( spinlock * this DEBUG_CTX_PARAM2 ) { 532 596 for ( unsigned int i = 1;; i += 1 ) { 533 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break; 534 } 535 } 597 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 598 } 599 LIB_DEBUG_DO( 600 this->prev_name = caller; 601 this->prev_thrd = this_thread; 602 ) 603 } 604 605 void lock_yield( spinlock * this DEBUG_CTX_PARAM2 ) { 606 for ( unsigned int i = 1;; i += 1 ) { 607 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 608 yield(); 609 } 610 LIB_DEBUG_DO( 611 this->prev_name = caller; 612 this->prev_thrd = this_thread; 613 ) 614 } 615 536 616 537 617 void unlock( spinlock * this ) { … … 539 619 } 540 620 541 void ?{}( signal_once * this ) { 542 this->cond = false; 543 } 544 void ^?{}( signal_once * this ) { 545 546 } 547 548 void wait( signal_once * this ) { 549 lock( &this->lock ); 550 if( !this->cond ) { 551 append( &this->blocked, this_thread() ); 552 ScheduleInternal( &this->lock ); 553 lock( &this->lock ); 554 } 621 void ?{}( semaphore * this, int count = 1 ) { 622 (&this->lock){}; 623 this->count = count; 624 (&this->waiting){}; 625 } 626 void ^?{}(semaphore * this) {} 627 628 void P(semaphore * this) { 629 lock( &this->lock DEBUG_CTX2 ); 630 this->count -= 1; 631 if ( this->count < 0 ) { 632 // queue current task 633 append( &this->waiting, (thread_desc *)this_thread ); 634 635 // atomically release spin lock and block 636 BlockInternal( &this->lock ); 637 } 638 else { 639 unlock( &this->lock ); 640 } 641 } 642 643 void V(semaphore * this) { 644 thread_desc * thrd = NULL; 645 lock( &this->lock DEBUG_CTX2 ); 646 this->count += 1; 647 if ( this->count <= 0 ) { 648 // remove task at head of waiting list 649 thrd = pop_head( &this->waiting ); 650 } 651 555 652 unlock( &this->lock ); 556 } 557 558 void signal( signal_once * this ) { 559 lock( &this->lock ); 560 { 561 this->cond = true; 562 563 thread_desc * it; 564 while( it = pop_head( &this->blocked) ) { 565 ScheduleThread( it ); 566 } 567 } 568 unlock( &this->lock ); 653 654 // make new owner 655 WakeThread( thrd ); 569 656 } 570 657 … … 590 677 } 591 678 head->next = NULL; 592 } 679 } 593 680 return head; 594 681 } … … 609 696 this->top = top->next; 610 697 top->next = NULL; 611 } 698 } 612 699 return top; 613 700 }
Note:
See TracChangeset
for help on using the changeset viewer.