Changes in src/libcfa/concurrency/kernel.c [b227f68:4aa2fb2]
- File:
-
- 1 edited
-
src/libcfa/concurrency/kernel.c (modified) (35 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
rb227f68 r4aa2fb2 15 15 // 16 16 17 #include "libhdr.h" 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" 18 25 19 26 //C Includes … … 28 35 29 36 //CFA Includes 30 #include " kernel_private.h"37 #include "libhdr.h" 31 38 #include "preemption.h" 32 #include "startup.h"33 39 34 40 //Private includes 35 41 #define __CFA_INVOKE_PRIVATE__ 36 42 #include "invoke.h" 37 38 //Start and stop routine for the kernel, declared first to make sure they run first39 void kernel_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_KERNEL ) ));40 void kernel_shutdown(void) __attribute__(( destructor ( STARTUP_PRIORITY_KERNEL ) ));41 43 42 44 //----------------------------------------------------------------------------- … … 57 59 // Global state 58 60 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 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 } 63 70 64 71 //----------------------------------------------------------------------------- 65 72 // Main thread construction 66 73 struct current_stack_info_t { 67 machine_context_t ctx; 74 machine_context_t ctx; 68 75 unsigned int size; // size of stack 69 76 void *base; // base of stack … … 99 106 100 107 void ?{}( coroutine_desc * this, current_stack_info_t * info) { 101 (&this->stack){ info }; 108 (&this->stack){ info }; 102 109 this->name = "Main Thread"; 103 110 this->errno_ = 0; … … 129 136 void ?{}(processor * this, cluster * cltr) { 130 137 this->cltr = cltr; 138 this->current_coroutine = NULL; 139 this->current_thread = NULL; 131 140 (&this->terminated){}; 132 141 this->is_terminated = false; 133 142 this->preemption_alarm = NULL; 134 143 this->preemption = default_preemption(); 144 this->disable_preempt_count = 1; //Start with interrupts disabled 135 145 this->pending_preemption = false; 136 146 … … 140 150 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) { 141 151 this->cltr = cltr; 152 this->current_coroutine = NULL; 153 this->current_thread = NULL; 142 154 (&this->terminated){}; 143 155 this->is_terminated = false; 144 this->preemption_alarm = NULL; 145 this->preemption = default_preemption(); 156 this->disable_preempt_count = 0; 146 157 this->pending_preemption = false; 147 this->kernel_thread = pthread_self();148 158 149 159 this->runner = runner; 150 LIB_DEBUG_PRINT_SAFE("Kernel : constructing systemprocessor context %p\n", runner);160 LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner); 151 161 runner{ this }; 152 162 } 153 154 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )155 163 156 164 void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) { … … 160 168 161 169 (&this->proc){ cltr, runner }; 162 163 verify( validate( &this->alarms ) );164 170 } 165 171 … … 178 184 179 185 void ^?{}(cluster * this) { 180 186 181 187 } 182 188 … … 197 203 198 204 thread_desc * readyThread = NULL; 199 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 205 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 200 206 { 201 207 readyThread = nextThread( this->cltr ); … … 203 209 if(readyThread) 204 210 { 205 verify( disable_preempt_count > 0 );206 207 211 runThread(this, readyThread); 208 209 verify( disable_preempt_count > 0 );210 212 211 213 //Some actions need to be taken from the kernel … … 227 229 } 228 230 229 // runThread runs a thread by context switching 230 // 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 231 233 void runThread(processor * this, thread_desc * dst) { 232 234 coroutine_desc * proc_cor = get_coroutine(this->runner); 233 235 coroutine_desc * thrd_cor = get_coroutine(dst); 234 236 235 237 //Reset the terminating actions here 236 238 this->finish.action_code = No_Action; 237 239 238 240 //Update global state 239 this _thread = dst;241 this->current_thread = dst; 240 242 241 243 // Context Switch to the thread … … 244 246 } 245 247 246 // Once a thread has finished running, some of 248 // Once a thread has finished running, some of 247 249 // its final actions must be executed from the kernel 248 250 void finishRunning(processor * this) { … … 254 256 } 255 257 else if( this->finish.action_code == Release_Schedule ) { 256 unlock( this->finish.lock ); 258 unlock( this->finish.lock ); 257 259 ScheduleThread( this->finish.thrd ); 258 260 } … … 287 289 processor * proc = (processor *) arg; 288 290 this_processor = proc; 289 this_coroutine = NULL;290 this_thread = NULL;291 disable_preempt_count = 1;292 291 // SKULLDUGGERY: We want to create a context for the processor coroutine 293 292 // which is needed for the 2-step context switch. However, there is no reason 294 // to waste the perfectly valid stack create by pthread. 293 // to waste the perfectly valid stack create by pthread. 295 294 current_stack_info_t info; 296 295 machine_context_t ctx; … … 301 300 302 301 //Set global state 303 this_coroutine = &proc->runner->__cor;304 this_thread = NULL;302 proc->current_coroutine = &proc->runner->__cor; 303 proc->current_thread = NULL; 305 304 306 305 //We now have a proper context from which to schedule threads 307 306 LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx); 308 307 309 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't 310 // resume it to start it like it normally would, it will just context switch 311 // 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 312 311 // appropriate stack. 313 312 proc_cor_storage.__cor.state = Active; … … 316 315 317 316 // Main routine of the core returned, the core is now fully terminated 318 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); 319 318 320 319 return NULL; … … 323 322 void start(processor * this) { 324 323 LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this); 325 326 // SIGALRM must only be caught by the system processor 327 sigset_t old_mask; 328 bool is_system_proc = this_processor == &systemProcessor->proc; 329 if ( is_system_proc ) { 330 // Child kernel-thread inherits the signal mask from the parent kernel-thread. So one special case for the 331 // system processor creating the user processor => toggle the blocking SIGALRM on system processor, create user 332 // processor, and toggle back (below) previous signal mask of the system processor. 333 334 sigset_t new_mask; 335 sigemptyset( &new_mask ); 336 sigemptyset( &old_mask ); 337 sigaddset( &new_mask, SIGALRM ); 338 339 if ( sigprocmask( SIG_BLOCK, &new_mask, &old_mask ) == -1 ) { 340 abortf( "internal error, sigprocmask" ); 341 } 342 343 assert( ! sigismember( &old_mask, SIGALRM ) ); 344 } 345 324 346 325 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 347 326 348 // Toggle back previous signal mask of system processor. 349 if ( is_system_proc ) { 350 if ( sigprocmask( SIG_SETMASK, &old_mask, NULL ) == -1 ) { 351 abortf( "internal error, sigprocmask" ); 352 } // if 353 } // if 354 355 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 356 328 } 357 329 … … 359 331 // Scheduler routines 360 332 void ScheduleThread( thread_desc * thrd ) { 361 // if( !thrd ) return; 362 assert( thrd ); 363 assert( thrd->cor.state != Halted ); 364 365 verify( disable_preempt_count > 0 ); 333 if( !thrd ) return; 366 334 367 335 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 368 369 lock( &systemProcessor->proc.cltr->lock DEBUG_CTX2);336 337 lock( &systemProcessor->proc.cltr->lock ); 370 338 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 371 339 unlock( &systemProcessor->proc.cltr->lock ); 372 373 verify( disable_preempt_count > 0 );374 340 } 375 341 376 342 thread_desc * nextThread(cluster * this) { 377 verify( disable_preempt_count > 0 ); 378 lock( &this->lock DEBUG_CTX2 ); 343 lock( &this->lock ); 379 344 thread_desc * head = pop_head( &this->ready_queue ); 380 345 unlock( &this->lock ); 381 verify( disable_preempt_count > 0 );382 346 return head; 383 347 } 384 348 385 void BlockInternal() { 386 disable_interrupts(); 387 verify( disable_preempt_count > 0 ); 349 void ScheduleInternal() { 388 350 suspend(); 389 verify( disable_preempt_count > 0 ); 390 enable_interrupts( DEBUG_CTX ); 391 } 392 393 void BlockInternal( spinlock * lock ) { 394 disable_interrupts(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 395 354 this_processor->finish.action_code = Release; 396 355 this_processor->finish.lock = lock; 397 398 verify( disable_preempt_count > 0 );399 356 suspend(); 400 verify( disable_preempt_count > 0 ); 401 402 enable_interrupts( DEBUG_CTX ); 403 } 404 405 void BlockInternal( thread_desc * thrd ) { 406 disable_interrupts(); 407 assert( thrd->cor.state != Halted ); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 408 360 this_processor->finish.action_code = Schedule; 409 361 this_processor->finish.thrd = thrd; 410 411 verify( disable_preempt_count > 0 );412 362 suspend(); 413 verify( disable_preempt_count > 0 ); 414 415 enable_interrupts( DEBUG_CTX ); 416 } 417 418 void BlockInternal( spinlock * lock, thread_desc * thrd ) { 419 disable_interrupts(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 420 366 this_processor->finish.action_code = Release_Schedule; 421 367 this_processor->finish.lock = lock; 422 368 this_processor->finish.thrd = thrd; 423 424 verify( disable_preempt_count > 0 );425 369 suspend(); 426 verify( disable_preempt_count > 0 ); 427 428 enable_interrupts( DEBUG_CTX ); 429 } 430 431 void BlockInternal(spinlock ** locks, unsigned short count) { 432 disable_interrupts(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 433 373 this_processor->finish.action_code = Release_Multi; 434 374 this_processor->finish.locks = locks; 435 375 this_processor->finish.lock_count = count; 436 437 verify( disable_preempt_count > 0 );438 376 suspend(); 439 verify( disable_preempt_count > 0 ); 440 441 enable_interrupts( DEBUG_CTX ); 442 } 443 444 void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 445 disable_interrupts(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 446 380 this_processor->finish.action_code = Release_Multi_Schedule; 447 381 this_processor->finish.locks = locks; … … 449 383 this_processor->finish.thrds = thrds; 450 384 this_processor->finish.thrd_count = thrd_count; 451 452 verify( disable_preempt_count > 0 );453 385 suspend(); 454 verify( disable_preempt_count > 0 );455 456 enable_interrupts( DEBUG_CTX );457 386 } 458 387 … … 463 392 // Kernel boot procedures 464 393 void kernel_startup(void) { 465 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 466 395 467 396 // Start by initializing the main thread 468 // SKULLDUGGERY: the mainThread steals the process main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 469 398 // which will then be scheduled by the systemProcessor normally 470 399 mainThread = (thread_desc *)&mainThread_storage; … … 474 403 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 475 404 405 // Enable preemption 406 kernel_start_preemption(); 407 476 408 // Initialize the system cluster 477 409 systemCluster = (cluster *)&systemCluster_storage; … … 485 417 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage }; 486 418 487 // Add the main thread to the ready queue 419 // Add the main thread to the ready queue 488 420 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 489 421 ScheduleThread(mainThread); … … 491 423 //initialize the global state variables 492 424 this_processor = &systemProcessor->proc; 493 this_thread = mainThread; 494 this_coroutine = &mainThread->cor; 495 disable_preempt_count = 1; 496 497 // Enable preemption 498 kernel_start_preemption(); 425 this_processor->current_thread = mainThread; 426 this_processor->current_coroutine = &mainThread->cor; 499 427 500 428 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 501 429 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 502 // mainThread is on the ready queue when this call is made. 430 // mainThread is on the ready queue when this call is made. 503 431 resume( systemProcessor->proc.runner ); 504 432 … … 507 435 // THE SYSTEM IS NOW COMPLETELY RUNNING 508 436 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 509 510 enable_interrupts( DEBUG_CTX );511 437 } 512 438 513 439 void kernel_shutdown(void) { 514 440 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 515 516 disable_interrupts();517 441 518 442 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 524 448 // THE SYSTEM IS NOW COMPLETELY STOPPED 525 449 526 // Disable preemption527 kernel_stop_preemption();528 529 450 // Destroy the system processor and its context in reverse order of construction 530 451 // These were manually constructed so we need manually destroy them … … 536 457 ^(mainThread){}; 537 458 538 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 539 460 } 540 461 … … 546 467 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 547 468 // the globalAbort flag is true. 548 lock( &kernel_abort_lock DEBUG_CTX2);469 lock( &kernel_abort_lock ); 549 470 550 471 // first task to abort ? … … 552 473 kernel_abort_called = true; 553 474 unlock( &kernel_abort_lock ); 554 } 475 } 555 476 else { 556 477 unlock( &kernel_abort_lock ); 557 478 558 479 sigset_t mask; 559 480 sigemptyset( &mask ); … … 561 482 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 562 483 sigsuspend( &mask ); // block the processor to prevent further damage during abort 563 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 564 } 565 566 return this_thread ;484 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 485 } 486 487 return this_thread(); 567 488 } 568 489 … … 573 494 __lib_debug_write( STDERR_FILENO, abort_text, len ); 574 495 575 if ( thrd != this_coroutine ) {576 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() ); 577 498 __lib_debug_write( STDERR_FILENO, abort_text, len ); 578 } 499 } 579 500 else { 580 501 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 584 505 extern "C" { 585 506 void __lib_debug_acquire() { 586 lock( &kernel_debug_lock DEBUG_CTX2);507 lock(&kernel_debug_lock); 587 508 } 588 509 589 510 void __lib_debug_release() { 590 unlock( &kernel_debug_lock);511 unlock(&kernel_debug_lock); 591 512 } 592 513 } … … 604 525 } 605 526 606 bool try_lock( spinlock * this DEBUG_CTX_PARAM2) {527 bool try_lock( spinlock * this ) { 607 528 return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 608 529 } 609 530 610 void lock( spinlock * this DEBUG_CTX_PARAM2) {531 void lock( spinlock * this ) { 611 532 for ( unsigned int i = 1;; i += 1 ) { 612 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 613 } 614 LIB_DEBUG_DO( 615 this->prev_name = caller; 616 this->prev_thrd = this_thread; 617 ) 618 } 619 620 void lock_yield( spinlock * this DEBUG_CTX_PARAM2 ) { 621 for ( unsigned int i = 1;; i += 1 ) { 622 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 623 yield(); 624 } 625 LIB_DEBUG_DO( 626 this->prev_name = caller; 627 this->prev_thrd = this_thread; 628 ) 629 } 630 533 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break; 534 } 535 } 631 536 632 537 void unlock( spinlock * this ) { … … 642 547 643 548 void wait( signal_once * this ) { 644 lock( &this->lock DEBUG_CTX2);549 lock( &this->lock ); 645 550 if( !this->cond ) { 646 append( &this->blocked, (thread_desc*)this_thread ); 647 BlockInternal( &this->lock ); 648 } 649 else { 650 unlock( &this->lock ); 651 } 551 append( &this->blocked, this_thread() ); 552 ScheduleInternal( &this->lock ); 553 lock( &this->lock ); 554 } 555 unlock( &this->lock ); 652 556 } 653 557 654 558 void signal( signal_once * this ) { 655 lock( &this->lock DEBUG_CTX2);559 lock( &this->lock ); 656 560 { 657 561 this->cond = true; 658 562 659 disable_interrupts();660 563 thread_desc * it; 661 564 while( it = pop_head( &this->blocked) ) { 662 565 ScheduleThread( it ); 663 566 } 664 enable_interrupts( DEBUG_CTX );665 567 } 666 568 unlock( &this->lock ); … … 688 590 } 689 591 head->next = NULL; 690 } 592 } 691 593 return head; 692 594 } … … 707 609 this->top = top->next; 708 610 top->next = NULL; 709 } 611 } 710 612 return top; 711 613 }
Note:
See TracChangeset
for help on using the changeset viewer.