Changes in / [730f4f1:4fa44e7]


Ignore:
Files:
1 added
14 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/Makefile.am

    r730f4f1 r4fa44e7  
    4848thread_headers_nosrc = concurrency/invoke.h
    4949thread_headers = concurrency/coroutine.hfa concurrency/thread.hfa concurrency/kernel.hfa concurrency/monitor.hfa concurrency/mutex.hfa
    50 thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/io.cfa concurrency/preemption.cfa ${thread_headers:.hfa=.cfa}
     50thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/io.cfa concurrency/preemption.cfa concurrency/ready_queue.cfa ${thread_headers:.hfa=.cfa}
    5151else
    5252headers =
  • libcfa/src/Makefile.in

    r730f4f1 r4fa44e7  
    166166        concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa \
    167167        concurrency/invoke.c concurrency/io.cfa \
    168         concurrency/preemption.cfa concurrency/coroutine.cfa \
    169         concurrency/thread.cfa concurrency/kernel.cfa \
    170         concurrency/monitor.cfa concurrency/mutex.cfa
     168        concurrency/preemption.cfa concurrency/ready_queue.cfa \
     169        concurrency/coroutine.cfa concurrency/thread.cfa \
     170        concurrency/kernel.cfa concurrency/monitor.cfa \
     171        concurrency/mutex.cfa
    171172@BUILDLIB_TRUE@am__objects_3 = concurrency/coroutine.lo \
    172173@BUILDLIB_TRUE@ concurrency/thread.lo concurrency/kernel.lo \
     
    176177@BUILDLIB_TRUE@ concurrency/alarm.lo concurrency/invoke.lo \
    177178@BUILDLIB_TRUE@ concurrency/io.lo concurrency/preemption.lo \
    178 @BUILDLIB_TRUE@ $(am__objects_3)
     179@BUILDLIB_TRUE@ concurrency/ready_queue.lo $(am__objects_3)
    179180am_libcfathread_la_OBJECTS = $(am__objects_4)
    180181libcfathread_la_OBJECTS = $(am_libcfathread_la_OBJECTS)
     
    477478@BUILDLIB_FALSE@thread_headers =
    478479@BUILDLIB_TRUE@thread_headers = concurrency/coroutine.hfa concurrency/thread.hfa concurrency/kernel.hfa concurrency/monitor.hfa concurrency/mutex.hfa
    479 @BUILDLIB_TRUE@thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/io.cfa concurrency/preemption.cfa ${thread_headers:.hfa=.cfa}
     480@BUILDLIB_TRUE@thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/io.cfa concurrency/preemption.cfa concurrency/ready_queue.cfa ${thread_headers:.hfa=.cfa}
    480481
    481482#----------------------------------------------------------------------------------------------------------------
     
    615616        concurrency/$(DEPDIR)/$(am__dirstamp)
    616617concurrency/preemption.lo: concurrency/$(am__dirstamp) \
     618        concurrency/$(DEPDIR)/$(am__dirstamp)
     619concurrency/ready_queue.lo: concurrency/$(am__dirstamp) \
    617620        concurrency/$(DEPDIR)/$(am__dirstamp)
    618621concurrency/coroutine.lo: concurrency/$(am__dirstamp) \
  • libcfa/src/bits/debug.hfa

    r730f4f1 r4fa44e7  
    5252                || defined(__CFA_DEBUG_PRINT_IO__) || defined(__CFA_DEBUG_PRINT_IO_CORE__) \
    5353                || defined(__CFA_DEBUG_PRINT_MONITOR__) || defined(__CFA_DEBUG_PRINT_PREEMPTION__) \
    54                 || defined(__CFA_DEBUG_PRINT_RUNTIME_CORE__) || defined(__CFA_DEBUG_PRINT_EXCEPTION__)
     54                || defined(__CFA_DEBUG_PRINT_RUNTIME_CORE__) || defined(__CFA_DEBUG_PRINT_EXCEPTION__) \
     55                || defined(__CFA_DEBUG_PRINT_READY_QUEUE__)
    5556        #include <stdio.h>
    5657        #include <unistd.h>
  • libcfa/src/bits/defs.hfa

    r730f4f1 r4fa44e7  
    5454    return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
    5555}
     56
     57// #define __CFA_NO_BIT_TEST_AND_SET__
     58
     59#if defined( __i386 )
     60static inline bool __atomic_bts(volatile unsigned long int * target, unsigned long int bit ) {
     61        #if defined(__CFA_NO_BIT_TEST_AND_SET__)
     62        unsigned long int mask = 1ul << bit;
     63        unsigned long int ret = __atomic_fetch_or(target, mask, (int)__ATOMIC_RELAXED);
     64        return (ret & mask) != 0;
     65    #else
     66        int result = 0;
     67        asm volatile(
     68            "LOCK btsl %[bit], %[target]\n\t"
     69            : "=@ccc" (result)
     70            : [target] "m" (*target), [bit] "r" (bit)
     71        );
     72        return result != 0;
     73    #endif
     74}
     75
     76static inline bool __atomic_btr(volatile unsigned long int * target, unsigned long int bit ) {
     77        #if defined(__CFA_NO_BIT_TEST_AND_SET__)
     78        unsigned long int mask = 1ul << bit;
     79        unsigned long int ret = __atomic_fetch_and(target, ~mask, (int)__ATOMIC_RELAXED);
     80        return (ret & mask) != 0;
     81        #else
     82        int result = 0;
     83        asm volatile(
     84            "LOCK btrl %[bit], %[target]\n\t"
     85            :"=@ccc" (result)
     86            : [target] "m" (*target), [bit] "r" (bit)
     87        );
     88        return result != 0;
     89    #endif
     90}
     91#elif defined( __x86_64 )
     92static inline bool __atomic_bts(volatile unsigned long long int * target, unsigned long long int bit ) {
     93        #if defined(__CFA_NO_BIT_TEST_AND_SET__)
     94        unsigned long long int mask = 1ul << bit;
     95        unsigned long long int ret = __atomic_fetch_or(target, mask, (int)__ATOMIC_RELAXED);
     96        return (ret & mask) != 0;
     97    #else
     98        int result = 0;
     99        asm volatile(
     100            "LOCK btsq %[bit], %[target]\n\t"
     101            : "=@ccc" (result)
     102            : [target] "m" (*target), [bit] "r" (bit)
     103        );
     104        return result != 0;
     105    #endif
     106}
     107
     108static inline bool __atomic_btr(volatile unsigned long long int * target, unsigned long long int bit ) {
     109        #if defined(__CFA_NO_BIT_TEST_AND_SET__)
     110        unsigned long long int mask = 1ul << bit;
     111        unsigned long long int ret = __atomic_fetch_and(target, ~mask, (int)__ATOMIC_RELAXED);
     112        return (ret & mask) != 0;
     113        #else
     114        int result = 0;
     115        asm volatile(
     116            "LOCK btrq %[bit], %[target]\n\t"
     117            :"=@ccc" (result)
     118            : [target] "m" (*target), [bit] "r" (bit)
     119        );
     120        return result != 0;
     121    #endif
     122}
     123#elif defined( __ARM_ARCH )
     124    #error __atomic_bts and __atomic_btr not implemented for arm
     125#else
     126        #error uknown hardware architecture
     127#endif
  • libcfa/src/concurrency/invoke.h

    r730f4f1 r4fa44e7  
    161161        };
    162162
     163        // Link lists fields
     164        // instrusive link field for threads
     165        struct __thread_desc_link {
     166                struct $thread * next;
     167                struct $thread * prev;
     168                unsigned long long ts;
     169        };
     170
    163171        struct $thread {
    164172                // Core threading fields
     
    192200                // Link lists fields
    193201                // instrusive link field for threads
    194                 struct $thread * next;
     202                struct __thread_desc_link link;
    195203
    196204                struct {
     
    218226        #ifdef __cforall
    219227        extern "Cforall" {
     228
    220229                static inline $thread *& get_next( $thread & this ) __attribute__((const)) {
    221                         return this.next;
     230                        return this.link.next;
    222231                }
    223232
  • libcfa/src/concurrency/kernel.cfa

    r730f4f1 r4fa44e7  
    120120static void __run_thread(processor * this, $thread * dst);
    121121static $thread * __halt(processor * this);
    122 static bool __wake_one(cluster * cltr, bool was_empty);
     122static bool __wake_one(cluster * cltr);
    123123static bool __wake_proc(processor *);
    124124
     
    197197        self_mon.recursion = 1;
    198198        self_mon_p = &self_mon;
    199         next = 0p;
     199        link.next = 0p;
     200        link.prev = 0p;
    200201
    201202        node.next = 0p;
     
    223224        this.name = name;
    224225        this.cltr = &cltr;
     226        id = -1u;
    225227        terminated{ 0 };
    226228        destroyer = 0p;
     
    260262        this.preemption_rate = preemption_rate;
    261263        ready_queue{};
    262         ready_queue_lock{};
     264        ready_lock{};
    263265
    264266        #if !defined(__CFA_NO_STATISTICS__)
     
    295297        __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this);
    296298
     299        // register the processor unless it's the main thread which is handled in the boot sequence
     300        if(this != mainProcessor) {
     301                this->id = doregister2(this->cltr, this);
     302                ready_queue_grow( this->cltr );
     303        }
     304
    297305        doregister(this->cltr, this);
    298306
     
    318326                                /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    319327                                /* paranoid */ verifyf( readyThread->state == Ready || readyThread->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", readyThread->state, readyThread->preempted);
    320                                 /* paranoid */ verifyf( readyThread->next == 0p, "Expected null got %p", readyThread->next );
     328                                /* paranoid */ verifyf( readyThread->link.next == 0p, "Expected null got %p", readyThread->link.next );
    321329
    322330                                // We found a thread run it
     
    334342        V( this->terminated );
    335343
     344        // unregister the processor unless it's the main thread which is handled in the boot sequence
     345        if(this != mainProcessor) {
     346                ready_queue_shrink( this->cltr );
     347                unregister2(this->cltr, this);
     348        }
     349        else {
     350                // HACK : the coroutine context switch expects this_thread to be set
     351                // and it make sense for it to be set in all other cases except here
     352                // fake it
     353                kernelTLS.this_thread = mainThread;
     354        }
     355
    336356        __cfadbg_print_safe(runtime_core, "Kernel : core %p terminated\n", this);
    337357
    338         // HACK : the coroutine context switch expects this_thread to be set
    339         // and it make sense for it to be set in all other cases except here
    340         // fake it
    341         if( this == mainProcessor ) kernelTLS.this_thread = mainThread;
     358        stats_tls_tally(this->cltr);
    342359}
    343360
     
    591608// Scheduler routines
    592609// KERNEL ONLY
    593 void __schedule_thread( $thread * thrd ) with( *thrd->curr_cluster ) {
     610void __schedule_thread( $thread * thrd ) {
     611        /* paranoid */ verify( thrd );
     612        /* paranoid */ verify( thrd->state != Halted );
    594613        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    595614        /* paranoid */ #if defined( __CFA_WITH_VERIFY__ )
    596         /* paranoid */ if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION,
    597                           "Error inactive thread marked as preempted, state %d, preemption %d\n", thrd->state, thrd->preempted );
    598         /* paranoid */ if( thrd->preempted != __NO_PREEMPTION ) assertf(thrd->state == Active || thrd->state == Rerun,
    599                           "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted );
     615        /* paranoid */  if( thrd->state == Blocked || thrd->state == Start ) assertf( thrd->preempted == __NO_PREEMPTION,
     616                                        "Error inactive thread marked as preempted, state %d, preemption %d\n", thrd->state, thrd->preempted );
     617        /* paranoid */  if( thrd->preempted != __NO_PREEMPTION ) assertf(thrd->state == Active || thrd->state == Rerun,
     618                                        "Error preempted thread marked as not currently running, state %d, preemption %d\n", thrd->state, thrd->preempted );
    600619        /* paranoid */ #endif
    601         /* paranoid */ verifyf( thrd->next == 0p, "Expected null got %p", thrd->next );
     620        /* paranoid */ verifyf( thrd->link.next == 0p, "Expected null got %p", thrd->link.next );
    602621
    603622        if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready;
    604623
    605         lock  ( ready_queue_lock __cfaabi_dbg_ctx2 );
    606         bool was_empty = !(ready_queue != 0);
    607         append( ready_queue, thrd );
    608         unlock( ready_queue_lock );
    609 
    610         __wake_one(thrd->curr_cluster, was_empty);
     624        ready_schedule_lock(thrd->curr_cluster, kernelTLS.this_processor);
     625                push( thrd->curr_cluster, thrd );
     626
     627                __wake_one(thrd->curr_cluster);
     628        ready_schedule_unlock(thrd->curr_cluster, kernelTLS.this_processor);
    611629
    612630        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     
    617635        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    618636
    619         lock( ready_queue_lock __cfaabi_dbg_ctx2 );
    620         $thread * head = pop_head( ready_queue );
    621         unlock( ready_queue_lock );
     637        ready_schedule_lock(this, kernelTLS.this_processor);
     638                $thread * head = pop( this );
     639        ready_schedule_unlock(this, kernelTLS.this_processor);
    622640
    623641        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     
    703721        // If that is the case, abandon the preemption.
    704722        bool preempted = false;
    705         if(thrd->next == 0p) {
     723        if(thrd->link.next == 0p) {
    706724                preempted = true;
    707725                thrd->preempted = reason;
     
    763781                pending_preemption = false;
    764782                kernel_thread = pthread_self();
     783                id = -1u;
    765784
    766785                runner{ &this };
     
    772791        mainProcessor = (processor *)&storage_mainProcessor;
    773792        (*mainProcessor){};
     793
     794        mainProcessor->id = doregister2(mainCluster, mainProcessor);
    774795
    775796        //initialize the global state variables
     
    826847        kernel_stop_preemption();
    827848
     849        unregister2(mainCluster, mainProcessor);
     850
    828851        // Destroy the main processor and its context in reverse order of construction
    829852        // These were manually constructed so we need manually destroy them
    830853        void ^?{}(processor & this) with( this ){
    831854                /* paranoid */ verify( this.do_terminate == true );
     855                __cfaabi_dbg_print_safe("Kernel : destroyed main processor context %p\n", &runner);
    832856        }
    833857
     
    835859
    836860        // Final step, destroy the main thread since it is no longer needed
     861
    837862        // Since we provided a stack to this taxk it will not destroy anything
    838863        /* paranoid */ verify(mainThread->self_cor.stack.storage == (__stack_t*)(((uintptr_t)&storage_mainThreadCtx)| 0x1));
     
    887912
    888913// Wake a thread from the front if there are any
    889 static bool __wake_one(cluster * this, __attribute__((unused)) bool force) {
    890         // if we don't want to force check if we know it's false
    891         // if( !this->idles.head && !force ) return false;
    892 
     914static bool __wake_one(cluster * this) {
    893915        // First, lock the cluster idle
    894916        lock( this->idle_lock __cfaabi_dbg_ctx2 );
  • libcfa/src/concurrency/kernel.hfa

    r730f4f1 r4fa44e7  
    6060        // Cluster from which to get threads
    6161        struct cluster * cltr;
     62        unsigned int id;
    6263
    6364        // Name of the processor
     
    9293
    9394        // Link lists fields
    94         struct __dbg_node_proc {
    95                 struct processor * next;
    96                 struct processor * prev;
     95        struct __dbg_node_cltr {
     96                processor * next;
     97                processor * prev;
    9798        } node;
    9899
     
    119120// #define CFA_CLUSTER_IO_POLLER_KERNEL_SIDE 1 << 1
    120121
     122
     123//-----------------------------------------------------------------------------
     124// Cluster Tools
     125
     126// Cells use by the reader writer lock
     127// while not generic it only relies on a opaque pointer
     128struct __processor_id;
     129
     130// Reader-Writer lock protecting the ready-queue
     131// while this lock is mostly generic some aspects
     132// have been hard-coded to for the ready-queue for
     133// simplicity and performance
     134struct __clusterRWLock_t {
     135        // total cachelines allocated
     136        unsigned int max;
     137
     138        // cachelines currently in use
     139        volatile unsigned int alloc;
     140
     141        // cachelines ready to itereate over
     142        // (!= to alloc when thread is in second half of doregister)
     143        volatile unsigned int ready;
     144
     145        // writer lock
     146        volatile bool lock;
     147
     148        // data pointer
     149        __processor_id * data;
     150};
     151
     152void  ?{}(__clusterRWLock_t & this);
     153void ^?{}(__clusterRWLock_t & this);
     154
     155// Intrusives lanes which are used by the relaxed ready queue
     156struct __attribute__((aligned(128))) __intrusive_lane_t {
     157        // spin lock protecting the queue
     158        volatile bool lock;
     159
     160        // anchor for the head and the tail of the queue
     161        struct __sentinel_t {
     162                // Link lists fields
     163                // instrusive link field for threads
     164                // must be exactly as in $thread
     165                __thread_desc_link link;
     166        } before, after;
     167
     168#if defined(__CFA_WITH_VERIFY__)
     169        // id of last processor to acquire the lock
     170        // needed only to check for mutual exclusion violations
     171        unsigned int last_id;
     172
     173        // number of items on this list
     174        // needed only to check for deadlocks
     175        unsigned int count;
     176#endif
     177
     178        // Optional statistic counters
     179        #if !defined(__CFA_NO_SCHED_STATS__)
     180                struct __attribute__((aligned(64))) {
     181                        // difference between number of push and pops
     182                        ssize_t diff;
     183
     184                        // total number of pushes and pops
     185                        size_t  push;
     186                        size_t  pop ;
     187                } stat;
     188        #endif
     189};
     190
     191void  ?{}(__intrusive_lane_t & this);
     192void ^?{}(__intrusive_lane_t & this);
     193
     194typedef unsigned long long __cfa_readyQ_mask_t;
     195
     196// enum {
     197//      __cfa_ready_queue_mask_size = (64 - sizeof(size_t)) / sizeof(size_t),
     198//      __cfa_max_ready_queues = __cfa_ready_queue_mask_size * 8 * sizeof(size_t)
     199// };
     200
     201#define __cfa_lane_mask_size ((64 - sizeof(size_t)) / sizeof(__cfa_readyQ_mask_t))
     202#define __cfa_max_lanes (__cfa_lane_mask_size * 8 * sizeof(__cfa_readyQ_mask_t))
     203
     204//TODO adjust cache size to ARCHITECTURE
     205// Structure holding the relaxed ready queue
     206struct __attribute__((aligned(128))) __ready_queue_t {
     207        // Data tracking how many/which lanes are used
     208        // Aligned to 128 for cache locality
     209        struct {
     210                // number of non-empty lanes
     211                volatile size_t count;
     212
     213                // bit mask, set bits indentify which lanes are non-empty
     214                volatile __cfa_readyQ_mask_t mask[ __cfa_lane_mask_size ];
     215        } used;
     216
     217        // Data tracking the actual lanes
     218        // On a seperate cacheline from the used struct since
     219        // used can change on each push/pop but this data
     220        // only changes on shrink/grow
     221        struct __attribute__((aligned(64))) {
     222                // Arary of lanes
     223                __intrusive_lane_t * volatile data;
     224
     225                // Number of lanes (empty or not)
     226                volatile size_t count;
     227        } lanes;
     228
     229        // Statistics
     230        #if !defined(__CFA_NO_STATISTICS__)
     231                __attribute__((aligned(64))) struct {
     232                        struct {
     233                                // Push statistic
     234                                struct {
     235                                        // number of attemps at pushing something
     236                                        volatile size_t attempt;
     237
     238                                        // number of successes at pushing
     239                                        volatile size_t success;
     240                                } push;
     241
     242                                // Pop statistic
     243                                struct {
     244                                        // number of reads of the mask
     245                                        // picking an empty __cfa_readyQ_mask_t counts here
     246                                        // but not as an attempt
     247                                        volatile size_t maskrds;
     248
     249                                        // number of attemps at poping something
     250                                        volatile size_t attempt;
     251
     252                                        // number of successes at poping
     253                                        volatile size_t success;
     254                                } pop;
     255                        } pick;
     256
     257                        // stats on the "used" struct of the queue
     258                        // tracks average number of queues that are not empty
     259                        // when pushing / poping
     260                        struct {
     261                                volatile size_t value;
     262                                volatile size_t count;
     263                        } used;
     264                } global_stats;
     265
     266        #endif
     267};
     268
     269void  ?{}(__ready_queue_t & this);
     270void ^?{}(__ready_queue_t & this);
     271
    121272//-----------------------------------------------------------------------------
    122273// Cluster
    123274struct cluster {
    124275        // Ready queue locks
    125         __spinlock_t ready_queue_lock;
     276        __clusterRWLock_t ready_lock;
    126277
    127278        // Ready queue for threads
    128         __queue_t($thread) ready_queue;
     279        __ready_queue_t ready_queue;
    129280
    130281        // Name of the cluster
  • libcfa/src/concurrency/kernel_private.hfa

    r730f4f1 r4fa44e7  
    8484//-----------------------------------------------------------------------------
    8585// Utils
    86 #define KERNEL_STORAGE(T,X) static char storage_##X[sizeof(T)]
     86#define KERNEL_STORAGE(T,X) __attribute((aligned(__alignof__(T)))) static char storage_##X[sizeof(T)]
    8787
    8888static inline uint32_t __tls_rand() {
     
    103103void unregister( struct cluster * cltr, struct processor * proc );
    104104
     105//=======================================================================
     106// Cluster lock API
     107//=======================================================================
     108struct __attribute__((aligned(64))) __processor_id {
     109        processor * volatile handle;
     110        volatile bool lock;
     111};
     112
     113// Lock-Free registering/unregistering of threads
     114// Register a processor to a given cluster and get its unique id in return
     115unsigned doregister2( struct cluster * cltr, struct processor * proc );
     116
     117// Unregister a processor from a given cluster using its id, getting back the original pointer
     118void     unregister2( struct cluster * cltr, struct processor * proc );
     119
     120//=======================================================================
     121// Reader-writer lock implementation
     122// Concurrent with doregister/unregister,
     123//    i.e., threads can be added at any point during or between the entry/exit
     124
     125//-----------------------------------------------------------------------
     126// simple spinlock underlying the RWLock
     127// Blocking acquire
     128static inline void __atomic_acquire(volatile bool * ll) {
     129        while( __builtin_expect(__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST), false) ) {
     130                while(__atomic_load_n(ll, (int)__ATOMIC_RELAXED))
     131                        asm volatile("pause");
     132        }
     133        /* paranoid */ verify(*ll);
     134}
     135
     136// Non-Blocking acquire
     137static inline bool __atomic_try_acquire(volatile bool * ll) {
     138        return !__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST);
     139}
     140
     141// Release
     142static inline void __atomic_unlock(volatile bool * ll) {
     143        /* paranoid */ verify(*ll);
     144        __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE);
     145}
     146
     147//-----------------------------------------------------------------------
     148// Reader side : acquire when using the ready queue to schedule but not
     149//  creating/destroying queues
     150static inline void ready_schedule_lock( struct cluster * cltr, struct processor * proc) with(cltr->ready_lock) {
     151        unsigned iproc = proc->id;
     152        /*paranoid*/ verify(data[iproc].handle == proc);
     153        /*paranoid*/ verify(iproc < ready);
     154
     155        // Step 1 : make sure no writer are in the middle of the critical section
     156        while(__atomic_load_n(&lock, (int)__ATOMIC_RELAXED))
     157                asm volatile("pause");
     158
     159        // Fence needed because we don't want to start trying to acquire the lock
     160        // before we read a false.
     161        // Not needed on x86
     162        // std::atomic_thread_fence(std::memory_order_seq_cst);
     163
     164        // Step 2 : acquire our local lock
     165        __atomic_acquire( &data[iproc].lock );
     166        /*paranoid*/ verify(data[iproc].lock);
     167}
     168
     169static inline void ready_schedule_unlock( struct cluster * cltr, struct processor * proc) with(cltr->ready_lock) {
     170        unsigned iproc = proc->id;
     171        /*paranoid*/ verify(data[iproc].handle == proc);
     172        /*paranoid*/ verify(iproc < ready);
     173        /*paranoid*/ verify(data[iproc].lock);
     174        __atomic_unlock(&data[iproc].lock);
     175}
     176
     177//-----------------------------------------------------------------------
     178// Writer side : acquire when changing the ready queue, e.g. adding more
     179//  queues or removing them.
     180uint_fast32_t ready_mutate_lock( struct cluster & cltr );
     181
     182void ready_mutate_unlock( struct cluster & cltr, uint_fast32_t /* value returned by lock */ );
     183
     184//=======================================================================
     185// Ready-Queue API
     186//-----------------------------------------------------------------------
     187// push thread onto a ready queue for a cluster
     188// returns true if the list was previously empty, false otherwise
     189__attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd);
     190
     191//-----------------------------------------------------------------------
     192// pop thread from the ready queue of a cluster
     193// returns 0p if empty
     194__attribute__((hot)) struct $thread * pop(struct cluster * cltr);
     195
     196//-----------------------------------------------------------------------
     197// Increase the width of the ready queue (number of lanes) by 4
     198void ready_queue_grow  (struct cluster * cltr);
     199
     200//-----------------------------------------------------------------------
     201// Decrease the width of the ready queue (number of lanes) by 4
     202void ready_queue_shrink(struct cluster * cltr);
     203
     204//-----------------------------------------------------------------------
     205// Statics call at the end of each thread to register statistics
     206#if !defined(__CFA_NO_STATISTICS__)
     207void stats_tls_tally(struct cluster * cltr);
     208#else
     209static inline void stats_tls_tally(struct cluster * cltr) {}
     210#endif
     211
    105212// Local Variables: //
    106213// mode: c //
  • libcfa/src/concurrency/monitor.cfa

    r730f4f1 r4fa44e7  
    114114
    115115                // Some one else has the monitor, wait in line for it
    116                 /* paranoid */ verify( thrd->next == 0p );
     116                /* paranoid */ verify( thrd->link.next == 0p );
    117117                append( this->entry_queue, thrd );
    118                 /* paranoid */ verify( thrd->next == 1p );
     118                /* paranoid */ verify( thrd->link.next == 1p );
    119119
    120120                unlock( this->lock );
     
    199199
    200200                // Some one else has the monitor, wait in line for it
    201                 /* paranoid */ verify( thrd->next == 0p );
     201                /* paranoid */ verify( thrd->link.next == 0p );
    202202                append( this->entry_queue, thrd );
    203                 /* paranoid */ verify( thrd->next == 1p );
     203                /* paranoid */ verify( thrd->link.next == 1p );
    204204                unlock( this->lock );
    205205
     
    761761        $thread * new_owner = pop_head( this->entry_queue );
    762762        /* paranoid */ verifyf( !this->owner || kernelTLS.this_thread == this->owner, "Expected owner to be %p, got %p (r: %i, m: %p)", kernelTLS.this_thread, this->owner, this->recursion, this );
    763         /* paranoid */ verify( !new_owner || new_owner->next == 0p );
     763        /* paranoid */ verify( !new_owner || new_owner->link.next == 0p );
    764764        __set_owner( this, new_owner );
    765765
     
    883883        }
    884884
    885         __cfaabi_dbg_print_safe( "Kernel :  Runing %i (%p)\n", ready2run, ready2run ? node->waiting_thread : 0p );
     885        __cfaabi_dbg_print_safe( "Kernel :  Runing %i (%p)\n", ready2run, ready2run ? (thread*)node->waiting_thread : (thread*)0p );
    886886        return ready2run ? node->waiting_thread : 0p;
    887887}
     
    907907        // For each thread in the entry-queue
    908908        for(    $thread ** thrd_it = &entry_queue.head;
    909                 *thrd_it != 1p;
    910                 thrd_it = &(*thrd_it)->next
     909                *thrd_it;
     910                thrd_it = &(*thrd_it)->link.next
    911911        ) {
    912912                // For each acceptable check if it matches
  • libcfa/src/concurrency/preemption.cfa

    r730f4f1 r4fa44e7  
    121121        // If there are still alarms pending, reset the timer
    122122        if( & (*alarms)`first ) {
    123                 __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                __cfadbg_print_buffer_decl(preemption, " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);
    124124                Duration delta = (*alarms)`first.alarm - currtime;
    125125                Duration capped = max(delta, 50`us);
  • libcfa/src/concurrency/thread.cfa

    r730f4f1 r4fa44e7  
    3535        self_mon_p = &self_mon;
    3636        curr_cluster = &cl;
    37         next = 0p;
     37        link.next = 0p;
     38        link.prev = 0p;
    3839
    3940        node.next = 0p;
  • libcfa/src/stdhdr/assert.h

    r730f4f1 r4fa44e7  
    3333        #define verify(x) assert(x)
    3434        #define verifyf(x, ...) assertf(x, __VA_ARGS__)
     35        #define verifyfail(...)
    3536        #define __CFA_WITH_VERIFY__
    3637#else
    3738        #define verify(x)
    3839        #define verifyf(x, ...)
     40        #define verifyfail(...)
    3941#endif
    4042
  • tests/concurrent/examples/datingService.cfa

    r730f4f1 r4fa44e7  
    3535                signal_block( Boys[ccode] );                                    // restart boy to set phone number
    3636        } // if
    37         //sout | "Girl:" | PhoneNo | "is dating Boy at" | BoyPhoneNo | "with ccode" | ccode;
     37        // sout | "Girl:" | PhoneNo | "is dating Boy at" | BoyPhoneNo | "with ccode" | ccode;
    3838        return BoyPhoneNo;
    3939} // DatingService girl
     
    4747                signal_block( Girls[ccode] );                                   // restart girl to set phone number
    4848        } // if
    49         //sout | " Boy:" | PhoneNo | "is dating Girl" | GirlPhoneNo | "with ccode" | ccode;
     49        // sout | " Boy:" | PhoneNo | "is dating Girl" | GirlPhoneNo | "with ccode" | ccode;
    5050        return GirlPhoneNo;
    5151} // DatingService boy
  • tests/concurrent/waitfor/when.cfa

    r730f4f1 r4fa44e7  
    5757
    5858void arbiter( global_t & mutex this ) {
     59        // There is a race at start where callers can get in before the arbiter.
     60        // It doesn't really matter here so just restart the loop correctly and move on
     61        this.last_call = 6;
     62
    5963        for( int i = 0; i < N; i++ ) {
    6064                   when( this.last_call == 6 ) waitfor( call1 : this ) { if( this.last_call != 1) { serr | "Expected last_call to be 1 got" | this.last_call; } }
Note: See TracChangeset for help on using the changeset viewer.