Changes in src/libcfa/concurrency/kernel.c [cd17862:4aa2fb2]
- File:
-
- 1 edited
-
src/libcfa/concurrency/kernel.c (modified) (35 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
rcd17862 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 324 326 325 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 327 326 328 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 329 328 } 330 329 … … 332 331 // Scheduler routines 333 332 void ScheduleThread( thread_desc * thrd ) { 334 // if( !thrd ) return; 335 assert( thrd ); 336 assert( thrd->cor.state != Halted ); 337 338 verify( disable_preempt_count > 0 ); 333 if( !thrd ) return; 339 334 340 335 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 341 342 lock( &systemProcessor->proc.cltr->lock DEBUG_CTX2);336 337 lock( &systemProcessor->proc.cltr->lock ); 343 338 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 344 339 unlock( &systemProcessor->proc.cltr->lock ); 345 346 verify( disable_preempt_count > 0 );347 340 } 348 341 349 342 thread_desc * nextThread(cluster * this) { 350 verify( disable_preempt_count > 0 ); 351 lock( &this->lock DEBUG_CTX2 ); 343 lock( &this->lock ); 352 344 thread_desc * head = pop_head( &this->ready_queue ); 353 345 unlock( &this->lock ); 354 verify( disable_preempt_count > 0 );355 346 return head; 356 347 } 357 348 358 void BlockInternal() { 359 disable_interrupts(); 360 verify( disable_preempt_count > 0 ); 349 void ScheduleInternal() { 361 350 suspend(); 362 verify( disable_preempt_count > 0 ); 363 enable_interrupts( DEBUG_CTX ); 364 } 365 366 void BlockInternal( spinlock * lock ) { 367 disable_interrupts(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 368 354 this_processor->finish.action_code = Release; 369 355 this_processor->finish.lock = lock; 370 371 verify( disable_preempt_count > 0 );372 356 suspend(); 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 ); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 381 360 this_processor->finish.action_code = Schedule; 382 361 this_processor->finish.thrd = thrd; 383 384 verify( disable_preempt_count > 0 );385 362 suspend(); 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(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 393 366 this_processor->finish.action_code = Release_Schedule; 394 367 this_processor->finish.lock = lock; 395 368 this_processor->finish.thrd = thrd; 396 397 verify( disable_preempt_count > 0 );398 369 suspend(); 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(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 406 373 this_processor->finish.action_code = Release_Multi; 407 374 this_processor->finish.locks = locks; 408 375 this_processor->finish.lock_count = count; 409 410 verify( disable_preempt_count > 0 );411 376 suspend(); 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(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 419 380 this_processor->finish.action_code = Release_Multi_Schedule; 420 381 this_processor->finish.locks = locks; … … 422 383 this_processor->finish.thrds = thrds; 423 384 this_processor->finish.thrd_count = thrd_count; 424 425 verify( disable_preempt_count > 0 );426 385 suspend(); 427 verify( disable_preempt_count > 0 );428 429 enable_interrupts( DEBUG_CTX );430 386 } 431 387 … … 436 392 // Kernel boot procedures 437 393 void kernel_startup(void) { 438 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 439 395 440 396 // Start by initializing the main thread 441 // SKULLDUGGERY: the mainThread steals the process main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 442 398 // which will then be scheduled by the systemProcessor normally 443 399 mainThread = (thread_desc *)&mainThread_storage; … … 447 403 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 448 404 405 // Enable preemption 406 kernel_start_preemption(); 407 449 408 // Initialize the system cluster 450 409 systemCluster = (cluster *)&systemCluster_storage; … … 458 417 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage }; 459 418 460 // Add the main thread to the ready queue 419 // Add the main thread to the ready queue 461 420 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 462 421 ScheduleThread(mainThread); … … 464 423 //initialize the global state variables 465 424 this_processor = &systemProcessor->proc; 466 this_thread = mainThread; 467 this_coroutine = &mainThread->cor; 468 disable_preempt_count = 1; 469 470 // Enable preemption 471 kernel_start_preemption(); 425 this_processor->current_thread = mainThread; 426 this_processor->current_coroutine = &mainThread->cor; 472 427 473 428 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 474 429 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 475 // mainThread is on the ready queue when this call is made. 430 // mainThread is on the ready queue when this call is made. 476 431 resume( systemProcessor->proc.runner ); 477 432 … … 480 435 // THE SYSTEM IS NOW COMPLETELY RUNNING 481 436 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 482 483 enable_interrupts( DEBUG_CTX );484 437 } 485 438 486 439 void kernel_shutdown(void) { 487 440 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 488 489 disable_interrupts();490 441 491 442 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 497 448 // THE SYSTEM IS NOW COMPLETELY STOPPED 498 449 499 // Disable preemption500 kernel_stop_preemption();501 502 450 // Destroy the system processor and its context in reverse order of construction 503 451 // These were manually constructed so we need manually destroy them … … 509 457 ^(mainThread){}; 510 458 511 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 512 460 } 513 461 … … 519 467 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 520 468 // the globalAbort flag is true. 521 lock( &kernel_abort_lock DEBUG_CTX2);469 lock( &kernel_abort_lock ); 522 470 523 471 // first task to abort ? … … 525 473 kernel_abort_called = true; 526 474 unlock( &kernel_abort_lock ); 527 } 475 } 528 476 else { 529 477 unlock( &kernel_abort_lock ); 530 478 531 479 sigset_t mask; 532 480 sigemptyset( &mask ); … … 534 482 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 535 483 sigsuspend( &mask ); // block the processor to prevent further damage during abort 536 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 537 } 538 539 return this_thread ;484 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 485 } 486 487 return this_thread(); 540 488 } 541 489 … … 546 494 __lib_debug_write( STDERR_FILENO, abort_text, len ); 547 495 548 if ( thrd != this_coroutine ) {549 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() ); 550 498 __lib_debug_write( STDERR_FILENO, abort_text, len ); 551 } 499 } 552 500 else { 553 501 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 557 505 extern "C" { 558 506 void __lib_debug_acquire() { 559 lock( &kernel_debug_lock DEBUG_CTX2);507 lock(&kernel_debug_lock); 560 508 } 561 509 562 510 void __lib_debug_release() { 563 unlock( &kernel_debug_lock);511 unlock(&kernel_debug_lock); 564 512 } 565 513 } … … 577 525 } 578 526 579 bool try_lock( spinlock * this DEBUG_CTX_PARAM2) {527 bool try_lock( spinlock * this ) { 580 528 return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 581 529 } 582 530 583 void lock( spinlock * this DEBUG_CTX_PARAM2) {531 void lock( spinlock * this ) { 584 532 for ( unsigned int i = 1;; i += 1 ) { 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 533 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break; 534 } 535 } 604 536 605 537 void unlock( spinlock * this ) { … … 615 547 616 548 void wait( signal_once * this ) { 617 lock( &this->lock DEBUG_CTX2);549 lock( &this->lock ); 618 550 if( !this->cond ) { 619 append( &this->blocked, (thread_desc*)this_thread ); 620 BlockInternal( &this->lock ); 621 } 622 else { 623 unlock( &this->lock ); 624 } 551 append( &this->blocked, this_thread() ); 552 ScheduleInternal( &this->lock ); 553 lock( &this->lock ); 554 } 555 unlock( &this->lock ); 625 556 } 626 557 627 558 void signal( signal_once * this ) { 628 lock( &this->lock DEBUG_CTX2);559 lock( &this->lock ); 629 560 { 630 561 this->cond = true; 631 562 632 disable_interrupts();633 563 thread_desc * it; 634 564 while( it = pop_head( &this->blocked) ) { 635 565 ScheduleThread( it ); 636 566 } 637 enable_interrupts( DEBUG_CTX );638 567 } 639 568 unlock( &this->lock ); … … 661 590 } 662 591 head->next = NULL; 663 } 592 } 664 593 return head; 665 594 } … … 680 609 this->top = top->next; 681 610 top->next = NULL; 682 } 611 } 683 612 return top; 684 613 }
Note:
See TracChangeset
for help on using the changeset viewer.