Changes in src/libcfa/concurrency/kernel.c [4aa2fb2:1c273d0]
- File:
-
- 1 edited
-
src/libcfa/concurrency/kernel.c (modified) (33 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
r4aa2fb2 r1c273d0 59 59 // Global state 60 60 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 } 61 volatile thread_local processor * this_processor; 62 volatile thread_local coroutine_desc * this_coroutine; 63 volatile thread_local thread_desc * this_thread; 64 volatile thread_local unsigned short disable_preempt_count = 1; 70 65 71 66 //----------------------------------------------------------------------------- 72 67 // Main thread construction 73 68 struct current_stack_info_t { 74 machine_context_t ctx; 69 machine_context_t ctx; 75 70 unsigned int size; // size of stack 76 71 void *base; // base of stack … … 106 101 107 102 void ?{}( coroutine_desc * this, current_stack_info_t * info) { 108 (&this->stack){ info }; 103 (&this->stack){ info }; 109 104 this->name = "Main Thread"; 110 105 this->errno_ = 0; … … 136 131 void ?{}(processor * this, cluster * cltr) { 137 132 this->cltr = cltr; 138 this->current_coroutine = NULL;139 this->current_thread = NULL;140 133 (&this->terminated){}; 141 134 this->is_terminated = false; 142 135 this->preemption_alarm = NULL; 143 136 this->preemption = default_preemption(); 144 this->disable_preempt_count = 1; //Start with interrupts disabled145 137 this->pending_preemption = false; 146 138 … … 150 142 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) { 151 143 this->cltr = cltr; 152 this->current_coroutine = NULL;153 this->current_thread = NULL;154 144 (&this->terminated){}; 155 145 this->is_terminated = false; 156 this->disable_preempt_count = 0; 146 this->preemption_alarm = NULL; 147 this->preemption = default_preemption(); 157 148 this->pending_preemption = false; 149 this->kernel_thread = pthread_self(); 158 150 159 151 this->runner = runner; 160 LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner);152 LIB_DEBUG_PRINT_SAFE("Kernel : constructing system processor context %p\n", runner); 161 153 runner{ this }; 162 154 } 155 156 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); ) 163 157 164 158 void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) { … … 168 162 169 163 (&this->proc){ cltr, runner }; 164 165 verify( validate( &this->alarms ) ); 170 166 } 171 167 … … 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 … … 229 229 } 230 230 231 // runThread runs a thread by context switching 232 // from the processor coroutine to the target thread 231 // runThread runs a thread by context switching 232 // from the processor coroutine to the target thread 233 233 void runThread(processor * this, thread_desc * dst) { 234 234 coroutine_desc * proc_cor = get_coroutine(this->runner); 235 235 coroutine_desc * thrd_cor = get_coroutine(dst); 236 236 237 237 //Reset the terminating actions here 238 238 this->finish.action_code = No_Action; 239 239 240 240 //Update global state 241 this ->current_thread = dst;241 this_thread = dst; 242 242 243 243 // Context Switch to the thread … … 246 246 } 247 247 248 // Once a thread has finished running, some of 248 // Once a thread has finished running, some of 249 249 // its final actions must be executed from the kernel 250 250 void finishRunning(processor * this) { … … 256 256 } 257 257 else if( this->finish.action_code == Release_Schedule ) { 258 unlock( this->finish.lock ); 258 unlock( this->finish.lock ); 259 259 ScheduleThread( this->finish.thrd ); 260 260 } … … 289 289 processor * proc = (processor *) arg; 290 290 this_processor = proc; 291 this_coroutine = NULL; 292 this_thread = NULL; 293 disable_preempt_count = 1; 291 294 // SKULLDUGGERY: We want to create a context for the processor coroutine 292 295 // which is needed for the 2-step context switch. However, there is no reason 293 // to waste the perfectly valid stack create by pthread. 296 // to waste the perfectly valid stack create by pthread. 294 297 current_stack_info_t info; 295 298 machine_context_t ctx; … … 300 303 301 304 //Set global state 302 proc->current_coroutine = &proc->runner->__cor;303 proc->current_thread = NULL;305 this_coroutine = &proc->runner->__cor; 306 this_thread = NULL; 304 307 305 308 //We now have a proper context from which to schedule threads 306 309 LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx); 307 310 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 311 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't 312 // resume it to start it like it normally would, it will just context switch 313 // back to here. Instead directly call the main since we already are on the 311 314 // appropriate stack. 312 315 proc_cor_storage.__cor.state = Active; … … 315 318 316 319 // 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); 320 LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 318 321 319 322 return NULL; … … 322 325 void start(processor * this) { 323 326 LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this); 324 327 328 // SIGALRM must only be caught by the system processor 329 sigset_t old_mask; 330 bool is_system_proc = this_processor == &systemProcessor->proc; 331 if ( is_system_proc ) { 332 // Child kernel-thread inherits the signal mask from the parent kernel-thread. So one special case for the 333 // system processor creating the user processor => toggle the blocking SIGALRM on system processor, create user 334 // processor, and toggle back (below) previous signal mask of the system processor. 335 336 sigset_t new_mask; 337 sigemptyset( &new_mask ); 338 sigemptyset( &old_mask ); 339 sigaddset( &new_mask, SIGALRM ); 340 341 if ( sigprocmask( SIG_BLOCK, &new_mask, &old_mask ) == -1 ) { 342 abortf( "internal error, sigprocmask" ); 343 } 344 345 assert( ! sigismember( &old_mask, SIGALRM ) ); 346 } 347 325 348 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 326 349 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 350 // Toggle back previous signal mask of system processor. 351 if ( is_system_proc ) { 352 if ( sigprocmask( SIG_SETMASK, &old_mask, NULL ) == -1 ) { 353 abortf( "internal error, sigprocmask" ); 354 } // if 355 } // if 356 357 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 328 358 } 329 359 … … 331 361 // Scheduler routines 332 362 void ScheduleThread( thread_desc * thrd ) { 333 if( !thrd ) return; 363 // if( !thrd ) return; 364 assert( thrd ); 365 assert( thrd->cor.state != Halted ); 366 367 verify( disable_preempt_count > 0 ); 334 368 335 369 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 336 337 lock( &systemProcessor->proc.cltr->lock );370 371 lock( &systemProcessor->proc.cltr->lock, __PRETTY_FUNCTION__ ); 338 372 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 339 373 unlock( &systemProcessor->proc.cltr->lock ); 374 375 verify( disable_preempt_count > 0 ); 340 376 } 341 377 342 378 thread_desc * nextThread(cluster * this) { 343 lock( &this->lock ); 379 verify( disable_preempt_count > 0 ); 380 lock( &this->lock, __PRETTY_FUNCTION__ ); 344 381 thread_desc * head = pop_head( &this->ready_queue ); 345 382 unlock( &this->lock ); 383 verify( disable_preempt_count > 0 ); 346 384 return head; 347 385 } 348 386 349 void ScheduleInternal() { 387 void BlockInternal() { 388 disable_interrupts(); 389 verify( disable_preempt_count > 0 ); 350 390 suspend(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 391 verify( disable_preempt_count > 0 ); 392 enable_interrupts( __PRETTY_FUNCTION__ ); 393 } 394 395 void BlockInternal( spinlock * lock ) { 396 disable_interrupts(); 354 397 this_processor->finish.action_code = Release; 355 398 this_processor->finish.lock = lock; 399 400 verify( disable_preempt_count > 0 ); 356 401 suspend(); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 402 verify( disable_preempt_count > 0 ); 403 404 enable_interrupts( __PRETTY_FUNCTION__ ); 405 } 406 407 void BlockInternal( thread_desc * thrd ) { 408 disable_interrupts(); 409 assert( thrd->cor.state != Halted ); 360 410 this_processor->finish.action_code = Schedule; 361 411 this_processor->finish.thrd = thrd; 412 413 verify( disable_preempt_count > 0 ); 362 414 suspend(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 415 verify( disable_preempt_count > 0 ); 416 417 enable_interrupts( __PRETTY_FUNCTION__ ); 418 } 419 420 void BlockInternal( spinlock * lock, thread_desc * thrd ) { 421 disable_interrupts(); 366 422 this_processor->finish.action_code = Release_Schedule; 367 423 this_processor->finish.lock = lock; 368 424 this_processor->finish.thrd = thrd; 425 426 verify( disable_preempt_count > 0 ); 369 427 suspend(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 428 verify( disable_preempt_count > 0 ); 429 430 enable_interrupts( __PRETTY_FUNCTION__ ); 431 } 432 433 void BlockInternal(spinlock ** locks, unsigned short count) { 434 disable_interrupts(); 373 435 this_processor->finish.action_code = Release_Multi; 374 436 this_processor->finish.locks = locks; 375 437 this_processor->finish.lock_count = count; 438 439 verify( disable_preempt_count > 0 ); 376 440 suspend(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 441 verify( disable_preempt_count > 0 ); 442 443 enable_interrupts( __PRETTY_FUNCTION__ ); 444 } 445 446 void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 447 disable_interrupts(); 380 448 this_processor->finish.action_code = Release_Multi_Schedule; 381 449 this_processor->finish.locks = locks; … … 383 451 this_processor->finish.thrds = thrds; 384 452 this_processor->finish.thrd_count = thrd_count; 453 454 verify( disable_preempt_count > 0 ); 385 455 suspend(); 456 verify( disable_preempt_count > 0 ); 457 458 enable_interrupts( __PRETTY_FUNCTION__ ); 386 459 } 387 460 … … 392 465 // Kernel boot procedures 393 466 void kernel_startup(void) { 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 467 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 395 468 396 469 // Start by initializing the main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 470 // SKULLDUGGERY: the mainThread steals the process main thread 398 471 // which will then be scheduled by the systemProcessor normally 399 472 mainThread = (thread_desc *)&mainThread_storage; … … 403 476 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 404 477 405 // Enable preemption406 kernel_start_preemption();407 408 478 // Initialize the system cluster 409 479 systemCluster = (cluster *)&systemCluster_storage; … … 417 487 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage }; 418 488 419 // Add the main thread to the ready queue 489 // Add the main thread to the ready queue 420 490 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 421 491 ScheduleThread(mainThread); … … 423 493 //initialize the global state variables 424 494 this_processor = &systemProcessor->proc; 425 this_processor->current_thread = mainThread; 426 this_processor->current_coroutine = &mainThread->cor; 495 this_thread = mainThread; 496 this_coroutine = &mainThread->cor; 497 disable_preempt_count = 1; 498 499 // Enable preemption 500 kernel_start_preemption(); 427 501 428 502 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 429 503 // 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. 504 // mainThread is on the ready queue when this call is made. 431 505 resume( systemProcessor->proc.runner ); 432 506 … … 435 509 // THE SYSTEM IS NOW COMPLETELY RUNNING 436 510 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 511 512 enable_interrupts( __PRETTY_FUNCTION__ ); 437 513 } 438 514 439 515 void kernel_shutdown(void) { 440 516 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 517 518 disable_interrupts(); 441 519 442 520 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 448 526 // THE SYSTEM IS NOW COMPLETELY STOPPED 449 527 528 // Disable preemption 529 kernel_stop_preemption(); 530 450 531 // Destroy the system processor and its context in reverse order of construction 451 532 // These were manually constructed so we need manually destroy them … … 457 538 ^(mainThread){}; 458 539 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 540 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 460 541 } 461 542 … … 467 548 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 468 549 // the globalAbort flag is true. 469 lock( &kernel_abort_lock );550 lock( &kernel_abort_lock, __PRETTY_FUNCTION__ ); 470 551 471 552 // first task to abort ? … … 473 554 kernel_abort_called = true; 474 555 unlock( &kernel_abort_lock ); 475 } 556 } 476 557 else { 477 558 unlock( &kernel_abort_lock ); 478 559 479 560 sigset_t mask; 480 561 sigemptyset( &mask ); … … 482 563 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 483 564 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 ();565 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 566 } 567 568 return this_thread; 488 569 } 489 570 … … 494 575 __lib_debug_write( STDERR_FILENO, abort_text, len ); 495 576 496 if ( thrd != this_coroutine ()) {497 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine ()->name, this_coroutine());577 if ( thrd != this_coroutine ) { 578 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine->name, this_coroutine ); 498 579 __lib_debug_write( STDERR_FILENO, abort_text, len ); 499 } 580 } 500 581 else { 501 582 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 505 586 extern "C" { 506 587 void __lib_debug_acquire() { 507 lock(&kernel_debug_lock );588 lock(&kernel_debug_lock, __PRETTY_FUNCTION__); 508 589 } 509 590 … … 525 606 } 526 607 527 bool try_lock( spinlock * this ) { 528 return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 529 } 530 531 void lock( spinlock * this ) { 608 bool try_lock( spinlock * this, const char * caller ) { 609 bool ret = this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 610 this->prev = caller; 611 return ret; 612 } 613 614 void lock( spinlock * this, const char * caller ) { 532 615 for ( unsigned int i = 1;; i += 1 ) { 533 616 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break; 534 617 } 618 this->prev = caller; 535 619 } 536 620 … … 547 631 548 632 void wait( signal_once * this ) { 549 lock( &this->lock );633 lock( &this->lock, __PRETTY_FUNCTION__ ); 550 634 if( !this->cond ) { 551 append( &this->blocked, this_thread() ); 552 ScheduleInternal( &this->lock ); 553 lock( &this->lock ); 554 } 555 unlock( &this->lock ); 635 append( &this->blocked, (thread_desc*)this_thread ); 636 BlockInternal( &this->lock ); 637 } 638 else { 639 unlock( &this->lock ); 640 } 556 641 } 557 642 558 643 void signal( signal_once * this ) { 559 lock( &this->lock );644 lock( &this->lock, __PRETTY_FUNCTION__ ); 560 645 { 561 646 this->cond = true; 562 647 648 disable_interrupts(); 563 649 thread_desc * it; 564 650 while( it = pop_head( &this->blocked) ) { 565 651 ScheduleThread( it ); 566 652 } 653 enable_interrupts( __PRETTY_FUNCTION__ ); 567 654 } 568 655 unlock( &this->lock ); … … 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.