Changes in / [c083c3d:4daf79f]
- Files:
-
- 5 added
- 12 deleted
- 34 edited
-
benchmark/mutexStmt/JavaThread.java (added)
-
doc/theses/colby_parsons_MMAth/benchmarks/actors/data/nasus_CFA.txt (modified) (15 diffs)
-
doc/theses/colby_parsons_MMAth/benchmarks/actors/data/pyke_CFA.txt (modified) (15 diffs)
-
doc/theses/colby_parsons_MMAth/benchmarks/channels/plotData.py (modified) (1 diff)
-
doc/theses/colby_parsons_MMAth/code/swap_queues.cfa (modified) (3 diffs)
-
doc/theses/colby_parsons_MMAth/version.sh (modified) (1 prop)
-
doc/theses/mike_brooks_MMath/pictures/lst-issues-direct.vsdx (modified) ( previous)
-
libcfa/src/bits/weakso_locks.cfa (modified) (2 diffs)
-
libcfa/src/bits/weakso_locks.hfa (modified) (4 diffs)
-
libcfa/src/concurrency/channel.hfa (modified) (18 diffs)
-
libcfa/src/concurrency/future.hfa (modified) (7 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (1 diff)
-
libcfa/src/concurrency/locks.cfa (modified) (16 diffs)
-
libcfa/src/concurrency/locks.hfa (modified) (32 diffs)
-
libcfa/src/concurrency/mutex_stmt.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/select.hfa (modified) (1 diff)
-
libcfa/src/concurrency/thread.cfa (modified) (3 diffs)
-
src/AST/Convert.cpp (modified) (4 diffs)
-
src/AST/Fwd.hpp (modified) (1 diff)
-
src/AST/Node.cpp (modified) (1 diff)
-
src/AST/Pass.hpp (modified) (1 diff)
-
src/AST/Pass.impl.hpp (modified) (2 diffs)
-
src/AST/Print.cpp (modified) (4 diffs)
-
src/AST/Stmt.hpp (modified) (2 diffs)
-
src/AST/Visitor.hpp (modified) (1 diff)
-
src/Common/CodeLocationTools.cpp (modified) (1 diff)
-
src/Concurrency/WaitforNew.cpp (modified) (2 diffs)
-
src/Concurrency/Waituntil.cpp (deleted)
-
src/Concurrency/Waituntil.hpp (deleted)
-
src/Concurrency/module.mk (modified) (1 diff)
-
src/Parser/StatementNode.cc (modified) (2 diffs)
-
src/Parser/StatementNode.h (modified) (1 diff)
-
src/Parser/parser.yy (modified) (4 diffs)
-
src/ResolvExpr/Resolver.cc (modified) (3 diffs)
-
src/main.cc (modified) (2 diffs)
-
tests/Makefile.am (modified) (2 diffs)
-
tests/concurrent/futures/select_future.cfa (modified) (1 diff)
-
tests/concurrent/mutexstmt/.expect/scoped_lock.txt (added)
-
tests/concurrent/mutexstmt/scoped_lock.cfa (added)
-
tests/concurrent/unified_locking/.expect/clh.txt (added)
-
tests/concurrent/unified_locking/clh.cfa (added)
-
tests/concurrent/waituntil/.expect/basic_else.txt (deleted)
-
tests/concurrent/waituntil/.expect/channel_close.txt (deleted)
-
tests/concurrent/waituntil/.expect/channels.txt (deleted)
-
tests/concurrent/waituntil/.expect/futures.txt (deleted)
-
tests/concurrent/waituntil/.expect/locks.txt (deleted)
-
tests/concurrent/waituntil/basic_else.cfa (deleted)
-
tests/concurrent/waituntil/channel_close.cfa (deleted)
-
tests/concurrent/waituntil/channels.cfa (deleted)
-
tests/concurrent/waituntil/futures.cfa (deleted)
-
tests/concurrent/waituntil/locks.cfa (deleted)
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/colby_parsons_MMAth/benchmarks/actors/data/nasus_CFA.txt
rc083c3d r4daf79f 1 1 5 2 2 1 2 4 8 16 24 32 48 3 Longest-Victim No-Stealing Random3 CFA-LV CFA-NS CFA-R 4 4 executor 5 Longest-Victim:5 CFA-LV: 6 6 proc time (s) 7 7 1 29.22 … … 45 45 48 1.20 46 46 48 1.20 47 No-Stealing:47 CFA-NS: 48 48 proc time (s) 49 49 1 28.25 … … 87 87 48 1.18 88 88 48 1.16 89 Random:89 CFA-R: 90 90 proc time (s) 91 91 1 28.58 … … 131 131 132 132 matrix 133 Longest-Victim:133 CFA-LV: 134 134 proc time (s) 135 135 1 105.48 … … 173 173 48 2.75 174 174 48 2.96 175 No-Stealing:175 CFA-NS: 176 176 proc time (s) 177 177 1 106.01 … … 215 215 48 2.78 216 216 48 2.92 217 Random:217 CFA-R: 218 218 proc time (s) 219 219 1 105.91 … … 259 259 260 260 repeat 261 Longest-Victim:261 CFA-LV: 262 262 proc time (s) 263 263 1 1.17 … … 301 301 48 13.73 302 302 48 14.55 303 No-Stealing:303 CFA-NS: 304 304 proc time (s) 305 305 1 1.15 … … 343 343 48 13.03 344 344 48 12.83 345 Random:345 CFA-R: 346 346 proc time (s) 347 347 1 1.15 … … 387 387 388 388 balance_one 389 Longest-Victim:389 CFA-LV: 390 390 proc time (s) 391 391 1 20.06 … … 429 429 48 1.11 430 430 48 1.12 431 No-Stealing:431 CFA-NS: 432 432 proc time (s) 433 433 1 20.13 … … 471 471 48 19.95 472 472 48 20.00 473 Random:473 CFA-R: 474 474 proc time (s) 475 475 1 19.92 … … 515 515 516 516 balance_multi 517 Longest-Victim:517 CFA-LV: 518 518 proc time (s) 519 519 1 8.17 … … 557 557 48 5.75 558 558 48 5.68 559 No-Stealing:559 CFA-NS: 560 560 proc time (s) 561 561 1 8.10 … … 599 599 48 9.28 600 600 48 9.26 601 Random:601 CFA-R: 602 602 proc time (s) 603 603 1 8.08 -
doc/theses/colby_parsons_MMAth/benchmarks/actors/data/pyke_CFA.txt
rc083c3d r4daf79f 1 1 5 2 2 1 2 4 8 16 24 32 48 3 Longest-Victim No-Stealing Random3 CFA-LV CFA-NS CFA-R 4 4 executor 5 Longest-Victim:5 CFA-LV: 6 6 proc time (s) 7 7 1 29.04 … … 45 45 48 2.58 46 46 48 2.55 47 No-Stealing:47 CFA-NS: 48 48 proc time (s) 49 49 1 28.15 … … 87 87 48 2.59 88 88 48 2.60 89 Random:89 CFA-R: 90 90 proc time (s) 91 91 1 29.06 … … 131 131 132 132 matrix 133 Longest-Victim:133 CFA-LV: 134 134 proc time (s) 135 135 1 127.44 … … 173 173 48 6.83 174 174 48 6.81 175 No-Stealing:175 CFA-NS: 176 176 proc time (s) 177 177 1 127.64 … … 215 215 48 6.77 216 216 48 6.74 217 Random:217 CFA-R: 218 218 proc time (s) 219 219 1 127.26 … … 259 259 260 260 repeat 261 Longest-Victim:261 CFA-LV: 262 262 proc time (s) 263 263 1 1.16 … … 301 301 48 19.75 302 302 48 19.71 303 No-Stealing:303 CFA-NS: 304 304 proc time (s) 305 305 1 1.18 … … 343 343 48 13.88 344 344 48 13.71 345 Random:345 CFA-R: 346 346 proc time (s) 347 347 1 1.18 … … 387 387 388 388 balance_one 389 Longest-Victim:389 CFA-LV: 390 390 proc time (s) 391 391 1 19.46 … … 429 429 48 2.12 430 430 48 2.17 431 No-Stealing:431 CFA-NS: 432 432 proc time (s) 433 433 1 21.00 … … 471 471 48 47.50 472 472 48 47.72 473 Random:473 CFA-R: 474 474 proc time (s) 475 475 1 20.81 … … 515 515 516 516 balance_multi 517 Longest-Victim:517 CFA-LV: 518 518 proc time (s) 519 519 1 7.94 … … 557 557 48 14.38 558 558 48 14.50 559 No-Stealing:559 CFA-NS: 560 560 proc time (s) 561 561 1 8.48 … … 599 599 48 21.50 600 600 48 21.15 601 Random:601 CFA-R: 602 602 proc time (s) 603 603 1 8.49 -
doc/theses/colby_parsons_MMAth/benchmarks/channels/plotData.py
rc083c3d r4daf79f 70 70 if currBench == Bench.Unset: 71 71 if line == "contend:": 72 name = "C hannel Contention"72 name = "Contend" 73 73 currBench = Bench.Contend 74 74 elif line == "zero:": -
doc/theses/colby_parsons_MMAth/code/swap_queues.cfa
rc083c3d r4daf79f 1 // sequential equivalent swap 2 void swap( uint victim_idx, uint my_idx ) { 3 // Step 0: 1 // this is a code stub and will not compile 2 3 // tries to atomically swap two queues and returns 0p if the swap failed 4 // returns ptr to newly owned queue if swap succeeds 5 static inline work_queue * try_swap_queues( worker & this, unsigned int victim_idx, unsigned int my_idx ) with(this) { 4 6 work_queue * my_queue = request_queues[my_idx]; 5 work_queue * vic_queue = request_queues[victim_idx]; 6 // Step 2: 7 request_queues[my_idx] = 0p; 8 // Step 3: 9 request_queues[victim_idx] = my_queue; 10 // Step 4: 11 request_queues[my_idx] = vic_queue; 7 work_queue * other_queue = request_queues[victim_idx]; 8 9 // if either queue is 0p then they are in the process of being stolen 10 if ( other_queue == 0p || my_queue == 0p ) return 0p; 11 12 // try to set our queue ptr to be 0p. If it fails someone moved our queue so return false 13 if ( !__atomic_compare_exchange_n( &request_queues[my_idx], &my_queue, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) 14 return 0p; 15 16 // try to set other queue ptr to be our queue ptr. If it fails someone moved the other queue so fix up then return false 17 if ( !__atomic_compare_exchange_n( &request_queues[victim_idx], &other_queue, my_queue, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) { 18 /* paranoid */ verify( request_queues[my_idx] == 0p ); 19 request_queues[my_idx] = my_queue; // reset my queue ptr back to appropriate val 20 return 0p; 21 } 22 23 // we have successfully swapped and since our queue is 0p no one will touch it so write back new queue ptr non atomically 24 request_queues[my_idx] = other_queue; // last write does not need to be atomic 25 return other_queue; 12 26 } 13 27 … … 21 35 22 36 bool try_swap_queues( worker & this, uint victim_idx, uint my_idx ) with(this) { 23 // Step 0:24 // request_queues is the shared array of all sharded queues25 37 work_queue * my_queue = request_queues[my_idx]; 26 38 work_queue * vic_queue = request_queues[victim_idx]; 27 39 28 // Step 1:29 40 // If either queue is 0p then they are in the process of being stolen 30 41 // 0p is CForAll's equivalent of C++'s nullptr 31 if ( vic_queue == 0p ) return false;42 if ( vic_queue == 0p || my_queue == 0p ) return false; 32 43 33 // Step 2: 34 // Try to set thief's queue ptr to be 0p. 35 // If this CAS fails someone stole thief's queue so return false 44 // Try to set our queue ptr to be 0p. 45 // If this CAS fails someone moved our queue so return false 36 46 if ( !CAS( &request_queues[my_idx], &my_queue, 0p ) ) 37 47 return false; 38 39 // Step 3: 40 // Try to set victim queue ptr to be thief's queue ptr. 41 // If it fails someone stole the other queue, so fix up then return false 48 49 // Try to set other queue ptr to be our queue ptr. 50 // If it fails someone moved the other queue, so fix up then return false 42 51 if ( !CAS( &request_queues[victim_idx], &vic_queue, my_queue ) ) { 43 52 request_queues[my_idx] = my_queue; // reset queue ptr back to prev val … … 45 54 } 46 55 47 // Step 4:48 56 // Successfully swapped. 49 // Thief's ptr is 0p so no one will touch it 50 // Write back without CAS is safe 57 // Our queue is 0p so no one will touch it so write back without CAS is safe 51 58 request_queues[my_idx] = vic_queue; 52 59 return true; -
doc/theses/colby_parsons_MMAth/version.sh
-
Property mode
changed from
100644to100755
-
Property mode
changed from
-
libcfa/src/bits/weakso_locks.cfa
rc083c3d r4daf79f 15 15 // Update Count : 16 16 // 17 17 18 #include "bits/weakso_locks.hfa" 19 18 20 #pragma GCC visibility push(default) 19 21 … … 28 30 void on_wakeup( blocking_lock &, size_t ) {} 29 31 size_t wait_count( blocking_lock & ) { return 0; } 30 bool register_select( blocking_lock & this, select_node & node ) { return false; }31 bool unregister_select( blocking_lock & this, select_node & node ) { return false; }32 bool on_selected( blocking_lock & this, select_node & node ) { return true; }33 -
libcfa/src/bits/weakso_locks.hfa
rc083c3d r4daf79f 23 23 #include "containers/list.hfa" 24 24 25 struct select_node;25 struct thread$; 26 26 27 27 //----------------------------------------------------------------------------- … … 32 32 33 33 // List of blocked threads 34 dlist( select_node) blocked_threads;34 dlist( thread$ ) blocked_threads; 35 35 36 36 // Count of current blocked threads … … 60 60 void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD; 61 61 size_t wait_count( blocking_lock & this ) OPTIONAL_THREAD; 62 bool register_select( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;63 bool unregister_select( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;64 bool on_selected( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;65 62 66 63 //---------- … … 78 75 static inline void on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 79 76 static inline void on_notify( multiple_acquisition_lock & this, struct thread$ * t ){ on_notify( (blocking_lock &)this, t ); } 80 static inline bool register_select( multiple_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }81 static inline bool unregister_select( multiple_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }82 static inline bool on_selected( multiple_acquisition_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); } -
libcfa/src/concurrency/channel.hfa
rc083c3d r4daf79f 4 4 #include <list.hfa> 5 5 #include <mutex_stmt.hfa> 6 #include "select.hfa" 6 7 // link field used for threads waiting on channel 8 struct wait_link { 9 // used to put wait_link on a dl queue 10 inline dlink(wait_link); 11 12 // waiting thread 13 struct thread$ * t; 14 15 // shadow field 16 void * elem; 17 }; 18 P9_EMBEDDED( wait_link, dlink(wait_link) ) 19 20 static inline void ?{}( wait_link & this, thread$ * t, void * elem ) { 21 this.t = t; 22 this.elem = elem; 23 } 24 25 // wake one thread from the list 26 static inline void wake_one( dlist( wait_link ) & queue ) { 27 wait_link & popped = try_pop_front( queue ); 28 unpark( popped.t ); 29 } 7 30 8 31 // returns true if woken due to shutdown 9 32 // blocks thread on list and releases passed lock 10 static inline bool block( dlist( select_node) & queue, void * elem_ptr, go_mutex & lock ) {11 select_node sn{ active_thread(), elem_ptr };12 insert_last( queue, sn);33 static inline bool block( dlist( wait_link ) & queue, void * elem_ptr, go_mutex & lock ) { 34 wait_link w{ active_thread(), elem_ptr }; 35 insert_last( queue, w ); 13 36 unlock( lock ); 14 37 park(); 15 return sn.extra == 0p; 16 } 17 18 // Waituntil support (un)register_select helper routine 19 // Sets select node avail if not special OR case and then unlocks 20 static inline void __set_avail_then_unlock( select_node & node, go_mutex & mutex_lock ) { 21 if ( node.park_counter ) __make_select_node_available( node ); 22 unlock( mutex_lock ); 38 return w.elem == 0p; 23 39 } 24 40 … … 43 59 size_t size, front, back, count; 44 60 T * buffer; 45 dlist( select_node) prods, cons; // lists of blocked threads61 dlist( wait_link ) prods, cons; // lists of blocked threads 46 62 go_mutex mutex_lock; // MX lock 47 63 bool closed; // indicates channel close/open … … 54 70 size = _size; 55 71 front = back = count = 0; 56 if ( size != 0 )buffer = aalloc( size );72 buffer = aalloc( size ); 57 73 prods{}; 58 74 cons{}; … … 71 87 #endif 72 88 verifyf( cons`isEmpty && prods`isEmpty, "Attempted to delete channel with waiting threads (Deadlock).\n" ); 73 if ( size != 0 )delete( buffer );89 delete( buffer ); 74 90 } 75 91 static inline size_t get_count( channel(T) & chan ) with(chan) { return count; } … … 86 102 // flush waiting consumers and producers 87 103 while ( has_waiting_consumers( chan ) ) { 88 if( !__handle_waituntil_OR( cons ) ) // ensure we only signal special OR case threads when they win the race 89 break; // if __handle_waituntil_OR returns false cons is empty so break 90 cons`first.extra = 0p; 104 cons`first.elem = 0p; 91 105 wake_one( cons ); 92 106 } 93 107 while ( has_waiting_producers( chan ) ) { 94 if( !__handle_waituntil_OR( prods ) ) // ensure we only signal special OR case threads when they win the race 95 break; // if __handle_waituntil_OR returns false prods is empty so break 96 prods`first.extra = 0p; 108 prods`first.elem = 0p; 97 109 wake_one( prods ); 98 110 } … … 102 114 static inline void is_closed( channel(T) & chan ) with(chan) { return closed; } 103 115 104 // used to hand an element to a blocked consumer and signal it105 static inline void __cons_handoff( channel(T) & chan, T & elem ) with(chan) {106 memcpy( cons`first.extra, (void *)&elem, sizeof(T) ); // do waiting consumer work107 wake_one( cons );108 }109 110 // used to hand an element to a blocked producer and signal it111 static inline void __prods_handoff( channel(T) & chan, T & retval ) with(chan) {112 memcpy( (void *)&retval, prods`first.extra, sizeof(T) );113 wake_one( prods );114 }115 116 116 static inline void flush( channel(T) & chan, T elem ) with(chan) { 117 117 lock( mutex_lock ); 118 118 while ( count == 0 && !cons`isEmpty ) { 119 __cons_handoff( chan, elem ); 119 memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work 120 wake_one( cons ); 120 121 } 121 122 unlock( mutex_lock ); … … 124 125 // handles buffer insert 125 126 static inline void __buf_insert( channel(T) & chan, T & elem ) with(chan) { 126 memcpy( (void *)&buffer[back], (void *)&elem, sizeof(T));127 memcpy((void *)&buffer[back], (void *)&elem, sizeof(T)); 127 128 count += 1; 128 129 back++; … … 130 131 } 131 132 133 // does the buffer insert or hands elem directly to consumer if one is waiting 134 static inline void __do_insert( channel(T) & chan, T & elem ) with(chan) { 135 if ( count == 0 && !cons`isEmpty ) { 136 memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work 137 wake_one( cons ); 138 } else __buf_insert( chan, elem ); 139 } 140 132 141 // needed to avoid an extra copy in closed case 133 142 static inline bool __internal_try_insert( channel(T) & chan, T & elem ) with(chan) { … … 136 145 operations++; 137 146 #endif 138 139 ConsEmpty: if ( !cons`isEmpty ) {140 if ( !__handle_waituntil_OR( cons ) ) break ConsEmpty;141 __cons_handoff( chan, elem );142 unlock( mutex_lock );143 return true;144 }145 146 147 if ( count == size ) { unlock( mutex_lock ); return false; } 147 148 __buf_insert( chan, elem ); 148 __do_insert( chan, elem ); 149 149 unlock( mutex_lock ); 150 150 return true; … … 157 157 // handles closed case of insert routine 158 158 static inline void __closed_insert( channel(T) & chan, T & elem ) with(chan) { 159 channel_closed except{ &channel_closed_vt, &elem, &chan };159 channel_closed except{&channel_closed_vt, &elem, &chan }; 160 160 throwResume except; // throw closed resumption 161 161 if ( !__internal_try_insert( chan, elem ) ) throw except; // if try to insert fails (would block), throw termination … … 182 182 } 183 183 184 // buffer count must be zero if cons are blocked (also handles zero-size case)185 ConsEmpty: if (!cons`isEmpty ) {186 if ( !__handle_waituntil_OR( cons ) ) break ConsEmpty;187 __cons_handoff( chan, elem);184 // have to check for the zero size channel case 185 if ( size == 0 && !cons`isEmpty ) { 186 memcpy(cons`first.elem, (void *)&elem, sizeof(T)); 187 wake_one( cons ); 188 188 unlock( mutex_lock ); 189 return ;189 return true; 190 190 } 191 191 … … 202 202 } // if 203 203 204 __buf_insert( chan, elem ); 205 unlock( mutex_lock ); 204 if ( count == 0 && !cons`isEmpty ) { 205 memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work 206 wake_one( cons ); 207 } else __buf_insert( chan, elem ); 208 209 unlock( mutex_lock ); 210 return; 211 } 212 213 // handles buffer remove 214 static inline void __buf_remove( channel(T) & chan, T & retval ) with(chan) { 215 memcpy((void *)&retval, (void *)&buffer[front], sizeof(T)); 216 count -= 1; 217 front = (front + 1) % size; 206 218 } 207 219 208 220 // does the buffer remove and potentially does waiting producer work 209 221 static inline void __do_remove( channel(T) & chan, T & retval ) with(chan) { 210 memcpy( (void *)&retval, (void *)&buffer[front], sizeof(T) ); 211 count -= 1; 212 front = (front + 1) % size; 222 __buf_remove( chan, retval ); 213 223 if (count == size - 1 && !prods`isEmpty ) { 214 if ( !__handle_waituntil_OR( prods ) ) return; 215 __buf_insert( chan, *(T *)prods`first.extra ); // do waiting producer work 224 __buf_insert( chan, *(T *)prods`first.elem ); // do waiting producer work 216 225 wake_one( prods ); 217 226 } … … 224 233 operations++; 225 234 #endif 226 227 ZeroSize: if ( size == 0 && !prods`isEmpty ) {228 if ( !__handle_waituntil_OR( prods ) ) break ZeroSize;229 __prods_handoff( chan, retval );230 unlock( mutex_lock );231 return true;232 }233 234 235 if ( count == 0 ) { unlock( mutex_lock ); return false; } 235 236 236 __do_remove( chan, retval ); 237 237 unlock( mutex_lock ); … … 244 244 static inline [T, bool] try_remove( channel(T) & chan ) { 245 245 T retval; 246 bool success = __internal_try_remove( chan, retval ); 247 return [ retval, success ]; 248 } 249 250 static inline T try_remove( channel(T) & chan ) { 246 return [ retval, __internal_try_remove( chan, retval ) ]; 247 } 248 249 static inline T try_remove( channel(T) & chan, T elem ) { 251 250 T retval; 252 251 __internal_try_remove( chan, retval ); … … 256 255 // handles closed case of insert routine 257 256 static inline void __closed_remove( channel(T) & chan, T & retval ) with(chan) { 258 channel_closed except{ &channel_closed_vt, 0p, &chan };257 channel_closed except{&channel_closed_vt, 0p, &chan }; 259 258 throwResume except; // throw resumption 260 259 if ( !__internal_try_remove( chan, retval ) ) throw except; // if try to remove fails (would block), throw termination … … 280 279 281 280 // have to check for the zero size channel case 282 ZeroSize:if ( size == 0 && !prods`isEmpty ) {283 if ( !__handle_waituntil_OR( prods ) ) break ZeroSize;284 __prods_handoff( chan, retval);281 if ( size == 0 && !prods`isEmpty ) { 282 memcpy((void *)&retval, (void *)prods`first.elem, sizeof(T)); 283 wake_one( prods ); 285 284 unlock( mutex_lock ); 286 285 return retval; … … 288 287 289 288 // wait if buffer is empty, work will be completed by someone else 290 if ( count == 0) {289 if (count == 0) { 291 290 #ifdef CHAN_STATS 292 291 blocks++; … … 300 299 // Remove from buffer 301 300 __do_remove( chan, retval ); 301 302 302 unlock( mutex_lock ); 303 303 return retval; 304 304 } 305 306 ///////////////////////////////////////////////////////////////////////////////////////////307 // The following is support for waituntil (select) statements308 ///////////////////////////////////////////////////////////////////////////////////////////309 static inline bool unregister_chan( channel(T) & chan, select_node & node ) with(chan) {310 if ( !node`isListed && !node.park_counter ) return false; // handle special OR case311 lock( mutex_lock );312 if ( node`isListed ) { // op wasn't performed313 #ifdef CHAN_STATS314 operations--;315 #endif316 remove( node );317 unlock( mutex_lock );318 return false;319 }320 unlock( mutex_lock );321 322 // only return true when not special OR case, not exceptional calse and status is SAT323 return ( node.extra == 0p || !node.park_counter ) ? false : *node.clause_status == __SELECT_SAT;324 }325 326 // type used by select statement to capture a chan read as the selected operation327 struct chan_read {328 channel(T) & chan;329 T & ret;330 };331 332 static inline void ?{}( chan_read(T) & cr, channel(T) & chan, T & ret ) {333 &cr.chan = &chan;334 &cr.ret = &ret;335 }336 static inline chan_read(T) ?<<?( T & ret, channel(T) & chan ) { chan_read(T) cr{ chan, ret }; return cr; }337 338 static inline void __handle_select_closed_read( chan_read(T) & this, select_node & node ) with(this.chan, this) {339 __closed_remove( chan, ret );340 // if we get here then the insert succeeded341 __make_select_node_available( node );342 }343 344 static inline bool register_select( chan_read(T) & this, select_node & node ) with(this.chan, this) {345 // mutex(sout) sout | "register_read";346 lock( mutex_lock );347 node.extra = &ret; // set .extra so that if it == 0p later in on_selected it is due to channel close348 349 #ifdef CHAN_STATS350 if ( !closed ) operations++;351 #endif352 353 // check if we can complete operation. If so race to establish winner in special OR case354 if ( !node.park_counter && ( count != 0 || !prods`isEmpty || unlikely(closed) ) ) {355 if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering356 unlock( mutex_lock );357 return false;358 }359 }360 361 if ( unlikely(closed) ) {362 unlock( mutex_lock );363 __handle_select_closed_read( this, node );364 return true;365 }366 367 // have to check for the zero size channel case368 ZeroSize: if ( size == 0 && !prods`isEmpty ) {369 if ( !__handle_waituntil_OR( prods ) ) break ZeroSize;370 __prods_handoff( chan, ret );371 __set_avail_then_unlock( node, mutex_lock );372 return true;373 }374 375 // wait if buffer is empty, work will be completed by someone else376 if ( count == 0 ) {377 #ifdef CHAN_STATS378 blocks++;379 #endif380 381 insert_last( cons, node );382 unlock( mutex_lock );383 return false;384 }385 386 // Remove from buffer387 __do_remove( chan, ret );388 __set_avail_then_unlock( node, mutex_lock );389 return true;390 }391 static inline bool unregister_select( chan_read(T) & this, select_node & node ) { return unregister_chan( this.chan, node ); }392 static inline bool on_selected( chan_read(T) & this, select_node & node ) with(this) {393 if ( node.extra == 0p ) // check if woken up due to closed channel394 __closed_remove( chan, ret );395 // This is only reachable if not closed or closed exception was handled396 return true;397 }398 399 // type used by select statement to capture a chan write as the selected operation400 struct chan_write {401 channel(T) & chan;402 T elem;403 };404 405 static inline void ?{}( chan_write(T) & cw, channel(T) & chan, T elem ) {406 &cw.chan = &chan;407 memcpy( (void *)&cw.elem, (void *)&elem, sizeof(T) );408 }409 static inline chan_write(T) ?>>?( T elem, channel(T) & chan ) { chan_write(T) cw{ chan, elem }; return cw; }410 411 static inline void __handle_select_closed_write( chan_write(T) & this, select_node & node ) with(this.chan, this) {412 __closed_insert( chan, elem );413 // if we get here then the insert succeeded414 __make_select_node_available( node );415 }416 417 static inline bool register_select( chan_write(T) & this, select_node & node ) with(this.chan, this) {418 // mutex(sout) sout | "register_write";419 lock( mutex_lock );420 node.extra = &elem; // set .extra so that if it == 0p later in on_selected it is due to channel close421 422 #ifdef CHAN_STATS423 if ( !closed ) operations++;424 #endif425 426 // check if we can complete operation. If so race to establish winner in special OR case427 if ( !node.park_counter && ( count != size || !cons`isEmpty || unlikely(closed) ) ) {428 if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering429 unlock( mutex_lock );430 return false;431 }432 }433 434 // if closed handle435 if ( unlikely(closed) ) {436 unlock( mutex_lock );437 __handle_select_closed_write( this, node );438 return true;439 }440 441 // handle blocked consumer case via handoff (buffer is implicitly empty)442 ConsEmpty: if ( !cons`isEmpty ) {443 if ( !__handle_waituntil_OR( cons ) ) {444 // mutex(sout) sout | "empty";445 break ConsEmpty;446 }447 // mutex(sout) sout | "signal";448 __cons_handoff( chan, elem );449 __set_avail_then_unlock( node, mutex_lock );450 return true;451 }452 453 // insert node in list if buffer is full, work will be completed by someone else454 if ( count == size ) {455 #ifdef CHAN_STATS456 blocks++;457 #endif458 459 insert_last( prods, node );460 unlock( mutex_lock );461 return false;462 } // if463 464 // otherwise carry out write either via normal insert465 __buf_insert( chan, elem );466 __set_avail_then_unlock( node, mutex_lock );467 return true;468 }469 static inline bool unregister_select( chan_write(T) & this, select_node & node ) { return unregister_chan( this.chan, node ); }470 471 static inline bool on_selected( chan_write(T) & this, select_node & node ) with(this) {472 if ( node.extra == 0p ) // check if woken up due to closed channel473 __closed_insert( chan, elem );474 475 // This is only reachable if not closed or closed exception was handled476 return true;477 }478 479 480 305 } // forall( T ) 481 482 483 -
libcfa/src/concurrency/future.hfa
rc083c3d r4daf79f 19 19 #include "monitor.hfa" 20 20 #include "select.hfa" 21 #include "locks.hfa"22 21 23 22 //---------------------------------------------------------------------------- … … 27 26 // future_t is lockfree and uses atomics which aren't needed given we use locks here 28 27 forall( T ) { 29 // enum { FUTURE_EMPTY = 0, FUTURE_FULFILLED = 1 }; // Enums seem to be broken so feel free to add this back afterwards28 // enum(int) { FUTURE_EMPTY = 0, FUTURE_FULFILLED = 1 }; // Enums seem to be broken so feel free to add this back afterwards 30 29 31 30 // temporary enum replacement … … 45 44 }; 46 45 46 // C_TODO: perhaps allow exceptions to be inserted like uC++? 47 47 48 static inline { 48 49 … … 81 82 void _internal_flush( future(T) & this ) with(this) { 82 83 while( ! waiters`isEmpty ) { 83 if ( !__handle_waituntil_OR( waiters ) ) // handle special waituntil OR case84 break; // if handle_OR returns false then waiters is empty so break85 84 select_node &s = try_pop_front( waiters ); 86 85 87 if ( s. clause_status== 0p )86 if ( s.race_flag == 0p ) 88 87 // poke in result so that woken threads do not need to reacquire any locks 88 // *(((future_node(T) &)s).my_result) = result; 89 89 copy_T( result, *(((future_node(T) &)s).my_result) ); 90 else if ( ! __make_select_node_available(s ) ) continue;90 else if ( !install_select_winner( s, &this ) ) continue; 91 91 92 92 // only unpark if future is not selected … … 97 97 98 98 // Fulfil the future, returns whether or not someone was unblocked 99 bool fulfil( future(T) & this, T val ) with(this) {99 bool fulfil( future(T) & this, T & val ) with(this) { 100 100 lock( lock ); 101 101 if( state != FUTURE_EMPTY ) … … 153 153 } 154 154 155 bool register_select( future(T) & this, select_node & s ) with(this) { 156 lock( lock ); 157 158 // check if we can complete operation. If so race to establish winner in special OR case 159 if ( !s.park_counter && state != FUTURE_EMPTY ) { 160 if ( !__make_select_node_available( s ) ) { // we didn't win the race so give up on registering 161 unlock( lock ); 162 return false; 163 } 164 } 165 166 // future not ready -> insert select node and return 155 void * register_select( future(T) & this, select_node & s ) with(this) { 156 lock( lock ); 157 158 // future not ready -> insert select node and return 0p 167 159 if( state == FUTURE_EMPTY ) { 168 160 insert_last( waiters, s ); 169 161 unlock( lock ); 170 return false; 171 } 172 173 __make_select_node_available( s ); 174 unlock( lock ); 175 return true; 176 } 177 178 bool unregister_select( future(T) & this, select_node & s ) with(this) { 179 if ( ! s`isListed ) return false; 162 return 0p; 163 } 164 165 // future ready and we won race to install it as the select winner return 1p 166 if ( install_select_winner( s, &this ) ) { 167 unlock( lock ); 168 return 1p; 169 } 170 171 unlock( lock ); 172 // future ready and we lost race to install it as the select winner 173 return 2p; 174 } 175 176 void unregister_select( future(T) & this, select_node & s ) with(this) { 180 177 lock( lock ); 181 178 if ( s`isListed ) remove( s ); 182 179 unlock( lock ); 183 return false;184 180 } 185 181 186 bool on_selected( future(T) & this, select_node & node ) { return true; }187 182 } 188 183 } … … 191 186 // These futures below do not support select statements so they may not be as useful as 'future' 192 187 // however the 'single_future' is cheap and cheerful and is most likely more performant than 'future' 193 // since it uses raw atomics and no locks 188 // since it uses raw atomics and no locks afaik 194 189 // 195 190 // As far as 'multi_future' goes I can't see many use cases as it will be less performant than 'future' -
libcfa/src/concurrency/invoke.h
rc083c3d r4daf79f 217 217 struct __thread_user_link cltr_link; 218 218 219 // used to point to this thd's current clh node 220 volatile bool * clh_node; 221 219 222 struct processor * last_proc; 220 221 // ptr used during handover between blocking lists to allow for stack allocation of intrusive nodes222 // main use case is wait-morphing to allow a different node to be used to block on condvar vs lock223 void * link_node;224 223 225 224 PRNG_STATE_T random_state; // fast random numbers -
libcfa/src/concurrency/locks.cfa
rc083c3d r4daf79f 79 79 // lock is held by some other thread 80 80 if ( owner != 0p && owner != thrd ) { 81 select_node node; 82 insert_last( blocked_threads, node ); 81 insert_last( blocked_threads, *thrd ); 83 82 wait_count++; 84 83 unlock( lock ); 85 84 park( ); 86 return; 87 } else if ( owner == thrd && multi_acquisition ) { // multi acquisition lock is held by current thread 85 } 86 // multi acquisition lock is held by current thread 87 else if ( owner == thrd && multi_acquisition ) { 88 88 recursion_count++; 89 } else { // lock isn't held 89 unlock( lock ); 90 } 91 // lock isn't held 92 else { 90 93 owner = thrd; 91 94 recursion_count = 1; 92 }93 unlock( lock ); 95 unlock( lock ); 96 } 94 97 } 95 98 … … 114 117 } 115 118 116 // static void pop_and_set_new_owner( blocking_lock & this ) with( this ) { 117 // thread$ * t = &try_pop_front( blocked_threads ); 118 // owner = t; 119 // recursion_count = ( t ? 1 : 0 ); 120 // if ( t ) wait_count--; 121 // unpark( t ); 122 // } 123 124 static inline void pop_node( blocking_lock & this ) with( this ) { 125 __handle_waituntil_OR( blocked_threads ); 126 select_node * node = &try_pop_front( blocked_threads ); 127 if ( node ) { 128 wait_count--; 129 owner = node->blocked_thread; 130 recursion_count = 1; 131 // if ( !node->clause_status || __make_select_node_available( *node ) ) unpark( node->blocked_thread ); 132 wake_one( blocked_threads, *node ); 133 } else { 134 owner = 0p; 135 recursion_count = 0; 136 } 119 static void pop_and_set_new_owner( blocking_lock & this ) with( this ) { 120 thread$ * t = &try_pop_front( blocked_threads ); 121 owner = t; 122 recursion_count = ( t ? 1 : 0 ); 123 if ( t ) wait_count--; 124 unpark( t ); 137 125 } 138 126 … … 146 134 recursion_count--; 147 135 if ( recursion_count == 0 ) { 148 pop_ node( this );136 pop_and_set_new_owner( this ); 149 137 } 150 138 unlock( lock ); … … 159 147 // lock held 160 148 if ( owner != 0p ) { 161 insert_last( blocked_threads, * (select_node *)t->link_node);149 insert_last( blocked_threads, *t ); 162 150 wait_count++; 151 unlock( lock ); 163 152 } 164 153 // lock not held … … 167 156 recursion_count = 1; 168 157 unpark( t ); 169 }170 unlock( lock ); 158 unlock( lock ); 159 } 171 160 } 172 161 … … 178 167 size_t ret = recursion_count; 179 168 180 pop_node( this ); 181 182 select_node node; 183 active_thread()->link_node = (void *)&node; 169 pop_and_set_new_owner( this ); 184 170 unlock( lock ); 185 186 park();187 188 171 return ret; 189 172 } … … 192 175 recursion_count = recursion; 193 176 } 194 195 // waituntil() support196 bool register_select( blocking_lock & this, select_node & node ) with(this) {197 lock( lock __cfaabi_dbg_ctx2 );198 thread$ * thrd = active_thread();199 200 // single acquisition lock is held by current thread201 /* paranoid */ verifyf( owner != thrd || multi_acquisition, "Single acquisition lock holder (%p) attempted to reacquire the lock %p resulting in a deadlock.", owner, &this );202 203 if ( !node.park_counter && ( (owner == thrd && multi_acquisition) || owner == 0p ) ) { // OR special case204 if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering205 unlock( lock );206 return false;207 }208 }209 210 // lock is held by some other thread211 if ( owner != 0p && owner != thrd ) {212 insert_last( blocked_threads, node );213 wait_count++;214 unlock( lock );215 return false;216 } else if ( owner == thrd && multi_acquisition ) { // multi acquisition lock is held by current thread217 recursion_count++;218 } else { // lock isn't held219 owner = thrd;220 recursion_count = 1;221 }222 223 if ( node.park_counter ) __make_select_node_available( node );224 unlock( lock );225 return true;226 }227 228 bool unregister_select( blocking_lock & this, select_node & node ) with(this) {229 lock( lock __cfaabi_dbg_ctx2 );230 if ( node`isListed ) {231 remove( node );232 wait_count--;233 unlock( lock );234 return false;235 }236 237 if ( owner == active_thread() ) {238 /* paranoid */ verifyf( recursion_count == 1 || multi_acquisition, "Thread %p attempted to unlock owner lock %p in waituntil unregister, which is not recursive but has a recursive count of %zu", active_thread(), &this, recursion_count );239 // if recursion count is zero release lock and set new owner if one is waiting240 recursion_count--;241 if ( recursion_count == 0 ) {242 pop_node( this );243 }244 }245 unlock( lock );246 return false;247 }248 249 bool on_selected( blocking_lock & this, select_node & node ) { return true; }250 177 251 178 //----------------------------------------------------------------------------- … … 384 311 int counter( condition_variable(L) & this ) with(this) { return count; } 385 312 386 static void enqueue_thread( condition_variable(L) & this, info_thread(L) * i ) with(this) {313 static size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) { 387 314 // add info_thread to waiting queue 388 315 insert_last( blocked_threads, *i ); 389 316 count++; 390 // size_t recursion_count = 0; 391 // if (i->lock) { 392 // // if lock was passed get recursion count to reset to after waking thread 393 // recursion_count = on_wait( *i->lock ); 394 // } 395 // return recursion_count; 396 } 397 398 static size_t block_and_get_recursion( info_thread(L) & i ) { 399 size_t recursion_count = 0; 400 if ( i.lock ) { 317 size_t recursion_count = 0; 318 if (i->lock) { 401 319 // if lock was passed get recursion count to reset to after waking thread 402 recursion_count = on_wait( *i .lock ); // this call blocks403 } else park( );404 return recursion_count;405 }320 recursion_count = on_wait( *i->lock ); 321 } 322 return recursion_count; 323 } 406 324 407 325 // helper for wait()'s' with no timeout 408 326 static void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) { 409 327 lock( lock __cfaabi_dbg_ctx2 ); 410 enqueue_thread( this, &i ); 411 // size_t recursion_count = queue_and_get_recursion( this, &i ); 328 size_t recursion_count = queue_and_get_recursion(this, &i); 412 329 unlock( lock ); 413 330 414 331 // blocks here 415 size_t recursion_count = block_and_get_recursion( i ); 416 // park( ); 332 park( ); 417 333 418 334 // resets recursion count here after waking 419 if ( i.lock ) on_wakeup( *i.lock, recursion_count);335 if (i.lock) on_wakeup(*i.lock, recursion_count); 420 336 } 421 337 … … 427 343 static void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) { 428 344 lock( lock __cfaabi_dbg_ctx2 ); 429 enqueue_thread( this, &info ); 430 // size_t recursion_count = queue_and_get_recursion( this, &info ); 345 size_t recursion_count = queue_and_get_recursion(this, &info); 431 346 alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info }; 432 347 unlock( lock ); … … 436 351 437 352 // blocks here 438 size_t recursion_count = block_and_get_recursion( info ); 439 // park(); 353 park(); 440 354 441 355 // unregisters alarm so it doesn't go off if this happens first … … 443 357 444 358 // resets recursion count here after waking 445 if ( info.lock ) on_wakeup( *info.lock, recursion_count);359 if (info.lock) on_wakeup(*info.lock, recursion_count); 446 360 } 447 361 … … 503 417 info_thread( L ) i = { active_thread(), info, &l }; 504 418 insert_last( blocked_threads, i ); 505 size_t recursion_count = on_wait( *i.lock ); // blocks here506 //park( );419 size_t recursion_count = on_wait( *i.lock ); 420 park( ); 507 421 on_wakeup(*i.lock, recursion_count); 508 422 } … … 545 459 bool empty ( pthread_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty; } 546 460 547 // static size_t queue_and_get_recursion( pthread_cond_var(L) & this, info_thread(L) * i ) with(this) { 548 // // add info_thread to waiting queue 549 // insert_last( blocked_threads, *i ); 550 // size_t recursion_count = 0; 551 // recursion_count = on_wait( *i->lock ); 552 // return recursion_count; 553 // } 554 461 static size_t queue_and_get_recursion( pthread_cond_var(L) & this, info_thread(L) * i ) with(this) { 462 // add info_thread to waiting queue 463 insert_last( blocked_threads, *i ); 464 size_t recursion_count = 0; 465 recursion_count = on_wait( *i->lock ); 466 return recursion_count; 467 } 555 468 556 469 static void queue_info_thread_timeout( pthread_cond_var(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) { 557 470 lock( lock __cfaabi_dbg_ctx2 ); 558 // size_t recursion_count = queue_and_get_recursion(this, &info); 559 insert_last( blocked_threads, info ); 471 size_t recursion_count = queue_and_get_recursion(this, &info); 560 472 pthread_alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info }; 561 473 unlock( lock ); … … 565 477 566 478 // blocks here 567 size_t recursion_count = block_and_get_recursion( info ); 568 // park(); 479 park(); 569 480 570 481 // unregisters alarm so it doesn't go off if this happens first … … 572 483 573 484 // resets recursion count here after waking 574 if ( info.lock ) on_wakeup( *info.lock, recursion_count);485 if (info.lock) on_wakeup(*info.lock, recursion_count); 575 486 } 576 487 … … 582 493 lock( lock __cfaabi_dbg_ctx2 ); 583 494 info_thread( L ) i = { active_thread(), info, &l }; 584 insert_last( blocked_threads, i ); 585 // size_t recursion_count = queue_and_get_recursion( this, &i ); 586 unlock( lock ); 587 588 // blocks here 589 size_t recursion_count = block_and_get_recursion( i ); 590 // park(); 591 on_wakeup( *i.lock, recursion_count ); 495 size_t recursion_count = queue_and_get_recursion(this, &i); 496 unlock( lock ); 497 park( ); 498 on_wakeup(*i.lock, recursion_count); 592 499 } 593 500 -
libcfa/src/concurrency/locks.hfa
rc083c3d r4daf79f 30 30 #include "time.hfa" 31 31 32 #include "select.hfa"33 34 32 #include <fstream.hfa> 35 33 … … 72 70 static inline void on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 73 71 static inline void on_notify( single_acquisition_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); } 74 static inline bool register_select( single_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }75 static inline bool unregister_select( single_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }76 static inline bool on_selected( single_acquisition_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }77 72 78 73 //---------- … … 89 84 static inline void on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 90 85 static inline void on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); } 91 static inline bool register_select( owner_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }92 static inline bool unregister_select( owner_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }93 static inline bool on_selected( owner_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }94 86 95 87 //----------------------------------------------------------------------------- … … 188 180 189 181 // if this is called recursively IT WILL DEADLOCK!!!!! 190 static inline void lock( futex_mutex & this) with(this) {182 static inline void lock(futex_mutex & this) with(this) { 191 183 int state; 192 184 … … 198 190 for (int i = 0; i < spin; i++) Pause(); 199 191 } 192 193 // // no contention try to acquire 194 // if (internal_try_lock(this, state)) return; 200 195 201 196 // if not in contended state, set to be in contended state … … 218 213 219 214 static inline void on_notify( futex_mutex & f, thread$ * t){ unpark(t); } 220 static inline size_t on_wait( futex_mutex & f ) { unlock(f); park(); return 0;}215 static inline size_t on_wait( futex_mutex & f ) {unlock(f); return 0;} 221 216 222 217 // to set recursion count after getting signalled; … … 249 244 250 245 // if this is called recursively IT WILL DEADLOCK!!!!! 251 static inline void lock( go_mutex & this ) with( this) {246 static inline void lock(go_mutex & this) with(this) { 252 247 int state, init_state; 253 248 … … 260 255 while( !val ) { // lock unlocked 261 256 state = 0; 262 if ( internal_try_lock( this, state, init_state )) return;257 if (internal_try_lock(this, state, init_state)) return; 263 258 } 264 259 for (int i = 0; i < 30; i++) Pause(); … … 267 262 while( !val ) { // lock unlocked 268 263 state = 0; 269 if ( internal_try_lock( this, state, init_state )) return;264 if (internal_try_lock(this, state, init_state)) return; 270 265 } 271 266 sched_yield(); 272 267 273 268 // if not in contended state, set to be in contended state 274 state = internal_exchange( this, 2);269 state = internal_exchange(this, 2); 275 270 if ( !state ) return; // state == 0 276 271 init_state = 2; 277 futex( (int*)&val, FUTEX_WAIT, 2); // if val is not 2 this returns with EWOULDBLOCK272 futex((int*)&val, FUTEX_WAIT, 2); // if val is not 2 this returns with EWOULDBLOCK 278 273 } 279 274 } … … 281 276 static inline void unlock( go_mutex & this ) with(this) { 282 277 // if uncontended do atomic unlock and then return 283 if ( __atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return;278 if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return; 284 279 285 280 // otherwise threads are blocked so we must wake one 286 futex( (int *)&val, FUTEX_WAKE, 1);287 } 288 289 static inline void on_notify( go_mutex & f, thread$ * t){ unpark( t); }290 static inline size_t on_wait( go_mutex & f ) { unlock( f ); park(); return 0;}281 futex((int *)&val, FUTEX_WAKE, 1); 282 } 283 284 static inline void on_notify( go_mutex & f, thread$ * t){ unpark(t); } 285 static inline size_t on_wait( go_mutex & f ) {unlock(f); return 0;} 291 286 static inline void on_wakeup( go_mutex & f, size_t recursion ) {} 287 288 //----------------------------------------------------------------------------- 289 // CLH Spinlock 290 // - No recursive acquisition 291 // - Needs to be released by owner 292 293 struct clh_lock { 294 volatile bool * volatile tail; 295 volatile bool * volatile head; 296 }; 297 298 static inline void ?{}( clh_lock & this ) { this.tail = malloc(); *this.tail = true; } 299 static inline void ^?{}( clh_lock & this ) { free(this.tail); } 300 301 static inline void lock(clh_lock & l) { 302 thread$ * curr_thd = active_thread(); 303 *(curr_thd->clh_node) = false; 304 volatile bool * prev = __atomic_exchange_n((bool **)(&l.tail), (bool *)(curr_thd->clh_node), __ATOMIC_SEQ_CST); 305 while(!__atomic_load_n(prev, __ATOMIC_SEQ_CST)) Pause(); 306 __atomic_store_n((bool **)(&l.head), (bool *)curr_thd->clh_node, __ATOMIC_SEQ_CST); 307 curr_thd->clh_node = prev; 308 } 309 310 static inline void unlock(clh_lock & l) { 311 __atomic_store_n((bool *)(l.head), true, __ATOMIC_SEQ_CST); 312 } 313 314 static inline void on_notify(clh_lock & this, struct thread$ * t ) { unpark(t); } 315 static inline size_t on_wait(clh_lock & this) { unlock(this); return 0; } 316 static inline void on_wakeup(clh_lock & this, size_t recursion ) { lock(this); } 292 317 293 318 //----------------------------------------------------------------------------- … … 312 337 static inline void ^?{}( exp_backoff_then_block_lock & this ){} 313 338 314 static inline bool internal_try_lock( exp_backoff_then_block_lock & this, size_t & compare_val) with(this) {339 static inline bool internal_try_lock(exp_backoff_then_block_lock & this, size_t & compare_val) with(this) { 315 340 return __atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); 316 341 } 317 342 318 static inline bool try_lock( exp_backoff_then_block_lock & this ) { size_t compare_val = 0; return internal_try_lock( this, compare_val); }319 320 static inline bool try_lock_contention( exp_backoff_then_block_lock & this) with(this) {321 return !__atomic_exchange_n( &lock_value, 2, __ATOMIC_ACQUIRE);322 } 323 324 static inline bool block( exp_backoff_then_block_lock & this) with(this) {343 static inline bool try_lock(exp_backoff_then_block_lock & this) { size_t compare_val = 0; return internal_try_lock(this, compare_val); } 344 345 static inline bool try_lock_contention(exp_backoff_then_block_lock & this) with(this) { 346 return !__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE); 347 } 348 349 static inline bool block(exp_backoff_then_block_lock & this) with(this) { 325 350 lock( spinlock __cfaabi_dbg_ctx2 ); 326 351 if (__atomic_load_n( &lock_value, __ATOMIC_SEQ_CST) != 2) { … … 334 359 } 335 360 336 static inline void lock( exp_backoff_then_block_lock & this) with(this) {361 static inline void lock(exp_backoff_then_block_lock & this) with(this) { 337 362 size_t compare_val = 0; 338 363 int spin = 4; … … 353 378 } 354 379 355 static inline void unlock( exp_backoff_then_block_lock & this) with(this) {380 static inline void unlock(exp_backoff_then_block_lock & this) with(this) { 356 381 if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return; 357 382 lock( spinlock __cfaabi_dbg_ctx2 ); … … 361 386 } 362 387 363 static inline void on_notify( exp_backoff_then_block_lock & this, struct thread$ * t ) { unpark( t); }364 static inline size_t on_wait( exp_backoff_then_block_lock & this ) { unlock( this ); park(); return 0; }365 static inline void on_wakeup( exp_backoff_then_block_lock & this, size_t recursion ) { lock( this); }388 static inline void on_notify(exp_backoff_then_block_lock & this, struct thread$ * t ) { unpark(t); } 389 static inline size_t on_wait(exp_backoff_then_block_lock & this) { unlock(this); return 0; } 390 static inline void on_wakeup(exp_backoff_then_block_lock & this, size_t recursion ) { lock(this); } 366 391 367 392 //----------------------------------------------------------------------------- … … 393 418 394 419 // if this is called recursively IT WILL DEADLOCK!!!!! 395 static inline void lock( fast_block_lock & this) with(this) {420 static inline void lock(fast_block_lock & this) with(this) { 396 421 lock( lock __cfaabi_dbg_ctx2 ); 397 422 if ( held ) { … … 405 430 } 406 431 407 static inline void unlock( fast_block_lock & this) with(this) {432 static inline void unlock(fast_block_lock & this) with(this) { 408 433 lock( lock __cfaabi_dbg_ctx2 ); 409 434 /* paranoid */ verifyf( held != false, "Attempt to release lock %p that isn't held", &this ); … … 414 439 } 415 440 416 static inline void on_notify( fast_block_lock & this, struct thread$ * t ) with(this) {441 static inline void on_notify(fast_block_lock & this, struct thread$ * t ) with(this) { 417 442 lock( lock __cfaabi_dbg_ctx2 ); 418 443 insert_last( blocked_threads, *t ); 419 444 unlock( lock ); 420 445 } 421 static inline size_t on_wait( fast_block_lock & this) { unlock(this); park(); return 0; }422 static inline void on_wakeup( fast_block_lock & this, size_t recursion ) { }446 static inline size_t on_wait(fast_block_lock & this) { unlock(this); return 0; } 447 static inline void on_wakeup(fast_block_lock & this, size_t recursion ) { } 423 448 424 449 //----------------------------------------------------------------------------- … … 431 456 struct simple_owner_lock { 432 457 // List of blocked threads 433 dlist( select_node) blocked_threads;458 dlist( thread$ ) blocked_threads; 434 459 435 460 // Spin lock used for mutual exclusion … … 452 477 static inline void ?=?( simple_owner_lock & this, simple_owner_lock this2 ) = void; 453 478 454 static inline void lock( simple_owner_lock & this) with(this) {455 if ( owner == active_thread()) {479 static inline void lock(simple_owner_lock & this) with(this) { 480 if (owner == active_thread()) { 456 481 recursion_count++; 457 482 return; … … 459 484 lock( lock __cfaabi_dbg_ctx2 ); 460 485 461 if ( owner != 0p ) { 462 select_node node; 463 insert_last( blocked_threads, node ); 486 if (owner != 0p) { 487 insert_last( blocked_threads, *active_thread() ); 464 488 unlock( lock ); 465 489 park( ); … … 471 495 } 472 496 473 static inline void pop_node( simple_owner_lock & this ) with(this) { 474 __handle_waituntil_OR( blocked_threads ); 475 select_node * node = &try_pop_front( blocked_threads ); 476 if ( node ) { 477 owner = node->blocked_thread; 478 recursion_count = 1; 479 // if ( !node->clause_status || __make_select_node_available( *node ) ) unpark( node->blocked_thread ); 480 wake_one( blocked_threads, *node ); 481 } else { 482 owner = 0p; 483 recursion_count = 0; 484 } 485 } 486 487 static inline void unlock( simple_owner_lock & this ) with(this) { 497 // TODO: fix duplicate def issue and bring this back 498 // void pop_and_set_new_owner( simple_owner_lock & this ) with( this ) { 499 // thread$ * t = &try_pop_front( blocked_threads ); 500 // owner = t; 501 // recursion_count = ( t ? 1 : 0 ); 502 // unpark( t ); 503 // } 504 505 static inline void unlock(simple_owner_lock & this) with(this) { 488 506 lock( lock __cfaabi_dbg_ctx2 ); 489 507 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); … … 492 510 recursion_count--; 493 511 if ( recursion_count == 0 ) { 494 pop_node( this ); 512 // pop_and_set_new_owner( this ); 513 thread$ * t = &try_pop_front( blocked_threads ); 514 owner = t; 515 recursion_count = ( t ? 1 : 0 ); 516 unpark( t ); 495 517 } 496 518 unlock( lock ); 497 519 } 498 520 499 static inline void on_notify(simple_owner_lock & this, thread$ * t ) with(this) {521 static inline void on_notify(simple_owner_lock & this, struct thread$ * t ) with(this) { 500 522 lock( lock __cfaabi_dbg_ctx2 ); 501 523 // lock held 502 524 if ( owner != 0p ) { 503 insert_last( blocked_threads, * (select_node *)t->link_node);525 insert_last( blocked_threads, *t ); 504 526 } 505 527 // lock not held … … 512 534 } 513 535 514 static inline size_t on_wait( simple_owner_lock & this) with(this) {536 static inline size_t on_wait(simple_owner_lock & this) with(this) { 515 537 lock( lock __cfaabi_dbg_ctx2 ); 516 538 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); … … 519 541 size_t ret = recursion_count; 520 542 521 pop_node( this ); 522 523 select_node node; 524 active_thread()->link_node = (void *)&node; 543 // pop_and_set_new_owner( this ); 544 545 thread$ * t = &try_pop_front( blocked_threads ); 546 owner = t; 547 recursion_count = ( t ? 1 : 0 ); 548 unpark( t ); 549 525 550 unlock( lock ); 526 park();527 528 551 return ret; 529 552 } 530 553 531 static inline void on_wakeup( simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; } 532 533 // waituntil() support 534 static inline bool register_select( simple_owner_lock & this, select_node & node ) with(this) { 535 lock( lock __cfaabi_dbg_ctx2 ); 536 537 // check if we can complete operation. If so race to establish winner in special OR case 538 if ( !node.park_counter && ( owner == active_thread() || owner == 0p ) ) { 539 if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering 540 unlock( lock ); 541 return false; 542 } 543 } 544 545 if ( owner == active_thread() ) { 546 recursion_count++; 547 if ( node.park_counter ) __make_select_node_available( node ); 548 unlock( lock ); 549 return true; 550 } 551 552 if ( owner != 0p ) { 553 insert_last( blocked_threads, node ); 554 unlock( lock ); 555 return false; 556 } 557 558 owner = active_thread(); 559 recursion_count = 1; 560 561 if ( node.park_counter ) __make_select_node_available( node ); 562 unlock( lock ); 563 return true; 564 } 565 566 static inline bool unregister_select( simple_owner_lock & this, select_node & node ) with(this) { 567 lock( lock __cfaabi_dbg_ctx2 ); 568 if ( node`isListed ) { 569 remove( node ); 570 unlock( lock ); 571 return false; 572 } 573 574 if ( owner == active_thread() ) { 575 recursion_count--; 576 if ( recursion_count == 0 ) { 577 pop_node( this ); 578 } 579 } 580 unlock( lock ); 581 return false; 582 } 583 584 static inline bool on_selected( simple_owner_lock & this, select_node & node ) { return true; } 585 554 static inline void on_wakeup(simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; } 586 555 587 556 //----------------------------------------------------------------------------- … … 609 578 610 579 // if this is called recursively IT WILL DEADLOCK! 611 static inline void lock( spin_queue_lock & this) with(this) {580 static inline void lock(spin_queue_lock & this) with(this) { 612 581 mcs_spin_node node; 613 582 lock( lock, node ); … … 617 586 } 618 587 619 static inline void unlock( spin_queue_lock & this) with(this) {588 static inline void unlock(spin_queue_lock & this) with(this) { 620 589 __atomic_store_n(&held, false, __ATOMIC_RELEASE); 621 590 } 622 591 623 static inline void on_notify( spin_queue_lock & this, struct thread$ * t ) {592 static inline void on_notify(spin_queue_lock & this, struct thread$ * t ) { 624 593 unpark(t); 625 594 } 626 static inline size_t on_wait( spin_queue_lock & this ) { unlock( this ); park(); return 0; }627 static inline void on_wakeup( spin_queue_lock & this, size_t recursion ) { lock( this); }595 static inline size_t on_wait(spin_queue_lock & this) { unlock(this); return 0; } 596 static inline void on_wakeup(spin_queue_lock & this, size_t recursion ) { lock(this); } 628 597 629 598 … … 652 621 653 622 // if this is called recursively IT WILL DEADLOCK!!!!! 654 static inline void lock( mcs_block_spin_lock & this) with(this) {623 static inline void lock(mcs_block_spin_lock & this) with(this) { 655 624 mcs_node node; 656 625 lock( lock, node ); … … 664 633 } 665 634 666 static inline void on_notify( mcs_block_spin_lock & this, struct thread$ * t ) { unpark( t); }667 static inline size_t on_wait( mcs_block_spin_lock & this) { unlock( this ); park(); return 0; }668 static inline void on_wakeup( mcs_block_spin_lock & this, size_t recursion ) {lock( this); }635 static inline void on_notify(mcs_block_spin_lock & this, struct thread$ * t ) { unpark(t); } 636 static inline size_t on_wait(mcs_block_spin_lock & this) { unlock(this); return 0; } 637 static inline void on_wakeup(mcs_block_spin_lock & this, size_t recursion ) {lock(this); } 669 638 670 639 //----------------------------------------------------------------------------- … … 692 661 693 662 // if this is called recursively IT WILL DEADLOCK!!!!! 694 static inline void lock( block_spin_lock & this) with(this) {663 static inline void lock(block_spin_lock & this) with(this) { 695 664 lock( lock ); 696 665 while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause(); … … 699 668 } 700 669 701 static inline void unlock( block_spin_lock & this) with(this) {670 static inline void unlock(block_spin_lock & this) with(this) { 702 671 __atomic_store_n(&held, false, __ATOMIC_RELEASE); 703 672 } 704 673 705 static inline void on_notify( block_spin_lock & this, struct thread$ * t ) with(this.lock) {674 static inline void on_notify(block_spin_lock & this, struct thread$ * t ) with(this.lock) { 706 675 // first we acquire internal fast_block_lock 707 676 lock( lock __cfaabi_dbg_ctx2 ); … … 717 686 unpark(t); 718 687 } 719 static inline size_t on_wait( block_spin_lock & this ) { unlock( this ); park(); return 0; }720 static inline void on_wakeup( block_spin_lock & this, size_t recursion ) with(this) {688 static inline size_t on_wait(block_spin_lock & this) { unlock(this); return 0; } 689 static inline void on_wakeup(block_spin_lock & this, size_t recursion ) with(this) { 721 690 // now we acquire the entire block_spin_lock upon waking up 722 691 while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause(); … … 745 714 forall(L & | is_blocking_lock(L)) { 746 715 struct info_thread; 716 717 // // for use by sequence 718 // info_thread(L) *& Back( info_thread(L) * this ); 719 // info_thread(L) *& Next( info_thread(L) * this ); 747 720 } 748 721 -
libcfa/src/concurrency/mutex_stmt.hfa
rc083c3d r4daf79f 15 15 }; 16 16 17 17 18 struct __mutex_stmt_lock_guard { 18 19 void ** lockarr; … … 29 30 30 31 forall(L & | is_lock(L)) { 31 static inline void * __get_mutexstmt_lock_ptr( L & this ) { return &this; } 32 static inline L __get_mutexstmt_lock_type( L & this ) {} 33 static inline L __get_mutexstmt_lock_type( L * this ) {} 32 33 struct scoped_lock { 34 L * internal_lock; 35 }; 36 37 static inline void ?{}( scoped_lock(L) & this, L & internal_lock ) { 38 this.internal_lock = &internal_lock; 39 lock(internal_lock); 40 } 41 42 static inline void ^?{}( scoped_lock(L) & this ) with(this) { 43 unlock(*internal_lock); 44 } 45 46 static inline void * __get_mutexstmt_lock_ptr( L & this ) { 47 return &this; 48 } 49 50 static inline L __get_mutexstmt_lock_type( L & this ); 51 52 static inline L __get_mutexstmt_lock_type( L * this ); 34 53 } -
libcfa/src/concurrency/select.hfa
rc083c3d r4daf79f 2 2 3 3 #include "containers/list.hfa" 4 #include "stdint.h" 5 #include "kernel.hfa" 4 #include <stdint.h> 5 #include <kernel.hfa> 6 #include <locks.hfa> 6 7 7 struct select_node;8 9 // node status10 static const unsigned long int __SELECT_UNSAT = 0;11 static const unsigned long int __SELECT_SAT = 1;12 static const unsigned long int __SELECT_RUN = 2;13 14 static inline bool __CFA_has_clause_run( unsigned long int status ) { return status == __SELECT_RUN; }15 static inline void __CFA_maybe_park( int * park_counter ) {16 if ( __atomic_sub_fetch( park_counter, 1, __ATOMIC_SEQ_CST) < 0 )17 park();18 }19 20 // node used for coordinating waituntil synchronization21 8 struct select_node { 22 int * park_counter; // If this is 0p then the node is in a special OR case waituntil23 unsigned long int * clause_status; // needs to point at ptr sized location, if this is 0p then node is not part of a waituntil24 25 void * extra; // used to store arbitrary data needed by some primitives26 27 9 thread$ * blocked_thread; 10 void ** race_flag; 28 11 inline dlink(select_node); 29 12 }; 30 13 P9_EMBEDDED( select_node, dlink(select_node) ) 31 14 32 static inline void ?{}( select_node & this ) { 33 this.blocked_thread = active_thread(); 34 this.clause_status = 0p; 35 this.park_counter = 0p; 36 this.extra = 0p; 15 void ?{}( select_node & this ) { 16 this.blocked_thread = 0p; 17 this.race_flag = 0p; 37 18 } 38 19 39 static inlinevoid ?{}( select_node & this, thread$ * blocked_thread ) {20 void ?{}( select_node & this, thread$ * blocked_thread ) { 40 21 this.blocked_thread = blocked_thread; 41 this.clause_status = 0p; 42 this.park_counter = 0p; 43 this.extra = 0p; 22 this.race_flag = 0p; 44 23 } 45 24 46 static inline void ?{}( select_node & this, thread$ * blocked_thread, void * extra) {25 void ?{}( select_node & this, thread$ * blocked_thread, void ** race_flag ) { 47 26 this.blocked_thread = blocked_thread; 48 this.clause_status = 0p; 49 this.park_counter = 0p; 50 this.extra = extra; 27 this.race_flag = race_flag; 51 28 } 52 29 53 static inlinevoid ^?{}( select_node & this ) {}30 void ^?{}( select_node & this ) {} 54 31 55 static inline unsigned long int * __get_clause_status( select_node & s ) { return s.clause_status; }56 32 57 33 //----------------------------------------------------------------------------- 58 34 // is_selectable 59 forall(T & | sized(T)) 60 trait is_selectable { 61 // For registering a select stmt on a selectable concurrency primitive 62 // Returns bool that indicates if operation is already SAT 63 bool register_select( T &, select_node & ); 35 trait is_selectable(T & | sized(T)) { 36 // For registering a select on a selectable concurrency primitive 37 // return 0p if primitive not accessible yet 38 // return 1p if primitive gets acquired 39 // return 2p if primitive is accessible but some other primitive won the race 40 // C_TODO: add enum for return values 41 void * register_select( T &, select_node & ); 64 42 65 // For unregistering a select stmt on a selectable concurrency primitive 66 // If true is returned then the corresponding code block is run (only in non-special OR case and only if node status is not RUN) 67 bool unregister_select( T &, select_node & ); 68 69 // This routine is run on the selecting thread prior to executing the statement corresponding to the select_node 70 // passed as an arg to this routine 71 // If on_selected returns false, the statement is not run, if it returns true it is run. 72 bool on_selected( T &, select_node & ); 43 void unregister_select( T &, select_node & ); 73 44 }; 74 45 75 // this is used inside the compiler to attempt to establish an else clause as a winner in the OR special case race 76 static inline bool __select_node_else_race( select_node & this ) with( this ) { 77 unsigned long int cmp_status = __SELECT_UNSAT; 78 return *clause_status == 0 79 && __atomic_compare_exchange_n( clause_status, &cmp_status, 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ); 46 static inline bool install_select_winner( select_node & this, void * primitive_ptr ) with(this) { 47 // temporary needed for atomic instruction 48 void * cmp_flag = 0p; 49 50 // if we dont win the selector race we need to potentially 51 // ignore this node and move to the next one so we return accordingly 52 if ( *race_flag != 0p || 53 !__atomic_compare_exchange_n( 54 race_flag, 55 &cmp_flag, 56 primitive_ptr, 57 false, 58 __ATOMIC_SEQ_CST, 59 __ATOMIC_SEQ_CST 60 ) 61 ) return false; // lost race and some other node triggered select 62 return true; // won race so this node is what the select proceeds with 80 63 } 81 82 // when a primitive becomes available it calls the following routine on it's node to update the select state:83 // return true if we want to unpark the thd84 static inline bool __make_select_node_available( select_node & this ) with( this ) {85 unsigned long int cmp_status = __SELECT_UNSAT;86 87 if( !park_counter )88 return *clause_status == 089 && __atomic_compare_exchange_n( clause_status, &cmp_status, (unsigned long int)&this, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ); // OR specific case where race was won90 91 return *clause_status == 092 && __atomic_compare_exchange_n( clause_status, &cmp_status, __SELECT_SAT, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) // can maybe just use atomic write93 && !__atomic_add_fetch( park_counter, 1, __ATOMIC_SEQ_CST);94 }95 96 // Handles the special OR case of the waituntil statement97 // Since only one select node can win in the OR case, we need to race to set the node available BEFORE98 // performing the operation since if we lose the race the operation should not be performed as it will be lost99 // Returns true if execution can continue normally and false if the queue has now been drained100 static inline bool __handle_waituntil_OR( dlist( select_node ) & queue ) {101 if ( queue`isEmpty ) return false;102 if ( queue`first.clause_status && !queue`first.park_counter ) {103 while ( !queue`isEmpty ) {104 // if node not a special OR case or if we win the special OR case race break105 if ( !queue`first.clause_status || queue`first.park_counter || __make_select_node_available( queue`first ) ) { return true; }106 // otherwise we lost the special OR race so discard node107 try_pop_front( queue );108 }109 return false;110 }111 return true;112 }113 114 // wake one thread from the list115 static inline void wake_one( dlist( select_node ) & queue, select_node & popped ) {116 if ( !popped.clause_status // normal case, node is not a select node117 || ( popped.clause_status && !popped.park_counter ) // If popped link is special case OR selecting unpark but don't call __make_select_node_available118 || __make_select_node_available( popped ) ) // check if popped link belongs to a selecting thread119 unpark( popped.blocked_thread );120 }121 122 static inline void wake_one( dlist( select_node ) & queue ) { wake_one( queue, try_pop_front( queue ) ); }123 124 static inline void setup_clause( select_node & this, unsigned long int * clause_status, int * park_counter ) {125 this.blocked_thread = active_thread();126 this.clause_status = clause_status;127 this.park_counter = park_counter;128 }129 -
libcfa/src/concurrency/thread.cfa
rc083c3d r4daf79f 53 53 preferred = ready_queue_new_preferred(); 54 54 last_proc = 0p; 55 link_node = 0p;56 55 PRNG_SET_SEED( random_state, __global_random_mask ? __global_random_prime : __global_random_prime ^ rdtscl() ); 57 56 #if defined( __CFA_WITH_VERIFY__ ) … … 60 59 #endif 61 60 61 clh_node = malloc( ); 62 *clh_node = false; 63 62 64 doregister(curr_cluster, this); 63 65 monitors{ &self_mon_p, 1, (fptr_t)0 }; … … 68 70 canary = 0xDEADDEADDEADDEADp; 69 71 #endif 72 free(clh_node); 70 73 unregister(curr_cluster, this); 71 74 ^self_cor{}; -
src/AST/Convert.cpp
rc083c3d r4daf79f 567 567 } 568 568 569 const ast::WhenClause * visit( const ast::WhenClause * node ) override final {570 // There is no old-AST WhenClause, so this should never be called.571 assert( !node );572 return nullptr;573 }574 575 569 const ast::Stmt * visit( const ast::WaitForStmt * node ) override final { 576 570 if ( inCache( node ) ) return nullptr; … … 579 573 for ( auto clause : node->clauses ) { 580 574 stmt->clauses.push_back({{ 581 get<Expression>().accept1( clause->target ),575 get<Expression>().accept1( clause->target_func ), 582 576 get<Expression>().acceptL( clause->target_args ), 583 577 }, 584 578 get<Statement>().accept1( clause->stmt ), 585 get<Expression>().accept1( clause-> when_cond ),579 get<Expression>().accept1( clause->cond ), 586 580 }); 587 581 } … … 600 594 const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final { 601 595 // There is no old-AST WaitForClause, so this should never be called. 602 assert( !node );603 return nullptr;604 }605 606 const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {607 // There is no old-AST WaitUntilStmt, so this should never be called.608 596 assert( !node ); 609 597 return nullptr; … … 2170 2158 auto clause = new ast::WaitForClause( old->location ); 2171 2159 2172 clause->target = GET_ACCEPT_1(clauses[i].target.function, Expr);2160 clause->target_func = GET_ACCEPT_1(clauses[i].target.function, Expr); 2173 2161 clause->target_args = GET_ACCEPT_V(clauses[i].target.arguments, Expr); 2174 2162 clause->stmt = GET_ACCEPT_1(clauses[i].statement, Stmt); 2175 clause-> when_cond = GET_ACCEPT_1(clauses[i].condition, Expr);2163 clause->cond = GET_ACCEPT_1(clauses[i].condition, Expr); 2176 2164 2177 2165 stmt->clauses.push_back( clause ); -
src/AST/Fwd.hpp
rc083c3d r4daf79f 58 58 class FinallyClause; 59 59 class SuspendStmt; 60 class WhenClause;61 60 class WaitForStmt; 62 61 class WaitForClause; 63 class WaitUntilStmt;64 62 class WithStmt; 65 63 class DeclStmt; -
src/AST/Node.cpp
rc083c3d r4daf79f 174 174 template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::weak >; 175 175 template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::strong >; 176 template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::weak >;177 template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::strong >;178 176 template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::weak >; 179 177 template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::strong >; 180 178 template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::weak >; 181 179 template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::strong >; 182 template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::weak >;183 template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::strong >;184 180 template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::weak >; 185 181 template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::strong >; -
src/AST/Pass.hpp
rc083c3d r4daf79f 162 162 const ast::FinallyClause * visit( const ast::FinallyClause * ) override final; 163 163 const ast::Stmt * visit( const ast::SuspendStmt * ) override final; 164 const ast::WhenClause * visit( const ast::WhenClause * ) override final;165 164 const ast::Stmt * visit( const ast::WaitForStmt * ) override final; 166 165 const ast::WaitForClause * visit( const ast::WaitForClause * ) override final; 167 const ast::Stmt * visit( const ast::WaitUntilStmt * ) override final;168 166 const ast::Decl * visit( const ast::WithStmt * ) override final; 169 167 const ast::NullStmt * visit( const ast::NullStmt * ) override final; -
src/AST/Pass.impl.hpp
rc083c3d r4daf79f 1066 1066 1067 1067 //-------------------------------------------------------------------------- 1068 // WhenClause1069 template< typename core_t >1070 const ast::WhenClause * ast::Pass< core_t >::visit( const ast::WhenClause * node ) {1071 VISIT_START( node );1072 1073 if ( __visit_children() ) {1074 maybe_accept( node, &WhenClause::target );1075 maybe_accept( node, &WhenClause::stmt );1076 maybe_accept( node, &WhenClause::when_cond );1077 }1078 1079 VISIT_END( WhenClause, node );1080 }1081 1082 //--------------------------------------------------------------------------1083 1068 // WaitForStmt 1084 1069 template< typename core_t > … … 1105 1090 1106 1091 if ( __visit_children() ) { 1107 maybe_accept( node, &WaitForClause::target );1092 maybe_accept( node, &WaitForClause::target_func ); 1108 1093 maybe_accept( node, &WaitForClause::target_args ); 1109 1094 maybe_accept( node, &WaitForClause::stmt ); 1110 maybe_accept( node, &WaitForClause:: when_cond );1095 maybe_accept( node, &WaitForClause::cond ); 1111 1096 } 1112 1097 1113 1098 VISIT_END( WaitForClause, node ); 1114 }1115 1116 //--------------------------------------------------------------------------1117 // WaitUntilStmt1118 template< typename core_t >1119 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitUntilStmt * node ) {1120 VISIT_START( node );1121 1122 if ( __visit_children() ) {1123 maybe_accept( node, &WaitUntilStmt::clauses );1124 maybe_accept( node, &WaitUntilStmt::timeout_time );1125 maybe_accept( node, &WaitUntilStmt::timeout_stmt );1126 maybe_accept( node, &WaitUntilStmt::timeout_cond );1127 maybe_accept( node, &WaitUntilStmt::else_stmt );1128 maybe_accept( node, &WaitUntilStmt::else_cond );1129 }1130 1131 VISIT_END( Stmt, node );1132 1099 } 1133 1100 -
src/AST/Print.cpp
rc083c3d r4daf79f 208 208 } 209 209 210 void print( const ast::WaitStmt * node ) {211 if ( node->timeout_time ) {212 os << indent-1 << "timeout of:" << endl;213 node->timeout_time->accept( *this );214 215 if ( node->timeout_stmt ) {216 os << indent-1 << "... with statment:" << endl;217 node->timeout_stmt->accept( *this );218 }219 220 if ( node->timeout_cond ) {221 os << indent-1 << "... with condition:" << endl;222 node->timeout_cond->accept( *this );223 }224 }225 226 if ( node->else_stmt ) {227 os << indent-1 << "else:" << endl;228 node->else_stmt->accept( *this );229 230 if ( node->else_cond ) {231 os << indent-1 << "... with condition:" << endl;232 node->else_cond->accept( *this );233 }234 }235 }236 237 210 void preprint( const ast::NamedTypeDecl * node ) { 238 211 if ( ! node->name.empty() ) { … … 783 756 } 784 757 785 virtual const ast::WhenClause * visit( const ast::WhenClause * node ) override final {786 os << indent-1 << "target: ";787 safe_print( node->target );788 789 if ( node->stmt ) {790 os << indent-1 << "... with statment:" << endl;791 node->stmt->accept( *this );792 }793 794 if ( node->when_cond ) {795 os << indent-1 << "... with when condition:" << endl;796 node->when_cond->accept( *this );797 }798 799 return node;800 }801 802 758 virtual const ast::Stmt * visit( const ast::WaitForStmt * node ) override final { 803 759 os << "Waitfor Statement" << endl; … … 837 793 virtual const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final { 838 794 os << indent-1 << "target function: "; 839 safe_print( node->target );795 safe_print( node->target_func ); 840 796 841 797 if ( !node->target_args.empty() ) { … … 851 807 } 852 808 853 if ( node-> when_cond ) {809 if ( node->cond ) { 854 810 os << indent-1 << "... with condition:" << endl; 855 node->when_cond->accept( *this ); 856 } 857 858 return node; 859 } 860 861 virtual const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final { 862 os << "Waituntil Statement" << endl; 863 indent += 2; 864 for( const auto & clause : node->clauses ) { 865 clause->accept( *this ); 866 } 867 print(node); // calls print( const ast::WaitStmt * node ) 811 node->cond->accept( *this ); 812 } 813 868 814 return node; 869 815 } -
src/AST/Stmt.hpp
rc083c3d r4daf79f 378 378 }; 379 379 380 // Base class of WaitFor/WaitUntil statements381 // form: KEYWORD(...) ... timeout(...) ... else ... 382 class WaitStmt : public Stmt { 383 public: 384 ptr<Expr> timeout_time;380 // Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ... 381 class WaitForStmt final : public Stmt { 382 public: 383 std::vector<ptr<WaitForClause>> clauses; 384 ptr<Expr> timeout_time; 385 385 ptr<Stmt> timeout_stmt; 386 386 ptr<Expr> timeout_cond; … … 388 388 ptr<Expr> else_cond; 389 389 390 WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )390 WaitForStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} ) 391 391 : Stmt(loc, std::move(labels)) {} 392 392 393 private: 394 WaitStmt * clone() const override = 0; 395 MUTATE_FRIEND 396 }; 397 398 // Base class for WaitFor/WaitUntil clauses 399 // form: when( when_cond ) KEYWORD( target ) stmt 400 class WhenClause : public StmtClause { 401 public: 402 ptr<Expr> target; 393 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 394 private: 395 WaitForStmt * clone() const override { return new WaitForStmt{ *this }; } 396 MUTATE_FRIEND 397 }; 398 399 // Clause in a waitfor statement: waitfor (..., ...) ... 400 class WaitForClause final : public StmtClause { 401 public: 402 ptr<Expr> target_func; 403 std::vector<ptr<Expr>> target_args; 403 404 ptr<Stmt> stmt; 404 ptr<Expr> when_cond;405 406 W henClause( const CodeLocation & loc )405 ptr<Expr> cond; 406 407 WaitForClause( const CodeLocation & loc ) 407 408 : StmtClause( loc ) {} 408 409 409 const WhenClause * accept( Visitor & v ) const override { return v.visit( this ); }410 private:411 WhenClause * clone() const override { return new WhenClause{ *this }; }412 MUTATE_FRIEND413 };414 415 // Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...416 class WaitForStmt final : public WaitStmt {417 public:418 std::vector<ptr<WaitForClause>> clauses;419 420 WaitForStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )421 : WaitStmt(loc, std::move(labels)) {}422 423 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }424 private:425 WaitForStmt * clone() const override { return new WaitForStmt{ *this }; }426 MUTATE_FRIEND427 };428 429 // Clause in a waitfor statement: waitfor (..., ...) ...430 class WaitForClause final : public WhenClause {431 public:432 std::vector<ptr<Expr>> target_args;433 434 WaitForClause( const CodeLocation & loc )435 : WhenClause( loc ) {}436 437 410 const WaitForClause * accept( Visitor & v ) const override { return v.visit( this ); } 438 411 private: 439 412 WaitForClause * clone() const override { return new WaitForClause{ *this }; } 440 MUTATE_FRIEND441 };442 443 // waituntil statement: when (...) waituntil (...) ... timeout(...) ... else ...444 class WaitUntilStmt final : public WaitStmt {445 public:446 // Non-ast node used during compilation to store data needed to generate predicates447 // and set initial status values for clauses448 // Used to create a tree corresponding to the structure of the clauses in a WaitUntil449 struct ClauseNode {450 enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag451 // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing452 453 ClauseNode * left;454 ClauseNode * right;455 WhenClause * leaf; // only set if this node is a leaf (points into vector of clauses)456 457 bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses458 bool whenState; // used to track if when_cond is toggled on or off for generating init values459 bool childOfAnd; // true on leaf nodes that are children of AND, false otherwise460 461 ClauseNode( Op op, ClauseNode * left, ClauseNode * right )462 : op(op), left(left), right(right), leaf(nullptr),463 ambiguousWhen(false), whenState(true), childOfAnd(false) {}464 ClauseNode( Op op, WhenClause * leaf )465 : op(op), left(nullptr), right(nullptr), leaf(leaf),466 ambiguousWhen(false), whenState(true), childOfAnd(false) {}467 ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {}468 469 ~ClauseNode() {470 if ( left ) delete left;471 if ( right ) delete right;472 }473 };474 475 std::vector<ptr<WhenClause>> clauses;476 ClauseNode * predicateTree;477 478 WaitUntilStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )479 : WaitStmt(loc, std::move(labels)) {}480 481 ~WaitUntilStmt() { delete predicateTree; }482 483 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }484 private:485 WaitUntilStmt * clone() const override { return new WaitUntilStmt{ *this }; }486 413 MUTATE_FRIEND 487 414 }; -
src/AST/Visitor.hpp
rc083c3d r4daf79f 50 50 virtual const ast::FinallyClause * visit( const ast::FinallyClause * ) = 0; 51 51 virtual const ast::Stmt * visit( const ast::SuspendStmt * ) = 0; 52 virtual const ast::WhenClause * visit( const ast::WhenClause * ) = 0;53 52 virtual const ast::Stmt * visit( const ast::WaitForStmt * ) = 0; 54 53 virtual const ast::WaitForClause * visit( const ast::WaitForClause * ) = 0; 55 virtual const ast::Stmt * visit( const ast::WaitUntilStmt * ) = 0;56 54 virtual const ast::Decl * visit( const ast::WithStmt * ) = 0; 57 55 virtual const ast::NullStmt * visit( const ast::NullStmt * ) = 0; -
src/Common/CodeLocationTools.cpp
rc083c3d r4daf79f 128 128 macro(FinallyClause, FinallyClause) \ 129 129 macro(SuspendStmt, Stmt) \ 130 macro(WhenClause, WhenClause) \131 130 macro(WaitForStmt, Stmt) \ 132 131 macro(WaitForClause, WaitForClause) \ 133 macro(WaitUntilStmt, Stmt) \134 132 macro(WithStmt, Decl) \ 135 133 macro(NullStmt, NullStmt) \ -
src/Concurrency/WaitforNew.cpp
rc083c3d r4daf79f 305 305 306 306 const ast::VariableExpr * variableExpr = 307 clause->target .as<ast::VariableExpr>();307 clause->target_func.as<ast::VariableExpr>(); 308 308 ast::Expr * castExpr = new ast::CastExpr( 309 309 location, 310 310 new ast::CastExpr( 311 311 location, 312 clause->target ,312 clause->target_func, 313 313 ast::deepCopy( variableExpr->result.get() ), 314 314 ast::GeneratedCast ), … … 325 325 326 326 ResolveContext context{ symtab, transUnit().global }; 327 out->push_back( maybeCond( location, clause-> when_cond.get(), {327 out->push_back( maybeCond( location, clause->cond.get(), { 328 328 makeAccStmt( location, acceptables, index, "is_dtor", 329 detectIsDtor( location, clause->target ), context ),329 detectIsDtor( location, clause->target_func ), context ), 330 330 makeAccStmt( location, acceptables, index, "func", 331 331 funcExpr, context ), -
src/Concurrency/module.mk
rc083c3d r4daf79f 23 23 Concurrency/WaitforNew.cpp \ 24 24 Concurrency/Waitfor.cc \ 25 Concurrency/Waitfor.h \ 26 Concurrency/Waituntil.cpp \ 27 Concurrency/Waituntil.hpp 25 Concurrency/Waitfor.h -
src/Parser/StatementNode.cc
rc083c3d r4daf79f 328 328 ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) { 329 329 auto clause = new ast::WaitForClause( location ); 330 clause->target = maybeBuild( targetExpr );330 clause->target_func = maybeBuild( targetExpr ); 331 331 clause->stmt = maybeMoveBuild( stmt ); 332 clause-> when_cond = notZeroExpr( maybeMoveBuild( when ) );332 clause->cond = notZeroExpr( maybeMoveBuild( when ) ); 333 333 334 334 ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() ); … … 359 359 return existing; 360 360 } // build_waitfor_timeout 361 362 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {363 ast::WhenClause * clause = new ast::WhenClause( loc );364 clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );365 clause->stmt = maybeMoveBuild( stmt );366 clause->target = maybeMoveBuild( targetExpr );367 return new ast::WaitUntilStmt::ClauseNode( clause );368 }369 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {370 ast::WhenClause * clause = new ast::WhenClause( loc );371 clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );372 clause->stmt = maybeMoveBuild( stmt );373 return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );374 }375 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {376 ast::WhenClause * clause = new ast::WhenClause( loc );377 clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );378 clause->stmt = maybeMoveBuild( stmt );379 clause->target = maybeMoveBuild( timeout );380 return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::TIMEOUT, clause );381 }382 383 ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation & loc, ast::WaitUntilStmt::ClauseNode * root ) {384 ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc );385 retStmt->predicateTree = root;386 387 // iterative tree traversal388 std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal389 ast::WaitUntilStmt::ClauseNode * currNode = nullptr;390 ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr;391 ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout392 nodeStack.push_back(root);393 394 do {395 currNode = nodeStack.back();396 nodeStack.pop_back(); // remove node since it will be processed397 398 switch (currNode->op) {399 case ast::WaitUntilStmt::ClauseNode::LEAF:400 retStmt->clauses.push_back(currNode->leaf);401 break;402 case ast::WaitUntilStmt::ClauseNode::ELSE:403 retStmt->else_stmt = currNode->leaf->stmt404 ? ast::deepCopy( currNode->leaf->stmt )405 : nullptr;406 407 retStmt->else_cond = currNode->leaf->when_cond408 ? ast::deepCopy( currNode->leaf->when_cond )409 : nullptr;410 411 delete currNode->leaf;412 break;413 case ast::WaitUntilStmt::ClauseNode::TIMEOUT:414 retStmt->timeout_time = currNode->leaf->target415 ? ast::deepCopy( currNode->leaf->target )416 : nullptr;417 retStmt->timeout_stmt = currNode->leaf->stmt418 ? ast::deepCopy( currNode->leaf->stmt )419 : nullptr;420 retStmt->timeout_cond = currNode->leaf->when_cond421 ? ast::deepCopy( currNode->leaf->when_cond )422 : nullptr;423 424 delete currNode->leaf;425 break;426 default:427 nodeStack.push_back( currNode->right ); // process right after left428 nodeStack.push_back( currNode->left );429 430 // Cut else/timeout out of the tree431 if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) {432 if ( lastInternalNode )433 lastInternalNode->right = currNode->left;434 else // if not set then root is LEFT_OR435 retStmt->predicateTree = currNode->left;436 437 currNode->left = nullptr;438 cleanup = currNode;439 }440 441 lastInternalNode = currNode;442 break;443 }444 } while ( !nodeStack.empty() );445 446 if ( cleanup ) delete cleanup;447 448 return retStmt;449 }450 361 451 362 ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) { -
src/Parser/StatementNode.h
rc083c3d r4daf79f 100 100 ast::WaitForStmt * build_waitfor_else( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt ); 101 101 ast::WaitForStmt * build_waitfor_timeout( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ); 102 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );103 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt );104 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation &, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );105 ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root );106 102 ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt ); 107 103 ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt ); -
src/Parser/parser.yy
rc083c3d r4daf79f 307 307 ClauseNode * clause; 308 308 ast::WaitForStmt * wfs; 309 ast::WaitUntilStmt::ClauseNode * wucn;310 309 CondCtl * ifctl; 311 310 ForCtrl * forctl; … … 428 427 %type<expr> when_clause when_clause_opt waitfor waituntil timeout 429 428 %type<stmt> waitfor_statement waituntil_statement 430 %type<wfs> wor_waitfor_clause 431 %type<wucn> waituntil_clause wand_waituntil_clause wor_waituntil_clause 429 %type<wfs> wor_waitfor_clause waituntil_clause wand_waituntil_clause wor_waituntil_clause 432 430 433 431 // declarations … … 1687 1685 waituntil_clause: 1688 1686 when_clause_opt waituntil statement 1689 { $$ = build_waituntil_clause( yylloc, $1, $2, maybe_build_compound( yylloc, $3 ) ); }1687 { printf( "waituntil_clause 1\n" ); $$ = nullptr; } 1690 1688 | '(' wor_waituntil_clause ')' 1691 { $$ = $2; }1689 { printf( "waituntil_clause 2\n" ); $$ = nullptr; } 1692 1690 ; 1693 1691 1694 1692 wand_waituntil_clause: 1695 1693 waituntil_clause %prec THEN 1696 { $$ = $1; }1694 { printf( "wand_waituntil_clause 1\n" ); $$ = nullptr; } 1697 1695 | waituntil_clause wand wand_waituntil_clause 1698 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::AND, $1, $3 ); }1696 { printf( "wand_waituntil_clause 2\n" ); $$ = nullptr; } 1699 1697 ; 1700 1698 1701 1699 wor_waituntil_clause: 1702 1700 wand_waituntil_clause 1703 { $$ = $1; }1701 { printf( "wor_waituntil_clause 1\n" ); $$ = nullptr; } 1704 1702 | wor_waituntil_clause wor wand_waituntil_clause 1705 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::OR, $1, $3 ); }1703 { printf( "wor_waituntil_clause 2\n" ); $$ = nullptr; } 1706 1704 | wor_waituntil_clause wor when_clause_opt ELSE statement 1707 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_else( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }1705 { printf( "wor_waituntil_clause 3\n" ); $$ = nullptr; } 1708 1706 | wor_waituntil_clause wor when_clause_opt timeout statement %prec THEN 1709 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ) ); }1707 { printf( "wor_waituntil_clause 4\n" ); $$ = nullptr; } 1710 1708 // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless) 1711 1709 | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error 1712 1710 { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; } 1713 1711 | wor_waituntil_clause wor when_clause_opt timeout statement wor when_clause ELSE statement 1714 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, 1715 new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::OR, 1716 build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ), 1717 build_waituntil_else( yylloc, $7, maybe_build_compound( yylloc, $9 ) ) ) ); } 1712 { printf( "wor_waituntil_clause 6\n" ); $$ = nullptr; } 1718 1713 ; 1719 1714 … … 1721 1716 wor_waituntil_clause %prec THEN 1722 1717 // SKULLDUGGERY: create an empty compound statement to test parsing of waituntil statement. 1723 { 1724 $$ = new StatementNode( build_waituntil_stmt( yylloc, $1 ) ); 1725 // $$ = new StatementNode( build_compound( yylloc, nullptr ) ); 1726 } 1718 { $$ = new StatementNode( build_compound( yylloc, nullptr ) ); } 1727 1719 ; 1728 1720 -
src/ResolvExpr/Resolver.cc
rc083c3d r4daf79f 1730 1730 1731 1731 // Find all candidates for a function in canonical form 1732 funcFinder.find( clause.target , ResolvMode::withAdjustment() );1732 funcFinder.find( clause.target_func, ResolvMode::withAdjustment() ); 1733 1733 1734 1734 if ( funcFinder.candidates.empty() ) { 1735 1735 stringstream ss; 1736 1736 ss << "Use of undeclared indentifier '"; 1737 ss << clause.target .strict_as< ast::NameExpr >()->name;1737 ss << clause.target_func.strict_as< ast::NameExpr >()->name; 1738 1738 ss << "' in call to waitfor"; 1739 1739 SemanticError( stmt->location, ss.str() ); … … 1922 1922 auto clause2 = new ast::WaitForClause( clause.location ); 1923 1923 1924 clause2->target = funcCandidates.front()->expr;1924 clause2->target_func = funcCandidates.front()->expr; 1925 1925 1926 1926 clause2->target_args.reserve( clause.target_args.size() ); … … 1945 1945 1946 1946 // Resolve the conditions as if it were an IfStmt, statements normally 1947 clause2-> when_cond = findSingleExpression( clause.when_cond, context );1947 clause2->cond = findSingleExpression( clause.cond, context ); 1948 1948 clause2->stmt = clause.stmt->accept( *visitor ); 1949 1949 -
src/main.cc
rc083c3d r4daf79f 48 48 #include "Concurrency/Keywords.h" // for implementMutex, implement... 49 49 #include "Concurrency/Waitfor.h" // for generateWaitfor 50 #include "Concurrency/Waituntil.hpp" // for generateWaitUntil51 50 #include "ControlStruct/ExceptDecl.h" // for translateExcept 52 51 #include "ControlStruct/ExceptTranslate.h" // for translateThrows, translat... … … 341 340 PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit ); 342 341 PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit ); 343 PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit );344 342 PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit ); 345 343 -
tests/Makefile.am
rc083c3d r4daf79f 11 11 ## Created On : Sun May 31 09:08:15 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Mon May 1 1 7:25:24202314 ## Update Count : 14 513 ## Last Modified On : Mon May 1 16:45:07 2023 14 ## Update Count : 144 15 15 ############################################################################### 16 16 … … 116 116 #---------------------------------------------------------------------------------------------------------------- 117 117 118 all-local : # This name is important to automake and implies the default build target.118 all-local : 119 119 @+$(TEST_PY) --debug=$(debug) --install=$(installed) --archive-errors=$(archiveerrors) $(concurrent) $(timeouts) $(ARCH) --all # '@' => do not echo command (SILENT), '+' => allows recursive make from within python program 120 120 -
tests/concurrent/futures/select_future.cfa
rc083c3d r4daf79f 196 196 delete( shared_future ); 197 197 printf( "done 3\n" ); 198 } 198 199 // C_TODO: add test for select statement once it is implemented 200 }
Note:
See TracChangeset
for help on using the changeset viewer.