Ignore:
File:
1 edited

Legend:

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

    r8fc652e0 re235429  
    3838// FwdDeclarations : timeout handlers
    3939static void preempt( processor   * this );
    40 static void timeout( $thread * this );
     40static void timeout( struct __processor_id_t * id, $thread * this );
    4141
    4242// FwdDeclarations : Signal handlers
     
    9191
    9292// Tick one frame of the Discrete Event Simulation for alarms
    93 static void tick_preemption(void) {
     93static void tick_preemption( struct __processor_id_t * id ) {
    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->type == Kernel ) {
     107                if( node->kernel_alarm ) {
    108108                        preempt( node->proc );
    109109                }
    110                 else if( node->type == User ) {
    111                         timeout( node->thrd );
    112                 }
    113110                else {
    114                         node->callback(*node);
     111                        timeout( id, node->thrd );
    115112                }
    116113
     
    164161//=============================================================================================
    165162
    166 //----------
    167 // special case for preemption since used often
    168 bool __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
    184 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems
    185 uintptr_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 
    234163__cfaabi_dbg_debug_do( static thread_local void * last_interrupt = 0; )
    235164
     
    237166        // Disable interrupts by incrementing the counter
    238167        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 ) {
    244169                        #if GCC_VERSION > 50000
    245170                        static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
     
    258183                        verify( new_val < 65_000u );              // If this triggers someone is disabling interrupts without enabling them
    259184                }
    260 
    261                 // create a assembler label after
    262                 // marked as clobber all to avoid movement
    263                 asm volatile("__cfaasm_disable_after:":::"memory");
    264185        }
    265186
     
    267188        // If counter reaches 0, execute any pending __cfactx_switch
    268189        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
    274191                /* paranoid */ verify( proc );
    275192
    276                 with( __cfaabi_tls.preemption_state ){
     193                with( kernelTLS.preemption_state ){
    277194                        unsigned short prev = disable_count;
    278195                        disable_count -= 1;
     
    301218                // For debugging purposes : keep track of the last person to enable the interrupts
    302219                __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");
    307220        }
    308221
     
    310223        // Don't execute any pending __cfactx_switch even if counter reaches 0
    311224        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;
    318227                verifyf( prev != 0u, "Incremented from %u\n", prev );                     // If this triggers someone is enabled already enabled interrupts
    319228                if( prev == 1 ) {
    320229                        #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");
    322231                        #endif
    323232                        // Set enabled flag to true
    324233                        // should be atomic to avoid preemption in the middle of the operation.
    325234                        // 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);
    327236
    328237                        // Signal the compiler that a fence is needed but only for signal handlers
    329238                        __atomic_signal_fence(__ATOMIC_RELEASE);
    330239                }
    331 
    332                 // create a assembler label after
    333                 // marked as clobber all to avoid movement
    334                 asm volatile("__cfaasm_nopoll_after:":::"memory");
    335240        }
    336241}
     
    365270
    366271// reserved for future use
    367 static void timeout( $thread * this ) {
     272static void timeout( struct __processor_id_t * id, $thread * this ) {
    368273        #if !defined( __CFA_NO_STATISTICS__ )
    369                 kernelTLS().this_stats = this->curr_cluster->stats;
     274                kernelTLS.this_stats = this->curr_cluster->stats;
    370275        #endif
    371         unpark( this );
     276        __unpark( id, this );
    372277}
    373278
     
    378283static inline bool preemption_ready() {
    379284        // 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;
    381286
    382287        // Adjust the pending flag accordingly
    383         __cfaabi_tls.this_processor->pending_preemption = !ready;
     288        kernelTLS.this_processor->pending_preemption = !ready;
    384289        return ready;
    385290}
     
    395300
    396301        // 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;
    399304
    400305        // Initialize the event kernel
     
    454359// Kernel Signal Handlers
    455360//=============================================================================================
    456 struct 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
    495361
    496362// Context switch signal handler
    497363// Receives SIGUSR1 signal and causes the current thread to yield
    498364static 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); )
    501366
    502367        // SKULLDUGGERY: if a thread creates a processor and the immediately deletes it,
     
    504369        // before the kernel thread has even started running. When that happens, an interrupt
    505370        // with a null 'this_processor' will be caught, just ignore it.
    506         if(! __cfaabi_tls.this_processor ) return;
     371        if(! kernelTLS.this_processor ) return;
    507372
    508373        choose(sfp->si_value.sival_int) {
    509374                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 ) );
    511376                default:
    512377                        abort( "internal error, signal value is %d", sfp->si_value.sival_int );
     
    516381        if( !preemption_ready() ) { return; }
    517382
    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) );
    526384
    527385        // Sync flag : prevent recursive calls to the signal handler
    528         __cfaabi_tls.preemption_state.in_progress = true;
     386        kernelTLS.preemption_state.in_progress = true;
    529387
    530388        // Clear sighandler mask before context switching.
     
    536394        }
    537395
     396        // TODO: this should go in finish action
    538397        // Clear the in progress flag
    539         __cfaabi_tls.preemption_state.in_progress = false;
     398        kernelTLS.preemption_state.in_progress = false;
    540399
    541400        // Preemption can occur here
     
    554413        id.full_proc = false;
    555414        id.id = doregister(&id);
    556         __cfaabi_tls.this_proc_id = &id;
    557415
    558416        // Block sigalrms to control when they arrive
     
    600458                        // __cfaabi_dbg_print_safe( "Kernel : Preemption thread tick\n" );
    601459                        lock( event_kernel->lock __cfaabi_dbg_ctx2 );
    602                         tick_preemption();
     460                        tick_preemption( &id );
    603461                        unlock( event_kernel->lock );
    604462                        break;
     
    622480
    623481void __cfaabi_check_preemption() {
    624         bool ready = __preemption_enabled();
     482        bool ready = kernelTLS.preemption_state.enabled;
    625483        if(!ready) { abort("Preemption should be ready"); }
    626484
     
    645503#ifdef __CFA_WITH_VERIFY__
    646504bool __cfaabi_dbg_in_kernel() {
    647         return !__preemption_enabled();
     505        return !kernelTLS.preemption_state.enabled;
    648506}
    649507#endif
Note: See TracChangeset for help on using the changeset viewer.