Changes in src/libcfa/concurrency/kernel.c [d6ff3ff:4aa2fb2]
- File:
-
- 1 edited
-
src/libcfa/concurrency/kernel.c (modified) (40 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/kernel.c
rd6ff3ff 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 … … 36 42 #include "invoke.h" 37 43 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 42 44 //----------------------------------------------------------------------------- 43 45 // Kernel storage 44 #define KERNEL_STORAGE(T,X) static char X## Storage[sizeof(T)]46 #define KERNEL_STORAGE(T,X) static char X##_storage[sizeof(T)] 45 47 46 48 KERNEL_STORAGE(processorCtx_t, systemProcessorCtx); … … 48 50 KERNEL_STORAGE(system_proc_t, systemProcessor); 49 51 KERNEL_STORAGE(thread_desc, mainThread); 50 KERNEL_STORAGE(machine_context_t, mainThread Ctx);52 KERNEL_STORAGE(machine_context_t, mainThread_context); 51 53 52 54 cluster * systemCluster; … … 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 bool preemption_in_progress = 0; 63 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 } 64 70 65 71 //----------------------------------------------------------------------------- 66 72 // Main thread construction 67 73 struct current_stack_info_t { 68 machine_context_t ctx; 74 machine_context_t ctx; 69 75 unsigned int size; // size of stack 70 76 void *base; // base of stack … … 76 82 77 83 void ?{}( current_stack_info_t * this ) { 78 CtxGet( this->ctx );84 CtxGet( &this->ctx ); 79 85 this->base = this->ctx.FP; 80 86 this->storage = this->ctx.SP; … … 85 91 86 92 this->limit = (void *)(((intptr_t)this->base) - this->size); 87 this->context = &mainThread CtxStorage;93 this->context = &mainThread_context_storage; 88 94 this->top = this->base; 89 95 } … … 100 106 101 107 void ?{}( coroutine_desc * this, current_stack_info_t * info) { 102 (&this->stack){ info }; 108 (&this->stack){ info }; 103 109 this->name = "Main Thread"; 104 110 this->errno_ = 0; … … 130 136 void ?{}(processor * this, cluster * cltr) { 131 137 this->cltr = cltr; 132 (&this->terminated){ 0 }; 138 this->current_coroutine = NULL; 139 this->current_thread = NULL; 140 (&this->terminated){}; 133 141 this->is_terminated = false; 134 142 this->preemption_alarm = NULL; 135 143 this->preemption = default_preemption(); 144 this->disable_preempt_count = 1; //Start with interrupts disabled 136 145 this->pending_preemption = false; 137 146 … … 141 150 void ?{}(processor * this, cluster * cltr, processorCtx_t * runner) { 142 151 this->cltr = cltr; 143 (&this->terminated){ 0 }; 152 this->current_coroutine = NULL; 153 this->current_thread = NULL; 154 (&this->terminated){}; 144 155 this->is_terminated = false; 145 this->preemption_alarm = NULL; 146 this->preemption = default_preemption(); 156 this->disable_preempt_count = 0; 147 157 this->pending_preemption = false; 148 this->kernel_thread = pthread_self();149 158 150 159 this->runner = runner; 151 LIB_DEBUG_PRINT_SAFE("Kernel : constructing systemprocessor context %p\n", runner);160 LIB_DEBUG_PRINT_SAFE("Kernel : constructing processor context %p\n", runner); 152 161 runner{ this }; 153 162 } 154 155 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )156 163 157 164 void ?{}(system_proc_t * this, cluster * cltr, processorCtx_t * runner) { … … 161 168 162 169 (&this->proc){ cltr, runner }; 163 164 verify( validate( &this->alarms ) );165 170 } 166 171 … … 169 174 LIB_DEBUG_PRINT_SAFE("Kernel : core %p signaling termination\n", this); 170 175 this->is_terminated = true; 171 P( &this->terminated ); 172 pthread_join( this->kernel_thread, NULL ); 176 wait( &this->terminated ); 173 177 } 174 178 } … … 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 … … 225 225 } 226 226 227 V( &this->terminated ); 228 227 signal( &this->terminated ); 229 228 LIB_DEBUG_PRINT_SAFE("Kernel : core %p terminated\n", this); 230 229 } 231 230 232 // runThread runs a thread by context switching 233 // 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 234 233 void runThread(processor * this, thread_desc * dst) { 235 234 coroutine_desc * proc_cor = get_coroutine(this->runner); 236 235 coroutine_desc * thrd_cor = get_coroutine(dst); 237 236 238 237 //Reset the terminating actions here 239 238 this->finish.action_code = No_Action; 240 239 241 240 //Update global state 242 this _thread = dst;241 this->current_thread = dst; 243 242 244 243 // Context Switch to the thread … … 247 246 } 248 247 249 // Once a thread has finished running, some of 248 // Once a thread has finished running, some of 250 249 // its final actions must be executed from the kernel 251 250 void finishRunning(processor * this) { … … 257 256 } 258 257 else if( this->finish.action_code == Release_Schedule ) { 259 unlock( this->finish.lock ); 258 unlock( this->finish.lock ); 260 259 ScheduleThread( this->finish.thrd ); 261 260 } … … 290 289 processor * proc = (processor *) arg; 291 290 this_processor = proc; 292 this_coroutine = NULL;293 this_thread = NULL;294 disable_preempt_count = 1;295 291 // SKULLDUGGERY: We want to create a context for the processor coroutine 296 292 // which is needed for the 2-step context switch. However, there is no reason 297 // to waste the perfectly valid stack create by pthread. 293 // to waste the perfectly valid stack create by pthread. 298 294 current_stack_info_t info; 299 295 machine_context_t ctx; … … 304 300 305 301 //Set global state 306 this_coroutine = &proc->runner->__cor;307 this_thread = NULL;302 proc->current_coroutine = &proc->runner->__cor; 303 proc->current_thread = NULL; 308 304 309 305 //We now have a proper context from which to schedule threads 310 306 LIB_DEBUG_PRINT_SAFE("Kernel : core %p created (%p, %p)\n", proc, proc->runner, &ctx); 311 307 312 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't 313 // resume it to start it like it normally would, it will just context switch 314 // 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 315 311 // appropriate stack. 316 312 proc_cor_storage.__cor.state = Active; … … 319 315 320 316 // Main routine of the core returned, the core is now fully terminated 321 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); 322 318 323 319 return NULL; … … 326 322 void start(processor * this) { 327 323 LIB_DEBUG_PRINT_SAFE("Kernel : Starting core %p\n", this); 328 324 329 325 pthread_create( &this->kernel_thread, NULL, CtxInvokeProcessor, (void*)this ); 330 326 331 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 327 LIB_DEBUG_PRINT_SAFE("Kernel : core %p started\n", this); 332 328 } 333 329 … … 335 331 // Scheduler routines 336 332 void ScheduleThread( thread_desc * thrd ) { 337 // if( !thrd ) return; 338 assert( thrd ); 339 assert( thrd->cor.state != Halted ); 340 341 verify( disable_preempt_count > 0 ); 333 if( !thrd ) return; 342 334 343 335 verifyf( thrd->next == NULL, "Expected null got %p", thrd->next ); 344 345 lock( &systemProcessor->proc.cltr->lock DEBUG_CTX2);336 337 lock( &systemProcessor->proc.cltr->lock ); 346 338 append( &systemProcessor->proc.cltr->ready_queue, thrd ); 347 339 unlock( &systemProcessor->proc.cltr->lock ); 348 349 verify( disable_preempt_count > 0 );350 340 } 351 341 352 342 thread_desc * nextThread(cluster * this) { 353 verify( disable_preempt_count > 0 ); 354 lock( &this->lock DEBUG_CTX2 ); 343 lock( &this->lock ); 355 344 thread_desc * head = pop_head( &this->ready_queue ); 356 345 unlock( &this->lock ); 357 verify( disable_preempt_count > 0 );358 346 return head; 359 347 } 360 348 361 void BlockInternal() { 362 disable_interrupts(); 363 verify( disable_preempt_count > 0 ); 349 void ScheduleInternal() { 364 350 suspend(); 365 verify( disable_preempt_count > 0 ); 366 enable_interrupts( DEBUG_CTX ); 367 } 368 369 void BlockInternal( spinlock * lock ) { 370 disable_interrupts(); 351 } 352 353 void ScheduleInternal( spinlock * lock ) { 371 354 this_processor->finish.action_code = Release; 372 355 this_processor->finish.lock = lock; 373 374 verify( disable_preempt_count > 0 );375 356 suspend(); 376 verify( disable_preempt_count > 0 ); 377 378 enable_interrupts( DEBUG_CTX ); 379 } 380 381 void BlockInternal( thread_desc * thrd ) { 382 disable_interrupts(); 383 assert( thrd->cor.state != Halted ); 357 } 358 359 void ScheduleInternal( thread_desc * thrd ) { 384 360 this_processor->finish.action_code = Schedule; 385 361 this_processor->finish.thrd = thrd; 386 387 verify( disable_preempt_count > 0 );388 362 suspend(); 389 verify( disable_preempt_count > 0 ); 390 391 enable_interrupts( DEBUG_CTX ); 392 } 393 394 void BlockInternal( spinlock * lock, thread_desc * thrd ) { 395 disable_interrupts(); 363 } 364 365 void ScheduleInternal( spinlock * lock, thread_desc * thrd ) { 396 366 this_processor->finish.action_code = Release_Schedule; 397 367 this_processor->finish.lock = lock; 398 368 this_processor->finish.thrd = thrd; 399 400 verify( disable_preempt_count > 0 );401 369 suspend(); 402 verify( disable_preempt_count > 0 ); 403 404 enable_interrupts( DEBUG_CTX ); 405 } 406 407 void BlockInternal(spinlock ** locks, unsigned short count) { 408 disable_interrupts(); 370 } 371 372 void ScheduleInternal(spinlock ** locks, unsigned short count) { 409 373 this_processor->finish.action_code = Release_Multi; 410 374 this_processor->finish.locks = locks; 411 375 this_processor->finish.lock_count = count; 412 413 verify( disable_preempt_count > 0 );414 376 suspend(); 415 verify( disable_preempt_count > 0 ); 416 417 enable_interrupts( DEBUG_CTX ); 418 } 419 420 void BlockInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 421 disable_interrupts(); 377 } 378 379 void ScheduleInternal(spinlock ** locks, unsigned short lock_count, thread_desc ** thrds, unsigned short thrd_count) { 422 380 this_processor->finish.action_code = Release_Multi_Schedule; 423 381 this_processor->finish.locks = locks; … … 425 383 this_processor->finish.thrds = thrds; 426 384 this_processor->finish.thrd_count = thrd_count; 427 428 verify( disable_preempt_count > 0 );429 suspend();430 verify( disable_preempt_count > 0 );431 432 enable_interrupts( DEBUG_CTX );433 }434 435 void LeaveThread(spinlock * lock, thread_desc * thrd) {436 verify( disable_preempt_count > 0 );437 this_processor->finish.action_code = thrd ? Release_Schedule : Release;438 this_processor->finish.lock = lock;439 this_processor->finish.thrd = thrd;440 441 385 suspend(); 442 386 } … … 448 392 // Kernel boot procedures 449 393 void kernel_startup(void) { 450 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 394 LIB_DEBUG_PRINT_SAFE("Kernel : Starting\n"); 451 395 452 396 // Start by initializing the main thread 453 // SKULLDUGGERY: the mainThread steals the process main thread 397 // SKULLDUGGERY: the mainThread steals the process main thread 454 398 // which will then be scheduled by the systemProcessor normally 455 mainThread = (thread_desc *)&mainThread Storage;399 mainThread = (thread_desc *)&mainThread_storage; 456 400 current_stack_info_t info; 457 401 mainThread{ &info }; … … 459 403 LIB_DEBUG_PRINT_SAFE("Kernel : Main thread ready\n"); 460 404 405 // Enable preemption 406 kernel_start_preemption(); 407 461 408 // Initialize the system cluster 462 systemCluster = (cluster *)&systemCluster Storage;409 systemCluster = (cluster *)&systemCluster_storage; 463 410 systemCluster{}; 464 411 … … 467 414 // Initialize the system processor and the system processor ctx 468 415 // (the coroutine that contains the processing control flow) 469 systemProcessor = (system_proc_t *)&systemProcessor Storage;470 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx Storage };471 472 // Add the main thread to the ready queue 416 systemProcessor = (system_proc_t *)&systemProcessor_storage; 417 systemProcessor{ systemCluster, (processorCtx_t *)&systemProcessorCtx_storage }; 418 419 // Add the main thread to the ready queue 473 420 // once resume is called on systemProcessor->runner the mainThread needs to be scheduled like any normal thread 474 421 ScheduleThread(mainThread); … … 476 423 //initialize the global state variables 477 424 this_processor = &systemProcessor->proc; 478 this_thread = mainThread; 479 this_coroutine = &mainThread->cor; 480 disable_preempt_count = 1; 481 482 // Enable preemption 483 kernel_start_preemption(); 425 this_processor->current_thread = mainThread; 426 this_processor->current_coroutine = &mainThread->cor; 484 427 485 428 // SKULLDUGGERY: Force a context switch to the system processor to set the main thread's context to the current UNIX 486 429 // context. Hence, the main thread does not begin through CtxInvokeThread, like all other threads. The trick here is that 487 // mainThread is on the ready queue when this call is made. 430 // mainThread is on the ready queue when this call is made. 488 431 resume( systemProcessor->proc.runner ); 489 432 … … 492 435 // THE SYSTEM IS NOW COMPLETELY RUNNING 493 436 LIB_DEBUG_PRINT_SAFE("Kernel : Started\n--------------------------------------------------\n\n"); 494 495 enable_interrupts( DEBUG_CTX );496 437 } 497 438 498 439 void kernel_shutdown(void) { 499 440 LIB_DEBUG_PRINT_SAFE("\n--------------------------------------------------\nKernel : Shutting down\n"); 500 501 disable_interrupts();502 441 503 442 // SKULLDUGGERY: Notify the systemProcessor it needs to terminates. … … 509 448 // THE SYSTEM IS NOW COMPLETELY STOPPED 510 449 511 // Disable preemption512 kernel_stop_preemption();513 514 450 // Destroy the system processor and its context in reverse order of construction 515 451 // These were manually constructed so we need manually destroy them … … 521 457 ^(mainThread){}; 522 458 523 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 459 LIB_DEBUG_PRINT_SAFE("Kernel : Shutdown complete\n"); 524 460 } 525 461 … … 531 467 // abort cannot be recursively entered by the same or different processors because all signal handlers return when 532 468 // the globalAbort flag is true. 533 lock( &kernel_abort_lock DEBUG_CTX2);469 lock( &kernel_abort_lock ); 534 470 535 471 // first task to abort ? … … 537 473 kernel_abort_called = true; 538 474 unlock( &kernel_abort_lock ); 539 } 475 } 540 476 else { 541 477 unlock( &kernel_abort_lock ); 542 478 543 479 sigset_t mask; 544 480 sigemptyset( &mask ); … … 546 482 sigaddset( &mask, SIGUSR1 ); // block SIGUSR1 signals 547 483 sigsuspend( &mask ); // block the processor to prevent further damage during abort 548 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 549 } 550 551 return this_thread ;484 _exit( EXIT_FAILURE ); // if processor unblocks before it is killed, terminate it 485 } 486 487 return this_thread(); 552 488 } 553 489 … … 558 494 __lib_debug_write( STDERR_FILENO, abort_text, len ); 559 495 560 if ( thrd != this_coroutine ) {561 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() ); 562 498 __lib_debug_write( STDERR_FILENO, abort_text, len ); 563 } 499 } 564 500 else { 565 501 __lib_debug_write( STDERR_FILENO, ".\n", 2 ); … … 569 505 extern "C" { 570 506 void __lib_debug_acquire() { 571 lock( &kernel_debug_lock DEBUG_CTX2);507 lock(&kernel_debug_lock); 572 508 } 573 509 574 510 void __lib_debug_release() { 575 unlock( &kernel_debug_lock);511 unlock(&kernel_debug_lock); 576 512 } 577 513 } … … 589 525 } 590 526 591 bool try_lock( spinlock * this DEBUG_CTX_PARAM2) {527 bool try_lock( spinlock * this ) { 592 528 return this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0; 593 529 } 594 530 595 void lock( spinlock * this DEBUG_CTX_PARAM2) {531 void lock( spinlock * this ) { 596 532 for ( unsigned int i = 1;; i += 1 ) { 597 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 598 } 599 LIB_DEBUG_DO( 600 this->prev_name = caller; 601 this->prev_thrd = this_thread; 602 ) 603 } 604 605 void lock_yield( spinlock * this DEBUG_CTX_PARAM2 ) { 606 for ( unsigned int i = 1;; i += 1 ) { 607 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) { break; } 608 yield(); 609 } 610 LIB_DEBUG_DO( 611 this->prev_name = caller; 612 this->prev_thrd = this_thread; 613 ) 614 } 615 533 if ( this->lock == 0 && __sync_lock_test_and_set_4( &this->lock, 1 ) == 0 ) break; 534 } 535 } 616 536 617 537 void unlock( spinlock * this ) { … … 619 539 } 620 540 621 void ?{}( semaphore * this, int count = 1 ) { 622 (&this->lock){}; 623 this->count = count; 624 (&this->waiting){}; 625 } 626 void ^?{}(semaphore * this) {} 627 628 void P(semaphore * this) { 629 lock( &this->lock DEBUG_CTX2 ); 630 this->count -= 1; 631 if ( this->count < 0 ) { 632 // queue current task 633 append( &this->waiting, (thread_desc *)this_thread ); 634 635 // atomically release spin lock and block 636 BlockInternal( &this->lock ); 637 } 638 else { 639 unlock( &this->lock ); 640 } 641 } 642 643 void V(semaphore * this) { 644 thread_desc * thrd = NULL; 645 lock( &this->lock DEBUG_CTX2 ); 646 this->count += 1; 647 if ( this->count <= 0 ) { 648 // remove task at head of waiting list 649 thrd = pop_head( &this->waiting ); 650 } 651 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 } 652 555 unlock( &this->lock ); 653 654 // make new owner 655 WakeThread( thrd ); 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 ); 656 569 } 657 570 … … 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.