Changes in src/libcfa/concurrency/kernel.c [4aa2fb2:cd17862]
- File:
-
- 1 edited
-
src/libcfa/concurrency/kernel.c (modified) (35 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
r4aa2fb2 rcd17862 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 41 35 #define __CFA_INVOKE_PRIVATE__ 42 36 #include "invoke.h" 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 ) )); 43 41 44 42 //----------------------------------------------------------------------------- … … 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 unsigned short disable_preempt_count = 1; 70 63 71 64 //----------------------------------------------------------------------------- 72 65 // Main thread construction 73 66 struct current_stack_info_t { 74 machine_context_t ctx; 67 machine_context_t ctx; 75 68 unsigned int size; // size of stack 76 69 void *base; // base of stack … … 106 99 107 100 void ?{}( coroutine_desc * this, current_stack_info_t * info) { 108 (&this->stack){ info }; 101 (&this->stack){ info }; 109 102 this->name = "Main Thread"; 110 103 this->errno_ = 0; … … 136 129 void ?{}(processor * this, cluster * cltr) { 137 130 this->cltr = cltr; 138 this->current_coroutine = NULL;139 this->current_thread = NULL;140 131 (&this->terminated){}; 141 132 this->is_terminated = false; 142 133 this->preemption_alarm = NULL; 143 134 this->preemption = default_preemption(); 144 this->disable_preempt_count = 1; //Start with interrupts disabled145 135 this->pending_preemption = false; 146 136 … … 150 140 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) { 151 141 this->cltr = cltr; 152 this->current_coroutine = NULL;153 this->current_thread = NULL;154 142 (&this->terminated){}; 155 143 this->is_terminated = false; 156 this->disable_preempt_count = 0; 144 this->preemption_alarm = NULL; 145 this->preemption = default_preemption(); 157 146 this->pending_preemption = false; 147 this->kernel_thread = pthread_self(); 158 148 159 149 this->runner = runner; 160 LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner);150 LIB_DEBUG_PRINT_SAFE("Kernel : constructing system processor context %p\n", runner); 161 151 runner{ this }; 162 152 } 153 154 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); ) 163 155 164 156 void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) { … … 168 160 169 161 (&this->proc){ cltr, runner }; 162 163 verify( validate( &this->alarms ) ); 170 164 } 171 165 … … 184 178 185 179 void ^?{}(cluster * this) { 186 180 187 181 } 188 182 … … 203 197 204 198 thread_desc * readyThread = NULL; 205 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 199 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 206 200 { 207 201 readyThread = nextThread( this->cltr ); … … 209 203 if(readyThread) 210 204 { 205 verify( disable_preempt_count > 0 ); 206 211 207 runThread(this, readyThread); 208 209 verify( disable_preempt_count > 0 ); 212 210 213 211 //Some actions need to be taken from the kernel … … 229 227 } 230 228 231 // runThread runs a thread by context switching 232 // from the processor coroutine to the target thread 229 // runThread runs a thread by context switching 230 // from the processor coroutine to the target thread 233 231 void runThread(processor * this, thread_desc * dst) { 234 232 coroutine_desc * proc_cor = get_coroutine(this->runner); 235 233 coroutine_desc * thrd_cor = get_coroutine(dst); 236 234 237 235 //Reset the terminating actions here 238 236 this->finish.action_code = No_Action; 239 237 240 238 //Update global state 241 this ->current_thread = dst;239 this_thread = dst; 242 240 243 241 // Context Switch to the thread … … 246 244 } 247 245 248 // Once a thread has finished running, some of 246 // Once a thread has finished running, some of 249 247 // its final actions must be executed from the kernel 250 248 void finishRunning(processor * this) { … … 256 254 } 257 255 else if( this->finish.action_code == Release_Schedule ) { 258 unlock( this->finish.lock ); 256 unlock( this->finish.lock ); 259 257 ScheduleThread( this->finish.thrd ); 260 258 } … … 289 287 processor * proc = (processor *) arg; 290 288 this_processor = proc; 289 this_coroutine = NULL; 290 this_thread = NULL; 291 disable_preempt_count = 1; 291 292 // SKULLDUGGERY: We want to create a context for the processor coroutine 292 293 // which is needed for the 2-step context switch. However, there is no reason 293 // to waste the perfectly valid stack create by pthread. 294 // to waste the perfectly valid stack create by pthread. 294 295 current_stack_info_t info; 295 296 machine_context_t ctx; … … 300 301 301 302 //Set global state 302 proc->current_coroutine = &proc->runner->__cor;303 proc->current_thread = NULL;303 this_coroutine = &proc->runner->__cor; 304 this_thread = NULL; 304 305 305 306 //We now have a proper context from which to schedule threads 306 307 LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx); 307 308 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 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 311 312 // appropriate stack. 312 313 proc_cor_storage.__cor.state = Active; … … 315 316 316 317 // 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); 318 LIB_DEBUG_PRINT_SAFE("Kernel : core %p main ended (%p)\n", proc, proc->runner); 318 319 319 320 return NULL; … … 322 323 void start(processor * this) { 323 324 LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this); 324 325 325 326 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 326 327 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 328 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 328 329 } 329 330 … … 331 332 // Scheduler routines 332 333 void ScheduleThread( thread_desc * thrd ) { 333 if( !thrd ) return; 334 // if( !thrd ) return; 335 assert( thrd ); 336 assert( thrd->cor.state != Halted ); 337 338 verify( disable_preempt_count > 0 ); 334 339 335 340 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 336 337 lock( &systemProcessor->proc.cltr->lock );341 342 lock( &systemProcessor->proc.cltr->lock DEBUG_CTX2 ); 338 343 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 339 344 unlock( &systemProcessor->proc.cltr->lock ); 345 346 verify( disable_preempt_count > 0 ); 340 347 } 341 348 342 349 thread_desc * nextThread(cluster * this) { 343 lock( &this->lock ); 350 verify( disable_preempt_count > 0 ); 351 lock( &this->lock DEBUG_CTX2 ); 344 352 thread_desc * head = pop_head( &this->ready_queue ); 345 353 unlock( &this->lock ); 354 verify( disable_preempt_count > 0 ); 346 355 return head; 347 356 } 348 357 349 void ScheduleInternal() { 358 void BlockInternal() { 359 disable_interrupts(); 360 verify( disable_preempt_count > 0 ); 350 361 suspend(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 362 verify( disable_preempt_count > 0 ); 363 enable_interrupts( DEBUG_CTX ); 364 } 365 366 void BlockInternal( spinlock * lock ) { 367 disable_interrupts(); 354 368 this_processor->finish.action_code = Release; 355 369 this_processor->finish.lock = lock; 370 371 verify( disable_preempt_count > 0 ); 356 372 suspend(); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 373 verify( disable_preempt_count > 0 ); 374 375 enable_interrupts( DEBUG_CTX ); 376 } 377 378 void BlockInternal( thread_desc * thrd ) { 379 disable_interrupts(); 380 assert( thrd->cor.state != Halted ); 360 381 this_processor->finish.action_code = Schedule; 361 382 this_processor->finish.thrd = thrd; 383 384 verify( disable_preempt_count > 0 ); 362 385 suspend(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 386 verify( disable_preempt_count > 0 ); 387 388 enable_interrupts( DEBUG_CTX ); 389 } 390 391 void BlockInternal( spinlock * lock, thread_desc * thrd ) { 392 disable_interrupts(); 366 393 this_processor->finish.action_code = Release_Schedule; 367 394 this_processor->finish.lock = lock; 368 395 this_processor->finish.thrd = thrd; 396 397 verify( disable_preempt_count > 0 ); 369 398 suspend(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 399 verify( disable_preempt_count > 0 ); 400 401 enable_interrupts( DEBUG_CTX ); 402 } 403 404 void BlockInternal(spinlock ** locks, unsigned short count) { 405 disable_interrupts(); 373 406 this_processor->finish.action_code = Release_Multi; 374 407 this_processor->finish.locks = locks; 375 408 this_processor->finish.lock_count = count; 409 410 verify( disable_preempt_count > 0 ); 376 411 suspend(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 412 verify( disable_preempt_count > 0 ); 413 414 enable_interrupts( DEBUG_CTX ); 415 } 416 417 void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 418 disable_interrupts(); 380 419 this_processor->finish.action_code = Release_Multi_Schedule; 381 420 this_processor->finish.locks = locks; … … 383 422 this_processor->finish.thrds = thrds; 384 423 this_processor->finish.thrd_count = thrd_count; 424 425 verify( disable_preempt_count > 0 ); 385 426 suspend(); 427 verify( disable_preempt_count > 0 ); 428 429 enable_interrupts( DEBUG_CTX ); 386 430 } 387 431 … … 392 436 // Kernel boot procedures 393 437 void kernel_startup(void) { 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 438 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 395 439 396 440 // Start by initializing the main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 441 // SKULLDUGGERY: the mainThread steals the process main thread 398 442 // which will then be scheduled by the systemProcessor normally 399 443 mainThread = (thread_desc *)&mainThread_storage; … … 403 447 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 404 448 405 // Enable preemption406 kernel_start_preemption();407 408 449 // Initialize the system cluster 409 450 systemCluster = (cluster *)&systemCluster_storage; … … 417 458 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage }; 418 459 419 // Add the main thread to the ready queue 460 // Add the main thread to the ready queue 420 461 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 421 462 ScheduleThread(mainThread); … … 423 464 //initialize the global state variables 424 465 this_processor = &systemProcessor->proc; 425 this_processor->current_thread = mainThread; 426 this_processor->current_coroutine = &mainThread->cor; 466 this_thread = mainThread; 467 this_coroutine = &mainThread->cor; 468 disable_preempt_count = 1; 469 470 // Enable preemption 471 kernel_start_preemption(); 427 472 428 473 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 429 474 // 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. 475 // mainThread is on the ready queue when this call is made. 431 476 resume( systemProcessor->proc.runner ); 432 477 … … 435 480 // THE SYSTEM IS NOW COMPLETELY RUNNING 436 481 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 482 483 enable_interrupts( DEBUG_CTX ); 437 484 } 438 485 439 486 void kernel_shutdown(void) { 440 487 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 488 489 disable_interrupts(); 441 490 442 491 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 448 497 // THE SYSTEM IS NOW COMPLETELY STOPPED 449 498 499 // Disable preemption 500 kernel_stop_preemption(); 501 450 502 // Destroy the system processor and its context in reverse order of construction 451 503 // These were manually constructed so we need manually destroy them … … 457 509 ^(mainThread){}; 458 510 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 511 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 460 512 } 461 513 … … 467 519 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 468 520 // the globalAbort flag is true. 469 lock( &kernel_abort_lock );521 lock( &kernel_abort_lock DEBUG_CTX2 ); 470 522 471 523 // first task to abort ? … … 473 525 kernel_abort_called = true; 474 526 unlock( &kernel_abort_lock ); 475 } 527 } 476 528 else { 477 529 unlock( &kernel_abort_lock ); 478 530 479 531 sigset_t mask; 480 532 sigemptyset( &mask ); … … 482 534 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 483 535 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 ();536 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 537 } 538 539 return this_thread; 488 540 } 489 541 … … 494 546 __lib_debug_write( STDERR_FILENO, abort_text, len ); 495 547 496 if ( thrd != this_coroutine ()) {497 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine ()->name, this_coroutine());548 if ( thrd != this_coroutine ) { 549 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine->name, this_coroutine ); 498 550 __lib_debug_write( STDERR_FILENO, abort_text, len ); 499 } 551 } 500 552 else { 501 553 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 505 557 extern "C" { 506 558 void __lib_debug_acquire() { 507 lock( &kernel_debug_lock);559 lock( &kernel_debug_lock DEBUG_CTX2 ); 508 560 } 509 561 510 562 void __lib_debug_release() { 511 unlock( &kernel_debug_lock);563 unlock( &kernel_debug_lock ); 512 564 } 513 565 } … … 525 577 } 526 578 527 bool try_lock( spinlock * this ) {579 bool try_lock( spinlock * this DEBUG_CTX_PARAM2 ) { 528 580 return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 529 581 } 530 582 531 void lock( spinlock * this ) {583 void lock( spinlock * this DEBUG_CTX_PARAM2 ) { 532 584 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 } 585 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 586 } 587 LIB_DEBUG_DO( 588 this->prev_name = caller; 589 this->prev_thrd = this_thread; 590 ) 591 } 592 593 void lock_yield( spinlock * this DEBUG_CTX_PARAM2 ) { 594 for ( unsigned int i = 1;; i += 1 ) { 595 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 596 yield(); 597 } 598 LIB_DEBUG_DO( 599 this->prev_name = caller; 600 this->prev_thrd = this_thread; 601 ) 602 } 603 536 604 537 605 void unlock( spinlock * this ) { … … 547 615 548 616 void wait( signal_once * this ) { 549 lock( &this->lock );617 lock( &this->lock DEBUG_CTX2 ); 550 618 if( !this->cond ) { 551 append( &this->blocked, this_thread() ); 552 ScheduleInternal( &this->lock ); 553 lock( &this->lock ); 554 } 555 unlock( &this->lock ); 619 append( &this->blocked, (thread_desc*)this_thread ); 620 BlockInternal( &this->lock ); 621 } 622 else { 623 unlock( &this->lock ); 624 } 556 625 } 557 626 558 627 void signal( signal_once * this ) { 559 lock( &this->lock );628 lock( &this->lock DEBUG_CTX2 ); 560 629 { 561 630 this->cond = true; 562 631 632 disable_interrupts(); 563 633 thread_desc * it; 564 634 while( it = pop_head( &this->blocked) ) { 565 635 ScheduleThread( it ); 566 636 } 637 enable_interrupts( DEBUG_CTX ); 567 638 } 568 639 unlock( &this->lock ); … … 590 661 } 591 662 head->next = NULL; 592 } 663 } 593 664 return head; 594 665 } … … 609 680 this->top = top->next; 610 681 top->next = NULL; 611 } 682 } 612 683 return top; 613 684 }
Note:
See TracChangeset
for help on using the changeset viewer.