Changes in / [b7d6a36:2cbfe92]
- Files:
-
- 1 deleted
- 15 edited
-
libcfa/src/Makefile.am (modified) (1 diff)
-
libcfa/src/Makefile.in (modified) (4 diffs)
-
libcfa/src/bits/debug.hfa (modified) (2 diffs)
-
libcfa/src/bits/defs.hfa (modified) (1 diff)
-
libcfa/src/concurrency/invoke.h (modified) (3 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (12 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (3 diffs)
-
libcfa/src/concurrency/kernel_private.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/monitor.cfa (modified) (2 diffs)
-
libcfa/src/concurrency/preemption.cfa (modified) (1 diff)
-
libcfa/src/concurrency/ready_queue.cfa (deleted)
-
libcfa/src/concurrency/thread.cfa (modified) (1 diff)
-
libcfa/src/stdhdr/assert.h (modified) (1 diff)
-
tests/concurrent/examples/.expect/datingService.txt (modified) (1 diff)
-
tests/concurrent/examples/datingService.cfa (modified) (3 diffs)
-
tests/concurrent/waitfor/when.cfa (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/Makefile.am
rb7d6a36 r2cbfe92 48 48 thread_headers_nosrc = concurrency/invoke.h 49 49 thread_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/preemption.cfa concurrency/ready_queue.cfa${thread_headers:.hfa=.cfa}50 thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/preemption.cfa ${thread_headers:.hfa=.cfa} 51 51 else 52 52 headers = -
libcfa/src/Makefile.in
rb7d6a36 r2cbfe92 165 165 concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa \ 166 166 concurrency/invoke.c concurrency/preemption.cfa \ 167 concurrency/ ready_queue.cfa concurrency/coroutine.cfa \168 concurrency/ thread.cfa concurrency/kernel.cfa \169 concurrency/m onitor.cfa concurrency/mutex.cfa167 concurrency/coroutine.cfa concurrency/thread.cfa \ 168 concurrency/kernel.cfa concurrency/monitor.cfa \ 169 concurrency/mutex.cfa 170 170 @BUILDLIB_TRUE@am__objects_3 = concurrency/coroutine.lo \ 171 171 @BUILDLIB_TRUE@ concurrency/thread.lo concurrency/kernel.lo \ … … 174 174 @BUILDLIB_TRUE@ concurrency/CtxSwitch-@ARCHITECTURE@.lo \ 175 175 @BUILDLIB_TRUE@ concurrency/alarm.lo concurrency/invoke.lo \ 176 @BUILDLIB_TRUE@ concurrency/preemption.lo \ 177 @BUILDLIB_TRUE@ concurrency/ready_queue.lo $(am__objects_3) 176 @BUILDLIB_TRUE@ concurrency/preemption.lo $(am__objects_3) 178 177 am_libcfathread_la_OBJECTS = $(am__objects_4) 179 178 libcfathread_la_OBJECTS = $(am_libcfathread_la_OBJECTS) … … 471 470 @BUILDLIB_FALSE@thread_headers = 472 471 @BUILDLIB_TRUE@thread_headers = concurrency/coroutine.hfa concurrency/thread.hfa concurrency/kernel.hfa concurrency/monitor.hfa concurrency/mutex.hfa 473 @BUILDLIB_TRUE@thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/preemption.cfa concurrency/ready_queue.cfa${thread_headers:.hfa=.cfa}472 @BUILDLIB_TRUE@thread_libsrc = concurrency/CtxSwitch-@ARCHITECTURE@.S concurrency/alarm.cfa concurrency/invoke.c concurrency/preemption.cfa ${thread_headers:.hfa=.cfa} 474 473 475 474 #---------------------------------------------------------------------------------------------------------------- … … 607 606 concurrency/$(DEPDIR)/$(am__dirstamp) 608 607 concurrency/preemption.lo: concurrency/$(am__dirstamp) \ 609 concurrency/$(DEPDIR)/$(am__dirstamp)610 concurrency/ready_queue.lo: concurrency/$(am__dirstamp) \611 608 concurrency/$(DEPDIR)/$(am__dirstamp) 612 609 concurrency/coroutine.lo: concurrency/$(am__dirstamp) \ -
libcfa/src/bits/debug.hfa
rb7d6a36 r2cbfe92 37 37 #include <stdarg.h> 38 38 #include <stdio.h> 39 #include <unistd.h>40 39 41 40 extern void __cfaabi_bits_write( int fd, const char buffer[], int len ); … … 50 49 #endif 51 50 52 // #define __CFA_DEBUG_PRINT__53 54 51 #ifdef __CFA_DEBUG_PRINT__ 55 52 #define __cfaabi_dbg_write( buffer, len ) __cfaabi_bits_write( STDERR_FILENO, buffer, len ) 56 53 #define __cfaabi_dbg_acquire() __cfaabi_bits_acquire() 57 54 #define __cfaabi_dbg_release() __cfaabi_bits_release() 58 #define __cfaabi_dbg_print_safe(...) __cfaabi_bits_print_safe ( STDERR_FILENO, __VA_ARGS__)59 #define __cfaabi_dbg_print_nolock(...) __cfaabi_bits_print_nolock ( STDERR_FILENO, __VA_ARGS__)60 #define __cfaabi_dbg_print_buffer(...) __cfaabi_bits_print_buffer ( STDERR_FILENO, __VA_ARGS__)61 #define __cfaabi_dbg_print_buffer_decl(...) char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( STDERR_FILENO,__dbg_text, __dbg_len );62 #define __cfaabi_dbg_print_buffer_local(...) __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_ bits_write( STDERR_FILENO,__dbg_text, __dbg_len );55 #define __cfaabi_dbg_print_safe(...) __cfaabi_bits_print_safe (__VA_ARGS__) 56 #define __cfaabi_dbg_print_nolock(...) __cfaabi_bits_print_nolock (__VA_ARGS__) 57 #define __cfaabi_dbg_print_buffer(...) __cfaabi_bits_print_buffer (__VA_ARGS__) 58 #define __cfaabi_dbg_print_buffer_decl(...) char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( __dbg_text, __dbg_len ); 59 #define __cfaabi_dbg_print_buffer_local(...) __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_dbg_write( __dbg_text, __dbg_len ); 63 60 #else 64 61 #define __cfaabi_dbg_write(...) ((void)0) -
libcfa/src/bits/defs.hfa
rb7d6a36 r2cbfe92 54 54 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 55 55 } 56 57 // #define __CFA_NO_BIT_TEST_AND_SET__58 59 #if defined( __i386 )60 static 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 #else66 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 #endif74 }75 76 static 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 #else82 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 #endif90 }91 #elif defined( __x86_64 )92 static 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 #else98 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 #endif106 }107 108 static 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 #else114 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 #endif122 }123 #elif defined( __ARM_ARCH )124 #error __atomic_bts and __atomic_btr not implemented for arm125 #else126 #error uknown hardware architecture127 #endif -
libcfa/src/concurrency/invoke.h
rb7d6a36 r2cbfe92 158 158 }; 159 159 160 // Link lists fields161 // instrusive link field for threads162 struct __thread_desc_link {163 struct thread_desc * next;164 struct thread_desc * prev;165 unsigned long long ts;166 };167 168 160 struct thread_desc { 169 161 // Core threading fields … … 196 188 // Link lists fields 197 189 // instrusive link field for threads 198 struct __thread_desc_link link;190 struct thread_desc * next; 199 191 200 192 struct { … … 207 199 extern "Cforall" { 208 200 static inline thread_desc *& get_next( thread_desc & this ) { 209 return this. link.next;201 return this.next; 210 202 } 211 203 -
libcfa/src/concurrency/kernel.cfa
rb7d6a36 r2cbfe92 187 187 self_mon.recursion = 1; 188 188 self_mon_p = &self_mon; 189 link.next = 0p; 190 link.prev = 0p; 189 next = 0p; 191 190 192 191 node.next = 0p; … … 213 212 this.name = name; 214 213 this.cltr = &cltr; 215 id = -1u;216 214 terminated{ 0 }; 217 215 do_terminate = false; … … 244 242 this.preemption_rate = preemption_rate; 245 243 ready_queue{}; 246 ready_lock{}; 247 244 ready_queue_lock{}; 245 246 procs{ __get }; 248 247 idles{ __get }; 249 248 threads{ __get }; … … 274 273 __cfaabi_dbg_print_safe("Kernel : core %p starting\n", this); 275 274 276 // register the processor unless it's the main thread which is handled in the boot sequence 277 if(this != mainProcessor) { 278 this->id = doregister(this->cltr, this); 279 ready_queue_grow( this->cltr ); 280 } 281 275 doregister(this->cltr, this); 282 276 283 277 { … … 311 305 } 312 306 307 unregister(this->cltr, this); 308 313 309 V( this->terminated ); 314 310 315 316 // unregister the processor unless it's the main thread which is handled in the boot sequence317 if(this != mainProcessor) {318 ready_queue_shrink( this->cltr );319 unregister(this->cltr, this);320 }321 322 311 __cfaabi_dbg_print_safe("Kernel : core %p terminated\n", this); 323 324 stats_tls_tally(this->cltr);325 312 } 326 313 … … 551 538 verify( ! kernelTLS.preemption_state.enabled ); 552 539 553 verifyf( thrd->link.next == 0p, "Expected null got %p", thrd->link.next ); 554 555 556 ready_schedule_lock(thrd->curr_cluster, kernelTLS.this_processor); 557 bool was_empty = push( thrd->curr_cluster, thrd ); 558 ready_schedule_unlock(thrd->curr_cluster, kernelTLS.this_processor); 540 verifyf( thrd->next == 0p, "Expected null got %p", thrd->next ); 559 541 560 542 with( *thrd->curr_cluster ) { 561 // if(was_empty) { 562 // lock (proc_list_lock __cfaabi_dbg_ctx2); 563 // if(idles) { 564 // wake_fast(idles.head); 565 // } 566 // unlock (proc_list_lock); 567 // } 568 // else if( struct processor * idle = idles.head ) { 569 // wake_fast(idle); 570 // } 543 lock ( ready_queue_lock __cfaabi_dbg_ctx2 ); 544 bool was_empty = !(ready_queue != 0); 545 append( ready_queue, thrd ); 546 unlock( ready_queue_lock ); 547 548 if(was_empty) { 549 lock (proc_list_lock __cfaabi_dbg_ctx2); 550 if(idles) { 551 wake_fast(idles.head); 552 } 553 unlock (proc_list_lock); 554 } 555 else if( struct processor * idle = idles.head ) { 556 wake_fast(idle); 557 } 558 571 559 } 572 560 … … 577 565 thread_desc * nextThread(cluster * this) with( *this ) { 578 566 verify( ! kernelTLS.preemption_state.enabled ); 579 580 ready_schedule_lock(this, kernelTLS.this_processor); 581 thread_desc * head = pop( this ); 582 ready_schedule_unlock(this, kernelTLS.this_processor); 583 567 lock( ready_queue_lock __cfaabi_dbg_ctx2 ); 568 thread_desc * head = pop_head( ready_queue ); 569 unlock( ready_queue_lock ); 584 570 verify( ! kernelTLS.preemption_state.enabled ); 585 571 return head; … … 743 729 pending_preemption = false; 744 730 kernel_thread = pthread_self(); 745 id = -1u;746 731 747 732 runner{ &this }; … … 753 738 mainProcessor = (processor *)&storage_mainProcessor; 754 739 (*mainProcessor){}; 755 756 mainProcessor->id = doregister(mainCluster, mainProcessor);757 740 758 741 //initialize the global state variables … … 801 784 kernel_stop_preemption(); 802 785 803 unregister(mainCluster, mainProcessor);804 805 786 // Destroy the main processor and its context in reverse order of construction 806 787 // These were manually constructed so we need manually destroy them 807 void ^?{}(processor & this) with( this ) { 808 //don't join the main thread here, that wouldn't make any sense 809 __cfaabi_dbg_print_safe("Kernel : destroyed main processor context %p\n", &runner); 810 } 811 812 ^(*mainProcessor){}; 788 ^(mainProcessor->runner){}; 789 ^(mainProcessor){}; 813 790 814 791 // Final step, destroy the main thread since it is no longer needed 815 // Since we provided a stack to this task it will not destroy anything 816 ^(*mainThread){}; 817 818 ^(*mainCluster){}; 792 // Since we provided a stack to this taxk it will not destroy anything 793 ^(mainThread){}; 819 794 820 795 ^(__cfa_dbg_global_clusters.list){}; … … 828 803 //============================================================================================= 829 804 static void halt(processor * this) with( *this ) { 830 // // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 831 832 // with( *cltr ) { 833 // lock (proc_list_lock __cfaabi_dbg_ctx2); 834 // push_front(idles, *this); 835 // unlock (proc_list_lock); 836 // } 837 838 // __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this); 839 840 // wait( idleLock ); 841 842 // __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this); 843 844 // with( *cltr ) { 845 // lock (proc_list_lock __cfaabi_dbg_ctx2); 846 // remove (idles, *this); 847 // unlock (proc_list_lock); 848 // } 805 // verify( ! __atomic_load_n(&do_terminate, __ATOMIC_SEQ_CST) ); 806 807 with( *cltr ) { 808 lock (proc_list_lock __cfaabi_dbg_ctx2); 809 remove (procs, *this); 810 push_front(idles, *this); 811 unlock (proc_list_lock); 812 } 813 814 __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this); 815 816 wait( idleLock ); 817 818 __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this); 819 820 with( *cltr ) { 821 lock (proc_list_lock __cfaabi_dbg_ctx2); 822 remove (idles, *this); 823 push_front(procs, *this); 824 unlock (proc_list_lock); 825 } 849 826 } 850 827 … … 986 963 } 987 964 965 void doregister( cluster * cltr, processor * proc ) { 966 lock (cltr->proc_list_lock __cfaabi_dbg_ctx2); 967 cltr->nprocessors += 1; 968 push_front(cltr->procs, *proc); 969 unlock (cltr->proc_list_lock); 970 } 971 972 void unregister( cluster * cltr, processor * proc ) { 973 lock (cltr->proc_list_lock __cfaabi_dbg_ctx2); 974 remove(cltr->procs, *proc ); 975 cltr->nprocessors -= 1; 976 unlock(cltr->proc_list_lock); 977 } 978 988 979 //----------------------------------------------------------------------------- 989 980 // Debug -
libcfa/src/concurrency/kernel.hfa
rb7d6a36 r2cbfe92 107 107 // Cluster from which to get threads 108 108 struct cluster * cltr; 109 unsigned int id;110 109 111 110 // Name of the processor … … 162 161 } 163 162 164 165 //-----------------------------------------------------------------------------166 // Cluster Tools167 168 // Cells use by the reader writer lock169 // while not generic it only relies on a opaque pointer170 struct __processor_id;171 172 // Reader-Writer lock protecting the ready-queue173 // while this lock is mostly generic some aspects174 // have been hard-coded to for the ready-queue for175 // simplicity and performance176 struct __clusterRWLock_t {177 // total cachelines allocated178 unsigned int max;179 180 // cachelines currently in use181 volatile unsigned int alloc;182 183 // cachelines ready to itereate over184 // (!= to alloc when thread is in second half of doregister)185 volatile unsigned int ready;186 187 // writer lock188 volatile bool lock;189 190 // data pointer191 __processor_id * data;192 };193 194 void ?{}(__clusterRWLock_t & this);195 void ^?{}(__clusterRWLock_t & this);196 197 // Intrusives lanes which are used by the relaxed ready queue198 struct __attribute__((aligned(128))) __intrusive_lane_t {199 // spin lock protecting the queue200 volatile bool lock;201 202 // anchor for the head and the tail of the queue203 struct __sentinel_t {204 // Link lists fields205 // instrusive link field for threads206 // must be exactly as in thread_desc207 __thread_desc_link link;208 } before, after;209 210 #if defined(__CFA_WITH_VERIFY__)211 // id of last processor to acquire the lock212 // needed only to check for mutual exclusion violations213 unsigned int last_id;214 215 // number of items on this list216 // needed only to check for deadlocks217 unsigned int count;218 #endif219 220 // Optional statistic counters221 #if !defined(__CFA_NO_SCHED_STATS__)222 struct __attribute__((aligned(64))) {223 // difference between number of push and pops224 ssize_t diff;225 226 // total number of pushes and pops227 size_t push;228 size_t pop ;229 } stat;230 #endif231 };232 233 void ?{}(__intrusive_lane_t & this);234 void ^?{}(__intrusive_lane_t & this);235 236 typedef unsigned long long __cfa_readyQ_mask_t;237 238 // enum {239 // __cfa_ready_queue_mask_size = (64 - sizeof(size_t)) / sizeof(size_t),240 // __cfa_max_ready_queues = __cfa_ready_queue_mask_size * 8 * sizeof(size_t)241 // };242 243 #define __cfa_lane_mask_size ((64 - sizeof(size_t)) / sizeof(__cfa_readyQ_mask_t))244 #define __cfa_max_lanes (__cfa_lane_mask_size * 8 * sizeof(__cfa_readyQ_mask_t))245 246 //TODO adjust cache size to ARCHITECTURE247 // Structure holding the relaxed ready queue248 struct __attribute__((aligned(128))) __ready_queue_t {249 // Data tracking how many/which lanes are used250 // Aligned to 128 for cache locality251 struct {252 // number of non-empty lanes253 volatile size_t count;254 255 // bit mask, set bits indentify which lanes are non-empty256 volatile __cfa_readyQ_mask_t mask[ __cfa_lane_mask_size ];257 } used;258 259 // Data tracking the actual lanes260 // On a seperate cacheline from the used struct since261 // used can change on each push/pop but this data262 // only changes on shrink/grow263 struct __attribute__((aligned(64))) {264 // Arary of lanes265 __intrusive_lane_t * volatile data;266 267 // Number of lanes (empty or not)268 volatile size_t count;269 } lanes;270 271 // Statistics272 #if !defined(__CFA_NO_STATISTICS__)273 __attribute__((aligned(64))) struct {274 struct {275 // Push statistic276 struct {277 // number of attemps at pushing something278 volatile size_t attempt;279 280 // number of successes at pushing281 volatile size_t success;282 } push;283 284 // Pop statistic285 struct {286 // number of reads of the mask287 // picking an empty __cfa_readyQ_mask_t counts here288 // but not as an attempt289 volatile size_t maskrds;290 291 // number of attemps at poping something292 volatile size_t attempt;293 294 // number of successes at poping295 volatile size_t success;296 } pop;297 } pick;298 299 // stats on the "used" struct of the queue300 // tracks average number of queues that are not empty301 // when pushing / poping302 struct {303 volatile size_t value;304 volatile size_t count;305 } used;306 } global_stats;307 308 #endif309 };310 311 void ?{}(__ready_queue_t & this);312 void ^?{}(__ready_queue_t & this);313 314 163 //----------------------------------------------------------------------------- 315 164 // Cluster 316 165 struct cluster { 317 166 // Ready queue locks 318 __ clusterRWLock_t ready_lock;167 __spinlock_t ready_queue_lock; 319 168 320 169 // Ready queue for threads 321 __ ready_queue_tready_queue;170 __queue_t(thread_desc) ready_queue; 322 171 323 172 // Name of the cluster … … 329 178 // List of processors 330 179 __spinlock_t proc_list_lock; 180 __dllist_t(struct processor) procs; 331 181 __dllist_t(struct processor) idles; 182 unsigned int nprocessors; 332 183 333 184 // List of threads -
libcfa/src/concurrency/kernel_private.hfa
rb7d6a36 r2cbfe92 100 100 //----------------------------------------------------------------------------- 101 101 // Utils 102 #define KERNEL_STORAGE(T,X) __attribute((aligned(__alignof__(T))))static char storage_##X[sizeof(T)]102 #define KERNEL_STORAGE(T,X) static char storage_##X[sizeof(T)] 103 103 104 104 static inline uint32_t tls_rand() { … … 116 116 void unregister( struct cluster * cltr, struct thread_desc & thrd ); 117 117 118 //======================================================================= 119 // Cluster lock API 120 //======================================================================= 121 struct __attribute__((aligned(64))) __processor_id { 122 processor * volatile handle; 123 volatile bool lock; 124 }; 125 126 // Lock-Free registering/unregistering of threads 127 // Register a processor to a given cluster and get its unique id in return 128 unsigned doregister( struct cluster * cltr, struct processor * proc ); 129 130 // Unregister a processor from a given cluster using its id, getting back the original pointer 131 void unregister( struct cluster * cltr, struct processor * proc ); 132 133 //======================================================================= 134 // Reader-writer lock implementation 135 // Concurrent with doregister/unregister, 136 // i.e., threads can be added at any point during or between the entry/exit 137 138 //----------------------------------------------------------------------- 139 // simple spinlock underlying the RWLock 140 // Blocking acquire 141 static inline void __atomic_acquire(volatile bool * ll) { 142 while( __builtin_expect(__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST), false) ) { 143 while(__atomic_load_n(ll, (int)__ATOMIC_RELAXED)) 144 asm volatile("pause"); 145 } 146 /* paranoid */ verify(*ll); 147 } 148 149 // Non-Blocking acquire 150 static inline bool __atomic_try_acquire(volatile bool * ll) { 151 return !__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST); 152 } 153 154 // Release 155 static inline void __atomic_unlock(volatile bool * ll) { 156 /* paranoid */ verify(*ll); 157 __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE); 158 } 159 160 //----------------------------------------------------------------------- 161 // Reader side : acquire when using the ready queue to schedule but not 162 // creating/destroying queues 163 static inline void ready_schedule_lock( struct cluster * cltr, struct processor * proc) with(cltr->ready_lock) { 164 unsigned iproc = proc->id; 165 /*paranoid*/ verify(data[iproc].handle == proc); 166 /*paranoid*/ verify(iproc < ready); 167 168 // Step 1 : make sure no writer are in the middle of the critical section 169 while(__atomic_load_n(&lock, (int)__ATOMIC_RELAXED)) 170 asm volatile("pause"); 171 172 // Fence needed because we don't want to start trying to acquire the lock 173 // before we read a false. 174 // Not needed on x86 175 // std::atomic_thread_fence(std::memory_order_seq_cst); 176 177 // Step 2 : acquire our local lock 178 __atomic_acquire( &data[iproc].lock ); 179 /*paranoid*/ verify(data[iproc].lock); 180 } 181 182 static inline void ready_schedule_unlock( struct cluster * cltr, struct processor * proc) with(cltr->ready_lock) { 183 unsigned iproc = proc->id; 184 /*paranoid*/ verify(data[iproc].handle == proc); 185 /*paranoid*/ verify(iproc < ready); 186 /*paranoid*/ verify(data[iproc].lock); 187 __atomic_unlock(&data[iproc].lock); 188 } 189 190 //----------------------------------------------------------------------- 191 // Writer side : acquire when changing the ready queue, e.g. adding more 192 // queues or removing them. 193 uint_fast32_t ready_mutate_lock( struct cluster & cltr ); 194 195 void ready_mutate_unlock( struct cluster & cltr, uint_fast32_t /* value returned by lock */ ); 196 197 //======================================================================= 198 // Ready-Queue API 199 //----------------------------------------------------------------------- 200 // push thread onto a ready queue for a cluster 201 // returns true if the list was previously empty, false otherwise 202 __attribute__((hot)) bool push(struct cluster * cltr, struct thread_desc * thrd); 203 204 //----------------------------------------------------------------------- 205 // pop thread from the ready queue of a cluster 206 // returns 0p if empty 207 __attribute__((hot)) thread_desc * pop(struct cluster * cltr); 208 209 //----------------------------------------------------------------------- 210 // Increase the width of the ready queue (number of lanes) by 4 211 void ready_queue_grow (struct cluster * cltr); 212 213 //----------------------------------------------------------------------- 214 // Decrease the width of the ready queue (number of lanes) by 4 215 void ready_queue_shrink(struct cluster * cltr); 216 217 //----------------------------------------------------------------------- 218 // Statics call at the end of each thread to register statistics 219 #if !defined(__CFA_NO_STATISTICS__) 220 void stats_tls_tally(struct cluster * cltr); 221 #else 222 static inline void stats_tls_tally(struct cluster * cltr) {} 223 #endif 118 void doregister( struct cluster * cltr, struct processor * proc ); 119 void unregister( struct cluster * cltr, struct processor * proc ); 224 120 225 121 // Local Variables: // -
libcfa/src/concurrency/monitor.cfa
rb7d6a36 r2cbfe92 817 817 } 818 818 819 __cfaabi_dbg_print_safe( "Kernel : Runing %i (%p)\n", ready2run, ready2run ? (thread_desc*)node->waiting_thread : (thread_desc*)0p );819 __cfaabi_dbg_print_safe( "Kernel : Runing %i (%p)\n", ready2run, ready2run ? node->waiting_thread : 0p ); 820 820 return ready2run ? node->waiting_thread : 0p; 821 821 } … … 842 842 for( thread_desc ** thrd_it = &entry_queue.head; 843 843 *thrd_it; 844 thrd_it = &(*thrd_it)-> link.next844 thrd_it = &(*thrd_it)->next 845 845 ) { 846 846 // For each acceptable check if it matches -
libcfa/src/concurrency/preemption.cfa
rb7d6a36 r2cbfe92 120 120 // If there are still alarms pending, reset the timer 121 121 if( alarms->head ) { 122 //__cfaabi_dbg_print_buffer_decl( " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);122 __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 123 Duration delta = alarms->head->alarm - currtime; 124 124 Duration caped = max(delta, 50`us); -
libcfa/src/concurrency/thread.cfa
rb7d6a36 r2cbfe92 41 41 self_mon_p = &self_mon; 42 42 curr_cluster = &cl; 43 link.next = 0p; 44 link.prev = 0p; 43 next = 0p; 45 44 46 45 node.next = 0p; -
libcfa/src/stdhdr/assert.h
rb7d6a36 r2cbfe92 33 33 #define verify(x) assert(x) 34 34 #define verifyf(x, ...) assertf(x, __VA_ARGS__) 35 #define verifyfail(...)36 35 #define __CFA_WITH_VERIFY__ 37 36 #else 38 37 #define verify(x) 39 38 #define verifyf(x, ...) 40 #define verifyfail(...)41 39 #endif 42 40 -
tests/concurrent/examples/.expect/datingService.txt
rb7d6a36 r2cbfe92 1 Girl:17 is dating Boy at 2 with ccode 17 2 Boy:2 is dating Girl 17 with ccode 17 3 Boy:14 is dating Girl 5 with ccode 5 4 Girl:5 is dating Boy at 14 with ccode 5 5 Boy:9 is dating Girl 10 with ccode 10 6 Girl:10 is dating Boy at 9 with ccode 10 7 Boy:1 is dating Girl 18 with ccode 18 8 Girl:18 is dating Boy at 1 with ccode 18 9 Boy:16 is dating Girl 3 with ccode 3 10 Girl:3 is dating Boy at 16 with ccode 3 11 Boy:5 is dating Girl 14 with ccode 14 12 Girl:14 is dating Boy at 5 with ccode 14 13 Boy:15 is dating Girl 4 with ccode 4 14 Girl:4 is dating Boy at 15 with ccode 4 15 Girl:0 is dating Boy at 19 with ccode 0 16 Boy:19 is dating Girl 0 with ccode 0 17 Girl:9 is dating Boy at 10 with ccode 9 18 Boy:10 is dating Girl 9 with ccode 9 19 Girl:11 is dating Boy at 8 with ccode 11 20 Boy:8 is dating Girl 11 with ccode 11 21 Boy:12 is dating Girl 7 with ccode 7 22 Girl:7 is dating Boy at 12 with ccode 7 23 Boy:11 is dating Girl 8 with ccode 8 24 Girl:8 is dating Boy at 11 with ccode 8 25 Girl:16 is dating Boy at 3 with ccode 16 26 Boy:3 is dating Girl 16 with ccode 16 27 Girl:15 is dating Boy at 4 with ccode 15 28 Boy:4 is dating Girl 15 with ccode 15 29 Girl:19 is dating Boy at 0 with ccode 19 30 Boy:0 is dating Girl 19 with ccode 19 31 Girl:2 is dating Boy at 17 with ccode 2 32 Boy:17 is dating Girl 2 with ccode 2 33 Boy:13 is dating Girl 6 with ccode 6 34 Girl:6 is dating Boy at 13 with ccode 6 35 Boy:7 is dating Girl 12 with ccode 12 36 Girl:12 is dating Boy at 7 with ccode 12 37 Girl:13 is dating Boy at 6 with ccode 13 38 Boy:6 is dating Girl 13 with ccode 13 39 Girl:1 is dating Boy at 18 with ccode 1 40 Boy:18 is dating Girl 1 with ccode 1 -
tests/concurrent/examples/datingService.cfa
rb7d6a36 r2cbfe92 1 1 // 2 2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo 3 // 3 // 4 4 // The contents of this file are covered under the licence agreement in the 5 5 // file "LICENCE" distributed with Cforall. … … 35 35 signal_block( Boys[ccode] ); // restart boy to set phone number 36 36 } // 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; 38 38 return BoyPhoneNo; 39 39 } // DatingService girl … … 47 47 signal_block( Girls[ccode] ); // restart girl to set phone number 48 48 } // if 49 //sout | " Boy:" | PhoneNo | "is dating Girl" | GirlPhoneNo | "with ccode" | ccode;49 sout | " Boy:" | PhoneNo | "is dating Girl" | GirlPhoneNo | "with ccode" | ccode; 50 50 return GirlPhoneNo; 51 51 } // DatingService boy -
tests/concurrent/waitfor/when.cfa
rb7d6a36 r2cbfe92 57 57 58 58 void 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 on61 this.last_call = 6;62 63 59 for( int i = 0; i < N; i++ ) { 64 60 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.