Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/preemption.cfa

    re235429 r8fc652e0  
    3838// FwdDeclarations : timeout handlers
    3939static void preempt( processor   * this );
    40 static void timeout( struct __processor_id_t * id, $thread * this );
     40static void timeout( $thread * this );
    4141
    4242// FwdDeclarations : Signal handlers
     
    9191
    9292// Tick one frame of the Discrete Event Simulation for alarms
    93 static void tick_preemption( struct __processor_id_t * id ) {
     93static void tick_preemption(void) {
    9494        alarm_node_t * node = 0p;                                                       // Used in the while loop but cannot be declared in the while condition
    9595        alarm_list_t * alarms = &event_kernel->alarms;          // Local copy for ease of reading
     
    105105
    106106                // Check if this is a kernel
    107                 if( node->kernel_alarm ) {
     107                if( node->type == Kernel ) {
    108108                        preempt( node->proc );
    109109                }
     110                else if( node->type == User ) {
     111                        timeout( node->thrd );
     112                }
    110113                else {
    111                         timeout( id, node->thrd );
     114                        node->callback(*node);
    112115                }
    113116
     
    161164//=============================================================================================
    162165
     166//----------
     167// special case for preemption since used often
     168bool __preemption_enabled() {
     169        // create a assembler label before
     170        // marked as clobber all to avoid movement
     171        asm volatile("__cfaasm_check_before:":::"memory");
     172
     173        // access tls as normal
     174        bool enabled = __cfaabi_tls.preemption_state.enabled;
     175
     176        // create a assembler label after
     177        // marked as clobber all to avoid movement
     178        asm volatile("__cfaasm_check_after:":::"memory");
     179        return enabled;
     180}
     181
     182//----------
     183// Get data from the TLS block
     184uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems
     185uintptr_t __cfatls_get( unsigned long int offset ) {
     186        // create a assembler label before
     187        // marked as clobber all to avoid movement
     188        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 after
     194        // marked as clobber all to avoid movement
     195        asm volatile("__cfaasm_get_after:":::"memory");
     196        return val;
     197}
     198
     199// //----------
     200// // Write data to the TLS block
     201// // sadly it looses the type information and can only write 1 word at a time
     202// // use with __builtin_offsetof
     203// void __cfatls_set(uintptr_t offset, void * value) __attribute__((__noinline__));
     204// void __cfatls_set(uintptr_t offset, void * value) {
     205//     // create a assembler label before
     206//     // marked as clobber all to avoid movement
     207//     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 after
     213//     // marked as clobber all to avoid movement
     214//     asm volatile("__cfaasm_set_after:":::"memory");
     215// }
     216
     217// //----------
     218// #include <stdio.h>
     219// int main() {
     220//     // Get the information
     221//     // Must use inline assembly to get access to label
     222//     // 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 function
     224//     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
    163234__cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; )
    164235
     
    166237        // Disable interrupts by incrementing the counter
    167238        void disable_interrupts() {
    168                 with( kernelTLS.preemption_state ) {
     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 ) {
    169244                        #if GCC_VERSION > 50000
    170245                        static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
     
    183258                        verify( new_val < 65_000u );              // If this triggers someone is disabling interrupts without enabling them
    184259                }
     260
     261                // create a assembler label after
     262                // marked as clobber all to avoid movement
     263                asm volatile("__cfaasm_disable_after:":::"memory");
    185264        }
    186265
     
    188267        // If counter reaches 0, execute any pending __cfactx_switch
    189268        void enable_interrupts( __cfaabi_dbg_ctx_param ) {
    190                 processor   * proc = kernelTLS.this_processor; // Cache the processor now since interrupts can start happening after the atomic store
     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
    191274                /* paranoid */ verify( proc );
    192275
    193                 with( kernelTLS.preemption_state ){
     276                with( __cfaabi_tls.preemption_state ){
    194277                        unsigned short prev = disable_count;
    195278                        disable_count -= 1;
     
    218301                // For debugging purposes : keep track of the last person to enable the interrupts
    219302                __cfaabi_dbg_debug_do( proc->last_enable = caller; )
     303
     304                // create a assembler label after
     305                // marked as clobber all to avoid movement
     306                asm volatile("__cfaasm_enable_after:":::"memory");
    220307        }
    221308
     
    223310        // Don't execute any pending __cfactx_switch even if counter reaches 0
    224311        void enable_interrupts_noPoll() {
    225                 unsigned short prev = kernelTLS.preemption_state.disable_count;
    226                 kernelTLS.preemption_state.disable_count -= 1;
     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;
    227318                verifyf( prev != 0u, "Incremented from %u\n", prev );                     // If this triggers someone is enabled already enabled interrupts
    228319                if( prev == 1 ) {
    229320                        #if GCC_VERSION > 50000
    230                         static_assert(__atomic_always_lock_free(sizeof(kernelTLS.preemption_state.enabled), &kernelTLS.preemption_state.enabled), "Must be lock-free");
     321                        static_assert(__atomic_always_lock_free(sizeof(__cfaabi_tls.preemption_state.enabled), &__cfaabi_tls.preemption_state.enabled), "Must be lock-free");
    231322                        #endif
    232323                        // Set enabled flag to true
    233324                        // should be atomic to avoid preemption in the middle of the operation.
    234325                        // use memory order RELAXED since there is no inter-thread on this variable requirements
    235                         __atomic_store_n(&kernelTLS.preemption_state.enabled, true, __ATOMIC_RELAXED);
     326                        __atomic_store_n(&__cfaabi_tls.preemption_state.enabled, true, __ATOMIC_RELAXED);
    236327
    237328                        // Signal the compiler that a fence is needed but only for signal handlers
    238329                        __atomic_signal_fence(__ATOMIC_RELEASE);
    239330                }
     331
     332                // create a assembler label after
     333                // marked as clobber all to avoid movement
     334                asm volatile("__cfaasm_nopoll_after:":::"memory");
    240335        }
    241336}
     
    270365
    271366// reserved for future use
    272 static void timeout( struct __processor_id_t * id, $thread * this ) {
     367static void timeout( $thread * this ) {
    273368        #if !defined( __CFA_NO_STATISTICS__ )
    274                 kernelTLS.this_stats = this->curr_cluster->stats;
     369                kernelTLS().this_stats = this->curr_cluster->stats;
    275370        #endif
    276         __unpark( id, this );
     371        unpark( this );
    277372}
    278373
     
    283378static inline bool preemption_ready() {
    284379        // Check if preemption is safe
    285         bool ready = kernelTLS.preemption_state.enabled && ! kernelTLS.preemption_state.in_progress;
     380        bool ready = __cfaabi_tls.preemption_state.enabled && ! __cfaabi_tls.preemption_state.in_progress;
    286381
    287382        // Adjust the pending flag accordingly
    288         kernelTLS.this_processor->pending_preemption = !ready;
     383        __cfaabi_tls.this_processor->pending_preemption = !ready;
    289384        return ready;
    290385}
     
    300395
    301396        // Start with preemption disabled until ready
    302         kernelTLS.preemption_state.enabled = false;
    303         kernelTLS.preemption_state.disable_count = 1;
     397        __cfaabi_tls.preemption_state.enabled = false;
     398        __cfaabi_tls.preemption_state.disable_count = 1;
    304399
    305400        // Initialize the event kernel
     
    359454// Kernel Signal Handlers
    360455//=============================================================================================
     456struct asm_region {
     457        void * before;
     458        void * after;
     459};
     460
     461//-----------------------------------------------------------------------------
     462// Some assembly required
     463#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        #else
     478                #define PLT ""
     479        #endif
     480        #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 arm
     492#else
     493        #error unknown hardware architecture
     494#endif
    361495
    362496// Context switch signal handler
    363497// Receives SIGUSR1 signal and causes the current thread to yield
    364498static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ) {
    365         __cfaabi_dbg_debug_do( last_interrupt = (void *)(cxt->uc_mcontext.CFA_REG_IP); )
     499        void * ip = (void *)(cxt->uc_mcontext.CFA_REG_IP);
     500        __cfaabi_dbg_debug_do( last_interrupt = ip; )
    366501
    367502        // SKULLDUGGERY: if a thread creates a processor and the immediately deletes it,
     
    369504        // before the kernel thread has even started running. When that happens, an interrupt
    370505        // with a null 'this_processor' will be caught, just ignore it.
    371         if(! kernelTLS.this_processor ) return;
     506        if(! __cfaabi_tls.this_processor ) return;
    372507
    373508        choose(sfp->si_value.sival_int) {
    374509                case PREEMPT_NORMAL   : ;// Normal case, nothing to do here
    375                 case PREEMPT_TERMINATE: verify( __atomic_load_n( &kernelTLS.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );
     510                case PREEMPT_TERMINATE: verify( __atomic_load_n( &__cfaabi_tls.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );
    376511                default:
    377512                        abort( "internal error, signal value is %d", sfp->si_value.sival_int );
     
    381516        if( !preemption_ready() ) { return; }
    382517
    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) );
     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) );
    384526
    385527        // Sync flag : prevent recursive calls to the signal handler
    386         kernelTLS.preemption_state.in_progress = true;
     528        __cfaabi_tls.preemption_state.in_progress = true;
    387529
    388530        // Clear sighandler mask before context switching.
     
    394536        }
    395537
    396         // TODO: this should go in finish action
    397538        // Clear the in progress flag
    398         kernelTLS.preemption_state.in_progress = false;
     539        __cfaabi_tls.preemption_state.in_progress = false;
    399540
    400541        // Preemption can occur here
     
    413554        id.full_proc = false;
    414555        id.id = doregister(&id);
     556        __cfaabi_tls.this_proc_id = &id;
    415557
    416558        // Block sigalrms to control when they arrive
     
    458600                        // __cfaabi_dbg_print_safe( "Kernel : Preemption thread tick\n" );
    459601                        lock( event_kernel->lock __cfaabi_dbg_ctx2 );
    460                         tick_preemption( &id );
     602                        tick_preemption();
    461603                        unlock( event_kernel->lock );
    462604                        break;
     
    480622
    481623void __cfaabi_check_preemption() {
    482         bool ready = kernelTLS.preemption_state.enabled;
     624        bool ready = __preemption_enabled();
    483625        if(!ready) { abort("Preemption should be ready"); }
    484626
     
    503645#ifdef __CFA_WITH_VERIFY__
    504646bool __cfaabi_dbg_in_kernel() {
    505         return !kernelTLS.preemption_state.enabled;
     647        return !__preemption_enabled();
    506648}
    507649#endif
Note: See TracChangeset for help on using the changeset viewer.