Changes in src/libcfa/concurrency/kernel.c [1c273d0:4aa2fb2]
- File:
-
- 1 edited
-
src/libcfa/concurrency/kernel.c (modified) (33 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
r1c273d0 r4aa2fb2 59 59 // Global state 60 60 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; 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 } 65 70 66 71 //----------------------------------------------------------------------------- 67 72 // Main thread construction 68 73 struct current_stack_info_t { 69 machine_context_t ctx; 74 machine_context_t ctx; 70 75 unsigned int size; // size of stack 71 76 void *base; // base of stack … … 101 106 102 107 void ?{}( coroutine_desc * this, current_stack_info_t * info) { 103 (&this->stack){ info }; 108 (&this->stack){ info }; 104 109 this->name = "Main Thread"; 105 110 this->errno_ = 0; … … 131 136 void ?{}(processor * this, cluster * cltr) { 132 137 this->cltr = cltr; 138 this->current_coroutine = NULL; 139 this->current_thread = NULL; 133 140 (&this->terminated){}; 134 141 this->is_terminated = false; 135 142 this->preemption_alarm = NULL; 136 143 this->preemption = default_preemption(); 144 this->disable_preempt_count = 1; //Start with interrupts disabled 137 145 this->pending_preemption = false; 138 146 … … 142 150 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) { 143 151 this->cltr = cltr; 152 this->current_coroutine = NULL; 153 this->current_thread = NULL; 144 154 (&this->terminated){}; 145 155 this->is_terminated = false; 146 this->preemption_alarm = NULL; 147 this->preemption = default_preemption(); 156 this->disable_preempt_count = 0; 148 157 this->pending_preemption = false; 149 this->kernel_thread = pthread_self();150 158 151 159 this->runner = runner; 152 LIB_DEBUG_PRINT_SAFE("Kernel : constructing systemprocessor context %p\n", runner);160 LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner); 153 161 runner{ this }; 154 162 } 155 156 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )157 163 158 164 void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) { … … 162 168 163 169 (&this->proc){ cltr, runner }; 164 165 verify( validate( &this->alarms ) );166 170 } 167 171 … … 180 184 181 185 void ^?{}(cluster * this) { 182 186 183 187 } 184 188 … … 199 203 200 204 thread_desc * readyThread = NULL; 201 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 205 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 202 206 { 203 207 readyThread = nextThread( this->cltr ); … … 205 209 if(readyThread) 206 210 { 207 verify( disable_preempt_count > 0 );208 209 211 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 _thread = dst;241 this->current_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;294 291 // SKULLDUGGERY: We want to create a context for the processor coroutine 295 292 // which is needed for the 2-step context switch. However, there is no reason 296 // to waste the perfectly valid stack create by pthread. 293 // to waste the perfectly valid stack create by pthread. 297 294 current_stack_info_t info; 298 295 machine_context_t ctx; … … 303 300 304 301 //Set global state 305 this_coroutine = &proc->runner->__cor;306 this_thread = NULL;302 proc->current_coroutine = &proc->runner->__cor; 303 proc->current_thread = NULL; 307 304 308 305 //We now have a proper context from which to schedule threads 309 306 LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx); 310 307 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 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 314 311 // appropriate stack. 315 312 proc_cor_storage.__cor.state = Active; … … 318 315 319 316 // Main routine of the core returned, the core is now fully terminated 320 LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 317 LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 321 318 322 319 return NULL; … … 325 322 void start(processor * this) { 326 323 LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this); 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 324 348 325 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 349 326 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); 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 358 328 } 359 329 … … 361 331 // Scheduler routines 362 332 void ScheduleThread( thread_desc * thrd ) { 363 // if( !thrd ) return; 364 assert( thrd ); 365 assert( thrd->cor.state != Halted ); 366 367 verify( disable_preempt_count > 0 ); 333 if( !thrd ) return; 368 334 369 335 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 370 371 lock( &systemProcessor->proc.cltr->lock , __PRETTY_FUNCTION__);336 337 lock( &systemProcessor->proc.cltr->lock ); 372 338 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 373 339 unlock( &systemProcessor->proc.cltr->lock ); 374 375 verify( disable_preempt_count > 0 );376 340 } 377 341 378 342 thread_desc * nextThread(cluster * this) { 379 verify( disable_preempt_count > 0 ); 380 lock( &this->lock, __PRETTY_FUNCTION__ ); 343 lock( &this->lock ); 381 344 thread_desc * head = pop_head( &this->ready_queue ); 382 345 unlock( &this->lock ); 383 verify( disable_preempt_count > 0 );384 346 return head; 385 347 } 386 348 387 void BlockInternal() { 388 disable_interrupts(); 389 verify( disable_preempt_count > 0 ); 349 void ScheduleInternal() { 390 350 suspend(); 391 verify( disable_preempt_count > 0 ); 392 enable_interrupts( __PRETTY_FUNCTION__ ); 393 } 394 395 void BlockInternal( spinlock * lock ) { 396 disable_interrupts(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 397 354 this_processor->finish.action_code = Release; 398 355 this_processor->finish.lock = lock; 399 400 verify( disable_preempt_count > 0 );401 356 suspend(); 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 ); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 410 360 this_processor->finish.action_code = Schedule; 411 361 this_processor->finish.thrd = thrd; 412 413 verify( disable_preempt_count > 0 );414 362 suspend(); 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(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 422 366 this_processor->finish.action_code = Release_Schedule; 423 367 this_processor->finish.lock = lock; 424 368 this_processor->finish.thrd = thrd; 425 426 verify( disable_preempt_count > 0 );427 369 suspend(); 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(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 435 373 this_processor->finish.action_code = Release_Multi; 436 374 this_processor->finish.locks = locks; 437 375 this_processor->finish.lock_count = count; 438 439 verify( disable_preempt_count > 0 );440 376 suspend(); 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(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 448 380 this_processor->finish.action_code = Release_Multi_Schedule; 449 381 this_processor->finish.locks = locks; … … 451 383 this_processor->finish.thrds = thrds; 452 384 this_processor->finish.thrd_count = thrd_count; 453 454 verify( disable_preempt_count > 0 );455 385 suspend(); 456 verify( disable_preempt_count > 0 );457 458 enable_interrupts( __PRETTY_FUNCTION__ );459 386 } 460 387 … … 465 392 // Kernel boot procedures 466 393 void kernel_startup(void) { 467 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 468 395 469 396 // Start by initializing the main thread 470 // SKULLDUGGERY: the mainThread steals the process main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 471 398 // which will then be scheduled by the systemProcessor normally 472 399 mainThread = (thread_desc *)&mainThread_storage; … … 476 403 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 477 404 405 // Enable preemption 406 kernel_start_preemption(); 407 478 408 // Initialize the system cluster 479 409 systemCluster = (cluster *)&systemCluster_storage; … … 487 417 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage }; 488 418 489 // Add the main thread to the ready queue 419 // Add the main thread to the ready queue 490 420 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 491 421 ScheduleThread(mainThread); … … 493 423 //initialize the global state variables 494 424 this_processor = &systemProcessor->proc; 495 this_thread = mainThread; 496 this_coroutine = &mainThread->cor; 497 disable_preempt_count = 1; 498 499 // Enable preemption 500 kernel_start_preemption(); 425 this_processor->current_thread = mainThread; 426 this_processor->current_coroutine = &mainThread->cor; 501 427 502 428 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 503 429 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 504 // mainThread is on the ready queue when this call is made. 430 // mainThread is on the ready queue when this call is made. 505 431 resume( systemProcessor->proc.runner ); 506 432 … … 509 435 // THE SYSTEM IS NOW COMPLETELY RUNNING 510 436 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 511 512 enable_interrupts( __PRETTY_FUNCTION__ );513 437 } 514 438 515 439 void kernel_shutdown(void) { 516 440 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 517 518 disable_interrupts();519 441 520 442 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 526 448 // THE SYSTEM IS NOW COMPLETELY STOPPED 527 449 528 // Disable preemption529 kernel_stop_preemption();530 531 450 // Destroy the system processor and its context in reverse order of construction 532 451 // These were manually constructed so we need manually destroy them … … 538 457 ^(mainThread){}; 539 458 540 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 541 460 } 542 461 … … 548 467 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 549 468 // the globalAbort flag is true. 550 lock( &kernel_abort_lock , __PRETTY_FUNCTION__);469 lock( &kernel_abort_lock ); 551 470 552 471 // first task to abort ? … … 554 473 kernel_abort_called = true; 555 474 unlock( &kernel_abort_lock ); 556 } 475 } 557 476 else { 558 477 unlock( &kernel_abort_lock ); 559 478 560 479 sigset_t mask; 561 480 sigemptyset( &mask ); … … 563 482 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 564 483 sigsuspend( &mask ); // block the processor to prevent further damage during abort 565 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 566 } 567 568 return this_thread ;484 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 485 } 486 487 return this_thread(); 569 488 } 570 489 … … 575 494 __lib_debug_write( STDERR_FILENO, abort_text, len ); 576 495 577 if ( thrd != this_coroutine ) {578 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine ->name, this_coroutine);496 if ( thrd != this_coroutine() ) { 497 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine()->name, this_coroutine() ); 579 498 __lib_debug_write( STDERR_FILENO, abort_text, len ); 580 } 499 } 581 500 else { 582 501 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 586 505 extern "C" { 587 506 void __lib_debug_acquire() { 588 lock(&kernel_debug_lock , __PRETTY_FUNCTION__);507 lock(&kernel_debug_lock); 589 508 } 590 509 … … 606 525 } 607 526 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 ) { 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 ) { 615 532 for ( unsigned int i = 1;; i += 1 ) { 616 533 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break; 617 534 } 618 this->prev = caller;619 535 } 620 536 … … 631 547 632 548 void wait( signal_once * this ) { 633 lock( &this->lock , __PRETTY_FUNCTION__);549 lock( &this->lock ); 634 550 if( !this->cond ) { 635 append( &this->blocked, (thread_desc*)this_thread ); 636 BlockInternal( &this->lock ); 637 } 638 else { 639 unlock( &this->lock ); 640 } 551 append( &this->blocked, this_thread() ); 552 ScheduleInternal( &this->lock ); 553 lock( &this->lock ); 554 } 555 unlock( &this->lock ); 641 556 } 642 557 643 558 void signal( signal_once * this ) { 644 lock( &this->lock , __PRETTY_FUNCTION__);559 lock( &this->lock ); 645 560 { 646 561 this->cond = true; 647 562 648 disable_interrupts();649 563 thread_desc * it; 650 564 while( it = pop_head( &this->blocked) ) { 651 565 ScheduleThread( it ); 652 566 } 653 enable_interrupts( __PRETTY_FUNCTION__ );654 567 } 655 568 unlock( &this->lock ); … … 677 590 } 678 591 head->next = NULL; 679 } 592 } 680 593 return head; 681 594 } … … 696 609 this->top = top->next; 697 610 top->next = NULL; 698 } 611 } 699 612 return top; 700 613 }
Note:
See TracChangeset
for help on using the changeset viewer.