- File:
-
- 1 edited
-
libcfa/src/concurrency/preemption.cfa (modified) (20 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/preemption.cfa
r8fc652e0 re235429 38 38 // FwdDeclarations : timeout handlers 39 39 static void preempt( processor * this ); 40 static void timeout( $thread * this );40 static void timeout( struct __processor_id_t * id, $thread * this ); 41 41 42 42 // FwdDeclarations : Signal handlers … … 91 91 92 92 // Tick one frame of the Discrete Event Simulation for alarms 93 static void tick_preemption( void) {93 static void tick_preemption( struct __processor_id_t * id ) { 94 94 alarm_node_t * node = 0p; // Used in the while loop but cannot be declared in the while condition 95 95 alarm_list_t * alarms = &event_kernel->alarms; // Local copy for ease of reading … … 105 105 106 106 // Check if this is a kernel 107 if( node-> type == Kernel) {107 if( node->kernel_alarm ) { 108 108 preempt( node->proc ); 109 109 } 110 else if( node->type == User ) {111 timeout( node->thrd );112 }113 110 else { 114 node->callback(*node);111 timeout( id, node->thrd ); 115 112 } 116 113 … … 164 161 //============================================================================================= 165 162 166 //----------167 // special case for preemption since used often168 bool __preemption_enabled() {169 // create a assembler label before170 // marked as clobber all to avoid movement171 asm volatile("__cfaasm_check_before:":::"memory");172 173 // access tls as normal174 bool enabled = __cfaabi_tls.preemption_state.enabled;175 176 // create a assembler label after177 // marked as clobber all to avoid movement178 asm volatile("__cfaasm_check_after:":::"memory");179 return enabled;180 }181 182 //----------183 // Get data from the TLS block184 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems185 uintptr_t __cfatls_get( unsigned long int offset ) {186 // create a assembler label before187 // marked as clobber all to avoid movement188 asm volatile("__cfaasm_get_before:":::"memory");189 190 // access tls as normal (except for pointer arithmetic)191 uintptr_t val = *(uintptr_t*)((uintptr_t)&__cfaabi_tls + offset);192 193 // create a assembler label after194 // marked as clobber all to avoid movement195 asm volatile("__cfaasm_get_after:":::"memory");196 return val;197 }198 199 // //----------200 // // Write data to the TLS block201 // // sadly it looses the type information and can only write 1 word at a time202 // // use with __builtin_offsetof203 // void __cfatls_set(uintptr_t offset, void * value) __attribute__((__noinline__));204 // void __cfatls_set(uintptr_t offset, void * value) {205 // // create a assembler label before206 // // marked as clobber all to avoid movement207 // asm volatile("__cfaasm_set_before:":::"memory");208 209 // // access tls as normal (except for type information)210 // *(void**)(offset + (uintptr_t)&my_tls) = value;211 212 // // create a assembler label after213 // // marked as clobber all to avoid movement214 // asm volatile("__cfaasm_set_after:":::"memory");215 // }216 217 // //----------218 // #include <stdio.h>219 // int main() {220 // // Get the information221 // // Must use inline assembly to get access to label222 // // C is annoying here because this could easily be a static const but "initializer element is not a compile-time constant"223 // // The big advantage of this approach is that there is 0 overhead for the read and writes function224 // void * __cfaasm_addr_get_before = ({ void * value; asm("movq $__cfaasm_get_before, %[v]\n\t" : [v]"=r"(value) ); value; });225 // void * __cfaasm_addr_get_after = ({ void * value; asm("movq $__cfaasm_get_after , %[v]\n\t" : [v]"=r"(value) ); value; });226 // void * __cfaasm_addr_set_before = ({ void * value; asm("movq $__cfaasm_set_before, %[v]\n\t" : [v]"=r"(value) ); value; });227 // void * __cfaasm_addr_set_after = ({ void * value; asm("movq $__cfaasm_set_after , %[v]\n\t" : [v]"=r"(value) ); value; });228 229 // printf("%p to %p\n", __cfaasm_addr_get_before, __cfaasm_addr_get_after);230 // printf("%p to %p\n", __cfaasm_addr_set_before, __cfaasm_addr_set_after);231 // return 0;232 // }233 234 163 __cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; ) 235 164 … … 237 166 // Disable interrupts by incrementing the counter 238 167 void disable_interrupts() { 239 // create a assembler label before 240 // marked as clobber all to avoid movement 241 asm volatile("__cfaasm_disable_before:":::"memory"); 242 243 with( __cfaabi_tls.preemption_state ) { 168 with( kernelTLS.preemption_state ) { 244 169 #if GCC_VERSION > 50000 245 170 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free"); … … 258 183 verify( new_val < 65_000u ); // If this triggers someone is disabling interrupts without enabling them 259 184 } 260 261 // create a assembler label after262 // marked as clobber all to avoid movement263 asm volatile("__cfaasm_disable_after:":::"memory");264 185 } 265 186 … … 267 188 // If counter reaches 0, execute any pending __cfactx_switch 268 189 void enable_interrupts( __cfaabi_dbg_ctx_param ) { 269 // create a assembler label before 270 // marked as clobber all to avoid movement 271 asm volatile("__cfaasm_enable_before:":::"memory"); 272 273 processor * proc = __cfaabi_tls.this_processor; // Cache the processor now since interrupts can start happening after the atomic store 190 processor * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic store 274 191 /* paranoid */ verify( proc ); 275 192 276 with( __cfaabi_tls.preemption_state ){193 with( kernelTLS.preemption_state ){ 277 194 unsigned short prev = disable_count; 278 195 disable_count -= 1; … … 301 218 // For debugging purposes : keep track of the last person to enable the interrupts 302 219 __cfaabi_dbg_debug_do( proc->last_enable = caller; ) 303 304 // create a assembler label after305 // marked as clobber all to avoid movement306 asm volatile("__cfaasm_enable_after:":::"memory");307 220 } 308 221 … … 310 223 // Don't execute any pending __cfactx_switch even if counter reaches 0 311 224 void enable_interrupts_noPoll() { 312 // create a assembler label before 313 // marked as clobber all to avoid movement 314 asm volatile("__cfaasm_nopoll_before:":::"memory"); 315 316 unsigned short prev = __cfaabi_tls.preemption_state.disable_count; 317 __cfaabi_tls.preemption_state.disable_count -= 1; 225 unsigned short prev = kernelTLS.preemption_state.disable_count; 226 kernelTLS.preemption_state.disable_count -= 1; 318 227 verifyf( prev != 0u, "Incremented from %u\n", prev ); // If this triggers someone is enabled already enabled interrupts 319 228 if( prev == 1 ) { 320 229 #if GCC_VERSION > 50000 321 static_assert(__atomic_always_lock_free(sizeof( __cfaabi_tls.preemption_state.enabled), &__cfaabi_tls.preemption_state.enabled), "Must be lock-free");230 static_assert(__atomic_always_lock_free(sizeof(kernelTLS.preemption_state.enabled), &kernelTLS.preemption_state.enabled), "Must be lock-free"); 322 231 #endif 323 232 // Set enabled flag to true 324 233 // should be atomic to avoid preemption in the middle of the operation. 325 234 // use memory order RELAXED since there is no inter-thread on this variable requirements 326 __atomic_store_n(& __cfaabi_tls.preemption_state.enabled, true, __ATOMIC_RELAXED);235 __atomic_store_n(&kernelTLS.preemption_state.enabled, true, __ATOMIC_RELAXED); 327 236 328 237 // Signal the compiler that a fence is needed but only for signal handlers 329 238 __atomic_signal_fence(__ATOMIC_RELEASE); 330 239 } 331 332 // create a assembler label after333 // marked as clobber all to avoid movement334 asm volatile("__cfaasm_nopoll_after:":::"memory");335 240 } 336 241 } … … 365 270 366 271 // reserved for future use 367 static void timeout( $thread * this ) {272 static void timeout( struct __processor_id_t * id, $thread * this ) { 368 273 #if !defined( __CFA_NO_STATISTICS__ ) 369 kernelTLS ().this_stats = this->curr_cluster->stats;274 kernelTLS.this_stats = this->curr_cluster->stats; 370 275 #endif 371 unpark(this );276 __unpark( id, this ); 372 277 } 373 278 … … 378 283 static inline bool preemption_ready() { 379 284 // Check if preemption is safe 380 bool ready = __cfaabi_tls.preemption_state.enabled && ! __cfaabi_tls.preemption_state.in_progress;285 bool ready = kernelTLS.preemption_state.enabled && ! kernelTLS.preemption_state.in_progress; 381 286 382 287 // Adjust the pending flag accordingly 383 __cfaabi_tls.this_processor->pending_preemption = !ready;288 kernelTLS.this_processor->pending_preemption = !ready; 384 289 return ready; 385 290 } … … 395 300 396 301 // Start with preemption disabled until ready 397 __cfaabi_tls.preemption_state.enabled = false;398 __cfaabi_tls.preemption_state.disable_count = 1;302 kernelTLS.preemption_state.enabled = false; 303 kernelTLS.preemption_state.disable_count = 1; 399 304 400 305 // Initialize the event kernel … … 454 359 // Kernel Signal Handlers 455 360 //============================================================================================= 456 struct asm_region {457 void * before;458 void * after;459 };460 461 //-----------------------------------------------------------------------------462 // Some assembly required463 #if defined( __i386 )464 #define __cfaasm_label( label ) \465 ({ \466 struct asm_region region; \467 asm( \468 "movl $__cfaasm_" #label "_before, %[vb]\n\t" \469 "movl $__cfaasm_" #label "_after , %[va]\n\t" \470 : [vb]"=r"(region.before), [vb]"=r"(region.before) \471 ); \472 region; \473 });474 #elif defined( __x86_64 )475 #ifdef __PIC__476 #define PLT "@PLT"477 #else478 #define PLT ""479 #endif480 #define __cfaasm_label( label ) \481 ({ \482 struct asm_region region; \483 asm( \484 "movq $__cfaasm_" #label "_before" PLT ", %[vb]\n\t" \485 "movq $__cfaasm_" #label "_after" PLT ", %[va]\n\t" \486 : [vb]"=r"(region.before), [va]"=r"(region.after) \487 ); \488 region; \489 });490 #elif defined( __aarch64__ )491 #error __cfaasm_label undefined for arm492 #else493 #error unknown hardware architecture494 #endif495 361 496 362 // Context switch signal handler 497 363 // Receives SIGUSR1 signal and causes the current thread to yield 498 364 static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) { 499 void * ip = (void *)(cxt->uc_mcontext.CFA_REG_IP); 500 __cfaabi_dbg_debug_do( last_interrupt = ip; ) 365 __cfaabi_dbg_debug_do( last_interrupt = (void *)(cxt->uc_mcontext.CFA_REG_IP); ) 501 366 502 367 // SKULLDUGGERY: if a thread creates a processor and the immediately deletes it, … … 504 369 // before the kernel thread has even started running. When that happens, an interrupt 505 370 // with a null 'this_processor' will be caught, just ignore it. 506 if(! __cfaabi_tls.this_processor ) return;371 if(! kernelTLS.this_processor ) return; 507 372 508 373 choose(sfp->si_value.sival_int) { 509 374 case PREEMPT_NORMAL : ;// Normal case, nothing to do here 510 case PREEMPT_TERMINATE: verify( __atomic_load_n( & __cfaabi_tls.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );375 case PREEMPT_TERMINATE: verify( __atomic_load_n( &kernelTLS.this_processor->do_terminate, __ATOMIC_SEQ_CST ) ); 511 376 default: 512 377 abort( "internal error, signal value is %d", sfp->si_value.sival_int ); … … 516 381 if( !preemption_ready() ) { return; } 517 382 518 struct asm_region region; 519 region = __cfaasm_label( get ); if( ip >= region.before && ip <= region.after ) return; 520 region = __cfaasm_label( check ); if( ip >= region.before && ip <= region.after ) return; 521 region = __cfaasm_label( disable ); if( ip >= region.before && ip <= region.after ) return; 522 region = __cfaasm_label( enable ); if( ip >= region.before && ip <= region.after ) return; 523 region = __cfaasm_label( nopoll ); if( ip >= region.before && ip <= region.after ) return; 524 525 __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) ); 383 __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) ); 526 384 527 385 // Sync flag : prevent recursive calls to the signal handler 528 __cfaabi_tls.preemption_state.in_progress = true;386 kernelTLS.preemption_state.in_progress = true; 529 387 530 388 // Clear sighandler mask before context switching. … … 536 394 } 537 395 396 // TODO: this should go in finish action 538 397 // Clear the in progress flag 539 __cfaabi_tls.preemption_state.in_progress = false;398 kernelTLS.preemption_state.in_progress = false; 540 399 541 400 // Preemption can occur here … … 554 413 id.full_proc = false; 555 414 id.id = doregister(&id); 556 __cfaabi_tls.this_proc_id = &id;557 415 558 416 // Block sigalrms to control when they arrive … … 600 458 // __cfaabi_dbg_print_safe( "Kernel : Preemption thread tick\n" ); 601 459 lock( event_kernel->lock __cfaabi_dbg_ctx2 ); 602 tick_preemption( );460 tick_preemption( &id ); 603 461 unlock( event_kernel->lock ); 604 462 break; … … 622 480 623 481 void __cfaabi_check_preemption() { 624 bool ready = __preemption_enabled();482 bool ready = kernelTLS.preemption_state.enabled; 625 483 if(!ready) { abort("Preemption should be ready"); } 626 484 … … 645 503 #ifdef __CFA_WITH_VERIFY__ 646 504 bool __cfaabi_dbg_in_kernel() { 647 return ! __preemption_enabled();505 return !kernelTLS.preemption_state.enabled; 648 506 } 649 507 #endif
Note:
See TracChangeset
for help on using the changeset viewer.