- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/preemption.cfa
r5a05946 r6b33e89 10 10 // Created On : Mon Jun 5 14:20:42 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 9 08:42:59 202313 // Update Count : 6 012 // Last Modified On : Fri Apr 25 07:24:39 2025 13 // Update Count : 63 14 14 // 15 15 … … 39 39 __attribute__((weak)) Duration default_preemption() libcfa_public { 40 40 const char * preempt_rate_s = getenv("CFA_DEFAULT_PREEMPTION"); 41 if (!preempt_rate_s) {41 if ( !preempt_rate_s) { 42 42 __cfadbg_print_safe(preemption, "No CFA_DEFAULT_PREEMPTION in ENV\n"); 43 43 return __CFA_DEFAULT_PREEMPTION__; … … 46 46 char * endptr = 0p; 47 47 long int preempt_rate_l = strtol(preempt_rate_s, &endptr, 10); 48 if (preempt_rate_l < 0 || preempt_rate_l > 65535) {48 if (preempt_rate_l < 0 || preempt_rate_l > 65535) { 49 49 __cfadbg_print_safe(preemption, "CFA_DEFAULT_PREEMPTION out of range : %ld\n", preempt_rate_l); 50 50 return __CFA_DEFAULT_PREEMPTION__; 51 51 } 52 if ('\0' != *endptr) {52 if ('\0' != *endptr) { 53 53 __cfadbg_print_safe(preemption, "CFA_DEFAULT_PREEMPTION not a decimal number : %s\n", preempt_rate_s); 54 54 return __CFA_DEFAULT_PREEMPTION__; … … 64 64 // FwdDeclarations : Signal handlers 65 65 static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ); 66 static void sigHandler_alarm 67 static void sigHandler_segv 68 static void sigHandler_ill 69 static void sigHandler_fpe 70 static void sigHandler_abort 66 static void sigHandler_alarm( __CFA_SIGPARMS__ ); 67 static void sigHandler_segv( __CFA_SIGPARMS__ ); 68 static void sigHandler_ill( __CFA_SIGPARMS__ ); 69 static void sigHandler_fpe( __CFA_SIGPARMS__ ); 70 static void sigHandler_abort( __CFA_SIGPARMS__ ); 71 71 72 72 // FwdDeclarations : alarm thread main … … 86 86 #endif 87 87 88 KERNEL_STORAGE(event_kernel_t, event_kernel); 89 event_kernel_t * event_kernel; 90 static pthread_t alarm_thread; 91 static void * alarm_stack; 88 KERNEL_STORAGE(event_kernel_t, event_kernel); // private storage for event kernel 89 event_kernel_t * event_kernel; // kernel public handle to even kernel 90 static pthread_t alarm_thread; // pthread handle to alarm thread 91 static void * alarm_stack; // pthread stack for alarm thread 92 92 93 93 static void ?{}(event_kernel_t & this) with( this ) { … … 102 102 // Get next expired node 103 103 static inline alarm_node_t * get_expired( alarm_list_t * alarms, Time currtime ) { 104 if ( ! & (*alarms)`first ) return 0p;// If no alarms return null105 if ( (*alarms)`first.deadline >= currtime ) return 0p;// If alarms head not expired return null106 return pop(alarms); // Otherwise just pop head104 if ( ! & first( *alarms ) ) return 0p; // If no alarms return null 105 if ( first( *alarms ).deadline >= currtime ) return 0p; // If alarms head not expired return null 106 return pop(alarms); // Otherwise just pop head 107 107 } 108 108 … … 117 117 __cfadbg_print_buffer_decl( preemption, " KERNEL: preemption tick %lu\n", currtime.tn); 118 118 Duration period = node->period; 119 if ( period == 0 ) {120 node->set = false; 119 if ( period == 0 ) { 120 node->set = false; // Node is one-shot, just mark it as not pending 121 121 } 122 122 … … 125 125 126 126 // Check if this is a kernel 127 if ( node->type == Kernel ) {127 if ( node->type == Kernel ) { 128 128 preempt( node->proc ); 129 129 } 130 else if ( node->type == User ) {130 else if ( node->type == User ) { 131 131 __cfadbg_print_buffer_local( preemption, " KERNEL: alarm unparking %p.\n", node->thrd ); 132 132 timeout( node->thrd ); … … 137 137 138 138 // Check if this is a periodic alarm 139 if ( period > 0 ) {139 if ( period > 0 ) { 140 140 __cfadbg_print_buffer_local( preemption, " KERNEL: alarm period is %lu.\n", period`ns ); 141 141 node->deadline = currtime + period; // Alarm is periodic, add currtime to it (used cached current time) 142 insert( alarms, node ); 142 insert( alarms, node ); // Reinsert the node for the next time it triggers 143 143 } 144 144 } 145 145 146 146 // If there are still alarms pending, reset the timer 147 if ( & (*alarms)`first) {148 Duration delta = (*alarms)`first.deadline - currtime;147 if ( & first( *alarms ) ) { 148 Duration delta = first( *alarms ).deadline - currtime; 149 149 __kernel_set_timer( delta ); 150 150 } … … 283 283 __attribute__((unused)) unsigned short new_val = disable_count + 1; 284 284 disable_count = new_val; 285 verify( new_val < 65_000u ); 285 verify( new_val < 65_000u ); // If this triggers someone is disabling interrupts without enabling them 286 286 } 287 287 … … 301 301 302 302 // Check if we need to prempt the thread because an interrupt was missed 303 if ( prev == 1 ) {303 if ( prev == 1 ) { 304 304 #if GCC_VERSION > 50000 305 305 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free"); … … 313 313 // Signal the compiler that a fence is needed but only for signal handlers 314 314 __atomic_signal_fence(__ATOMIC_RELEASE); 315 if ( poll && proc->pending_preemption ) {315 if ( poll && proc->pending_preemption ) { 316 316 proc->pending_preemption = false; 317 317 force_yield( __POLL_PREEMPTION ); … … 334 334 // Signal the compiler that a fence is needed but only for signal handlers 335 335 __atomic_signal_fence(__ATOMIC_RELEASE); 336 if ( unlikely( proc->pending_preemption ) ) {336 if ( unlikely( proc->pending_preemption ) ) { 337 337 proc->pending_preemption = false; 338 338 force_yield( __POLL_PREEMPTION ); … … 347 347 void __cfaabi_check_preemption() libcfa_public { 348 348 bool ready = __preemption_enabled(); 349 if (!ready) { abort("Preemption should be ready"); }349 if ( !ready) { abort("Preemption should be ready"); } 350 350 351 351 sigset_t oldset; 352 352 int ret; 353 353 ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary 354 if (ret != 0) { abort("ERROR sigprocmask returned %d", ret); }354 if (ret != 0) { abort("ERROR sigprocmask returned %d", ret); } 355 355 356 356 ret = sigismember(&oldset, SIGUSR1); 357 if (ret < 0) { abort("ERROR sigismember returned %d", ret); }358 if (ret == 1) { abort("ERROR SIGUSR1 is disabled"); }357 if (ret < 0) { abort("ERROR sigismember returned %d", ret); } 358 if (ret == 1) { abort("ERROR SIGUSR1 is disabled"); } 359 359 360 360 ret = sigismember(&oldset, SIGALRM); 361 if (ret < 0) { abort("ERROR sigismember returned %d", ret); }362 if (ret == 0) { abort("ERROR SIGALRM is enabled"); }361 if (ret < 0) { abort("ERROR sigismember returned %d", ret); } 362 if (ret == 0) { abort("ERROR SIGALRM is enabled"); } 363 363 364 364 ret = sigismember(&oldset, SIGTERM); 365 if (ret < 0) { abort("ERROR sigismember returned %d", ret); }366 if (ret == 1) { abort("ERROR SIGTERM is disabled"); }365 if (ret < 0) { abort("ERROR sigismember returned %d", ret); } 366 if (ret == 1) { abort("ERROR SIGTERM is disabled"); } 367 367 } 368 368 … … 385 385 386 386 if ( __cfaabi_pthread_sigmask( SIG_UNBLOCK, &mask, 0p ) == -1 ) { 387 387 abort( "internal error, pthread_sigmask" ); 388 388 } 389 389 } … … 415 415 int ret; 416 416 ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary 417 if (ret != 0) { abort("ERROR sigprocmask returned %d", ret); }417 if (ret != 0) { abort("ERROR sigprocmask returned %d", ret); } 418 418 419 419 ret = sigismember(&oldset, SIGUSR1); 420 if (ret < 0) { abort("ERROR sigismember returned %d", ret); }421 if (ret == 1) { abort("ERROR SIGUSR1 is disabled"); }420 if (ret < 0) { abort("ERROR sigismember returned %d", ret); } 421 if (ret == 1) { abort("ERROR SIGUSR1 is disabled"); } 422 422 423 423 ret = sigismember(&oldset, SIGALRM); 424 if (ret < 0) { abort("ERROR sigismember returned %d", ret); }425 if (ret == 0) { abort("ERROR SIGALRM is enabled"); }424 if (ret < 0) { abort("ERROR sigismember returned %d", ret); } 425 if (ret == 0) { abort("ERROR SIGALRM is enabled"); } 426 426 427 427 signal_block( SIGUSR1 ); … … 434 434 int ret; 435 435 ret = __cfaabi_pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary 436 if (ret != 0) { abort("ERROR sigprocmask returned %d", ret); }436 if (ret != 0) { abort("ERROR sigprocmask returned %d", ret); } 437 437 438 438 ret = sigismember(&oldset, SIGUSR1); 439 if (ret < 0) { abort("ERROR sigismember returned %d", ret); }440 if (ret == 1) { abort("ERROR SIGUSR1 is disabled"); }439 if (ret < 0) { abort("ERROR sigismember returned %d", ret); } 440 if (ret == 1) { abort("ERROR SIGUSR1 is disabled"); } 441 441 442 442 ret = sigismember(&oldset, SIGALRM); 443 if (ret < 0) { abort("ERROR sigismember returned %d", ret); }444 if (ret == 0) { abort("ERROR SIGALRM is enabled"); }443 if (ret < 0) { abort("ERROR sigismember returned %d", ret); } 444 if (ret == 0) { abort("ERROR SIGALRM is enabled"); } 445 445 } 446 446 … … 453 453 // Check if preemption is safe 454 454 bool ready = true; 455 if ( __cfaabi_in( ip, __libcfa_nopreempt ) ) { ready = false; goto EXIT; };456 if ( __cfaabi_in( ip, __libcfathrd_nopreempt ) ) { ready = false; goto EXIT; };457 458 if ( !__cfaabi_tls.preemption_state.enabled) { ready = false; goto EXIT; };459 if ( __cfaabi_tls.preemption_state.in_progress ) { ready = false; goto EXIT; };455 if ( __cfaabi_in( ip, __libcfa_nopreempt ) ) { ready = false; goto EXIT; }; 456 if ( __cfaabi_in( ip, __libcfathrd_nopreempt ) ) { ready = false; goto EXIT; }; 457 458 if ( !__cfaabi_tls.preemption_state.enabled) { ready = false; goto EXIT; }; 459 if ( __cfaabi_tls.preemption_state.in_progress ) { ready = false; goto EXIT; }; 460 460 461 461 EXIT: … … 484 484 // Setup proper signal handlers 485 485 __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO ); // __cfactx_switch handler 486 __cfaabi_sigaction( SIGALRM, sigHandler_alarm 486 __cfaabi_sigaction( SIGALRM, sigHandler_alarm , SA_SIGINFO ); // debug handler 487 487 488 488 signal_block( SIGALRM ); … … 551 551 // before the kernel thread has even started running. When that happens, an interrupt 552 552 // with a null 'this_processor' will be caught, just ignore it. 553 if (! __cfaabi_tls.this_processor ) return;553 if ( ! __cfaabi_tls.this_processor ) return; 554 554 555 555 choose(sfp->si_value.sival_int) { 556 case PREEMPT_NORMAL : ;// Normal case, nothing to do here557 case PREEMPT_IO : ;// I/O asked to stop spinning, nothing to do here556 case PREEMPT_NORMAL: ; // Normal case, nothing to do here 557 case PREEMPT_IO: ; // I/O asked to stop spinning, nothing to do here 558 558 case PREEMPT_TERMINATE: verify( __atomic_load_n( &__cfaabi_tls.this_processor->do_terminate, __ATOMIC_SEQ_CST ) ); 559 559 default: … … 562 562 563 563 // Check if it is safe to preempt here 564 if ( !preemption_ready( ip ) ) {564 if ( !preemption_ready( ip ) ) { 565 565 #if !defined(__CFA_NO_STATISTICS__) 566 566 __cfaabi_tls.this_stats->ready.threads.preempt.rllfwd++; … … 607 607 sigfillset(&mask); 608 608 if ( __cfaabi_pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) { 609 609 abort( "internal error, pthread_sigmask" ); 610 610 } 611 611 … … 622 622 __cfadbg_print_buffer_local( preemption, " KERNEL: SI_QUEUE %d, SI_TIMER %d, SI_KERNEL %d\n", SI_QUEUE, SI_TIMER, SI_KERNEL ); 623 623 624 if ( sig < 0 ) {624 if ( sig < 0 ) { 625 625 //Error! 626 626 int err = errno;
Note:
See TracChangeset
for help on using the changeset viewer.