Ignore:
File:
1 edited

Legend:

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

    rb227f68 rc5ac6d5  
    1515//
    1616
    17 #include "libhdr.h"
    1817#include "preemption.h"
    1918
    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 
    36 #define __CFA_DEFAULT_PREEMPTION__ 10000
     23#define __CFA_DEFAULT_PREEMPTION__ 10
    3724
    3825__attribute__((weak)) unsigned int default_preemption() {
     
    4027}
    4128
    42 #define __CFA_SIGCXT__ ucontext_t *
    43 #define __CFA_SIGPARMS__ __attribute__((unused)) int sig, __attribute__((unused)) siginfo_t *sfp, __attribute__((unused)) __CFA_SIGCXT__ cxt
    44 
    4529static void preempt( processor   * this );
    4630static void timeout( thread_desc * this );
    47 
    48 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ );
    49 void sigHandler_alarm    ( __CFA_SIGPARMS__ );
    50 void sigHandler_segv     ( __CFA_SIGPARMS__ );
    51 void sigHandler_abort    ( __CFA_SIGPARMS__ );
    52 
    53 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags );
    5431
    5532//=============================================================================================
     
    5835
    5936void kernel_start_preemption() {
    60         LIB_DEBUG_PRINT_SAFE("Kernel : Starting preemption\n");
    61         __kernel_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO );
    62         __kernel_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO );
    63         __kernel_sigaction( SIGSEGV, sigHandler_segv     , SA_SIGINFO );
    64         __kernel_sigaction( SIGBUS , sigHandler_segv     , SA_SIGINFO );
    65         // __kernel_sigaction( SIGABRT, sigHandler_abort    , SA_SIGINFO );
     37
    6638}
    6739
    68 void kernel_stop_preemption() {
    69         //Block all signals, we are no longer in a position to handle them
    70         sigset_t mask;
    71         sigfillset( &mask );
    72         sigprocmask( SIG_BLOCK, &mask, NULL );
    73         LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopped\n");
    74 
    75         // assert( !systemProcessor->alarms.head );
    76         // assert( systemProcessor->alarms.tail == &systemProcessor->alarms.head );
    77 }
    78 
    79 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )
    80 
    8140void tick_preemption() {
    82         // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ticking preemption\n" );
    83 
    8441        alarm_list_t * alarms = &systemProcessor->alarms;
    8542        __cfa_time_t currtime = __kernel_get_time();
    8643        while( alarms->head && alarms->head->alarm < currtime ) {
    8744                alarm_node_t * node = pop(alarms);
    88                 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking %p\n", node );
    89 
    9045                if( node->kernel_alarm ) {
    9146                        preempt( node->proc );
     
    9550                }
    9651
    97                 verify( validate( alarms ) );
    98 
    9952                if( node->period > 0 ) {
    100                         node->alarm = currtime + node->period;
     53                        node->alarm += node->period;
    10154                        insert( alarms, node );
    10255                }
     
    10962                __kernel_set_timer( alarms->head->alarm - currtime );
    11063        }
    111 
    112         verify( validate( alarms ) );
    113         // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking preemption done\n" );
    11464}
    11565
    11666void update_preemption( processor * this, __cfa_time_t duration ) {
    117         LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p updating preemption to %lu\n", this, duration );
    118 
     67        //     assert( THREAD_GETMEM( disableInt ) && THREAD_GETMEM( disableIntCnt ) == 1 );
    11968        alarm_node_t * alarm = this->preemption_alarm;
    120         duration *= 1000;
    12169
    12270        // Alarms need to be enabled
     
    14997
    15098void ^?{}( preemption_scope * this ) {
    151         disable_interrupts();
    152 
    15399        update_preemption( this->proc, 0 );
    154100}
     
    158104//=============================================================================================
    159105
    160 LIB_DEBUG_DO( static thread_local void * last_interrupt = 0; )
    161 
    162 extern "C" {
    163         void disable_interrupts() {
    164                 __attribute__((unused)) unsigned short new_val = __atomic_add_fetch_2( &disable_preempt_count, 1, __ATOMIC_SEQ_CST );
    165                 verify( new_val < (unsigned short)65_000 );
    166                 verify( new_val != (unsigned short) 0 );
    167         }
    168 
    169         void enable_interrupts_noRF() {
    170                 __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );
    171                 verify( prev != (unsigned short) 0 );
    172         }
    173 
    174         void enable_interrupts( DEBUG_CTX_PARAM ) {
    175                 processor * proc   = this_processor;
    176                 thread_desc * thrd = this_thread;
    177                 unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );
    178                 verify( prev != (unsigned short) 0 );
    179                 if( prev == 1 && proc->pending_preemption ) {
    180                         proc->pending_preemption = false;
    181                         LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Executing deferred CtxSwitch on %p\n", this_processor );
    182                         BlockInternal( thrd );
    183                         LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Executing deferred back\n" );
    184                 }
    185 
    186                 LIB_DEBUG_DO( proc->last_enable = caller; )
    187         }
    188 }
    189 
    190 static inline void signal_unblock( int sig ) {
    191         // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p unblocking sig %i\n", this_processor, sig );
    192 
    193         // LIB_DEBUG_DO(
    194         //      sigset_t waiting;
    195         //      sigemptyset(&waiting);
    196         //      sigpending(&waiting);
    197         //      verify( !sigismember(&waiting, sig) );
    198         // )
    199 
    200         sigset_t mask;
    201         sigemptyset( &mask );
    202         sigaddset( &mask, sig );
    203 
    204         if ( sigprocmask( SIG_UNBLOCK, &mask, NULL ) == -1 ) {
    205             abortf( "internal error, sigprocmask" );
    206         } // if
    207 }
    208 
    209106static inline bool preemption_ready() {
    210         return disable_preempt_count == 0;
     107        return this_processor->disable_preempt_count == 0;
    211108}
    212109
     
    219116}
    220117
    221 extern "C" {
    222         __attribute__((noinline)) void __debug_break() {
    223                 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();
    224124        }
    225125}
    226126
    227 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) {
    228         LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "CtxSw IRH %10p running %10p @ %10p\n", this_processor, this_thread, (void *)(cxt->uc_mcontext.gregs[REG_RIP]) );
    229         LIB_DEBUG_DO( last_interrupt = (void *)(cxt->uc_mcontext.gregs[REG_RIP]); )
    230 
    231         if( preemption_ready() ) {
    232                 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Blocking thread %p on %p\n", this_thread, this_processor );
    233                 signal_unblock( SIGUSR1 );
    234                 BlockInternal( (thread_desc*)this_thread );
    235                 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Back\n\n");
    236         }
    237         else {
    238                 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ctx Switch IRH : Defering\n" );
    239                 defer_ctxSwitch();
    240                 signal_unblock( SIGUSR1 );
    241         }
    242 }
    243 
    244 void sigHandler_alarm( __CFA_SIGPARMS__ ) {
    245         LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "\nAlarm IRH %10p running %10p @ %10p\n", this_processor, this_thread, (void *)(cxt->uc_mcontext.gregs[REG_RIP]) );
    246         LIB_DEBUG_DO( last_interrupt = (void *)(cxt->uc_mcontext.gregs[REG_RIP]); )
    247 
    248         if( try_lock( &systemProcessor->alarm_lock DEBUG_CTX2 ) ) {
     127void sigHandler_alarm( __attribute__((unused)) int sig ) {
     128        if( try_lock( &systemProcessor->alarm_lock ) ) {
    249129                tick_preemption();
    250130                unlock( &systemProcessor->alarm_lock );
     
    253133                defer_alarm();
    254134        }
    255 
    256         signal_unblock( SIGALRM );
    257 
    258         if( preemption_ready() && this_processor->pending_preemption ) {
    259                 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Alarm IRH : Blocking thread %p on %p\n", this_thread, this_processor );
    260                 this_processor->pending_preemption = false;
    261                 BlockInternal( (thread_desc*)this_thread );
    262                 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Alarm Switch IRH : Back\n\n");
    263         }
    264135}
    265136
    266137static void preempt( processor * this ) {
    267         // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : signalling %p\n", this );
    268 
    269         if( this != systemProcessor ) {
    270                 pthread_kill( this->kernel_thread, SIGUSR1 );
    271         }
    272         else {
    273                 defer_ctxSwitch();
    274         }
     138        pthread_kill( this->kernel_thread, SIGUSR1 );
    275139}
    276140
     
    278142        //TODO : implement waking threads
    279143}
    280 
    281 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) {
    282         struct sigaction act;
    283 
    284         act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
    285         act.sa_flags = flags;
    286 
    287         // disabled during signal handler
    288         sigemptyset( &act.sa_mask );
    289         sigaddset( &act.sa_mask, sig );
    290 
    291         if ( sigaction( sig, &act, NULL ) == -1 ) {
    292                 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,
    293                         " __kernel_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",
    294                         sig, handler, flags, errno, strerror( errno )
    295                 );
    296                 _exit( EXIT_FAILURE );
    297         }
    298 }
    299 
    300 typedef void (*sa_handler_t)(int);
    301 
    302 static void __kernel_sigdefault( int sig ) {
    303         struct sigaction act;
    304 
    305         // act.sa_handler = SIG_DFL;
    306         act.sa_flags = 0;
    307         sigemptyset( &act.sa_mask );
    308 
    309         if ( sigaction( sig, &act, NULL ) == -1 ) {
    310                 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,
    311                         " __kernel_sigdefault( sig:%d ), problem reseting signal handler, error(%d) %s.\n",
    312                         sig, errno, strerror( errno )
    313                 );
    314                 _exit( EXIT_FAILURE );
    315         }
    316 }
    317 
    318 //=============================================================================================
    319 // Terminating Signals logic
    320 //=============================================================================================
    321 
    322 LIB_DEBUG_DO(
    323         static void __kernel_backtrace( int start ) {
    324                 // skip first N stack frames
    325 
    326                 enum { Frames = 50 };
    327                 void * array[Frames];
    328                 int size = backtrace( array, Frames );
    329                 char ** messages = backtrace_symbols( array, size );
    330 
    331                 // find executable name
    332                 *index( messages[0], '(' ) = '\0';
    333                 #ifdef __USE_STREAM__
    334                 serr | "Stack back trace for:" | messages[0] | endl;
    335                 #else
    336                 fprintf( stderr, "Stack back trace for: %s\n", messages[0]);
    337                 #endif
    338 
    339                 // skip last 2 stack frames after main
    340                 for ( int i = start; i < size && messages != NULL; i += 1 ) {
    341                         char * name = NULL;
    342                         char * offset_begin = NULL;
    343                         char * offset_end = NULL;
    344 
    345                         for ( char *p = messages[i]; *p; ++p ) {
    346                                 // find parantheses and +offset
    347                                 if ( *p == '(' ) {
    348                                         name = p;
    349                                 }
    350                                 else if ( *p == '+' ) {
    351                                         offset_begin = p;
    352                                 }
    353                                 else if ( *p == ')' ) {
    354                                         offset_end = p;
    355                                         break;
    356                                 }
    357                         }
    358 
    359                         // if line contains symbol print it
    360                         int frameNo = i - start;
    361                         if ( name && offset_begin && offset_end && name < offset_begin ) {
    362                                 // delimit strings
    363                                 *name++ = '\0';
    364                                 *offset_begin++ = '\0';
    365                                 *offset_end++ = '\0';
    366 
    367                                 #ifdef __USE_STREAM__
    368                                 serr    | "("  | frameNo | ")" | messages[i] | ":"
    369                                         | name | "+" | offset_begin | offset_end | endl;
    370                                 #else
    371                                 fprintf( stderr, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);
    372                                 #endif
    373                         }
    374                         // otherwise, print the whole line
    375                         else {
    376                                 #ifdef __USE_STREAM__
    377                                 serr | "(" | frameNo | ")" | messages[i] | endl;
    378                                 #else
    379                                 fprintf( stderr, "(%i) %s\n", frameNo, messages[i] );
    380                                 #endif
    381                         }
    382                 }
    383 
    384                 free( messages );
    385         }
    386 )
    387 
    388 void sigHandler_segv( __CFA_SIGPARMS__ ) {
    389         LIB_DEBUG_DO(
    390                 #ifdef __USE_STREAM__
    391                 serr    | "*CFA runtime error* program cfa-cpp terminated with"
    392                         | (sig == SIGSEGV ? "segment fault." : "bus error.")
    393                         | endl;
    394                 #else
    395                 fprintf( stderr, "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." );
    396                 #endif
    397 
    398                 // skip first 2 stack frames
    399                 __kernel_backtrace( 1 );
    400         )
    401         exit( EXIT_FAILURE );
    402 }
    403 
    404 // void sigHandler_abort( __CFA_SIGPARMS__ ) {
    405 //      // skip first 6 stack frames
    406 //      LIB_DEBUG_DO( __kernel_backtrace( 6 ); )
    407 
    408 //      // reset default signal handler
    409 //      __kernel_sigdefault( SIGABRT );
    410 
    411 //      raise( SIGABRT );
    412 // }
Note: See TracChangeset for help on using the changeset viewer.