Changeset b580bcc
- Timestamp:
- Apr 1, 2021, 4:20:00 PM (3 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- fd1f65e
- Parents:
- 3bd2464 (diff), 198e335 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 4 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/andrew_beach_MMath/future.tex
r3bd2464 rb580bcc 83 83 patterns to find the handler. 84 84 85 \section{Checked Exceptions} 86 Checked exceptions make exceptions part of a function's type by adding the 87 exception signature. An exception signature must declare all checked 88 exceptions that could propogate from the function (either because they were 89 raised inside the function or came from a sub-function). This improves safety 90 by making sure every checked exception is either handled or consciously 91 passed on. 92 93 However checked exceptions were never seriously considered for this project 94 for two reasons. The first is due to time constraints, even copying an 95 existing checked exception system would be pushing the remaining time and 96 trying to address the second problem would take even longer. The second 97 problem is that checked exceptions have some real usability trade-offs in 98 exchange for the increased safety. 99 100 These trade-offs are most problematic when trying to pass exceptions through 101 higher-order functions from the functions the user passed into the 102 higher-order function. There are no well known solutions to this problem 103 that were statifactory for \CFA (which carries some of C's flexability 104 over safety design) so one would have to be researched and developed. 105 106 Follow-up work might add checked exceptions to \CFA, possibly using 107 polymorphic exception signatures, a form of tunneling\cite{Zhang19} or 108 checked and unchecked raises. 109 85 110 \section{Zero-Cost Try} 86 111 \CFA does not have zero-cost try-statements because the compiler generates C -
libcfa/src/bits/weakso_locks.cfa
r3bd2464 rb580bcc 18 18 #include "bits/weakso_locks.hfa" 19 19 20 void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner) {}21 void ^?{}( blocking_lock & this) {}20 void ?{}( blocking_lock &, bool, bool ) {} 21 void ^?{}( blocking_lock & ) {} 22 22 23 void lock( blocking_lock & this ) {} 24 bool try_lock( blocking_lock & this ) { return false; } 25 void unlock( blocking_lock & this ) {} 26 void on_notify( blocking_lock & this, struct $thread * t ) {} 27 void on_wait( blocking_lock & this ) {} 28 size_t wait_count( blocking_lock & this ) { return 0; } 29 void set_recursion_count( blocking_lock & this, size_t recursion ) {} 30 size_t get_recursion_count( blocking_lock & this ) { return 0; } 23 void lock( blocking_lock & ) {} 24 bool try_lock( blocking_lock & ) { return false; } 25 void unlock( blocking_lock & ) {} 26 void on_notify( blocking_lock &, struct $thread * ) {} 27 size_t on_wait( blocking_lock & ) {} 28 void on_wakeup( blocking_lock &, size_t ) {} 29 size_t wait_count( blocking_lock & ) { return 0; } -
libcfa/src/bits/weakso_locks.hfa
r3bd2464 rb580bcc 56 56 void unlock( blocking_lock & this ) OPTIONAL_THREAD; 57 57 void on_notify( blocking_lock & this, struct $thread * t ) OPTIONAL_THREAD; 58 void on_wait( blocking_lock & this ) OPTIONAL_THREAD; 58 size_t on_wait( blocking_lock & this ) OPTIONAL_THREAD; 59 void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD; 59 60 size_t wait_count( blocking_lock & this ) OPTIONAL_THREAD; 60 void set_recursion_count( blocking_lock & this, size_t recursion ) OPTIONAL_THREAD;61 size_t get_recursion_count( blocking_lock & this ) OPTIONAL_THREAD;62 61 63 62 //---------- … … 72 71 static inline bool try_lock ( multiple_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); } 73 72 static inline void unlock ( multiple_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 74 static inline void on_wait ( multiple_acquisition_lock & this ) { on_wait ( (blocking_lock &)this ); } 73 static inline size_t on_wait ( multiple_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); } 74 static inline void on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 75 75 static inline void on_notify( multiple_acquisition_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); } 76 static inline void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }77 static inline size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); } -
libcfa/src/concurrency/locks.cfa
r3bd2464 rb580bcc 134 134 lock( lock __cfaabi_dbg_ctx2 ); 135 135 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); 136 /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 136 /* paranoid */ verifyf( owner == active_thread() || !strict_owner , "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 137 /* paranoid */ verifyf( recursion_count == 1 || multi_acquisition, "Thread %p attempted to release owner lock %p which is not recursive but has a recursive count of %zu", active_thread(), &this, recursion_count ); 137 138 138 139 // if recursion count is zero release lock and set new owner if one is waiting … … 146 147 size_t wait_count( blocking_lock & this ) with( this ) { 147 148 return wait_count; 148 }149 150 void set_recursion_count( blocking_lock & this, size_t recursion ) with( this ) {151 recursion_count = recursion;152 }153 154 size_t get_recursion_count( blocking_lock & this ) with( this ) {155 return recursion_count;156 149 } 157 150 … … 173 166 } 174 167 175 voidon_wait( blocking_lock & this ) with( this ) {168 size_t on_wait( blocking_lock & this ) with( this ) { 176 169 lock( lock __cfaabi_dbg_ctx2 ); 177 170 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); 178 171 /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 179 172 173 size_t ret = recursion_count; 174 180 175 pop_and_set_new_owner( this ); 181 176 unlock( lock ); 177 return ret; 178 } 179 180 void on_wakeup( blocking_lock & this, size_t recursion ) with( this ) { 181 recursion_count = recursion; 182 182 } 183 183 … … 274 274 } 275 275 276 bool empty( condition_variable(L) & this ) with(this) { return empty(blocked_threads); } 276 bool empty( condition_variable(L) & this ) with(this) { 277 lock( lock __cfaabi_dbg_ctx2 ); 278 bool ret = empty(blocked_threads); 279 unlock( lock ); 280 return ret; 281 } 277 282 278 283 int counter( condition_variable(L) & this ) with(this) { return count; } … … 285 290 if (i->lock) { 286 291 // if lock was passed get recursion count to reset to after waking thread 287 recursion_count = get_recursion_count(*i->lock); 288 on_wait( *i->lock ); 292 recursion_count = on_wait( *i->lock ); 289 293 } 290 294 return recursion_count; … … 301 305 302 306 // resets recursion count here after waking 303 if (i.lock) set_recursion_count(*i.lock, recursion_count);307 if (i.lock) on_wakeup(*i.lock, recursion_count); 304 308 } 305 309 … … 323 327 324 328 // resets recursion count here after waking 325 if (info.lock) set_recursion_count(*info.lock, recursion_count);329 if (info.lock) on_wakeup(*info.lock, recursion_count); 326 330 } 327 331 … … 373 377 } 374 378 375 bool V(semaphore & this) with( this ) {379 $thread * V (semaphore & this, const bool doUnpark ) with( this ) { 376 380 $thread * thrd = 0p; 377 381 lock( lock __cfaabi_dbg_ctx2 ); … … 385 389 386 390 // make new owner 387 unpark( thrd ); 388 391 if( doUnpark ) unpark( thrd ); 392 393 return thrd; 394 } 395 396 bool V(semaphore & this) with( this ) { 397 $thread * thrd = V(this, true); 389 398 return thrd != 0p; 390 399 } -
libcfa/src/concurrency/locks.hfa
r3bd2464 rb580bcc 39 39 }; 40 40 41 static inline bool P(Semaphore0nary & this, $thread * thrd) __attribute__((artificial));42 41 static inline bool P(Semaphore0nary & this, $thread * thrd) { 43 42 /* paranoid */ verify(!(thrd->seqable.next)); … … 48 47 } 49 48 50 static inline bool P(Semaphore0nary & this) __attribute__((artificial));51 49 static inline bool P(Semaphore0nary & this) { 52 50 $thread * thrd = active_thread(); … … 56 54 } 57 55 58 static inline $thread * V(Semaphore0nary & this, const bool doUnpark = true) __attribute__((artificial)); 59 static inline $thread * V(Semaphore0nary & this, const bool doUnpark = true) { 56 static inline $thread * V(Semaphore0nary & this, bool doUnpark = true) { 60 57 $thread * next; 61 58 lock(this.lock __cfaabi_dbg_ctx2); … … 82 79 83 80 // returns true if no blocking needed 84 bool P(BinaryBenaphore & this) { return __atomic_fetch_sub(&this.counter, 1, __ATOMIC_SEQ_CST) > 0; } 81 bool P(BinaryBenaphore & this) { 82 return __atomic_fetch_sub(&this.counter, 1, __ATOMIC_SEQ_CST) > 0; 83 } 84 85 85 bool tryP(BinaryBenaphore & this) { 86 86 ssize_t c = this.counter; … … 115 115 static inline void ?{}(ThreadBenaphore & this, one_t ) { (this.ben){ 1 }; } 116 116 117 static inline bool P(ThreadBenaphore & this) { return /* P(this.ben) ? false : */ P(this.sem); } 118 static inline bool P(ThreadBenaphore & this, $thread * t) { return /* P(this.ben) ? false : */ P(this.sem, t ); } 117 static inline bool P(ThreadBenaphore & this) { return P(this.ben) ? false : P(this.sem); } 119 118 static inline bool tryP(ThreadBenaphore & this) { return tryP(this.ben); } 120 119 static inline bool P(ThreadBenaphore & this, bool wait) { return wait ? P(this) : tryP(this); } 121 120 122 static inline $thread * V(ThreadBenaphore & this, constbool doUnpark = true) {123 //if (V(this.ben)) return 0p;121 static inline $thread * V(ThreadBenaphore & this, bool doUnpark = true) { 122 if (V(this.ben)) return 0p; 124 123 return V(this.sem, doUnpark); 125 124 } … … 138 137 bool V (semaphore & this); 139 138 bool V (semaphore & this, unsigned count); 139 $thread * V (semaphore & this, bool ); 140 140 141 141 //---------- … … 146 146 static inline void ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };} 147 147 static inline void ^?{}( single_acquisition_lock & this ) {} 148 static inline void lock ( single_acquisition_lock & this ) { lock ( (blocking_lock &)this ); } 149 static inline bool try_lock ( single_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); } 150 static inline void unlock ( single_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 151 static inline void on_wait ( single_acquisition_lock & this ) { on_wait ( (blocking_lock &)this ); } 152 static inline void on_notify ( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); } 153 static inline void set_recursion_count( single_acquisition_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); } 154 static inline size_t get_recursion_count( single_acquisition_lock & this ) { return get_recursion_count( (blocking_lock &)this ); } 148 static inline void lock ( single_acquisition_lock & this ) { lock ( (blocking_lock &)this ); } 149 static inline bool try_lock ( single_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); } 150 static inline void unlock ( single_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 151 static inline size_t on_wait ( single_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); } 152 static inline void on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 153 static inline void on_notify( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); } 155 154 156 155 //---------- … … 164 163 static inline bool try_lock ( owner_lock & this ) { return try_lock( (blocking_lock &)this ); } 165 164 static inline void unlock ( owner_lock & this ) { unlock ( (blocking_lock &)this ); } 166 static inline void on_wait ( owner_lock & this ) { on_wait ( (blocking_lock &)this ); } 165 static inline size_t on_wait ( owner_lock & this ) { return on_wait ( (blocking_lock &)this ); } 166 static inline void on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 167 167 static inline void on_notify( owner_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); } 168 static inline void set_recursion_count( owner_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }169 static inline size_t get_recursion_count( owner_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }170 168 171 169 struct fast_lock { … … 179 177 } 180 178 181 static inline void $lock(fast_lock & this, $thread * thrd) { 182 /* paranoid */verify(thrd != this.owner); 183 184 for (;;) { 185 if ($try_lock(this, thrd)) return; 186 P(this.sem, thrd); 187 } 188 } 189 179 static inline void lock( fast_lock & this ) __attribute__((artificial)); 190 180 static inline void lock( fast_lock & this ) { 191 181 $thread * thrd = active_thread(); … … 198 188 } 199 189 200 static inline void try_lock ( fast_lock & this ) { 190 static inline bool try_lock( fast_lock & this ) __attribute__((artificial)); 191 static inline bool try_lock ( fast_lock & this ) { 201 192 $thread * thrd = active_thread(); 202 193 /* paranoid */ verify(thrd != this.owner); … … 204 195 } 205 196 206 static inline void unlock( fast_lock & this ) { 197 static inline $thread * unlock( fast_lock & this ) __attribute__((artificial)); 198 static inline $thread * unlock( fast_lock & this ) { 207 199 $thread * thrd = active_thread(); 208 200 /* paranoid */ verify(thrd == this.owner); 209 $thread * next = V(this.sem, false); // implicit fence 210 // open 'owner' only after fence 201 202 // open 'owner' before unlocking anyone 203 // so new and unlocked threads don't park incorrectly. 204 // This may require additional fencing on ARM. 211 205 this.owner = 0p; 212 206 213 // Unpark the next person (can be 0p, unpark handles it) 214 unpark(next); 215 } 216 217 static inline void on_wait( fast_lock & this ) { 218 unlock(this); 219 #warning this is broken 220 } 221 222 static inline void on_notify( fast_lock & this, struct $thread * t ) { 223 $lock(this, t); 224 #warning this is broken 225 } 226 227 static inline void set_recursion_count( fast_lock & this, size_t recursion ) {} 228 static inline size_t get_recursion_count( fast_lock & this ) { return 0; } 207 return V(this.sem); 208 } 209 210 static inline size_t on_wait( fast_lock & this ) { unlock(this); return 0; } 211 static inline void on_wakeup( fast_lock & this, size_t ) { lock(this); } 212 static inline void on_notify( fast_lock &, struct $thread * t ) { unpark(t); } 229 213 230 214 struct mcs_node { … … 260 244 261 245 // For synchronization locks to use when releasing 262 void on_wait( L & ); 263 264 // to get recursion count for cond lock to reset after waking 265 size_t get_recursion_count( L & ); 246 size_t on_wait( L & ); 266 247 267 248 // to set recursion count after getting signalled; 268 void set_recursion_count( L &, size_t recursion );249 void on_wakeup( L &, size_t recursion ); 269 250 }; 270 251 -
tests/concurrent/spinaphore.cfa
r3bd2464 rb580bcc 36 36 this.sum = 0; 37 37 for(num_blocks) { 38 // sout | "b P" | me;39 38 P(sem); 40 39 if(((thread&)this).seqable.next != 0p) sout | "Link not invalidated"; 41 // sout | "a P" | me;42 40 } 43 41 } … … 58 56 this.sum += (unsigned)b; 59 57 unpark(t); 60 // sout | "a V" | t;61 58 yield(random(10)); 62 59 } -
tests/unified_locking/.expect/locks.txt
r3bd2464 rb580bcc 11 11 Start Test 6: owner lock and condition variable 3 wait/notify all 12 12 Done Test 6 13 Start Test 7: multi acquisiton lock and condition variable multiple acquire andwait/notify13 Start Test 7: fast lock and condition variable single wait/notify 14 14 Done Test 7 15 Start Test 8: owner lock and condition variable multiple acquire and wait/notify15 Start Test 8: fast lock and condition variable 3 wait/notify all 16 16 Done Test 8 17 Start Test 9: no lock condition variablewait/notify17 Start Test 9: multi acquisiton lock and condition variable multiple acquire and wait/notify 18 18 Done Test 9 19 Start Test 10: locked condition variable wait/notify with front()19 Start Test 10: owner lock and condition variable multiple acquire and wait/notify 20 20 Done Test 10 21 Start Test 11: no lock condition variable wait/notify 22 Done Test 11 23 Start Test 12: locked condition variable wait/notify with front() 24 Done Test 12 -
tests/unified_locking/locks.cfa
r3bd2464 rb580bcc 15 15 condition_variable( owner_lock ) c_o; 16 16 17 fast_lock f; 18 condition_variable( fast_lock ) c_f; 19 17 20 thread T_C_M_WS1 {}; 18 21 … … 68 71 } 69 72 unlock(s); 73 } 74 } 75 76 thread T_C_F_WS1 {}; 77 78 void main( T_C_F_WS1 & this ) { 79 for (unsigned int i = 0; i < num_times; i++) { 80 lock(f); 81 if(empty(c_f) && i != num_times - 1) { 82 wait(c_f,f); 83 }else{ 84 notify_one(c_f); 85 } 86 unlock(f); 87 } 88 } 89 90 thread T_C_F_WB1 {}; 91 92 void main( T_C_F_WB1 & this ) { 93 for (unsigned int i = 0; i < num_times; i++) { 94 lock(f); 95 if(counter(c_f) == 3 || i == num_times - 1) { 96 notify_all(c_f); 97 }else{ 98 wait(c_f,f); 99 } 100 unlock(f); 70 101 } 71 102 } … … 255 286 printf("Done Test 6\n"); 256 287 257 printf("Start Test 7: multi acquisiton lock and condition variable multiple acquire and wait/notify\n"); 288 printf("Start Test 7: fast lock and condition variable single wait/notify\n"); 289 { 290 T_C_F_WS1 t1[2]; 291 } 292 printf("Done Test 7\n"); 293 294 printf("Start Test 8: fast lock and condition variable 3 wait/notify all\n"); 295 { 296 T_C_F_WB1 t1[4]; 297 } 298 printf("Done Test 8\n"); 299 300 printf("Start Test 9: multi acquisiton lock and condition variable multiple acquire and wait/notify\n"); 258 301 { 259 302 T_C_M_WS2 t1[2]; 260 303 } 261 printf("Done Test 7\n");262 263 printf("Start Test 8: owner lock and condition variable multiple acquire and wait/notify\n");304 printf("Done Test 9\n"); 305 306 printf("Start Test 10: owner lock and condition variable multiple acquire and wait/notify\n"); 264 307 { 265 308 T_C_O_WS2 t1[2]; 266 309 } 267 printf("Done Test 8\n");268 269 printf("Start Test 9: no lock condition variable wait/notify\n");310 printf("Done Test 10\n"); 311 312 printf("Start Test 11: no lock condition variable wait/notify\n"); 270 313 { 271 314 T_C_NLW t1; 272 315 T_C_NLS t2; 273 316 } 274 printf("Done Test 9\n");275 276 printf("Start Test 1 0: locked condition variable wait/notify with front()\n");317 printf("Done Test 11\n"); 318 319 printf("Start Test 12: locked condition variable wait/notify with front()\n"); 277 320 { 278 321 T_C_S_WNF t1[2]; 279 322 } 280 printf("Done Test 1 0\n");323 printf("Done Test 12\n"); 281 324 282 325 // removed to limit test duration. Full test is in long run tests
Note: See TracChangeset
for help on using the changeset viewer.