Ignore:
File:
1 edited

Legend:

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

    rd6ff3ff 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 );
    54 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); )
    55 
    56 #ifdef __x86_64__
    57 #define CFA_REG_IP REG_RIP
    58 #else
    59 #define CFA_REG_IP REG_EIP
    60 #endif
    61 
    6231
    6332//=============================================================================================
     
    6534//=============================================================================================
    6635
     36void kernel_start_preemption() {
     37
     38}
     39
    6740void tick_preemption() {
    68         // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ticking preemption\n" );
    69 
    7041        alarm_list_t * alarms = &systemProcessor->alarms;
    7142        __cfa_time_t currtime = __kernel_get_time();
    7243        while( alarms->head && alarms->head->alarm < currtime ) {
    7344                alarm_node_t * node = pop(alarms);
    74                 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking %p\n", node );
    75 
    7645                if( node->kernel_alarm ) {
    7746                        preempt( node->proc );
     
    8150                }
    8251
    83                 verify( validate( alarms ) );
    84 
    8552                if( node->period > 0 ) {
    86                         node->alarm = currtime + node->period;
     53                        node->alarm += node->period;
    8754                        insert( alarms, node );
    8855                }
     
    9562                __kernel_set_timer( alarms->head->alarm - currtime );
    9663        }
    97 
    98         verify( validate( alarms ) );
    99         // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking preemption done\n" );
    10064}
    10165
    10266void update_preemption( processor * this, __cfa_time_t duration ) {
    103         LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p updating preemption to %lu\n", this, duration );
    104 
     67        //     assert( THREAD_GETMEM( disableInt ) && THREAD_GETMEM( disableIntCnt ) == 1 );
    10568        alarm_node_t * alarm = this->preemption_alarm;
    106         duration *= 1000;
    10769
    10870        // Alarms need to be enabled
     
    12789}
    12890
     91void ?{}( preemption_scope * this, processor * proc ) {
     92        (&this->alarm){ proc };
     93        this->proc = proc;
     94        this->proc->preemption_alarm = &this->alarm;
     95        update_preemption( this->proc, this->proc->preemption );
     96}
     97
     98void ^?{}( preemption_scope * this ) {
     99        update_preemption( this->proc, 0 );
     100}
     101
    129102//=============================================================================================
    130 // Kernel Signal Tools
     103// Kernel Signal logic
    131104//=============================================================================================
    132105
    133 LIB_DEBUG_DO( static thread_local void * last_interrupt = 0; )
    134 
    135 extern "C" {
    136         void disable_interrupts() {
    137                 __attribute__((unused)) unsigned short new_val = __atomic_add_fetch_2( &disable_preempt_count, 1, __ATOMIC_SEQ_CST );
    138                 verify( new_val < (unsigned short)65_000 );
    139                 verify( new_val != (unsigned short) 0 );
    140         }
    141 
    142         void enable_interrupts_noRF() {
    143                 __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );
    144                 verify( prev != (unsigned short) 0 );
    145         }
    146 
    147         void enable_interrupts( DEBUG_CTX_PARAM ) {
    148                 processor * proc   = this_processor;
    149                 thread_desc * thrd = this_thread;
    150                 unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST );
    151                 verify( prev != (unsigned short) 0 );
    152                 if( prev == 1 && proc->pending_preemption ) {
    153                         proc->pending_preemption = false;
    154                         BlockInternal( thrd );
    155                 }
    156 
    157                 LIB_DEBUG_DO( proc->last_enable = caller; )
    158         }
    159 }
    160 
    161 static inline void signal_unblock( int sig ) {
    162         sigset_t mask;
    163         sigemptyset( &mask );
    164         sigaddset( &mask, sig );
    165 
    166         if ( pthread_sigmask( SIG_UNBLOCK, &mask, NULL ) == -1 ) {
    167             abortf( "internal error, pthread_sigmask" );
    168         }
    169 }
    170 
    171 static inline void signal_block( int sig ) {
    172         sigset_t mask;
    173         sigemptyset( &mask );
    174         sigaddset( &mask, sig );
    175 
    176         if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) {
    177             abortf( "internal error, pthread_sigmask" );
    178         }
    179 }
    180 
    181106static inline bool preemption_ready() {
    182         return disable_preempt_count == 0 && !preemption_in_progress;
     107        return this_processor->disable_preempt_count == 0;
    183108}
    184109
     
    191116}
    192117
     118void sigHandler_ctxSwitch( __attribute__((unused)) int sig ) {
     119        if( preemption_ready() ) {
     120                ScheduleInternal( this_processor->current_thread );
     121        }
     122        else {
     123                defer_ctxSwitch();
     124        }
     125}
     126
     127void sigHandler_alarm( __attribute__((unused)) int sig ) {
     128        if( try_lock( &systemProcessor->alarm_lock ) ) {
     129                tick_preemption();
     130                unlock( &systemProcessor->alarm_lock );
     131        }
     132        else {
     133                defer_alarm();
     134        }
     135}
     136
    193137static void preempt( processor * this ) {
    194138        pthread_kill( this->kernel_thread, SIGUSR1 );
     
    198142        //TODO : implement waking threads
    199143}
    200 
    201 //=============================================================================================
    202 // Kernel Signal Startup/Shutdown logic
    203 //=============================================================================================
    204 
    205 static pthread_t alarm_thread;
    206 void * alarm_loop( __attribute__((unused)) void * args );
    207 
    208 void kernel_start_preemption() {
    209         LIB_DEBUG_PRINT_SAFE("Kernel : Starting preemption\n");
    210         __kernel_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO );
    211         // __kernel_sigaction( SIGSEGV, sigHandler_segv     , SA_SIGINFO );
    212         // __kernel_sigaction( SIGBUS , sigHandler_segv     , SA_SIGINFO );
    213 
    214         signal_block( SIGALRM );
    215 
    216         pthread_create( &alarm_thread, NULL, alarm_loop, NULL );
    217 }
    218 
    219 void kernel_stop_preemption() {
    220         LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopping\n");
    221 
    222         sigset_t mask;
    223         sigfillset( &mask );
    224         sigprocmask( SIG_BLOCK, &mask, NULL );
    225 
    226         sigval val = { 1 };
    227         pthread_sigqueue( alarm_thread, SIGALRM, val );
    228         pthread_join( alarm_thread, NULL );
    229         LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopped\n");
    230 }
    231 
    232 void ?{}( preemption_scope * this, processor * proc ) {
    233         (&this->alarm){ proc };
    234         this->proc = proc;
    235         this->proc->preemption_alarm = &this->alarm;
    236         update_preemption( this->proc, this->proc->preemption );
    237 }
    238 
    239 void ^?{}( preemption_scope * this ) {
    240         disable_interrupts();
    241 
    242         update_preemption( this->proc, 0 );
    243 }
    244 
    245 //=============================================================================================
    246 // Kernel Signal Handlers
    247 //=============================================================================================
    248 
    249 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) {
    250         LIB_DEBUG_DO( last_interrupt = (void *)(cxt->uc_mcontext.gregs[CFA_REG_IP]); )
    251         if( preemption_ready() ) {
    252                 preemption_in_progress = true;
    253                 signal_unblock( SIGUSR1 );
    254                 this_processor->pending_preemption = false;
    255                 preemption_in_progress = false;
    256                 BlockInternal( (thread_desc*)this_thread );
    257         }
    258         else {
    259                 defer_ctxSwitch();
    260         }
    261 }
    262 
    263 void * alarm_loop( __attribute__((unused)) void * args ) {
    264         sigset_t mask;
    265         sigemptyset( &mask );
    266         sigaddset( &mask, SIGALRM );
    267 
    268         if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) {
    269             abortf( "internal error, pthread_sigmask" );
    270         }
    271 
    272         while( true ) {
    273                 siginfo_t info;
    274                 int sig = sigwaitinfo( &mask, &info );
    275                 if( sig < 0 ) {
    276                         abortf( "internal error, sigwait" );
    277                 }
    278                 else if( sig == SIGALRM )
    279                 {
    280                         LIB_DEBUG_PRINT_SAFE("Kernel : Caught signal %d (%d)\n", sig, info.si_value.sival_int );
    281                         if( info.si_value.sival_int == 0 )
    282                         {
    283                                 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption thread tick\n");
    284                                 lock( &systemProcessor->alarm_lock DEBUG_CTX2 );
    285                                 tick_preemption();
    286                                 unlock( &systemProcessor->alarm_lock );
    287                         }
    288                         else if( info.si_value.sival_int == 1 )
    289                         {
    290                                 break;
    291                         }
    292                 }
    293                 else
    294                 {
    295                         LIB_DEBUG_PRINT_SAFE("Kernel : Unexpected signal %d (%d)\n", sig, info.si_value.sival_int);
    296                 }
    297         }
    298 
    299         LIB_DEBUG_PRINT_SAFE("Kernel : Preemption thread stopping\n");
    300         return NULL;
    301 }
    302 
    303 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) {
    304         struct sigaction act;
    305 
    306         act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
    307         act.sa_flags = flags;
    308 
    309         if ( sigaction( sig, &act, NULL ) == -1 ) {
    310                 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,
    311                         " __kernel_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",
    312                         sig, handler, flags, errno, strerror( errno )
    313                 );
    314                 _exit( EXIT_FAILURE );
    315         }
    316 }
    317 
    318 typedef void (*sa_handler_t)(int);
    319 
    320 static void __kernel_sigdefault( int sig ) {
    321         struct sigaction act;
    322 
    323         // act.sa_handler = SIG_DFL;
    324         act.sa_flags = 0;
    325         sigemptyset( &act.sa_mask );
    326 
    327         if ( sigaction( sig, &act, NULL ) == -1 ) {
    328                 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,
    329                         " __kernel_sigdefault( sig:%d ), problem reseting signal handler, error(%d) %s.\n",
    330                         sig, errno, strerror( errno )
    331                 );
    332                 _exit( EXIT_FAILURE );
    333         }
    334 }
    335 
    336 //=============================================================================================
    337 // Terminating Signals logic
    338 //=============================================================================================
    339 
    340 LIB_DEBUG_DO(
    341         static void __kernel_backtrace( int start ) {
    342                 // skip first N stack frames
    343 
    344                 enum { Frames = 50 };
    345                 void * array[Frames];
    346                 int size = backtrace( array, Frames );
    347                 char ** messages = backtrace_symbols( array, size );
    348 
    349                 // find executable name
    350                 *index( messages[0], '(' ) = '\0';
    351                 #ifdef __USE_STREAM__
    352                 serr | "Stack back trace for:" | messages[0] | endl;
    353                 #else
    354                 fprintf( stderr, "Stack back trace for: %s\n", messages[0]);
    355                 #endif
    356 
    357                 // skip last 2 stack frames after main
    358                 for ( int i = start; i < size && messages != NULL; i += 1 ) {
    359                         char * name = NULL;
    360                         char * offset_begin = NULL;
    361                         char * offset_end = NULL;
    362 
    363                         for ( char *p = messages[i]; *p; ++p ) {
    364                                 // find parantheses and +offset
    365                                 if ( *p == '(' ) {
    366                                         name = p;
    367                                 }
    368                                 else if ( *p == '+' ) {
    369                                         offset_begin = p;
    370                                 }
    371                                 else if ( *p == ')' ) {
    372                                         offset_end = p;
    373                                         break;
    374                                 }
    375                         }
    376 
    377                         // if line contains symbol print it
    378                         int frameNo = i - start;
    379                         if ( name && offset_begin && offset_end && name < offset_begin ) {
    380                                 // delimit strings
    381                                 *name++ = '\0';
    382                                 *offset_begin++ = '\0';
    383                                 *offset_end++ = '\0';
    384 
    385                                 #ifdef __USE_STREAM__
    386                                 serr    | "("  | frameNo | ")" | messages[i] | ":"
    387                                         | name | "+" | offset_begin | offset_end | endl;
    388                                 #else
    389                                 fprintf( stderr, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);
    390                                 #endif
    391                         }
    392                         // otherwise, print the whole line
    393                         else {
    394                                 #ifdef __USE_STREAM__
    395                                 serr | "(" | frameNo | ")" | messages[i] | endl;
    396                                 #else
    397                                 fprintf( stderr, "(%i) %s\n", frameNo, messages[i] );
    398                                 #endif
    399                         }
    400                 }
    401 
    402                 free( messages );
    403         }
    404 )
    405 
    406 // void sigHandler_segv( __CFA_SIGPARMS__ ) {
    407 //      LIB_DEBUG_DO(
    408 //              #ifdef __USE_STREAM__
    409 //              serr    | "*CFA runtime error* program cfa-cpp terminated with"
    410 //                      | (sig == SIGSEGV ? "segment fault." : "bus error.")
    411 //                      | endl;
    412 //              #else
    413 //              fprintf( stderr, "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." );
    414 //              #endif
    415 
    416 //              // skip first 2 stack frames
    417 //              __kernel_backtrace( 1 );
    418 //      )
    419 //      exit( EXIT_FAILURE );
    420 // }
    421 
    422 // void sigHandler_abort( __CFA_SIGPARMS__ ) {
    423 //      // skip first 6 stack frames
    424 //      LIB_DEBUG_DO( __kernel_backtrace( 6 ); )
    425 
    426 //      // reset default signal handler
    427 //      __kernel_sigdefault( SIGABRT );
    428 
    429 //      raise( SIGABRT );
    430 // }
Note: See TracChangeset for help on using the changeset viewer.