Changeset 33218c6 for src/libcfa/concurrency/preemption.c
- Timestamp:
- Jul 26, 2017, 12:19:41 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:
- b947fb2
- Parents:
- e0a653d (diff), ea91c42 (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
re0a653d r33218c6 1 // -*- Mode: CFA -*-2 1 // 3 2 // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo … … 10 9 // Author : Thierry Delisle 11 10 // Created On : Mon Jun 5 14:20:42 2017 12 // Last Modified By : Thierry Delisle13 // Last Modified On : --14 // Update Count : 011 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jul 21 22:36:05 2017 13 // Update Count : 2 15 14 // 16 15 … … 34 33 #endif 35 34 35 //TODO move to defaults 36 36 #define __CFA_DEFAULT_PREEMPTION__ 10000 37 37 38 //TODO move to defaults 38 39 __attribute__((weak)) unsigned int default_preemption() { 39 40 return __CFA_DEFAULT_PREEMPTION__; 40 41 } 41 42 43 // Short hands for signal context information 42 44 #define __CFA_SIGCXT__ ucontext_t * 43 45 #define __CFA_SIGPARMS__ __attribute__((unused)) int sig, __attribute__((unused)) siginfo_t *sfp, __attribute__((unused)) __CFA_SIGCXT__ cxt 44 46 47 // FwdDeclarations : timeout handlers 45 48 static void preempt( processor * this ); 46 49 static void timeout( thread_desc * this ); 47 50 51 // FwdDeclarations : Signal handlers 48 52 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ); 49 void sigHandler_alarm ( __CFA_SIGPARMS__ );50 53 void sigHandler_segv ( __CFA_SIGPARMS__ ); 51 54 void sigHandler_abort ( __CFA_SIGPARMS__ ); 52 55 56 // FwdDeclarations : sigaction wrapper 53 57 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ); 54 LIB_DEBUG_DO( bool validate( alarm_list_t * this ); ) 55 58 59 // FwdDeclarations : alarm thread main 60 void * alarm_loop( __attribute__((unused)) void * args ); 61 62 // Machine specific register name 56 63 #ifdef __x86_64__ 57 64 #define CFA_REG_IP REG_RIP … … 60 67 #endif 61 68 69 KERNEL_STORAGE(event_kernel_t, event_kernel); // private storage for event kernel 70 event_kernel_t * event_kernel; // kernel public handle to even kernel 71 static pthread_t alarm_thread; // pthread handle to alarm thread 72 73 void ?{}(event_kernel_t * this) { 74 (&this->alarms){}; 75 (&this->lock){}; 76 } 62 77 63 78 //============================================================================================= … … 65 80 //============================================================================================= 66 81 82 // Get next expired node 83 static inline alarm_node_t * get_expired( alarm_list_t * alarms, __cfa_time_t currtime ) { 84 if( !alarms->head ) return NULL; // If no alarms return null 85 if( alarms->head->alarm >= currtime ) return NULL; // If alarms head not expired return null 86 return pop(alarms); // Otherwise just pop head 87 } 88 89 // Tick one frame of the Discrete Event Simulation for alarms 67 90 void tick_preemption() { 68 // LIB_DEBUG_PRINT_BUFFER_DECL( STDERR_FILENO, "Ticking preemption\n" );69 70 alarm_list_t * alarms = &systemProcessor->alarms;71 __cfa_time_t currtime = __kernel_get_time(); 72 while( alarms->head && alarms->head->alarm < currtime ) {73 alarm_node_t * node = pop(alarms);74 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking %p\n", node ); 75 91 alarm_node_t * node = NULL; // Used in the while loop but cannot be declared in the while condition 92 alarm_list_t * alarms = &event_kernel->alarms; // Local copy for ease of reading 93 __cfa_time_t currtime = __kernel_get_time(); // Check current time once so we everything "happens at once" 94 95 //Loop throught every thing expired 96 while( node = get_expired( alarms, currtime ) ) { 97 98 // Check if this is a kernel 76 99 if( node->kernel_alarm ) { 77 100 preempt( node->proc ); … … 81 104 } 82 105 83 verify( validate( alarms ) );84 85 if( node->period > 0 ) {86 node->alarm = currtime + node->period;87 insert( alarms, node ); 106 // Check if this is a periodic alarm 107 __cfa_time_t period = node->period; 108 if( period > 0 ) { 109 node->alarm = currtime + period; // Alarm is periodic, add currtime to it (used cached current time) 110 insert( alarms, node ); // Reinsert the node for the next time it triggers 88 111 } 89 112 else { 90 node->set = false; 91 } 92 } 93 94 if( alarms->head ) { 95 __kernel_set_timer( alarms->head->alarm - currtime ); 96 } 97 98 verify( validate( alarms ) ); 99 // LIB_DEBUG_PRINT_BUFFER_LOCAL( STDERR_FILENO, "Ticking preemption done\n" ); 100 } 101 113 node->set = false; // Node is one-shot, just mark it as not pending 114 } 115 } 116 117 // If there are still alarms pending, reset the timer 118 if( alarms->head ) { __kernel_set_timer( alarms->head->alarm - currtime ); } 119 } 120 121 // Update the preemption of a processor and notify interested parties 102 122 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 105 123 alarm_node_t * alarm = this->preemption_alarm; 106 duration *= 1000;107 124 108 125 // Alarms need to be enabled … … 134 151 135 152 extern "C" { 153 // Disable interrupts by incrementing the counter 136 154 void disable_interrupts() { 137 155 __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 156 verify( new_val < 65_000u ); // If this triggers someone is disabling interrupts without enabling them 157 } 158 159 // Enable interrupts by decrementing the counter 160 // If counter reaches 0, execute any pending CtxSwitch 147 161 void enable_interrupts( DEBUG_CTX_PARAM ) { 148 processor * proc = this_processor; 149 thread_desc * thrd = this_thread; 162 processor * proc = this_processor; // Cache the processor now since interrupts can start happening after the atomic add 163 thread_desc * thrd = this_thread; // Cache the thread now since interrupts can start happening after the atomic add 164 150 165 unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST ); 151 verify( prev != (unsigned short) 0 ); 166 verify( prev != 0u ); // If this triggers someone is enabled already enabled interruptsverify( prev != 0u ); 167 168 // Check if we need to prempt the thread because an interrupt was missed 152 169 if( prev == 1 && proc->pending_preemption ) { 153 170 proc->pending_preemption = false; … … 155 172 } 156 173 174 // For debugging purposes : keep track of the last person to enable the interrupts 157 175 LIB_DEBUG_DO( proc->last_enable = caller; ) 158 176 } 159 } 160 177 178 // Disable interrupts by incrementint the counter 179 // Don't execute any pending CtxSwitch even if counter reaches 0 180 void enable_interrupts_noPoll() { 181 __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &disable_preempt_count, -1, __ATOMIC_SEQ_CST ); 182 verify( prev != 0u ); // If this triggers someone is enabled already enabled interrupts 183 } 184 } 185 186 // sigprocmask wrapper : unblock a single signal 161 187 static inline void signal_unblock( int sig ) { 162 188 sigset_t mask; … … 169 195 } 170 196 197 // sigprocmask wrapper : block a single signal 171 198 static inline void signal_block( int sig ) { 172 199 sigset_t mask; … … 179 206 } 180 207 181 static inline bool preemption_ready() { 182 return disable_preempt_count == 0; 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 208 // kill wrapper : signal a processor 193 209 static void preempt( processor * this ) { 194 210 pthread_kill( this->kernel_thread, SIGUSR1 ); 195 211 } 196 212 213 // reserved for future use 197 214 static void timeout( thread_desc * this ) { 198 215 //TODO : implement waking threads 199 216 } 200 217 218 219 // Check if a CtxSwitch signal handler shoud defer 220 // If true : preemption is safe 221 // If false : preemption is unsafe and marked as pending 222 static inline bool preemption_ready() { 223 bool ready = disable_preempt_count == 0 && !preemption_in_progress; // Check if preemption is safe 224 this_processor->pending_preemption = !ready; // Adjust the pending flag accordingly 225 return ready; 226 } 227 201 228 //============================================================================================= 202 229 // Kernel Signal Startup/Shutdown logic 203 230 //============================================================================================= 204 231 205 static pthread_t alarm_thread; 206 void * alarm_loop( __attribute__((unused)) void * args ); 207 232 // Startup routine to activate preemption 233 // Called from kernel_startup 208 234 void kernel_start_preemption() { 209 235 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 ); 236 237 // Start with preemption disabled until ready 238 disable_preempt_count = 1; 239 240 // Initialize the event kernel 241 event_kernel = (event_kernel_t *)&storage_event_kernel; 242 event_kernel{}; 243 244 // Setup proper signal handlers 245 __kernel_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO ); // CtxSwitch handler 246 // __kernel_sigaction( SIGSEGV, sigHandler_segv , SA_SIGINFO ); // Failure handler 247 // __kernel_sigaction( SIGBUS , sigHandler_segv , SA_SIGINFO ); // Failure handler 213 248 214 249 signal_block( SIGALRM ); … … 217 252 } 218 253 254 // Shutdown routine to deactivate preemption 255 // Called from kernel_shutdown 219 256 void kernel_stop_preemption() { 257 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopping\n"); 258 259 // Block all signals since we are already shutting down 220 260 sigset_t mask; 221 261 sigfillset( &mask ); 222 262 sigprocmask( SIG_BLOCK, &mask, NULL ); 223 263 224 pthread_kill( alarm_thread, SIGINT ); 264 // Notify the alarm thread of the shutdown 265 sigval val = { 1 }; 266 pthread_sigqueue( alarm_thread, SIGALRM, val ); 267 268 // Wait for the preemption thread to finish 225 269 pthread_join( alarm_thread, NULL ); 270 271 // Preemption is now fully stopped 272 226 273 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption stopped\n"); 227 274 } 228 275 276 // Raii ctor/dtor for the preemption_scope 277 // Used by thread to control when they want to receive preemption signals 229 278 void ?{}( preemption_scope * this, processor * proc ) { 230 (&this->alarm){ proc };279 (&this->alarm){ proc, zero_time, zero_time }; 231 280 this->proc = proc; 232 281 this->proc->preemption_alarm = &this->alarm; 233 update_preemption( this->proc, this->proc->preemption ); 282 283 update_preemption( this->proc, from_us(this->proc->cltr->preemption) ); 234 284 } 235 285 … … 237 287 disable_interrupts(); 238 288 239 update_preemption( this->proc, 0);289 update_preemption( this->proc, zero_time ); 240 290 } 241 291 … … 244 294 //============================================================================================= 245 295 296 // Context switch signal handler 297 // Receives SIGUSR1 signal and causes the current thread to yield 246 298 void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) { 247 299 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 300 301 // Check if it is safe to preempt here 302 if( !preemption_ready() ) { return; } 303 304 preemption_in_progress = true; // Sync flag : prevent recursive calls to the signal handler 305 signal_unblock( SIGUSR1 ); // We are about to CtxSwitch out of the signal handler, let other handlers in 306 preemption_in_progress = false; // Clear the in progress flag 307 308 // Preemption can occur here 309 310 BlockInternal( (thread_desc*)this_thread ); // Do the actual CtxSwitch 311 } 312 313 // Main of the alarm thread 314 // Waits on SIGALRM and send SIGUSR1 to whom ever needs it 279 315 void * alarm_loop( __attribute__((unused)) void * args ) { 316 // Block sigalrms to control when they arrive 280 317 sigset_t mask; 281 318 sigemptyset( &mask ); 282 319 sigaddset( &mask, SIGALRM ); 283 sigaddset( &mask, SIGUSR2 );284 sigaddset( &mask, SIGINT );285 320 286 321 if ( pthread_sigmask( SIG_BLOCK, &mask, NULL ) == -1 ) { … … 288 323 } 289 324 325 // Main loop 290 326 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 327 // Wait for a sigalrm 328 siginfo_t info; 329 int sig = sigwaitinfo( &mask, &info ); 330 331 // If another signal arrived something went wrong 332 assertf(sig == SIGALRM, "Kernel Internal Error, sigwait: Unexpected signal %d (%d : %d)\n", sig, info.si_code, info.si_value.sival_int); 333 334 LIB_DEBUG_PRINT_SAFE("Kernel : Caught alarm from %d with %d\n", info.si_code, info.si_value.sival_int ); 335 // Switch on the code (a.k.a. the sender) to 336 switch( info.si_code ) 337 { 338 // Timers can apparently be marked as sent for the kernel 339 // In either case, tick preemption 340 case SI_TIMER: 341 case SI_KERNEL: 342 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption thread tick\n"); 343 lock( &event_kernel->lock DEBUG_CTX2 ); 344 tick_preemption(); 345 unlock( &event_kernel->lock ); 346 break; 347 // Signal was not sent by the kernel but by an other thread 348 case SI_QUEUE: 349 // For now, other thread only signal the alarm thread to shut it down 350 // If this needs to change use info.si_value and handle the case here 351 goto EXIT; 352 } 353 } 354 355 EXIT: 356 LIB_DEBUG_PRINT_SAFE("Kernel : Preemption thread stopping\n"); 357 return NULL; 358 } 359 360 // Sigaction wrapper : register an signal handler 316 361 static void __kernel_sigaction( int sig, void (*handler)(__CFA_SIGPARMS__), int flags ) { 317 362 struct sigaction act; … … 329 374 } 330 375 331 typedef void (*sa_handler_t)(int); 332 376 // Sigaction wrapper : restore default handler 333 377 static void __kernel_sigdefault( int sig ) { 334 378 struct sigaction act; 335 379 336 //act.sa_handler = SIG_DFL;380 act.sa_handler = SIG_DFL; 337 381 act.sa_flags = 0; 338 382 sigemptyset( &act.sa_mask ); … … 442 486 // raise( SIGABRT ); 443 487 // } 488 489 // Local Variables: // 490 // mode: c // 491 // tab-width: 4 // 492 // End: //
Note:
See TracChangeset
for help on using the changeset viewer.