Changeset 3d4b23fa for src/libcfa/concurrency/preemption.c
- Timestamp:
- Jul 13, 2017, 3:57:04 PM (8 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- 0720e049, 9a1e509
- Parents:
- 55a68c3 (diff), d6ff3ff (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/preemption.c
r55a68c3 r3d4b23fa 15 15 // 16 16 17 #include "libhdr.h" 17 18 #include "preemption.h" 18 19 19 20 extern "C" { 21 #include <errno.h> 22 #include <execinfo.h> 23 #define __USE_GNU 20 24 #include <signal.h> 21 } 22 23 #define __CFA_DEFAULT_PREEMPTION__ 10 25 #undef __USE_GNU 26 #include <stdio.h> 27 #include <string.h> 28 #include <unistd.h> 29 } 30 31 32 #ifdef __USE_STREAM__ 33 #include "fstream" 34 #endif 35 36 #define __CFA_DEFAULT_PREEMPTION__ 10000 24 37 25 38 __attribute__((weak)) unsigned int default_preemption() { … … 27 40 } 28 41 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 29 45 static void preempt( processor * this ); 30 46 static void timeout( thread_desc * this ); 31 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 62 32 63 //============================================================================================= 33 64 // Kernel Preemption logic 34 65 //============================================================================================= 35 66 36 void kernel_start_preemption() {37 38 }39 40 67 void tick_preemption() { 68 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ticking preemption\n" ); 69 41 70 alarm_list_t * alarms = &systemProcessor->alarms; 42 71 __cfa_time_t currtime = __kernel_get_time(); 43 72 while( alarms->head && alarms->head->alarm < currtime ) { 44 73 alarm_node_t * node = pop(alarms); 74 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking %p\n", node ); 75 45 76 if( node->kernel_alarm ) { 46 77 preempt( node->proc ); … … 50 81 } 51 82 83 verify( validate( alarms ) ); 84 52 85 if( node->period > 0 ) { 53 node->alarm +=node->period;86 node->alarm = currtime + node->period; 54 87 insert( alarms, node ); 55 88 } … … 62 95 __kernel_set_timer( alarms->head->alarm - currtime ); 63 96 } 97 98 verify( validate( alarms ) ); 99 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking preemption done\n" ); 64 100 } 65 101 66 102 void update_preemption( processor * this, __cfa_time_t duration ) { 67 // assert( THREAD_GETMEM( disableInt ) && THREAD_GETMEM( disableIntCnt ) == 1 ); 103 LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Processor : %p updating preemption to %lu\n", this, duration ); 104 68 105 alarm_node_t * alarm = this->preemption_alarm; 106 duration *= 1000; 69 107 70 108 // Alarms need to be enabled … … 89 127 } 90 128 129 //============================================================================================= 130 // Kernel Signal Tools 131 //============================================================================================= 132 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 static inline bool preemption_ready() { 182 return disable_preempt_count == 0 && !preemption_in_progress; 183 } 184 185 static inline void defer_ctxSwitch() { 186 this_processor->pending_preemption = true; 187 } 188 189 static inline void defer_alarm() { 190 systemProcessor->pending_alarm = true; 191 } 192 193 static void preempt( processor * this ) { 194 pthread_kill( this->kernel_thread, SIGUSR1 ); 195 } 196 197 static void timeout( thread_desc * this ) { 198 //TODO : implement waking threads 199 } 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 91 232 void ?{}( preemption_scope * this, processor * proc ) { 92 233 (&this->alarm){ proc }; … … 97 238 98 239 void ^?{}( preemption_scope * this ) { 240 disable_interrupts(); 241 99 242 update_preemption( this->proc, 0 ); 100 243 } 101 244 102 245 //============================================================================================= 103 // Kernel Signal logic 104 //============================================================================================= 105 106 static inline bool preemption_ready() { 107 return this_processor->disable_preempt_count == 0; 108 } 109 110 static inline void defer_ctxSwitch() { 111 this_processor->pending_preemption = true; 112 } 113 114 static inline void defer_alarm() { 115 systemProcessor->pending_alarm = true; 116 } 117 118 void sigHandler_ctxSwitch( __attribute__((unused)) int sig ) { 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]); ) 119 251 if( preemption_ready() ) { 120 ScheduleInternal( this_processor->current_thread ); 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 ); 121 257 } 122 258 else { … … 125 261 } 126 262 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 137 static void preempt( processor * this ) { 138 pthread_kill( this->kernel_thread, SIGUSR1 ); 139 } 140 141 static void timeout( thread_desc * this ) { 142 //TODO : implement waking threads 143 } 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.