Changeset b110bcc for libcfa


Ignore:
Timestamp:
Apr 21, 2023, 5:36:12 PM (3 years ago)
Author:
JiadaL <j82liang@…>
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.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
libcfa/src
Files:
1 added
39 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/Makefile.am

    r2ed94a9 rb110bcc  
    4848        math.hfa \
    4949        time_t.hfa \
     50        virtual_dtor.hfa \
    5051        bits/algorithm.hfa \
    5152        bits/align.hfa \
  • libcfa/src/algorithms/range_iterator.hfa

    r2ed94a9 rb110bcc  
    99// Author           : Thierry Delisle
    1010// 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
    1414//
     15
     16#pragma once
    1517
    1618generator RangeIter {
  • libcfa/src/bitmanip.hfa

    r2ed94a9 rb110bcc  
    1111// Created On       : Sat Mar 14 18:12:27 2020
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Sat Oct  8 08:28:15 2022
    14 // Update Count     : 142
     13// Last Modified On : Mon Jan  9 09:02:43 2023
     14// Update Count     : 144
    1515//
    1616
    1717#pragma once
     18
     19#include "bits/debug.hfa"                                                               // verify
    1820
    1921// Reference: Bit Twiddling Hacks: http://graphics.stanford.edu/%7Eseander/bithacks.html#CountBitsSetNaive
  • libcfa/src/bits/random.hfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Fri Jan 14 07:18:11 2022
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Dec 22 20:54:22 2022
    13 // Update Count     : 178
     12// Last Modified On : Mon Mar 20 21:45:24 2023
     13// Update Count     : 186
    1414//
    1515
     
    2828        #define XOSHIRO256PP
    2929        //#define KISS_64
     30    // #define SPLITMIX_64
    3031
    3132        // 32-bit generators
    3233        //#define XORSHIFT_6_21_7
    3334        #define XOSHIRO128PP
     35    // #define SPLITMIX_32
    3436#else                                                                                                   // 32-bit architecture
    3537        // 64-bit generators
    3638        //#define XORSHIFT_13_7_17
    3739        #define XOSHIRO256PP
     40    // #define SPLITMIX_64
    3841
    3942        // 32-bit generators
    4043        //#define XORSHIFT_6_21_7
    4144        #define XOSHIRO128PP
     45    // #define SPLITMIX_32
    4246#endif // __x86_64__
    4347
    4448// 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.
    4749
    4850#ifdef XOSHIRO256PP
    4951#define PRNG_NAME_64 xoshiro256pp
    5052#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;
     53typedef struct { uint64_t s0, s1, s2, s3; } PRNG_STATE_64_T;
    5254#endif // XOSHIRO256PP
    5355
     
    5557#define PRNG_NAME_32 xoshiro128pp
    5658#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;
     59typedef struct { uint32_t s0, s1, s2, s3; } PRNG_STATE_32_T;
    5860#endif // XOSHIRO128PP
    5961
     
    8385#endif // XORSHIFT_12_25_27
    8486
     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
    8597#ifdef KISS_64
    8698#define PRNG_NAME_64 kiss_64
    8799#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;
     100typedef struct { uint64_t z, w, jsr, jcong; } PRNG_STATE_64_T;
    89101#endif // KISS_^64
    90102
     
    92104#define PRNG_NAME_32 xorwow
    93105#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;
     106typedef struct { uint32_t a, b, c, d, counter; } PRNG_STATE_32_T;
    95107#endif // XOSHIRO128PP
    96108
     
    119131#ifdef __cforall                                                                                // don't include in C code (invoke.h)
    120132
     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.
     138static 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
     146static 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
     156static 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
     164static 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//--------------------------------------------------
     171static 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
     177static 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//--------------------------------------------------
     183static 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
     194static 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
    121199// https://prng.di.unimi.it/xoshiro256starstar.c
    122200//
     
    130208
    131209#ifndef XOSHIRO256PP
    132 typedef struct xoshiro256pp_t { uint64_t s0, s1, s2, s3; } xoshiro256pp_t;
     210typedef struct { uint64_t s0, s1, s2, s3; } xoshiro256pp_t;
    133211#endif // ! XOSHIRO256PP
    134212
     
    151229
    152230static 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 };
    155237} // xoshiro256pp_set_seed
    156238
     
    165247
    166248#ifndef XOSHIRO128PP
    167 typedef struct xoshiro128pp_t { uint32_t s0, s1, s2, s3; } xoshiro128pp_t;
     249typedef struct { uint32_t s0, s1, s2, s3; } xoshiro128pp_t;
    168250#endif // ! XOSHIRO128PP
    169251
     
    186268
    187269static 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 };
    190276} // 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         } // lehmer64
    199 
    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 );                                                              // prime
    204         } // lehmer64_set_seed
    205 
    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         } // wyhash64
    217 
    218         static inline void wyhash64_set_seed( uint64_t & state, uint64_t seed ) {
    219                 state = seed;
    220                 wyhash64( state );                                                              // prime
    221         } // wyhash64_set_seed
    222 #endif // __SIZEOF_INT128__
    223277
    224278//--------------------------------------------------
     
    232286
    233287static 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
    236289} // xorshift_13_7_17_set_seed
    237290
     
    250303
    251304static 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
    254306} // xorshift_6_21_7_set_seed
    255307
     
    265317
    266318static 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
    269320} // xorshift_12_25_27_set_seed
    270321
     
    272323// The state must be seeded with a nonzero value.
    273324#ifndef KISS_64
    274 typedef struct kiss_64_t { uint64_t z, w, jsr, jcong; } kiss_64_t;
     325typedef struct { uint64_t z, w, jsr, jcong; } kiss_64_t;
    275326#endif // ! KISS_64
    276327
     
    287338
    288339static 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
    291341} // kiss_64_set_seed
    292342
     
    294344// The state array must be initialized to non-zero in the first four words.
    295345#ifndef XORWOW
    296 typedef struct xorwow_t { uint32_t a, b, c, d, counter; } xorwow_t;
     346typedef struct { uint32_t a, b, c, d, counter; } xorwow_t;
    297347#endif // ! XORWOW
    298348
     
    316366
    317367static 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 };
    320374} // xorwow_set_seed
    321375
     
    323377// Used in __tls_rand_fwd
    324378#define M  (1_l64u << 48_l64u)
    325 #define A  (25214903917_l64u)
    326 #define AI (18446708753438544741_l64u)
     379#define A  (25_214_903_917_l64u)
     380#define AI (18_446_708_753_438_544_741_l64u)
    327381#define C  (11_l64u)
    328382#define D  (16_l64u)
  • libcfa/src/concurrency/actor.hfa

    r2ed94a9 rb110bcc  
    33#include <locks.hfa>
    44#include <limits.hfa>
    5 #include <list.hfa>
    65#include <kernel.hfa>
     6#include <iofwd.hfa>
     7#include <virtual_dtor.hfa>
    78
    89#ifdef __CFA_DEBUG__
     
    2021// Define the default number of executor request-queues (mailboxes) written to by actors and serviced by the
    2122// actor-executor threads. Must be greater than 0.
    22 #define __DEFAULT_EXECUTOR_RQUEUES__ 2
     23#define __DEFAULT_EXECUTOR_RQUEUES__ 4
    2324
    2425// Define if executor is created in a separate cluster
    2526#define __DEFAULT_EXECUTOR_SEPCLUS__ false
    2627
    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
    2938
    3039// forward decls
    3140struct actor;
    3241struct message;
     42struct executor;
    3343
    3444enum Allocation { Nodelete, Delete, Destroy, Finished }; // allocation status
     
    4050    __receive_fn fn;
    4151    bool stop;
    42     inline dlink(request);
    4352};
    44 P9_EMBEDDED( request, dlink(request) )
    4553
    4654static inline void ?{}( request & this ) { this.stop = true; } // default ctor makes a sentinel
     
    5866}
    5967
    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)
    6170struct copy_queue {
    62     dlist( request ) list;
    63     #if ! __ALLOC
    6471    request * buffer;
    65     size_t count, buffer_size, index;
    66     #endif
     72    size_t count, buffer_size, index, utilized, last_size;
    6773};
    6874static inline void ?{}( copy_queue & this ) {}
    6975static inline void ?{}( copy_queue & this, size_t buf_size ) with(this) {
    70     list{};
    71     #if ! __ALLOC
    7276    buffer_size = buf_size;
    7377    buffer = aalloc( buffer_size );
    7478    count = 0;
     79    utilized = 0;
    7580    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}
     83static inline void ^?{}( copy_queue & this ) with(this) { adelete(buffer); }
    8384
    8485static 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++;
    9794}
    9895
    9996// 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
     98static inline request & remove( copy_queue & this ) with(this) {
    10499    if ( count > 0 ) {
    105100        count--;
    106         should_delete = false;
    107101        size_t old_idx = index;
    108102        index = count == 0 ? 0 : index + 1;
    109103        return buffer[old_idx];
    110104    }
    111     #endif
    112     should_delete = true;
    113     return try_pop_front( list );
    114 }
    115 
    116 static inline bool isEmpty( copy_queue & this ) with(this) {
    117     #if ! __ALLOC
    118     return count == 0 && list`isEmpty;
    119     #else
    120     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
     110static 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
     117static inline bool isEmpty( copy_queue & this ) with(this) { return count == 0; }
     118
    125119struct work_queue {
    126120    __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
    130128}; // 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 ); }
     129static 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
     141static inline void ^?{}( work_queue & this ) with(this) { delete( owned_queue ); }
    138142
    139143static inline void insert( work_queue & this, request & elem ) with(this) {
     
    145149static inline void transfer( work_queue & this, copy_queue ** transfer_to ) with(this) {
    146150    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
    147167    // swap copy queue ptrs
    148168    copy_queue * temp = *transfer_to;
     
    152172} // transfer
    153173
     174// needed since some info needs to persist past worker lifetimes
     175struct 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};
     183static 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
    154200thread worker {
    155     copy_queue owned_queue;
    156     work_queue * request_queues;
     201    work_queue ** request_queues;
    157202    copy_queue * current_queue;
    158         request & req;
     203    executor * executor_;
    159204    unsigned int start, range;
     205    int id;
    160206};
    161207
    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
     210size_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
     213static 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 ) {
    163215    ((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
     224static bool no_steal = false;
    174225struct executor {
    175226    cluster * cluster;                                                      // if workers execute on separate cluster
    176227        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
    179233        unsigned int nprocessors, nworkers, nrqueues;   // number of processors/threads/request queues
    180234        bool seperate_clus;                                                             // use same or separate cluster for executor
    181235}; // executor
    182236
     237// #ifdef ACTOR_STATS
     238// __spinlock_t out_lock;
     239// #endif
     240static 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
    183268static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues, bool seperate_clus, size_t buf_size ) with(this) {
    184269    if ( nrqueues < nworkers ) abort( "nrqueues needs to be >= nworkers\n" );
    185     __buffer_size = buf_size;
    186270    this.nprocessors = nprocessors;
    187271    this.nworkers = nworkers;
     
    189273    this.seperate_clus = seperate_clus;
    190274
     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
    191284    if ( seperate_clus ) {
    192285        cluster = alloc();
     
    195288
    196289    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    }
    199295   
    200296    processors = aalloc( nprocessors );
     
    202298        (*(processors[i] = alloc())){ *cluster };
    203299
    204     workers = alloc( nworkers );
     300    local_queues = aalloc( nworkers );
     301    workers = aalloc( nworkers );
     302    w_infos = aalloc( nworkers );
    205303    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
    206310    for ( unsigned int i = 0, start = 0, range; i < nworkers; i += 1, start += range ) {
    207311        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 };
    209313    } // for
    210314}
    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 }; }
     315static 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__ }; }
    212316static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers, unsigned int nrqueues ) { this{ nprocessors, nworkers, nrqueues, __DEFAULT_EXECUTOR_SEPCLUS__ }; }
    213317static inline void ?{}( executor & this, unsigned int nprocessors, unsigned int nworkers ) { this{ nprocessors, nworkers, __DEFAULT_EXECUTOR_RQUEUES__ }; }
     
    216320
    217321static 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
    218328    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 );
    221332        insert( request_queues[step], sentinels[i] );           // force eventually termination
    222333    } // for
     334    #endif
    223335
    224336    for ( i; nworkers )
     
    229341    } // for
    230342
     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
    231352    adelete( workers );
     353    adelete( w_infos );
     354    adelete( local_queues );
    232355    adelete( request_queues );
     356    adelete( worker_req_queues );
    233357    adelete( processors );
    234358    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       
    235371}
    236372
    237373// 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;
     374static size_t __next_ticket = 0;
     375
     376static 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
    242386} // tickets
    243387
    244 // C_TODO: update globals in this file to be static fields once the project is done
     388// TODO: update globals in this file to be static fields once the static fields project is done
    245389static executor * __actor_executor_ = 0p;
    246 static bool __actor_executor_passed = false;        // was an executor passed to start_actor_system
    247 static unsigned long int __num_actors_;                         // number of actor objects in system
     390static bool __actor_executor_passed = false;            // was an executor passed to start_actor_system
     391static size_t __num_actors_ = 0;                                        // number of actor objects in system
    248392static struct thread$ * __actor_executor_thd = 0p;              // used to wake executor after actors finish
    249393struct 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;
    252397};
    253398
    254 static inline void ?{}( actor & this ) {
     399static inline void ?{}( actor & this ) with(this) {
    255400    // Once an actor is allocated it must be sent a message or the actor system cannot stop. Hence, its receive
    256401    // 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}
    263410
    264411static inline void check_actor( actor & this ) {
     
    276423        }
    277424
    278         if ( unlikely( __atomic_add_fetch( &__num_actors_, -1, __ATOMIC_SEQ_CST ) == 0 ) ) { // all actors have terminated
     425        if ( unlikely( __atomic_add_fetch( &__num_actors_, -1, __ATOMIC_RELAXED ) == 0 ) ) { // all actors have terminated
    279426            unpark( __actor_executor_thd );
    280427        }
     
    284431struct message {
    285432    Allocation allocation_;                     // allocation action
     433    inline virtual_dtor;
    286434};
    287435
    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 ) {}
     436static inline void ?{}( message & this ) {
     437    this.allocation_ = Nodelete;
     438}
     439static 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}
     443static 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}
    291446
    292447static inline void check_message( message & this ) {
    293448    switch ( this.allocation_ ) {                                               // analyze message status
    294         case Nodelete: break;
     449        case Nodelete: CFA_DEBUG(this.allocation_ = Finished); break;
    295450        case Delete: delete( &this ); break;
    296451        case Destroy: ^?{}(this); break;
     
    298453    } // switch
    299454}
     455static inline void set_allocation( message & this, Allocation state ) {
     456    this.allocation_ = state;
     457}
    300458
    301459static 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 );
    304462    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
     467static 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
     491static 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
     537static 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
    306557}
    307558
    308559void 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
    310575    Exit:
    311576    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], &current_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, &current_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
    314609        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;
    317615            if ( req.stop ) break Exit;
    318616            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 );
    322625    } // for
    323626}
     
    328631
    329632static inline void send( actor & this, request & req ) {
     633    verifyf( this.ticket != (unsigned long int)MAX, "Attempted to send message to deleted/dead actor\n" );
    330634    send( *__actor_executor_, req, this.ticket );
    331635}
    332636
     637static 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
    333649static inline void start_actor_system( size_t num_thds ) {
     650    __reset_stats();
    334651    __actor_executor_thd = active_thread();
    335652    __actor_executor_ = alloc();
     
    337654}
    338655
    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 ); }
     660static inline void start_actor_system() { start_actor_system( 1 ); }
    340661
    341662static inline void start_actor_system( executor & this ) {
     663    __reset_stats();
    342664    __actor_executor_thd = active_thread();
    343665    __actor_executor_ = &this;
     
    354676    __actor_executor_passed = false;
    355677}
     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
     681message __base_msg_finished @= { .allocation_ : Finished };
     682struct __DeleteMsg { inline message; } DeleteMsg = __base_msg_finished;
     683struct __DestroyMsg { inline message; } DestroyMsg = __base_msg_finished;
     684struct __FinishedMsg { inline message; } FinishedMsg = __base_msg_finished;
     685
     686Allocation receive( actor & this, __DeleteMsg & msg ) { return Delete; }
     687Allocation receive( actor & this, __DestroyMsg & msg ) { return Destroy; }
     688Allocation receive( actor & this, __FinishedMsg & msg ) { return Finished; }
     689
  • libcfa/src/concurrency/channel.hfa

    r2ed94a9 rb110bcc  
     1#pragma once
     2
    13#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
     8struct 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;
    517};
    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 ) {}
     18P9_EMBEDDED( wait_link, dlink(wait_link) )
     19
     20static 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
     26static 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
     33static 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
     42exception 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};
     52vtable(channel_closed) channel_closed_vt;
     53
     54// #define CHAN_STATS // define this to get channel stats printed in dtor
    1655
    1756forall( T ) {
    18 struct channel {
    19     size_t size;
    20     size_t front, back, count;
     57
     58struct __attribute__((aligned(128))) channel {
     59    size_t size, front, back, count;
    2160    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
    2467};
    2568
     
    2770    size = _size;
    2871    front = back = count = 0;
    29     buffer = anew( size );
     72    buffer = aalloc( size );
    3073    prods{};
    3174    cons{};
    3275    mutex_lock{};
     76    closed = false;
     77    #ifdef CHAN_STATS
     78    blocks = 0;
     79    operations = 0;
     80    #endif
    3381}
    3482
    3583static inline void ?{}( channel(T) &c ){ ((channel(T) &)c){ 0 }; }
    36 static inline void ^?{}( channel(T) &c ) with(c) { delete( buffer ); }
     84static 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}
    3791static inline size_t get_count( channel(T) & chan ) with(chan) { return count; }
    3892static 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) {
     93static inline bool has_waiters( channel(T) & chan ) with(chan) { return !cons`isEmpty || !prods`isEmpty; }
     94static inline bool has_waiting_consumers( channel(T) & chan ) with(chan) { return !cons`isEmpty; }
     95static inline bool has_waiting_producers( channel(T) & chan ) with(chan) { return !prods`isEmpty; }
     96
     97// closes the channel and notifies all blocked threads
     98static 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
     114static inline void is_closed( channel(T) & chan ) with(chan) { return closed; }
     115
     116static 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
     126static inline void __buf_insert( channel(T) & chan, T & elem ) with(chan) {
    44127    memcpy((void *)&buffer[back], (void *)&elem, sizeof(T));
    45128    count += 1;
     
    48131}
    49132
     133// does the buffer insert or hands elem directly to consumer if one is waiting
     134static 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
     142static 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
     155static inline bool try_insert( channel(T) & chan, T elem ) { return __internal_try_insert( chan, elem ); }
     156
     157// handles closed case of insert routine
     158static 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}
    50163
    51164static 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    }
    53183
    54184    // 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 );
    58188        unlock( mutex_lock );
    59         return;
     189        return true;
    60190    }
    61191
    62192    // 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 );
    65201        return;
    66202    } // if
    67203
    68     if ( count == 0 && !empty( cons ) )
    69         // do waiting consumer work
    70         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 );
    72208   
    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
     214static inline void __buf_remove( channel(T) & chan, T & retval ) with(chan) {
    96215    memcpy((void *)&retval, (void *)&buffer[front], sizeof(T));
    97216    count -= 1;
    98217    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
     221static 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
     230static 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)
     244static inline [T, bool] try_remove( channel(T) & chan ) {
     245    T retval;
     246    return [ retval, __internal_try_remove( chan, retval ) ];
     247}
     248
     249static inline T try_remove( channel(T) & chan, T elem ) {
     250    T retval;
     251    __internal_try_remove( chan, retval );
    105252    return retval;
    106253}
    107254
     255// handles closed case of insert routine
     256static 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
     262static 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}
    108305} // forall( T )
  • libcfa/src/concurrency/clib/cfathread.cfa

    r2ed94a9 rb110bcc  
    1616// #define EPOLL_FOR_SOCKETS
    1717
     18#include <string.h>
     19
    1820#include "fstream.hfa"
    1921#include "locks.hfa"
     
    2325#include "time.hfa"
    2426#include "stdlib.hfa"
    25 
     27#include "iofwd.hfa"
    2628#include "cfathread.h"
    27 
    28 extern "C" {
    29                 #include <string.h>
    30                 #include <errno.h>
    31 }
    3229
    3330extern void ?{}(processor &, const char[], cluster &, thread$ *);
    3431extern "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);
    3733}
    3834
     
    472468}
    473469
    474 #include <iofwd.hfa>
    475 
    476470extern "C" {
    477         #include <unistd.h>
    478         #include <sys/types.h>
    479         #include <sys/socket.h>
    480 
    481471        //--------------------
    482472        // IO operations
     
    488478                , protocol);
    489479        }
    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) {
    491481                return bind(socket, address, address_len);
    492482        }
     
    496486        }
    497487
    498         int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) {
     488        int cfathread_accept(int socket, __SOCKADDR_ARG address, socklen_t *restrict address_len) {
    499489                #if defined(EPOLL_FOR_SOCKETS)
    500490                        int ret;
     
    513503        }
    514504
    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) {
    516506                #if defined(EPOLL_FOR_SOCKETS)
    517507                        int ret;
  • libcfa/src/concurrency/clib/cfathread.h

    r2ed94a9 rb110bcc  
    99// Author           : Thierry Delisle
    1010// 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
    1414//
    1515
     16#pragma once
     17
    1618#if defined(__cforall) || defined(__cplusplus)
     19#include <unistd.h>
     20#include <errno.h>
     21#include <sys/socket.h>
     22
    1723extern "C" {
    1824#endif
    19         #include <asm/types.h>
    20         #include <errno.h>
    21         #include <unistd.h>
    22 
    23 
    2425        //--------------------
    2526        // Basic types
     
    7374        } cfathread_mutexattr_t;
    7475        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)));
    7677        int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
    7778        int cfathread_mutex_lock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
     
    9192        //--------------------
    9293        // IO operations
    93         struct sockaddr;
    94         struct msghdr;
    9594        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);
    9796        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);
    10099        int cfathread_dup(int fildes);
    101100        int cfathread_close(int fildes);
  • libcfa/src/concurrency/coroutine.cfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec 15 12:06:04 2020
    13 // Update Count     : 23
     12// Last Modified On : Thu Feb 16 15:34:46 2023
     13// Update Count     : 24
    1414//
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#include "coroutine.hfa"
  • libcfa/src/concurrency/future.hfa

    r2ed94a9 rb110bcc  
    1414//
    1515
    16 // #pragma once
     16#pragma once
    1717
    1818#include "bits/locks.hfa"
  • libcfa/src/concurrency/invoke.h

    r2ed94a9 rb110bcc  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// 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.
    1517
    1618#include "bits/containers.hfa"
  • libcfa/src/concurrency/io.cfa

    r2ed94a9 rb110bcc  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#if defined(__CFA_DEBUG__)
     
    296295                                // make sure the target hasn't stopped existing since last time
    297296                                HELP: if(target < ctxs_count) {
    298                                         // calculate it's age and how young it could be before we give ip on helping
     297                                        // calculate it's age and how young it could be before we give up on helping
    299298                                        const __readyQ_avg_t cutoff = calc_cutoff(ctsc, ctx->cq.id, ctxs_count, io.data, io.tscs, __shard_factor.io, false);
    300299                                        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  
    3131Prelude = """#define __cforall_thread__
    3232
     33#include <unistd.h>
     34#include <errno.h>
     35#include <sys/socket.h>
     36#include <time.hfa>
     37
    3338#include "bits/defs.hfa"
    3439#include "kernel.hfa"
     
    4348        #include <assert.h>
    4449        #include <stdint.h>
    45         #include <errno.h>
    4650        #include <linux/io_uring.h>
    47 
    4851        #include "kernel/fwd.hfa"
    4952
     
    8285// I/O Forwards
    8386//=============================================================================================
    84 #include <time.hfa>
    85 
    86 // Some forward declarations
    87 #include <errno.h>
    88 #include <unistd.h>
    8987
    9088extern "C" {
    91         #include <asm/types.h>
    92         #include <sys/socket.h>
    93         #include <sys/syscall.h>
    94 
    9589#if defined(CFA_HAVE_PREADV2)
    9690        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);
    9892#endif
    9993#if defined(CFA_HAVE_PWRITEV2)
    10094        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);
    10296#endif
    10397
     
    114108        struct msghdr;
    115109        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);
    122114
    123115        extern int fallocate(int fd, int mode, off_t offset, off_t len);
    124116        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);
    128120        extern int close(int fd);
    129121
    130         extern ssize_t read (int fd, void *buf, size_t count);
     122        extern ssize_t read (int fd, void * buf, size_t count);
    131123
    132124        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);
    136128        extern ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);
    137129}
     
    232224calls = [
    233225        # 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)', {
    235227                'fd'  : 'fd',
     228                'addr': '(typeof(sqe->addr))iov',
     229                'len' : 'iovcnt',
    236230                'off' : 'offset',
    237                 'addr': '(uintptr_t)iov',
    238                 'len' : 'iovcnt',
     231                'rw_flags' : 'flags'
    239232        }, define = 'CFA_HAVE_PREADV2'),
    240233        # 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)', {
    242235                'fd'  : 'fd',
     236                'addr': '(typeof(sqe->addr))iov',
     237                'len' : 'iovcnt',
    243238                'off' : 'offset',
    244                 'addr': '(uintptr_t)iov',
    245                 'len' : 'iovcnt'
     239                'rw_flags' : 'flags'
    246240        }, define = 'CFA_HAVE_PWRITEV2'),
    247241        # CFA_HAVE_IORING_OP_FSYNC
     
    250244        }),
    251245        # 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)', {
    253247                'fd': 'epfd',
     248                'len': 'op',
    254249                'addr': 'fd',
    255                 'len': 'op',
    256                 'off': '(uintptr_t)event'
     250                'off': '(typeof(sqe->off))event'
    257251        }),
    258252        # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE
     
    264258        }),
    265259        # 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',
    269263                'len': '1',
    270264                'msg_flags': 'flags'
    271265        }),
    272266        # 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',
    276270                'len': '1',
    277271                'msg_flags': 'flags'
    278272        }),
    279273        # 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',
    283277                'len': 'len',
    284278                'msg_flags': 'flags'
    285279        }),
    286280        # 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',
    290284                'len': 'len',
    291285                'msg_flags': 'flags'
    292286        }),
    293287        # 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',
    298292                'accept_flags': 'flags'
    299293        }),
    300294        # 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',
    304298                'off': 'addrlen'
    305299        }),
     
    307301        Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', {
    308302                'fd': 'fd',
    309                 'addr': '(uintptr_t)len',
    310303                'len': 'mode',
    311                 'off': 'offset'
     304                'off': 'offset',
     305                'addr': 'len'
    312306        }),
    313307        # CFA_HAVE_IORING_OP_FADVISE
     
    319313        }),
    320314        # 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',
    323317                'len': 'length',
    324318                'fadvise_advice': 'advice'
    325319        }),
    326320        # 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)', {
    328322                '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'
    332326        }),
    333327        # 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)', {
    335329                '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)'
    339333        }, define = 'CFA_HAVE_OPENAT2'),
    340334        # CFA_HAVE_IORING_OP_CLOSE
     
    343337        }),
    344338        # 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)', {
    346340                'fd': 'dirfd',
    347                 'off': '(uintptr_t)statxbuf',
    348                 'addr': 'pathname',
     341                'addr': '(typeof(sqe->addr))pathname',
     342                'statx_flags': 'flags',
    349343                'len': 'mask',
    350                 'statx_flags': 'flags'
     344                'off': '(typeof(sqe->off))statxbuf'
    351345        }, define = 'CFA_HAVE_STATX'),
    352346        # CFA_HAVE_IORING_OP_READ
    353347        Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', {
    354348                'fd': 'fd',
    355                 'addr': '(uintptr_t)buf',
     349                'addr': '(typeof(sqe->addr))buf',
    356350                'len': 'count'
    357351        }),
     
    359353        Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', {
    360354                'fd': 'fd',
    361                 'addr': '(uintptr_t)buf',
     355                'addr': '(typeof(sqe->addr))buf',
    362356                'len': 'count'
    363357        }),
    364358        # 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)', {
    366360                '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',
    368362                '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',
    370364                'len': 'len',
    371365                'splice_flags': 'flags'
  • libcfa/src/concurrency/io/setup.cfa

    r2ed94a9 rb110bcc  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#if defined(__CFA_DEBUG__)
  • libcfa/src/concurrency/iofwd.hfa

    r2ed94a9 rb110bcc  
    99// Author           : Thierry Delisle
    1010// 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
    1414//
    1515
     
    1717
    1818#include <unistd.h>
     19#include <sys/socket.h>
     20
    1921extern "C" {
    2022        #include <asm/types.h>
     
    4850typedef __off64_t off64_t;
    4951
    50 struct cluster;
    51 struct io_context$;
    52 
    53 struct iovec;
    54 struct msghdr;
    55 struct sockaddr;
    56 struct statx;
    5752struct epoll_event;
    58 
    59 struct io_uring_sqe;
    6053
    6154//-----------------------------------------------------------------------
     
    8881// synchronous calls
    8982#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);
    9184#endif
    9285#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);
    9487#endif
    9588extern 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);
     89extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags);
    9790extern 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);
     91extern  ssize_t cfa_sendmsg(int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags);
     92extern ssize_t cfa_recvmsg(int sockfd, struct msghdr * msg, int flags, __u64 submit_flags);
     93extern ssize_t cfa_send(int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags);
     94extern ssize_t cfa_recv(int sockfd, void * buf, size_t len, int flags, __u64 submit_flags);
     95extern int cfa_accept4(int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags, __u64 submit_flags);
     96extern int cfa_connect(int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen, __u64 submit_flags);
    10497extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, __u64 submit_flags);
    10598extern 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);
     99extern int cfa_madvise(void * addr, size_t length, int advice, __u64 submit_flags);
     100extern int cfa_openat(int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags);
    108101#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);
    110103#endif
    111104extern int cfa_close(int fd, __u64 submit_flags);
    112105#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);
    114107#endif
    115108extern ssize_t cfa_read(int fd, void * buf, size_t count, __u64 submit_flags);
    116109extern 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);
     110extern 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);
    118111extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);
    119112
     
    121114// asynchronous calls
    122115#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);
    124117#endif
    125118#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);
    127120#endif
    128121extern 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);
     122extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event * event, __u64 submit_flags);
    130123extern 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);
     124extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr * msg, int flags, __u64 submit_flags);
     125extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr * msg, int flags, __u64 submit_flags);
     126extern void async_send(io_future_t & future, int sockfd, const void * buf, size_t len, int flags, __u64 submit_flags);
     127extern void async_recv(io_future_t & future, int sockfd, void * buf, size_t len, int flags, __u64 submit_flags);
     128extern void async_accept4(io_future_t & future, int sockfd, __SOCKADDR_ARG addr, socklen_t * restrict addrlen, int flags, __u64 submit_flags);
     129extern void async_connect(io_future_t & future, int sockfd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen, __u64 submit_flags);
    137130extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, __u64 submit_flags);
    138131extern 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);
     132extern void async_madvise(io_future_t & future, void * addr, size_t length, int advice, __u64 submit_flags);
     133extern void async_openat(io_future_t & future, int dirfd, const char * pathname, int flags, mode_t mode, __u64 submit_flags);
    141134#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);
    143136#endif
    144137extern void async_close(io_future_t & future, int fd, __u64 submit_flags);
    145138#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);
    147140#endif
    148141void async_read(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);
    149142extern 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);
     143extern 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);
    151144extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);
    152145
  • libcfa/src/concurrency/kernel.cfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Nov 30 18:14:08 2022
    13 // Update Count     : 76
     12// Last Modified On : Mon Jan  9 08:42:05 2023
     13// Update Count     : 77
    1414//
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918// #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
  • libcfa/src/concurrency/kernel/cluster.cfa

    r2ed94a9 rb110bcc  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#include "bits/defs.hfa"
     
    6968        return max_cores_l;
    7069}
    71 
    72 #if   defined(CFA_HAVE_LINUX_LIBRSEQ)
    73         // No forward declaration needed
    74         #define __kernel_rseq_register rseq_register_current_thread
    75         #define __kernel_rseq_unregister rseq_unregister_current_thread
    76 #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_register
    81         #define __kernel_rseq_unregister __kernel_raw_rseq_unregister
    82 #else
    83         // No forward declaration needed
    84         // No initialization needed
    85         static inline void noop(void) {}
    86 
    87         #define __kernel_rseq_register noop
    88         #define __kernel_rseq_unregister noop
    89 #endif
    9070
    9171//=======================================================================
     
    11191// Lock-Free registering/unregistering of threads
    11292unsigned register_proc_id( void ) with(__scheduler_lock.lock) {
    113         __kernel_rseq_register();
    114 
    11593        bool * handle = (bool *)&kernelTLS().sched_lock;
    11694
     
    162140
    163141        __atomic_store_n(cell, 0p, __ATOMIC_RELEASE);
    164 
    165         __kernel_rseq_unregister();
    166142}
    167143
     
    505481        /* paranoid */ verify( mock_head(this)    == this.l.prev );
    506482}
    507 
    508 #if   defined(CFA_HAVE_LINUX_LIBRSEQ)
    509         // No definition needed
    510 #elif defined(CFA_HAVE_LINUX_RSEQ_H)
    511 
    512         #if defined( __x86_64 ) || defined( __i386 )
    513                 #define RSEQ_SIG        0x53053053
    514         #elif defined( __ARM_ARCH )
    515                 #ifdef __ARMEB__
    516                 #define RSEQ_SIG    0xf3def5e7      /* udf    #24035    ; 0x5de3 (ARMv6+) */
    517                 #else
    518                 #define RSEQ_SIG    0xe7f5def3      /* udf    #24035    ; 0x5de3 */
    519                 #endif
    520         #endif
    521 
    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 #else
    561         // No definition needed
    562 #endif
  • libcfa/src/concurrency/kernel/cluster.hfa

    r2ed94a9 rb110bcc  
    146146}
    147147
    148 static struct {
    149         const unsigned readyq;
    150         const unsigned io;
     148const static struct {
     149        unsigned readyq;
     150        unsigned io;
    151151} __shard_factor = { 2, 1 };
    152152
  • libcfa/src/concurrency/kernel/private.hfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Mon Feb 13 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Aug 12 08:21:33 2020
    13 // Update Count     : 9
     12// Last Modified On : Thu Mar  2 16:04:46 2023
     13// Update Count     : 11
    1414//
    1515
     
    2929
    3030extern "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 #else
    36         #ifndef _GNU_SOURCE
    37         #error kernel/private requires gnu_source
    38         #endif
    3931        #include <sched.h>
    40 #endif
    4132}
    4233
     
    110101// Hardware
    111102
    112 #if   defined(CFA_HAVE_LINUX_LIBRSEQ)
    113         // No data needed
    114 #elif defined(CFA_HAVE_LINUX_RSEQ_H)
    115         extern "Cforall" {
    116                 extern __attribute__((aligned(64))) __thread volatile struct rseq __cfaabi_rseq;
    117         }
    118 #else
    119         // No data needed
    120 #endif
    121 
    122103static inline int __kernel_getcpu() {
    123104        /* 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 #else
    131105        return sched_getcpu();
    132 #endif
    133106}
    134107
  • libcfa/src/concurrency/kernel/startup.cfa

    r2ed94a9 rb110bcc  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918// #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
    2019
    2120// C Includes
    22 #include <errno.h>                                      // errno
     21#include <errno.h>                                                                              // errno
    2322#include <signal.h>
    24 #include <string.h>                                     // strerror
    25 #include <unistd.h>                                     // sysconf
    26 
     23#include <string.h>                                                                             // strerror
     24#include <unistd.h>
     25#include <limits.h>                                                                             // PTHREAD_STACK_MIN
    2726extern "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
    3330}
    3431
     
    3633#include "kernel/private.hfa"
    3734#include "iofwd.hfa"
    38 #include "startup.hfa"                                  // STARTUP_PRIORITY_XXX
     35#include "startup.hfa"                                                                  // STARTUP_PRIORITY_XXX
    3936#include "limits.hfa"
    4037#include "math.hfa"
     
    150147__scheduler_RWLock_t __scheduler_lock @= { 0 };
    151148
    152 #if   defined(CFA_HAVE_LINUX_LIBRSEQ)
    153         // No data needed
    154 #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 #else
    161         // No data needed
    162 #endif
    163 
    164149//-----------------------------------------------------------------------------
    165150// Struct to steal stack
  • libcfa/src/concurrency/locks.cfa

    r2ed94a9 rb110bcc  
    1616
    1717#define __cforall_thread__
    18 #define _GNU_SOURCE
    1918
    2019#include "locks.hfa"
  • libcfa/src/concurrency/locks.hfa

    r2ed94a9 rb110bcc  
    3232#include <fstream.hfa>
    3333
    34 
    3534// futex headers
    3635#include <linux/futex.h>      /* Definition of FUTEX_* constants */
     
    155154// futex_mutex
    156155
    157 // - No cond var support
    158156// - Kernel thd blocking alternative to the spinlock
    159157// - No ownership (will deadlock on reacq)
     
    185183        int state;
    186184
    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;
    199195       
    200196        // if not in contended state, set to be in contended state
     
    209205
    210206static inline void unlock(futex_mutex & this) with(this) {
    211         // if uncontended do atomice unlock and then return
    212         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;
    213209       
    214210        // otherwise threads are blocked so we must wake one
    215         __atomic_store_n((int *)&val, 0, __ATOMIC_RELEASE);
    216211        futex((int *)&val, FUTEX_WAKE, 1);
    217212}
     
    222217// to set recursion count after getting signalled;
    223218static 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
     227struct 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
     235static inline void  ?{}( go_mutex & this ) with(this) { val = 0; }
     236
     237static 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
     241static 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!!!!!
     246static 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
     276static 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
     284static inline void on_notify( go_mutex & f, thread$ * t){ unpark(t); }
     285static inline size_t on_wait( go_mutex & f ) {unlock(f); return 0;}
     286static inline void on_wakeup( go_mutex & f, size_t recursion ) {}
    224287
    225288//-----------------------------------------------------------------------------
     
    253316static inline void on_wakeup(clh_lock & this, size_t recursion ) { lock(this); }
    254317
    255 
    256318//-----------------------------------------------------------------------------
    257319// Exponential backoff then block lock
     
    272334        this.lock_value = 0;
    273335}
    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
     337static inline void  ^?{}( exp_backoff_then_block_lock & this ){}
    277338
    278339static 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);
    283341}
    284342
     
    286344
    287345static 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);
    292347}
    293348
    294349static 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 );
    302357        park( );
    303358        return true;
     
    307362        size_t compare_val = 0;
    308363        int spin = 4;
     364
    309365        // linear backoff
    310366        for( ;; ) {
     
    324380static inline void unlock(exp_backoff_then_block_lock & this) with(this) {
    325381    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 );
    330386}
    331387
  • libcfa/src/concurrency/monitor.cfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Thd Feb 23 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec  4 07:55:14 2019
    13 // Update Count     : 10
     12// Last Modified On : Sun Feb 19 17:00:59 2023
     13// Update Count     : 12
    1414//
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#include "monitor.hfa"
  • libcfa/src/concurrency/mutex.cfa

    r2ed94a9 rb110bcc  
    1212// Created On       : Fri May 25 01:37:11 2018
    1313// Last Modified By : Peter A. Buhr
    14 // Last Modified On : Wed Dec  4 09:16:39 2019
    15 // Update Count     : 1
     14// Last Modified On : Sun Feb 19 17:01:36 2023
     15// Update Count     : 3
    1616//
    1717
    1818#define __cforall_thread__
    19 #define _GNU_SOURCE
    2019
    2120#include "mutex.hfa"
  • libcfa/src/concurrency/mutex_stmt.hfa

    r2ed94a9 rb110bcc  
     1#pragma once
     2
    13#include "bits/algorithm.hfa"
    24#include "bits/defs.hfa"
     
    46//-----------------------------------------------------------------------------
    57// is_lock
    6 trait is_lock(L & | sized(L)) {
     8forall(L & | sized(L))
     9trait is_lock {
    710        // For acquiring a lock
    811        void lock( L & );
     
    2427    // Sort locks based on address
    2528    __libcfa_small_sort(this.lockarr, count);
    26 
    27     // acquire locks in order
    28     // 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     // }
    3729}
    3830
  • libcfa/src/concurrency/preemption.cfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Mon Jun 5 14:20:42 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 17 11:18:57 2022
    13 // Update Count     : 59
     12// Last Modified On : Mon Jan  9 08:42:59 2023
     13// Update Count     : 60
    1414//
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918// #define __CFA_DEBUG_PRINT_PREEMPTION__
  • libcfa/src/concurrency/pthread.cfa

    r2ed94a9 rb110bcc  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#include <signal.h>
     
    3534struct pthread_values{
    3635        inline Seqable;
    37         void* value;
     36        void * value;
    3837        bool in_use;
    3938};
     
    5150struct pthread_keys {
    5251        bool in_use;
    53         void (*destructor)( void * );
     52        void (* destructor)( void * );
    5453        Sequence(pthread_values) threads;
    5554};
    5655
    57 static void ?{}(pthread_keys& k){
     56static void ?{}(pthread_keys& k) {
    5857        k.threads{};
    5958}
     
    6261static pthread_keys cfa_pthread_keys_storage[PTHREAD_KEYS_MAX] __attribute__((aligned (16)));
    6362
    64 static void init_pthread_storage(){
    65         for (int i = 0; i < PTHREAD_KEYS_MAX; i++){
     63static void init_pthread_storage() {
     64        for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) {
    6665                cfa_pthread_keys_storage[i]{};
    6766        }
     
    9695
    9796/* condvar helper routines */
    98 static void init(pthread_cond_t* pcond){
     97static void init(pthread_cond_t * pcond) {
    9998        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;
    101100        ?{}(*_cond);
    102101}
    103102
    104 static cfa2pthr_cond_var_t* get(pthread_cond_t* pcond){
     103static cfa2pthr_cond_var_t * get(pthread_cond_t * pcond) {
    105104        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
     108static void destroy(pthread_cond_t * cond) {
    110109        static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)");
    111110        ^?{}(*get(cond));
     
    116115
    117116/* mutex helper routines */
    118 static void mutex_check(pthread_mutex_t* t){
     117static void mutex_check(pthread_mutex_t * t) {
    119118        // Use double check to improve performance.
    120119        // 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;
    122121
    123122        // SKULLDUGGERY: not a portable way to access the kind field, /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h
     
    136135
    137136
    138 static void init(pthread_mutex_t* plock){
     137static void init(pthread_mutex_t * plock) {
    139138        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;
    141140        ?{}(*_lock);
    142141}
    143142
    144 static simple_owner_lock* get(pthread_mutex_t* plock){
     143static simple_owner_lock * get(pthread_mutex_t * plock) {
    145144        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
     148static void destroy(pthread_mutex_t * plock) {
    150149        static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)");
    151150        ^?{}(*get(plock));
     
    153152
    154153//######################### Attr helpers #########################
    155 struct cfaPthread_attr_t {                                                              // thread attributes
     154typedef struct cfaPthread_attr_t {                                              // thread attributes
    156155                int contentionscope;
    157156                int detachstate;
    158157                size_t stacksize;
    159                 void *stackaddr;
     158                void * stackaddr;
    160159                int policy;
    161160                int inheritsched;
    162161                struct sched_param param;
    163 } typedef cfaPthread_attr_t;
    164 
    165 static const cfaPthread_attr_t default_attrs{
     162} cfaPthread_attr_t;
     163
     164static const cfaPthread_attr_t default_attrs {
    166165        0,
    167166        0,
    168         (size_t)65000,
    169         (void *)NULL,
     167        65_000,
     168        NULL,
    170169        0,
    171170        0,
     
    173172};
    174173
    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;
     174static 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;
    178177}
    179178
     
    190189
    191190        // pthreads return value
    192         void *joinval;
     191        void * joinval;
    193192
    194193        // pthread attributes
    195194        pthread_attr_t pthread_attr;
    196195
    197         void *(*start_routine)(void *);
    198         void *start_arg;
     196        void *(* start_routine)(void *);
     197        void * start_arg;
    199198
    200199        // thread local data
    201         pthread_values* pthreadData;
     200        pthread_values * pthreadData;
    202201
    203202        // flag used for tryjoin
     
    207206/* thread part routines */
    208207//  cfaPthread entry point
    209 void main(cfaPthread& _thread) with(_thread){
    210         joinval =  start_routine(start_arg);
     208void main(cfaPthread & _thread) with(_thread) {
     209        joinval = start_routine(start_arg);
    211210        isTerminated = true;
    212211}
    213212
    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::invokeTask
    220         pthread_values* value;
    221         pthread_keys* key;
     213static cfaPthread * lookup( pthread_t p ) {
     214        static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *),"sizeof(pthread_t) < sizeof(cfaPthread *)");
     215        return (cfaPthread *)p;
     216}
     217
     218static void pthread_deletespecific_( pthread_values * values )  { // see uMachContext::invokeTask
     219        pthread_values * value;
     220        pthread_keys * key;
    222221        bool destcalled = true;
    223         if (values != NULL){
     222        if (values != NULL) {
    224223                for ( int attempts = 0; attempts < PTHREAD_DESTRUCTOR_ITERATIONS && destcalled ; attempts += 1 ) {
    225224                        destcalled = false;
    226225                        lock(key_lock);
    227                         for (int i = 0; i < PTHREAD_KEYS_MAX; i++){
     226                        for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) {
    228227                                // for each valid key
    229                                 if ( values[i].in_use){
     228                                if ( values[i].in_use) {
    230229                                        value = &values[i];
    231230                                        key = &cfa_pthread_keys[i];
     
    234233                                        // if  a  key  value  has  a  non-NULL  destructor pointer,  and  the  thread  has  a  non-NULL  value associated with that key,
    235234                                        // 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) {
    237236                                                unlock(key_lock);
    238237                                                key->destructor(value->value); // run destructor
     
    249248}
    250249
    251 static void ^?{}(cfaPthread & mutex t){
     250static void ^?{}(cfaPthread & mutex t) {
    252251        // delete pthread local storage
    253252        pthread_values * values = t.pthreadData;
     
    255254}
    256255
    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*)");
     256static 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 *)");
    259258
    260259        // set up user thread stackSize
     
    278277        //######################### Pthread Attrs #########################
    279278
    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);
    282281                ?{}(*_attr, default_attrs);
    283282                return 0;
    284283        }
    285         int pthread_attr_destroy(pthread_attr_t *attr) libcfa_public __THROW {
     284        int pthread_attr_destroy(pthread_attr_t * attr) libcfa_public __THROW {
    286285                ^?{}(*get(attr));
    287286                return 0;
    288287        }
    289288
    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 {
    291290                get( attr )->contentionscope = contentionscope;
    292291                return 0;
    293292        } // pthread_attr_setscope
    294293
    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 {
    296295                *contentionscope = get( attr )->contentionscope;
    297296                return 0;
    298297        } // pthread_attr_getscope
    299298
    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 {
    301300                get( attr )->detachstate = detachstate;
    302301                return 0;
    303302        } // pthread_attr_setdetachstate
    304303
    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 {
    306305                *detachstate = get( attr )->detachstate;
    307306                return 0;
    308307        } // pthread_attr_getdetachstate
    309308
    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 {
    311310                get( attr )->stacksize = stacksize;
    312311                return 0;
    313312        } // pthread_attr_setstacksize
    314313
    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 {
    316315                *stacksize = get( attr )->stacksize;
    317316                return 0;
     
    326325        } // pthread_attr_setguardsize
    327326
    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 {
    329328                get( attr )->stackaddr = stackaddr;
    330329                return 0;
    331330        } // pthread_attr_setstackaddr
    332331
    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 {
    334333                *stackaddr = get( attr )->stackaddr;
    335334                return 0;
    336335        } // pthread_attr_getstackaddr
    337336
    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 {
    339338                get( attr )->stackaddr = stackaddr;
    340339                get( attr )->stacksize = stacksize;
     
    342341        } // pthread_attr_setstack
    343342
    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 {
    345344                *stackaddr = get( attr )->stackaddr;
    346345                *stacksize = get( attr )->stacksize;
     
    351350        // already running thread threadID. It shall be called on unitialized attr
    352351        // 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 extension
     352        int pthread_getattr_np( pthread_t threadID, pthread_attr_t * attr ) libcfa_public __THROW { // GNU extension
    354353                check_nonnull(attr);
    355354
     
    363362        //######################### Threads #########################
    364363
    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();
    367366                (*t){_thread, attr, start_routine, arg};
    368367                return 0;
    369368        }
    370369
    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 {
    373371                // if thread is invalid
    374372                if (_thread == NULL) return EINVAL;
     
    376374
    377375                // get user thr pointer
    378                 cfaPthread* p = lookup(_thread);
     376                cfaPthread * p = lookup(_thread);
    379377                try {
    380378                        join(*p);
     
    389387        }
    390388
    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 {
    392390                // if thread is invalid
    393391                if (_thread == NULL) return EINVAL;
    394392                if (_thread == pthread_self()) return EDEADLK;
    395393
    396                 cfaPthread* p = lookup(_thread);
     394                cfaPthread * p = lookup(_thread);
    397395
    398396                // thread not finished ?
     
    412410        void pthread_exit(void * status) libcfa_public __THROW {
    413411                pthread_t pid = pthread_self();
    414                 cfaPthread* _thread = (cfaPthread*)pid;
     412                cfaPthread * _thread = (cfaPthread *)pid;
    415413                _thread->joinval = status;  // set return value
    416414                _thread->isTerminated = 1;  // set terminated flag
     
    426424        //######################### Mutex #########################
    427425
    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 {
    429427                check_nonnull(_mutex);
    430428                init(_mutex);
     
    435433        int pthread_mutex_destroy(pthread_mutex_t *_mutex) libcfa_public __THROW {
    436434                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) {
    439437                        return EBUSY;
    440438                }
     
    446444                check_nonnull(_mutex);
    447445                mutex_check(_mutex);
    448                 simple_owner_lock* _lock = get(_mutex);
     446                simple_owner_lock * _lock = get(_mutex);
    449447                lock(*_lock);
    450448                return 0;
     
    453451        int pthread_mutex_unlock(pthread_mutex_t *_mutex) libcfa_public __THROW {
    454452                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()) {
    457455                        return EPERM;
    458456                } // current thread does not hold the mutex
     
    463461        int pthread_mutex_trylock(pthread_mutex_t *_mutex) libcfa_public __THROW {
    464462                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) {
    467465                        return EBUSY;
    468466                }   // if mutex is owned
     
    474472
    475473        /* 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 {
    477475                check_nonnull(cond);
    478476                init(cond);
     
    480478        }  //pthread_cond_init
    481479
    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 {
    483481                check_nonnull(_mutex);
    484482                check_nonnull(cond);
     
    494492        } // pthread_cond_timedwait
    495493
    496         int pthread_cond_signal(pthread_cond_t *cond) libcfa_public __THROW {
     494        int pthread_cond_signal(pthread_cond_t * cond) libcfa_public __THROW {
    497495                check_nonnull(cond);
    498496                return notify_one(*get(cond));
    499497        } // pthread_cond_signal
    500498
    501         int pthread_cond_broadcast(pthread_cond_t *cond) libcfa_public __THROW {
     499        int pthread_cond_broadcast(pthread_cond_t * cond) libcfa_public __THROW {
    502500                check_nonnull(cond);
    503501                return notify_all(*get(cond));
    504502        } // pthread_cond_broadcast
    505503
    506         int pthread_cond_destroy(pthread_cond_t *cond) libcfa_public __THROW {
     504        int pthread_cond_destroy(pthread_cond_t * cond) libcfa_public __THROW {
    507505                check_nonnull(cond);
    508506                destroy(cond);
     
    514512        //######################### Local storage #########################
    515513
    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 {
    517515                static_assert(sizeof(pthread_once_t) >= sizeof(int),"sizeof(pthread_once_t) < sizeof(int)");
    518516                check_nonnull(once_control);
     
    527525        } // pthread_once
    528526
    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 {
    530528                lock(key_lock);
    531529                for ( int i = 0; i < PTHREAD_KEYS_MAX; i += 1 ) {
     
    562560        }   // pthread_key_delete
    563561
    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 {
    565563                // get current thread
    566                 cfaPthread* t = lookup(pthread_self());
     564                cfaPthread * t = lookup(pthread_self());
    567565                // 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) {
    570568                        values = anew( PTHREAD_KEYS_MAX);
    571569                        t->pthreadData = values;
    572                         for (int i = 0;i < PTHREAD_KEYS_MAX; i++){
     570                        for ( int i = 0;i < PTHREAD_KEYS_MAX; i++ ) {
    573571                                t->pthreadData[i].in_use = false;
    574572                        }   // for
     
    593591        } //pthread_setspecific
    594592
    595         void* pthread_getspecific(pthread_key_t key) libcfa_public __THROW {
     593        void * pthread_getspecific(pthread_key_t key) libcfa_public __THROW {
    596594                if (key >= PTHREAD_KEYS_MAX || ! cfa_pthread_keys[key].in_use) return NULL;
    597595
    598596                // get current thread
    599                 cfaPthread* t = lookup(pthread_self());
     597                cfaPthread * t = lookup(pthread_self());
    600598                if (t->pthreadData == NULL) return NULL;
    601599                lock(key_lock);
    602                 pthread_values &entry = ((pthread_values *)t->pthreadData)[key];
     600                pthread_values & entry = ((pthread_values *)t->pthreadData)[key];
    603601                if ( ! entry.in_use ) {
    604602                        unlock( key_lock );
    605603                        return NULL;
    606604                } // if
    607                 void *value = entry.value;
     605                void * value = entry.value;
    608606                unlock(key_lock);
    609607
     
    875873        //######################### Parallelism #########################
    876874
    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_np
    880 
    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_np
    884 
    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_np
    888 
    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_np
     875        // 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
    892890
    893891        //######################### Cancellation #########################
     
    906904        } // pthread_cancel
    907905
    908         int pthread_setcancelstate( int state, int *oldstate ) libcfa_public __THROW {
     906        int pthread_setcancelstate( int state, int * oldstate ) libcfa_public __THROW {
    909907                abort("pthread_setcancelstate not implemented");
    910908                return 0;
    911909        } // pthread_setcancelstate
    912910
    913         int pthread_setcanceltype( int type, int *oldtype ) libcfa_public __THROW {
     911        int pthread_setcanceltype( int type, int * oldtype ) libcfa_public __THROW {
    914912                abort("pthread_setcanceltype not implemented");
    915913                return 0;
     
    918916
    919917#pragma GCC diagnostic pop
    920 
  • libcfa/src/concurrency/ready_queue.cfa

    r2ed94a9 rb110bcc  
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918// #define __CFA_DEBUG_PRINT_READY_QUEUE__
  • libcfa/src/concurrency/select.hfa

    r2ed94a9 rb110bcc  
     1#pragma once
     2
    13#include "containers/list.hfa"
    24#include <stdint.h>
  • libcfa/src/concurrency/thread.cfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Tue Jan 17 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 11 20:56:54 2022
    13 // Update Count     : 102
     12// Last Modified On : Mon Jan  9 08:42:33 2023
     13// Update Count     : 103
    1414//
    1515
    1616#define __cforall_thread__
    17 #define _GNU_SOURCE
    1817
    1918#include "thread.hfa"
  • libcfa/src/containers/array.hfa

    r2ed94a9 rb110bcc  
    99
    1010
    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//
    1537forall( [N], S & | sized(S), Timmed &, Tbase & ) {
     38
     39    //
     40    // Single-dim array sruct (with explicit packing and atom)
     41    //
    1642    struct arpk {
    1743        S strides[N];
  • libcfa/src/containers/list.hfa

    r2ed94a9 rb110bcc  
    3232static inline tytagref(void, T) ?`inner ( T & this ) { tytagref( void, T ) ret = {this}; return ret; }
    3333
    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 ) { \
    3862        immedBase & ib = this; \
    3963        Tbase & b = ib`inner; \
  • libcfa/src/containers/vector2.hfa

    r2ed94a9 rb110bcc  
    99// Author           : Michael Brooks
    1010// 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
    1517
    1618#include <stdlib.hfa>
  • libcfa/src/interpose.cfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Wed Mar 29 16:10:31 2017
    1111// 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
    1716#include <stdio.h>
    18 #include <string.h>                                                                             // strlen
    1917#include <unistd.h>                                                                             // _exit, getpid
    20 #include <signal.h>
    2118extern "C" {
    2219#include <dlfcn.h>                                                                              // dlopen, dlsym
     
    2421}
    2522
    26 #include "bits/debug.hfa"
    2723#include "bits/defs.hfa"
    2824#include "bits/signal.hfa"                                                              // sigHandler_?
     
    4036
    4137typedef void (* generic_fptr_t)(void);
     38
    4239static generic_fptr_t do_interpose_symbol( void * library, const char symbol[], const char version[] ) {
    43         const char * error;
    44 
    4540        union { generic_fptr_t fptr; void * ptr; } originalFunc;
    4641
    4742        #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
    5348        #else
    54                 originalFunc.ptr = dlsym( library, symbol );
     49        originalFunc.ptr = dlsym( library, symbol );
    5550        #endif // _GNU_SOURCE
    5651
    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
    6055        return originalFunc.fptr;
    6156}
    6257
    6358static 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() );
    7968        } // 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 );
    9472}
    9573
     
    12199                preload_libgcc();
    122100
    123 #pragma GCC diagnostic push
    124 #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
     101                #pragma GCC diagnostic push
     102                #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
    125103                INTERPOSE_LIBC( abort, version );
    126104                INTERPOSE_LIBC( exit , version );
    127 #pragma GCC diagnostic pop
     105                #pragma GCC diagnostic pop
    128106
    129107                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
    130118
    131119                // As a precaution (and necessity), errors that result in termination are delivered on a separate stack because
     
    293281        va_start( args, fmt );
    294282        __abort( false, fmt, args );
    295     // CONTROL NEVER REACHES HERE!
     283        // CONTROL NEVER REACHES HERE!
    296284        va_end( args );
    297285}
    298286
    299287void 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 );
    305293}
    306294
  • libcfa/src/interpose_thread.cfa

    r2ed94a9 rb110bcc  
    1414//
    1515
    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
    1921#include <signal.h>
    2022#include <pthread.h>
     23#include <signal.h>
    2124extern "C" {
    2225#include <dlfcn.h>                                                                              // dlopen, dlsym
    23 #include <execinfo.h>                                                                   // backtrace, messages
    2426}
    2527
    26 #include "bits/debug.hfa"
    2728#include "bits/defs.hfa"
    28 #include <assert.h>
    2929
    3030//=============================================================================================
     
    3434typedef void (* generic_fptr_t)(void);
    3535
    36 generic_fptr_t interpose_symbol(
     36generic_fptr_t libcfa_public interpose_symbol(
    3737        generic_fptr_t (*do_interpose_symbol)( void * library, const char symbol[], const char version[] ),
    3838        const char symbol[],
    3939        const char version[]
    40 ) libcfa_public {
    41         const char * error;
     40) {
     41        void * library;
    4242
    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() );
    5550        } // if
     51        #endif // RTLD_NEXT
    5652
    57         return do_interpose_symbol(library, symbol, version);
     53        return do_interpose_symbol( library, symbol, version );
    5854}
    5955
     
    8379#pragma GCC diagnostic push
    8480#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 );
    9591#pragma GCC diagnostic pop
    9692        }
  • libcfa/src/iostream.cfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 27 15:04:15 2022
    13 // Update Count     : 1358
     12// Last Modified On : Mon Jan  9 09:27:58 2023
     13// Update Count     : 1361
    1414//
    1515
     
    667667                        } /* if */ \
    668668                        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 */ ); \
    670670                        } else { \
    671671                                len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \
  • libcfa/src/limits.cfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Wed Apr  6 18:06:52 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jan  5 22:27:40 2023
    13 // Update Count     : 84
     12// Last Modified On : Fri Feb 17 12:25:39 2023
     13// Update Count     : 87
    1414//
    1515
    16 #define _GNU_SOURCE                                                                             // access long double M_*l in math.h
    1716#include <limits.h>
    1817#include <float.h>
  • libcfa/src/stdlib.cfa

    r2ed94a9 rb110bcc  
    1010// Created On       : Thu Jan 28 17:10:29 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec  9 15:11:30 2022
    13 // Update Count     : 631
     12// Last Modified On : Thu Feb 16 16:31:34 2023
     13// Update Count     : 633
    1414//
    1515
     
    2020//---------------------------------------
    2121
    22 #define _XOPEN_SOURCE 600                                                               // posix_memalign, *rand48
    2322#include <string.h>                                                                             // memcpy, memset
    2423//#include <math.h>                                                                             // fabsf, fabs, fabsl
  • libcfa/src/vec/vec.hfa

    r2ed94a9 rb110bcc  
    1818#include <math.hfa>
    1919
    20 trait fromint(T) {
     20forall(T)
     21trait fromint {
    2122    void ?{}(T&, int);
    2223};
    23 trait zeroinit(T) {
     24forall(T)
     25trait zeroinit {
    2426    void ?{}(T&, zero_t);
    2527};
    26 trait zero_assign(T) {
     28forall(T)
     29trait zero_assign {
    2730    T ?=?(T&, zero_t);
    2831};
    29 trait subtract(T) {
     32forall(T)
     33trait subtract {
    3034    T ?-?(T, T);
    3135};
    32 trait negate(T) {
     36forall(T)
     37trait negate {
    3338    T -?(T);
    3439};
    35 trait add(T) {
     40forall(T)
     41trait add {
    3642    T ?+?(T, T);
    3743};
    38 trait multiply(T) {
     44forall(T)
     45trait multiply {
    3946    T ?*?(T, T);
    4047};
    41 trait divide(T) {
     48forall(T)
     49trait divide {
    4250    T ?/?(T, T);
    4351};
    44 trait lessthan(T) {
     52forall(T)
     53trait lessthan {
    4554    int ?<?(T, T);
    4655};
    47 trait equality(T) {
     56forall(T)
     57trait equality {
    4858    int ?==?(T, T);
    4959};
    50 trait sqrt(T) {
     60forall(T)
     61trait sqrt {
    5162    T sqrt(T);
    5263};
Note: See TracChangeset for help on using the changeset viewer.