Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/libcfa/concurrency/preemption.c

    r1c273d0 rc5ac6d5  
    1717#include "preemption.h"
    1818
    19 
    2019extern "C" {
    21 #include <errno.h>
    22 #include <execinfo.h>
    23 #define __USE_GNU
    2420#include <signal.h>
    25 #undef __USE_GNU
    26 #include <stdio.h>
    27 #include <string.h>
    28 #include <unistd.h>
    2921}
    3022
    31 
    32 #ifdef __USE_STREAM__
    33 #include "fstream"
    34 #endif
    35 #include "libhdr.h"
    36 
    37 #define __CFA_DEFAULT_PREEMPTION__ 10000
     23#define __CFA_DEFAULT_PREEMPTION__ 10
    3824
    3925__attribute__((weak)) unsigned int default_preemption() {
     
    4127}
    4228
    43 #define __CFA_SIGCXT__ ucontext_t *
    44 #define __CFA_SIGPARMS__ __attribute__((unused)) int sig, __attribute__((unused)) siginfo_t *sfp, __attribute__((unused)) __CFA_SIGCXT__ cxt
    45 
    4629static void preempt( processor   * this );
    4730static void timeout( thread_desc * this );
    48 
    49 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ );
    50 void sigHandler_alarm    ( __CFA_SIGPARMS__ );
    51 void sigHandler_segv     ( __CFA_SIGPARMS__ );
    52 void sigHandler_abort    ( __CFA_SIGPARMS__ );
    53 
    54 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags );
    5531
    5632//=============================================================================================
     
    5935
    6036void kernel_start_preemption() {
    61         LIB_DEBUG_PRINT_SAFE("Kernel : Starting preemption\n");
    62         __kernel_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO );
    63         __kernel_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO );
    64         __kernel_sigaction( SIGSEGV, sigHandler_segv     , SA_SIGINFO );
    65         __kernel_sigaction( SIGBUS , sigHandler_segv     , SA_SIGINFO );
    66         // __kernel_sigaction( SIGABRT, sigHandler_abort    , SA_SIGINFO );
     37
    6738}
    6839
    69 void kernel_stop_preemption() {
    70         //Block all signals, we are no longer in a position to handle them
    71         sigset_t mask;
    72         sigfillset( &mask );
    73         sigprocmask( SIG_BLOCK, &mask, NULL );
    74         LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopped\n");
    75 
    76         // assert( !systemProcessor->alarms.head );
    77         // assert( systemProcessor->alarms.tail == &systemProcessor->alarms.head );
    78 }
    79 
    80 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )
    81 
    8240void tick_preemption() {
    83         // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ticking preemption\n" );
    84 
    8541        alarm_list_t * alarms = &systemProcessor->alarms;
    8642        __cfa_time_t currtime = __kernel_get_time();
    8743        while( alarms->head && alarms->head->alarm < currtime ) {
    8844                alarm_node_t * node = pop(alarms);
    89                 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking %p\n", node );
    90 
    9145                if( node->kernel_alarm ) {
    9246                        preempt( node->proc );
     
    9650                }
    9751
    98                 verify( validate( alarms ) );
    99 
    10052                if( node->period > 0 ) {
    101                         node->alarm = currtime + node->period;
     53                        node->alarm += node->period;
    10254                        insert( alarms, node );
    10355                }
     
    11062                __kernel_set_timer( alarms->head->alarm - currtime );
    11163        }
    112 
    113         verify( validate( alarms ) );
    114         // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking preemption done\n" );
    11564}
    11665
    11766void update_preemption( processor * this, __cfa_time_t duration ) {
    118         LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p updating preemption to %lu\n", this, duration );
    119 
     67        //     assert( THREAD_GETMEM( disableInt ) && THREAD_GETMEM( disableIntCnt ) == 1 );
    12068        alarm_node_t * alarm = this->preemption_alarm;
    121         duration *= 1000;
    12269
    12370        // Alarms need to be enabled
     
    15097
    15198void ^?{}( preemption_scope * this ) {
    152         disable_interrupts();
    153 
    15499        update_preemption( this->proc, 0 );
    155100}
     
    159104//=============================================================================================
    160105
    161 extern "C" {
    162         void disable_interrupts() {
    163                 __attribute__((unused)) unsigned short new_val = __atomic_add_fetch_2( &disable_preempt_count, 1, __ATOMIC_SEQ_CST );
    164                 verify( new_val < (unsigned short)65_000 );
    165                 verify( new_val != (unsigned short) 0 );
    166         }
    167 
    168         void enable_interrupts_noRF() {
    169                 unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );
    170                 verify( prev != (unsigned short) 0 );
    171         }
    172 
    173         void enable_interrupts( const char * func ) {
    174                 processor * proc   = this_processor;
    175                 thread_desc * thrd = this_thread;
    176                 unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );
    177                 verify( prev != (unsigned short) 0 );
    178                 if( prev == 1 && proc->pending_preemption ) {
    179                         proc->pending_preemption = false;
    180                         LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Executing deferred CtxSwitch on %p\n", this_processor );
    181                         BlockInternal( thrd );
    182                         LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Executing deferred back\n" );
    183                 }
    184 
    185                 proc->last_enable = func;
    186         }
    187 }
    188 
    189 static inline void signal_unblock( int sig ) {
    190         LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p unblocking sig %i\n", this_processor, sig );
    191 
    192         sigset_t mask;
    193         sigemptyset( &mask );
    194         sigaddset( &mask, sig );
    195 
    196         if ( sigprocmask( SIG_UNBLOCK, &mask, NULL ) == -1 ) {
    197             abortf( "internal error, sigprocmask" );
    198         } // if
    199 }
    200 
    201106static inline bool preemption_ready() {
    202         return disable_preempt_count == 0;
     107        return this_processor->disable_preempt_count == 0;
    203108}
    204109
     
    211116}
    212117
    213 extern "C" {
    214         __attribute__((noinline)) void __debug_break() {
    215                 pthread_kill( pthread_self(), SIGTRAP );
     118void sigHandler_ctxSwitch( __attribute__((unused)) int sig ) {
     119        if( preemption_ready() ) {
     120                ScheduleInternal( this_processor->current_thread );
     121        }
     122        else {
     123                defer_ctxSwitch();
    216124        }
    217125}
    218126
    219 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) {
    220         LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ctx Switch IRH %p running %p @ %p\n", this_processor, this_thread, (void *)(cxt->uc_mcontext.gregs[REG_RIP]) );
    221 
    222         if( preemption_ready() ) {
    223                 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Blocking thread %p on %p\n", this_thread, this_processor );
    224                 signal_unblock( SIGUSR1 );
    225                 BlockInternal( (thread_desc*)this_thread );
    226                 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Back\n\n");
    227         }
    228         else {
    229                 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Defering\n" );
    230                 defer_ctxSwitch();
    231                 signal_unblock( SIGUSR1 );
    232         }
    233 }
    234 
    235 void sigHandler_alarm( __CFA_SIGPARMS__ ) {
    236         LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "\nAlarm IRH %p running %p @ %p\n", this_processor, this_thread, (void *)(cxt->uc_mcontext.gregs[REG_RIP]) );
    237 
    238         // if( ((intptr_t)cxt->uc_mcontext.gregs[REG_RIP]) > 0xFFFFFF ) __debug_break();
    239 
    240         if( try_lock( &systemProcessor->alarm_lock, __PRETTY_FUNCTION__ ) ) {
     127void sigHandler_alarm( __attribute__((unused)) int sig ) {
     128        if( try_lock( &systemProcessor->alarm_lock ) ) {
    241129                tick_preemption();
    242130                unlock( &systemProcessor->alarm_lock );
     
    245133                defer_alarm();
    246134        }
    247 
    248         signal_unblock( SIGALRM );
    249 
    250         if( preemption_ready() && this_processor->pending_preemption ) {
    251                 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Alarm IRH : Blocking thread %p on %p\n", this_thread, this_processor );
    252                 this_processor->pending_preemption = false;
    253                 BlockInternal( (thread_desc*)this_thread );
    254                 LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Alarm Switch IRH : Back\n\n");
    255         }
    256135}
    257136
    258137static void preempt( processor * this ) {
    259         // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : signalling %p\n", this );
    260 
    261         if( this != systemProcessor ) {
    262                 pthread_kill( this->kernel_thread, SIGUSR1 );
    263         }
    264         else {
    265                 defer_ctxSwitch();
    266         }
     138        pthread_kill( this->kernel_thread, SIGUSR1 );
    267139}
    268140
     
    270142        //TODO : implement waking threads
    271143}
    272 
    273 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) {
    274         struct sigaction act;
    275 
    276         act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
    277         act.sa_flags = flags;
    278 
    279         // disabled during signal handler
    280         sigemptyset( &act.sa_mask );
    281         sigaddset( &act.sa_mask, sig );
    282 
    283         if ( sigaction( sig, &act, NULL ) == -1 ) {
    284                 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,
    285                         " __kernel_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",
    286                         sig, handler, flags, errno, strerror( errno )
    287                 );
    288                 _exit( EXIT_FAILURE );
    289         }
    290 }
    291 
    292 typedef void (*sa_handler_t)(int);
    293 
    294 static void __kernel_sigdefault( int sig ) {
    295         struct sigaction act;
    296 
    297         // act.sa_handler = SIG_DFL;
    298         act.sa_flags = 0;
    299         sigemptyset( &act.sa_mask );
    300 
    301         if ( sigaction( sig, &act, NULL ) == -1 ) {
    302                 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,
    303                         " __kernel_sigdefault( sig:%d ), problem reseting signal handler, error(%d) %s.\n",
    304                         sig, errno, strerror( errno )
    305                 );
    306                 _exit( EXIT_FAILURE );
    307         }
    308 }
    309 
    310 //=============================================================================================
    311 // Terminating Signals logic
    312 //=============================================================================================
    313 
    314 LIB_DEBUG_DO(
    315         static void __kernel_backtrace( int start ) {
    316                 // skip first N stack frames
    317 
    318                 enum { Frames = 50 };
    319                 void * array[Frames];
    320                 int size = backtrace( array, Frames );
    321                 char ** messages = backtrace_symbols( array, size );
    322 
    323                 // find executable name
    324                 *index( messages[0], '(' ) = '\0';
    325                 #ifdef __USE_STREAM__
    326                 serr | "Stack back trace for:" | messages[0] | endl;
    327                 #else
    328                 fprintf( stderr, "Stack back trace for: %s\n", messages[0]);
    329                 #endif
    330 
    331                 // skip last 2 stack frames after main
    332                 for ( int i = start; i < size && messages != NULL; i += 1 ) {
    333                         char * name = NULL;
    334                         char * offset_begin = NULL;
    335                         char * offset_end = NULL;
    336 
    337                         for ( char *p = messages[i]; *p; ++p ) {
    338                                 // find parantheses and +offset
    339                                 if ( *p == '(' ) {
    340                                         name = p;
    341                                 }
    342                                 else if ( *p == '+' ) {
    343                                         offset_begin = p;
    344                                 }
    345                                 else if ( *p == ')' ) {
    346                                         offset_end = p;
    347                                         break;
    348                                 }
    349                         }
    350 
    351                         // if line contains symbol print it
    352                         int frameNo = i - start;
    353                         if ( name && offset_begin && offset_end && name < offset_begin ) {
    354                                 // delimit strings
    355                                 *name++ = '\0';
    356                                 *offset_begin++ = '\0';
    357                                 *offset_end++ = '\0';
    358 
    359                                 #ifdef __USE_STREAM__
    360                                 serr    | "("  | frameNo | ")" | messages[i] | ":"
    361                                         | name | "+" | offset_begin | offset_end | endl;
    362                                 #else
    363                                 fprintf( stderr, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);
    364                                 #endif
    365                         }
    366                         // otherwise, print the whole line
    367                         else {
    368                                 #ifdef __USE_STREAM__
    369                                 serr | "(" | frameNo | ")" | messages[i] | endl;
    370                                 #else
    371                                 fprintf( stderr, "(%i) %s\n", frameNo, messages[i] );
    372                                 #endif
    373                         }
    374                 }
    375 
    376                 free( messages );
    377         }
    378 )
    379 
    380 void sigHandler_segv( __CFA_SIGPARMS__ ) {
    381         LIB_DEBUG_DO(
    382                 #ifdef __USE_STREAM__
    383                 serr    | "*CFA runtime error* program cfa-cpp terminated with"
    384                         | (sig == SIGSEGV ? "segment fault." : "bus error.")
    385                         | endl;
    386                 #else
    387                 fprintf( stderr, "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." );
    388                 #endif
    389 
    390                 // skip first 2 stack frames
    391                 __kernel_backtrace( 1 );
    392         )
    393         exit( EXIT_FAILURE );
    394 }
    395 
    396 // void sigHandler_abort( __CFA_SIGPARMS__ ) {
    397 //      // skip first 6 stack frames
    398 //      LIB_DEBUG_DO( __kernel_backtrace( 6 ); )
    399 
    400 //      // reset default signal handler
    401 //      __kernel_sigdefault( SIGABRT );
    402 
    403 //      raise( SIGABRT );
    404 // }
Note: See TracChangeset for help on using the changeset viewer.