Ignore:
File:
1 edited

Legend:

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

    rcd17862 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;
     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         sigset_t mask;
    221         sigfillset( &mask );
    222         sigprocmask( SIG_BLOCK, &mask, NULL );
    223 
    224         pthread_kill( alarm_thread, SIGINT );
    225         pthread_join( alarm_thread, NULL );
    226         LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopped\n");
    227 }
    228 
    229 void ?{}( preemption_scope * this, processor * proc ) {
    230         (&this->alarm){ proc };
    231         this->proc = proc;
    232         this->proc->preemption_alarm = &this->alarm;
    233         update_preemption( this->proc, this->proc->preemption );
    234 }
    235 
    236 void ^?{}( preemption_scope * this ) {
    237         disable_interrupts();
    238 
    239         update_preemption( this->proc, 0 );
    240 }
    241 
    242 //=============================================================================================
    243 // Kernel Signal Handlers
    244 //=============================================================================================
    245 
    246 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) {
    247         LIB_DEBUG_DO( last_interrupt = (void *)(cxt->uc_mcontext.gregs[CFA_REG_IP]); )
    248         if( preemption_ready() ) {
    249                 signal_unblock( SIGUSR1 );
    250                 BlockInternal( (thread_desc*)this_thread );
    251         }
    252         else {
    253                 defer_ctxSwitch();
    254         }
    255 }
    256 
    257 // void sigHandler_alarm( __CFA_SIGPARMS__ ) {
    258 //      LIB_DEBUG_DO( last_interrupt = (void *)(cxt->uc_mcontext.gregs[CFA_REG_IP]); )
    259 //      verify( this_processor == systemProcessor );
    260 
    261 //      if( try_lock( &systemProcessor->alarm_lock DEBUG_CTX2 ) ) {
    262 //              tick_preemption();
    263 //              systemProcessor->pending_alarm = false;
    264 //              unlock( &systemProcessor->alarm_lock );
    265 //      }
    266 //      else {
    267 //              defer_alarm();
    268 //      }
    269 
    270 //      signal_unblock( SIGALRM );
    271 
    272 //      if( preemption_ready() && this_processor->pending_preemption ) {
    273 
    274 //              this_processor->pending_preemption = false;
    275 //              BlockInternal( (thread_desc*)this_thread );
    276 //      }
    277 // }
    278 
    279 void * alarm_loop( __attribute__((unused)) void * args ) {
    280         sigset_t mask;
    281         sigemptyset( &mask );
    282         sigaddset( &mask, SIGALRM );
    283         sigaddset( &mask, SIGUSR2 );
    284         sigaddset( &mask, SIGINT  );
    285 
    286         if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) {
    287             abortf( "internal error, pthread_sigmask" );
    288         }
    289 
    290         while( true ) {
    291                 int sig;
    292                 if( sigwait( &mask, &sig ) != 0  ) {
    293                         abortf( "internal error, sigwait" );
    294                 }
    295 
    296                 switch( sig) {
    297                         case SIGALRM:
    298                                 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption thread tick\n");
    299                                 lock( &systemProcessor->alarm_lock DEBUG_CTX2 );
    300                                 tick_preemption();
    301                                 unlock( &systemProcessor->alarm_lock );
    302                                 break;
    303                         case SIGUSR2:
    304                                 //TODO other actions
    305                                 break;
    306                         case SIGINT:
    307                                 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption thread stopping\n");
    308                                 return NULL;
    309                         default:
    310                                 abortf( "internal error, sigwait returned sig %d", sig );
    311                                 break;
    312                 }
    313         }
    314 }
    315 
    316 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) {
    317         struct sigaction act;
    318 
    319         act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
    320         act.sa_flags = flags;
    321 
    322         if ( sigaction( sig, &act, NULL ) == -1 ) {
    323                 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,
    324                         " __kernel_sigaction( sig:%d, handler:%p, flags:%d ), problem installing signal handler, error(%d) %s.\n",
    325                         sig, handler, flags, errno, strerror( errno )
    326                 );
    327                 _exit( EXIT_FAILURE );
    328         }
    329 }
    330 
    331 typedef void (*sa_handler_t)(int);
    332 
    333 static void __kernel_sigdefault( int sig ) {
    334         struct sigaction act;
    335 
    336         // act.sa_handler = SIG_DFL;
    337         act.sa_flags = 0;
    338         sigemptyset( &act.sa_mask );
    339 
    340         if ( sigaction( sig, &act, NULL ) == -1 ) {
    341                 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO,
    342                         " __kernel_sigdefault( sig:%d ), problem reseting signal handler, error(%d) %s.\n",
    343                         sig, errno, strerror( errno )
    344                 );
    345                 _exit( EXIT_FAILURE );
    346         }
    347 }
    348 
    349 //=============================================================================================
    350 // Terminating Signals logic
    351 //=============================================================================================
    352 
    353 LIB_DEBUG_DO(
    354         static void __kernel_backtrace( int start ) {
    355                 // skip first N stack frames
    356 
    357                 enum { Frames = 50 };
    358                 void * array[Frames];
    359                 int size = backtrace( array, Frames );
    360                 char ** messages = backtrace_symbols( array, size );
    361 
    362                 // find executable name
    363                 *index( messages[0], '(' ) = '\0';
    364                 #ifdef __USE_STREAM__
    365                 serr | "Stack back trace for:" | messages[0] | endl;
    366                 #else
    367                 fprintf( stderr, "Stack back trace for: %s\n", messages[0]);
    368                 #endif
    369 
    370                 // skip last 2 stack frames after main
    371                 for ( int i = start; i < size && messages != NULL; i += 1 ) {
    372                         char * name = NULL;
    373                         char * offset_begin = NULL;
    374                         char * offset_end = NULL;
    375 
    376                         for ( char *p = messages[i]; *p; ++p ) {
    377                                 // find parantheses and +offset
    378                                 if ( *p == '(' ) {
    379                                         name = p;
    380                                 }
    381                                 else if ( *p == '+' ) {
    382                                         offset_begin = p;
    383                                 }
    384                                 else if ( *p == ')' ) {
    385                                         offset_end = p;
    386                                         break;
    387                                 }
    388                         }
    389 
    390                         // if line contains symbol print it
    391                         int frameNo = i - start;
    392                         if ( name && offset_begin && offset_end && name < offset_begin ) {
    393                                 // delimit strings
    394                                 *name++ = '\0';
    395                                 *offset_begin++ = '\0';
    396                                 *offset_end++ = '\0';
    397 
    398                                 #ifdef __USE_STREAM__
    399                                 serr    | "("  | frameNo | ")" | messages[i] | ":"
    400                                         | name | "+" | offset_begin | offset_end | endl;
    401                                 #else
    402                                 fprintf( stderr, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);
    403                                 #endif
    404                         }
    405                         // otherwise, print the whole line
    406                         else {
    407                                 #ifdef __USE_STREAM__
    408                                 serr | "(" | frameNo | ")" | messages[i] | endl;
    409                                 #else
    410                                 fprintf( stderr, "(%i) %s\n", frameNo, messages[i] );
    411                                 #endif
    412                         }
    413                 }
    414 
    415                 free( messages );
    416         }
    417 )
    418 
    419 void sigHandler_segv( __CFA_SIGPARMS__ ) {
    420         LIB_DEBUG_DO(
    421                 #ifdef __USE_STREAM__
    422                 serr    | "*CFA runtime error* program cfa-cpp terminated with"
    423                         | (sig == SIGSEGV ? "segment fault." : "bus error.")
    424                         | endl;
    425                 #else
    426                 fprintf( stderr, "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." );
    427                 #endif
    428 
    429                 // skip first 2 stack frames
    430                 __kernel_backtrace( 1 );
    431         )
    432         exit( EXIT_FAILURE );
    433 }
    434 
    435 // void sigHandler_abort( __CFA_SIGPARMS__ ) {
    436 //      // skip first 6 stack frames
    437 //      LIB_DEBUG_DO( __kernel_backtrace( 6 ); )
    438 
    439 //      // reset default signal handler
    440 //      __kernel_sigdefault( SIGABRT );
    441 
    442 //      raise( SIGABRT );
    443 // }
Note: See TracChangeset for help on using the changeset viewer.