- File:
-
- 1 edited
-
src/libcfa/concurrency/preemption.c (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/preemption.c
rcd17862 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;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 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 Handlers244 //=============================================================================================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 actions305 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 logic351 //=============================================================================================352 353 LIB_DEBUG_DO(354 static void __kernel_backtrace( int start ) {355 // skip first N stack frames356 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 name363 *index( messages[0], '(' ) = '\0';364 #ifdef __USE_STREAM__365 serr | "Stack back trace for:" | messages[0] | endl;366 #else367 fprintf( stderr, "Stack back trace for: %s\n", messages[0]);368 #endif369 370 // skip last 2 stack frames after main371 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 +offset378 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 it391 int frameNo = i - start;392 if ( name && offset_begin && offset_end && name < offset_begin ) {393 // delimit strings394 *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 #else402 fprintf( stderr, "(%i) %s : %s + %s %s\n", frameNo, messages[i], name, offset_begin, offset_end);403 #endif404 }405 // otherwise, print the whole line406 else {407 #ifdef __USE_STREAM__408 serr | "(" | frameNo | ")" | messages[i] | endl;409 #else410 fprintf( stderr, "(%i) %s\n", frameNo, messages[i] );411 #endif412 }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 #else426 fprintf( stderr, "*CFA runtime error* program cfa-cpp terminated with %s\n", sig == SIGSEGV ? "segment fault." : "bus error." );427 #endif428 429 // skip first 2 stack frames430 __kernel_backtrace( 1 );431 )432 exit( EXIT_FAILURE );433 }434 435 // void sigHandler_abort( __CFA_SIGPARMS__ ) {436 // // skip first 6 stack frames437 // LIB_DEBUG_DO( __kernel_backtrace( 6 ); )438 439 // // reset default signal handler440 // __kernel_sigdefault( SIGABRT );441 442 // raise( SIGABRT );443 // }
Note:
See TracChangeset
for help on using the changeset viewer.