Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/kernel.cfa

    rc33c2af r1f45c7d  
    2222#include <errno.h>
    2323#include <stdio.h>
    24 #include <string.h>
    2524#include <signal.h>
    2625#include <unistd.h>
     
    3231#include "kernel_private.hfa"
    3332#include "preemption.hfa"
    34 #include "strstream.hfa"
    35 #include "device/cpu.hfa"
    3633
    3734//Private includes
     
    113110#endif
    114111
    115 extern thread$ * mainThread;
     112extern $thread * mainThread;
    116113extern processor * mainProcessor;
    117114
    118115//-----------------------------------------------------------------------------
    119116// Kernel Scheduling logic
    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);
     117static $thread * __next_thread(cluster * this);
     118static $thread * __next_thread_slow(cluster * this);
     119static inline bool __must_unpark( $thread * thrd ) __attribute((nonnull(1)));
     120static void __run_thread(processor * this, $thread * dst);
    124121static void __wake_one(cluster * cltr);
    125122
     
    184181                __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this);
    185182
    186                 thread$ * readyThread = 0p;
     183                $thread * readyThread = 0p;
    187184                MAIN_LOOP:
    188185                for() {
     
    196193
    197194                        if( !readyThread ) {
    198                                 ready_schedule_lock();
    199195                                __cfa_io_flush( this );
    200                                 ready_schedule_unlock();
    201 
    202196                                readyThread = __next_thread_slow( this->cltr );
    203197                        }
     
    237231                                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
    238232
    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                                 }
     233                                __disable_interrupts_hard();
     234                                eventfd_t val;
     235                                eventfd_read( this->idle, &val );
     236                                __enable_interrupts_hard();
    256237
    257238                                #if !defined(__CFA_NO_STATISTICS__)
     
    280261
    281262                        if(this->io.pending && !this->io.dirty) {
    282                                 ready_schedule_lock();
    283263                                __cfa_io_flush( this );
    284                                 ready_schedule_unlock();
    285264                        }
    286265
     
    322301
    323302                                // Don't block if we are done
    324                                 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) {
    325                                         ready_schedule_unlock();
    326                                         break MAIN_LOOP;
    327                                 }
     303                                if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    328304
    329305                                __STATS( __tls_stats()->ready.sleep.halts++; )
     
    349325                                }
    350326
    351                                 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )
     327                                        __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )
    352328                                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
    353329
    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                                 }
     330                                // __disable_interrupts_hard();
     331                                eventfd_t val;
     332                                eventfd_read( this->idle, &val );
     333                                // __enable_interrupts_hard();
    371334
    372335                                        __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); )
     
    425388// runThread runs a thread by context switching
    426389// from the processor coroutine to the target thread
    427 static void __run_thread(processor * this, thread$ * thrd_dst) {
     390static void __run_thread(processor * this, $thread * thrd_dst) {
    428391        /* paranoid */ verify( ! __preemption_enabled() );
    429392        /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted);
     
    431394        __builtin_prefetch( thrd_dst->context.SP );
    432395
     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
    433406        __cfadbg_print_safe(runtime_core, "Kernel : core %p running thread %p (%s)\n", this, thrd_dst, thrd_dst->self_cor.name);
    434407
    435         coroutine$ * proc_cor = get_coroutine(this->runner);
     408        $coroutine * proc_cor = get_coroutine(this->runner);
    436409
    437410        // set state of processor coroutine to inactive
     
    452425                /* paranoid */ verify( thrd_dst->context.SP );
    453426                /* paranoid */ verify( thrd_dst->state != Halted );
    454                 /* 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
     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 processor
     428                /* 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
    456429                /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary );
    457430
     
    465438
    466439                /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary );
    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 );
     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 );
    469442                /* paranoid */ verify( thrd_dst->context.SP );
    470443                /* paranoid */ verify( thrd_dst->curr_cluster == this->cltr );
     
    484457                if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) {
    485458                        // The thread was preempted, reschedule it and reset the flag
    486                         schedule_thread$( thrd_dst, UNPARK_LOCAL );
     459                        schedule_thread$( thrd_dst );
    487460                        break RUNNING;
    488461                }
     
    532505void returnToKernel() {
    533506        /* paranoid */ verify( ! __preemption_enabled() );
    534         coroutine$ * proc_cor = get_coroutine(kernelTLS().this_processor->runner);
    535         thread$ * thrd_src = kernelTLS().this_thread;
     507        $coroutine * proc_cor = get_coroutine(kernelTLS().this_processor->runner);
     508        $thread * thrd_src = kernelTLS().this_thread;
    536509
    537510        __STATS( thrd_src->last_proc = kernelTLS().this_processor; )
     
    561534
    562535        /* paranoid */ verify( ! __preemption_enabled() );
    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 );
     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 );
    565538}
    566539
     
    568541// Scheduler routines
    569542// KERNEL ONLY
    570 static void __schedule_thread( thread$ * thrd, unpark_hint hint ) {
     543static void __schedule_thread( $thread * thrd ) {
    571544        /* paranoid */ verify( ! __preemption_enabled() );
    572545        /* paranoid */ verify( ready_schedule_islocked());
     
    588561        // Dereference the thread now because once we push it, there is not guaranteed it's still valid.
    589562        struct cluster * cl = thrd->curr_cluster;
    590         __STATS(bool outside = hint == UNPARK_LOCAL && thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
     563        __STATS(bool outside = thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
    591564
    592565        // push the thread to the cluster ready-queue
    593         push( cl, thrd, hint );
     566        push( cl, thrd, local );
    594567
    595568        // variable thrd is no longer safe to use
     
    616589}
    617590
    618 void schedule_thread$( thread$ * thrd, unpark_hint hint ) {
     591void schedule_thread$( $thread * thrd ) {
    619592        ready_schedule_lock();
    620                 __schedule_thread( thrd, hint );
     593                __schedule_thread( thrd );
    621594        ready_schedule_unlock();
    622595}
    623596
    624597// KERNEL ONLY
    625 static inline thread$ * __next_thread(cluster * this) with( *this ) {
     598static inline $thread * __next_thread(cluster * this) with( *this ) {
    626599        /* paranoid */ verify( ! __preemption_enabled() );
    627600
    628601        ready_schedule_lock();
    629                 thread$ * thrd = pop_fast( this );
     602                $thread * thrd = pop_fast( this );
    630603        ready_schedule_unlock();
    631604
     
    635608
    636609// KERNEL ONLY
    637 static inline thread$ * __next_thread_slow(cluster * this) with( *this ) {
     610static inline $thread * __next_thread_slow(cluster * this) with( *this ) {
    638611        /* paranoid */ verify( ! __preemption_enabled() );
    639612
    640613        ready_schedule_lock();
    641                 thread$ * thrd;
     614                $thread * thrd;
    642615                for(25) {
    643616                        thrd = pop_slow( this );
     
    653626}
    654627
    655 static inline bool __must_unpark( thread$ * thrd ) {
     628static inline bool __must_unpark( $thread * thrd ) {
    656629        int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST);
    657630        switch(old_ticket) {
     
    669642}
    670643
    671 void __kernel_unpark( thread$ * thrd, unpark_hint hint ) {
     644void __kernel_unpark( $thread * thrd ) {
    672645        /* paranoid */ verify( ! __preemption_enabled() );
    673646        /* paranoid */ verify( ready_schedule_islocked());
     
    677650        if(__must_unpark(thrd)) {
    678651                // Wake lost the race,
    679                 __schedule_thread( thrd, hint );
     652                __schedule_thread( thrd );
    680653        }
    681654
     
    684657}
    685658
    686 void unpark( thread$ * thrd, unpark_hint hint ) {
     659void unpark( $thread * thrd ) {
    687660        if( !thrd ) return;
    688661
     
    690663                disable_interrupts();
    691664                        // Wake lost the race,
    692                         schedule_thread$( thrd, hint );
     665                        schedule_thread$( thrd );
    693666                enable_interrupts(false);
    694667        }
     
    708681        // Should never return
    709682        void __cfactx_thrd_leave() {
    710                 thread$ * thrd = active_thread();
    711                 monitor$ * this = &thrd->self_mon;
     683                $thread * thrd = active_thread();
     684                $monitor * this = &thrd->self_mon;
    712685
    713686                // Lock the monitor now
     
    721694                /* paranoid */ verify( kernelTLS().this_thread == thrd );
    722695                /* paranoid */ verify( thrd->context.SP );
    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 );
     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 );
    725698
    726699                thrd->state = Halting;
     
    740713bool force_yield( __Preemption_Reason reason ) {
    741714        __disable_interrupts_checked();
    742                 thread$ * thrd = kernelTLS().this_thread;
     715                $thread * thrd = kernelTLS().this_thread;
    743716                /* paranoid */ verify(thrd->state == Active);
    744717
     
    852825//=============================================================================================
    853826void __kernel_abort_msg( char * abort_text, int abort_text_size ) {
    854         thread$ * thrd = __cfaabi_tls.this_thread;
     827        $thread * thrd = __cfaabi_tls.this_thread;
    855828
    856829        if(thrd) {
     
    947920                        /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
    948921                        /* paranoid */ verify( it->local_data->this_stats );
    949                         // __print_stats( it->local_data->this_stats, cltr->print_stats, "Processor", it->name, (void*)it );
    950922                        __tally_stats( cltr->stats, it->local_data->this_stats );
    951923                        it = &(*it)`next;
     
    957929                // this doesn't solve all problems but does solve many
    958930                // so it's probably good enough
    959                 disable_interrupts();
    960931                uint_fast32_t last_size = ready_mutate_lock();
    961932
     
    965936                // Unlock the RWlock
    966937                ready_mutate_unlock( last_size );
    967                 enable_interrupts();
    968938        }
    969939
Note: See TracChangeset for help on using the changeset viewer.