- File:
-
- 1 edited
-
libcfa/src/concurrency/preemption.cfa (modified) (24 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/preemption.cfa
rbfcf6b9 r09d4b22 10 10 // Created On : Mon Jun 5 14:20:42 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Nov 6 07:42:13 202013 // Update Count : 5412 // Last Modified On : Thu Dec 5 16:34:05 2019 13 // Update Count : 43 14 14 // 15 15 … … 19 19 #include <assert.h> 20 20 21 extern "C" { 21 22 #include <errno.h> 22 23 #include <stdio.h> … … 24 25 #include <unistd.h> 25 26 #include <limits.h> // PTHREAD_STACK_MIN 27 } 26 28 27 29 #include "bits/signal.hfa" 28 #include "kernel_private.hfa"29 30 30 31 #if !defined(__CFA_DEFAULT_PREEMPTION__) … … 38 39 // FwdDeclarations : timeout handlers 39 40 static void preempt( processor * this ); 40 static void timeout( $thread* this );41 static void timeout( thread_desc * this ); 41 42 42 43 // FwdDeclarations : Signal handlers 43 44 static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ); 44 static void sigHandler_alarm ( __CFA_SIGPARMS__ );45 45 static void sigHandler_segv ( __CFA_SIGPARMS__ ); 46 46 static void sigHandler_ill ( __CFA_SIGPARMS__ ); … … 56 56 #elif defined( __x86_64 ) 57 57 #define CFA_REG_IP gregs[REG_RIP] 58 #elif defined( __ arm__)58 #elif defined( __ARM_ARCH ) 59 59 #define CFA_REG_IP arm_pc 60 #elif defined( __aarch64__ )61 #define CFA_REG_IP pc62 60 #else 63 #error un supportedhardware architecture61 #error unknown hardware architecture 64 62 #endif 65 63 … … 85 83 // Get next expired node 86 84 static inline alarm_node_t * get_expired( alarm_list_t * alarms, Time currtime ) { 87 if( ! & (*alarms)`first) return 0p; // If no alarms return null88 if( (*alarms)`first.alarm >= currtime ) return 0p; // If alarms head not expired return null85 if( !alarms->head ) return 0p; // If no alarms return null 86 if( alarms->head->alarm >= currtime ) return 0p; // If alarms head not expired return null 89 87 return pop(alarms); // Otherwise just pop head 90 88 } 91 89 92 90 // Tick one frame of the Discrete Event Simulation for alarms 93 static void tick_preemption( void) {91 static void tick_preemption() { 94 92 alarm_node_t * node = 0p; // Used in the while loop but cannot be declared in the while condition 95 93 alarm_list_t * alarms = &event_kernel->alarms; // Local copy for ease of reading … … 99 97 while( node = get_expired( alarms, currtime ) ) { 100 98 // __cfaabi_dbg_print_buffer_decl( " KERNEL: preemption tick.\n" ); 99 100 // Check if this is a kernel 101 if( node->kernel_alarm ) { 102 preempt( node->proc ); 103 } 104 else { 105 timeout( node->thrd ); 106 } 107 108 // Check if this is a periodic alarm 101 109 Duration period = node->period; 102 if( period == 0) {103 node->set = false; // Node is one-shot, just mark it as not pending104 }105 106 // Check if this is a kernel107 if( node->type == Kernel ) {108 preempt( node->proc );109 }110 else if( node->type == User ) {111 timeout( node->thrd );112 }113 else {114 node->callback(*node);115 }116 117 // Check if this is a periodic alarm118 110 if( period > 0 ) { 119 111 // __cfaabi_dbg_print_buffer_local( " KERNEL: alarm period is %lu.\n", period.tv ); … … 121 113 insert( alarms, node ); // Reinsert the node for the next time it triggers 122 114 } 115 else { 116 node->set = false; // Node is one-shot, just mark it as not pending 117 } 123 118 } 124 119 125 120 // If there are still alarms pending, reset the timer 126 if( & (*alarms)`first) {127 __cfa dbg_print_buffer_decl(preemption," KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);128 Duration delta = (*alarms)`first.alarm - currtime;129 Duration cap ped = max(delta, 50`us);121 if( alarms->head ) { 122 __cfaabi_dbg_print_buffer_decl( " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv); 123 Duration delta = alarms->head->alarm - currtime; 124 Duration caped = max(delta, 50`us); 130 125 // itimerval tim = { caped }; 131 126 // __cfaabi_dbg_print_buffer_local( " Values are %lu, %lu, %lu %lu.\n", delta.tv, caped.tv, tim.it_value.tv_sec, tim.it_value.tv_usec); 132 127 133 __kernel_set_timer( cap ped );128 __kernel_set_timer( caped ); 134 129 } 135 130 } … … 163 158 // Kernel Signal Tools 164 159 //============================================================================================= 165 // In a user-level threading system, there are handful of thread-local variables where this problem occurs on the ARM. 166 // 167 // For each kernel thread running user-level threads, there is a flag variable to indicate if interrupts are 168 // enabled/disabled for that kernel thread. Therefore, this variable is made thread local. 169 // 170 // For example, this code fragment sets the state of the "interrupt" variable in thread-local memory. 171 // 172 // _Thread_local volatile int interrupts; 173 // int main() { 174 // interrupts = 0; // disable interrupts } 175 // 176 // which generates the following code on the ARM 177 // 178 // (gdb) disassemble main 179 // Dump of assembler code for function main: 180 // 0x0000000000000610 <+0>: mrs x1, tpidr_el0 181 // 0x0000000000000614 <+4>: mov w0, #0x0 // #0 182 // 0x0000000000000618 <+8>: add x1, x1, #0x0, lsl #12 183 // 0x000000000000061c <+12>: add x1, x1, #0x10 184 // 0x0000000000000620 <+16>: str wzr, [x1] 185 // 0x0000000000000624 <+20>: ret 186 // 187 // The mrs moves a pointer from coprocessor register tpidr_el0 into register x1. Register w0 is set to 0. The two adds 188 // increase the TLS pointer with the displacement (offset) 0x10, which is the location in the TSL of variable 189 // "interrupts". Finally, 0 is stored into "interrupts" through the pointer in register x1 that points into the 190 // TSL. Now once x1 has the pointer to the location of the TSL for kernel thread N, it can be be preempted at a 191 // user-level and the user thread is put on the user-level ready-queue. When the preempted thread gets to the front of 192 // the user-level ready-queue it is run on kernel thread M. It now stores 0 into "interrupts" back on kernel thread N, 193 // turning off interrupt on the wrong kernel thread. 194 // 195 // On the x86, the following code is generated for the same code fragment. 196 // 197 // (gdb) disassemble main 198 // Dump of assembler code for function main: 199 // 0x0000000000400420 <+0>: movl $0x0,%fs:0xfffffffffffffffc 200 // 0x000000000040042c <+12>: xor %eax,%eax 201 // 0x000000000040042e <+14>: retq 202 // 203 // and there is base-displacement addressing used to atomically reset variable "interrupts" off of the TSL pointer in 204 // register "fs". 205 // 206 // Hence, the ARM has base-displacement address for the general purpose registers, BUT not to the coprocessor 207 // registers. As a result, generating the address for the write into variable "interrupts" is no longer atomic. 208 // 209 // Note this problem does NOT occur when just using multiple kernel threads because the preemption ALWAYS restarts the 210 // thread on the same kernel thread. 211 // 212 // The obvious question is why does ARM use a coprocessor register to store the TSL pointer given that coprocessor 213 // registers are second-class registers with respect to the instruction set. One possible answer is that they did not 214 // want to dedicate one of the general registers to hold the TLS pointer and there was a free coprocessor register 215 // available. 216 217 //----------------------------------------------------------------------------- 218 // Some assembly required 219 #define __cfaasm_label(label, when) when: asm volatile goto(".global __cfaasm_" #label "_" #when "\n" "__cfaasm_" #label "_" #when ":":::"memory":when) 220 221 //---------- 222 // special case for preemption since used often 223 bool __preemption_enabled() { 224 // create a assembler label before 225 // marked as clobber all to avoid movement 226 __cfaasm_label(check, before); 227 228 // access tls as normal 229 bool enabled = __cfaabi_tls.preemption_state.enabled; 230 231 // create a assembler label after 232 // marked as clobber all to avoid movement 233 __cfaasm_label(check, after); 234 return enabled; 235 } 236 237 struct asm_region { 238 void * before; 239 void * after; 240 }; 241 242 static inline bool __cfaasm_in( void * ip, struct asm_region & region ) { 243 return ip >= region.before && ip <= region.after; 244 } 245 246 247 //---------- 248 // Get data from the TLS block 249 // struct asm_region __cfaasm_get; 250 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems 251 uintptr_t __cfatls_get( unsigned long int offset ) { 252 // create a assembler label before 253 // marked as clobber all to avoid movement 254 __cfaasm_label(get, before); 255 256 // access tls as normal (except for pointer arithmetic) 257 uintptr_t val = *(uintptr_t*)((uintptr_t)&__cfaabi_tls + offset); 258 259 // create a assembler label after 260 // marked as clobber all to avoid movement 261 __cfaasm_label(get, after); 262 return val; 263 } 160 161 __cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; ) 264 162 265 163 extern "C" { 266 164 // Disable interrupts by incrementing the counter 267 165 void disable_interrupts() { 268 // create a assembler label before 269 // marked as clobber all to avoid movement 270 __cfaasm_label(dsable, before); 271 272 with( __cfaabi_tls.preemption_state ) { 166 with( kernelTLS.preemption_state ) { 273 167 #if GCC_VERSION > 50000 274 168 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free"); … … 287 181 verify( new_val < 65_000u ); // If this triggers someone is disabling interrupts without enabling them 288 182 } 289 290 // create a assembler label after291 // marked as clobber all to avoid movement292 __cfaasm_label(dsable, after);293 294 183 } 295 184 296 185 // Enable interrupts by decrementing the counter 297 // If counter reaches 0, execute any pending __cfactx_switch186 // If counter reaches 0, execute any pending CtxSwitch 298 187 void enable_interrupts( __cfaabi_dbg_ctx_param ) { 299 // Cache the processor now since interrupts can start happening after the atomic store 300 processor * proc = __cfaabi_tls.this_processor; 301 /* paranoid */ verify( proc ); 302 303 with( __cfaabi_tls.preemption_state ){ 188 processor * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic store 189 thread_desc * thrd = kernelTLS.this_thread; // Cache the thread now since interrupts can start happening after the atomic store 190 191 with( kernelTLS.preemption_state ){ 304 192 unsigned short prev = disable_count; 305 193 disable_count -= 1; 306 307 // If this triggers someone is enabled already enabled interruptsverify( prev != 0u ); 308 /* paranoid */ verify( prev != 0u ); 194 verify( prev != 0u ); // If this triggers someone is enabled already enabled interruptsverify( prev != 0u ); 309 195 310 196 // Check if we need to prempt the thread because an interrupt was missed 311 197 if( prev == 1 ) { 312 198 #if GCC_VERSION > 50000 313 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");199 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free"); 314 200 #endif 315 201 … … 323 209 if( proc->pending_preemption ) { 324 210 proc->pending_preemption = false; 325 force_yield( __POLL_PREEMPTION);211 BlockInternal( thrd ); 326 212 } 327 213 } … … 333 219 334 220 // Disable interrupts by incrementint the counter 335 // Don't execute any pending __cfactx_switch even if counter reaches 0221 // Don't execute any pending CtxSwitch even if counter reaches 0 336 222 void enable_interrupts_noPoll() { 337 unsigned short prev = __cfaabi_tls.preemption_state.disable_count; 338 __cfaabi_tls.preemption_state.disable_count -= 1; 339 // If this triggers someone is enabled already enabled interrupts 340 /* paranoid */ verifyf( prev != 0u, "Incremented from %u\n", prev ); 223 unsigned short prev = kernelTLS.preemption_state.disable_count; 224 kernelTLS.preemption_state.disable_count -= 1; 225 verifyf( prev != 0u, "Incremented from %u\n", prev ); // If this triggers someone is enabled already enabled interrupts 341 226 if( prev == 1 ) { 342 227 #if GCC_VERSION > 50000 343 static_assert(__atomic_always_lock_free(sizeof(__cfaabi_tls.preemption_state.enabled), &__cfaabi_tls.preemption_state.enabled), "Must be lock-free");228 static_assert(__atomic_always_lock_free(sizeof(kernelTLS.preemption_state.enabled), &kernelTLS.preemption_state.enabled), "Must be lock-free"); 344 229 #endif 345 230 // Set enabled flag to true 346 231 // should be atomic to avoid preemption in the middle of the operation. 347 232 // use memory order RELAXED since there is no inter-thread on this variable requirements 348 __atomic_store_n(& __cfaabi_tls.preemption_state.enabled, true, __ATOMIC_RELAXED);233 __atomic_store_n(&kernelTLS.preemption_state.enabled, true, __ATOMIC_RELAXED); 349 234 350 235 // Signal the compiler that a fence is needed but only for signal handlers … … 353 238 } 354 239 } 355 356 #undef __cfaasm_label357 240 358 241 // sigprocmask wrapper : unblock a single signal … … 374 257 375 258 if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) { 376 abort( "internal error, pthread_sigmask" );259 abort( "internal error, pthread_sigmask" ); 377 260 } 378 261 } … … 385 268 386 269 // reserved for future use 387 static void timeout( $thread * this ) { 388 unpark( this ); 389 } 390 391 //----------------------------------------------------------------------------- 392 // Some assembly required 393 #if defined( __i386 ) 394 #ifdef __PIC__ 395 #define RELOC_PRELUDE( label ) \ 396 "calll .Lcfaasm_prelude_" #label "$pb\n\t" \ 397 ".Lcfaasm_prelude_" #label "$pb:\n\t" \ 398 "popl %%eax\n\t" \ 399 ".Lcfaasm_prelude_" #label "_end:\n\t" \ 400 "addl $_GLOBAL_OFFSET_TABLE_+(.Lcfaasm_prelude_" #label "_end-.Lcfaasm_prelude_" #label "$pb), %%eax\n\t" 401 #define RELOC_PREFIX "" 402 #define RELOC_SUFFIX "@GOT(%%eax)" 403 #else 404 #define RELOC_PREFIX "$" 405 #define RELOC_SUFFIX "" 406 #endif 407 #define __cfaasm_label( label ) struct asm_region label = \ 408 ({ \ 409 struct asm_region region; \ 410 asm( \ 411 RELOC_PRELUDE( label ) \ 412 "movl " RELOC_PREFIX "__cfaasm_" #label "_before" RELOC_SUFFIX ", %[vb]\n\t" \ 413 "movl " RELOC_PREFIX "__cfaasm_" #label "_after" RELOC_SUFFIX ", %[va]\n\t" \ 414 : [vb]"=r"(region.before), [va]"=r"(region.after) \ 415 ); \ 416 region; \ 417 }); 418 #elif defined( __x86_64 ) 419 #ifdef __PIC__ 420 #define RELOC_PREFIX "" 421 #define RELOC_SUFFIX "@GOTPCREL(%%rip)" 422 #else 423 #define RELOC_PREFIX "$" 424 #define RELOC_SUFFIX "" 425 #endif 426 #define __cfaasm_label( label ) struct asm_region label = \ 427 ({ \ 428 struct asm_region region; \ 429 asm( \ 430 "movq " RELOC_PREFIX "__cfaasm_" #label "_before" RELOC_SUFFIX ", %[vb]\n\t" \ 431 "movq " RELOC_PREFIX "__cfaasm_" #label "_after" RELOC_SUFFIX ", %[va]\n\t" \ 432 : [vb]"=r"(region.before), [va]"=r"(region.after) \ 433 ); \ 434 region; \ 435 }); 436 #elif defined( __aarch64__ ) 437 #ifdef __PIC__ 438 // Note that this works only for gcc 439 #define __cfaasm_label( label ) struct asm_region label = \ 440 ({ \ 441 struct asm_region region; \ 442 asm( \ 443 "adrp %[vb], _GLOBAL_OFFSET_TABLE_" "\n\t" \ 444 "ldr %[vb], [%[vb], #:gotpage_lo15:__cfaasm_" #label "_before]" "\n\t" \ 445 "adrp %[va], _GLOBAL_OFFSET_TABLE_" "\n\t" \ 446 "ldr %[va], [%[va], #:gotpage_lo15:__cfaasm_" #label "_after]" "\n\t" \ 447 : [vb]"=r"(region.before), [va]"=r"(region.after) \ 448 ); \ 449 region; \ 450 }); 451 #else 452 #error this is not the right thing to do 453 /* 454 #define __cfaasm_label( label ) struct asm_region label = \ 455 ({ \ 456 struct asm_region region; \ 457 asm( \ 458 "adrp %[vb], __cfaasm_" #label "_before" "\n\t" \ 459 "add %[vb], %[vb], :lo12:__cfaasm_" #label "_before" "\n\t" \ 460 "adrp %[va], :got:__cfaasm_" #label "_after" "\n\t" \ 461 "add %[va], %[va], :lo12:__cfaasm_" #label "_after" "\n\t" \ 462 : [vb]"=r"(region.before), [va]"=r"(region.after) \ 463 ); \ 464 region; \ 465 }); 466 */ 467 #endif 468 #else 469 #error unknown hardware architecture 470 #endif 270 static void timeout( thread_desc * this ) { 271 //TODO : implement waking threads 272 } 471 273 472 274 // KERNEL ONLY 473 // Check if a __cfactx_switch signal handler shoud defer275 // Check if a CtxSwitch signal handler shoud defer 474 276 // If true : preemption is safe 475 277 // If false : preemption is unsafe and marked as pending 476 static inline bool preemption_ready( void * ip ) { 477 // Get all the region for which it is not safe to preempt 478 __cfaasm_label( get ); 479 __cfaasm_label( check ); 480 __cfaasm_label( dsable ); 481 278 static inline bool preemption_ready() { 482 279 // Check if preemption is safe 483 bool ready = true; 484 if( __cfaasm_in( ip, get ) ) { ready = false; goto EXIT; }; 485 if( __cfaasm_in( ip, check ) ) { ready = false; goto EXIT; }; 486 if( __cfaasm_in( ip, dsable ) ) { ready = false; goto EXIT; }; 487 if( !__cfaabi_tls.preemption_state.enabled) { ready = false; goto EXIT; }; 488 if( __cfaabi_tls.preemption_state.in_progress ) { ready = false; goto EXIT; }; 489 490 EXIT: 280 bool ready = kernelTLS.preemption_state.enabled && ! kernelTLS.preemption_state.in_progress; 281 491 282 // Adjust the pending flag accordingly 492 __cfaabi_tls.this_processor->pending_preemption = !ready;283 kernelTLS.this_processor->pending_preemption = !ready; 493 284 return ready; 494 285 } … … 500 291 // Startup routine to activate preemption 501 292 // Called from kernel_startup 502 void __kernel_alarm_startup() {293 void kernel_start_preemption() { 503 294 __cfaabi_dbg_print_safe( "Kernel : Starting preemption\n" ); 504 295 505 296 // Start with preemption disabled until ready 506 __cfaabi_tls.preemption_state.enabled = false;507 __cfaabi_tls.preemption_state.disable_count = 1;297 kernelTLS.preemption_state.enabled = false; 298 kernelTLS.preemption_state.disable_count = 1; 508 299 509 300 // Initialize the event kernel … … 512 303 513 304 // Setup proper signal handlers 514 __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler 515 __cfaabi_sigaction( SIGALRM, sigHandler_alarm , SA_SIGINFO | SA_RESTART ); // debug handler 305 __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // CtxSwitch handler 516 306 517 307 signal_block( SIGALRM ); 518 308 519 alarm_stack = __create_pthread( &alarm_thread, alarm_loop, 0p );309 alarm_stack = create_pthread( &alarm_thread, alarm_loop, 0p ); 520 310 } 521 311 522 312 // Shutdown routine to deactivate preemption 523 313 // Called from kernel_shutdown 524 void __kernel_alarm_shutdown() {314 void kernel_stop_preemption() { 525 315 __cfaabi_dbg_print_safe( "Kernel : Preemption stopping\n" ); 526 316 … … 536 326 // Wait for the preemption thread to finish 537 327 538 __destroy_pthread( alarm_thread, alarm_stack, 0p ); 328 pthread_join( alarm_thread, 0p ); 329 free( alarm_stack ); 539 330 540 331 // Preemption is now fully stopped … … 562 353 // Kernel Signal Handlers 563 354 //============================================================================================= 564 __cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; )565 355 566 356 // Context switch signal handler 567 357 // Receives SIGUSR1 signal and causes the current thread to yield 568 358 static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) { 569 void * ip = (void *)(cxt->uc_mcontext.CFA_REG_IP); 570 __cfaabi_dbg_debug_do( last_interrupt = ip; ) 359 __cfaabi_dbg_debug_do( last_interrupt = (void *)(cxt->uc_mcontext.CFA_REG_IP); ) 571 360 572 361 // SKULLDUGGERY: if a thread creates a processor and the immediately deletes it, 573 362 // the interrupt that is supposed to force the kernel thread to preempt might arrive 574 // before the kernel thread has even started running. When that happens , an interrupt575 // w itha null 'this_processor' will be caught, just ignore it.576 if(! __cfaabi_tls.this_processor ) return;363 // before the kernel thread has even started running. When that happens an iterrupt 364 // we a null 'this_processor' will be caught, just ignore it. 365 if(! kernelTLS.this_processor ) return; 577 366 578 367 choose(sfp->si_value.sival_int) { 579 368 case PREEMPT_NORMAL : ;// Normal case, nothing to do here 580 case PREEMPT_TERMINATE: verify( __atomic_load_n( & __cfaabi_tls.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );369 case PREEMPT_TERMINATE: verify( __atomic_load_n( &kernelTLS.this_processor->do_terminate, __ATOMIC_SEQ_CST ) ); 581 370 default: 582 371 abort( "internal error, signal value is %d", sfp->si_value.sival_int ); … … 584 373 585 374 // Check if it is safe to preempt here 586 if( !preemption_ready( ip) ) { return; }587 588 __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", __cfaabi_tls.this_processor, __cfaabi_tls.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) );375 if( !preemption_ready() ) { return; } 376 377 __cfaabi_dbg_print_buffer_decl( " KERNEL: preempting core %p (%p @ %p).\n", kernelTLS.this_processor, kernelTLS.this_thread, (void *)(cxt->uc_mcontext.CFA_REG_IP) ); 589 378 590 379 // Sync flag : prevent recursive calls to the signal handler 591 __cfaabi_tls.preemption_state.in_progress = true;380 kernelTLS.preemption_state.in_progress = true; 592 381 593 382 // Clear sighandler mask before context switching. … … 599 388 } 600 389 390 // TODO: this should go in finish action 601 391 // Clear the in progress flag 602 __cfaabi_tls.preemption_state.in_progress = false;392 kernelTLS.preemption_state.in_progress = false; 603 393 604 394 // Preemption can occur here 605 395 606 force_yield( __ALARM_PREEMPTION ); // Do the actual __cfactx_switch 607 } 608 609 static void sigHandler_alarm( __CFA_SIGPARMS__ ) { 610 abort("SIGALRM should never reach the signal handler"); 611 } 612 613 #if !defined(__CFA_NO_STATISTICS__) 614 int __print_alarm_stats = 0; 615 #endif 396 BlockInternal( kernelTLS.this_thread ); // Do the actual CtxSwitch 397 } 616 398 617 399 // Main of the alarm thread 618 400 // Waits on SIGALRM and send SIGUSR1 to whom ever needs it 619 401 static void * alarm_loop( __attribute__((unused)) void * args ) { 620 __processor_id_t id;621 id.full_proc = false;622 id.id = doregister(&id);623 __cfaabi_tls.this_proc_id = &id;624 625 #if !defined(__CFA_NO_STATISTICS__)626 struct __stats_t local_stats;627 __cfaabi_tls.this_stats = &local_stats;628 __init_stats( &local_stats );629 #endif630 631 402 // Block sigalrms to control when they arrive 632 403 sigset_t mask; … … 686 457 EXIT: 687 458 __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" ); 688 unregister(&id);689 690 #if !defined(__CFA_NO_STATISTICS__)691 if( 0 != __print_alarm_stats ) {692 __print_stats( &local_stats, __print_alarm_stats, "Alarm", "Thread", 0p );693 }694 #endif695 459 return 0p; 696 460 } … … 701 465 702 466 void __cfaabi_check_preemption() { 703 bool ready = __preemption_enabled();467 bool ready = kernelTLS.preemption_state.enabled; 704 468 if(!ready) { abort("Preemption should be ready"); } 705 469 706 470 sigset_t oldset; 707 471 int ret; 708 ret = pthread_sigmask(0, ( const sigset_t * ) 0p, &oldset); // workaround trac#208: cast should be unnecessary472 ret = pthread_sigmask(0, 0p, &oldset); 709 473 if(ret != 0) { abort("ERROR sigprocmask returned %d", ret); } 710 474 … … 724 488 #ifdef __CFA_WITH_VERIFY__ 725 489 bool __cfaabi_dbg_in_kernel() { 726 return ! __preemption_enabled();490 return !kernelTLS.preemption_state.enabled; 727 491 } 728 492 #endif
Note:
See TracChangeset
for help on using the changeset viewer.