Changes in / [e5256bd:4f102fa]


Ignore:
Location:
libcfa/src/concurrency
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/kernel/fwd.hfa

    re5256bd r4f102fa  
    276276                        // intented to be use by wait, wait_any, waitfor, etc. rather than used directly
    277277                        bool retract( future_t & this, oneshot & wait_ctx ) {
    278                                 struct oneshot * expected = &wait_ctx;
     278                                struct oneshot * expected = this.ptr;
    279279
    280280                                // attempt to remove the context so it doesn't get consumed.
  • libcfa/src/concurrency/preemption.cfa

    re5256bd r4f102fa  
    232232// available.
    233233
     234//-----------------------------------------------------------------------------
     235// Some assembly required
     236#define __cfaasm_label(label, when) when: asm volatile goto(".global __cfaasm_" #label "_" #when "\n" "__cfaasm_" #label "_" #when ":":::"memory":when)
     237
    234238//----------
    235239// special case for preemption since used often
    236 bool __preemption_enabled() libcfa_nopreempt libcfa_public {
     240__attribute__((optimize("no-reorder-blocks"))) bool __preemption_enabled() libcfa_nopreempt libcfa_public {
     241        // create a assembler label before
     242        // marked as clobber all to avoid movement
     243        __cfaasm_label(check, before);
     244
    237245        // access tls as normal
    238         return __cfaabi_tls.preemption_state.enabled;
     246        bool enabled = __cfaabi_tls.preemption_state.enabled;
     247
     248        // Check if there is a pending preemption
     249        processor   * proc = __cfaabi_tls.this_processor;
     250        bool pending = proc ? proc->pending_preemption : false;
     251        if( enabled && pending ) proc->pending_preemption = false;
     252
     253        // create a assembler label after
     254        // marked as clobber all to avoid movement
     255        __cfaasm_label(check, after);
     256
     257        // If we can preempt and there is a pending one
     258        // this is a good time to yield
     259        if( enabled && pending ) {
     260                force_yield( __POLL_PREEMPTION );
     261        }
     262        return enabled;
     263}
     264
     265struct asm_region {
     266        void * before;
     267        void * after;
     268};
     269
     270static inline bool __cfaasm_in( void * ip, struct asm_region & region ) {
     271        return ip >= region.before && ip <= region.after;
    239272}
    240273
     
    260293uintptr_t __cfatls_get( unsigned long int offset ) libcfa_nopreempt libcfa_public; //no inline to avoid problems
    261294uintptr_t __cfatls_get( unsigned long int offset ) {
     295        // create a assembler label before
     296        // marked as clobber all to avoid movement
     297        __cfaasm_label(get, before);
     298
    262299        // access tls as normal (except for pointer arithmetic)
    263300        uintptr_t val = *(uintptr_t*)((uintptr_t)&__cfaabi_tls + offset);
    264301
     302        // create a assembler label after
     303        // marked as clobber all to avoid movement
     304        __cfaasm_label(get, after);
     305
    265306        // This is used everywhere, to avoid cost, we DO NOT poll pending preemption
    266307        return val;
     
    269310extern "C" {
    270311        // Disable interrupts by incrementing the counter
    271         void disable_interrupts() libcfa_nopreempt libcfa_public with( __cfaabi_tls.preemption_state ) {
    272                 #if GCC_VERSION > 50000
    273                 static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
    274                 #endif
    275 
    276                 // Set enabled flag to false
    277                 // should be atomic to avoid preemption in the middle of the operation.
    278                 // use memory order RELAXED since there is no inter-thread on this variable requirements
    279                 __atomic_store_n(&enabled, false, __ATOMIC_RELAXED);
    280 
    281                 // Signal the compiler that a fence is needed but only for signal handlers
    282                 __atomic_signal_fence(__ATOMIC_ACQUIRE);
    283 
    284                 __attribute__((unused)) unsigned short new_val = disable_count + 1;
    285                 disable_count = new_val;
    286                 verify( new_val < 65_000u );              // If this triggers someone is disabling interrupts without enabling them
     312        void disable_interrupts() libcfa_nopreempt libcfa_public {
     313                // create a assembler label before
     314                // marked as clobber all to avoid movement
     315                __cfaasm_label(dsable, before);
     316
     317                with( __cfaabi_tls.preemption_state ) {
     318                        #if GCC_VERSION > 50000
     319                        static_assert(__atomic_always_lock_free(sizeof(enabled), &enabled), "Must be lock-free");
     320                        #endif
     321
     322                        // Set enabled flag to false
     323                        // should be atomic to avoid preemption in the middle of the operation.
     324                        // use memory order RELAXED since there is no inter-thread on this variable requirements
     325                        __atomic_store_n(&enabled, false, __ATOMIC_RELAXED);
     326
     327                        // Signal the compiler that a fence is needed but only for signal handlers
     328                        __atomic_signal_fence(__ATOMIC_ACQUIRE);
     329
     330                        __attribute__((unused)) unsigned short new_val = disable_count + 1;
     331                        disable_count = new_val;
     332                        verify( new_val < 65_000u );              // If this triggers someone is disabling interrupts without enabling them
     333                }
     334
     335                // create a assembler label after
     336                // marked as clobber all to avoid movement
     337                __cfaasm_label(dsable, after);
     338
    287339        }
    288340
     
    327379        // i.e. on a real processor and not in the kernel
    328380        // (can return true even if no preemption was pending)
    329         bool poll_interrupts() libcfa_nopreempt libcfa_public {
     381        bool poll_interrupts() libcfa_public {
    330382                // Cache the processor now since interrupts can start happening after the atomic store
    331                 processor   * proc =  __cfaabi_tls.this_processor;
     383                processor   * proc = publicTLS_get( this_processor );
    332384                if ( ! proc ) return false;
    333                 if ( ! __cfaabi_tls.preemption_state.enabled ) return false;
    334 
    335                 // Signal the compiler that a fence is needed but only for signal handlers
    336                 __atomic_signal_fence(__ATOMIC_RELEASE);
    337                 if( unlikely( proc->pending_preemption ) ) {
    338                         proc->pending_preemption = false;
    339                         force_yield( __POLL_PREEMPTION );
     385                if ( ! __preemption_enabled() ) return false;
     386
     387                with( __cfaabi_tls.preemption_state ){
     388                        // Signal the compiler that a fence is needed but only for signal handlers
     389                        __atomic_signal_fence(__ATOMIC_RELEASE);
     390                        if( proc->pending_preemption ) {
     391                                proc->pending_preemption = false;
     392                                force_yield( __POLL_PREEMPTION );
     393                        }
    340394                }
    341395
Note: See TracChangeset for help on using the changeset viewer.