- File:
-
- 1 edited
-
libcfa/src/concurrency/kernel.cfa (modified) (32 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/kernel.cfa
r1f45c7d rc33c2af 22 22 #include <errno.h> 23 23 #include <stdio.h> 24 #include <string.h> 24 25 #include <signal.h> 25 26 #include <unistd.h> … … 31 32 #include "kernel_private.hfa" 32 33 #include "preemption.hfa" 34 #include "strstream.hfa" 35 #include "device/cpu.hfa" 33 36 34 37 //Private includes … … 110 113 #endif 111 114 112 extern $thread* mainThread;115 extern thread$ * mainThread; 113 116 extern processor * mainProcessor; 114 117 115 118 //----------------------------------------------------------------------------- 116 119 // Kernel Scheduling logic 117 static $thread* __next_thread(cluster * this);118 static $thread* __next_thread_slow(cluster * this);119 static inline bool __must_unpark( $thread* thrd ) __attribute((nonnull(1)));120 static void __run_thread(processor * this, $thread* dst);120 static thread$ * __next_thread(cluster * this); 121 static thread$ * __next_thread_slow(cluster * this); 122 static inline bool __must_unpark( thread$ * thrd ) __attribute((nonnull(1))); 123 static void __run_thread(processor * this, thread$ * dst); 121 124 static void __wake_one(cluster * cltr); 122 125 … … 181 184 __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this); 182 185 183 $thread* readyThread = 0p;186 thread$ * readyThread = 0p; 184 187 MAIN_LOOP: 185 188 for() { … … 193 196 194 197 if( !readyThread ) { 198 ready_schedule_lock(); 195 199 __cfa_io_flush( this ); 200 ready_schedule_unlock(); 201 196 202 readyThread = __next_thread_slow( this->cltr ); 197 203 } … … 231 237 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 232 238 233 __disable_interrupts_hard(); 234 eventfd_t val; 235 eventfd_read( this->idle, &val ); 236 __enable_interrupts_hard(); 239 { 240 eventfd_t val; 241 ssize_t ret = read( this->idle, &val, sizeof(val) ); 242 if(ret < 0) { 243 switch((int)errno) { 244 case EAGAIN: 245 #if EAGAIN != EWOULDBLOCK 246 case EWOULDBLOCK: 247 #endif 248 case EINTR: 249 // No need to do anything special here, just assume it's a legitimate wake-up 250 break; 251 default: 252 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 253 } 254 } 255 } 237 256 238 257 #if !defined(__CFA_NO_STATISTICS__) … … 261 280 262 281 if(this->io.pending && !this->io.dirty) { 282 ready_schedule_lock(); 263 283 __cfa_io_flush( this ); 284 ready_schedule_unlock(); 264 285 } 265 286 … … 301 322 302 323 // Don't block if we are done 303 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 324 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) { 325 ready_schedule_unlock(); 326 break MAIN_LOOP; 327 } 304 328 305 329 __STATS( __tls_stats()->ready.sleep.halts++; ) … … 325 349 } 326 350 327 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )351 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); ) 328 352 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 329 353 330 // __disable_interrupts_hard(); 331 eventfd_t val; 332 eventfd_read( this->idle, &val ); 333 // __enable_interrupts_hard(); 354 { 355 eventfd_t val; 356 ssize_t ret = read( this->idle, &val, sizeof(val) ); 357 if(ret < 0) { 358 switch((int)errno) { 359 case EAGAIN: 360 #if EAGAIN != EWOULDBLOCK 361 case EWOULDBLOCK: 362 #endif 363 case EINTR: 364 // No need to do anything special here, just assume it's a legitimate wake-up 365 break; 366 default: 367 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 368 } 369 } 370 } 334 371 335 372 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); ) … … 388 425 // runThread runs a thread by context switching 389 426 // from the processor coroutine to the target thread 390 static void __run_thread(processor * this, $thread* thrd_dst) {427 static void __run_thread(processor * this, thread$ * thrd_dst) { 391 428 /* paranoid */ verify( ! __preemption_enabled() ); 392 429 /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted); … … 394 431 __builtin_prefetch( thrd_dst->context.SP ); 395 432 396 int curr = __kernel_getcpu();397 if(thrd_dst->last_cpu != curr) {398 int64_t l = thrd_dst->last_cpu;399 int64_t c = curr;400 int64_t v = (l << 32) | c;401 __push_stat( __tls_stats(), v, false, "Processor", this );402 }403 404 thrd_dst->last_cpu = curr;405 406 433 __cfadbg_print_safe(runtime_core, "Kernel : core %p running thread %p (%s)\n", this, thrd_dst, thrd_dst->self_cor.name); 407 434 408 $coroutine* proc_cor = get_coroutine(this->runner);435 coroutine$ * proc_cor = get_coroutine(this->runner); 409 436 410 437 // set state of processor coroutine to inactive … … 425 452 /* paranoid */ verify( thrd_dst->context.SP ); 426 453 /* paranoid */ verify( thrd_dst->state != Halted ); 427 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor || thrd_dst->corctx_flag, "ERROR : Destination $thread%p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor428 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor || thrd_dst->corctx_flag, "ERROR : Destination $thread%p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor454 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->curr_cor == proc_cor || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); // add escape condition if we are setting up the processor 455 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->curr_cor == proc_cor || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); // add escape condition if we are setting up the processor 429 456 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary ); 430 457 … … 438 465 439 466 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary ); 440 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->corctx_flag, "ERROR : Destination $thread%p has been corrupted.\n StackPointer too large.\n", thrd_dst );441 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->corctx_flag, "ERROR : Destination $thread%p has been corrupted.\n StackPointer too small.\n", thrd_dst );467 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) > ((uintptr_t)__get_stack(thrd_dst->curr_cor)->limit) || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too large.\n", thrd_dst ); 468 /* paranoid */ verifyf( ((uintptr_t)thrd_dst->context.SP) < ((uintptr_t)__get_stack(thrd_dst->curr_cor)->base ) || thrd_dst->corctx_flag, "ERROR : Destination thread$ %p has been corrupted.\n StackPointer too small.\n", thrd_dst ); 442 469 /* paranoid */ verify( thrd_dst->context.SP ); 443 470 /* paranoid */ verify( thrd_dst->curr_cluster == this->cltr ); … … 457 484 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) { 458 485 // The thread was preempted, reschedule it and reset the flag 459 schedule_thread$( thrd_dst );486 schedule_thread$( thrd_dst, UNPARK_LOCAL ); 460 487 break RUNNING; 461 488 } … … 505 532 void returnToKernel() { 506 533 /* paranoid */ verify( ! __preemption_enabled() ); 507 $coroutine* proc_cor = get_coroutine(kernelTLS().this_processor->runner);508 $thread* thrd_src = kernelTLS().this_thread;534 coroutine$ * proc_cor = get_coroutine(kernelTLS().this_processor->runner); 535 thread$ * thrd_src = kernelTLS().this_thread; 509 536 510 537 __STATS( thrd_src->last_proc = kernelTLS().this_processor; ) … … 534 561 535 562 /* paranoid */ verify( ! __preemption_enabled() ); 536 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) < ((uintptr_t)__get_stack(thrd_src->curr_cor)->base ) || thrd_src->corctx_flag, "ERROR : Returning $thread%p has been corrupted.\n StackPointer too small.\n", thrd_src );537 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) > ((uintptr_t)__get_stack(thrd_src->curr_cor)->limit) || thrd_src->corctx_flag, "ERROR : Returning $thread%p has been corrupted.\n StackPointer too large.\n", thrd_src );563 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) < ((uintptr_t)__get_stack(thrd_src->curr_cor)->base ) || thrd_src->corctx_flag, "ERROR : Returning thread$ %p has been corrupted.\n StackPointer too small.\n", thrd_src ); 564 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) > ((uintptr_t)__get_stack(thrd_src->curr_cor)->limit) || thrd_src->corctx_flag, "ERROR : Returning thread$ %p has been corrupted.\n StackPointer too large.\n", thrd_src ); 538 565 } 539 566 … … 541 568 // Scheduler routines 542 569 // KERNEL ONLY 543 static void __schedule_thread( $thread * thrd) {570 static void __schedule_thread( thread$ * thrd, unpark_hint hint ) { 544 571 /* paranoid */ verify( ! __preemption_enabled() ); 545 572 /* paranoid */ verify( ready_schedule_islocked()); … … 561 588 // Dereference the thread now because once we push it, there is not guaranteed it's still valid. 562 589 struct cluster * cl = thrd->curr_cluster; 563 __STATS(bool outside = thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )590 __STATS(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; ) 564 591 565 592 // push the thread to the cluster ready-queue 566 push( cl, thrd, local);593 push( cl, thrd, hint ); 567 594 568 595 // variable thrd is no longer safe to use … … 589 616 } 590 617 591 void schedule_thread$( $thread * thrd) {618 void schedule_thread$( thread$ * thrd, unpark_hint hint ) { 592 619 ready_schedule_lock(); 593 __schedule_thread( thrd );620 __schedule_thread( thrd, hint ); 594 621 ready_schedule_unlock(); 595 622 } 596 623 597 624 // KERNEL ONLY 598 static inline $thread* __next_thread(cluster * this) with( *this ) {625 static inline thread$ * __next_thread(cluster * this) with( *this ) { 599 626 /* paranoid */ verify( ! __preemption_enabled() ); 600 627 601 628 ready_schedule_lock(); 602 $thread* thrd = pop_fast( this );629 thread$ * thrd = pop_fast( this ); 603 630 ready_schedule_unlock(); 604 631 … … 608 635 609 636 // KERNEL ONLY 610 static inline $thread* __next_thread_slow(cluster * this) with( *this ) {637 static inline thread$ * __next_thread_slow(cluster * this) with( *this ) { 611 638 /* paranoid */ verify( ! __preemption_enabled() ); 612 639 613 640 ready_schedule_lock(); 614 $thread* thrd;641 thread$ * thrd; 615 642 for(25) { 616 643 thrd = pop_slow( this ); … … 626 653 } 627 654 628 static inline bool __must_unpark( $thread* thrd ) {655 static inline bool __must_unpark( thread$ * thrd ) { 629 656 int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST); 630 657 switch(old_ticket) { … … 642 669 } 643 670 644 void __kernel_unpark( $thread * thrd) {671 void __kernel_unpark( thread$ * thrd, unpark_hint hint ) { 645 672 /* paranoid */ verify( ! __preemption_enabled() ); 646 673 /* paranoid */ verify( ready_schedule_islocked()); … … 650 677 if(__must_unpark(thrd)) { 651 678 // Wake lost the race, 652 __schedule_thread( thrd );679 __schedule_thread( thrd, hint ); 653 680 } 654 681 … … 657 684 } 658 685 659 void unpark( $thread * thrd) {686 void unpark( thread$ * thrd, unpark_hint hint ) { 660 687 if( !thrd ) return; 661 688 … … 663 690 disable_interrupts(); 664 691 // Wake lost the race, 665 schedule_thread$( thrd );692 schedule_thread$( thrd, hint ); 666 693 enable_interrupts(false); 667 694 } … … 681 708 // Should never return 682 709 void __cfactx_thrd_leave() { 683 $thread* thrd = active_thread();684 $monitor* this = &thrd->self_mon;710 thread$ * thrd = active_thread(); 711 monitor$ * this = &thrd->self_mon; 685 712 686 713 // Lock the monitor now … … 694 721 /* paranoid */ verify( kernelTLS().this_thread == thrd ); 695 722 /* paranoid */ verify( thrd->context.SP ); 696 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) > ((uintptr_t)__get_stack(thrd->curr_cor)->limit), "ERROR : $thread%p has been corrupted.\n StackPointer too large.\n", thrd );697 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) < ((uintptr_t)__get_stack(thrd->curr_cor)->base ), "ERROR : $thread%p has been corrupted.\n StackPointer too small.\n", thrd );723 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) > ((uintptr_t)__get_stack(thrd->curr_cor)->limit), "ERROR : thread$ %p has been corrupted.\n StackPointer too large.\n", thrd ); 724 /* paranoid */ verifyf( ((uintptr_t)thrd->context.SP) < ((uintptr_t)__get_stack(thrd->curr_cor)->base ), "ERROR : thread$ %p has been corrupted.\n StackPointer too small.\n", thrd ); 698 725 699 726 thrd->state = Halting; … … 713 740 bool force_yield( __Preemption_Reason reason ) { 714 741 __disable_interrupts_checked(); 715 $thread* thrd = kernelTLS().this_thread;742 thread$ * thrd = kernelTLS().this_thread; 716 743 /* paranoid */ verify(thrd->state == Active); 717 744 … … 825 852 //============================================================================================= 826 853 void __kernel_abort_msg( char * abort_text, int abort_text_size ) { 827 $thread* thrd = __cfaabi_tls.this_thread;854 thread$ * thrd = __cfaabi_tls.this_thread; 828 855 829 856 if(thrd) { … … 920 947 /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count); 921 948 /* paranoid */ verify( it->local_data->this_stats ); 949 // __print_stats( it->local_data->this_stats, cltr->print_stats, "Processor", it->name, (void*)it ); 922 950 __tally_stats( cltr->stats, it->local_data->this_stats ); 923 951 it = &(*it)`next; … … 929 957 // this doesn't solve all problems but does solve many 930 958 // so it's probably good enough 959 disable_interrupts(); 931 960 uint_fast32_t last_size = ready_mutate_lock(); 932 961 … … 936 965 // Unlock the RWlock 937 966 ready_mutate_unlock( last_size ); 967 enable_interrupts(); 938 968 } 939 969
Note:
See TracChangeset
for help on using the changeset viewer.