- Timestamp:
- Apr 21, 2023, 5:36:12 PM (3 years ago)
- Branches:
- ADT, master, stuck-waitfor-destruct
- Children:
- 28f8f15, 6e4c44d
- Parents:
- 2ed94a9 (diff), 699a97d (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. - Location:
- libcfa/src
- Files:
-
- 1 added
- 39 edited
-
Makefile.am (modified) (1 diff)
-
algorithms/range_iterator.hfa (modified) (1 diff)
-
bitmanip.hfa (modified) (1 diff)
-
bits/random.hfa (modified) (18 diffs)
-
concurrency/actor.hfa (modified) (17 diffs)
-
concurrency/channel.hfa (modified) (3 diffs)
-
concurrency/clib/cfathread.cfa (modified) (6 diffs)
-
concurrency/clib/cfathread.h (modified) (3 diffs)
-
concurrency/coroutine.cfa (modified) (1 diff)
-
concurrency/future.hfa (modified) (1 diff)
-
concurrency/invoke.h (modified) (1 diff)
-
concurrency/io.cfa (modified) (2 diffs)
-
concurrency/io/call.cfa.in (modified) (11 diffs)
-
concurrency/io/setup.cfa (modified) (1 diff)
-
concurrency/iofwd.hfa (modified) (5 diffs)
-
concurrency/kernel.cfa (modified) (1 diff)
-
concurrency/kernel/cluster.cfa (modified) (5 diffs)
-
concurrency/kernel/cluster.hfa (modified) (1 diff)
-
concurrency/kernel/private.hfa (modified) (3 diffs)
-
concurrency/kernel/startup.cfa (modified) (3 diffs)
-
concurrency/locks.cfa (modified) (1 diff)
-
concurrency/locks.hfa (modified) (10 diffs)
-
concurrency/monitor.cfa (modified) (1 diff)
-
concurrency/mutex.cfa (modified) (1 diff)
-
concurrency/mutex_stmt.hfa (modified) (3 diffs)
-
concurrency/preemption.cfa (modified) (1 diff)
-
concurrency/pthread.cfa (modified) (37 diffs)
-
concurrency/ready_queue.cfa (modified) (1 diff)
-
concurrency/select.hfa (modified) (1 diff)
-
concurrency/thread.cfa (modified) (1 diff)
-
containers/array.hfa (modified) (1 diff)
-
containers/list.hfa (modified) (1 diff)
-
containers/vector2.hfa (modified) (1 diff)
-
interpose.cfa (modified) (5 diffs)
-
interpose_thread.cfa (modified) (3 diffs)
-
iostream.cfa (modified) (2 diffs)
-
limits.cfa (modified) (1 diff)
-
stdlib.cfa (modified) (2 diffs)
-
vec/vec.hfa (modified) (1 diff)
-
virtual_dtor.hfa (added)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/Makefile.am
r2ed94a9 rb110bcc 48 48 math.hfa \ 49 49 time_t.hfa \ 50 virtual_dtor.hfa \ 50 51 bits/algorithm.hfa \ 51 52 bits/align.hfa \ -
libcfa/src/algorithms/range_iterator.hfa
r2ed94a9 rb110bcc 9 9 // Author : Thierry Delisle 10 10 // Created On : Tue Nov 30 13:06:22 2021 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 13 23:10:35 2023 13 // Update Count : 1 14 14 // 15 16 #pragma once 15 17 16 18 generator RangeIter { -
libcfa/src/bitmanip.hfa
r2ed94a9 rb110bcc 11 11 // Created On : Sat Mar 14 18:12:27 2020 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Sat Oct 8 08:28:15 202214 // Update Count : 14 213 // Last Modified On : Mon Jan 9 09:02:43 2023 14 // Update Count : 144 15 15 // 16 16 17 17 #pragma once 18 19 #include "bits/debug.hfa" // verify 18 20 19 21 // Reference: Bit Twiddling Hacks: http://graphics.stanford.edu/%7Eseander/bithacks.html#CountBitsSetNaive -
libcfa/src/bits/random.hfa
r2ed94a9 rb110bcc 10 10 // Created On : Fri Jan 14 07:18:11 2022 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Dec 22 20:54:22 202213 // Update Count : 1 7812 // Last Modified On : Mon Mar 20 21:45:24 2023 13 // Update Count : 186 14 14 // 15 15 … … 28 28 #define XOSHIRO256PP 29 29 //#define KISS_64 30 // #define SPLITMIX_64 30 31 31 32 // 32-bit generators 32 33 //#define XORSHIFT_6_21_7 33 34 #define XOSHIRO128PP 35 // #define SPLITMIX_32 34 36 #else // 32-bit architecture 35 37 // 64-bit generators 36 38 //#define XORSHIFT_13_7_17 37 39 #define XOSHIRO256PP 40 // #define SPLITMIX_64 38 41 39 42 // 32-bit generators 40 43 //#define XORSHIFT_6_21_7 41 44 #define XOSHIRO128PP 45 // #define SPLITMIX_32 42 46 #endif // __x86_64__ 43 47 44 48 // Define C/CFA PRNG name and random-state. 45 46 // SKULLDUGGERY: typedefs name struct and typedef with the same name to deal with CFA typedef numbering problem.47 49 48 50 #ifdef XOSHIRO256PP 49 51 #define PRNG_NAME_64 xoshiro256pp 50 52 #define PRNG_STATE_64_T GLUE(PRNG_NAME_64,_t) 51 typedef struct PRNG_STATE_64_T{ uint64_t s0, s1, s2, s3; } PRNG_STATE_64_T;53 typedef struct { uint64_t s0, s1, s2, s3; } PRNG_STATE_64_T; 52 54 #endif // XOSHIRO256PP 53 55 … … 55 57 #define PRNG_NAME_32 xoshiro128pp 56 58 #define PRNG_STATE_32_T GLUE(PRNG_NAME_32,_t) 57 typedef struct PRNG_STATE_32_T{ uint32_t s0, s1, s2, s3; } PRNG_STATE_32_T;59 typedef struct { uint32_t s0, s1, s2, s3; } PRNG_STATE_32_T; 58 60 #endif // XOSHIRO128PP 59 61 … … 83 85 #endif // XORSHIFT_12_25_27 84 86 87 #ifdef SPLITMIX_64 88 #define PRNG_NAME_64 splitmix64 89 #define PRNG_STATE_64_T uint64_t 90 #endif // SPLITMIX32 91 92 #ifdef SPLITMIX_32 93 #define PRNG_NAME_32 splitmix32 94 #define PRNG_STATE_32_T uint32_t 95 #endif // SPLITMIX32 96 85 97 #ifdef KISS_64 86 98 #define PRNG_NAME_64 kiss_64 87 99 #define PRNG_STATE_64_T GLUE(PRNG_NAME_64,_t) 88 typedef struct PRNG_STATE_64_T{ uint64_t z, w, jsr, jcong; } PRNG_STATE_64_T;100 typedef struct { uint64_t z, w, jsr, jcong; } PRNG_STATE_64_T; 89 101 #endif // KISS_^64 90 102 … … 92 104 #define PRNG_NAME_32 xorwow 93 105 #define PRNG_STATE_32_T GLUE(PRNG_NAME_32,_t) 94 typedef struct PRNG_STATE_32_T{ uint32_t a, b, c, d, counter; } PRNG_STATE_32_T;106 typedef struct { uint32_t a, b, c, d, counter; } PRNG_STATE_32_T; 95 107 #endif // XOSHIRO128PP 96 108 … … 119 131 #ifdef __cforall // don't include in C code (invoke.h) 120 132 133 // https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64 134 // 135 // Splitmix64 is not recommended for demanding random number requirements, but is often used to calculate initial states 136 // for other more complex pseudo-random number generators (see https://prng.di.unimi.it). 137 // Also https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64. 138 static inline uint64_t splitmix64( uint64_t & state ) { 139 state += 0x9e3779b97f4a7c15; 140 uint64_t z = state; 141 z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; 142 z = (z ^ (z >> 27)) * 0x94d049bb133111eb; 143 return z ^ (z >> 31); 144 } // splitmix64 145 146 static inline void splitmix64_set_seed( uint64_t & state , uint64_t seed ) { 147 state = seed; 148 splitmix64( state ); // prime 149 } // splitmix64_set_seed 150 151 // https://github.com/bryc/code/blob/master/jshash/PRNGs.md#splitmix32 152 // 153 // Splitmix32 is not recommended for demanding random number requirements, but is often used to calculate initial states 154 // for other more complex pseudo-random number generators (see https://prng.di.unimi.it). 155 156 static inline uint32_t splitmix32( uint32_t & state ) { 157 state += 0x9e3779b9; 158 uint64_t z = state; 159 z = (z ^ (z >> 15)) * 0x85ebca6b; 160 z = (z ^ (z >> 13)) * 0xc2b2ae35; 161 return z ^ (z >> 16); 162 } // splitmix32 163 164 static inline void splitmix32_set_seed( uint32_t & state, uint64_t seed ) { 165 state = seed; 166 splitmix32( state ); // prime 167 } // splitmix32_set_seed 168 169 #ifdef __SIZEOF_INT128__ 170 //-------------------------------------------------- 171 static inline uint64_t lehmer64( __uint128_t & state ) { 172 __uint128_t ret = state; 173 state *= 0x_da94_2042_e4dd_58b5; 174 return ret >> 64; 175 } // lehmer64 176 177 static inline void lehmer64_set_seed( __uint128_t & state, uint64_t seed ) { 178 // The seed needs to be coprime with the 2^64 modulus to get the largest period, so no factors of 2 in the seed. 179 state = splitmix64( seed ); // prime 180 } // lehmer64_set_seed 181 182 //-------------------------------------------------- 183 static inline uint64_t wyhash64( uint64_t & state ) { 184 uint64_t ret = state; 185 state += 0x_60be_e2be_e120_fc15; 186 __uint128_t tmp; 187 tmp = (__uint128_t) ret * 0x_a3b1_9535_4a39_b70d; 188 uint64_t m1 = (tmp >> 64) ^ tmp; 189 tmp = (__uint128_t)m1 * 0x_1b03_7387_12fa_d5c9; 190 uint64_t m2 = (tmp >> 64) ^ tmp; 191 return m2; 192 } // wyhash64 193 194 static inline void wyhash64_set_seed( uint64_t & state, uint64_t seed ) { 195 state = splitmix64( seed ); // prime 196 } // wyhash64_set_seed 197 #endif // __SIZEOF_INT128__ 198 121 199 // https://prng.di.unimi.it/xoshiro256starstar.c 122 200 // … … 130 208 131 209 #ifndef XOSHIRO256PP 132 typedef struct xoshiro256pp_t{ uint64_t s0, s1, s2, s3; } xoshiro256pp_t;210 typedef struct { uint64_t s0, s1, s2, s3; } xoshiro256pp_t; 133 211 #endif // ! XOSHIRO256PP 134 212 … … 151 229 152 230 static inline void xoshiro256pp_set_seed( xoshiro256pp_t & state, uint64_t seed ) { 153 state = (xoshiro256pp_t){ seed, seed, seed, seed }; 154 xoshiro256pp( state ); 231 // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined. 232 uint64_t seed1 = splitmix64( seed ); // prime 233 uint64_t seed2 = splitmix64( seed ); 234 uint64_t seed3 = splitmix64( seed ); 235 uint64_t seed4 = splitmix64( seed ); 236 state = (xoshiro256pp_t){ seed1, seed2, seed3, seed4 }; 155 237 } // xoshiro256pp_set_seed 156 238 … … 165 247 166 248 #ifndef XOSHIRO128PP 167 typedef struct xoshiro128pp_t{ uint32_t s0, s1, s2, s3; } xoshiro128pp_t;249 typedef struct { uint32_t s0, s1, s2, s3; } xoshiro128pp_t; 168 250 #endif // ! XOSHIRO128PP 169 251 … … 186 268 187 269 static inline void xoshiro128pp_set_seed( xoshiro128pp_t & state, uint32_t seed ) { 188 state = (xoshiro128pp_t){ seed, seed, seed, seed }; 189 xoshiro128pp( state ); // prime 270 // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined. 271 uint32_t seed1 = splitmix32( seed ); // prime 272 uint32_t seed2 = splitmix32( seed ); 273 uint32_t seed3 = splitmix32( seed ); 274 uint32_t seed4 = splitmix32( seed ); 275 state = (xoshiro128pp_t){ seed1, seed2, seed3, seed4 }; 190 276 } // xoshiro128pp_set_seed 191 192 #ifdef __SIZEOF_INT128__193 //--------------------------------------------------194 static inline uint64_t lehmer64( __uint128_t & state ) {195 __uint128_t ret = state;196 state *= 0x_da94_2042_e4dd_58b5;197 return ret >> 64;198 } // lehmer64199 200 static inline void lehmer64_set_seed( __uint128_t & state, uint64_t seed ) {201 // The seed needs to be coprime with the 2^64 modulus to get the largest period, so no factors of 2 in the seed.202 state = seed;203 lehmer64( state ); // prime204 } // lehmer64_set_seed205 206 //--------------------------------------------------207 static inline uint64_t wyhash64( uint64_t & state ) {208 uint64_t ret = state;209 state += 0x_60be_e2be_e120_fc15;210 __uint128_t tmp;211 tmp = (__uint128_t) ret * 0x_a3b1_9535_4a39_b70d;212 uint64_t m1 = (tmp >> 64) ^ tmp;213 tmp = (__uint128_t)m1 * 0x_1b03_7387_12fa_d5c9;214 uint64_t m2 = (tmp >> 64) ^ tmp;215 return m2;216 } // wyhash64217 218 static inline void wyhash64_set_seed( uint64_t & state, uint64_t seed ) {219 state = seed;220 wyhash64( state ); // prime221 } // wyhash64_set_seed222 #endif // __SIZEOF_INT128__223 277 224 278 //-------------------------------------------------- … … 232 286 233 287 static inline void xorshift_13_7_17_set_seed( uint64_t & state, uint64_t seed ) { 234 state = seed; 235 xorshift_13_7_17( state ); // prime 288 state = splitmix64( seed ); // prime 236 289 } // xorshift_13_7_17_set_seed 237 290 … … 250 303 251 304 static inline void xorshift_6_21_7_set_seed( uint32_t & state, uint32_t seed ) { 252 state = seed; 253 xorshift_6_21_7( state ); // prime 305 state = splitmix32( seed ); // prime 254 306 } // xorshift_6_21_7_set_seed 255 307 … … 265 317 266 318 static inline void xorshift_12_25_27_set_seed( uint64_t & state, uint64_t seed ) { 267 state = seed; 268 xorshift_12_25_27( state ); // prime 319 state = splitmix64( seed ); // prime 269 320 } // xorshift_12_25_27_set_seed 270 321 … … 272 323 // The state must be seeded with a nonzero value. 273 324 #ifndef KISS_64 274 typedef struct kiss_64_t{ uint64_t z, w, jsr, jcong; } kiss_64_t;325 typedef struct { uint64_t z, w, jsr, jcong; } kiss_64_t; 275 326 #endif // ! KISS_64 276 327 … … 287 338 288 339 static inline void kiss_64_set_seed( kiss_64_t & rs, uint64_t seed ) with(rs) { 289 z = 1; w = 1; jsr = 4; jcong = seed; 290 kiss_64( rs ); // prime 340 z = 1; w = 1; jsr = 4; jcong = splitmix64( seed ); // prime 291 341 } // kiss_64_set_seed 292 342 … … 294 344 // The state array must be initialized to non-zero in the first four words. 295 345 #ifndef XORWOW 296 typedef struct xorwow_t{ uint32_t a, b, c, d, counter; } xorwow_t;346 typedef struct { uint32_t a, b, c, d, counter; } xorwow_t; 297 347 #endif // ! XORWOW 298 348 … … 316 366 317 367 static inline void xorwow_set_seed( xorwow_t & rs, uint32_t seed ) { 318 rs = (xorwow_t){ seed, seed, seed, seed, 0 }; 319 xorwow( rs ); // prime 368 // To attain repeatable seeding, compute seeds separately because the order of argument evaluation is undefined. 369 uint32_t seed1 = splitmix32( seed ); // prime 370 uint32_t seed2 = splitmix32( seed ); 371 uint32_t seed3 = splitmix32( seed ); 372 uint32_t seed4 = splitmix32( seed ); 373 rs = (xorwow_t){ seed1, seed2, seed3, seed4, 0 }; 320 374 } // xorwow_set_seed 321 375 … … 323 377 // Used in __tls_rand_fwd 324 378 #define M (1_l64u << 48_l64u) 325 #define A (25 214903917_l64u)326 #define AI (18 446708753438544741_l64u)379 #define A (25_214_903_917_l64u) 380 #define AI (18_446_708_753_438_544_741_l64u) 327 381 #define C (11_l64u) 328 382 #define D (16_l64u) -
libcfa/src/concurrency/actor.hfa
r2ed94a9 rb110bcc 3 3 #include <locks.hfa> 4 4 #include <limits.hfa> 5 #include <list.hfa>6 5 #include <kernel.hfa> 6 #include <iofwd.hfa> 7 #include <virtual_dtor.hfa> 7 8 8 9 #ifdef __CFA_DEBUG__ … … 20 21 // Define the default number of executor request-queues (mailboxes) written to by actors and serviced by the 21 22 // actor-executor threads. Must be greater than 0. 22 #define __DEFAULT_EXECUTOR_RQUEUES__ 223 #define __DEFAULT_EXECUTOR_RQUEUES__ 4 23 24 24 25 // Define if executor is created in a separate cluster 25 26 #define __DEFAULT_EXECUTOR_SEPCLUS__ false 26 27 27 // when you flip this make sure to recompile compiler and flip the appropriate flag there too in Actors.cpp 28 #define __ALLOC 0 28 #define __DEFAULT_EXECUTOR_BUFSIZE__ 10 29 30 #define __STEAL 0 // workstealing toggle. Disjoint from toggles above 31 32 // workstealing heuristic selection (only set one to be 1) 33 // #define RAND 0 34 #define SEARCH 1 35 36 // show stats 37 // #define ACTOR_STATS 29 38 30 39 // forward decls 31 40 struct actor; 32 41 struct message; 42 struct executor; 33 43 34 44 enum Allocation { Nodelete, Delete, Destroy, Finished }; // allocation status … … 40 50 __receive_fn fn; 41 51 bool stop; 42 inline dlink(request);43 52 }; 44 P9_EMBEDDED( request, dlink(request) )45 53 46 54 static inline void ?{}( request & this ) { this.stop = true; } // default ctor makes a sentinel … … 58 66 } 59 67 60 // hybrid data structure. Copies until buffer is full and then allocates for intrusive list 68 // Vector-like data structure that supports O(1) queue operations with no bound on size 69 // assumes gulping behaviour (once a remove occurs, removes happen until empty beforw next insert) 61 70 struct copy_queue { 62 dlist( request ) list;63 #if ! __ALLOC64 71 request * buffer; 65 size_t count, buffer_size, index; 66 #endif 72 size_t count, buffer_size, index, utilized, last_size; 67 73 }; 68 74 static inline void ?{}( copy_queue & this ) {} 69 75 static inline void ?{}( copy_queue & this, size_t buf_size ) with(this) { 70 list{};71 #if ! __ALLOC72 76 buffer_size = buf_size; 73 77 buffer = aalloc( buffer_size ); 74 78 count = 0; 79 utilized = 0; 75 80 index = 0; 76 #endif 77 } 78 static inline void ^?{}( copy_queue & this ) with(this) { 79 #if ! __ALLOC 80 adelete(buffer); 81 #endif 82 } 81 last_size = 0; 82 } 83 static inline void ^?{}( copy_queue & this ) with(this) { adelete(buffer); } 83 84 84 85 static inline void insert( copy_queue & this, request & elem ) with(this) { 85 #if ! __ALLOC 86 if ( count < buffer_size ) { // fast path ( no alloc ) 87 buffer[count]{ elem }; 88 count++; 89 return; 90 } 91 request * new_elem = alloc(); 92 (*new_elem){ elem }; 93 insert_last( list, *new_elem ); 94 #else 95 insert_last( list, elem ); 96 #endif 86 if ( count >= buffer_size ) { // increase arr size 87 last_size = buffer_size; 88 buffer_size = 2 * buffer_size; 89 buffer = realloc( buffer, sizeof( request ) * buffer_size ); 90 /* paranoid */ verify( buffer ); 91 } 92 memcpy( &buffer[count], &elem, sizeof(request) ); 93 count++; 97 94 } 98 95 99 96 // once you start removing you need to remove all elements 100 // it is not supported to call insert() before the list is fully empty 101 // should_delete is an output param 102 static inline request & remove( copy_queue & this, bool & should_delete ) with(this) { 103 #if ! __ALLOC 97 // it is not supported to call insert() before the array is fully empty 98 static inline request & remove( copy_queue & this ) with(this) { 104 99 if ( count > 0 ) { 105 100 count--; 106 should_delete = false;107 101 size_t old_idx = index; 108 102 index = count == 0 ? 0 : index + 1; 109 103 return buffer[old_idx]; 110 104 } 111 #endif112 should_delete = true;113 return try_pop_front( list ); 114 } 115 116 static inline bool isEmpty( copy_queue & this ) with(this) {117 #if ! __ALLOC118 return count == 0 && list`isEmpty;119 #else120 return list`isEmpty;121 #endif 122 } 123 124 static size_t __buffer_size = 10; // C_TODO: rework this to be passed from executor through ctors (no need for global) 105 request * ret = 0p; 106 return *0p; 107 } 108 109 // try to reclaim some memory if less than half of buffer is utilized 110 static inline void reclaim( copy_queue & this ) with(this) { 111 if ( utilized >= last_size || buffer_size <= 4 ) { utilized = 0; return; } 112 utilized = 0; 113 buffer_size--; 114 buffer = realloc( buffer, sizeof( request ) * buffer_size ); // try to reclaim some memory 115 } 116 117 static inline bool isEmpty( copy_queue & this ) with(this) { return count == 0; } 118 125 119 struct work_queue { 126 120 __spinlock_t mutex_lock; 127 copy_queue owned_queue; 128 copy_queue * c_queue; // C_TODO: try putting this on the stack with ptr juggling 129 121 copy_queue * owned_queue; // copy queue allocated and cleaned up by this work_queue 122 copy_queue * c_queue; // current queue 123 volatile bool being_processed; // flag to prevent concurrent processing 124 #ifdef ACTOR_STATS 125 unsigned int id; 126 size_t missed; // transfers skipped due to being_processed flag being up 127 #endif 130 128 }; // work_queue 131 static inline void ?{}( work_queue & this ) with(this) { 132 // c_queue = alloc(); 133 // (*c_queue){ __buffer_size }; 134 owned_queue{ __buffer_size }; 135 c_queue = &owned_queue; 136 } 137 // static inline void ^?{}( work_queue & this ) with(this) { delete( c_queue ); } 129 static inline void ?{}( work_queue & this, size_t buf_size, unsigned int i ) with(this) { 130 owned_queue = alloc(); // allocated separately to avoid false sharing 131 (*owned_queue){ buf_size }; 132 c_queue = owned_queue; 133 being_processed = false; 134 #ifdef ACTOR_STATS 135 id = i; 136 missed = 0; 137 #endif 138 } 139 140 // clean up copy_queue owned by this work_queue 141 static inline void ^?{}( work_queue & this ) with(this) { delete( owned_queue ); } 138 142 139 143 static inline void insert( work_queue & this, request & elem ) with(this) { … … 145 149 static inline void transfer( work_queue & this, copy_queue ** transfer_to ) with(this) { 146 150 lock( mutex_lock __cfaabi_dbg_ctx2 ); 151 #ifdef __STEAL 152 153 // check if queue is being processed elsewhere 154 if ( unlikely( being_processed ) ) { 155 #ifdef ACTOR_STATS 156 missed++; 157 #endif 158 unlock( mutex_lock ); 159 return; 160 } 161 162 being_processed = c_queue->count != 0; 163 #endif // __STEAL 164 165 c_queue->utilized = c_queue->count; 166 147 167 // swap copy queue ptrs 148 168 copy_queue * temp = *transfer_to; … … 152 172 } // transfer 153 173 174 // needed since some info needs to persist past worker lifetimes 175 struct worker_info { 176 volatile unsigned long long stamp; 177 #ifdef ACTOR_STATS 178 size_t stolen_from, try_steal, stolen, failed_swaps, msgs_stolen; 179 unsigned long long processed; 180 size_t gulps; 181 #endif 182 }; 183 static inline void ?{}( worker_info & this ) { 184 #ifdef ACTOR_STATS 185 this.stolen_from = 0; 186 this.try_steal = 0; // attempts to steal 187 this.stolen = 0; // successful steals 188 this.processed = 0; // requests processed 189 this.gulps = 0; // number of gulps 190 this.failed_swaps = 0; // steal swap failures 191 this.msgs_stolen = 0; // number of messages stolen 192 #endif 193 this.stamp = rdtscl(); 194 } 195 196 // #ifdef ACTOR_STATS 197 // unsigned int * stolen_arr; 198 // unsigned int * replaced_queue; 199 // #endif 154 200 thread worker { 155 copy_queue owned_queue; 156 work_queue * request_queues; 201 work_queue ** request_queues; 157 202 copy_queue * current_queue; 158 request & req;203 executor * executor_; 159 204 unsigned int start, range; 205 int id; 160 206 }; 161 207 162 static inline void ?{}( worker & this, cluster & clu, work_queue * request_queues, unsigned int start, unsigned int range ) { 208 #ifdef ACTOR_STATS 209 // aggregate counters for statistics 210 size_t __total_tries = 0, __total_stolen = 0, __total_workers, __all_gulps = 0, 211 __total_failed_swaps = 0, __all_processed = 0, __num_actors_stats = 0, __all_msgs_stolen = 0; 212 #endif 213 static inline void ?{}( worker & this, cluster & clu, work_queue ** request_queues, copy_queue * current_queue, executor * executor_, 214 unsigned int start, unsigned int range, int id ) { 163 215 ((thread &)this){ clu }; 164 this.request_queues = request_queues; 165 // this.current_queue = alloc(); 166 // (*this.current_queue){ __buffer_size }; 167 this.owned_queue{ __buffer_size }; 168 this.current_queue = &this.owned_queue; 169 this.start = start; 170 this.range = range; 171 } 172 // static inline void ^?{}( worker & mutex this ) with(this) { delete( current_queue ); } 173 216 this.request_queues = request_queues; // array of all queues 217 this.current_queue = current_queue; // currently gulped queue (start with empty queue to use in swap later) 218 this.executor_ = executor_; // pointer to current executor 219 this.start = start; // start of worker's subrange of request_queues 220 this.range = range; // size of worker's subrange of request_queues 221 this.id = id; // worker's id and index in array of workers 222 } 223 224 static bool no_steal = false; 174 225 struct executor { 175 226 cluster * cluster; // if workers execute on separate cluster 176 227 processor ** processors; // array of virtual processors adding parallelism for workers 177 work_queue * request_queues; // master list of work request queues 178 worker ** workers; // array of workers executing work requests 228 work_queue * request_queues; // master array of work request queues 229 copy_queue * local_queues; // array of all worker local queues to avoid deletion race 230 work_queue ** worker_req_queues; // secondary array of work queues to allow for swapping 231 worker ** workers; // array of workers executing work requests 232 worker_info * w_infos; // array of info about each worker 179 233 unsigned int nprocessors, nworkers, nrqueues; // number of processors/threads/request queues 180 234 bool seperate_clus; // use same or separate cluster for executor 181 235 }; // executor 182 236 237 // #ifdef ACTOR_STATS 238 // __spinlock_t out_lock; 239 // #endif 240 static inline void ^?{}( worker & mutex this ) with(this) { 241 #ifdef ACTOR_STATS 242 __atomic_add_fetch(&__all_gulps, executor_->w_infos[id].gulps,__ATOMIC_SEQ_CST); 243 __atomic_add_fetch(&__all_processed, executor_->w_infos[id].processed,__ATOMIC_SEQ_CST); 244 __atomic_add_fetch(&__all_msgs_stolen, executor_->w_infos[id].msgs_stolen,__ATOMIC_SEQ_CST); 245 __atomic_add_fetch(&__total_tries, executor_->w_infos[id].try_steal, __ATOMIC_SEQ_CST); 246 __atomic_add_fetch(&__total_stolen, executor_->w_infos[id].stolen, __ATOMIC_SEQ_CST); 247 __atomic_add_fetch(&__total_failed_swaps, executor_->w_infos[id].failed_swaps, __ATOMIC_SEQ_CST); 248 249 // per worker steal stats (uncomment alongside the lock above this routine to print) 250 // lock( out_lock __cfaabi_dbg_ctx2 ); 251 // printf("Worker id: %d, processed: %llu messages, attempted %lu, stole: %lu, stolen from: %lu\n", id, processed, try_steal, stolen, __atomic_add_fetch(&executor_->w_infos[id].stolen_from, 0, __ATOMIC_SEQ_CST) ); 252 // int count = 0; 253 // int count2 = 0; 254 // for ( i; range ) { 255 // if ( replaced_queue[start + i] > 0 ){ 256 // count++; 257 // // printf("%d: %u, ",i, replaced_queue[i]); 258 // } 259 // if (__atomic_add_fetch(&stolen_arr[start + i],0,__ATOMIC_SEQ_CST) > 0) 260 // count2++; 261 // } 262 // printf("swapped with: %d of %u indices\n", count, executor_->nrqueues / executor_->nworkers ); 263 // printf("%d of %u indices were stolen\n", count2, executor_->nrqueues / executor_->nworkers ); 264 // unlock( out_lock ); 265 #endif 266 } 267 183 268 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus, size_t buf_size ) with(this) { 184 269 if ( nrqueues < nworkers ) abort( "nrqueues needs to be >= nworkers\n" ); 185 __buffer_size = buf_size;186 270 this.nprocessors = nprocessors; 187 271 this.nworkers = nworkers; … … 189 273 this.seperate_clus = seperate_clus; 190 274 275 if ( nworkers == nrqueues ) 276 no_steal = true; 277 278 #ifdef ACTOR_STATS 279 // stolen_arr = aalloc( nrqueues ); 280 // replaced_queue = aalloc( nrqueues ); 281 __total_workers = nworkers; 282 #endif 283 191 284 if ( seperate_clus ) { 192 285 cluster = alloc(); … … 195 288 196 289 request_queues = aalloc( nrqueues ); 197 for ( i; nrqueues ) 198 request_queues[i]{}; 290 worker_req_queues = aalloc( nrqueues ); 291 for ( i; nrqueues ) { 292 request_queues[i]{ buf_size, i }; 293 worker_req_queues[i] = &request_queues[i]; 294 } 199 295 200 296 processors = aalloc( nprocessors ); … … 202 298 (*(processors[i] = alloc())){ *cluster }; 203 299 204 workers = alloc( nworkers ); 300 local_queues = aalloc( nworkers ); 301 workers = aalloc( nworkers ); 302 w_infos = aalloc( nworkers ); 205 303 unsigned int reqPerWorker = nrqueues / nworkers, extras = nrqueues % nworkers; 304 305 for ( i; nworkers ) { 306 w_infos[i]{}; 307 local_queues[i]{ buf_size }; 308 } 309 206 310 for ( unsigned int i = 0, start = 0, range; i < nworkers; i += 1, start += range ) { 207 311 range = reqPerWorker + ( i < extras ? 1 : 0 ); 208 (*(workers[i] = alloc())){ *cluster, request_queues, start, range};312 (*(workers[i] = alloc())){ *cluster, worker_req_queues, &local_queues[i], &this, start, range, i }; 209 313 } // for 210 314 } 211 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus ) { this{ nprocessors, nworkers, nrqueues, seperate_clus, __ buffer_size}; }315 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus ) { this{ nprocessors, nworkers, nrqueues, seperate_clus, __DEFAULT_EXECUTOR_BUFSIZE__ }; } 212 316 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues ) { this{ nprocessors, nworkers, nrqueues, __DEFAULT_EXECUTOR_SEPCLUS__ }; } 213 317 static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers ) { this{ nprocessors, nworkers, __DEFAULT_EXECUTOR_RQUEUES__ }; } … … 216 320 217 321 static inline void ^?{}( executor & this ) with(this) { 322 #ifdef __STEAL 323 request sentinels[nrqueues]; 324 for ( unsigned int i = 0; i < nrqueues; i++ ) { 325 insert( request_queues[i], sentinels[i] ); // force eventually termination 326 } // for 327 #else 218 328 request sentinels[nworkers]; 219 unsigned int reqPerWorker = nrqueues / nworkers; 220 for ( unsigned int i = 0, step = 0; i < nworkers; i += 1, step += reqPerWorker ) { 329 unsigned int reqPerWorker = nrqueues / nworkers, extras = nrqueues % nworkers; 330 for ( unsigned int i = 0, step = 0, range; i < nworkers; i += 1, step += range ) { 331 range = reqPerWorker + ( i < extras ? 1 : 0 ); 221 332 insert( request_queues[step], sentinels[i] ); // force eventually termination 222 333 } // for 334 #endif 223 335 224 336 for ( i; nworkers ) … … 229 341 } // for 230 342 343 #ifdef ACTOR_STATS 344 size_t misses = 0; 345 for ( i; nrqueues ) { 346 misses += worker_req_queues[i]->missed; 347 } 348 // adelete( stolen_arr ); 349 // adelete( replaced_queue ); 350 #endif 351 231 352 adelete( workers ); 353 adelete( w_infos ); 354 adelete( local_queues ); 232 355 adelete( request_queues ); 356 adelete( worker_req_queues ); 233 357 adelete( processors ); 234 358 if ( seperate_clus ) delete( cluster ); 359 360 #ifdef ACTOR_STATS // print formatted stats 361 printf(" Actor System Stats:\n"); 362 printf("\tActors Created:\t\t\t\t%lu\n\tMessages Sent:\t\t\t\t%lu\n", __num_actors_stats, __all_processed); 363 size_t avg_gulps = __all_gulps == 0 ? 0 : __all_processed / __all_gulps; 364 printf("\tGulps:\t\t\t\t\t%lu\n\tAverage Gulp Size:\t\t\t%lu\n\tMissed gulps:\t\t\t\t%lu\n", __all_gulps, avg_gulps, misses); 365 printf("\tSteal attempts:\t\t\t\t%lu\n\tSteals:\t\t\t\t\t%lu\n\tSteal failures (no candidates):\t\t%lu\n\tSteal failures (failed swaps):\t\t%lu\n", 366 __total_tries, __total_stolen, __total_tries - __total_stolen - __total_failed_swaps, __total_failed_swaps); 367 size_t avg_steal = __total_stolen == 0 ? 0 : __all_msgs_stolen / __total_stolen; 368 printf("\tMessages stolen:\t\t\t%lu\n\tAverage steal size:\t\t\t%lu\n", __all_msgs_stolen, avg_steal); 369 #endif 370 235 371 } 236 372 237 373 // this is a static field of executor but have to forward decl for get_next_ticket 238 static unsigned int __next_ticket = 0; 239 240 static inline unsigned int get_next_ticket( executor & this ) with(this) { 241 return __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_SEQ_CST) % nrqueues; 374 static size_t __next_ticket = 0; 375 376 static inline size_t __get_next_ticket( executor & this ) with(this) { 377 #ifdef __CFA_DEBUG__ 378 size_t temp = __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_SEQ_CST) % nrqueues; 379 380 // reserve MAX for dead actors 381 if ( unlikely( temp == MAX ) ) temp = __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_SEQ_CST) % nrqueues; 382 return temp; 383 #else 384 return __atomic_fetch_add( &__next_ticket, 1, __ATOMIC_RELAXED) % nrqueues; 385 #endif 242 386 } // tickets 243 387 244 // C_TODO: update globals in this file to be static fields once theproject is done388 // TODO: update globals in this file to be static fields once the static fields project is done 245 389 static executor * __actor_executor_ = 0p; 246 static bool __actor_executor_passed = false; // was an executor passed to start_actor_system247 static unsigned long int __num_actors_;// number of actor objects in system390 static bool __actor_executor_passed = false; // was an executor passed to start_actor_system 391 static size_t __num_actors_ = 0; // number of actor objects in system 248 392 static struct thread$ * __actor_executor_thd = 0p; // used to wake executor after actors finish 249 393 struct actor { 250 unsigned long int ticket; // executor-queue handle to provide FIFO message execution 251 Allocation allocation_; // allocation action 394 size_t ticket; // executor-queue handle 395 Allocation allocation_; // allocation action 396 inline virtual_dtor; 252 397 }; 253 398 254 static inline void ?{}( actor & this ) {399 static inline void ?{}( actor & this ) with(this) { 255 400 // Once an actor is allocated it must be sent a message or the actor system cannot stop. Hence, its receive 256 401 // member must be called to end it 257 verifyf( __actor_executor_, "Creating actor before calling start_actor_system()." ); 258 this.allocation_ = Nodelete; 259 this.ticket = get_next_ticket( *__actor_executor_ ); 260 __atomic_fetch_add( &__num_actors_, 1, __ATOMIC_SEQ_CST ); 261 } 262 static inline void ^?{}( actor & this ) {} 402 verifyf( __actor_executor_, "Creating actor before calling start_actor_system() can cause undefined behaviour.\n" ); 403 allocation_ = Nodelete; 404 ticket = __get_next_ticket( *__actor_executor_ ); 405 __atomic_fetch_add( &__num_actors_, 1, __ATOMIC_RELAXED ); 406 #ifdef ACTOR_STATS 407 __atomic_fetch_add( &__num_actors_stats, 1, __ATOMIC_SEQ_CST ); 408 #endif 409 } 263 410 264 411 static inline void check_actor( actor & this ) { … … 276 423 } 277 424 278 if ( unlikely( __atomic_add_fetch( &__num_actors_, -1, __ATOMIC_ SEQ_CST) == 0 ) ) { // all actors have terminated425 if ( unlikely( __atomic_add_fetch( &__num_actors_, -1, __ATOMIC_RELAXED ) == 0 ) ) { // all actors have terminated 279 426 unpark( __actor_executor_thd ); 280 427 } … … 284 431 struct message { 285 432 Allocation allocation_; // allocation action 433 inline virtual_dtor; 286 434 }; 287 435 288 static inline void ?{}( message & this ) { this.allocation_ = Nodelete; } 289 static inline void ?{}( message & this, Allocation allocation ) { this.allocation_ = allocation; } 290 static inline void ^?{}( message & this ) {} 436 static inline void ?{}( message & this ) { 437 this.allocation_ = Nodelete; 438 } 439 static inline void ?{}( message & this, Allocation allocation ) { 440 memcpy( &this.allocation_, &allocation, sizeof(allocation) ); // optimization to elide ctor 441 verifyf( this.allocation_ != Finished, "The Finished Allocation status is not supported for message types.\n"); 442 } 443 static inline void ^?{}( message & this ) with(this) { 444 CFA_DEBUG( if ( allocation_ == Nodelete ) printf("A message at location %p was allocated but never sent.\n", &this); ) 445 } 291 446 292 447 static inline void check_message( message & this ) { 293 448 switch ( this.allocation_ ) { // analyze message status 294 case Nodelete: break;449 case Nodelete: CFA_DEBUG(this.allocation_ = Finished); break; 295 450 case Delete: delete( &this ); break; 296 451 case Destroy: ^?{}(this); break; … … 298 453 } // switch 299 454 } 455 static inline void set_allocation( message & this, Allocation state ) { 456 this.allocation_ = state; 457 } 300 458 301 459 static inline void deliver_request( request & this ) { 302 Allocation actor_allocation= this.fn( *this.receiver, *this.msg );303 this.receiver->allocation_ = actor_allocation;460 this.receiver->allocation_ = this.fn( *this.receiver, *this.msg ); 461 check_message( *this.msg ); 304 462 check_actor( *this.receiver ); 305 check_message( *this.msg ); 463 } 464 465 // tries to atomically swap two queues and returns 0p if the swap failed 466 // returns ptr to newly owned queue if swap succeeds 467 static inline work_queue * try_swap_queues( worker & this, unsigned int victim_idx, unsigned int my_idx ) with(this) { 468 work_queue * my_queue = request_queues[my_idx]; 469 work_queue * other_queue = request_queues[victim_idx]; 470 471 // if either queue is 0p then they are in the process of being stolen 472 if ( other_queue == 0p ) return 0p; 473 474 // try to set our queue ptr to be 0p. If it fails someone moved our queue so return false 475 if ( !__atomic_compare_exchange_n( &request_queues[my_idx], &my_queue, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) 476 return 0p; 477 478 // 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 479 if ( !__atomic_compare_exchange_n( &request_queues[victim_idx], &other_queue, my_queue, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) { 480 /* paranoid */ verify( request_queues[my_idx] == 0p ); 481 request_queues[my_idx] = my_queue; // reset my queue ptr back to appropriate val 482 return 0p; 483 } 484 485 // we have successfully swapped and since our queue is 0p no one will touch it so write back new queue ptr non atomically 486 request_queues[my_idx] = other_queue; // last write does not need to be atomic 487 return other_queue; 488 } 489 490 // once a worker to steal from has been chosen, choose queue to steal from 491 static inline void choose_queue( worker & this, unsigned int victim_id, unsigned int swap_idx ) with(this) { 492 // have to calculate victim start and range since victim may be deleted before us in shutdown 493 const unsigned int queues_per_worker = executor_->nrqueues / executor_->nworkers; 494 const unsigned int extras = executor_->nrqueues % executor_->nworkers; 495 unsigned int vic_start, vic_range; 496 if ( extras > victim_id ) { 497 vic_range = queues_per_worker + 1; 498 vic_start = vic_range * victim_id; 499 } else { 500 vic_start = extras + victim_id * queues_per_worker; 501 vic_range = queues_per_worker; 502 } 503 unsigned int start_idx = prng( vic_range ); 504 505 unsigned int tries = 0; 506 work_queue * curr_steal_queue; 507 508 for ( unsigned int i = start_idx; tries < vic_range; i = (i + 1) % vic_range ) { 509 tries++; 510 curr_steal_queue = request_queues[ i + vic_start ]; 511 // avoid empty queues and queues that are being operated on 512 if ( curr_steal_queue == 0p || curr_steal_queue->being_processed || isEmpty( *curr_steal_queue->c_queue ) ) 513 continue; 514 515 #ifdef ACTOR_STATS 516 curr_steal_queue = try_swap_queues( this, i + vic_start, swap_idx ); 517 if ( curr_steal_queue ) { 518 executor_->w_infos[id].msgs_stolen += curr_steal_queue->c_queue->count; 519 executor_->w_infos[id].stolen++; 520 // __atomic_add_fetch(&executor_->w_infos[victim_id].stolen_from, 1, __ATOMIC_RELAXED); 521 // replaced_queue[swap_idx]++; 522 // __atomic_add_fetch(&stolen_arr[ i + vic_start ], 1, __ATOMIC_RELAXED); 523 } else { 524 executor_->w_infos[id].failed_swaps++; 525 } 526 #else 527 curr_steal_queue = try_swap_queues( this, i + vic_start, swap_idx ); 528 #endif // ACTOR_STATS 529 530 return; 531 } 532 533 return; 534 } 535 536 // choose a worker to steal from 537 static inline void steal_work( worker & this, unsigned int swap_idx ) with(this) { 538 #if RAND 539 unsigned int victim = prng( executor_->nworkers ); 540 if ( victim == id ) victim = ( victim + 1 ) % executor_->nworkers; 541 choose_queue( this, victim, swap_idx ); 542 #elif SEARCH 543 unsigned long long min = MAX; // smaller timestamp means longer since service 544 int min_id = 0; // use ints not uints to avoid integer underflow without hacky math 545 int n_workers = executor_->nworkers; 546 unsigned long long curr_stamp; 547 int scount = 1; 548 for ( int i = (id + 1) % n_workers; scount < n_workers; i = (i + 1) % n_workers, scount++ ) { 549 curr_stamp = executor_->w_infos[i].stamp; 550 if ( curr_stamp < min ) { 551 min = curr_stamp; 552 min_id = i; 553 } 554 } 555 choose_queue( this, min_id, swap_idx ); 556 #endif 306 557 } 307 558 308 559 void main( worker & this ) with(this) { 309 bool should_delete; 560 // #ifdef ACTOR_STATS 561 // for ( i; executor_->nrqueues ) { 562 // replaced_queue[i] = 0; 563 // __atomic_store_n( &stolen_arr[i], 0, __ATOMIC_SEQ_CST ); 564 // } 565 // #endif 566 567 // threshold of empty queues we see before we go stealing 568 const unsigned int steal_threshold = 2 * range; 569 570 // Store variable data here instead of worker struct to avoid any potential false sharing 571 unsigned int empty_count = 0; 572 request & req; 573 work_queue * curr_work_queue; 574 310 575 Exit: 311 576 for ( unsigned int i = 0;; i = (i + 1) % range ) { // cycle through set of request buffers 312 // C_TODO: potentially check queue count instead of immediately trying to transfer 313 transfer( request_queues[i + start], ¤t_queue ); 577 curr_work_queue = request_queues[i + start]; 578 579 // check if queue is empty before trying to gulp it 580 if ( isEmpty( *curr_work_queue->c_queue ) ) { 581 #ifdef __STEAL 582 empty_count++; 583 if ( empty_count < steal_threshold ) continue; 584 #else 585 continue; 586 #endif 587 } 588 transfer( *curr_work_queue, ¤t_queue ); 589 #ifdef ACTOR_STATS 590 executor_->w_infos[id].gulps++; 591 #endif // ACTOR_STATS 592 #ifdef __STEAL 593 if ( isEmpty( *current_queue ) ) { 594 if ( unlikely( no_steal ) ) continue; 595 empty_count++; 596 if ( empty_count < steal_threshold ) continue; 597 empty_count = 0; 598 599 __atomic_store_n( &executor_->w_infos[id].stamp, rdtscl(), __ATOMIC_RELAXED ); 600 601 #ifdef ACTOR_STATS 602 executor_->w_infos[id].try_steal++; 603 #endif // ACTOR_STATS 604 605 steal_work( this, start + prng( range ) ); 606 continue; 607 } 608 #endif // __STEAL 314 609 while ( ! isEmpty( *current_queue ) ) { 315 &req = &remove( *current_queue, should_delete ); 316 if ( !&req ) continue; // possibly add some work stealing/idle sleep here 610 #ifdef ACTOR_STATS 611 executor_->w_infos[id].processed++; 612 #endif 613 &req = &remove( *current_queue ); 614 if ( !&req ) continue; 317 615 if ( req.stop ) break Exit; 318 616 deliver_request( req ); 319 320 if ( should_delete ) delete( &req ); 321 } // while 617 } 618 #ifdef __STEAL 619 curr_work_queue->being_processed = false; // set done processing 620 empty_count = 0; // we found work so reset empty counter 621 #endif 622 623 // potentially reclaim some of the current queue's vector space if it is unused 624 reclaim( *current_queue ); 322 625 } // for 323 626 } … … 328 631 329 632 static inline void send( actor & this, request & req ) { 633 verifyf( this.ticket != (unsigned long int)MAX, "Attempted to send message to deleted/dead actor\n" ); 330 634 send( *__actor_executor_, req, this.ticket ); 331 635 } 332 636 637 static inline void __reset_stats() { 638 #ifdef ACTOR_STATS 639 __total_tries = 0; 640 __total_stolen = 0; 641 __all_gulps = 0; 642 __total_failed_swaps = 0; 643 __all_processed = 0; 644 __num_actors_stats = 0; 645 __all_msgs_stolen = 0; 646 #endif 647 } 648 333 649 static inline void start_actor_system( size_t num_thds ) { 650 __reset_stats(); 334 651 __actor_executor_thd = active_thread(); 335 652 __actor_executor_ = alloc(); … … 337 654 } 338 655 339 static inline void start_actor_system() { start_actor_system( active_cluster()->procs.total ); } 656 // TODO: potentially revisit getting number of processors 657 // ( currently the value stored in active_cluster()->procs.total is often stale 658 // and doesn't reflect how many procs are allocated ) 659 // static inline void start_actor_system() { start_actor_system( active_cluster()->procs.total ); } 660 static inline void start_actor_system() { start_actor_system( 1 ); } 340 661 341 662 static inline void start_actor_system( executor & this ) { 663 __reset_stats(); 342 664 __actor_executor_thd = active_thread(); 343 665 __actor_executor_ = &this; … … 354 676 __actor_executor_passed = false; 355 677 } 678 679 // Default messages to send to any actor to change status 680 // assigned at creation to __base_msg_finished to avoid unused message warning 681 message __base_msg_finished @= { .allocation_ : Finished }; 682 struct __DeleteMsg { inline message; } DeleteMsg = __base_msg_finished; 683 struct __DestroyMsg { inline message; } DestroyMsg = __base_msg_finished; 684 struct __FinishedMsg { inline message; } FinishedMsg = __base_msg_finished; 685 686 Allocation receive( actor & this, __DeleteMsg & msg ) { return Delete; } 687 Allocation receive( actor & this, __DestroyMsg & msg ) { return Destroy; } 688 Allocation receive( actor & this, __FinishedMsg & msg ) { return Finished; } 689 -
libcfa/src/concurrency/channel.hfa
r2ed94a9 rb110bcc 1 #pragma once 2 1 3 #include <locks.hfa> 2 3 struct no_reacq_lock { 4 inline exp_backoff_then_block_lock; 4 #include <list.hfa> 5 #include <mutex_stmt.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; 5 17 }; 6 7 // have to override these by hand to get around plan 9 inheritance bug where resolver can't find the appropriate routine to call 8 static inline void ?{}( no_reacq_lock & this ) { ((exp_backoff_then_block_lock &)this){}; } 9 static inline bool try_lock(no_reacq_lock & this) { return try_lock(((exp_backoff_then_block_lock &)this)); } 10 static inline void lock(no_reacq_lock & this) { lock(((exp_backoff_then_block_lock &)this)); } 11 static inline void unlock(no_reacq_lock & this) { unlock(((exp_backoff_then_block_lock &)this)); } 12 static inline void on_notify(no_reacq_lock & this, struct thread$ * t ) { on_notify(((exp_backoff_then_block_lock &)this), t); } 13 static inline size_t on_wait(no_reacq_lock & this) { return on_wait(((exp_backoff_then_block_lock &)this)); } 14 // override wakeup so that we don't reacquire the lock if using a condvar 15 static inline void on_wakeup( no_reacq_lock & this, size_t recursion ) {} 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 } 30 31 // returns true if woken due to shutdown 32 // blocks thread on list and releases passed lock 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 ); 36 unlock( lock ); 37 park(); 38 return w.elem == 0p; 39 } 40 41 // void * used for some fields since exceptions don't work with parametric polymorphism currently 42 exception channel_closed { 43 // on failed insert elem is a ptr to the element attempting to be inserted 44 // on failed remove elem ptr is 0p 45 // on resumption of a failed insert this elem will be inserted 46 // so a user may modify it in the resumption handler 47 void * elem; 48 49 // pointer to chan that is closed 50 void * closed_chan; 51 }; 52 vtable(channel_closed) channel_closed_vt; 53 54 // #define CHAN_STATS // define this to get channel stats printed in dtor 16 55 17 56 forall( T ) { 18 struct channel { 19 size_t size; 20 size_t front, back, count;57 58 struct __attribute__((aligned(128))) channel { 59 size_t size, front, back, count; 21 60 T * buffer; 22 fast_cond_var( no_reacq_lock ) prods, cons; 23 no_reacq_lock mutex_lock; 61 dlist( wait_link ) prods, cons; // lists of blocked threads 62 go_mutex mutex_lock; // MX lock 63 bool closed; // indicates channel close/open 64 #ifdef CHAN_STATS 65 size_t blocks, operations; // counts total ops and ops resulting in a blocked thd 66 #endif 24 67 }; 25 68 … … 27 70 size = _size; 28 71 front = back = count = 0; 29 buffer = a new( size );72 buffer = aalloc( size ); 30 73 prods{}; 31 74 cons{}; 32 75 mutex_lock{}; 76 closed = false; 77 #ifdef CHAN_STATS 78 blocks = 0; 79 operations = 0; 80 #endif 33 81 } 34 82 35 83 static inline void ?{}( channel(T) &c ){ ((channel(T) &)c){ 0 }; } 36 static inline void ^?{}( channel(T) &c ) with(c) { delete( buffer ); } 84 static inline void ^?{}( channel(T) &c ) with(c) { 85 #ifdef CHAN_STATS 86 printf("Channel %p Blocks: %lu, Operations: %lu, %.2f%% of ops blocked\n", &c, blocks, operations, ((double)blocks)/operations * 100); 87 #endif 88 verifyf( cons`isEmpty && prods`isEmpty, "Attempted to delete channel with waiting threads (Deadlock).\n" ); 89 delete( buffer ); 90 } 37 91 static inline size_t get_count( channel(T) & chan ) with(chan) { return count; } 38 92 static inline size_t get_size( channel(T) & chan ) with(chan) { return size; } 39 static inline bool has_waiters( channel(T) & chan ) with(chan) { return !empty( cons ) || !empty( prods ); } 40 static inline bool has_waiting_consumers( channel(T) & chan ) with(chan) { return !empty( cons ); } 41 static inline bool has_waiting_producers( channel(T) & chan ) with(chan) { return !empty( prods ); } 42 43 static inline void insert_( channel(T) & chan, T elem ) with(chan) { 93 static inline bool has_waiters( channel(T) & chan ) with(chan) { return !cons`isEmpty || !prods`isEmpty; } 94 static inline bool has_waiting_consumers( channel(T) & chan ) with(chan) { return !cons`isEmpty; } 95 static inline bool has_waiting_producers( channel(T) & chan ) with(chan) { return !prods`isEmpty; } 96 97 // closes the channel and notifies all blocked threads 98 static inline void close( channel(T) & chan ) with(chan) { 99 lock( mutex_lock ); 100 closed = true; 101 102 // flush waiting consumers and producers 103 while ( has_waiting_consumers( chan ) ) { 104 cons`first.elem = 0p; 105 wake_one( cons ); 106 } 107 while ( has_waiting_producers( chan ) ) { 108 prods`first.elem = 0p; 109 wake_one( prods ); 110 } 111 unlock(mutex_lock); 112 } 113 114 static inline void is_closed( channel(T) & chan ) with(chan) { return closed; } 115 116 static inline void flush( channel(T) & chan, T elem ) with(chan) { 117 lock( mutex_lock ); 118 while ( count == 0 && !cons`isEmpty ) { 119 memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work 120 wake_one( cons ); 121 } 122 unlock( mutex_lock ); 123 } 124 125 // handles buffer insert 126 static inline void __buf_insert( channel(T) & chan, T & elem ) with(chan) { 44 127 memcpy((void *)&buffer[back], (void *)&elem, sizeof(T)); 45 128 count += 1; … … 48 131 } 49 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 141 // needed to avoid an extra copy in closed case 142 static inline bool __internal_try_insert( channel(T) & chan, T & elem ) with(chan) { 143 lock( mutex_lock ); 144 #ifdef CHAN_STATS 145 operations++; 146 #endif 147 if ( count == size ) { unlock( mutex_lock ); return false; } 148 __do_insert( chan, elem ); 149 unlock( mutex_lock ); 150 return true; 151 } 152 153 // attempts a nonblocking insert 154 // returns true if insert was successful, false otherwise 155 static inline bool try_insert( channel(T) & chan, T elem ) { return __internal_try_insert( chan, elem ); } 156 157 // handles closed case of insert routine 158 static inline void __closed_insert( channel(T) & chan, T & elem ) with(chan) { 159 channel_closed except{&channel_closed_vt, &elem, &chan }; 160 throwResume except; // throw closed resumption 161 if ( !__internal_try_insert( chan, elem ) ) throw except; // if try to insert fails (would block), throw termination 162 } 50 163 51 164 static inline void insert( channel(T) & chan, T elem ) with(chan) { 52 lock( mutex_lock ); 165 // check for close before acquire mx 166 if ( unlikely(closed) ) { 167 __closed_insert( chan, elem ); 168 return; 169 } 170 171 lock( mutex_lock ); 172 173 #ifdef CHAN_STATS 174 if ( !closed ) operations++; 175 #endif 176 177 // if closed handle 178 if ( unlikely(closed) ) { 179 unlock( mutex_lock ); 180 __closed_insert( chan, elem ); 181 return; 182 } 53 183 54 184 // have to check for the zero size channel case 55 if ( size == 0 && ! empty( cons )) {56 memcpy( (void *)front( cons ), (void *)&elem, sizeof(T));57 notify_one( cons );185 if ( size == 0 && !cons`isEmpty ) { 186 memcpy(cons`first.elem, (void *)&elem, sizeof(T)); 187 wake_one( cons ); 58 188 unlock( mutex_lock ); 59 return ;189 return true; 60 190 } 61 191 62 192 // wait if buffer is full, work will be completed by someone else 63 if ( count == size ) { 64 wait( prods, mutex_lock, (uintptr_t)&elem ); 193 if ( count == size ) { 194 #ifdef CHAN_STATS 195 blocks++; 196 #endif 197 198 // check for if woken due to close 199 if ( unlikely( block( prods, &elem, mutex_lock ) ) ) 200 __closed_insert( chan, elem ); 65 201 return; 66 202 } // if 67 203 68 if ( count == 0 && ! empty( cons ) )69 // do waiting consumer work70 memcpy((void *)front( cons ), (void *)&elem, sizeof(T));71 else insert_( chan, elem );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 ); 72 208 73 notify_one( cons ); 74 unlock( mutex_lock ); 75 } 76 77 static inline T remove( channel(T) & chan ) with(chan) { 78 lock( mutex_lock ); 79 T retval; 80 81 // have to check for the zero size channel case 82 if ( size == 0 && !empty( prods ) ) { 83 memcpy((void *)&retval, (void *)front( prods ), sizeof(T)); 84 notify_one( prods ); 85 unlock( mutex_lock ); 86 return retval; 87 } 88 89 // wait if buffer is empty, work will be completed by someone else 90 if (count == 0) { 91 wait( cons, mutex_lock, (uintptr_t)&retval ); 92 return retval; 93 } 94 95 // Remove from buffer 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) { 96 215 memcpy((void *)&retval, (void *)&buffer[front], sizeof(T)); 97 216 count -= 1; 98 217 front = (front + 1) % size; 99 100 if (count == size - 1 && !empty( prods ) ) 101 insert_( chan, *((T *)front( prods )) ); // do waiting producer work 102 103 notify_one( prods ); 104 unlock( mutex_lock ); 218 } 219 220 // does the buffer remove and potentially does waiting producer work 221 static inline void __do_remove( channel(T) & chan, T & retval ) with(chan) { 222 __buf_remove( chan, retval ); 223 if (count == size - 1 && !prods`isEmpty ) { 224 __buf_insert( chan, *(T *)prods`first.elem ); // do waiting producer work 225 wake_one( prods ); 226 } 227 } 228 229 // needed to avoid an extra copy in closed case and single return val case 230 static inline bool __internal_try_remove( channel(T) & chan, T & retval ) with(chan) { 231 lock( mutex_lock ); 232 #ifdef CHAN_STATS 233 operations++; 234 #endif 235 if ( count == 0 ) { unlock( mutex_lock ); return false; } 236 __do_remove( chan, retval ); 237 unlock( mutex_lock ); 238 return true; 239 } 240 241 // attempts a nonblocking remove 242 // returns [T, true] if insert was successful 243 // returns [T, false] if insert was successful (T uninit) 244 static inline [T, bool] try_remove( channel(T) & chan ) { 245 T retval; 246 return [ retval, __internal_try_remove( chan, retval ) ]; 247 } 248 249 static inline T try_remove( channel(T) & chan, T elem ) { 250 T retval; 251 __internal_try_remove( chan, retval ); 105 252 return retval; 106 253 } 107 254 255 // handles closed case of insert routine 256 static inline void __closed_remove( channel(T) & chan, T & retval ) with(chan) { 257 channel_closed except{&channel_closed_vt, 0p, &chan }; 258 throwResume except; // throw resumption 259 if ( !__internal_try_remove( chan, retval ) ) throw except; // if try to remove fails (would block), throw termination 260 } 261 262 static inline T remove( channel(T) & chan ) with(chan) { 263 T retval; 264 if ( unlikely(closed) ) { 265 __closed_remove( chan, retval ); 266 return retval; 267 } 268 lock( mutex_lock ); 269 270 #ifdef CHAN_STATS 271 if ( !closed ) operations++; 272 #endif 273 274 if ( unlikely(closed) ) { 275 unlock( mutex_lock ); 276 __closed_remove( chan, retval ); 277 return retval; 278 } 279 280 // have to check for the zero size channel case 281 if ( size == 0 && !prods`isEmpty ) { 282 memcpy((void *)&retval, (void *)prods`first.elem, sizeof(T)); 283 wake_one( prods ); 284 unlock( mutex_lock ); 285 return retval; 286 } 287 288 // wait if buffer is empty, work will be completed by someone else 289 if (count == 0) { 290 #ifdef CHAN_STATS 291 blocks++; 292 #endif 293 // check for if woken due to close 294 if ( unlikely( block( cons, &retval, mutex_lock ) ) ) 295 __closed_remove( chan, retval ); 296 return retval; 297 } 298 299 // Remove from buffer 300 __do_remove( chan, retval ); 301 302 unlock( mutex_lock ); 303 return retval; 304 } 108 305 } // forall( T ) -
libcfa/src/concurrency/clib/cfathread.cfa
r2ed94a9 rb110bcc 16 16 // #define EPOLL_FOR_SOCKETS 17 17 18 #include <string.h> 19 18 20 #include "fstream.hfa" 19 21 #include "locks.hfa" … … 23 25 #include "time.hfa" 24 26 #include "stdlib.hfa" 25 27 #include "iofwd.hfa" 26 28 #include "cfathread.h" 27 28 extern "C" {29 #include <string.h>30 #include <errno.h>31 }32 29 33 30 extern void ?{}(processor &, const char[], cluster &, thread$ *); 34 31 extern "C" { 35 extern void __cfactx_invoke_thread(void (*main)(void *), void * this); 36 extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); 32 extern void __cfactx_invoke_thread(void (*main)(void *), void * this); 37 33 } 38 34 … … 472 468 } 473 469 474 #include <iofwd.hfa>475 476 470 extern "C" { 477 #include <unistd.h>478 #include <sys/types.h>479 #include <sys/socket.h>480 481 471 //-------------------- 482 472 // IO operations … … 488 478 , protocol); 489 479 } 490 int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) {480 int cfathread_bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len) { 491 481 return bind(socket, address, address_len); 492 482 } … … 496 486 } 497 487 498 int cfathread_accept(int socket, struct sockaddr *restrictaddress, socklen_t *restrict address_len) {488 int cfathread_accept(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len) { 499 489 #if defined(EPOLL_FOR_SOCKETS) 500 490 int ret; … … 513 503 } 514 504 515 int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) {505 int cfathread_connect(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len) { 516 506 #if defined(EPOLL_FOR_SOCKETS) 517 507 int ret; -
libcfa/src/concurrency/clib/cfathread.h
r2ed94a9 rb110bcc 9 9 // Author : Thierry Delisle 10 10 // Created On : Tue Sep 22 15:31:20 2020 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 13 23:48:40 2023 13 // Update Count : 7 14 14 // 15 15 16 #pragma once 17 16 18 #if defined(__cforall) || defined(__cplusplus) 19 #include <unistd.h> 20 #include <errno.h> 21 #include <sys/socket.h> 22 17 23 extern "C" { 18 24 #endif 19 #include <asm/types.h>20 #include <errno.h>21 #include <unistd.h>22 23 24 25 //-------------------- 25 26 // Basic types … … 73 74 } cfathread_mutexattr_t; 74 75 typedef struct cfathread_mutex * cfathread_mutex_t; 75 int cfathread_mutex_init(cfathread_mutex_t * restrict mut, const cfathread_mutexattr_t *restrict attr) __attribute__((nonnull (1)));76 int cfathread_mutex_init(cfathread_mutex_t * restrict mut, const cfathread_mutexattr_t * restrict attr) __attribute__((nonnull (1))); 76 77 int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1))); 77 78 int cfathread_mutex_lock(cfathread_mutex_t *mut) __attribute__((nonnull (1))); … … 91 92 //-------------------- 92 93 // IO operations 93 struct sockaddr;94 struct msghdr;95 94 int cfathread_socket(int domain, int type, int protocol); 96 int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len);95 int cfathread_bind(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len); 97 96 int cfathread_listen(int socket, int backlog); 98 int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);99 int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len);97 int cfathread_accept(int socket, __SOCKADDR_ARG address, socklen_t * restrict address_len); 98 int cfathread_connect(int socket, __CONST_SOCKADDR_ARG address, socklen_t address_len); 100 99 int cfathread_dup(int fildes); 101 100 int cfathread_close(int fildes); -
libcfa/src/concurrency/coroutine.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Dec 15 12:06:04 202013 // Update Count : 2 312 // Last Modified On : Thu Feb 16 15:34:46 2023 13 // Update Count : 24 14 14 // 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #include "coroutine.hfa" -
libcfa/src/concurrency/future.hfa
r2ed94a9 rb110bcc 14 14 // 15 15 16 //#pragma once16 #pragma once 17 17 18 18 #include "bits/locks.hfa" -
libcfa/src/concurrency/invoke.h
r2ed94a9 rb110bcc 10 10 // Created On : Tue Jan 17 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Nov 29 20:42:21 2022 13 // Update Count : 56 14 // 12 // Last Modified On : Tue Mar 14 13:39:31 2023 13 // Update Count : 59 14 // 15 16 // No not use #pragma once was this file is included twice in some places. It has its own guard system. 15 17 16 18 #include "bits/containers.hfa" -
libcfa/src/concurrency/io.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #if defined(__CFA_DEBUG__) … … 296 295 // make sure the target hasn't stopped existing since last time 297 296 HELP: if(target < ctxs_count) { 298 // calculate it's age and how young it could be before we give ip on helping297 // calculate it's age and how young it could be before we give up on helping 299 298 const __readyQ_avg_t cutoff = calc_cutoff(ctsc, ctx->cq.id, ctxs_count, io.data, io.tscs, __shard_factor.io, false); 300 299 const __readyQ_avg_t age = moving_average(ctsc, io.tscs[target].t.tv, io.tscs[target].t.ma, false); -
libcfa/src/concurrency/io/call.cfa.in
r2ed94a9 rb110bcc 31 31 Prelude = """#define __cforall_thread__ 32 32 33 #include <unistd.h> 34 #include <errno.h> 35 #include <sys/socket.h> 36 #include <time.hfa> 37 33 38 #include "bits/defs.hfa" 34 39 #include "kernel.hfa" … … 43 48 #include <assert.h> 44 49 #include <stdint.h> 45 #include <errno.h>46 50 #include <linux/io_uring.h> 47 48 51 #include "kernel/fwd.hfa" 49 52 … … 82 85 // I/O Forwards 83 86 //============================================================================================= 84 #include <time.hfa>85 86 // Some forward declarations87 #include <errno.h>88 #include <unistd.h>89 87 90 88 extern "C" { 91 #include <asm/types.h>92 #include <sys/socket.h>93 #include <sys/syscall.h>94 95 89 #if defined(CFA_HAVE_PREADV2) 96 90 struct iovec; 97 extern ssize_t preadv2 (int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags);91 extern ssize_t preadv2 (int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags); 98 92 #endif 99 93 #if defined(CFA_HAVE_PWRITEV2) 100 94 struct iovec; 101 extern ssize_t pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags);95 extern ssize_t pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags); 102 96 #endif 103 97 … … 114 108 struct msghdr; 115 109 struct sockaddr; 116 extern ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 117 extern ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 118 extern ssize_t send(int sockfd, const void *buf, size_t len, int flags); 119 extern ssize_t recv(int sockfd, void *buf, size_t len, int flags); 120 extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); 121 extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 110 extern ssize_t sendmsg(int sockfd, const struct msghdr * msg, int flags); 111 extern ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags); 112 extern ssize_t send(int sockfd, const void * buf, size_t len, int flags); 113 extern ssize_t recv(int sockfd, void * buf, size_t len, int flags); 122 114 123 115 extern int fallocate(int fd, int mode, off_t offset, off_t len); 124 116 extern int posix_fadvise(int fd, off_t offset, off_t len, int advice); 125 extern int madvise(void * addr, size_t length, int advice);126 127 extern int openat(int dirfd, const char * pathname, int flags, mode_t mode);117 extern int madvise(void * addr, size_t length, int advice); 118 119 extern int openat(int dirfd, const char * pathname, int flags, mode_t mode); 128 120 extern int close(int fd); 129 121 130 extern ssize_t read (int fd, void * buf, size_t count);122 extern ssize_t read (int fd, void * buf, size_t count); 131 123 132 124 struct epoll_event; 133 extern int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event);134 135 extern ssize_t splice(int fd_in, __off64_t * off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags);125 extern int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event); 126 127 extern ssize_t splice(int fd_in, __off64_t * off_in, int fd_out, __off64_t * off_out, size_t len, unsigned int flags); 136 128 extern ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags); 137 129 } … … 232 224 calls = [ 233 225 # CFA_HAVE_IORING_OP_READV 234 Call('READV', 'ssize_t preadv2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags)', {226 Call('READV', 'ssize_t preadv2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags)', { 235 227 'fd' : 'fd', 228 'addr': '(typeof(sqe->addr))iov', 229 'len' : 'iovcnt', 236 230 'off' : 'offset', 237 'addr': '(uintptr_t)iov', 238 'len' : 'iovcnt', 231 'rw_flags' : 'flags' 239 232 }, define = 'CFA_HAVE_PREADV2'), 240 233 # CFA_HAVE_IORING_OP_WRITEV 241 Call('WRITEV', 'ssize_t pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags)', {234 Call('WRITEV', 'ssize_t pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags)', { 242 235 'fd' : 'fd', 236 'addr': '(typeof(sqe->addr))iov', 237 'len' : 'iovcnt', 243 238 'off' : 'offset', 244 'addr': '(uintptr_t)iov', 245 'len' : 'iovcnt' 239 'rw_flags' : 'flags' 246 240 }, define = 'CFA_HAVE_PWRITEV2'), 247 241 # CFA_HAVE_IORING_OP_FSYNC … … 250 244 }), 251 245 # CFA_HAVE_IORING_OP_EPOLL_CTL 252 Call('EPOLL_CTL', 'int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event)', {246 Call('EPOLL_CTL', 'int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event)', { 253 247 'fd': 'epfd', 248 'len': 'op', 254 249 'addr': 'fd', 255 'len': 'op', 256 'off': '(uintptr_t)event' 250 'off': '(typeof(sqe->off))event' 257 251 }), 258 252 # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE … … 264 258 }), 265 259 # CFA_HAVE_IORING_OP_SENDMSG 266 Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr * msg, int flags)', {267 'fd': 'sockfd', 268 'addr': '( uintptr_t)(struct msghdr *)msg',260 Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr * msg, int flags)', { 261 'fd': 'sockfd', 262 'addr': '(typeof(sqe->addr))(struct msghdr *)msg', 269 263 'len': '1', 270 264 'msg_flags': 'flags' 271 265 }), 272 266 # CFA_HAVE_IORING_OP_RECVMSG 273 Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags)', {274 'fd': 'sockfd', 275 'addr': '( uintptr_t)(struct msghdr *)msg',267 Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags)', { 268 'fd': 'sockfd', 269 'addr': '(typeof(sqe->addr))(struct msghdr *)msg', 276 270 'len': '1', 277 271 'msg_flags': 'flags' 278 272 }), 279 273 # CFA_HAVE_IORING_OP_SEND 280 Call('SEND', 'ssize_t send(int sockfd, const void * buf, size_t len, int flags)', {281 'fd': 'sockfd', 282 'addr': '( uintptr_t)buf',274 Call('SEND', 'ssize_t send(int sockfd, const void * buf, size_t len, int flags)', { 275 'fd': 'sockfd', 276 'addr': '(typeof(sqe->addr))buf', 283 277 'len': 'len', 284 278 'msg_flags': 'flags' 285 279 }), 286 280 # CFA_HAVE_IORING_OP_RECV 287 Call('RECV', 'ssize_t recv(int sockfd, void * buf, size_t len, int flags)', {288 'fd': 'sockfd', 289 'addr': '( uintptr_t)buf',281 Call('RECV', 'ssize_t recv(int sockfd, void * buf, size_t len, int flags)', { 282 'fd': 'sockfd', 283 'addr': '(typeof(sqe->addr))buf', 290 284 'len': 'len', 291 285 'msg_flags': 'flags' 292 286 }), 293 287 # CFA_HAVE_IORING_OP_ACCEPT 294 Call('ACCEPT', 'int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)', {295 'fd': 'sockfd', 296 'addr': '( uintptr_t)addr',297 'addr2': '( uintptr_t)addrlen',288 Call('ACCEPT', 'int accept4(int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags)', { 289 'fd': 'sockfd', 290 'addr': '(typeof(sqe->addr))&addr', 291 'addr2': '(typeof(sqe->addr2))addrlen', 298 292 'accept_flags': 'flags' 299 293 }), 300 294 # CFA_HAVE_IORING_OP_CONNECT 301 Call('CONNECT', 'int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)', {302 'fd': 'sockfd', 303 'addr': '( uintptr_t)addr',295 Call('CONNECT', 'int connect(int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen)', { 296 'fd': 'sockfd', 297 'addr': '(typeof(sqe->addr))&addr', 304 298 'off': 'addrlen' 305 299 }), … … 307 301 Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', { 308 302 'fd': 'fd', 309 'addr': '(uintptr_t)len',310 303 'len': 'mode', 311 'off': 'offset' 304 'off': 'offset', 305 'addr': 'len' 312 306 }), 313 307 # CFA_HAVE_IORING_OP_FADVISE … … 319 313 }), 320 314 # CFA_HAVE_IORING_OP_MADVISE 321 Call('MADVISE', 'int madvise(void * addr, size_t length, int advice)', {322 'addr': '( uintptr_t)addr',315 Call('MADVISE', 'int madvise(void * addr, size_t length, int advice)', { 316 'addr': '(typeof(sqe->addr))addr', 323 317 'len': 'length', 324 318 'fadvise_advice': 'advice' 325 319 }), 326 320 # CFA_HAVE_IORING_OP_OPENAT 327 Call('OPENAT', 'int openat(int dirfd, const char * pathname, int flags, mode_t mode)', {321 Call('OPENAT', 'int openat(int dirfd, const char * pathname, int flags, mode_t mode)', { 328 322 'fd': 'dirfd', 329 'addr': '( uintptr_t)pathname',330 ' len': 'mode',331 ' open_flags': 'flags;'323 'addr': '(typeof(sqe->addr))pathname', 324 'open_flags': 'flags;', 325 'len': 'mode' 332 326 }), 333 327 # CFA_HAVE_IORING_OP_OPENAT2 334 Call('OPENAT2', 'int openat2(int dirfd, const char * pathname, struct open_how * how, size_t size)', {328 Call('OPENAT2', 'int openat2(int dirfd, const char * pathname, struct open_how * how, size_t size)', { 335 329 'fd': 'dirfd', 336 'addr': ' pathname',337 ' len': 'sizeof(*how)',338 ' off': '(uintptr_t)how',330 'addr': '(typeof(sqe->addr))pathname', 331 'off': '(typeof(sqe->off))how', 332 'len': 'sizeof(*how)' 339 333 }, define = 'CFA_HAVE_OPENAT2'), 340 334 # CFA_HAVE_IORING_OP_CLOSE … … 343 337 }), 344 338 # CFA_HAVE_IORING_OP_STATX 345 Call('STATX', 'int statx(int dirfd, const char * pathname, int flags, unsigned int mask, struct statx *statxbuf)', {339 Call('STATX', 'int statx(int dirfd, const char * pathname, int flags, unsigned int mask, struct statx * statxbuf)', { 346 340 'fd': 'dirfd', 347 ' off': '(uintptr_t)statxbuf',348 ' addr': 'pathname',341 'addr': '(typeof(sqe->addr))pathname', 342 'statx_flags': 'flags', 349 343 'len': 'mask', 350 ' statx_flags': 'flags'344 'off': '(typeof(sqe->off))statxbuf' 351 345 }, define = 'CFA_HAVE_STATX'), 352 346 # CFA_HAVE_IORING_OP_READ 353 347 Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', { 354 348 'fd': 'fd', 355 'addr': '( uintptr_t)buf',349 'addr': '(typeof(sqe->addr))buf', 356 350 'len': 'count' 357 351 }), … … 359 353 Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', { 360 354 'fd': 'fd', 361 'addr': '( uintptr_t)buf',355 'addr': '(typeof(sqe->addr))buf', 362 356 'len': 'count' 363 357 }), 364 358 # CFA_HAVE_IORING_OP_SPLICE 365 Call('SPLICE', 'ssize_t splice(int fd_in, __off64_t * off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags)', {359 Call('SPLICE', 'ssize_t splice(int fd_in, __off64_t * off_in, int fd_out, __off64_t * off_out, size_t len, unsigned int flags)', { 366 360 'splice_fd_in': 'fd_in', 367 'splice_off_in': 'off_in ? ( __u64)*off_in : (__u64)-1',361 'splice_off_in': 'off_in ? (typeof(sqe->splice_off_in))*off_in : (typeof(sqe->splice_off_in))-1', 368 362 'fd': 'fd_out', 369 'off': 'off_out ? ( __u64)*off_out : (__u64)-1',363 'off': 'off_out ? (typeof(sqe->off))*off_out : (typeof(sqe->off))-1', 370 364 'len': 'len', 371 365 'splice_flags': 'flags' -
libcfa/src/concurrency/io/setup.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #if defined(__CFA_DEBUG__) -
libcfa/src/concurrency/iofwd.hfa
r2ed94a9 rb110bcc 9 9 // Author : Thierry Delisle 10 10 // Created On : Thu Apr 23 17:31:00 2020 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 13 23:54:57 2023 13 // Update Count : 1 14 14 // 15 15 … … 17 17 18 18 #include <unistd.h> 19 #include <sys/socket.h> 20 19 21 extern "C" { 20 22 #include <asm/types.h> … … 48 50 typedef __off64_t off64_t; 49 51 50 struct cluster;51 struct io_context$;52 53 struct iovec;54 struct msghdr;55 struct sockaddr;56 struct statx;57 52 struct epoll_event; 58 59 struct io_uring_sqe;60 53 61 54 //----------------------------------------------------------------------- … … 88 81 // synchronous calls 89 82 #if defined(CFA_HAVE_PREADV2) 90 extern ssize_t cfa_preadv2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);83 extern ssize_t cfa_preadv2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags); 91 84 #endif 92 85 #if defined(CFA_HAVE_PWRITEV2) 93 extern ssize_t cfa_pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);86 extern ssize_t cfa_pwritev2(int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags); 94 87 #endif 95 88 extern int cfa_fsync(int fd, __u64 submit_flags); 96 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags);89 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags); 97 90 extern int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags); 98 extern ssize_t cfa_sendmsg(int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags);99 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr * msg, int flags, __u64 submit_flags);100 extern ssize_t cfa_send(int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags);101 extern ssize_t cfa_recv(int sockfd, void * buf, size_t len, int flags, __u64 submit_flags);102 extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);103 extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);91 extern ssize_t cfa_sendmsg(int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags); 92 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr * msg, int flags, __u64 submit_flags); 93 extern ssize_t cfa_send(int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags); 94 extern ssize_t cfa_recv(int sockfd, void * buf, size_t len, int flags, __u64 submit_flags); 95 extern int cfa_accept4(int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags, __u64 submit_flags); 96 extern int cfa_connect(int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen, __u64 submit_flags); 104 97 extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, __u64 submit_flags); 105 98 extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, __u64 submit_flags); 106 extern int cfa_madvise(void * addr, size_t length, int advice, __u64 submit_flags);107 extern int cfa_openat(int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags);99 extern int cfa_madvise(void * addr, size_t length, int advice, __u64 submit_flags); 100 extern int cfa_openat(int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags); 108 101 #if defined(CFA_HAVE_OPENAT2) 109 extern int cfa_openat2(int dirfd, const char * pathname, struct open_how * how, size_t size, __u64 submit_flags);102 extern int cfa_openat2(int dirfd, const char * pathname, struct open_how * how, size_t size, __u64 submit_flags); 110 103 #endif 111 104 extern int cfa_close(int fd, __u64 submit_flags); 112 105 #if defined(CFA_HAVE_STATX) 113 extern int cfa_statx(int dirfd, const char * pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);106 extern int cfa_statx(int dirfd, const char * pathname, int flags, unsigned int mask, struct statx * statxbuf, __u64 submit_flags); 114 107 #endif 115 108 extern ssize_t cfa_read(int fd, void * buf, size_t count, __u64 submit_flags); 116 109 extern ssize_t cfa_write(int fd, void * buf, size_t count, __u64 submit_flags); 117 extern ssize_t cfa_splice(int fd_in, __off64_t * off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags);110 extern ssize_t cfa_splice(int fd_in, __off64_t * off_in, int fd_out, __off64_t * off_out, size_t len, unsigned int flags, __u64 submit_flags); 118 111 extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags); 119 112 … … 121 114 // asynchronous calls 122 115 #if defined(CFA_HAVE_PREADV2) 123 extern void async_preadv2(io_future_t & future, int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);116 extern void async_preadv2(io_future_t & future, int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags); 124 117 #endif 125 118 #if defined(CFA_HAVE_PWRITEV2) 126 extern void async_pwritev2(io_future_t & future, int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);119 extern void async_pwritev2(io_future_t & future, int fd, const struct iovec * iov, int iovcnt, off_t offset, int flags, __u64 submit_flags); 127 120 #endif 128 121 extern void async_fsync(io_future_t & future, int fd, __u64 submit_flags); 129 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags);122 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags); 130 123 extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags); 131 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags);132 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr * msg, int flags, __u64 submit_flags);133 extern void async_send(io_future_t & future, int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags);134 extern void async_recv(io_future_t & future, int sockfd, void * buf, size_t len, int flags, __u64 submit_flags);135 extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);136 extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);124 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags); 125 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr * msg, int flags, __u64 submit_flags); 126 extern void async_send(io_future_t & future, int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags); 127 extern void async_recv(io_future_t & future, int sockfd, void * buf, size_t len, int flags, __u64 submit_flags); 128 extern void async_accept4(io_future_t & future, int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags, __u64 submit_flags); 129 extern void async_connect(io_future_t & future, int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen, __u64 submit_flags); 137 130 extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, __u64 submit_flags); 138 131 extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, __u64 submit_flags); 139 extern void async_madvise(io_future_t & future, void * addr, size_t length, int advice, __u64 submit_flags);140 extern void async_openat(io_future_t & future, int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags);132 extern void async_madvise(io_future_t & future, void * addr, size_t length, int advice, __u64 submit_flags); 133 extern void async_openat(io_future_t & future, int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags); 141 134 #if defined(CFA_HAVE_OPENAT2) 142 extern void async_openat2(io_future_t & future, int dirfd, const char * pathname, struct open_how * how, size_t size, __u64 submit_flags);135 extern void async_openat2(io_future_t & future, int dirfd, const char * pathname, struct open_how * how, size_t size, __u64 submit_flags); 143 136 #endif 144 137 extern void async_close(io_future_t & future, int fd, __u64 submit_flags); 145 138 #if defined(CFA_HAVE_STATX) 146 extern void async_statx(io_future_t & future, int dirfd, const char * pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);139 extern void async_statx(io_future_t & future, int dirfd, const char * pathname, int flags, unsigned int mask, struct statx * statxbuf, __u64 submit_flags); 147 140 #endif 148 141 void async_read(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags); 149 142 extern void async_write(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags); 150 extern void async_splice(io_future_t & future, int fd_in, __off64_t * off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags);143 extern void async_splice(io_future_t & future, int fd_in, __off64_t * off_in, int fd_out, __off64_t * off_out, size_t len, unsigned int flags, __u64 submit_flags); 151 144 extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags); 152 145 -
libcfa/src/concurrency/kernel.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Nov 30 18:14:08 202213 // Update Count : 7 612 // Last Modified On : Mon Jan 9 08:42:05 2023 13 // Update Count : 77 14 14 // 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__ -
libcfa/src/concurrency/kernel/cluster.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #include "bits/defs.hfa" … … 69 68 return max_cores_l; 70 69 } 71 72 #if defined(CFA_HAVE_LINUX_LIBRSEQ)73 // No forward declaration needed74 #define __kernel_rseq_register rseq_register_current_thread75 #define __kernel_rseq_unregister rseq_unregister_current_thread76 #elif defined(CFA_HAVE_LINUX_RSEQ_H)77 static void __kernel_raw_rseq_register (void);78 static void __kernel_raw_rseq_unregister(void);79 80 #define __kernel_rseq_register __kernel_raw_rseq_register81 #define __kernel_rseq_unregister __kernel_raw_rseq_unregister82 #else83 // No forward declaration needed84 // No initialization needed85 static inline void noop(void) {}86 87 #define __kernel_rseq_register noop88 #define __kernel_rseq_unregister noop89 #endif90 70 91 71 //======================================================================= … … 111 91 // Lock-Free registering/unregistering of threads 112 92 unsigned register_proc_id( void ) with(__scheduler_lock.lock) { 113 __kernel_rseq_register();114 115 93 bool * handle = (bool *)&kernelTLS().sched_lock; 116 94 … … 162 140 163 141 __atomic_store_n(cell, 0p, __ATOMIC_RELEASE); 164 165 __kernel_rseq_unregister();166 142 } 167 143 … … 505 481 /* paranoid */ verify( mock_head(this) == this.l.prev ); 506 482 } 507 508 #if defined(CFA_HAVE_LINUX_LIBRSEQ)509 // No definition needed510 #elif defined(CFA_HAVE_LINUX_RSEQ_H)511 512 #if defined( __x86_64 ) || defined( __i386 )513 #define RSEQ_SIG 0x53053053514 #elif defined( __ARM_ARCH )515 #ifdef __ARMEB__516 #define RSEQ_SIG 0xf3def5e7 /* udf #24035 ; 0x5de3 (ARMv6+) */517 #else518 #define RSEQ_SIG 0xe7f5def3 /* udf #24035 ; 0x5de3 */519 #endif520 #endif521 522 extern void __disable_interrupts_hard();523 extern void __enable_interrupts_hard();524 525 static void __kernel_raw_rseq_register (void) {526 /* paranoid */ verify( __cfaabi_rseq.cpu_id == RSEQ_CPU_ID_UNINITIALIZED );527 528 // int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), 0, (sigset_t *)0p, _NSIG / 8);529 int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), 0, RSEQ_SIG);530 if(ret != 0) {531 int e = errno;532 switch(e) {533 case EINVAL: abort("KERNEL ERROR: rseq register invalid argument");534 case ENOSYS: abort("KERNEL ERROR: rseq register no supported");535 case EFAULT: abort("KERNEL ERROR: rseq register with invalid argument");536 case EBUSY : abort("KERNEL ERROR: rseq register already registered");537 case EPERM : abort("KERNEL ERROR: rseq register sig argument on unregistration does not match the signature received on registration");538 default: abort("KERNEL ERROR: rseq register unexpected return %d", e);539 }540 }541 }542 543 static void __kernel_raw_rseq_unregister(void) {544 /* paranoid */ verify( __cfaabi_rseq.cpu_id >= 0 );545 546 // int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), RSEQ_FLAG_UNREGISTER, (sigset_t *)0p, _NSIG / 8);547 int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), RSEQ_FLAG_UNREGISTER, RSEQ_SIG);548 if(ret != 0) {549 int e = errno;550 switch(e) {551 case EINVAL: abort("KERNEL ERROR: rseq unregister invalid argument");552 case ENOSYS: abort("KERNEL ERROR: rseq unregister no supported");553 case EFAULT: abort("KERNEL ERROR: rseq unregister with invalid argument");554 case EBUSY : abort("KERNEL ERROR: rseq unregister already registered");555 case EPERM : abort("KERNEL ERROR: rseq unregister sig argument on unregistration does not match the signature received on registration");556 default: abort("KERNEL ERROR: rseq unregisteunexpected return %d", e);557 }558 }559 }560 #else561 // No definition needed562 #endif -
libcfa/src/concurrency/kernel/cluster.hfa
r2ed94a9 rb110bcc 146 146 } 147 147 148 static struct {149 constunsigned readyq;150 constunsigned io;148 const static struct { 149 unsigned readyq; 150 unsigned io; 151 151 } __shard_factor = { 2, 1 }; 152 152 -
libcfa/src/concurrency/kernel/private.hfa
r2ed94a9 rb110bcc 10 10 // Created On : Mon Feb 13 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Aug 12 08:21:33 202013 // Update Count : 912 // Last Modified On : Thu Mar 2 16:04:46 2023 13 // Update Count : 11 14 14 // 15 15 … … 29 29 30 30 extern "C" { 31 #if defined(CFA_HAVE_LINUX_LIBRSEQ)32 #include <rseq/rseq.h>33 #elif defined(CFA_HAVE_LINUX_RSEQ_H)34 #include <linux/rseq.h>35 #else36 #ifndef _GNU_SOURCE37 #error kernel/private requires gnu_source38 #endif39 31 #include <sched.h> 40 #endif41 32 } 42 33 … … 110 101 // Hardware 111 102 112 #if defined(CFA_HAVE_LINUX_LIBRSEQ)113 // No data needed114 #elif defined(CFA_HAVE_LINUX_RSEQ_H)115 extern "Cforall" {116 extern __attribute__((aligned(64))) __thread volatile struct rseq __cfaabi_rseq;117 }118 #else119 // No data needed120 #endif121 122 103 static inline int __kernel_getcpu() { 123 104 /* paranoid */ verify( ! __preemption_enabled() ); 124 #if defined(CFA_HAVE_LINUX_LIBRSEQ)125 return rseq_current_cpu();126 #elif defined(CFA_HAVE_LINUX_RSEQ_H)127 int r = __cfaabi_rseq.cpu_id;128 /* paranoid */ verify( r >= 0 );129 return r;130 #else131 105 return sched_getcpu(); 132 #endif133 106 } 134 107 -
libcfa/src/concurrency/kernel/startup.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__ 20 19 21 20 // C Includes 22 #include <errno.h> // errno21 #include <errno.h> // errno 23 22 #include <signal.h> 24 #include <string.h> // strerror25 #include <unistd.h> // sysconf26 23 #include <string.h> // strerror 24 #include <unistd.h> 25 #include <limits.h> // PTHREAD_STACK_MIN 27 26 extern "C" { 28 #include <limits.h> // PTHREAD_STACK_MIN 29 #include <unistd.h> // syscall 30 #include <sys/eventfd.h> // eventfd 31 #include <sys/mman.h> // mprotect 32 #include <sys/resource.h> // getrlimit 27 #include <sys/eventfd.h> // eventfd 28 #include <sys/mman.h> // mprotect 29 #include <sys/resource.h> // getrlimit 33 30 } 34 31 … … 36 33 #include "kernel/private.hfa" 37 34 #include "iofwd.hfa" 38 #include "startup.hfa" // STARTUP_PRIORITY_XXX35 #include "startup.hfa" // STARTUP_PRIORITY_XXX 39 36 #include "limits.hfa" 40 37 #include "math.hfa" … … 150 147 __scheduler_RWLock_t __scheduler_lock @= { 0 }; 151 148 152 #if defined(CFA_HAVE_LINUX_LIBRSEQ)153 // No data needed154 #elif defined(CFA_HAVE_LINUX_RSEQ_H)155 extern "Cforall" {156 __attribute__((aligned(64))) __thread volatile struct rseq __cfaabi_rseq @= {157 .cpu_id : RSEQ_CPU_ID_UNINITIALIZED,158 };159 }160 #else161 // No data needed162 #endif163 164 149 //----------------------------------------------------------------------------- 165 150 // Struct to steal stack -
libcfa/src/concurrency/locks.cfa
r2ed94a9 rb110bcc 16 16 17 17 #define __cforall_thread__ 18 #define _GNU_SOURCE19 18 20 19 #include "locks.hfa" -
libcfa/src/concurrency/locks.hfa
r2ed94a9 rb110bcc 32 32 #include <fstream.hfa> 33 33 34 35 34 // futex headers 36 35 #include <linux/futex.h> /* Definition of FUTEX_* constants */ … … 155 154 // futex_mutex 156 155 157 // - No cond var support158 156 // - Kernel thd blocking alternative to the spinlock 159 157 // - No ownership (will deadlock on reacq) … … 185 183 int state; 186 184 187 188 // // linear backoff omitted for now 189 // for( int spin = 4; spin < 1024; spin += spin) { 190 // state = 0; 191 // // if unlocked, lock and return 192 // if (internal_try_lock(this, state)) return; 193 // if (2 == state) break; 194 // for (int i = 0; i < spin; i++) Pause(); 195 // } 196 197 // no contention try to acquire 198 if (internal_try_lock(this, state)) return; 185 for( int spin = 4; spin < 1024; spin += spin) { 186 state = 0; 187 // if unlocked, lock and return 188 if (internal_try_lock(this, state)) return; 189 if (2 == state) break; 190 for (int i = 0; i < spin; i++) Pause(); 191 } 192 193 // // no contention try to acquire 194 // if (internal_try_lock(this, state)) return; 199 195 200 196 // if not in contended state, set to be in contended state … … 209 205 210 206 static inline void unlock(futex_mutex & this) with(this) { 211 // if uncontended do atomic eunlock and then return212 if (__atomic_fetch_sub(&val, 1, __ATOMIC_RELEASE) == 1) return; // TODO: try acq/rel 207 // if uncontended do atomic unlock and then return 208 if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return; 213 209 214 210 // otherwise threads are blocked so we must wake one 215 __atomic_store_n((int *)&val, 0, __ATOMIC_RELEASE);216 211 futex((int *)&val, FUTEX_WAKE, 1); 217 212 } … … 222 217 // to set recursion count after getting signalled; 223 218 static inline void on_wakeup( futex_mutex & f, size_t recursion ) {} 219 220 //----------------------------------------------------------------------------- 221 // go_mutex 222 223 // - Kernel thd blocking alternative to the spinlock 224 // - No ownership (will deadlock on reacq) 225 // - Golang's flavour of mutex 226 // - Impl taken from Golang: src/runtime/lock_futex.go 227 struct go_mutex { 228 // lock state any state other than UNLOCKED is locked 229 // enum LockState { UNLOCKED = 0, LOCKED = 1, SLEEPING = 2 }; 230 231 // stores a lock state 232 int val; 233 }; 234 235 static inline void ?{}( go_mutex & this ) with(this) { val = 0; } 236 237 static inline bool internal_try_lock(go_mutex & this, int & compare_val, int new_val ) with(this) { 238 return __atomic_compare_exchange_n((int*)&val, (int*)&compare_val, new_val, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE); 239 } 240 241 static inline int internal_exchange(go_mutex & this, int swap ) with(this) { 242 return __atomic_exchange_n((int*)&val, swap, __ATOMIC_ACQUIRE); 243 } 244 245 // if this is called recursively IT WILL DEADLOCK!!!!! 246 static inline void lock(go_mutex & this) with(this) { 247 int state, init_state; 248 249 // speculative grab 250 state = internal_exchange(this, 1); 251 if ( !state ) return; // state == 0 252 init_state = state; 253 for (;;) { 254 for( int i = 0; i < 4; i++ ) { 255 while( !val ) { // lock unlocked 256 state = 0; 257 if (internal_try_lock(this, state, init_state)) return; 258 } 259 for (int i = 0; i < 30; i++) Pause(); 260 } 261 262 while( !val ) { // lock unlocked 263 state = 0; 264 if (internal_try_lock(this, state, init_state)) return; 265 } 266 sched_yield(); 267 268 // if not in contended state, set to be in contended state 269 state = internal_exchange(this, 2); 270 if ( !state ) return; // state == 0 271 init_state = 2; 272 futex((int*)&val, FUTEX_WAIT, 2); // if val is not 2 this returns with EWOULDBLOCK 273 } 274 } 275 276 static inline void unlock( go_mutex & this ) with(this) { 277 // if uncontended do atomic unlock and then return 278 if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return; 279 280 // otherwise threads are blocked so we must wake one 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;} 286 static inline void on_wakeup( go_mutex & f, size_t recursion ) {} 224 287 225 288 //----------------------------------------------------------------------------- … … 253 316 static inline void on_wakeup(clh_lock & this, size_t recursion ) { lock(this); } 254 317 255 256 318 //----------------------------------------------------------------------------- 257 319 // Exponential backoff then block lock … … 272 334 this.lock_value = 0; 273 335 } 274 static inline void ^?{}( exp_backoff_then_block_lock & this ) {} 275 // static inline void ?{}( exp_backoff_then_block_lock & this, exp_backoff_then_block_lock this2 ) = void; 276 // static inline void ?=?( exp_backoff_then_block_lock & this, exp_backoff_then_block_lock this2 ) = void; 336 337 static inline void ^?{}( exp_backoff_then_block_lock & this ){} 277 338 278 339 static inline bool internal_try_lock(exp_backoff_then_block_lock & this, size_t & compare_val) with(this) { 279 if (__atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { 280 return true; 281 } 282 return false; 340 return __atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); 283 341 } 284 342 … … 286 344 287 345 static inline bool try_lock_contention(exp_backoff_then_block_lock & this) with(this) { 288 if (__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE) == 0) { 289 return true; 290 } 291 return false; 346 return !__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE); 292 347 } 293 348 294 349 static inline bool block(exp_backoff_then_block_lock & this) with(this) { 295 lock( spinlock __cfaabi_dbg_ctx2 ); // TODO change to lockfree queue (MPSC) 296 if (lock_value!= 2) {297 unlock( spinlock );298 return true;299 }300 insert_last( blocked_threads, *active_thread() );301 unlock( spinlock );350 lock( spinlock __cfaabi_dbg_ctx2 ); 351 if (__atomic_load_n( &lock_value, __ATOMIC_SEQ_CST) != 2) { 352 unlock( spinlock ); 353 return true; 354 } 355 insert_last( blocked_threads, *active_thread() ); 356 unlock( spinlock ); 302 357 park( ); 303 358 return true; … … 307 362 size_t compare_val = 0; 308 363 int spin = 4; 364 309 365 // linear backoff 310 366 for( ;; ) { … … 324 380 static inline void unlock(exp_backoff_then_block_lock & this) with(this) { 325 381 if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return; 326 lock( spinlock __cfaabi_dbg_ctx2 );327 thread$ * t = &try_pop_front( blocked_threads );328 unlock( spinlock );329 unpark( t );382 lock( spinlock __cfaabi_dbg_ctx2 ); 383 thread$ * t = &try_pop_front( blocked_threads ); 384 unlock( spinlock ); 385 unpark( t ); 330 386 } 331 387 -
libcfa/src/concurrency/monitor.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Thd Feb 23 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Dec 4 07:55:14 201913 // Update Count : 1 012 // Last Modified On : Sun Feb 19 17:00:59 2023 13 // Update Count : 12 14 14 // 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #include "monitor.hfa" -
libcfa/src/concurrency/mutex.cfa
r2ed94a9 rb110bcc 12 12 // Created On : Fri May 25 01:37:11 2018 13 13 // Last Modified By : Peter A. Buhr 14 // Last Modified On : Wed Dec 4 09:16:39 201915 // Update Count : 114 // Last Modified On : Sun Feb 19 17:01:36 2023 15 // Update Count : 3 16 16 // 17 17 18 18 #define __cforall_thread__ 19 #define _GNU_SOURCE20 19 21 20 #include "mutex.hfa" -
libcfa/src/concurrency/mutex_stmt.hfa
r2ed94a9 rb110bcc 1 #pragma once 2 1 3 #include "bits/algorithm.hfa" 2 4 #include "bits/defs.hfa" … … 4 6 //----------------------------------------------------------------------------- 5 7 // is_lock 6 trait is_lock(L & | sized(L)) { 8 forall(L & | sized(L)) 9 trait is_lock { 7 10 // For acquiring a lock 8 11 void lock( L & ); … … 24 27 // Sort locks based on address 25 28 __libcfa_small_sort(this.lockarr, count); 26 27 // acquire locks in order28 // for ( size_t i = 0; i < count; i++ ) {29 // lock(*this.lockarr[i]);30 // }31 }32 33 static inline void ^?{}( __mutex_stmt_lock_guard & this ) with(this) {34 // for ( size_t i = count; i > 0; i-- ) {35 // unlock(*lockarr[i - 1]);36 // }37 29 } 38 30 -
libcfa/src/concurrency/preemption.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Mon Jun 5 14:20:42 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Feb 17 11:18:57 202213 // Update Count : 5912 // Last Modified On : Mon Jan 9 08:42:59 2023 13 // Update Count : 60 14 14 // 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 // #define __CFA_DEBUG_PRINT_PREEMPTION__ -
libcfa/src/concurrency/pthread.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #include <signal.h> … … 35 34 struct pthread_values{ 36 35 inline Seqable; 37 void * value;36 void * value; 38 37 bool in_use; 39 38 }; … … 51 50 struct pthread_keys { 52 51 bool in_use; 53 void (* destructor)( void * );52 void (* destructor)( void * ); 54 53 Sequence(pthread_values) threads; 55 54 }; 56 55 57 static void ?{}(pthread_keys& k) {56 static void ?{}(pthread_keys& k) { 58 57 k.threads{}; 59 58 } … … 62 61 static pthread_keys cfa_pthread_keys_storage[PTHREAD_KEYS_MAX] __attribute__((aligned (16))); 63 62 64 static void init_pthread_storage() {65 for ( int i = 0; i < PTHREAD_KEYS_MAX; i++){63 static void init_pthread_storage() { 64 for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) { 66 65 cfa_pthread_keys_storage[i]{}; 67 66 } … … 96 95 97 96 /* condvar helper routines */ 98 static void init(pthread_cond_t * pcond){97 static void init(pthread_cond_t * pcond) { 99 98 static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)"); 100 cfa2pthr_cond_var_t * _cond = (cfa2pthr_cond_var_t*)pcond;99 cfa2pthr_cond_var_t * _cond = (cfa2pthr_cond_var_t *)pcond; 101 100 ?{}(*_cond); 102 101 } 103 102 104 static cfa2pthr_cond_var_t * get(pthread_cond_t* pcond){103 static cfa2pthr_cond_var_t * get(pthread_cond_t * pcond) { 105 104 static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)"); 106 return (cfa2pthr_cond_var_t *)pcond;107 } 108 109 static void destroy(pthread_cond_t * cond){105 return (cfa2pthr_cond_var_t *)pcond; 106 } 107 108 static void destroy(pthread_cond_t * cond) { 110 109 static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)"); 111 110 ^?{}(*get(cond)); … … 116 115 117 116 /* mutex helper routines */ 118 static void mutex_check(pthread_mutex_t * t){117 static void mutex_check(pthread_mutex_t * t) { 119 118 // Use double check to improve performance. 120 119 // Check is safe on x86; volatile prevents compiler reordering 121 volatile pthread_mutex_t * const mutex_ = t;120 volatile pthread_mutex_t * const mutex_ = t; 122 121 123 122 // SKULLDUGGERY: not a portable way to access the kind field, /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h … … 136 135 137 136 138 static void init(pthread_mutex_t * plock){137 static void init(pthread_mutex_t * plock) { 139 138 static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)"); 140 simple_owner_lock * _lock = (simple_owner_lock*)plock;139 simple_owner_lock * _lock = (simple_owner_lock *)plock; 141 140 ?{}(*_lock); 142 141 } 143 142 144 static simple_owner_lock * get(pthread_mutex_t* plock){143 static simple_owner_lock * get(pthread_mutex_t * plock) { 145 144 static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)"); 146 return (simple_owner_lock *)plock;147 } 148 149 static void destroy(pthread_mutex_t * plock){145 return (simple_owner_lock *)plock; 146 } 147 148 static void destroy(pthread_mutex_t * plock) { 150 149 static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)"); 151 150 ^?{}(*get(plock)); … … 153 152 154 153 //######################### Attr helpers ######################### 155 struct cfaPthread_attr_t {// thread attributes154 typedef struct cfaPthread_attr_t { // thread attributes 156 155 int contentionscope; 157 156 int detachstate; 158 157 size_t stacksize; 159 void * stackaddr;158 void * stackaddr; 160 159 int policy; 161 160 int inheritsched; 162 161 struct sched_param param; 163 } typedefcfaPthread_attr_t;164 165 static const cfaPthread_attr_t default_attrs {162 } cfaPthread_attr_t; 163 164 static const cfaPthread_attr_t default_attrs { 166 165 0, 167 166 0, 168 (size_t)65000,169 (void *)NULL,167 65_000, 168 NULL, 170 169 0, 171 170 0, … … 173 172 }; 174 173 175 static cfaPthread_attr_t * get(const pthread_attr_t* attr){176 static_assert(sizeof(pthread_attr_t) >= sizeof(cfaPthread_attr_t), "sizeof(pthread_attr_t) < sizeof(cfaPthread_attr_t)");177 return (cfaPthread_attr_t *)attr;174 static cfaPthread_attr_t * get(const pthread_attr_t * attr) { 175 static_assert(sizeof(pthread_attr_t) >= sizeof(cfaPthread_attr_t), "sizeof(pthread_attr_t) < sizeof(cfaPthread_attr_t)"); 176 return (cfaPthread_attr_t *)attr; 178 177 } 179 178 … … 190 189 191 190 // pthreads return value 192 void * joinval;191 void * joinval; 193 192 194 193 // pthread attributes 195 194 pthread_attr_t pthread_attr; 196 195 197 void *(* start_routine)(void *);198 void * start_arg;196 void *(* start_routine)(void *); 197 void * start_arg; 199 198 200 199 // thread local data 201 pthread_values * pthreadData;200 pthread_values * pthreadData; 202 201 203 202 // flag used for tryjoin … … 207 206 /* thread part routines */ 208 207 // cfaPthread entry point 209 void main(cfaPthread & _thread) with(_thread){210 joinval = start_routine(start_arg);208 void main(cfaPthread & _thread) with(_thread) { 209 joinval = start_routine(start_arg); 211 210 isTerminated = true; 212 211 } 213 212 214 static cfaPthread * lookup( pthread_t p ){215 static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *),"sizeof(pthread_t) < sizeof(cfaPthread*)");216 return (cfaPthread *)p;217 } 218 219 static void pthread_deletespecific_( pthread_values * values ) { // see uMachContext::invokeTask220 pthread_values * value;221 pthread_keys * key;213 static cfaPthread * lookup( pthread_t p ) { 214 static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *),"sizeof(pthread_t) < sizeof(cfaPthread *)"); 215 return (cfaPthread *)p; 216 } 217 218 static void pthread_deletespecific_( pthread_values * values ) { // see uMachContext::invokeTask 219 pthread_values * value; 220 pthread_keys * key; 222 221 bool destcalled = true; 223 if (values != NULL) {222 if (values != NULL) { 224 223 for ( int attempts = 0; attempts < PTHREAD_DESTRUCTOR_ITERATIONS && destcalled ; attempts += 1 ) { 225 224 destcalled = false; 226 225 lock(key_lock); 227 for ( int i = 0; i < PTHREAD_KEYS_MAX; i++){226 for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) { 228 227 // for each valid key 229 if ( values[i].in_use) {228 if ( values[i].in_use) { 230 229 value = &values[i]; 231 230 key = &cfa_pthread_keys[i]; … … 234 233 // if a key value has a non-NULL destructor pointer, and the thread has a non-NULL value associated with that key, 235 234 // the value of the key is set to NULL, and then the function pointed to is called with the previously associated value as its sole argument. 236 if (value->value != NULL && key->destructor != NULL) {235 if (value->value != NULL && key->destructor != NULL) { 237 236 unlock(key_lock); 238 237 key->destructor(value->value); // run destructor … … 249 248 } 250 249 251 static void ^?{}(cfaPthread & mutex t) {250 static void ^?{}(cfaPthread & mutex t) { 252 251 // delete pthread local storage 253 252 pthread_values * values = t.pthreadData; … … 255 254 } 256 255 257 static void ?{}(cfaPthread & t, pthread_t* _thread, const pthread_attr_t * _attr,void *(*start_routine)(void *), void * arg) {258 static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *), "pthread_t too small to hold a pointer: sizeof(pthread_t) < sizeof(cfaPthread*)");256 static void ?{}(cfaPthread & t, pthread_t * _thread, const pthread_attr_t * _attr,void *(* start_routine)(void *), void * arg) { 257 static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *), "pthread_t too small to hold a pointer: sizeof(pthread_t) < sizeof(cfaPthread *)"); 259 258 260 259 // set up user thread stackSize … … 278 277 //######################### Pthread Attrs ######################### 279 278 280 int pthread_attr_init(pthread_attr_t * attr) libcfa_public __THROW {281 cfaPthread_attr_t * _attr = get(attr);279 int pthread_attr_init(pthread_attr_t * attr) libcfa_public __THROW { 280 cfaPthread_attr_t * _attr = get(attr); 282 281 ?{}(*_attr, default_attrs); 283 282 return 0; 284 283 } 285 int pthread_attr_destroy(pthread_attr_t * attr) libcfa_public __THROW {284 int pthread_attr_destroy(pthread_attr_t * attr) libcfa_public __THROW { 286 285 ^?{}(*get(attr)); 287 286 return 0; 288 287 } 289 288 290 int pthread_attr_setscope( pthread_attr_t * attr, int contentionscope ) libcfa_public __THROW {289 int pthread_attr_setscope( pthread_attr_t * attr, int contentionscope ) libcfa_public __THROW { 291 290 get( attr )->contentionscope = contentionscope; 292 291 return 0; 293 292 } // pthread_attr_setscope 294 293 295 int pthread_attr_getscope( const pthread_attr_t * attr, int *contentionscope ) libcfa_public __THROW {294 int pthread_attr_getscope( const pthread_attr_t * attr, int * contentionscope ) libcfa_public __THROW { 296 295 *contentionscope = get( attr )->contentionscope; 297 296 return 0; 298 297 } // pthread_attr_getscope 299 298 300 int pthread_attr_setdetachstate( pthread_attr_t * attr, int detachstate ) libcfa_public __THROW {299 int pthread_attr_setdetachstate( pthread_attr_t * attr, int detachstate ) libcfa_public __THROW { 301 300 get( attr )->detachstate = detachstate; 302 301 return 0; 303 302 } // pthread_attr_setdetachstate 304 303 305 int pthread_attr_getdetachstate( const pthread_attr_t * attr, int *detachstate ) libcfa_public __THROW {304 int pthread_attr_getdetachstate( const pthread_attr_t * attr, int * detachstate ) libcfa_public __THROW { 306 305 *detachstate = get( attr )->detachstate; 307 306 return 0; 308 307 } // pthread_attr_getdetachstate 309 308 310 int pthread_attr_setstacksize( pthread_attr_t * attr, size_t stacksize ) libcfa_public __THROW {309 int pthread_attr_setstacksize( pthread_attr_t * attr, size_t stacksize ) libcfa_public __THROW { 311 310 get( attr )->stacksize = stacksize; 312 311 return 0; 313 312 } // pthread_attr_setstacksize 314 313 315 int pthread_attr_getstacksize( const pthread_attr_t * attr, size_t *stacksize ) libcfa_public __THROW {314 int pthread_attr_getstacksize( const pthread_attr_t * attr, size_t * stacksize ) libcfa_public __THROW { 316 315 *stacksize = get( attr )->stacksize; 317 316 return 0; … … 326 325 } // pthread_attr_setguardsize 327 326 328 int pthread_attr_setstackaddr( pthread_attr_t * attr, void *stackaddr ) libcfa_public __THROW {327 int pthread_attr_setstackaddr( pthread_attr_t * attr, void * stackaddr ) libcfa_public __THROW { 329 328 get( attr )->stackaddr = stackaddr; 330 329 return 0; 331 330 } // pthread_attr_setstackaddr 332 331 333 int pthread_attr_getstackaddr( const pthread_attr_t * attr, void **stackaddr ) libcfa_public __THROW {332 int pthread_attr_getstackaddr( const pthread_attr_t * attr, void ** stackaddr ) libcfa_public __THROW { 334 333 *stackaddr = get( attr )->stackaddr; 335 334 return 0; 336 335 } // pthread_attr_getstackaddr 337 336 338 int pthread_attr_setstack( pthread_attr_t * attr, void *stackaddr, size_t stacksize ) libcfa_public __THROW {337 int pthread_attr_setstack( pthread_attr_t * attr, void * stackaddr, size_t stacksize ) libcfa_public __THROW { 339 338 get( attr )->stackaddr = stackaddr; 340 339 get( attr )->stacksize = stacksize; … … 342 341 } // pthread_attr_setstack 343 342 344 int pthread_attr_getstack( const pthread_attr_t * attr, void **stackaddr, size_t *stacksize ) libcfa_public __THROW {343 int pthread_attr_getstack( const pthread_attr_t * attr, void ** stackaddr, size_t * stacksize ) libcfa_public __THROW { 345 344 *stackaddr = get( attr )->stackaddr; 346 345 *stacksize = get( attr )->stacksize; … … 351 350 // already running thread threadID. It shall be called on unitialized attr 352 351 // and destroyed with pthread_attr_destroy when no longer needed. 353 int pthread_getattr_np( pthread_t threadID, pthread_attr_t * attr ) libcfa_public __THROW { // GNU extension352 int pthread_getattr_np( pthread_t threadID, pthread_attr_t * attr ) libcfa_public __THROW { // GNU extension 354 353 check_nonnull(attr); 355 354 … … 363 362 //######################### Threads ######################### 364 363 365 int pthread_create(pthread_t * _thread, const pthread_attr_t * attr, void *(* start_routine)(void *), void * arg) libcfa_public __THROW {366 cfaPthread * t = alloc();364 int pthread_create(pthread_t * _thread, const pthread_attr_t * attr, void *(* start_routine)(void *), void * arg) libcfa_public __THROW { 365 cfaPthread * t = alloc(); 367 366 (*t){_thread, attr, start_routine, arg}; 368 367 return 0; 369 368 } 370 369 371 372 int pthread_join(pthread_t _thread, void **value_ptr) libcfa_public __THROW { 370 int pthread_join(pthread_t _thread, void ** value_ptr) libcfa_public __THROW { 373 371 // if thread is invalid 374 372 if (_thread == NULL) return EINVAL; … … 376 374 377 375 // get user thr pointer 378 cfaPthread * p = lookup(_thread);376 cfaPthread * p = lookup(_thread); 379 377 try { 380 378 join(*p); … … 389 387 } 390 388 391 int pthread_tryjoin_np(pthread_t _thread, void ** value_ptr) libcfa_public __THROW {389 int pthread_tryjoin_np(pthread_t _thread, void ** value_ptr) libcfa_public __THROW { 392 390 // if thread is invalid 393 391 if (_thread == NULL) return EINVAL; 394 392 if (_thread == pthread_self()) return EDEADLK; 395 393 396 cfaPthread * p = lookup(_thread);394 cfaPthread * p = lookup(_thread); 397 395 398 396 // thread not finished ? … … 412 410 void pthread_exit(void * status) libcfa_public __THROW { 413 411 pthread_t pid = pthread_self(); 414 cfaPthread * _thread = (cfaPthread*)pid;412 cfaPthread * _thread = (cfaPthread *)pid; 415 413 _thread->joinval = status; // set return value 416 414 _thread->isTerminated = 1; // set terminated flag … … 426 424 //######################### Mutex ######################### 427 425 428 int pthread_mutex_init(pthread_mutex_t *_mutex, const pthread_mutexattr_t * attr) libcfa_public __THROW {426 int pthread_mutex_init(pthread_mutex_t *_mutex, const pthread_mutexattr_t * attr) libcfa_public __THROW { 429 427 check_nonnull(_mutex); 430 428 init(_mutex); … … 435 433 int pthread_mutex_destroy(pthread_mutex_t *_mutex) libcfa_public __THROW { 436 434 check_nonnull(_mutex); 437 simple_owner_lock * _lock = get(_mutex);438 if (_lock->owner != NULL) {435 simple_owner_lock * _lock = get(_mutex); 436 if (_lock->owner != NULL) { 439 437 return EBUSY; 440 438 } … … 446 444 check_nonnull(_mutex); 447 445 mutex_check(_mutex); 448 simple_owner_lock * _lock = get(_mutex);446 simple_owner_lock * _lock = get(_mutex); 449 447 lock(*_lock); 450 448 return 0; … … 453 451 int pthread_mutex_unlock(pthread_mutex_t *_mutex) libcfa_public __THROW { 454 452 check_nonnull(_mutex); 455 simple_owner_lock * _lock = get(_mutex);456 if (_lock->owner != active_thread()) {453 simple_owner_lock * _lock = get(_mutex); 454 if (_lock->owner != active_thread()) { 457 455 return EPERM; 458 456 } // current thread does not hold the mutex … … 463 461 int pthread_mutex_trylock(pthread_mutex_t *_mutex) libcfa_public __THROW { 464 462 check_nonnull(_mutex); 465 simple_owner_lock * _lock = get(_mutex);466 if (_lock->owner != active_thread() && _lock->owner != NULL) {463 simple_owner_lock * _lock = get(_mutex); 464 if (_lock->owner != active_thread() && _lock->owner != NULL) { 467 465 return EBUSY; 468 466 } // if mutex is owned … … 474 472 475 473 /* conditional variable routines */ 476 int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t *attr) libcfa_public __THROW {474 int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr) libcfa_public __THROW { 477 475 check_nonnull(cond); 478 476 init(cond); … … 480 478 } //pthread_cond_init 481 479 482 int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t *_mutex) libcfa_public __THROW {480 int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t *_mutex) libcfa_public __THROW { 483 481 check_nonnull(_mutex); 484 482 check_nonnull(cond); … … 494 492 } // pthread_cond_timedwait 495 493 496 int pthread_cond_signal(pthread_cond_t * cond) libcfa_public __THROW {494 int pthread_cond_signal(pthread_cond_t * cond) libcfa_public __THROW { 497 495 check_nonnull(cond); 498 496 return notify_one(*get(cond)); 499 497 } // pthread_cond_signal 500 498 501 int pthread_cond_broadcast(pthread_cond_t * cond) libcfa_public __THROW {499 int pthread_cond_broadcast(pthread_cond_t * cond) libcfa_public __THROW { 502 500 check_nonnull(cond); 503 501 return notify_all(*get(cond)); 504 502 } // pthread_cond_broadcast 505 503 506 int pthread_cond_destroy(pthread_cond_t * cond) libcfa_public __THROW {504 int pthread_cond_destroy(pthread_cond_t * cond) libcfa_public __THROW { 507 505 check_nonnull(cond); 508 506 destroy(cond); … … 514 512 //######################### Local storage ######################### 515 513 516 int pthread_once(pthread_once_t * once_control, void (*init_routine)(void)) libcfa_public __THROW {514 int pthread_once(pthread_once_t * once_control, void (* init_routine)(void)) libcfa_public __THROW { 517 515 static_assert(sizeof(pthread_once_t) >= sizeof(int),"sizeof(pthread_once_t) < sizeof(int)"); 518 516 check_nonnull(once_control); … … 527 525 } // pthread_once 528 526 529 int pthread_key_create( pthread_key_t * key, void (*destructor)( void * ) ) libcfa_public __THROW {527 int pthread_key_create( pthread_key_t * key, void (* destructor)( void * ) ) libcfa_public __THROW { 530 528 lock(key_lock); 531 529 for ( int i = 0; i < PTHREAD_KEYS_MAX; i += 1 ) { … … 562 560 } // pthread_key_delete 563 561 564 int pthread_setspecific( pthread_key_t key, const void * value ) libcfa_public __THROW {562 int pthread_setspecific( pthread_key_t key, const void * value ) libcfa_public __THROW { 565 563 // get current thread 566 cfaPthread * t = lookup(pthread_self());564 cfaPthread * t = lookup(pthread_self()); 567 565 // if current thread's pthreadData is NULL; initialize it 568 pthread_values * values;569 if (t->pthreadData == NULL) {566 pthread_values * values; 567 if (t->pthreadData == NULL) { 570 568 values = anew( PTHREAD_KEYS_MAX); 571 569 t->pthreadData = values; 572 for ( int i = 0;i < PTHREAD_KEYS_MAX; i++){570 for ( int i = 0;i < PTHREAD_KEYS_MAX; i++ ) { 573 571 t->pthreadData[i].in_use = false; 574 572 } // for … … 593 591 } //pthread_setspecific 594 592 595 void * pthread_getspecific(pthread_key_t key) libcfa_public __THROW {593 void * pthread_getspecific(pthread_key_t key) libcfa_public __THROW { 596 594 if (key >= PTHREAD_KEYS_MAX || ! cfa_pthread_keys[key].in_use) return NULL; 597 595 598 596 // get current thread 599 cfaPthread * t = lookup(pthread_self());597 cfaPthread * t = lookup(pthread_self()); 600 598 if (t->pthreadData == NULL) return NULL; 601 599 lock(key_lock); 602 pthread_values & entry = ((pthread_values *)t->pthreadData)[key];600 pthread_values & entry = ((pthread_values *)t->pthreadData)[key]; 603 601 if ( ! entry.in_use ) { 604 602 unlock( key_lock ); 605 603 return NULL; 606 604 } // if 607 void * value = entry.value;605 void * value = entry.value; 608 606 unlock(key_lock); 609 607 … … 875 873 //######################### Parallelism ######################### 876 874 877 int pthread_setaffinity_np( pthread_t /* __th */, size_t /* __cpusetsize */, __const cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {878 abort( "pthread_setaffinity_np" );879 } // pthread_setaffinity_np880 881 int pthread_getaffinity_np( pthread_t /* __th */, size_t /* __cpusetsize */, cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {882 abort( "pthread_getaffinity_np" );883 } // pthread_getaffinity_np884 885 int pthread_attr_setaffinity_np( pthread_attr_t * /* __attr */, size_t /* __cpusetsize */, __const cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {886 abort( "pthread_attr_setaffinity_np" );887 } // pthread_attr_setaffinity_np888 889 int pthread_attr_getaffinity_np( __const pthread_attr_t * /* __attr */, size_t /* __cpusetsize */, cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {890 abort( "pthread_attr_getaffinity_np" );891 } // pthread_attr_getaffinity_np875 // int pthread_setaffinity_np( pthread_t /* __th */, size_t /* __cpusetsize */, __const cpu_set_t * /* __cpuset */ ) libcfa_public __THROW { 876 // abort( "pthread_setaffinity_np" ); 877 // } // pthread_setaffinity_np 878 879 // int pthread_getaffinity_np( pthread_t /* __th */, size_t /* __cpusetsize */, cpu_set_t * /* __cpuset */ ) libcfa_public __THROW { 880 // abort( "pthread_getaffinity_np" ); 881 // } // pthread_getaffinity_np 882 883 // int pthread_attr_setaffinity_np( pthread_attr_t * /* __attr */, size_t /* __cpusetsize */, __const cpu_set_t * /* __cpuset */ ) libcfa_public __THROW { 884 // abort( "pthread_attr_setaffinity_np" ); 885 // } // pthread_attr_setaffinity_np 886 887 // int pthread_attr_getaffinity_np( __const pthread_attr_t * /* __attr */, size_t /* __cpusetsize */, cpu_set_t * /* __cpuset */ ) libcfa_public __THROW { 888 // abort( "pthread_attr_getaffinity_np" ); 889 // } // pthread_attr_getaffinity_np 892 890 893 891 //######################### Cancellation ######################### … … 906 904 } // pthread_cancel 907 905 908 int pthread_setcancelstate( int state, int * oldstate ) libcfa_public __THROW {906 int pthread_setcancelstate( int state, int * oldstate ) libcfa_public __THROW { 909 907 abort("pthread_setcancelstate not implemented"); 910 908 return 0; 911 909 } // pthread_setcancelstate 912 910 913 int pthread_setcanceltype( int type, int * oldtype ) libcfa_public __THROW {911 int pthread_setcanceltype( int type, int * oldtype ) libcfa_public __THROW { 914 912 abort("pthread_setcanceltype not implemented"); 915 913 return 0; … … 918 916 919 917 #pragma GCC diagnostic pop 920 -
libcfa/src/concurrency/ready_queue.cfa
r2ed94a9 rb110bcc 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 // #define __CFA_DEBUG_PRINT_READY_QUEUE__ -
libcfa/src/concurrency/select.hfa
r2ed94a9 rb110bcc 1 #pragma once 2 1 3 #include "containers/list.hfa" 2 4 #include <stdint.h> -
libcfa/src/concurrency/thread.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Tue Jan 17 12:27:26 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Dec 11 20:56:54 202213 // Update Count : 10 212 // Last Modified On : Mon Jan 9 08:42:33 2023 13 // Update Count : 103 14 14 // 15 15 16 16 #define __cforall_thread__ 17 #define _GNU_SOURCE18 17 19 18 #include "thread.hfa" -
libcfa/src/containers/array.hfa
r2ed94a9 rb110bcc 9 9 10 10 11 // 12 // Single-dim array sruct (with explicit packing and atom) 13 // 14 11 // 12 // The `array` macro is the public interface. 13 // It computes the type of a dense (trivially strided) array. 14 // All user-declared objects are dense arrays. 15 // 16 // The `arpk` (ARray with PacKing info explicit) type is, generally, a slice with _any_ striding. 17 // This type is meant for internal use. 18 // CFA programmers should not instantiate it directly, nor access its field. 19 // CFA programmers should call ?[?] on it. 20 // Yet user-given `array(stuff)` expands to `arpk(stuff')`. 21 // The comments here explain the resulting internals. 22 // 23 // Just as a plain-C "multidimesional" array is really array-of-array-of-..., 24 // so does arpk generally show up as arpk-of-arpk-of... 25 // 26 // In the example of `array(float, 3, 4, 5) a;`, 27 // `typeof(a)` is an `arpk` instantiation. 28 // These comments explain _its_ arguments, i.e. those of the topmost `arpk` level. 29 // 30 // [N] : the number of elements in `a`; 3 in the example 31 // S : carries the stride size (distance in bytes between &myA[0] and &myA[1]), in sizeof(S); 32 // same as Timmed when striding is trivial, same as Timmed in the example 33 // Timmed : (T-immediate) the inner type; conceptually, `typeof(a)` is "arpk of Timmed"; 34 // array(float, 4, 5) in the example 35 // Tbase : (T-base) the deepest element type that is not arpk; float in the example 36 // 15 37 forall( [N], S & | sized(S), Timmed &, Tbase & ) { 38 39 // 40 // Single-dim array sruct (with explicit packing and atom) 41 // 16 42 struct arpk { 17 43 S strides[N]; -
libcfa/src/containers/list.hfa
r2ed94a9 rb110bcc 32 32 static inline tytagref(void, T) ?`inner ( T & this ) { tytagref( void, T ) ret = {this}; return ret; } 33 33 34 // use this on every case of plan-9 inheritance, to make embedded a closure of plan-9 inheritance 35 #define P9_EMBEDDED( derived, immedBase ) \ 36 forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \ 37 static inline tytagref(immedBase, Tbase) ?`inner( derived & this ) { \ 34 35 // 36 // P9_EMBEDDED: Use on every case of plan-9 inheritance, to make "implements embedded" be a closure of plan-9 inheritance. 37 // 38 // struct foo { 39 // int a, b, c; 40 // inline (bar); 41 // }; 42 // P9_EMBEDDED( foo, bar ) 43 // 44 45 // usual version, for structs that are top-level declarations 46 #define P9_EMBEDDED( derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase, static ) P9_EMBEDDED_BDY_( immedBase ) 47 48 // special version, for structs that are declared in functions 49 #define P9_EMBEDDED_INFUNC( derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase, ) P9_EMBEDDED_BDY_( immedBase ) 50 51 // forward declarations of both the above; generally not needed 52 // may help you control where the P9_EMBEEDED cruft goes, in case "right after the stuct" isn't where you want it 53 #define P9_EMBEDDED_FWD( derived, immedBase ) P9_EMBEDDED_DECL_( derived, immedBase, static ) ; 54 #define P9_EMBEDDED_FWD_INFUNC( derived, immedBase ) auto P9_EMBEDDED_DECL_( derived, immedBase, ) ; 55 56 // private helpers 57 #define P9_EMBEDDED_DECL_( derived, immedBase, STORAGE ) \ 58 forall( Tbase &, TdiscardPath & | { tytagref( TdiscardPath, Tbase ) ?`inner( immedBase & ); } ) \ 59 STORAGE inline tytagref(immedBase, Tbase) ?`inner( derived & this ) 60 61 #define P9_EMBEDDED_BDY_( immedBase ) { \ 38 62 immedBase & ib = this; \ 39 63 Tbase & b = ib`inner; \ -
libcfa/src/containers/vector2.hfa
r2ed94a9 rb110bcc 9 9 // Author : Michael Brooks 10 10 // Created On : Thu Jun 23 22:00:00 2021 11 // Last Modified By : Michael Brooks 12 // Last Modified On : Thu Jun 23 22:00:00 2021 13 // Update Count : 1 14 // 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Mar 14 08:40:53 2023 13 // Update Count : 2 14 // 15 16 #pragma once 15 17 16 18 #include <stdlib.hfa> -
libcfa/src/interpose.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Wed Mar 29 16:10:31 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jan 5 22:23:57 2023 13 // Update Count : 180 14 // 15 16 #include <stdarg.h> // va_start, va_end 12 // Last Modified On : Mon Mar 27 21:09:03 2023 13 // Update Count : 196 14 // 15 17 16 #include <stdio.h> 18 #include <string.h> // strlen19 17 #include <unistd.h> // _exit, getpid 20 #include <signal.h>21 18 extern "C" { 22 19 #include <dlfcn.h> // dlopen, dlsym … … 24 21 } 25 22 26 #include "bits/debug.hfa"27 23 #include "bits/defs.hfa" 28 24 #include "bits/signal.hfa" // sigHandler_? … … 40 36 41 37 typedef void (* generic_fptr_t)(void); 38 42 39 static generic_fptr_t do_interpose_symbol( void * library, const char symbol[], const char version[] ) { 43 const char * error;44 45 40 union { generic_fptr_t fptr; void * ptr; } originalFunc; 46 41 47 42 #if defined( _GNU_SOURCE ) 48 if ( version ) {49 originalFunc.ptr = dlvsym( library, symbol, version );50 } else {51 originalFunc.ptr = dlsym( library, symbol );52 }43 if ( version ) { 44 originalFunc.ptr = dlvsym( library, symbol, version ); 45 } else { 46 originalFunc.ptr = dlsym( library, symbol ); 47 } // if 53 48 #else 54 originalFunc.ptr = dlsym( library, symbol );49 originalFunc.ptr = dlsym( library, symbol ); 55 50 #endif // _GNU_SOURCE 56 51 57 error = dlerror();58 if ( error ) abort( "interpose_symbol : internal error, %s\n", error);59 52 if ( ! originalFunc.ptr ) { // == nullptr 53 abort( "interpose_symbol : internal error, %s\n", dlerror() ); 54 } // if 60 55 return originalFunc.fptr; 61 56 } 62 57 63 58 static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) { 64 const char * error; 65 66 static void * library; 67 static void * pthread_library; 68 if ( ! library ) { 69 #if defined( RTLD_NEXT ) 70 library = RTLD_NEXT; 71 #else 72 // missing RTLD_NEXT => must hard-code library name, assuming libstdc++ 73 library = dlopen( "libc.so.6", RTLD_LAZY ); 74 error = dlerror(); 75 if ( error ) { 76 abort( "interpose_symbol : failed to open libc, %s\n", error ); 77 } 78 #endif 59 void * library; 60 61 #if defined( RTLD_NEXT ) 62 library = RTLD_NEXT; 63 #else 64 // missing RTLD_NEXT => must hard-code library name, assuming libstdc++ 65 library = dlopen( "libc.so.6", RTLD_LAZY ); 66 if ( ! library ) { // == nullptr 67 abort( "interpose_symbol : failed to open libc, %s\n", dlerror() ); 79 68 } // if 80 if ( ! pthread_library ) { 81 #if defined( RTLD_NEXT ) 82 pthread_library = RTLD_NEXT; 83 #else 84 // missing RTLD_NEXT => must hard-code library name, assuming libstdc++ 85 pthread_library = dlopen( "libpthread.so", RTLD_LAZY ); 86 error = dlerror(); 87 if ( error ) { 88 abort( "interpose_symbol : failed to open libpthread, %s\n", error ); 89 } 90 #endif 91 } // if 92 93 return do_interpose_symbol(library, symbol, version); 69 #endif // RTLD_NEXT 70 71 return do_interpose_symbol( library, symbol, version ); 94 72 } 95 73 … … 121 99 preload_libgcc(); 122 100 123 #pragma GCC diagnostic push124 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"101 #pragma GCC diagnostic push 102 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" 125 103 INTERPOSE_LIBC( abort, version ); 126 104 INTERPOSE_LIBC( exit , version ); 127 #pragma GCC diagnostic pop105 #pragma GCC diagnostic pop 128 106 129 107 if(__cfathreadabi_interpose_startup) __cfathreadabi_interpose_startup( do_interpose_symbol ); 108 109 // SKULLDUGGERY: In Ubuntu 22.04, someone augmented signal.h to allow SIGSTKSZ to be "sysconf(_SC_SIGSTKSZ)" in 110 // sigstksz.h, as well as 8192 in sigstack.h. HOWEVER, they forgot to provide a mechanism to tell signal.h to 111 // use sigstack.h rather than sigstksz.h. (I'm not happy.) By undefining _GNU_SOURCE before signal.h and 112 // redefining it afterwards, you can get 8192, but then nothing works correctly inside of signal.h without 113 // _GNU_SOURCE defined. So what is needed is a way to get signal.h to use sigstack.h WITH _GNU_SOURCE defined. 114 // Basically something is wrong with features.h and its use in signal.h. 115 116 #undef SIGSTKSZ 117 #define SIGSTKSZ 8192 130 118 131 119 // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because … … 293 281 va_start( args, fmt ); 294 282 __abort( false, fmt, args ); 295 // CONTROL NEVER REACHES HERE!283 // CONTROL NEVER REACHES HERE! 296 284 va_end( args ); 297 285 } 298 286 299 287 void abort( bool signalAbort, const char fmt[], ... ) { 300 va_list args;301 va_start( args, fmt );302 __abort( signalAbort, fmt, args );303 // CONTROL NEVER REACHES HERE!304 va_end( args );288 va_list args; 289 va_start( args, fmt ); 290 __abort( signalAbort, fmt, args ); 291 // CONTROL NEVER REACHES HERE! 292 va_end( args ); 305 293 } 306 294 -
libcfa/src/interpose_thread.cfa
r2ed94a9 rb110bcc 14 14 // 15 15 16 #include <stdarg.h> // va_start, va_end 17 #include <stdio.h> 18 #include <string.h> // strlen 16 // BUG in 32-bit gcc with interpose: fixed in >= gcc-9.5, gcc-10.4, gcc-12.2 17 #ifdef __i386__ // 32-bit architecture 18 #undef _GNU_SOURCE 19 #endif // __i386__ 20 19 21 #include <signal.h> 20 22 #include <pthread.h> 23 #include <signal.h> 21 24 extern "C" { 22 25 #include <dlfcn.h> // dlopen, dlsym 23 #include <execinfo.h> // backtrace, messages24 26 } 25 27 26 #include "bits/debug.hfa"27 28 #include "bits/defs.hfa" 28 #include <assert.h>29 29 30 30 //============================================================================================= … … 34 34 typedef void (* generic_fptr_t)(void); 35 35 36 generic_fptr_t interpose_symbol(36 generic_fptr_t libcfa_public interpose_symbol( 37 37 generic_fptr_t (*do_interpose_symbol)( void * library, const char symbol[], const char version[] ), 38 38 const char symbol[], 39 39 const char version[] 40 ) libcfa_public{41 const char * error;40 ) { 41 void * library; 42 42 43 static void * library; 44 if ( ! library ) { 45 #if defined( RTLD_NEXT ) 46 library = RTLD_NEXT; 47 #else 48 // missing RTLD_NEXT => must hard-code library name, assuming libstdc++ 49 library = dlopen( "libpthread.so", RTLD_LAZY ); 50 error = dlerror(); 51 if ( error ) { 52 abort( "interpose_symbol : failed to open libpthread, %s\n", error ); 53 } 54 #endif 43 #if defined( RTLD_NEXT ) 44 library = RTLD_NEXT; 45 #else 46 // missing RTLD_NEXT => must hard-code library name, assuming libstdc++ 47 library = dlopen( "libpthread.so", RTLD_LAZY ); 48 if ( ! library ) { // == nullptr 49 abort( "interpose_symbol : failed to open libpthread, %s\n", dlerror() ); 55 50 } // if 51 #endif // RTLD_NEXT 56 52 57 return do_interpose_symbol( library, symbol, version);53 return do_interpose_symbol( library, symbol, version ); 58 54 } 59 55 … … 83 79 #pragma GCC diagnostic push 84 80 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" 85 INTERPOSE( pthread_create , version );86 INTERPOSE( pthread_join , version );87 INTERPOSE( pthread_self , version );88 INTERPOSE( pthread_attr_init , version );89 INTERPOSE( pthread_attr_destroy , version );90 INTERPOSE( pthread_attr_setstack , version );91 INTERPOSE( pthread_attr_getstacksize , version );92 INTERPOSE( pthread_sigmask , version );93 INTERPOSE( pthread_sigqueue , version );94 INTERPOSE( pthread_once , version );81 INTERPOSE( pthread_create, version ); 82 INTERPOSE( pthread_join, version ); 83 INTERPOSE( pthread_self, version ); 84 INTERPOSE( pthread_attr_init, version ); 85 INTERPOSE( pthread_attr_destroy, version ); 86 INTERPOSE( pthread_attr_setstack, version ); 87 INTERPOSE( pthread_attr_getstacksize, version ); 88 INTERPOSE( pthread_sigmask, version ); 89 INTERPOSE( pthread_sigqueue, version ); 90 INTERPOSE( pthread_once, version ); 95 91 #pragma GCC diagnostic pop 96 92 } -
libcfa/src/iostream.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Aug 27 15:04:15 202213 // Update Count : 13 5812 // Last Modified On : Mon Jan 9 09:27:58 2023 13 // Update Count : 1361 14 14 // 15 15 … … 667 667 } /* if */ \ 668 668 if ( ! f.flags.nobsdp || (exp10 < SUFFIXES_START) || (exp10 > SUFFIXES_END) ) { \ 669 len2 = snprintf( &buf[len], size - len, "e%d", exp10); \669 len2 = snprintf( &buf[len], size - len, "e%d", (int)exp10 /* ambiguity with function exp10 */ ); \ 670 670 } else { \ 671 671 len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \ -
libcfa/src/limits.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Wed Apr 6 18:06:52 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jan 5 22:27:40202313 // Update Count : 8 412 // Last Modified On : Fri Feb 17 12:25:39 2023 13 // Update Count : 87 14 14 // 15 15 16 #define _GNU_SOURCE // access long double M_*l in math.h17 16 #include <limits.h> 18 17 #include <float.h> -
libcfa/src/stdlib.cfa
r2ed94a9 rb110bcc 10 10 // Created On : Thu Jan 28 17:10:29 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 9 15:11:30 202213 // Update Count : 63 112 // Last Modified On : Thu Feb 16 16:31:34 2023 13 // Update Count : 633 14 14 // 15 15 … … 20 20 //--------------------------------------- 21 21 22 #define _XOPEN_SOURCE 600 // posix_memalign, *rand4823 22 #include <string.h> // memcpy, memset 24 23 //#include <math.h> // fabsf, fabs, fabsl -
libcfa/src/vec/vec.hfa
r2ed94a9 rb110bcc 18 18 #include <math.hfa> 19 19 20 trait fromint(T) { 20 forall(T) 21 trait fromint { 21 22 void ?{}(T&, int); 22 23 }; 23 trait zeroinit(T) { 24 forall(T) 25 trait zeroinit { 24 26 void ?{}(T&, zero_t); 25 27 }; 26 trait zero_assign(T) { 28 forall(T) 29 trait zero_assign { 27 30 T ?=?(T&, zero_t); 28 31 }; 29 trait subtract(T) { 32 forall(T) 33 trait subtract { 30 34 T ?-?(T, T); 31 35 }; 32 trait negate(T) { 36 forall(T) 37 trait negate { 33 38 T -?(T); 34 39 }; 35 trait add(T) { 40 forall(T) 41 trait add { 36 42 T ?+?(T, T); 37 43 }; 38 trait multiply(T) { 44 forall(T) 45 trait multiply { 39 46 T ?*?(T, T); 40 47 }; 41 trait divide(T) { 48 forall(T) 49 trait divide { 42 50 T ?/?(T, T); 43 51 }; 44 trait lessthan(T) { 52 forall(T) 53 trait lessthan { 45 54 int ?<?(T, T); 46 55 }; 47 trait equality(T) { 56 forall(T) 57 trait equality { 48 58 int ?==?(T, T); 49 59 }; 50 trait sqrt(T) { 60 forall(T) 61 trait sqrt { 51 62 T sqrt(T); 52 63 };
Note:
See TracChangeset
for help on using the changeset viewer.