- File:
-
- 1 edited
-
src/libcfa/concurrency/preemption.c (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/preemption.c
rd6ff3ff rc5ac6d5 15 15 // 16 16 17 #include "libhdr.h"18 17 #include "preemption.h" 19 18 20 19 extern "C" { 21 #include <errno.h>22 #include <execinfo.h>23 #define __USE_GNU24 20 #include <signal.h> 25 #undef __USE_GNU26 #include <stdio.h>27 #include <string.h>28 #include <unistd.h>29 21 } 30 22 31 32 #ifdef __USE_STREAM__ 33 #include "fstream" 34 #endif 35 36 #define __CFA_DEFAULT_PREEMPTION__ 10000 23 #define __CFA_DEFAULT_PREEMPTION__ 10 37 24 38 25 __attribute__((weak)) unsigned int default_preemption() { … … 40 27 } 41 28 42 #define __CFA_SIGCXT__ ucontext_t *43 #define __CFA_SIGPARMS__ __attribute__((unused)) int sig, __attribute__((unused)) siginfo_t *sfp, __attribute__((unused)) __CFA_SIGCXT__ cxt44 45 29 static void preempt( processor * this ); 46 30 static 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_RIP58 #else59 #define CFA_REG_IP REG_EIP60 #endif61 62 31 63 32 //============================================================================================= … … 65 34 //============================================================================================= 66 35 36 void kernel_start_preemption() { 37 38 } 39 67 40 void tick_preemption() { 68 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ticking preemption\n" );69 70 41 alarm_list_t * alarms = &systemProcessor->alarms; 71 42 __cfa_time_t currtime = __kernel_get_time(); 72 43 while( alarms->head && alarms->head->alarm < currtime ) { 73 44 alarm_node_t * node = pop(alarms); 74 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking %p\n", node );75 76 45 if( node->kernel_alarm ) { 77 46 preempt( node->proc ); … … 81 50 } 82 51 83 verify( validate( alarms ) );84 85 52 if( node->period > 0 ) { 86 node->alarm = currtime +node->period;53 node->alarm += node->period; 87 54 insert( alarms, node ); 88 55 } … … 95 62 __kernel_set_timer( alarms->head->alarm - currtime ); 96 63 } 97 98 verify( validate( alarms ) );99 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking preemption done\n" );100 64 } 101 65 102 66 void 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 ); 105 68 alarm_node_t * alarm = this->preemption_alarm; 106 duration *= 1000;107 69 108 70 // Alarms need to be enabled … … 127 89 } 128 90 91 void ?{}( 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 98 void ^?{}( preemption_scope * this ) { 99 update_preemption( this->proc, 0 ); 100 } 101 129 102 //============================================================================================= 130 // Kernel Signal Tools103 // Kernel Signal logic 131 104 //============================================================================================= 132 105 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 181 106 static inline bool preemption_ready() { 182 return disable_preempt_count == 0 && !preemption_in_progress;107 return this_processor->disable_preempt_count == 0; 183 108 } 184 109 … … 191 116 } 192 117 118 void 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 127 void 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 193 137 static void preempt( processor * this ) { 194 138 pthread_kill( this->kernel_thread, SIGUSR1 ); … … 198 142 //TODO : implement waking threads 199 143 } 200 201 //=============================================================================================202 // Kernel Signal Startup/Shutdown logic203 //=============================================================================================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 Handlers247 //=============================================================================================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 else294 {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 logic338 //=============================================================================================339 340 LIB_DEBUG_DO(341 static void __kernel_backtrace( int start ) {342 // skip first N stack frames343 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 name350 *index( messages[0], '(' ) = '\0';351 #ifdef __USE_STREAM__352 serr | "Stack back trace for:" | messages[0] | endl;353 #else354 fprintf( stderr, "Stack back trace for: %s\n", messages[0]);355 #endif356 357 // skip last 2 stack frames after main358 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 +offset365 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 it378 int frameNo = i - start;379 if ( name && offset_begin && offset_end && name < offset_begin ) {380 // delimit strings381 *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 #else389 fprintf( stderr, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);390 #endif391 }392 // otherwise, print the whole line393 else {394 #ifdef __USE_STREAM__395 serr | "(" | frameNo | ")" | messages[i] | endl;396 #else397 fprintf( stderr, "(%i) %s\n", frameNo, messages[i] );398 #endif399 }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 // #else413 // fprintf( stderr, "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." );414 // #endif415 416 // // skip first 2 stack frames417 // __kernel_backtrace( 1 );418 // )419 // exit( EXIT_FAILURE );420 // }421 422 // void sigHandler_abort( __CFA_SIGPARMS__ ) {423 // // skip first 6 stack frames424 // LIB_DEBUG_DO( __kernel_backtrace( 6 ); )425 426 // // reset default signal handler427 // __kernel_sigdefault( SIGABRT );428 429 // raise( SIGABRT );430 // }
Note:
See TracChangeset
for help on using the changeset viewer.