Changes in src/libcfa/concurrency/kernel.c [4aa2fb2:bdeba0b]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
r4aa2fb2 rbdeba0b 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 (&this->terminated){}; 131 (&this->terminated){ 0 }; 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 (&this->terminated){}; 142 (&this->terminated){ 0 }; 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 … … 174 168 LIB_DEBUG_PRINT_SAFE("Kernel : core %p signaling termination\n", this); 175 169 this->is_terminated = true; 176 wait( &this->terminated ); 170 P( &this->terminated ); 171 pthread_join( this->kernel_thread, NULL ); 177 172 } 178 173 } … … 184 179 185 180 void ^?{}(cluster * this) { 186 181 187 182 } 188 183 … … 203 198 204 199 thread_desc * readyThread = NULL; 205 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 200 for( unsigned int spin_count = 0; ! this->is_terminated; spin_count++ ) 206 201 { 207 202 readyThread = nextThread( this->cltr ); … … 209 204 if(readyThread) 210 205 { 206 verify( disable_preempt_count > 0 ); 207 211 208 runThread(this, readyThread); 209 210 verify( disable_preempt_count > 0 ); 212 211 213 212 //Some actions need to be taken from the kernel … … 225 224 } 226 225 227 signal( &this->terminated ); 226 V( &this->terminated ); 227 228 228 LIB_DEBUG_PRINT_SAFE("Kernel : core %p terminated\n", this); 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 325 328 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 326 329 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 330 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 328 331 } 329 332 … … 331 334 // Scheduler routines 332 335 void ScheduleThread( thread_desc * thrd ) { 333 if( !thrd ) return; 336 // if( !thrd ) return; 337 assert( thrd ); 338 assert( thrd->cor.state != Halted ); 339 340 verify( disable_preempt_count > 0 ); 334 341 335 342 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 336 337 lock( &systemProcessor->proc.cltr->lock );343 344 lock( &systemProcessor->proc.cltr->lock DEBUG_CTX2 ); 338 345 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 339 346 unlock( &systemProcessor->proc.cltr->lock ); 347 348 verify( disable_preempt_count > 0 ); 340 349 } 341 350 342 351 thread_desc * nextThread(cluster * this) { 343 lock( &this->lock ); 352 verify( disable_preempt_count > 0 ); 353 lock( &this->lock DEBUG_CTX2 ); 344 354 thread_desc * head = pop_head( &this->ready_queue ); 345 355 unlock( &this->lock ); 356 verify( disable_preempt_count > 0 ); 346 357 return head; 347 358 } 348 359 349 void ScheduleInternal() { 360 void BlockInternal() { 361 disable_interrupts(); 362 verify( disable_preempt_count > 0 ); 350 363 suspend(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 364 verify( disable_preempt_count > 0 ); 365 enable_interrupts( DEBUG_CTX ); 366 } 367 368 void BlockInternal( spinlock * lock ) { 369 disable_interrupts(); 354 370 this_processor->finish.action_code = Release; 355 371 this_processor->finish.lock = lock; 372 373 verify( disable_preempt_count > 0 ); 356 374 suspend(); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 375 verify( disable_preempt_count > 0 ); 376 377 enable_interrupts( DEBUG_CTX ); 378 } 379 380 void BlockInternal( thread_desc * thrd ) { 381 disable_interrupts(); 382 assert( thrd->cor.state != Halted ); 360 383 this_processor->finish.action_code = Schedule; 361 384 this_processor->finish.thrd = thrd; 385 386 verify( disable_preempt_count > 0 ); 362 387 suspend(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 388 verify( disable_preempt_count > 0 ); 389 390 enable_interrupts( DEBUG_CTX ); 391 } 392 393 void BlockInternal( spinlock * lock, thread_desc * thrd ) { 394 disable_interrupts(); 366 395 this_processor->finish.action_code = Release_Schedule; 367 396 this_processor->finish.lock = lock; 368 397 this_processor->finish.thrd = thrd; 398 399 verify( disable_preempt_count > 0 ); 369 400 suspend(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 401 verify( disable_preempt_count > 0 ); 402 403 enable_interrupts( DEBUG_CTX ); 404 } 405 406 void BlockInternal(spinlock ** locks, unsigned short count) { 407 disable_interrupts(); 373 408 this_processor->finish.action_code = Release_Multi; 374 409 this_processor->finish.locks = locks; 375 410 this_processor->finish.lock_count = count; 411 412 verify( disable_preempt_count > 0 ); 376 413 suspend(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 414 verify( disable_preempt_count > 0 ); 415 416 enable_interrupts( DEBUG_CTX ); 417 } 418 419 void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 420 disable_interrupts(); 380 421 this_processor->finish.action_code = Release_Multi_Schedule; 381 422 this_processor->finish.locks = locks; … … 383 424 this_processor->finish.thrds = thrds; 384 425 this_processor->finish.thrd_count = thrd_count; 426 427 verify( disable_preempt_count > 0 ); 385 428 suspend(); 429 verify( disable_preempt_count > 0 ); 430 431 enable_interrupts( DEBUG_CTX ); 386 432 } 387 433 … … 392 438 // Kernel boot procedures 393 439 void kernel_startup(void) { 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 440 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 395 441 396 442 // Start by initializing the main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 443 // SKULLDUGGERY: the mainThread steals the process main thread 398 444 // which will then be scheduled by the systemProcessor normally 399 445 mainThread = (thread_desc *)&mainThread_storage; … … 403 449 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 404 450 405 // Enable preemption406 kernel_start_preemption();407 408 451 // Initialize the system cluster 409 452 systemCluster = (cluster *)&systemCluster_storage; … … 417 460 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage }; 418 461 419 // Add the main thread to the ready queue 462 // Add the main thread to the ready queue 420 463 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 421 464 ScheduleThread(mainThread); … … 423 466 //initialize the global state variables 424 467 this_processor = &systemProcessor->proc; 425 this_processor->current_thread = mainThread; 426 this_processor->current_coroutine = &mainThread->cor; 468 this_thread = mainThread; 469 this_coroutine = &mainThread->cor; 470 disable_preempt_count = 1; 471 472 // Enable preemption 473 kernel_start_preemption(); 427 474 428 475 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 429 476 // 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. 477 // mainThread is on the ready queue when this call is made. 431 478 resume( systemProcessor->proc.runner ); 432 479 … … 435 482 // THE SYSTEM IS NOW COMPLETELY RUNNING 436 483 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 484 485 enable_interrupts( DEBUG_CTX ); 437 486 } 438 487 439 488 void kernel_shutdown(void) { 440 489 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 490 491 disable_interrupts(); 441 492 442 493 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 448 499 // THE SYSTEM IS NOW COMPLETELY STOPPED 449 500 501 // Disable preemption 502 kernel_stop_preemption(); 503 450 504 // Destroy the system processor and its context in reverse order of construction 451 505 // These were manually constructed so we need manually destroy them … … 457 511 ^(mainThread){}; 458 512 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 513 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 460 514 } 461 515 … … 467 521 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 468 522 // the globalAbort flag is true. 469 lock( &kernel_abort_lock );523 lock( &kernel_abort_lock DEBUG_CTX2 ); 470 524 471 525 // first task to abort ? … … 473 527 kernel_abort_called = true; 474 528 unlock( &kernel_abort_lock ); 475 } 529 } 476 530 else { 477 531 unlock( &kernel_abort_lock ); 478 532 479 533 sigset_t mask; 480 534 sigemptyset( &mask ); … … 482 536 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 483 537 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 ();538 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 539 } 540 541 return this_thread; 488 542 } 489 543 … … 494 548 __lib_debug_write( STDERR_FILENO, abort_text, len ); 495 549 496 if ( thrd != this_coroutine ()) {497 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine ()->name, this_coroutine());550 if ( thrd != this_coroutine ) { 551 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", this_coroutine->name, this_coroutine ); 498 552 __lib_debug_write( STDERR_FILENO, abort_text, len ); 499 } 553 } 500 554 else { 501 555 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 505 559 extern "C" { 506 560 void __lib_debug_acquire() { 507 lock( &kernel_debug_lock);561 lock( &kernel_debug_lock DEBUG_CTX2 ); 508 562 } 509 563 510 564 void __lib_debug_release() { 511 unlock( &kernel_debug_lock);565 unlock( &kernel_debug_lock ); 512 566 } 513 567 } … … 525 579 } 526 580 527 bool try_lock( spinlock * this ) {581 bool try_lock( spinlock * this DEBUG_CTX_PARAM2 ) { 528 582 return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 529 583 } 530 584 531 void lock( spinlock * this ) {585 void lock( spinlock * this DEBUG_CTX_PARAM2 ) { 532 586 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 } 587 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 588 } 589 LIB_DEBUG_DO( 590 this->prev_name = caller; 591 this->prev_thrd = this_thread; 592 ) 593 } 594 595 void lock_yield( spinlock * this DEBUG_CTX_PARAM2 ) { 596 for ( unsigned int i = 1;; i += 1 ) { 597 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 598 yield(); 599 } 600 LIB_DEBUG_DO( 601 this->prev_name = caller; 602 this->prev_thrd = this_thread; 603 ) 604 } 605 536 606 537 607 void unlock( spinlock * this ) { … … 539 609 } 540 610 541 void ?{}( signal_once * this ) { 542 this->cond = false; 543 } 544 void ^?{}( signal_once * this ) { 545 546 } 547 548 void wait( signal_once * this ) { 549 lock( &this->lock ); 550 if( !this->cond ) { 551 append( &this->blocked, this_thread() ); 552 ScheduleInternal( &this->lock ); 553 lock( &this->lock ); 554 } 611 void ?{}( semaphore * this, int count = 1 ) { 612 (&this->lock){}; 613 this->count = count; 614 (&this->waiting){}; 615 } 616 void ^?{}(semaphore * this) {} 617 618 void P(semaphore * this) { 619 lock( &this->lock DEBUG_CTX2 ); 620 this->count -= 1; 621 if ( this->count < 0 ) { 622 // queue current task 623 append( &this->waiting, (thread_desc *)this_thread ); 624 625 // atomically release spin lock and block 626 BlockInternal( &this->lock ); 627 } 628 else { 629 unlock( &this->lock ); 630 } 631 } 632 633 void V(semaphore * this) { 634 thread_desc * thrd = NULL; 635 lock( &this->lock DEBUG_CTX2 ); 636 this->count += 1; 637 if ( this->count <= 0 ) { 638 // remove task at head of waiting list 639 thrd = pop_head( &this->waiting ); 640 } 641 555 642 unlock( &this->lock ); 556 } 557 558 void signal( signal_once * this ) { 559 lock( &this->lock ); 560 { 561 this->cond = true; 562 563 thread_desc * it; 564 while( it = pop_head( &this->blocked) ) { 565 ScheduleThread( it ); 566 } 567 } 568 unlock( &this->lock ); 643 644 // make new owner 645 WakeThread( thrd ); 569 646 } 570 647 … … 590 667 } 591 668 head->next = NULL; 592 } 669 } 593 670 return head; 594 671 } … … 609 686 this->top = top->next; 610 687 top->next = NULL; 611 } 688 } 612 689 return top; 613 690 }
Note: See TracChangeset
for help on using the changeset viewer.