Changes in / [c8a0210:857a1c6]


Ignore:
Files:
5 deleted
114 edited

Legend:

Unmodified
Added
Removed
  • benchmark/basic/ttst_lock.c

    rc8a0210 r857a1c6  
    99#define CALIGN __attribute__(( aligned (CACHE_ALIGN) ))
    1010#define CACHE_ALIGN 128
    11 #if defined( __i386 ) || defined( __x86_64 )
    12         #define Pause() __asm__ __volatile__ ( "pause" : : : )
    13 #elif defined( __ARM_ARCH )
    14         #define Pause() __asm__ __volatile__ ( "YIELD" : : : )
    15 #else
    16         #error unsupported architecture
    17 #endif
     11#define Pause() __asm__ __volatile__ ( "pause" : : : )
    1812
    1913typedef uintptr_t TYPE;                                                                 // addressable word-size
  • benchmark/benchcltr.hfa

    rc8a0210 r857a1c6  
    114114        for() {
    115115                sleep(100`ms);
    116                 end = timeNsec();
     116                end = getTimeNsec();
    117117                Duration delta = end - start;
    118118                /*if(is_tty)*/ {
     
    126126}
    127127#else
    128 uint64_t timeNsec() {
     128uint64_t getTimeNsec() {
    129129        timespec curr;
    130130        clock_gettime( CLOCK_REALTIME, &curr );
     
    140140        for(;;) {
    141141                usleep(100000);
    142                 end = timeNsec();
     142                end = getTimeNsec();
    143143                uint64_t delta = end - start;
    144144                /*if(is_tty)*/ {
  • benchmark/io/http/protocol.cfa

    rc8a0210 r857a1c6  
    249249
    250250                char buff[100];
    251                 Time now = timeNsec();
     251                Time now = getTimeNsec();
    252252                strftime( buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now );
    253253                sout | "Updated date to '" | buff | "'";
  • benchmark/io/readv-posix.c

    rc8a0210 r857a1c6  
    111111                                printf("Starting\n");
    112112                                bool is_tty = isatty(STDOUT_FILENO);
    113                                 start = timeNsec();
     113                                start = getTimeNsec();
    114114                                run = true;
    115115
     
    118118
    119119                                run = false;
    120                                 end = timeNsec();
     120                                end = getTimeNsec();
    121121                                printf("\nDone\n");
    122122
  • benchmark/io/readv.cfa

    rc8a0210 r857a1c6  
    147147                                printf("Starting\n");
    148148                                bool is_tty = isatty(STDOUT_FILENO);
    149                                 start = timeNsec();
     149                                start = getTimeNsec();
    150150                                run = true;
    151151
     
    156156
    157157                                run = false;
    158                                 end = timeNsec();
     158                                end = getTimeNsec();
    159159                                printf("\nDone\n");
    160160                        }
  • benchmark/readyQ/cycle.cc

    rc8a0210 r857a1c6  
    8989
    9090                        bool is_tty = isatty(STDOUT_FILENO);
    91                         start = timeNsec();
     91                        start = getTimeNsec();
    9292
    9393                        for(int i = 0; i < nthreads; i++) {
     
    9797
    9898                        stop = true;
    99                         end = timeNsec();
     99                        end = getTimeNsec();
    100100                        printf("\nDone\n");
    101101
  • benchmark/readyQ/cycle.cfa

    rc8a0210 r857a1c6  
    6565
    6666                        bool is_tty = isatty(STDOUT_FILENO);
    67                         start = timeNsec();
     67                        start = getTimeNsec();
    6868
    6969                        for(i; nthreads) {
     
    7373
    7474                        stop = true;
    75                         end = timeNsec();
     75                        end = getTimeNsec();
    7676                        printf("\nDone\n");
    7777
  • benchmark/readyQ/cycle.cpp

    rc8a0210 r857a1c6  
    9393
    9494                        bool is_tty = isatty(STDOUT_FILENO);
    95                         start = timeNsec();
     95                        start = getTimeNsec();
    9696
    9797                        for(int i = 0; i < nthreads; i++) {
     
    101101
    102102                        stop = true;
    103                         end = timeNsec();
     103                        end = getTimeNsec();
    104104                        printf("\nDone\n");
    105105
  • benchmark/readyQ/locality.cc

    rc8a0210 r857a1c6  
    281281
    282282                        bool is_tty = isatty(STDOUT_FILENO);
    283                         start = timeNsec();
     283                        start = getTimeNsec();
    284284
    285285                        for(size_t i = 0; i < nthreads; i++) {
     
    289289
    290290                        stop = true;
    291                         end = timeNsec();
     291                        end = getTimeNsec();
    292292                        printf("\nDone\n");
    293293
  • benchmark/readyQ/locality.cfa

    rc8a0210 r857a1c6  
    232232
    233233                        bool is_tty = isatty(STDOUT_FILENO);
    234                         start = timeNsec();
     234                        start = getTimeNsec();
    235235
    236236                        for(i; nthreads) {
     
    240240
    241241                        stop = true;
    242                         end = timeNsec();
     242                        end = getTimeNsec();
    243243                        printf("\nDone\n");
    244244
  • benchmark/readyQ/locality.cpp

    rc8a0210 r857a1c6  
    287287
    288288                        bool is_tty = isatty(STDOUT_FILENO);
    289                         start = timeNsec();
     289                        start = getTimeNsec();
    290290
    291291                        for(size_t i = 0; i < nthreads; i++) {
     
    295295
    296296                        stop = true;
    297                         end = timeNsec();
     297                        end = getTimeNsec();
    298298                        printf("\nDone\n");
    299299
  • benchmark/readyQ/rq_bench.hfa

    rc8a0210 r857a1c6  
    7373        for() {
    7474                sleep(100`ms);
    75                 Time end = timeNsec();
     75                Time end = getTimeNsec();
    7676                Duration delta = end - start;
    7777                if(is_tty) {
  • benchmark/readyQ/rq_bench.hpp

    rc8a0210 r857a1c6  
    4646        }
    4747
    48 uint64_t timeNsec() {
     48uint64_t getTimeNsec() {
    4949        timespec curr;
    5050        clock_gettime( CLOCK_REALTIME, &curr );
     
    6060        for(;;) {
    6161                Sleeper::usleep(100000);
    62                 uint64_t end = timeNsec();
     62                uint64_t end = getTimeNsec();
    6363                uint64_t delta = end - start;
    6464                if(is_tty) {
  • benchmark/readyQ/yield.cfa

    rc8a0210 r857a1c6  
    6666
    6767                                bool is_tty = isatty(STDOUT_FILENO);
    68                                 start = timeNsec();
     68                                start = getTimeNsec();
    6969                                run = true;
    7070
     
    7575
    7676                                run = false;
    77                                 end = timeNsec();
     77                                end = getTimeNsec();
    7878                                printf("\nDone\n");
    7979                        }
  • doc/bibliography/pl.bib

    rc8a0210 r857a1c6  
    17971797}
    17981798
    1799 @article{Delisle21,
     1799@article{Delisle20,
    18001800    keywords    = {concurrency, Cforall},
    18011801    contributer = {pabuhr@plg},
    18021802    author      = {Thierry Delisle and Peter A. Buhr},
    18031803    title       = {Advanced Control-flow and Concurrency in \textsf{C}$\mathbf{\forall}$},
     1804    year        = 2020,
    18041805    journal     = spe,
    1805     month       = may,
    1806     year        = 2021,
    1807     volume      = 51,
    1808     number      = 5,
    1809     pages       = {1005-1042},
    1810     note        = {\href{https://onlinelibrary.wiley.com/doi/10.1002/spe.2925}{https://\-onlinelibrary.wiley.com/\-doi/\-10.1002/\-spe.2925}},
     1806    pages       = {1-38},
     1807    note        = {\href{https://doi-org.proxy.lib.uwaterloo.ca/10.1002/spe.2925}{https://\-doi-org.proxy.lib.uwaterloo.ca/\-10.1002/\-spe.2925}},
     1808    note        = {},
    18111809}
    18121810
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/links.hpp

    rc8a0210 r857a1c6  
    117117        }
    118118
    119         unsigned long long ts() const {
     119        long long ts() const {
    120120                return before._links.ts;
    121121        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list.hpp

    rc8a0210 r857a1c6  
    3939                while( __builtin_expect(ll.exchange(true),false) ) {
    4040                        while(ll.load(std::memory_order_relaxed))
    41                                 Pause();
     41                                asm volatile("pause");
    4242                }
    4343                /* paranoid */ assert(ll);
     
    9393                         && ready.compare_exchange_weak(copy, n + 1) )
    9494                                break;
    95                         Pause();
     95                        asm volatile("pause");
    9696                }
    9797
     
    133133                // Step 1 : make sure no writer are in the middle of the critical section
    134134                while(lock.load(std::memory_order_relaxed))
    135                         Pause();
     135                        asm volatile("pause");
    136136
    137137                // Fence needed because we don't want to start trying to acquire the lock
     
    195195                //   to simply lock their own lock and enter.
    196196                while(lock.load(std::memory_order_relaxed))
    197                         Pause();
     197                        asm volatile("pause");
    198198
    199199                // Step 2 : lock per-proc lock
     
    204204                for(uint_fast32_t i = 0; i < s; i++) {
    205205                        while(data[i].lock.load(std::memory_order_relaxed))
    206                                 Pause();
     206                                asm volatile("pause");
    207207                }
    208208
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp

    rc8a0210 r857a1c6  
    2121                target = (target - (target % total)) + total;
    2222                while(waiting < target)
    23                         Pause();
     23                        asm volatile("pause");
    2424
    2525                assert(waiting < (1ul << 60));
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/randbit.cpp

    rc8a0210 r857a1c6  
    123123                target = (target - (target % total)) + total;
    124124                while(waiting < target)
    125                         Pause();
     125                        asm volatile("pause");
    126126
    127127                assert(waiting < (1ul << 60));
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/relaxed_list.cpp

    rc8a0210 r857a1c6  
    206206        std::cout << "Total ops     : " << ops << "(" << global.in << "i, " << global.out << "o, " << global.empty << "e)\n";
    207207        #ifndef NO_STATS
    208                 LIST_VARIANT<Node>::stats_print(std::cout, duration);
     208                LIST_VARIANT<Node>::stats_print(std::cout);
    209209        #endif
    210210}
     
    368368
    369369                for(Node * & node : nodes) {
    370                         node = nullptr;
    371                         while(!node) {
    372                                 node = list.pop();
    373                         }
     370                        node = list.pop();
     371                        assert(node);
    374372                        local.crc_out += node->value;
    375373                        local.out++;
     
    693691
    694692                                for(const auto & n : nodes) {
    695                                         local.valmax = std::max(local.valmax, size_t(n.value));
    696                                         local.valmin = std::min(local.valmin, size_t(n.value));
     693                                        local.valmax = max(local.valmax, size_t(n.value));
     694                                        local.valmin = min(local.valmin, size_t(n.value));
    697695                                }
    698696
     
    775773                                                try {
    776774                                                        arg = optarg = argv[optind];
    777                                                         nnodes = std::stoul(optarg, &len);
     775                                                        nnodes = stoul(optarg, &len);
    778776                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    779777                                                } catch(std::invalid_argument &) {
     
    794792                                                try {
    795793                                                        arg = optarg = argv[optind];
    796                                                         nnodes = std::stoul(optarg, &len);
     794                                                        nnodes = stoul(optarg, &len);
    797795                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    798796                                                } catch(std::invalid_argument &) {
     
    814812                                                try {
    815813                                                        arg = optarg = argv[optind];
    816                                                         nnodes = std::stoul(optarg, &len);
     814                                                        nnodes = stoul(optarg, &len);
    817815                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    818816                                                        nslots = nnodes;
     
    825823                                                try {
    826824                                                        arg = optarg = argv[optind];
    827                                                         nnodes = std::stoul(optarg, &len);
     825                                                        nnodes = stoul(optarg, &len);
    828826                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    829827                                                } catch(std::invalid_argument &) {
     
    833831                                                try {
    834832                                                        arg = optarg = argv[optind + 1];
    835                                                         nslots = std::stoul(optarg, &len);
     833                                                        nslots = stoul(optarg, &len);
    836834                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    837835                                                } catch(std::invalid_argument &) {
     
    886884                        case 'd':
    887885                                try {
    888                                         duration = std::stod(optarg, &len);
     886                                        duration = stod(optarg, &len);
    889887                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    890888                                } catch(std::invalid_argument &) {
     
    895893                        case 't':
    896894                                try {
    897                                         nthreads = std::stoul(optarg, &len);
     895                                        nthreads = stoul(optarg, &len);
    898896                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    899897                                } catch(std::invalid_argument &) {
     
    904902                        case 'q':
    905903                                try {
    906                                         nqueues = std::stoul(optarg, &len);
     904                                        nqueues = stoul(optarg, &len);
    907905                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    908906                                } catch(std::invalid_argument &) {
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp

    rc8a0210 r857a1c6  
    168168        for(int i = 0; i < width; i++) {
    169169                int idx = i % hwdith;
     170                std::cout << i << " -> " << idx + width << std::endl;
    170171                leafs[i].parent = &nodes[ idx ];
    171172        }
     
    173174        for(int i = 0; i < root; i++) {
    174175                int idx = (i / 2) + hwdith;
     176                std::cout << i + width << " -> " << idx + width << std::endl;
    175177                nodes[i].parent = &nodes[ idx ];
    176178        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp

    rc8a0210 r857a1c6  
    159159        std::cout << "SNZI: " << depth << "x" << width << "(" << mask - 1 << ") " << (sizeof(snzi_t::node) * (root + 1)) << " bytes" << std::endl;
    160160        for(int i = 0; i < root; i++) {
     161                std::cout << i << " -> " << (i / base) + width << std::endl;
    161162                nodes[i].parent = &nodes[(i / base) + width];
    162163        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp

    rc8a0210 r857a1c6  
    1111#include <sys/sysinfo.h>
    1212
    13 // #include <x86intrin.h>
     13#include <x86intrin.h>
     14
     15// Barrier from
     16class barrier_t {
     17public:
     18        barrier_t(size_t total)
     19                : waiting(0)
     20                , total(total)
     21        {}
     22
     23        void wait(unsigned) {
     24                size_t target = waiting++;
     25                target = (target - (target % total)) + total;
     26                while(waiting < target)
     27                        asm volatile("pause");
     28
     29                assert(waiting < (1ul << 60));
     30        }
     31
     32private:
     33        std::atomic<size_t> waiting;
     34        size_t total;
     35};
    1436
    1537// class Random {
     
    80102};
    81103
    82 static inline long long int rdtscl(void) {
    83         #if defined( __i386 ) || defined( __x86_64 )
    84                 unsigned int lo, hi;
    85                 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    86                 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
    87         #elif defined( __aarch64__ ) || defined( __arm__ )
    88                 // https://github.com/google/benchmark/blob/v1.1.0/src/cycleclock.h#L116
    89                 long long int virtual_timer_value;
    90                 asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
    91                 return virtual_timer_value;
    92         #else
    93                 #error unsupported hardware architecture
    94         #endif
    95 }
    96 
    97 #if defined( __i386 ) || defined( __x86_64 )
    98         #define Pause() __asm__ __volatile__ ( "pause" : : : )
    99 #elif defined( __ARM_ARCH )
    100         #define Pause() __asm__ __volatile__ ( "YIELD" : : : )
    101 #else
    102         #error unsupported architecture
    103 #endif
     104static inline long long rdtscl(void) {
     105    unsigned int lo, hi;
     106    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
     107    return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
     108}
    104109
    105110static inline void affinity(int tid) {
     
    190195}
    191196
    192 // Barrier from
    193 class barrier_t {
    194 public:
    195         barrier_t(size_t total)
    196                 : waiting(0)
    197                 , total(total)
    198         {}
    199 
    200         void wait(unsigned) {
    201                 size_t target = waiting++;
    202                 target = (target - (target % total)) + total;
    203                 while(waiting < target)
    204                         Pause();
    205 
    206                 assert(waiting < (1ul << 60));
    207         }
    208 
    209 private:
    210         std::atomic<size_t> waiting;
    211         size_t total;
    212 };
    213 
    214197struct spinlock_t {
    215198        std::atomic_bool ll = { false };
     
    218201                while( __builtin_expect(ll.exchange(true),false) ) {
    219202                        while(ll.load(std::memory_order_relaxed))
    220                                 Pause();
     203                                asm volatile("pause");
    221204                }
    222205        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp

    rc8a0210 r857a1c6  
    66#include <memory>
    77#include <mutex>
    8 #include <thread>
    98#include <type_traits>
    109
     
    1211#include "utils.hpp"
    1312#include "links.hpp"
    14 #include "links2.hpp"
    1513#include "snzi.hpp"
    1614
    17 // #include <x86intrin.h>
    18 
    1915using namespace std;
    20 
    21 static const long long lim = 2000;
    22 static const unsigned nqueues = 2;
    23 
    24 struct __attribute__((aligned(128))) timestamp_t {
    25         volatile unsigned long long val = 0;
    26 };
    27 
    28 template<typename node_t>
    29 struct __attribute__((aligned(128))) localQ_t {
    30         #ifdef NO_MPSC
    31                 intrusive_queue_t<node_t> list;
    32 
    33                 inline auto ts() { return list.ts(); }
    34                 inline auto lock() { return list.lock.lock(); }
    35                 inline auto try_lock() { return list.lock.try_lock(); }
    36                 inline auto unlock() { return list.lock.unlock(); }
    37 
    38                 inline auto push( node_t * node ) { return list.push( node ); }
    39                 inline auto pop() { return list.pop(); }
    40         #else
    41                 mpsc_queue<node_t> queue = {};
    42                 spinlock_t _lock = {};
    43 
    44                 inline auto ts() { auto h = queue.head(); return h ? h->_links.ts : 0ull; }
    45                 inline auto lock() { return _lock.lock(); }
    46                 inline auto try_lock() { return _lock.try_lock(); }
    47                 inline auto unlock() { return _lock.unlock(); }
    48 
    49                 inline auto push( node_t * node ) { return queue.push( node ); }
    50                 inline auto pop() { return queue.pop(); }
    51         #endif
    52 
    53 
    54 };
    5516
    5617template<typename node_t>
     
    6425
    6526        work_stealing(unsigned _numThreads, unsigned)
    66                 : numThreads(_numThreads * nqueues)
    67                 , lists(new localQ_t<node_t>[numThreads])
    68                 // , lists(new intrusive_queue_t<node_t>[numThreads])
    69                 , times(new timestamp_t[numThreads])
    70                 // , snzi( std::log2( numThreads / 2 ), 2 )
     27                : numThreads(_numThreads)
     28                , lists(new intrusive_queue_t<node_t>[numThreads])
     29                , snzi( std::log2( numThreads / 2 ), 2 )
    7130
    7231        {
     
    8140        __attribute__((noinline, hot)) void push(node_t * node) {
    8241                node->_links.ts = rdtscl();
    83                 // node->_links.ts = 1;
    84 
    85                 auto & list = *({
    86                         unsigned i;
    87                         #ifdef NO_MPSC
    88                                 do {
    89                         #endif
    90                                 tls.stats.push.attempt++;
    91                                 // unsigned r = tls.rng1.next();
    92                                 unsigned r = tls.it++;
    93                                 if(tls.my_queue == outside) {
    94                                         i = r % numThreads;
    95                                 } else {
    96                                         i = tls.my_queue + (r % nqueues);
     42                if( node->_links.hint > numThreads ) {
     43                        node->_links.hint = tls.rng.next() % numThreads;
     44                        tls.stat.push.nhint++;
     45                }
     46
     47                unsigned i = node->_links.hint;
     48                auto & list = lists[i];
     49                list.lock.lock();
     50
     51                if(list.push( node )) {
     52                        snzi.arrive(i);
     53                }
     54
     55                list.lock.unlock();
     56        }
     57
     58        __attribute__((noinline, hot)) node_t * pop() {
     59                node_t * node;
     60                while(true) {
     61                        if(!snzi.query()) {
     62                                return nullptr;
     63                        }
     64
     65                        {
     66                                unsigned i = tls.my_queue;
     67                                auto & list = lists[i];
     68                                if( list.ts() != 0 ) {
     69                                        list.lock.lock();
     70                                        if((node = try_pop(i))) {
     71                                                tls.stat.pop.local.success++;
     72                                                break;
     73                                        }
     74                                        else {
     75                                                tls.stat.pop.local.elock++;
     76                                        }
    9777                                }
    98                         #ifdef NO_MPSC
    99                                 } while(!lists[i].try_lock());
    100                         #endif
    101                         &lists[i];
    102                 });
    103 
    104                 list.push( node );
    105                 #ifdef NO_MPSC
    106                         list.unlock();
     78                                else {
     79                                        tls.stat.pop.local.espec++;
     80                                }
     81                        }
     82
     83                        tls.stat.pop.steal.tried++;
     84
     85                        int i = tls.rng.next() % numThreads;
     86                        auto & list = lists[i];
     87                        if( list.ts() == 0 ) {
     88                                tls.stat.pop.steal.empty++;
     89                                continue;
     90                        }
     91
     92                        if( !list.lock.try_lock() ) {
     93                                tls.stat.pop.steal.locked++;
     94                                continue;
     95                        }
     96
     97                        if((node = try_pop(i))) {
     98                                tls.stat.pop.steal.success++;
     99                                break;
     100                        }
     101                }
     102
     103                #if defined(READ)
     104                        const unsigned f = READ;
     105                        if(0 == (tls.it % f)) {
     106                                unsigned i = tls.it / f;
     107                                lists[i % numThreads].ts();
     108                        }
     109                        // lists[tls.it].ts();
     110                        tls.it++;
    107111                #endif
    108                 // tls.rng2.set_raw_state( tls.rng1.get_raw_state());
    109                 // count++;
    110                 tls.stats.push.success++;
    111         }
    112 
    113         __attribute__((noinline, hot)) node_t * pop() {
    114                 if(tls.my_queue != outside) {
    115                         // if( tls.myfriend == outside ) {
    116                         //      auto r  = tls.rng1.next();
    117                         //      tls.myfriend = r % numThreads;
    118                         //      // assert(lists[(tls.it % nqueues) + tls.my_queue].ts() >= lists[((tls.it + 1) % nqueues) + tls.my_queue].ts());
    119                         //      tls.mytime = std::min(lists[(tls.it % nqueues) + tls.my_queue].ts(), lists[((tls.it + 1) % nqueues) + tls.my_queue].ts());
    120                         //      // times[tls.myfriend].val = 0;
    121                         //      // lists[tls.myfriend].val = 0;
    122                         // }
    123                         // // else if(times[tls.myfriend].val == 0) {
    124                         // // else if(lists[tls.myfriend].val == 0) {
    125                         // else if(times[tls.myfriend].val < tls.mytime) {
    126                         // // else if(times[tls.myfriend].val < lists[(tls.it % nqueues) + tls.my_queue].ts()) {
    127                         //      node_t * n = try_pop(tls.myfriend, tls.stats.pop.help);
    128                         //      tls.stats.help++;
    129                         //      tls.myfriend = outside;
    130                         //      if(n) return n;
    131                         // }
    132                         // if( tls.myfriend == outside ) {
    133                         //      auto r  = tls.rng1.next();
    134                         //      tls.myfriend = r % numThreads;
    135                         //      tls.mytime = lists[((tls.it + 1) % nqueues) + tls.my_queue].ts();
    136                         // }
    137                         // else {
    138                         //      if(times[tls.myfriend].val + 1000 < tls.mytime) {
    139                         //              node_t * n = try_pop(tls.myfriend, tls.stats.pop.help);
    140                         //              tls.stats.help++;
    141                         //              if(n) return n;
    142                         //      }
    143                         //      tls.myfriend = outside;
    144                         // }
    145 
    146                         node_t * n = local();
    147                         if(n) return n;
    148                 }
    149 
    150                 // try steal
    151                 for(int i = 0; i < 25; i++) {
    152                         node_t * n = steal();
    153                         if(n) return n;
    154                 }
    155 
    156                 return search();
    157         }
    158 
    159 private:
    160         inline node_t * local() {
    161                 unsigned i = (--tls.it % nqueues) + tls.my_queue;
    162                 node_t * n = try_pop(i, tls.stats.pop.local);
    163                 if(n) return n;
    164                 i = (--tls.it % nqueues) + tls.my_queue;
    165                 return try_pop(i, tls.stats.pop.local);
    166         }
    167 
    168         inline node_t * steal() {
    169                 unsigned i = tls.rng2.prev() % numThreads;
    170                 return try_pop(i, tls.stats.pop.steal);
    171         }
    172 
    173         inline node_t * search() {
    174                 unsigned offset = tls.rng2.prev();
    175                 for(unsigned i = 0; i < numThreads; i++) {
    176                         unsigned idx = (offset + i) % numThreads;
    177                         node_t * thrd = try_pop(idx, tls.stats.pop.search);
    178                         if(thrd) {
    179                                 return thrd;
    180                         }
    181                 }
    182 
    183                 return nullptr;
    184         }
    185 
    186 private:
    187         struct attempt_stat_t {
    188                 std::size_t attempt = { 0 };
    189                 std::size_t elock   = { 0 };
    190                 std::size_t eempty  = { 0 };
    191                 std::size_t espec   = { 0 };
    192                 std::size_t success = { 0 };
    193         };
    194 
    195         node_t * try_pop(unsigned i, attempt_stat_t & stat) {
    196                 assert(i < numThreads);
     112
     113
     114                return node;
     115        }
     116
     117private:
     118        node_t * try_pop(unsigned i) {
    197119                auto & list = lists[i];
    198                 stat.attempt++;
    199 
    200                 // If the list is empty, don't try
    201                 if(list.ts() == 0) { stat.espec++; return nullptr; }
    202 
    203                 // If we can't get the lock, move on
    204                 if( !list.try_lock() ) { stat.elock++; return nullptr; }
    205120
    206121                // If list is empty, unlock and retry
    207122                if( list.ts() == 0 ) {
    208                         list.unlock();
    209                         stat.eempty++;
     123                        list.lock.unlock();
    210124                        return nullptr;
    211125                }
    212126
    213                 auto node = list.pop();
    214                 list.unlock();
    215                 stat.success++;
    216                 #ifdef NO_MPSC
    217                         // times[i].val = 1;
    218                         times[i].val = node.first->_links.ts;
    219                         // lists[i].val = node.first->_links.ts;
    220                         return node.first;
    221                 #else
    222                         times[i].val = node->_links.ts;
    223                         return node;
    224                 #endif
     127                        // Actually pop the list
     128                node_t * node;
     129                bool emptied;
     130                std::tie(node, emptied) = list.pop();
     131                assert(node);
     132
     133                if(emptied) {
     134                        snzi.depart(i);
     135                }
     136
     137                // Unlock and return
     138                list.lock.unlock();
     139                return node;
    225140        }
    226141
     
    229144
    230145        static std::atomic_uint32_t ticket;
    231         static const unsigned outside = 0xFFFFFFFF;
    232 
    233         static inline unsigned calc_preferred() {
    234                 unsigned t = ticket++;
    235                 if(t == 0) return outside;
    236                 unsigned i = (t - 1) * nqueues;
    237                 return i;
    238         }
    239 
    240146        static __attribute__((aligned(128))) thread_local struct TLS {
    241                 Random     rng1 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
    242                 Random     rng2 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
    243                 unsigned   it   = 0;
    244                 unsigned   my_queue = calc_preferred();
    245                 unsigned   myfriend = outside;
    246                 unsigned long long int mytime = 0;
     147                Random     rng = { int(rdtscl()) };
     148                unsigned   my_queue = ticket++;
    247149                #if defined(READ)
    248150                        unsigned it = 0;
     
    250152                struct {
    251153                        struct {
    252                                 std::size_t attempt = { 0 };
    253                                 std::size_t success = { 0 };
     154                                std::size_t nhint = { 0 };
    254155                        } push;
    255156                        struct {
    256                                 attempt_stat_t help;
    257                                 attempt_stat_t local;
    258                                 attempt_stat_t steal;
    259                                 attempt_stat_t search;
     157                                struct {
     158                                        std::size_t success = { 0 };
     159                                        std::size_t espec = { 0 };
     160                                        std::size_t elock = { 0 };
     161                                } local;
     162                                struct {
     163                                        std::size_t tried   = { 0 };
     164                                        std::size_t locked  = { 0 };
     165                                        std::size_t empty   = { 0 };
     166                                        std::size_t success = { 0 };
     167                                } steal;
    260168                        } pop;
    261                         std::size_t help = { 0 };
    262                 } stats;
     169                } stat;
    263170        } tls;
    264171
    265172private:
    266173        const unsigned numThreads;
    267         std::unique_ptr<localQ_t<node_t> []> lists;
    268         // std::unique_ptr<intrusive_queue_t<node_t> []> lists;
    269         std::unique_ptr<timestamp_t []> times;
    270         __attribute__((aligned(128))) std::atomic_size_t count;
     174        std::unique_ptr<intrusive_queue_t<node_t> []> lists;
     175        __attribute__((aligned(64))) snzi_t snzi;
    271176
    272177#ifndef NO_STATS
     
    274179        static struct GlobalStats {
    275180                struct {
    276                         std::atomic_size_t attempt = { 0 };
    277                         std::atomic_size_t success = { 0 };
     181                        std::atomic_size_t nhint = { 0 };
    278182                } push;
    279183                struct {
    280184                        struct {
    281                                 std::atomic_size_t attempt = { 0 };
    282                                 std::atomic_size_t elock   = { 0 };
    283                                 std::atomic_size_t eempty  = { 0 };
    284                                 std::atomic_size_t espec   = { 0 };
    285185                                std::atomic_size_t success = { 0 };
    286                         } help;
    287                         struct {
    288                                 std::atomic_size_t attempt = { 0 };
    289                                 std::atomic_size_t elock   = { 0 };
    290                                 std::atomic_size_t eempty  = { 0 };
    291                                 std::atomic_size_t espec   = { 0 };
    292                                 std::atomic_size_t success = { 0 };
     186                                std::atomic_size_t espec = { 0 };
     187                                std::atomic_size_t elock = { 0 };
    293188                        } local;
    294189                        struct {
    295                                 std::atomic_size_t attempt = { 0 };
    296                                 std::atomic_size_t elock   = { 0 };
    297                                 std::atomic_size_t eempty  = { 0 };
    298                                 std::atomic_size_t espec   = { 0 };
     190                                std::atomic_size_t tried   = { 0 };
     191                                std::atomic_size_t locked  = { 0 };
     192                                std::atomic_size_t empty   = { 0 };
    299193                                std::atomic_size_t success = { 0 };
    300194                        } steal;
    301                         struct {
    302                                 std::atomic_size_t attempt = { 0 };
    303                                 std::atomic_size_t elock   = { 0 };
    304                                 std::atomic_size_t eempty  = { 0 };
    305                                 std::atomic_size_t espec   = { 0 };
    306                                 std::atomic_size_t success = { 0 };
    307                         } search;
    308195                } pop;
    309                 std::atomic_size_t help = { 0 };
    310196        } global_stats;
    311197
    312198public:
    313199        static void stats_tls_tally() {
    314                 global_stats.push.attempt += tls.stats.push.attempt;
    315                 global_stats.push.success += tls.stats.push.success;
    316                 global_stats.pop.help  .attempt += tls.stats.pop.help  .attempt;
    317                 global_stats.pop.help  .elock   += tls.stats.pop.help  .elock  ;
    318                 global_stats.pop.help  .eempty  += tls.stats.pop.help  .eempty ;
    319                 global_stats.pop.help  .espec   += tls.stats.pop.help  .espec  ;
    320                 global_stats.pop.help  .success += tls.stats.pop.help  .success;
    321                 global_stats.pop.local .attempt += tls.stats.pop.local .attempt;
    322                 global_stats.pop.local .elock   += tls.stats.pop.local .elock  ;
    323                 global_stats.pop.local .eempty  += tls.stats.pop.local .eempty ;
    324                 global_stats.pop.local .espec   += tls.stats.pop.local .espec  ;
    325                 global_stats.pop.local .success += tls.stats.pop.local .success;
    326                 global_stats.pop.steal .attempt += tls.stats.pop.steal .attempt;
    327                 global_stats.pop.steal .elock   += tls.stats.pop.steal .elock  ;
    328                 global_stats.pop.steal .eempty  += tls.stats.pop.steal .eempty ;
    329                 global_stats.pop.steal .espec   += tls.stats.pop.steal .espec  ;
    330                 global_stats.pop.steal .success += tls.stats.pop.steal .success;
    331                 global_stats.pop.search.attempt += tls.stats.pop.search.attempt;
    332                 global_stats.pop.search.elock   += tls.stats.pop.search.elock  ;
    333                 global_stats.pop.search.eempty  += tls.stats.pop.search.eempty ;
    334                 global_stats.pop.search.espec   += tls.stats.pop.search.espec  ;
    335                 global_stats.pop.search.success += tls.stats.pop.search.success;
    336                 global_stats.help += tls.stats.help;
    337         }
    338 
    339         static void stats_print(std::ostream & os, double duration ) {
     200                global_stats.push.nhint += tls.stat.push.nhint;
     201                global_stats.pop.local.success += tls.stat.pop.local.success;
     202                global_stats.pop.local.espec   += tls.stat.pop.local.espec  ;
     203                global_stats.pop.local.elock   += tls.stat.pop.local.elock  ;
     204                global_stats.pop.steal.tried   += tls.stat.pop.steal.tried  ;
     205                global_stats.pop.steal.locked  += tls.stat.pop.steal.locked ;
     206                global_stats.pop.steal.empty   += tls.stat.pop.steal.empty  ;
     207                global_stats.pop.steal.success += tls.stat.pop.steal.success;
     208        }
     209
     210        static void stats_print(std::ostream & os ) {
    340211                std::cout << "----- Work Stealing Stats -----" << std::endl;
    341212
    342                 double push_suc = (100.0 * double(global_stats.push.success) / global_stats.push.attempt);
    343                 double push_len = double(global_stats.push.attempt     ) / global_stats.push.success;
    344                 os << "Push   Pick : " << push_suc << " %, len " << push_len << " (" << global_stats.push.attempt      << " / " << global_stats.push.success << ")\n";
    345 
    346                 double hlp_suc = (100.0 * double(global_stats.pop.help.success) / global_stats.pop.help.attempt);
    347                 double hlp_len = double(global_stats.pop.help.attempt     ) / global_stats.pop.help.success;
    348                 os << "Help        : " << hlp_suc << " %, len " << hlp_len << " (" << global_stats.pop.help.attempt      << " / " << global_stats.pop.help.success << ")\n";
    349                 os << "Help Fail   : " << global_stats.pop.help.espec << "s, " << global_stats.pop.help.eempty << "e, " << global_stats.pop.help.elock << "l\n";
    350 
    351                 double pop_suc = (100.0 * double(global_stats.pop.local.success) / global_stats.pop.local.attempt);
    352                 double pop_len = double(global_stats.pop.local.attempt     ) / global_stats.pop.local.success;
    353                 os << "Local       : " << pop_suc << " %, len " << pop_len << " (" << global_stats.pop.local.attempt      << " / " << global_stats.pop.local.success << ")\n";
    354                 os << "Local Fail  : " << global_stats.pop.local.espec << "s, " << global_stats.pop.local.eempty << "e, " << global_stats.pop.local.elock << "l\n";
    355 
    356                 double stl_suc = (100.0 * double(global_stats.pop.steal.success) / global_stats.pop.steal.attempt);
    357                 double stl_len = double(global_stats.pop.steal.attempt     ) / global_stats.pop.steal.success;
    358                 os << "Steal       : " << stl_suc << " %, len " << stl_len << " (" << global_stats.pop.steal.attempt      << " / " << global_stats.pop.steal.success << ")\n";
    359                 os << "Steal Fail  : " << global_stats.pop.steal.espec << "s, " << global_stats.pop.steal.eempty << "e, " << global_stats.pop.steal.elock << "l\n";
    360 
    361                 double srh_suc = (100.0 * double(global_stats.pop.search.success) / global_stats.pop.search.attempt);
    362                 double srh_len = double(global_stats.pop.search.attempt     ) / global_stats.pop.search.success;
    363                 os << "Search      : " << srh_suc << " %, len " << srh_len << " (" << global_stats.pop.search.attempt      << " / " << global_stats.pop.search.success << ")\n";
    364                 os << "Search Fail : " << global_stats.pop.search.espec << "s, " << global_stats.pop.search.eempty << "e, " << global_stats.pop.search.elock << "l\n";
    365                 os << "Helps       : " << std::setw(15) << std::scientific << global_stats.help / duration << "/sec (" << global_stats.help  << ")\n";
     213                double stealSucc = double(global_stats.pop.steal.success) / global_stats.pop.steal.tried;
     214                os << "Push to new Q : " << std::setw(15) << global_stats.push.nhint << "\n";
     215                os << "Local Pop     : " << std::setw(15) << global_stats.pop.local.success << "\n";
     216                os << "Steal Pop     : " << std::setw(15) << global_stats.pop.steal.success << "(" << global_stats.pop.local.espec << "s, " << global_stats.pop.local.elock << "l)\n";
     217                os << "Steal Success : " << std::setw(15) << stealSucc << "(" << global_stats.pop.steal.tried << " tries)\n";
     218                os << "Steal Fails   : " << std::setw(15) << global_stats.pop.steal.empty << "e, " << global_stats.pop.steal.locked << "l\n";
    366219        }
    367220private:
  • libcfa/prelude/builtins.c

    rc8a0210 r857a1c6  
    99// Author           : Peter A. Buhr
    1010// Created On       : Fri Jul 21 16:21:03 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 13 17:26:32 2021
    13 // Update Count     : 117
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct 27 14:42:00 2020
     13// Update Count     : 111
    1414//
    1515
     
    125125} // distribution
    126126
    127 #define __CFA_BASE_COMP_1__() if ( x == 1 ) return 1
    128 #define __CFA_BASE_COMP_2__() if ( x == 2 ) return x << (y - 1)
     127#define __CFA_BASE_COMP_1__() if ( ep == 1 ) return 1
     128#define __CFA_BASE_COMP_2__() if ( ep == 2 ) return ep << (y - 1)
    129129#define __CFA_EXP_OVERFLOW__() if ( y >= sizeof(y) * CHAR_BIT ) return 0
    130130
     
    134134        __CFA_BASE_COMP_2__();                                                          /* special case, positive shifting for integral types */ \
    135135        __CFA_EXP_OVERFLOW__();                                                         /* immediate overflow, negative exponent > 2^size-1 */ \
    136         typeof(x) op = 1;                                                                       /* accumulate odd product */ \
     136        typeof(ep) op = 1;                                                                      /* accumulate odd product */ \
    137137        for ( ; y > 1; y >>= 1 ) {                                                      /* squaring exponentiation, O(log2 y) */ \
    138                 if ( (y & 1) == 1 ) op = op * x;                                /* odd ? */ \
    139                 x = x * x; \
     138                if ( (y & 1) == 1 ) op = op * ep;                               /* odd ? */ \
     139                ep = ep * ep; \
    140140        } \
    141         return x * op
     141        return ep * op
    142142
    143143static inline {
    144         long int ?\?( int x, unsigned int y ) { __CFA_EXP__(); }
    145         long int ?\?( long int x, unsigned long int y ) { __CFA_EXP__(); }
    146         long long int ?\?( long long int x, unsigned long long int y ) { __CFA_EXP__(); }
     144        long int ?\?( int ep, unsigned int y ) { __CFA_EXP__(); }
     145        long int ?\?( long int ep, unsigned long int y ) { __CFA_EXP__(); }
    147146        // unsigned computation may be faster and larger
    148         unsigned long int ?\?( unsigned int x, unsigned int y ) { __CFA_EXP__(); }
    149         unsigned long int ?\?( unsigned long int x, unsigned long int y ) { __CFA_EXP__(); }
    150         unsigned long long int ?\?( unsigned long long int x, unsigned long long int y ) { __CFA_EXP__(); }
     147        unsigned long int ?\?( unsigned int ep, unsigned int y ) { __CFA_EXP__(); }
     148        unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { __CFA_EXP__(); }
    151149} // distribution
    152150
     
    159157
    160158static inline forall( OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) {
    161         OT ?\?( OT x, unsigned int y ) { __CFA_EXP__(); }
    162         OT ?\?( OT x, unsigned long int y ) { __CFA_EXP__(); }
    163         OT ?\?( OT x, unsigned long long int y ) { __CFA_EXP__(); }
     159        OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); }
     160        OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); }
    164161} // distribution
    165162
     
    169166
    170167static inline {
    171         long int ?\=?( int & x, unsigned int y ) { x = x \ y; return x; }
    172168        long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; }
    173         long long int ?\=?( long long int & x, unsigned long long int y ) { x = x \ y; return x; }
    174         unsigned long int ?\=?( unsigned int & x, unsigned int y ) { x = x \ y; return x; }
    175169        unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; }
    176         unsigned long long int ?\=?( unsigned long long int & x, unsigned long long int y ) { x = x \ y; return x; }
     170        int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; }
     171        unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; }
    177172} // distribution
    178173
  • libcfa/src/bits/weakso_locks.cfa

    rc8a0210 r857a1c6  
    2525void unlock( blocking_lock & ) {}
    2626void on_notify( blocking_lock &, struct $thread * ) {}
    27 size_t on_wait( blocking_lock & ) { return 0; }
     27size_t on_wait( blocking_lock & ) {}
    2828void on_wakeup( blocking_lock &, size_t ) {}
    2929size_t wait_count( blocking_lock & ) { return 0; }
  • libcfa/src/clock.hfa

    rc8a0210 r857a1c6  
    1010// Created On       : Thu Apr 12 14:36:06 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 14 17:48:25 2021
    13 // Update Count     : 20
     12// Last Modified On : Mon Jan  6 12:49:58 2020
     13// Update Count     : 9
    1414//
    1515
     
    3232
    3333static inline {
    34         void reset( Clock & clk, Duration adj ) with( clk ) {
     34        void resetClock( Clock & clk, Duration adj ) with( clk ) {
    3535                offset = adj + __timezone`s;                                    // timezone (global) is (UTC - local time) in seconds
    36         } // reset
     36        } // resetClock
    3737
    38         void ?{}( Clock & clk ) { reset( clk, (Duration){ 0 } ); }
    39         void ?{}( Clock & clk, Duration adj ) { reset( clk, adj ); }
     38        void ?{}( Clock & clk, Duration adj ) { resetClock( clk, adj ); }
    4039
    41         // System-wide clock that measures real, i.e., wall-clock) time. This clock is affected by discontinuous jumps in
    42         // the system time. For example, manual changes of the clock, and incremental adjustments performed by adjtime(3)
    43         // and NTP (daylight saving (Fall back).
    44         Duration resolutionNsec() {
     40        Duration getResNsec() {
    4541                struct timespec res;
    4642                clock_getres( CLOCK_REALTIME, &res );
    4743                return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns;
    48         } // resolutionNsec
     44        } // getRes
    4945
    50         Duration resolution() {
     46        Duration getRes() {
    5147                struct timespec res;
    5248                clock_getres( CLOCK_REALTIME_COARSE, &res );
    5349                return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns;
    54         } // resolution
     50        } // getRes
    5551
    56         Time timeNsec() {                                                                       // with nanoseconds
     52        Time getTimeNsec() {                                                            // with nanoseconds
    5753                timespec curr;
    5854                clock_gettime( CLOCK_REALTIME, &curr );
    5955                return (Time){ curr };
    60         } // timeNsec
     56        } // getTimeNsec
    6157
    62         Time time() {                                                                           // without nanoseconds
     58        Time getTime() {                                                                        // without nanoseconds
    6359                timespec curr;
    6460                clock_gettime( CLOCK_REALTIME_COARSE, &curr );
    6561                curr.tv_nsec = 0;
    6662                return (Time){ curr };
    67         } // time
     63        } // getTime
    6864
    69         Time time( Clock & clk ) with( clk ) {
    70                 return time() + offset;
    71         } // time
     65        Time getTime( Clock & clk ) with( clk ) {
     66                return getTime() + offset;
     67        } // getTime
    7268
    7369        Time ?()( Clock & clk ) with( clk ) {                           // alternative syntax
    74                 return time() + offset;
    75         } // ?()
     70                return getTime() + offset;
     71        } // getTime
    7672
    77         timeval time( Clock & clk ) {
     73        timeval getTime( Clock & clk ) {
    7874                return (timeval){ clk() };
    79         } // time
     75        } // getTime
    8076
    81         tm time( Clock & clk ) with( clk ) {
     77        tm getTime( Clock & clk ) with( clk ) {
    8278                tm ret;
    83                 localtime_r( time( clk ).tv_sec, &ret );
     79                localtime_r( getTime( clk ).tv_sec, &ret );
    8480                return ret;
    85         } // time
     81        } // getTime
    8682
    87         // CFA processor CPU-time watch that ticks when the processor (kernel thread) is running. This watch is affected by
    88         // discontinuous jumps when the OS is not running the kernal thread. A duration is returned because the value is
    89         // relative and cannot be converted to real-time (wall-clock) time.
    90         Duration processor() {
     83        Time getCPUTime() {
    9184                timespec ts;
    9285                clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts );
    93                 return (Duration){ ts };
    94         } // processor
    95 
    96         // Program CPU-time watch measures CPU time consumed by all processors (kernel threads) in the UNIX process.  This
    97         // watch is affected by discontinuous jumps when the OS is not running the kernel threads. A duration is returned
    98         // because the value is relative and cannot be converted to real-time (wall-clock) time.
    99         Duration program() {
    100                 timespec ts;
    101                 clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &ts );
    102                 return (Duration){ ts };
    103         } // program
    104 
    105         // Monotonic stopwatch starting at machine boot and includes system suspension. This watch is unaffected by
    106         // discontinuous jumps resulting from manual changes of the clock, and incremental adjustments performed by
    107         // adjtime(3) and NTP (Fall back). A duration is returned because the value is relative and cannot be converted to
    108         // real-time (wall-clock) time.
    109         Duration boot() {
    110                 timespec ts;
    111                 clock_gettime( CLOCK_BOOTTIME, &ts );
    112                 return (Duration){ ts };
    113         } // boot
     86                return (Time){ ts };
     87    } // getCPUTime
    11488} // distribution
    11589
  • libcfa/src/concurrency/coroutine.cfa

    rc8a0210 r857a1c6  
    4646
    4747//-----------------------------------------------------------------------------
    48 EHM_VIRTUAL_TABLE(SomeCoroutineCancelled, std_coroutine_cancelled);
     48FORALL_DATA_INSTANCE(CoroutineCancelled, (coroutine_t &), (coroutine_t))
     49
     50forall(T &)
     51void mark_exception(CoroutineCancelled(T) *) {}
    4952
    5053forall(T &)
     
    6871
    6972        // TODO: Remove explitate vtable set once trac#186 is fixed.
    70         SomeCoroutineCancelled except;
    71         except.virtual_table = &std_coroutine_cancelled;
     73        CoroutineCancelled(T) except;
     74        except.virtual_table = &get_exception_vtable(&except);
    7275        except.the_coroutine = &cor;
    7376        except.the_exception = except;
    74         // Why does this need a cast?
    75         throwResume (SomeCoroutineCancelled &)except;
     77        throwResume except;
    7678
    7779        except->virtual_table->free( except );
  • libcfa/src/concurrency/coroutine.hfa

    rc8a0210 r857a1c6  
    2222//-----------------------------------------------------------------------------
    2323// Exception thrown from resume when a coroutine stack is cancelled.
    24 EHM_EXCEPTION(SomeCoroutineCancelled)(
    25         void * the_coroutine;
    26         exception_t * the_exception;
    27 );
    28 
    29 EHM_EXTERN_VTABLE(SomeCoroutineCancelled, std_coroutine_cancelled);
    30 
    31 EHM_FORALL_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (
     24FORALL_DATA_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (
    3225        coroutine_t * the_coroutine;
    3326        exception_t * the_exception;
     
    4437// Anything that implements this trait can be resumed.
    4538// Anything that is resumed is a coroutine.
    46 trait is_coroutine(T & | IS_RESUMPTION_EXCEPTION(SomeCoroutineCancelled)) {
     39trait is_coroutine(T & | IS_RESUMPTION_EXCEPTION(CoroutineCancelled, (T))) {
    4740        void main(T & this);
    4841        $coroutine * get_coroutine(T & this);
  • libcfa/src/concurrency/invoke.h

    rc8a0210 r857a1c6  
    148148                struct $thread * prev;
    149149                volatile unsigned long long ts;
     150                int preferred;
    150151        };
    151152
  • libcfa/src/concurrency/io/call.cfa.in

    rc8a0210 r857a1c6  
    201201
    202202                sqe->opcode = IORING_OP_{op};
    203                 sqe->user_data = (uintptr_t)&future;
     203                sqe->user_data = (__u64)(uintptr_t)&future;
    204204                sqe->flags = sflags;
    205205                sqe->ioprio = 0;
     
    215215                asm volatile("": : :"memory");
    216216
    217                 verify( sqe->user_data == (uintptr_t)&future );
     217                verify( sqe->user_data == (__u64)(uintptr_t)&future );
    218218                cfa_io_submit( ctx, &idx, 1, 0 != (submit_flags & CFA_IO_LAZY) );
    219219        #endif
     
    238238                'fd'  : 'fd',
    239239                'off' : 'offset',
    240                 'addr': '(uintptr_t)iov',
     240                'addr': '(__u64)iov',
    241241                'len' : 'iovcnt',
    242242        }, define = 'CFA_HAVE_PREADV2'),
     
    245245                'fd'  : 'fd',
    246246                'off' : 'offset',
    247                 'addr': '(uintptr_t)iov',
     247                'addr': '(__u64)iov',
    248248                'len' : 'iovcnt'
    249249        }, define = 'CFA_HAVE_PWRITEV2'),
     
    257257                'addr': 'fd',
    258258                'len': 'op',
    259                 'off': '(uintptr_t)event'
     259                'off': '(__u64)event'
    260260        }),
    261261        # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE
     
    269269        Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)', {
    270270                'fd': 'sockfd',
    271                 'addr': '(uintptr_t)(struct msghdr *)msg',
     271                'addr': '(__u64)(struct msghdr *)msg',
    272272                'len': '1',
    273273                'msg_flags': 'flags'
     
    276276        Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)', {
    277277                'fd': 'sockfd',
    278                 'addr': '(uintptr_t)(struct msghdr *)msg',
     278                'addr': '(__u64)(struct msghdr *)msg',
    279279                'len': '1',
    280280                'msg_flags': 'flags'
     
    283283        Call('SEND', 'ssize_t send(int sockfd, const void *buf, size_t len, int flags)', {
    284284                'fd': 'sockfd',
    285                 'addr': '(uintptr_t)buf',
     285                'addr': '(__u64)buf',
    286286                'len': 'len',
    287287                'msg_flags': 'flags'
     
    290290        Call('RECV', 'ssize_t recv(int sockfd, void *buf, size_t len, int flags)', {
    291291                'fd': 'sockfd',
    292                 'addr': '(uintptr_t)buf',
     292                'addr': '(__u64)buf',
    293293                'len': 'len',
    294294                'msg_flags': 'flags'
     
    297297        Call('ACCEPT', 'int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)', {
    298298                'fd': 'sockfd',
    299                 'addr': '(uintptr_t)addr',
    300                 'addr2': '(uintptr_t)addrlen',
     299                'addr': '(__u64)addr',
     300                'addr2': '(__u64)addrlen',
    301301                'accept_flags': 'flags'
    302302        }),
     
    304304        Call('CONNECT', 'int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)', {
    305305                'fd': 'sockfd',
    306                 'addr': '(uintptr_t)addr',
     306                'addr': '(__u64)addr',
    307307                'off': 'addrlen'
    308308        }),
     
    310310        Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', {
    311311                'fd': 'fd',
    312                 'addr': '(uintptr_t)len',
     312                'addr': '(__u64)len',
    313313                'len': 'mode',
    314314                'off': 'offset'
     
    323323        # CFA_HAVE_IORING_OP_MADVISE
    324324        Call('MADVISE', 'int madvise(void *addr, size_t length, int advice)', {
    325                 'addr': '(uintptr_t)addr',
     325                'addr': '(__u64)addr',
    326326                'len': 'length',
    327327                'fadvise_advice': 'advice'
     
    330330        Call('OPENAT', 'int openat(int dirfd, const char *pathname, int flags, mode_t mode)', {
    331331                'fd': 'dirfd',
    332                 'addr': '(uintptr_t)pathname',
     332                'addr': '(__u64)pathname',
    333333                'len': 'mode',
    334334                'open_flags': 'flags;'
     
    339339                'addr': 'pathname',
    340340                'len': 'sizeof(*how)',
    341                 'off': '(uintptr_t)how',
     341                'off': '(__u64)how',
    342342        }, define = 'CFA_HAVE_OPENAT2'),
    343343        # CFA_HAVE_IORING_OP_CLOSE
     
    348348        Call('STATX', 'int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf)', {
    349349                'fd': 'dirfd',
    350                 'off': '(uintptr_t)statxbuf',
     350                'off': '(__u64)statxbuf',
    351351                'addr': 'pathname',
    352352                'len': 'mask',
     
    356356        Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', {
    357357                'fd': 'fd',
    358                 'addr': '(uintptr_t)buf',
     358                'addr': '(__u64)buf',
    359359                'len': 'count'
    360360        }),
     
    362362        Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', {
    363363                'fd': 'fd',
    364                 'addr': '(uintptr_t)buf',
     364                'addr': '(__u64)buf',
    365365                'len': 'count'
    366366        }),
  • libcfa/src/concurrency/kernel.cfa

    rc8a0210 r857a1c6  
    113113static void __wake_one(cluster * cltr);
    114114
    115 static void mark_idle (__cluster_proc_list & idles, processor & proc);
    116 static void mark_awake(__cluster_proc_list & idles, processor & proc);
    117 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list idles );
     115static void push  (__cluster_idles & idles, processor & proc);
     116static void remove(__cluster_idles & idles, processor & proc);
     117static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles );
    118118
    119119extern void __cfa_io_start( processor * );
     
    189189
    190190                                // Push self to idle stack
    191                                 mark_idle(this->cltr->procs, * this);
     191                                push(this->cltr->idles, * this);
    192192
    193193                                // Confirm the ready-queue is empty
     
    195195                                if( readyThread ) {
    196196                                        // A thread was found, cancel the halt
    197                                         mark_awake(this->cltr->procs, * this);
     197                                        remove(this->cltr->idles, * this);
    198198
    199199                                        #if !defined(__CFA_NO_STATISTICS__)
     
    225225
    226226                                // We were woken up, remove self from idle
    227                                 mark_awake(this->cltr->procs, * this);
     227                                remove(this->cltr->idles, * this);
    228228
    229229                                // DON'T just proceed, start looking again
     
    359359                                #if !defined(__CFA_NO_STATISTICS__)
    360360                                        __tls_stats()->ready.threads.threads++;
    361                                         __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );
    362361                                #endif
    363362                                // This is case 2, the racy case, someone tried to run this thread before it finished blocking
     
    377376        #if !defined(__CFA_NO_STATISTICS__)
    378377                __tls_stats()->ready.threads.threads--;
    379                 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );
    380378        #endif
    381379
     
    457455                if( kernelTLS().this_stats ) {
    458456                        __tls_stats()->ready.threads.threads++;
    459                         __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", kernelTLS().this_processor );
    460457                }
    461458                else {
    462459                        __atomic_fetch_add(&cl->stats->ready.threads.threads, 1, __ATOMIC_RELAXED);
    463                         __push_stat( cl->stats, cl->stats->ready.threads.threads, true, "Cluster", cl );
    464460                }
    465461        #endif
     
    474470
    475471        ready_schedule_lock();
    476                 $thread * thrd = pop_fast( this );
     472                $thread * thrd = pop( this );
    477473        ready_schedule_unlock();
    478474
     
    617613        unsigned idle;
    618614        unsigned total;
    619         [idle, total, p] = query_idles(this->procs);
     615        [idle, total, p] = query(this->idles);
    620616
    621617        // If no one is sleeping, we are done
     
    654650}
    655651
    656 static void mark_idle(__cluster_proc_list & this, processor & proc) {
     652static void push  (__cluster_idles & this, processor & proc) {
    657653        /* paranoid */ verify( ! __preemption_enabled() );
    658654        lock( this );
    659655                this.idle++;
    660656                /* paranoid */ verify( this.idle <= this.total );
    661                 remove(proc);
    662                 insert_first(this.idles, proc);
     657
     658                insert_first(this.list, proc);
    663659        unlock( this );
    664660        /* paranoid */ verify( ! __preemption_enabled() );
    665661}
    666662
    667 static void mark_awake(__cluster_proc_list & this, processor & proc) {
     663static void remove(__cluster_idles & this, processor & proc) {
    668664        /* paranoid */ verify( ! __preemption_enabled() );
    669665        lock( this );
    670666                this.idle--;
    671667                /* paranoid */ verify( this.idle >= 0 );
     668
    672669                remove(proc);
    673                 insert_last(this.actives, proc);
    674670        unlock( this );
    675671        /* paranoid */ verify( ! __preemption_enabled() );
    676672}
    677673
    678 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list this ) {
    679         /* paranoid */ verify( ! __preemption_enabled() );
    680         /* paranoid */ verify( ready_schedule_islocked() );
    681 
     674static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) {
    682675        for() {
    683676                uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
     
    685678                unsigned idle    = this.idle;
    686679                unsigned total   = this.total;
    687                 processor * proc = &this.idles`first;
     680                processor * proc = &this.list`first;
    688681                // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it
    689682                asm volatile("": : :"memory");
     
    691684                return [idle, total, proc];
    692685        }
    693 
    694         /* paranoid */ verify( ready_schedule_islocked() );
    695         /* paranoid */ verify( ! __preemption_enabled() );
    696686}
    697687
  • libcfa/src/concurrency/kernel.hfa

    rc8a0210 r857a1c6  
    6969        struct cluster * cltr;
    7070
    71         // Ready Queue state per processor
    72         struct {
    73                 unsigned short its;
    74                 unsigned short itr;
    75                 unsigned id;
    76                 unsigned target;
    77                 unsigned long long int cutoff;
    78         } rdq;
     71        // Id within the cluster
     72        unsigned cltr_id;
    7973
    8074        // Set to true to notify the processor should terminate
     
    146140// Cluster Tools
    147141
    148 // Intrusives lanes which are used by the ready queue
     142// Intrusives lanes which are used by the relaxed ready queue
    149143struct __attribute__((aligned(128))) __intrusive_lane_t;
    150144void  ?{}(__intrusive_lane_t & this);
    151145void ^?{}(__intrusive_lane_t & this);
    152146
    153 // Aligned timestamps which are used by the relaxed ready queue
    154 struct __attribute__((aligned(128))) __timestamp_t;
    155 void  ?{}(__timestamp_t & this);
    156 void ^?{}(__timestamp_t & this);
     147// Counter used for wether or not the lanes are all empty
     148struct __attribute__((aligned(128))) __snzi_node_t;
     149struct __snzi_t {
     150        unsigned mask;
     151        int root;
     152        __snzi_node_t * nodes;
     153};
     154
     155void  ?{}( __snzi_t & this, unsigned depth );
     156void ^?{}( __snzi_t & this );
    157157
    158158//TODO adjust cache size to ARCHITECTURE
    159159// Structure holding the relaxed ready queue
    160160struct __ready_queue_t {
     161        // Data tracking how many/which lanes are used
     162        // Aligned to 128 for cache locality
     163        __snzi_t snzi;
     164
    161165        // Data tracking the actual lanes
    162166        // On a seperate cacheline from the used struct since
     
    167171                __intrusive_lane_t * volatile data;
    168172
    169                 // Array of times
    170                 __timestamp_t * volatile tscs;
    171 
    172173                // Number of lanes (empty or not)
    173174                volatile size_t count;
     
    179180
    180181// Idle Sleep
    181 struct __cluster_proc_list {
     182struct __cluster_idles {
    182183        // Spin lock protecting the queue
    183184        volatile uint64_t lock;
     
    190191
    191192        // List of idle processors
    192         dlist(processor, processor) idles;
    193 
    194         // List of active processors
    195         dlist(processor, processor) actives;
     193        dlist(processor, processor) list;
    196194};
    197195
     
    209207
    210208        // List of idle processors
    211         __cluster_proc_list procs;
     209        __cluster_idles idles;
    212210
    213211        // List of threads
  • libcfa/src/concurrency/kernel/startup.cfa

    rc8a0210 r857a1c6  
    268268                        __print_stats( st, mainProcessor->print_stats, "Processor ", mainProcessor->name, (void*)mainProcessor );
    269269                }
    270                 #if defined(CFA_STATS_ARRAY)
    271                         __flush_stat( st, "Processor", mainProcessor );
    272                 #endif
    273270        #endif
    274271
     
    351348                        __print_stats( &local_stats, proc->print_stats, "Processor ", proc->name, (void*)proc );
    352349                }
    353                 #if defined(CFA_STATS_ARRAY)
    354                         __flush_stat( &local_stats, "Processor", proc );
    355                 #endif
    356350        #endif
    357351
     
    469463        this.name = name;
    470464        this.cltr = &_cltr;
    471         this.rdq.its = 0;
    472         this.rdq.itr = 0;
    473         this.rdq.id  = -1u;
    474         this.rdq.target = -1u;
    475         this.rdq.cutoff = -1ull;
    476465        do_terminate = false;
    477466        preemption_alarm = 0p;
     
    494483        #endif
    495484
    496         // Register and Lock the RWlock so no-one pushes/pops while we are changing the queue
    497         uint_fast32_t last_size = ready_mutate_register((__processor_id_t*)&this);
    498                 this.cltr->procs.total += 1u;
    499                 insert_last(this.cltr->procs.actives, this);
     485        lock( this.cltr->idles );
     486                int target = this.cltr->idles.total += 1u;
     487        unlock( this.cltr->idles );
     488
     489        id = doregister((__processor_id_t*)&this);
     490
     491        // Lock the RWlock so no-one pushes/pops while we are changing the queue
     492        uint_fast32_t last_size = ready_mutate_lock();
    500493
    501494                // Adjust the ready queue size
    502                 ready_queue_grow( cltr );
     495                this.cltr_id = ready_queue_grow( cltr, target );
    503496
    504497        // Unlock the RWlock
     
    510503// Not a ctor, it just preps the destruction but should not destroy members
    511504static void deinit(processor & this) {
     505        lock( this.cltr->idles );
     506                int target = this.cltr->idles.total -= 1u;
     507        unlock( this.cltr->idles );
     508
    512509        // Lock the RWlock so no-one pushes/pops while we are changing the queue
    513510        uint_fast32_t last_size = ready_mutate_lock();
    514                 this.cltr->procs.total -= 1u;
    515                 remove(this);
    516511
    517512                // Adjust the ready queue size
    518                 ready_queue_shrink( this.cltr );
    519 
    520         // Unlock the RWlock and unregister: we don't need the read_lock any more
    521         ready_mutate_unregister((__processor_id_t*)&this, last_size );
     513                ready_queue_shrink( this.cltr, target );
     514
     515        // Unlock the RWlock
     516        ready_mutate_unlock( last_size );
     517
     518        // Finally we don't need the read_lock any more
     519        unregister((__processor_id_t*)&this);
    522520
    523521        close(this.idle);
     
    562560//-----------------------------------------------------------------------------
    563561// Cluster
    564 static void ?{}(__cluster_proc_list & this) {
     562static void ?{}(__cluster_idles & this) {
    565563        this.lock  = 0;
    566564        this.idle  = 0;
    567565        this.total = 0;
     566        (this.list){};
    568567}
    569568
     
    591590
    592591                // Adjust the ready queue size
    593                 ready_queue_grow( &this );
     592                ready_queue_grow( &this, 0 );
    594593
    595594        // Unlock the RWlock
     
    606605
    607606                // Adjust the ready queue size
    608                 ready_queue_shrink( &this );
     607                ready_queue_shrink( &this, 0 );
    609608
    610609        // Unlock the RWlock
     
    616615                        __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this );
    617616                }
    618                 #if defined(CFA_STATS_ARRAY)
    619                         __flush_stat( this.stats, "Cluster", &this );
    620                 #endif
    621617                free( this.stats );
    622618        #endif
  • libcfa/src/concurrency/kernel_private.hfa

    rc8a0210 r857a1c6  
    8383// Cluster lock API
    8484//=======================================================================
     85// Cells use by the reader writer lock
     86// while not generic it only relies on a opaque pointer
     87struct __attribute__((aligned(128))) __scheduler_lock_id_t {
     88        // Spin lock used as the underlying lock
     89        volatile bool lock;
     90
     91        // Handle pointing to the proc owning this cell
     92        // Used for allocating cells and debugging
     93        __processor_id_t * volatile handle;
     94
     95        #ifdef __CFA_WITH_VERIFY__
     96                // Debug, check if this is owned for reading
     97                bool owned;
     98        #endif
     99};
     100
     101static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
     102
    85103// Lock-Free registering/unregistering of threads
    86104// Register a processor to a given cluster and get its unique id in return
    87 void register_proc_id( struct __processor_id_t * );
     105unsigned doregister( struct __processor_id_t * proc );
    88106
    89107// Unregister a processor from a given cluster using its id, getting back the original pointer
    90 void unregister_proc_id( struct __processor_id_t * proc );
     108void     unregister( struct __processor_id_t * proc );
     109
     110//-----------------------------------------------------------------------
     111// Cluster idle lock/unlock
     112static inline void lock(__cluster_idles & this) {
     113        for() {
     114                uint64_t l = this.lock;
     115                if(
     116                        (0 == (l % 2))
     117                        && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
     118                ) return;
     119                Pause();
     120        }
     121}
     122
     123static inline void unlock(__cluster_idles & this) {
     124        /* paranoid */ verify( 1 == (this.lock % 2) );
     125        __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
     126}
    91127
    92128//=======================================================================
     
    116152        __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE);
    117153}
    118 
    119 // Cells use by the reader writer lock
    120 // while not generic it only relies on a opaque pointer
    121 struct __attribute__((aligned(128))) __scheduler_lock_id_t {
    122         // Spin lock used as the underlying lock
    123         volatile bool lock;
    124 
    125         // Handle pointing to the proc owning this cell
    126         // Used for allocating cells and debugging
    127         __processor_id_t * volatile handle;
    128 
    129         #ifdef __CFA_WITH_VERIFY__
    130                 // Debug, check if this is owned for reading
    131                 bool owned;
    132         #endif
    133 };
    134 
    135 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
    136154
    137155//-----------------------------------------------------------------------
     
    229247void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ );
    230248
    231 //-----------------------------------------------------------------------
    232 // Lock-Free registering/unregistering of threads
    233 // Register a processor to a given cluster and get its unique id in return
    234 // For convenience, also acquires the lock
    235 static inline uint_fast32_t ready_mutate_register( struct __processor_id_t * proc ) {
    236         register_proc_id( proc );
    237         return ready_mutate_lock();
    238 }
    239 
    240 // Unregister a processor from a given cluster using its id, getting back the original pointer
    241 // assumes the lock is acquired
    242 static inline void ready_mutate_unregister( struct __processor_id_t * proc, uint_fast32_t last_s ) {
    243         ready_mutate_unlock( last_s );
    244         unregister_proc_id( proc );
    245 }
    246 
    247 //-----------------------------------------------------------------------
    248 // Cluster idle lock/unlock
    249 static inline void lock(__cluster_proc_list & this) {
    250         /* paranoid */ verify( ! __preemption_enabled() );
    251 
    252         // Start by locking the global RWlock so that we know no-one is
    253         // adding/removing processors while we mess with the idle lock
    254         ready_schedule_lock();
    255 
    256         // Simple counting lock, acquired, acquired by incrementing the counter
    257         // to an odd number
    258         for() {
    259                 uint64_t l = this.lock;
    260                 if(
    261                         (0 == (l % 2))
    262                         && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
    263                 ) return;
    264                 Pause();
    265         }
    266 
    267         /* paranoid */ verify( ! __preemption_enabled() );
    268 }
    269 
    270 static inline void unlock(__cluster_proc_list & this) {
    271         /* paranoid */ verify( ! __preemption_enabled() );
    272 
    273         /* paranoid */ verify( 1 == (this.lock % 2) );
    274         // Simple couting lock, release by incrementing to an even number
    275         __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
    276 
    277         // Release the global lock, which we acquired when locking
    278         ready_schedule_unlock();
    279 
    280         /* paranoid */ verify( ! __preemption_enabled() );
    281 }
    282 
    283249//=======================================================================
    284250// Ready-Queue API
     251//-----------------------------------------------------------------------
     252// pop thread from the ready queue of a cluster
     253// returns 0p if empty
     254__attribute__((hot)) bool query(struct cluster * cltr);
     255
    285256//-----------------------------------------------------------------------
    286257// push thread onto a ready queue for a cluster
    287258// returns true if the list was previously empty, false otherwise
    288 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd);
     259__attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd);
    289260
    290261//-----------------------------------------------------------------------
     
    292263// returns 0p if empty
    293264// May return 0p spuriously
    294 __attribute__((hot)) struct $thread * pop_fast(struct cluster * cltr);
     265__attribute__((hot)) struct $thread * pop(struct cluster * cltr);
    295266
    296267//-----------------------------------------------------------------------
     
    301272
    302273//-----------------------------------------------------------------------
     274// remove thread from the ready queue of a cluster
     275// returns bool if it wasn't found
     276bool remove_head(struct cluster * cltr, struct $thread * thrd);
     277
     278//-----------------------------------------------------------------------
    303279// Increase the width of the ready queue (number of lanes) by 4
    304 void ready_queue_grow  (struct cluster * cltr);
     280unsigned ready_queue_grow  (struct cluster * cltr, int target);
    305281
    306282//-----------------------------------------------------------------------
    307283// Decrease the width of the ready queue (number of lanes) by 4
    308 void ready_queue_shrink(struct cluster * cltr);
     284void ready_queue_shrink(struct cluster * cltr, int target);
    309285
    310286
  • libcfa/src/concurrency/preemption.cfa

    rc8a0210 r857a1c6  
    712712static void * alarm_loop( __attribute__((unused)) void * args ) {
    713713        __processor_id_t id;
    714         register_proc_id(&id);
     714        id.id = doregister(&id);
    715715        __cfaabi_tls.this_proc_id = &id;
    716716
     
    773773EXIT:
    774774        __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" );
    775         register_proc_id(&id);
     775        unregister(&id);
    776776
    777777        return 0p;
  • libcfa/src/concurrency/ready_queue.cfa

    rc8a0210 r857a1c6  
    1717// #define __CFA_DEBUG_PRINT_READY_QUEUE__
    1818
     19// #define USE_SNZI
    1920// #define USE_MPSC
    20 
    21 #define USE_RELAXED_FIFO
    22 // #define USE_WORK_STEALING
    2321
    2422#include "bits/defs.hfa"
     
    3129#include <unistd.h>
    3230
     31#include "snzi.hfa"
    3332#include "ready_subqueue.hfa"
    3433
     
    4140#endif
    4241
    43 #if   defined(USE_RELAXED_FIFO)
    44         #define BIAS 4
    45         #define READYQ_SHARD_FACTOR 4
    46         #define SEQUENTIAL_SHARD 1
    47 #elif defined(USE_WORK_STEALING)
    48         #define READYQ_SHARD_FACTOR 2
    49         #define SEQUENTIAL_SHARD 2
    50 #else
    51         #error no scheduling strategy selected
    52 #endif
    53 
    54 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred);
    55 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w);
    56 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j);
    57 static inline struct $thread * search(struct cluster * cltr);
    58 
     42#define BIAS 4
    5943
    6044// returns the maximum number of processors the RWLock support
     
    11094//=======================================================================
    11195// Lock-Free registering/unregistering of threads
    112 void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     96unsigned doregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {
    11397        __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc);
    11498
     
    124108                        /*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size));
    125109                        /*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0);
    126                         proc->id = i;
     110                        return i;
    127111                }
    128112        }
     
    151135        /*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size));
    152136        /*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0);
    153         proc->id = n;
    154 }
    155 
    156 void unregister_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     137        return n;
     138}
     139
     140void unregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {
    157141        unsigned id = proc->id;
    158142        /*paranoid*/ verify(id < ready);
     
    209193
    210194//=======================================================================
    211 // Cforall Ready Queue used for scheduling
     195// Cforall Reqdy Queue used for scheduling
    212196//=======================================================================
    213197void ?{}(__ready_queue_t & this) with (this) {
    214198        lanes.data  = 0p;
    215         lanes.tscs  = 0p;
    216199        lanes.count = 0;
    217200}
    218201
    219202void ^?{}(__ready_queue_t & this) with (this) {
    220         verify( SEQUENTIAL_SHARD == lanes.count );
     203        verify( 1 == lanes.count );
     204        #ifdef USE_SNZI
     205                verify( !query( snzi ) );
     206        #endif
    221207        free(lanes.data);
    222         free(lanes.tscs);
    223208}
    224209
    225210//-----------------------------------------------------------------------
    226 #if defined(USE_RELAXED_FIFO)
    227         //-----------------------------------------------------------------------
    228         // get index from random number with or without bias towards queues
    229         static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
    230                 unsigned i;
    231                 bool local;
     211__attribute__((hot)) bool query(struct cluster * cltr) {
     212        #ifdef USE_SNZI
     213                return query(cltr->ready_queue.snzi);
     214        #endif
     215        return true;
     216}
     217
     218static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
     219        unsigned i;
     220        bool local;
     221        #if defined(BIAS)
    232222                unsigned rlow  = r % BIAS;
    233223                unsigned rhigh = r / BIAS;
     
    235225                        // (BIAS - 1) out of BIAS chances
    236226                        // Use perferred queues
    237                         i = preferred + (rhigh % READYQ_SHARD_FACTOR);
     227                        i = preferred + (rhigh % 4);
    238228                        local = true;
    239229                }
     
    244234                        local = false;
    245235                }
    246                 return [i, local];
    247         }
    248 
    249         __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
    250                 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    251 
    252                 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
    253                 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
    254 
    255                 // write timestamp
    256                 thrd->link.ts = rdtscl();
    257 
    258                 bool local;
    259                 int preferred = external ? -1 : kernelTLS().this_processor->rdq.id;
    260 
    261                 // Try to pick a lane and lock it
    262                 unsigned i;
    263                 do {
    264                         // Pick the index of a lane
    265                         unsigned r = __tls_rand_fwd();
    266                         [i, local] = idx_from_r(r, preferred);
    267 
    268                         i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    269 
    270                         #if !defined(__CFA_NO_STATISTICS__)
    271                                 if(external) {
    272                                         if(local) __atomic_fetch_add(&cltr->stats->ready.pick.ext.local, 1, __ATOMIC_RELAXED);
    273                                         __atomic_fetch_add(&cltr->stats->ready.pick.ext.attempt, 1, __ATOMIC_RELAXED);
    274                                 }
    275                                 else {
    276                                         if(local) __tls_stats()->ready.pick.push.local++;
    277                                         __tls_stats()->ready.pick.push.attempt++;
    278                                 }
    279                         #endif
    280 
    281                 #if defined(USE_MPSC)
    282                         // mpsc always succeeds
    283                 } while( false );
    284                 #else
    285                         // If we can't lock it retry
    286                 } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
    287                 #endif
    288 
    289                 // Actually push it
    290                 push(lanes.data[i], thrd);
    291 
    292                 #if !defined(USE_MPSC)
    293                         // Unlock and return
    294                         __atomic_unlock( &lanes.data[i].lock );
    295                 #endif
    296 
    297                 // Mark the current index in the tls rng instance as having an item
    298                 __tls_rand_advance_bck();
    299 
    300                 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
    301 
    302                 // Update statistics
     236        #else
     237                i = r;
     238                local = false;
     239        #endif
     240        return [i, local];
     241}
     242
     243//-----------------------------------------------------------------------
     244__attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
     245        __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
     246
     247        const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
     248
     249        // write timestamp
     250        thrd->link.ts = rdtscl();
     251
     252        bool first = false;
     253        __attribute__((unused)) bool local;
     254        __attribute__((unused)) int preferred;
     255        #if defined(BIAS)
     256                preferred =
     257                        //*
     258                        external ? -1 : kernelTLS().this_processor->cltr_id;
     259                        /*/
     260                        thrd->link.preferred * 4;
     261                        //*/
     262        #endif
     263
     264        // Try to pick a lane and lock it
     265        unsigned i;
     266        do {
     267                // Pick the index of a lane
     268                // unsigned r = __tls_rand();
     269                unsigned r = __tls_rand_fwd();
     270                [i, local] = idx_from_r(r, preferred);
     271
     272                i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     273
    303274                #if !defined(__CFA_NO_STATISTICS__)
    304275                        if(external) {
    305                                 if(local) __atomic_fetch_add(&cltr->stats->ready.pick.ext.lsuccess, 1, __ATOMIC_RELAXED);
    306                                 __atomic_fetch_add(&cltr->stats->ready.pick.ext.success, 1, __ATOMIC_RELAXED);
     276                                if(local) __atomic_fetch_add(&cltr->stats->ready.pick.ext.local, 1, __ATOMIC_RELAXED);
     277                                __atomic_fetch_add(&cltr->stats->ready.pick.ext.attempt, 1, __ATOMIC_RELAXED);
    307278                        }
    308279                        else {
    309                                 if(local) __tls_stats()->ready.pick.push.lsuccess++;
    310                                 __tls_stats()->ready.pick.push.success++;
     280                                if(local) __tls_stats()->ready.pick.push.local++;
     281                                __tls_stats()->ready.pick.push.attempt++;
    311282                        }
    312283                #endif
    313         }
    314 
    315         // Pop from the ready queue from a given cluster
    316         __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
    317                 /* paranoid */ verify( lanes.count > 0 );
    318                 /* paranoid */ verify( kernelTLS().this_processor );
    319                 /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
    320 
    321                 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    322                 int preferred = kernelTLS().this_processor->rdq.id;
    323 
    324 
    325                 // As long as the list is not empty, try finding a lane that isn't empty and pop from it
    326                 for(25) {
    327                         // Pick two lists at random
    328                         unsigned ri = __tls_rand_bck();
    329                         unsigned rj = __tls_rand_bck();
    330 
    331                         unsigned i, j;
    332                         __attribute__((unused)) bool locali, localj;
    333                         [i, locali] = idx_from_r(ri, preferred);
    334                         [j, localj] = idx_from_r(rj, preferred);
    335 
    336                         #if !defined(__CFA_NO_STATISTICS__)
    337                                 if(locali && localj) {
    338                                         __tls_stats()->ready.pick.pop.local++;
    339                                 }
    340                         #endif
    341 
    342                         i %= count;
    343                         j %= count;
    344 
    345                         // try popping from the 2 picked lists
    346                         struct $thread * thrd = try_pop(cltr, i, j);
    347                         if(thrd) {
    348                                 #if !defined(__CFA_NO_STATISTICS__)
    349                                         if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++;
    350                                 #endif
    351                                 return thrd;
    352                         }
    353                 }
    354 
    355                 // All lanes where empty return 0p
    356                 return 0p;
    357         }
    358 
    359         __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) {
    360                 return search(cltr);
    361         }
    362 #endif
    363 #if defined(USE_WORK_STEALING)
    364         __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
    365                 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    366 
    367                 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
    368                 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
    369 
    370                 // write timestamp
    371                 thrd->link.ts = rdtscl();
    372 
    373                 // Try to pick a lane and lock it
    374                 unsigned i;
    375                 do {
    376                         if(unlikely(external)) {
    377                                 i = __tls_rand() % lanes.count;
    378                         }
    379                         else {
    380                                 processor * proc = kernelTLS().this_processor;
    381                                 unsigned r = proc->rdq.its++;
    382                                 i =  proc->rdq.id + (r % READYQ_SHARD_FACTOR);
    383                         }
    384 
    385 
    386                 #if defined(USE_MPSC)
    387                         // mpsc always succeeds
    388                 } while( false );
    389                 #else
    390                         // If we can't lock it retry
    391                 } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
    392                 #endif
    393 
    394                 // Actually push it
    395                 push(lanes.data[i], thrd);
    396 
    397                 #if !defined(USE_MPSC)
    398                         // Unlock and return
    399                         __atomic_unlock( &lanes.data[i].lock );
    400                 #endif
    401 
    402                 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
    403         }
    404 
    405         // Pop from the ready queue from a given cluster
    406         __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
    407                 /* paranoid */ verify( lanes.count > 0 );
    408                 /* paranoid */ verify( kernelTLS().this_processor );
    409                 /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
    410 
    411                 processor * proc = kernelTLS().this_processor;
    412 
    413                 if(proc->rdq.target == -1u) {
    414                         proc->rdq.target = __tls_rand() % lanes.count;
    415                         unsigned it1  = proc->rdq.itr;
    416                         unsigned it2  = proc->rdq.itr + 1;
    417                         unsigned idx1 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR);
    418                         unsigned idx2 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR);
    419                         unsigned long long tsc1 = ts(lanes.data[idx1]);
    420                         unsigned long long tsc2 = ts(lanes.data[idx2]);
    421                         proc->rdq.cutoff = min(tsc1, tsc2);
    422                 }
    423                 else if(lanes.tscs[proc->rdq.target].tv < proc->rdq.cutoff) {
    424                         $thread * t = try_pop(cltr, proc->rdq.target);
    425                         proc->rdq.target = -1u;
    426                         if(t) return t;
    427                 }
    428 
    429                 for(READYQ_SHARD_FACTOR) {
    430                         unsigned i = proc->rdq.id + (--proc->rdq.itr % READYQ_SHARD_FACTOR);
    431                         if($thread * t = try_pop(cltr, i)) return t;
    432                 }
    433                 return 0p;
    434         }
    435 
    436         __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
    437                 for(25) {
    438                         unsigned i = __tls_rand() % lanes.count;
    439                         $thread * t = try_pop(cltr, i);
    440                         if(t) return t;
    441                 }
    442 
    443                 return search(cltr);
    444         }
    445 #endif
    446 
    447 //=======================================================================
    448 // Various Ready Queue utilities
    449 //=======================================================================
    450 // these function work the same or almost the same
    451 // whether they are using work-stealing or relaxed fifo scheduling
    452 
    453 //-----------------------------------------------------------------------
    454 // try to pop from a lane given by index w
    455 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w) with (cltr->ready_queue) {
    456         // Get relevant elements locally
    457         __intrusive_lane_t & lane = lanes.data[w];
    458 
    459         // If list looks empty retry
    460         if( is_empty(lane) ) return 0p;
    461 
    462         // If we can't get the lock retry
    463         if( !__atomic_try_acquire(&lane.lock) ) return 0p;
    464 
    465         // If list is empty, unlock and retry
    466         if( is_empty(lane) ) {
    467                 __atomic_unlock(&lane.lock);
    468                 return 0p;
    469         }
    470 
    471         // Actually pop the list
    472         struct $thread * thrd;
    473         thrd = pop(lane);
    474 
    475         /* paranoid */ verify(thrd);
    476         /* paranoid */ verify(lane.lock);
    477 
    478         // Unlock and return
    479         __atomic_unlock(&lane.lock);
     284
     285        #if defined(USE_MPSC)
     286                // mpsc always succeeds
     287        } while( false );
     288        #else
     289                // If we can't lock it retry
     290        } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
     291        #endif
     292
     293        // Actually push it
     294        #ifdef USE_SNZI
     295                bool lane_first =
     296        #endif
     297
     298        push(lanes.data[i], thrd);
     299
     300        #ifdef USE_SNZI
     301                // If this lane used to be empty we need to do more
     302                if(lane_first) {
     303                        // Check if the entire queue used to be empty
     304                        first = !query(snzi);
     305
     306                        // Update the snzi
     307                        arrive( snzi, i );
     308                }
     309        #endif
     310
     311        #if !defined(USE_MPSC)
     312                // Unlock and return
     313                __atomic_unlock( &lanes.data[i].lock );
     314        #endif
     315
     316        // Mark the current index in the tls rng instance as having an item
     317        __tls_rand_advance_bck();
     318
     319        __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
    480320
    481321        // Update statistics
    482322        #if !defined(__CFA_NO_STATISTICS__)
    483                 __tls_stats()->ready.pick.pop.success++;
    484         #endif
    485 
    486         #if defined(USE_WORK_STEALING)
    487                 lanes.tscs[w].tv = thrd->link.ts;
    488         #endif
    489 
    490         // return the popped thread
    491         return thrd;
    492 }
    493 
    494 //-----------------------------------------------------------------------
    495 // try to pop from any lanes making sure you don't miss any threads push
    496 // before the start of the function
    497 static inline struct $thread * search(struct cluster * cltr) with (cltr->ready_queue) {
     323                if(external) {
     324                        if(local) __atomic_fetch_add(&cltr->stats->ready.pick.ext.lsuccess, 1, __ATOMIC_RELAXED);
     325                        __atomic_fetch_add(&cltr->stats->ready.pick.ext.success, 1, __ATOMIC_RELAXED);
     326                }
     327                else {
     328                        if(local) __tls_stats()->ready.pick.push.lsuccess++;
     329                        __tls_stats()->ready.pick.push.success++;
     330                }
     331        #endif
     332
     333        // return whether or not the list was empty before this push
     334        return first;
     335}
     336
     337static struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j);
     338static struct $thread * try_pop(struct cluster * cltr, unsigned i);
     339
     340// Pop from the ready queue from a given cluster
     341__attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) {
     342        /* paranoid */ verify( lanes.count > 0 );
     343        unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     344        int preferred;
     345        #if defined(BIAS)
     346                // Don't bother trying locally too much
     347                preferred = kernelTLS().this_processor->cltr_id;
     348        #endif
     349
     350
     351        // As long as the list is not empty, try finding a lane that isn't empty and pop from it
     352        #ifdef USE_SNZI
     353                while( query(snzi) ) {
     354        #else
     355                for(25) {
     356        #endif
     357                // Pick two lists at random
     358                // unsigned ri = __tls_rand();
     359                // unsigned rj = __tls_rand();
     360                unsigned ri = __tls_rand_bck();
     361                unsigned rj = __tls_rand_bck();
     362
     363                unsigned i, j;
     364                __attribute__((unused)) bool locali, localj;
     365                [i, locali] = idx_from_r(ri, preferred);
     366                [j, localj] = idx_from_r(rj, preferred);
     367
     368                #if !defined(__CFA_NO_STATISTICS__)
     369                        if(locali && localj) {
     370                                __tls_stats()->ready.pick.pop.local++;
     371                        }
     372                #endif
     373
     374                i %= count;
     375                j %= count;
     376
     377                // try popping from the 2 picked lists
     378                struct $thread * thrd = try_pop(cltr, i, j);
     379                if(thrd) {
     380                        #if defined(BIAS) && !defined(__CFA_NO_STATISTICS__)
     381                                if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++;
     382                        #endif
     383                        return thrd;
     384                }
     385        }
     386
     387        // All lanes where empty return 0p
     388        return 0p;
     389}
     390
     391__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
    498392        /* paranoid */ verify( lanes.count > 0 );
    499393        unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     
    511405}
    512406
     407
    513408//-----------------------------------------------------------------------
    514 // Check that all the intrusive queues in the data structure are still consistent
     409// Given 2 indexes, pick the list with the oldest push an try to pop from it
     410static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j) with (cltr->ready_queue) {
     411        #if !defined(__CFA_NO_STATISTICS__)
     412                __tls_stats()->ready.pick.pop.attempt++;
     413        #endif
     414
     415        // Pick the bet list
     416        int w = i;
     417        if( __builtin_expect(!is_empty(lanes.data[j]), true) ) {
     418                w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j;
     419        }
     420
     421        return try_pop(cltr, w);
     422}
     423
     424static inline struct $thread * try_pop(struct cluster * cltr, unsigned w) with (cltr->ready_queue) {
     425        // Get relevant elements locally
     426        __intrusive_lane_t & lane = lanes.data[w];
     427
     428        // If list looks empty retry
     429        if( is_empty(lane) ) return 0p;
     430
     431        // If we can't get the lock retry
     432        if( !__atomic_try_acquire(&lane.lock) ) return 0p;
     433
     434
     435        // If list is empty, unlock and retry
     436        if( is_empty(lane) ) {
     437                __atomic_unlock(&lane.lock);
     438                return 0p;
     439        }
     440
     441        // Actually pop the list
     442        struct $thread * thrd;
     443        thrd = pop(lane);
     444
     445        /* paranoid */ verify(thrd);
     446        /* paranoid */ verify(lane.lock);
     447
     448        #ifdef USE_SNZI
     449                // If this was the last element in the lane
     450                if(emptied) {
     451                        depart( snzi, w );
     452                }
     453        #endif
     454
     455        // Unlock and return
     456        __atomic_unlock(&lane.lock);
     457
     458        // Update statistics
     459        #if !defined(__CFA_NO_STATISTICS__)
     460                __tls_stats()->ready.pick.pop.success++;
     461        #endif
     462
     463        // Update the thread bias
     464        thrd->link.preferred = w / 4;
     465
     466        // return the popped thread
     467        return thrd;
     468}
     469//-----------------------------------------------------------------------
     470
     471bool remove_head(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
     472        for(i; lanes.count) {
     473                __intrusive_lane_t & lane = lanes.data[i];
     474
     475                bool removed = false;
     476
     477                __atomic_acquire(&lane.lock);
     478                        if(head(lane)->link.next == thrd) {
     479                                $thread * pthrd;
     480                                pthrd = pop(lane);
     481
     482                                /* paranoid */ verify( pthrd == thrd );
     483
     484                                removed = true;
     485                                #ifdef USE_SNZI
     486                                        if(emptied) {
     487                                                depart( snzi, i );
     488                                        }
     489                                #endif
     490                        }
     491                __atomic_unlock(&lane.lock);
     492
     493                if( removed ) return true;
     494        }
     495        return false;
     496}
     497
     498//-----------------------------------------------------------------------
     499
    515500static void check( __ready_queue_t & q ) with (q) {
    516501        #if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC)
     
    535520                }
    536521        #endif
    537 }
    538 
    539 //-----------------------------------------------------------------------
    540 // Given 2 indexes, pick the list with the oldest push an try to pop from it
    541 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j) with (cltr->ready_queue) {
    542         #if !defined(__CFA_NO_STATISTICS__)
    543                 __tls_stats()->ready.pick.pop.attempt++;
    544         #endif
    545 
    546         // Pick the bet list
    547         int w = i;
    548         if( __builtin_expect(!is_empty(lanes.data[j]), true) ) {
    549                 w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j;
    550         }
    551 
    552         return try_pop(cltr, w);
    553522}
    554523
     
    572541}
    573542
    574 static void assign_list(unsigned & value, dlist(processor, processor) & list, unsigned count) {
    575         processor * it = &list`first;
    576         for(unsigned i = 0; i < count; i++) {
    577                 /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
    578                 it->rdq.id = value;
    579                 it->rdq.target = -1u;
    580                 value += READYQ_SHARD_FACTOR;
    581                 it = &(*it)`next;
    582         }
    583 }
    584 
    585 static void reassign_cltr_id(struct cluster * cltr) {
    586         unsigned preferred = 0;
    587         assign_list(preferred, cltr->procs.actives, cltr->procs.total - cltr->procs.idle);
    588         assign_list(preferred, cltr->procs.idles  , cltr->procs.idle );
    589 }
    590 
    591 static void fix_times( struct cluster * cltr ) with( cltr->ready_queue ) {
    592         #if defined(USE_WORK_STEALING)
    593                 lanes.tscs = alloc(lanes.count, lanes.tscs`realloc);
    594                 for(i; lanes.count) {
    595                         lanes.tscs[i].tv = ts(lanes.data[i]);
    596                 }
    597         #endif
    598 }
    599 
    600543// Grow the ready queue
    601 void ready_queue_grow(struct cluster * cltr) {
     544unsigned ready_queue_grow(struct cluster * cltr, int target) {
     545        unsigned preferred;
    602546        size_t ncount;
    603         int target = cltr->procs.total;
    604547
    605548        /* paranoid */ verify( ready_mutate_islocked() );
     
    611554        // grow the ready queue
    612555        with( cltr->ready_queue ) {
     556                #ifdef USE_SNZI
     557                        ^(snzi){};
     558                #endif
     559
    613560                // Find new count
    614561                // Make sure we always have atleast 1 list
    615562                if(target >= 2) {
    616                         ncount = target * READYQ_SHARD_FACTOR;
     563                        ncount = target * 4;
     564                        preferred = ncount - 4;
    617565                } else {
    618                         ncount = SEQUENTIAL_SHARD;
     566                        ncount = 1;
     567                        preferred = 0;
    619568                }
    620569
     
    634583                // Update original
    635584                lanes.count = ncount;
    636         }
    637 
    638         fix_times(cltr);
    639 
    640         reassign_cltr_id(cltr);
     585
     586                #ifdef USE_SNZI
     587                        // Re-create the snzi
     588                        snzi{ log2( lanes.count / 8 ) };
     589                        for( idx; (size_t)lanes.count ) {
     590                                if( !is_empty(lanes.data[idx]) ) {
     591                                        arrive(snzi, idx);
     592                                }
     593                        }
     594                #endif
     595        }
    641596
    642597        // Make sure that everything is consistent
     
    646601
    647602        /* paranoid */ verify( ready_mutate_islocked() );
     603        return preferred;
    648604}
    649605
    650606// Shrink the ready queue
    651 void ready_queue_shrink(struct cluster * cltr) {
     607void ready_queue_shrink(struct cluster * cltr, int target) {
    652608        /* paranoid */ verify( ready_mutate_islocked() );
    653609        __cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue\n");
     
    656612        /* paranoid */ check( cltr->ready_queue );
    657613
    658         int target = cltr->procs.total;
    659 
    660614        with( cltr->ready_queue ) {
     615                #ifdef USE_SNZI
     616                        ^(snzi){};
     617                #endif
     618
    661619                // Remember old count
    662620                size_t ocount = lanes.count;
     
    664622                // Find new count
    665623                // Make sure we always have atleast 1 list
    666                 lanes.count = target >= 2 ? target * READYQ_SHARD_FACTOR: SEQUENTIAL_SHARD;
     624                lanes.count = target >= 2 ? target * 4: 1;
    667625                /* paranoid */ verify( ocount >= lanes.count );
    668                 /* paranoid */ verify( lanes.count == target * READYQ_SHARD_FACTOR || target < 2 );
     626                /* paranoid */ verify( lanes.count == target * 4 || target < 2 );
    669627
    670628                // for printing count the number of displaced threads
     
    709667                        fix(lanes.data[idx]);
    710668                }
    711         }
    712 
    713         fix_times(cltr);
    714 
    715         reassign_cltr_id(cltr);
     669
     670                #ifdef USE_SNZI
     671                        // Re-create the snzi
     672                        snzi{ log2( lanes.count / 8 ) };
     673                        for( idx; (size_t)lanes.count ) {
     674                                if( !is_empty(lanes.data[idx]) ) {
     675                                        arrive(snzi, idx);
     676                                }
     677                        }
     678                #endif
     679        }
    716680
    717681        // Make sure that everything is consistent
  • libcfa/src/concurrency/ready_subqueue.hfa

    rc8a0210 r857a1c6  
    246246        #endif
    247247}
    248 
    249 // Aligned timestamps which are used by the relaxed ready queue
    250 struct __attribute__((aligned(128))) __timestamp_t {
    251         volatile unsigned long long tv;
    252 };
    253 
    254 void  ?{}(__timestamp_t & this) { this.tv = 0; }
    255 void ^?{}(__timestamp_t & this) {}
  • libcfa/src/concurrency/stats.cfa

    rc8a0210 r857a1c6  
    55#include <inttypes.h>
    66#include "bits/debug.hfa"
    7 #include "bits/locks.hfa"
    87#include "stats.hfa"
    98
     
    4544                        stats->io.calls.errors.busy = 0;
    4645                        stats->io.poller.sleeps     = 0;
    47                 #endif
    48 
    49                 #if defined(CFA_STATS_ARRAY)
    50                         stats->array.values = alloc(CFA_STATS_ARRAY);
    51                         stats->array.cnt = 0;
    5246                #endif
    5347        }
     
    157151                #endif
    158152        }
    159 
    160         #if defined(CFA_STATS_ARRAY)
    161                 extern "C" {
    162                         #include <stdio.h>
    163                         #include <errno.h>
    164                         #include <sys/stat.h>
    165                         #include <fcntl.h>
    166                 }
    167 
    168                 void __flush_stat( struct __stats_t * this, const char * name, void * handle) {
    169                         int ret = mkdir(".cfadata", 0755);
    170                         if(ret < 0 && errno != EEXIST) abort("Failed to create directory .cfadata: %d\n", errno);
    171 
    172                         char filename[100];
    173                         snprintf(filename, 100, ".cfadata/%s%p.data", name, handle);
    174 
    175                         int fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0644);
    176                         if(fd < 0) abort("Failed to create file %s: %d\n", filename, errno);
    177 
    178                         for(i; this->array.cnt) {
    179                                 char line[100];
    180                                 size_t n = snprintf(line, 100, "%llu, %lld\n", this->array.values[i].ts, this->array.values[i].value);
    181                                 write(fd, line, n);
    182                         }
    183 
    184                         this->array.cnt = 0;
    185                         close(fd);
    186                 }
    187 
    188                 static __spinlock_t stats_lock;
    189 
    190                 void __push_stat( struct __stats_t * this, int64_t value, bool external, const char * name, void * handle ) {
    191                         if(external) lock(stats_lock __cfaabi_dbg_ctx2);
    192 
    193                         if( this->array.cnt >= CFA_STATS_ARRAY ) __flush_stat( this, name, handle );
    194 
    195                         size_t idx = this->array.cnt;
    196                         this->array.cnt++;
    197 
    198                         if(external) unlock(stats_lock);
    199 
    200                         this->array.values[idx].ts = rdtscl();
    201                         this->array.values[idx].value = value;
    202                 }
    203         #endif
    204153#endif
  • libcfa/src/concurrency/stats.hfa

    rc8a0210 r857a1c6  
    11#pragma once
    2 
    3 // #define CFA_STATS_ARRAY 10000
    42
    53#include <stdint.h>
     
    111109        #endif
    112110
    113         #if defined(CFA_STATS_ARRAY)
    114                 struct __stats_elem_t {
    115                         long long int ts;
    116                         int64_t value;
    117                 };
    118         #endif
    119 
    120111        struct __attribute__((aligned(128))) __stats_t {
    121112                __stats_readQ_t ready;
     
    123114                        __stats_io_t    io;
    124115                #endif
    125 
    126                 #if defined(CFA_STATS_ARRAY)
    127                         struct {
    128                                 __stats_elem_t * values;
    129                                 volatile size_t cnt;
    130                         } array;
    131                 #endif
    132 
    133116        };
    134117
     
    136119        void __tally_stats( struct __stats_t *, struct __stats_t * );
    137120        void __print_stats( struct __stats_t *, int, const char *, const char *, void * );
    138         #if defined(CFA_STATS_ARRAY)
    139                 void __push_stat ( struct __stats_t *, int64_t value, bool external, const char * name, void * handle);
    140                 void __flush_stat( struct __stats_t *, const char *, void * );
    141         #else
    142                 static inline void __push_stat ( struct __stats_t *, int64_t, bool, const char *, void * ) {}
    143                 static inline void __flush_stat( struct __stats_t *, const char *, void * ) {}
    144         #endif
    145121#endif
    146122
  • libcfa/src/concurrency/thread.cfa

    rc8a0210 r857a1c6  
    3939        link.next = 0p;
    4040        link.prev = 0p;
     41        link.preferred = -1;
    4142        #if defined( __CFA_WITH_VERIFY__ )
    4243                canary = 0x0D15EA5E0D15EA5Ep;
     
    6162}
    6263
    63 EHM_VIRTUAL_TABLE(SomeThreadCancelled, std_thread_cancelled);
     64FORALL_DATA_INSTANCE(ThreadCancelled, (thread_t &), (thread_t))
    6465
    6566forall(T &)
     
    7273forall(T &)
    7374const char * msg(ThreadCancelled(T) *) {
    74         return "ThreadCancelled(...)";
     75        return "ThreadCancelled";
    7576}
    7677
    7778forall(T &)
    7879static void default_thread_cancel_handler(ThreadCancelled(T) & ) {
    79         // Improve this error message, can I do formatting?
    8080        abort( "Unhandled thread cancellation.\n" );
    8181}
    8282
    83 static void default_thread_cancel_handler(SomeThreadCancelled & ) {
    84         // Improve this error message, can I do formatting?
    85         abort( "Unhandled thread cancellation.\n" );
    86 }
    87 
    88 forall(T & | is_thread(T) | IS_EXCEPTION(SomeThreadCancelled))
     83forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)))
    8984void ?{}( thread_dtor_guard_t & this,
    90                 T & thrd, void(*cancelHandler)(SomeThreadCancelled &)) {
    91         $monitor * m = get_monitor(thrd);
     85                T & thrd, void(*cancelHandler)(ThreadCancelled(T) &)) {
     86        $monitor * m = get_monitor(thrd);
    9287        $thread * desc = get_thread(thrd);
    9388
    9489        // Setup the monitor guard
    9590        void (*dtor)(T& mutex this) = ^?{};
    96         bool join = cancelHandler != (void(*)(SomeThreadCancelled&))0;
     91        bool join = cancelHandler != (void(*)(ThreadCancelled(T)&))0;
    9792        (this.mg){&m, (void(*)())dtor, join};
    9893
     
    108103        }
    109104        desc->state = Cancelled;
    110         void(*defaultResumptionHandler)(SomeThreadCancelled &) =
     105        void(*defaultResumptionHandler)(ThreadCancelled(T) &) =
    111106                join ? cancelHandler : default_thread_cancel_handler;
    112107
     108        ThreadCancelled(T) except;
    113109        // TODO: Remove explitate vtable set once trac#186 is fixed.
    114         SomeThreadCancelled except;
    115         except.virtual_table = &std_thread_cancelled;
     110        except.virtual_table = &get_exception_vtable(&except);
    116111        except.the_thread = &thrd;
    117112        except.the_exception = __cfaehm_cancellation_exception( cancellation );
    118         // Why is this cast required?
    119         throwResume (SomeThreadCancelled &)except;
     113        throwResume except;
    120114
    121115        except.the_exception->virtual_table->free( except.the_exception );
     
    164158
    165159//-----------------------------------------------------------------------------
    166 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(SomeThreadCancelled))
     160forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
    167161T & join( T & this ) {
    168162        thread_dtor_guard_t guard = { this, defaultResumptionHandler };
  • libcfa/src/concurrency/thread.hfa

    rc8a0210 r857a1c6  
    3232};
    3333
    34 EHM_EXCEPTION(SomeThreadCancelled) (
    35         void * the_thread;
    36         exception_t * the_exception;
    37 );
    38 
    39 EHM_EXTERN_VTABLE(SomeThreadCancelled, std_thread_cancelled);
    40 
    41 EHM_FORALL_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
     34FORALL_DATA_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
    4235        thread_t * the_thread;
    4336        exception_t * the_exception;
     
    8679};
    8780
    88 forall( T & | is_thread(T) | IS_EXCEPTION(SomeThreadCancelled) )
    89 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(SomeThreadCancelled &) );
     81forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
     82void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
    9083void ^?{}( thread_dtor_guard_t & this );
    9184
     
    132125//----------
    133126// join
    134 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(SomeThreadCancelled) )
     127forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
    135128T & join( T & this );
    136129
  • libcfa/src/exception.c

    rc8a0210 r857a1c6  
    1010// Created On       : Mon Jun 26 15:13:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Feb 24 13:40:00 2021
    13 // Update Count     : 36
     12// Last Modified On : Tue Oct 27 16:27:00 2020
     13// Update Count     : 35
    1414//
    1515
     
    2626#include "concurrency/invoke.h"
    2727#include "stdhdr/assert.h"
    28 #include "virtual.h"
    2928
    3029#if defined( __ARM_ARCH )
     
    4746const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643;
    4847
    49 // Base Exception type id:
    50 struct __cfa__parent_vtable __cfatid_exception_t = {
    51         NULL,
     48// Base exception vtable is abstract, you should not have base exceptions.
     49struct __cfaehm_base_exception_t_vtable
     50                ___cfaehm_base_exception_t_vtable_instance = {
     51        .parent = NULL,
     52        .size = 0,
     53        .copy = NULL,
     54        .free = NULL,
     55        .msg = NULL
    5256};
    5357
  • libcfa/src/exception.h

    rc8a0210 r857a1c6  
    1010// Created On       : Mon Jun 26 15:11:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Apr  8 15:20:00 2021
    13 // Update Count     : 12
     12// Last Modified On : Tue Oct 27 14:45:00 2020
     13// Update Count     : 11
    1414//
    1515
     
    2929struct __cfaehm_base_exception_t;
    3030typedef struct __cfaehm_base_exception_t exception_t;
    31 struct __cfa__parent_vtable;
    3231struct __cfaehm_base_exception_t_vtable {
    33         const struct __cfa__parent_vtable * __cfavir_typeid;
     32        const struct __cfaehm_base_exception_t_vtable * parent;
    3433        size_t size;
    3534        void (*copy)(struct __cfaehm_base_exception_t *this,
     
    4140        struct __cfaehm_base_exception_t_vtable const * virtual_table;
    4241};
    43 extern struct __cfa__parent_vtable __cfatid_exception_t;
     42extern struct __cfaehm_base_exception_t_vtable
     43        ___cfaehm_base_exception_t_vtable_instance;
    4444
    4545
     
    104104        /* The first field must be a pointer to a virtual table.
    105105         * That virtual table must be a decendent of the base exception virtual table.
    106          * The virtual table must point at the prober type-id.
    107          * None of these can be enforced in an assertion.
    108106         */
     107        virtualT const & get_exception_vtable(exceptT *);
     108        // Always returns the virtual table for this type (associated types hack).
    109109};
    110110
  • libcfa/src/exception.hfa

    rc8a0210 r857a1c6  
    1010// Created On       : Thu Apr  7 10:25:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Apr  8 15:16:00 2021
    13 // Update Count     : 4
     12// Last Modified On : Tue Aug  4 16:22:00 2020
     13// Update Count     : 3
    1414//
    1515
     
    1818// -----------------------------------------------------------------------------------------------
    1919
    20 // EHM_EXCEPTION(exception_name)(fields...);
    21 // Create an exception (a virtual structure that inherits from exception_t)
    22 // with the given name and fields.
    23 #define EHM_EXCEPTION(exception_name) \
    24         _EHM_TYPE_ID_STRUCT(exception_name, ); \
    25         _EHM_TYPE_ID_VALUE(exception_name, ); \
    26         _EHM_VIRTUAL_TABLE_STRUCT(exception_name, , ); \
    27         _EHM_EXCEPTION_STRUCT(exception_name, , )
    28 
    29 // EHM_EXTERN_VTABLE(exception_name, table_name);
    30 // Forward declare a virtual table called table_name for exception_name type.
    31 #define EHM_EXTERN_VTABLE(exception_name, table_name) \
    32         _EHM_EXTERN_VTABLE(exception_name, , table_name)
    33 
    34 // EHM_VIRTUAL_TABLE(exception_name, table_name);
    35 // Define a virtual table called table_name for exception_name type.
    36 #define EHM_VIRTUAL_TABLE(exception_name, table_name) \
    37         _EHM_DEFINE_COPY(exception_name, ) \
    38         _EHM_DEFINE_MSG(exception_name, ) \
    39         _EHM_VIRTUAL_TABLE(exception_name, , table_name)
    40 
    41 // EHM_FORALL_EXCEPTION(exception_name, (assertions), (parameters))(fields...);
    42 // As EHM_EXCEPTION but for polymorphic types instead of monomorphic ones.
    43 // The assertions list should include all polymorphic parameters and
    44 // assertions inside a parentisized list. Parameters should include all the
    45 // polymorphic parameter names inside a parentisized list (same order).
    46 #define EHM_FORALL_EXCEPTION(exception_name, assertions, parameters) \
    47         _EHM_TYPE_ID_STRUCT(exception_name, forall assertions); \
    48         _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall assertions, parameters); \
    49         _EHM_EXCEPTION_STRUCT(exception_name, forall assertions, parameters)
    50 
    51 // EHM_FORALL_EXTERN_VTABLE(exception_name, (arguments), table_name);
    52 // As EHM_EXTERN_VTABLE but for polymorphic types instead of monomorphic ones.
    53 // Arguments should be the parentisized list of polymorphic arguments.
    54 #define EHM_FORALL_EXTERN_VTABLE(exception_name, arguments, table_name) \
    55         _EHM_EXTERN_VTABLE(exception_name, arguments, table_name)
    56 
    57 // EHM_FORALL_VIRTUAL_TABLE(exception_name, (arguments), table_name);
    58 // As EHM_VIRTUAL_TABLE but for polymorphic types instead of monomorphic ones.
    59 // Arguments should be the parentisized list of polymorphic arguments.
    60 #define EHM_FORALL_VIRTUAL_TABLE(exception_name, arguments, table_name) \
    61         _EHM_TYPE_ID_VALUE(exception_name, arguments); \
    62         _EHM_DEFINE_COPY(exception_name, arguments) \
    63         _EHM_DEFINE_MSG(exception_name, arguments) \
    64         _EHM_VIRTUAL_TABLE(exception_name, arguments, table_name)
    65 
    66 #define EHM_TYPE_ID(exception_name) _EHM_TYPE_ID_TYPE(exception_name)
    67 
    68 #define EHM_MATCH_ALL __cfa__parent_vtable
     20// TRIVIAL_EXCEPTION_DECLARATION(exception_name);
     21// Declare a trivial exception, one that adds no fields or features.
     22// This will make the exception visible and may go in a .hfa or .cfa file.
     23#define TRIVIAL_EXCEPTION_DECLARATION(...) \
     24        _EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__)
     25
     26// TRIVIAL_EXCEPTION_INSTANCE(exception_name);
     27// Create the trival exception. This must be used exactly once and should be used in a .cfa file,
     28// as it creates the unique instance of the virtual table.
     29#define TRIVIAL_EXCEPTION_INSTANCE(...) _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__)
     30
     31// TRIVIAL_EXCEPTION(exception_name[, parent_name]);
     32// Does both of the above, a short hand if the exception is only used in one .cfa file.
     33// For legacy reasons this is the only one that official supports having a parent other than the
     34// base exception. This feature may be removed or changed.
     35#define TRIVIAL_EXCEPTION(...) \
     36        _EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__); \
     37        _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__)
     38
     39// FORALL_TRIVIAL_EXCEPTION(exception_name, (assertions...), (parameters...));
     40// Forward declare a polymorphic but otherwise trivial exception type. You must provide the entire
     41// assertion list (exactly what would go in the forall clause) and parameters list (only the
     42// parameter names from the assertion list, same order and comma seperated). This should be
     43// visible where ever use the exception. This just generates the polymorphic framework, see
     44// POLY_VTABLE_DECLARATION to allow instantiations.
     45#define FORALL_TRIVIAL_EXCEPTION(exception_name, assertions, parameters) \
     46        _FORALL_TRIVIAL_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, )
     47
     48// FORALL_TRIVIAL_INSTANCE(exception_name, (assertions...), (parameters...))
     49// Create the forall trivial exception. The assertion list and parameters must match.
     50// There must be exactly one use of this in a program for each exception type. This just
     51// generates the polymorphic framework, see POLY_VTABLE_INSTANCE to allow instantiations.
     52#define FORALL_TRIVIAL_INSTANCE(exception_name, assertions, parameters) \
     53        _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters)
     54
     55// DATA_EXCEPTION(exception_name)(fields...);
     56// Forward declare an exception that adds fields but no features. The added fields go in the
     57// second argument list. The virtual table instance must be provided later (see VTABLE_INSTANCE).
     58#define DATA_EXCEPTION(...) _EXC_DISPATCH(_DATA_EXCEPTION, __VA_ARGS__)
     59
     60// FORALL_DATA_EXCEPTION(exception_name, (assertions...), (parameters...))(fields...);
     61// Define a polymorphic exception that adds fields but no additional features. The assertion list
     62// and matching parameters must match. Then you can give the list of fields. This should be
     63// visible where ever you use the exception. This just generates the polymorphic framework, see
     64// POLY_VTABLE_DECLARATION to allow instantiations.
     65#define FORALL_DATA_EXCEPTION(exception_name, assertions, parameters) \
     66        _FORALL_DATA_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, )
     67
     68// FORALL_DATA_INSTANCE(exception_name, (assertions...), (parameters...))
     69// Create a polymorphic data exception. The assertion list and parameters must match. This should
     70// appear once in each program. This just generates the polymorphic framework, see
     71// POLY_VTABLE_INSTANCE to allow instantiations.
     72#define FORALL_DATA_INSTANCE(exception_name, assertions, parameters) \
     73        _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters)
     74
     75// VTABLE_DECLARATION(exception_name)([new_features...]);
     76// Declare a virtual table type for an exception with exception_name. You may also add features
     77// (fields on the virtual table) by including them in the second list.
     78#define VTABLE_DECLARATION(...) _EXC_DISPATCH(_VTABLE_DECLARATION, __VA_ARGS__)
     79
     80// VTABLE_INSTANCE(exception_name)(msg [, others...]);
     81// Create the instance of the virtual table. There must be exactly one instance of a virtual table
     82// for each exception type. This fills in most of the fields of the virtual table (uses ?=? and
     83// ^?{}) but you must provide the message function and any other fields added in the declaration.
     84#define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__)
     85
     86// FORALL_VTABLE_DECLARATION(exception_name, (assertions...), (parameters...))([new_features...]);
     87// Declare a polymorphic virtual table type for an exception with exception_name, the given
     88// assertions and parameters. You may also add features (fields on the virtual table). This just
     89// generates the polymorphic framework, see POLY_VTABLE_DECLARATION to allow instantiations.
     90#define FORALL_VTABLE_DECLARATION(exception_name, assertions, parameters) \
     91        _FORALL_VTABLE_DECLARATION(exception_name, __cfaehm_base_exception_t, assertions, parameters, )
     92
     93// POLY_VTABLE_DECLARATION(exception_name, types...);
     94// Declares that an instantiation for this exception exists for the given types. This should be
     95// visible anywhere you use the instantiation of the exception is used.
     96#define POLY_VTABLE_DECLARATION(exception_name, ...) \
     97        VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable(exception_name(__VA_ARGS__) *); \
     98        extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name)
     99
     100// POLY_VTABLE_INSTANCE(exception_name, types...)(msg [, others...]);
     101// Creates an instantiation for the given exception for the given types. This should occur only
     102// once in the entire program. You must fill in all features, message and any others given in the
     103// initial declaration.
     104#define POLY_VTABLE_INSTANCE(exception_name, ...) \
     105        _POLY_VTABLE_INSTANCE(exception_name, __cfaehm_base_exception_t, __VA_ARGS__)
     106
     107// VTABLE_TYPE(exception_name) | VTABLE_NAME(exception_name)
     108// Get the name of the vtable type or the name of the vtable instance for an exception type.
     109#define VTABLE_TYPE(exception_name) struct _GLUE2(exception_name,_vtable)
     110#define VTABLE_NAME(exception_name) _GLUE3(_,exception_name,_vtable_instance)
     111
     112// VTABLE_FIELD(exception_name);
     113// FORALL_VTABLE_FIELD(exception_name, (parameters-or-types));
     114// The declaration of the virtual table field. Should be the first declaration in a virtual type.
     115#define VTABLE_FIELD(exception_name) VTABLE_TYPE(exception_name) const * virtual_table
     116#define FORALL_VTABLE_FIELD(exception_name, parameters) \
     117        VTABLE_TYPE(exception_name) parameters const * virtual_table
     118
     119// VTABLE_INIT(object_reference, exception_name);
     120// Sets a virtual table field on an object to the virtual table instance for the type.
     121#define VTABLE_INIT(this, exception_name) (this).virtual_table = &VTABLE_NAME(exception_name)
     122
     123// VTABLE_ASSERTION(exception_name, (parameters...))
     124// The assertion that there is an instantiation of the vtable for the exception and types.
     125#define VTABLE_ASSERTION(exception_name, parameters) \
     126        { VTABLE_TYPE(exception_name) parameters VTABLE_NAME(exception_name); }
    69127
    70128// IS_EXCEPTION(exception_name [, (...parameters)])
     
    77135#define IS_TERMINATION_EXCEPTION(...) _IS_EXCEPTION(is_termination_exception, __VA_ARGS__, , ~)
    78136
    79 // Macros starting with a leading underscore are internal.
    80 
    81 // Create an exception type definition. must be tailing, can be polymorphic.
    82 #define _EHM_EXCEPTION_STRUCT(exception_name, forall_clause, parameters) \
    83         forall_clause struct exception_name { \
    84                 _EHM_VTABLE_TYPE(exception_name) parameters const * virtual_table; \
    85                 _CLOSE
    86 
    87 // Create a (possibly polymorphic) virtual table forward declaration.
    88 #define _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) \
    89         extern const _EHM_VTABLE_TYPE(exception_name) arguments table_name
    90 
    91 // Create a (possibly polymorphic) virtual table definition.
    92 #define _EHM_VIRTUAL_TABLE(exception_type, arguments, table_name) \
    93         const _EHM_VTABLE_TYPE(exception_type) arguments table_name @= { \
    94                 .__cfavir_typeid : &_EHM_TYPE_ID_NAME(exception_type), \
    95                 .size : sizeof(struct exception_type arguments), \
    96                 .copy : copy, \
    97                 .^?{} : ^?{}, \
    98                 .msg : msg, \
     137// All internal helper macros begin with an underscore.
     138#define _CLOSE(...) __VA_ARGS__ }
     139#define _GLUE2(left, right) left##right
     140#define _GLUE3(left, middle, right) left##middle##right
     141#define _EXC_DISPATCH(to, ...) to(__VA_ARGS__,__cfaehm_base_exception_t,)
     142#define _UNPACK(...) __VA_ARGS__
     143
     144#define _TRIVIAL_EXCEPTION_DECLARATION(exception_name, parent_name, ...) \
     145        _VTABLE_DECLARATION(exception_name, parent_name)(); \
     146        struct exception_name { \
     147                VTABLE_FIELD(exception_name); \
     148        }; \
     149        void ?{}(exception_name & this); \
     150        const char * _GLUE2(exception_name,_msg)(exception_name * this)
     151
     152#define _TRIVIAL_EXCEPTION_INSTANCE(exception_name, parent_name, ...) \
     153        void ?{}(exception_name & this) { \
     154                VTABLE_INIT(this, exception_name); \
     155        } \
     156        const char * _GLUE2(exception_name,_msg)(exception_name * this) { \
     157                return #exception_name; \
     158        } \
     159        _VTABLE_INSTANCE(exception_name, parent_name,)(_GLUE2(exception_name,_msg))
     160
     161#define _FORALL_TRIVIAL_EXCEPTION(exception_name, parent_name, assertions, \
     162                parameters, parent_parameters) \
     163        _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \
     164                parameters, parent_parameters)(); \
     165        forall assertions struct exception_name { \
     166                FORALL_VTABLE_FIELD(exception_name, parameters); \
     167        }; \
     168        _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters)
     169
     170#define _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) \
     171        forall(_UNPACK assertions | \
     172                is_exception(exception_name parameters, VTABLE_TYPE(exception_name) parameters)) \
     173        void ?{}(exception_name parameters & this)
     174
     175#define _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) \
     176        _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) { \
     177                (this).virtual_table = &get_exception_vtable(&this); \
    99178        }
    100179
    101 // Create a (possibly polymorphic) copy function from an assignment operator.
    102 #define _EHM_DEFINE_FORALL_COPY(exception_name, forall_clause, parameters) \
    103         forall_clause void copy(exception_name parameters * this, \
    104                         exception_name parameters * that) { \
    105                 *this = *that; \
    106         }
    107 
    108 #define _EHM_DEFINE_COPY(exception_name, arguments) \
    109         void copy(exception_name arguments * this, exception_name arguments * that) { \
    110                 *this = *that; \
    111         }
    112 
    113 // Create a (possibly polymorphic) msg function
    114 #define _EHM_DEFINE_FORALL_MSG(exception_name, forall_clause, parameters) \
    115         forall_clause const char * msg(exception_name parameters * this) { \
    116                 return #exception_name #parameters; \
    117         }
    118 
    119 #define _EHM_DEFINE_MSG(exception_name, arguments) \
    120         const char * msg(exception_name arguments * this) { \
    121                 return #exception_name #arguments; \
    122         }
    123 
    124 // Produces the C compatable name of the virtual table type for a virtual type.
    125 #define _EHM_VTABLE_TYPE(type_name) struct _GLUE2(type_name,_vtable)
    126 
    127 // Create the vtable type for exception name.
    128 #define _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall_clause, parameters) \
    129         forall_clause struct exception_name; \
    130         forall_clause _EHM_VTABLE_TYPE(exception_name) { \
    131                 _EHM_TYPE_ID_TYPE(exception_name) parameters const * __cfavir_typeid; \
     180#define _DATA_EXCEPTION(exception_name, parent_name, ...) \
     181        _VTABLE_DECLARATION(exception_name, parent_name)(); \
     182        struct exception_name { \
     183                VTABLE_FIELD(exception_name); \
     184                _CLOSE
     185
     186#define _FORALL_DATA_EXCEPTION(exception_name, parent_name, \
     187                assertions, parameters, parent_parameters) \
     188        _FORALL_VTABLE_DECLARATION(exception_name, parent_name, \
     189                assertions, parameters, parent_parameters)(); \
     190        _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters); \
     191        forall assertions struct exception_name { \
     192                FORALL_VTABLE_FIELD(exception_name, parameters); \
     193                _CLOSE
     194
     195#define _VTABLE_DECLARATION(exception_name, parent_name, ...) \
     196        struct exception_name; \
     197        VTABLE_TYPE(exception_name); \
     198        VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *); \
     199        extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \
     200        VTABLE_TYPE(exception_name) { \
     201                VTABLE_TYPE(parent_name) const * parent; \
     202                size_t size; \
     203                void (*copy)(exception_name * this, exception_name * other); \
     204                void (*^?{})(exception_name & this); \
     205                const char * (*msg)(exception_name * this); \
     206                _CLOSE
     207
     208#define _VTABLE_INSTANCE(exception_name, parent_name, ...) \
     209        VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *) { \
     210                return VTABLE_NAME(exception_name); \
     211        } \
     212        void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \
     213                *this = *other; \
     214        } \
     215        VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name) @= { \
     216                &VTABLE_NAME(parent_name), sizeof(exception_name), \
     217                _GLUE2(exception_name,_copy), ^?{}, \
     218                _CLOSE
     219
     220#define _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \
     221                parameters, parent_parameters) \
     222        forall assertions struct exception_name; \
     223        forall assertions VTABLE_TYPE(exception_name) { \
     224                VTABLE_TYPE(parent_name) parent_parameters const * parent; \
    132225                size_t size; \
    133226                void (*copy)(exception_name parameters * this, exception_name parameters * other); \
    134227                void (*^?{})(exception_name parameters & this); \
    135228                const char * (*msg)(exception_name parameters * this); \
    136         }
    137 
    138 // Define the function required to satify the trait for exceptions.
    139 #define _EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \
    140         forall_clause inline void mark_exception( \
    141                 exception_name parameters const &, \
    142                 _EHM_VTABLE_TYPE(exception_name) parameters const &) {} \
    143 
    144 #define _EHM_TRAIT_FUNCTION2(exception_name, forall_clause, parameters) \
    145         forall_clause _EHM_VTABLE_TYPE(exception_name) parameters const & \
    146                         get_exception_vtable(exception_name parameters const & this)
    147 
    148 #define __EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \
    149         forall_clause inline _EHM_VTABLE_TYPE(exception_name) parameters const & \
    150                         get_exception_vtable(exception_name parameters const & this) { \
    151                 /* This comes before the structure definition, but we know the offset. */ \
    152                 /* return (_EHM_VTABLE_TYPE(exception_name) parameters const &)this; */ \
    153                 assert(false); \
    154         }
    155 
    156 // Generates a new type-id structure. This is used to mangle the name of the
    157 // type-id instance so it also includes polymorphic information. Must be the
    158 // direct decendent of exception_t.
    159 // The second field is used to recover type information about the exception.
    160 #define _EHM_TYPE_ID_STRUCT(exception_name, forall_clause) \
    161         forall_clause _EHM_TYPE_ID_TYPE(exception_name) { \
    162                 __cfa__parent_vtable const * parent; \
    163         }
    164 
    165 // Generate a new type-id value.
    166 #define _EHM_TYPE_ID_VALUE(exception_name, arguments) \
    167         __attribute__(( section(".gnu.linkonce." "__cfatid_" #exception_name) )) \
    168         _EHM_TYPE_ID_TYPE(exception_name) arguments const \
    169                         _EHM_TYPE_ID_NAME(exception_name) = { \
    170                 &__cfatid_exception_t, \
    171         }
    172 
    173 // _EHM_TYPE_ID_STRUCT and _EHM_TYPE_ID_VALUE are the two that would need to
    174 // be updated to extend the hierarchy if we are still using macros when that
    175 // is added.
    176 
    177 // Produce the C compatable name of the type-id type for an exception type.
    178 #define _EHM_TYPE_ID_TYPE(exception_name) \
    179         struct _GLUE2(__cfatid_struct_, exception_name)
    180 
    181 // Produce the name of the instance of the type-id for an exception type.
    182 #define _EHM_TYPE_ID_NAME(exception_name) _GLUE2(__cfatid_,exception_name)
     229                _CLOSE
     230
     231#define _POLY_VTABLE_INSTANCE(exception_name, parent_name, ...) \
     232        extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name); \
     233        VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable( \
     234                        exception_name(__VA_ARGS__) *) { \
     235                return VTABLE_NAME(exception_name); \
     236        } \
     237        void _GLUE2(exception_name,_copy)( \
     238                        exception_name(__VA_ARGS__) * this, exception_name(__VA_ARGS__) * other) { \
     239                *this = *other; \
     240        } \
     241        VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name) @= { \
     242                &VTABLE_NAME(parent_name), sizeof(exception_name(__VA_ARGS__)), \
     243                _GLUE2(exception_name,_copy), ^?{}, \
     244                _CLOSE
    183245
    184246#define _IS_EXCEPTION(kind, exception_name, parameters, ...) \
    185         kind(exception_name parameters, _EHM_VTABLE_TYPE(exception_name) parameters)
    186 
    187 // Internal helper macros:
    188 #define _CLOSE(...) __VA_ARGS__ }
    189 #define _GLUE2(left, right) left##right
     247        kind(exception_name parameters, VTABLE_TYPE(exception_name) parameters)
  • libcfa/src/fstream.cfa

    rc8a0210 r857a1c6  
    321321
    322322
    323 EHM_VIRTUAL_TABLE(Open_Failure, Open_Failure_main_table);
    324323void ?{}( Open_Failure & this, ofstream & ostream ) {
    325         this.virtual_table = &Open_Failure_main_table;
     324        VTABLE_INIT(this, Open_Failure);
    326325        this.ostream = &ostream;
    327326        this.tag = 1;
    328327}
    329328void ?{}( Open_Failure & this, ifstream & istream ) {
    330         this.virtual_table = &Open_Failure_main_table;
     329        VTABLE_INIT(this, Open_Failure);
    331330        this.istream = &istream;
    332331        this.tag = 0;
    333332}
     333const char * Open_Failure_msg(Open_Failure * this) {
     334        return "Open_Failure";
     335}
     336VTABLE_INSTANCE(Open_Failure)(Open_Failure_msg);
    334337void throwOpen_Failure( ofstream & ostream ) {
    335338        Open_Failure exc = { ostream };
  • libcfa/src/fstream.hfa

    rc8a0210 r857a1c6  
    133133
    134134
    135 EHM_EXCEPTION(Open_Failure)(
     135DATA_EXCEPTION(Open_Failure)(
    136136        union {
    137137                ofstream * ostream;
  • libcfa/src/iostream.cfa

    rc8a0210 r857a1c6  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 13 13:05:24 2021
    13 // Update Count     : 1324
     12// Last Modified On : Tue Mar  2 14:51:30 2021
     13// Update Count     : 1151
    1414//
    1515
     
    195195                        int len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
    196196                        fmt( os, "%s", buf ); \
    197                         if ( isfinite( val ) ) { /* if number, print decimal point when no fraction or exponent */ \
     197                        if ( isfinite( val ) ) {                                        /* if number, always print decimal point */ \
    198198                                for ( int i = 0;; i += 1 ) { \
    199199                                        if ( i == len ) { fmt( os, "." ); break; } \
    200                                         if ( buf[i] == '.' || buf[i] == 'e' || buf[i] == 'E' ) break; /* decimal point or scientific ? */ \
     200                                        if ( buf[i] == '.' ) break; \
    201201                                } /* for */ \
    202202                        } /* if */ \
     
    525525} // distribution
    526526
    527 IntegralFMTImpl( signed char, "     *hh ", "     *.*hh " )
    528 IntegralFMTImpl( unsigned char, "     *hh ", "     *.*hh " )
    529 IntegralFMTImpl( signed short int, "     *h ", "     *.*h " )
    530 IntegralFMTImpl( unsigned short int, "     *h ", "     *.*h " )
    531 IntegralFMTImpl( signed int, "     * ", "     *.* " )
    532 IntegralFMTImpl( unsigned int, "     * ", "     *.* " )
    533 IntegralFMTImpl( signed long int, "     *l ", "     *.*l " )
    534 IntegralFMTImpl( unsigned long int, "     *l ", "     *.*l " )
    535 IntegralFMTImpl( signed long long int, "     *ll ", "     *.*ll " )
    536 IntegralFMTImpl( unsigned long long int, "     *ll ", "     *.*ll " )
    537 
    538 
     527IntegralFMTImpl( signed char, "%    *hh ", "%    *.*hh " )
     528IntegralFMTImpl( unsigned char, "%    *hh ", "%    *.*hh " )
     529IntegralFMTImpl( signed short int, "%    *h ", "%    *.*h " )
     530IntegralFMTImpl( unsigned short int, "%    *h ", "%    *.*h " )
     531IntegralFMTImpl( signed int, "%    * ", "%    *.* " )
     532IntegralFMTImpl( unsigned int, "%    * ", "%    *.* " )
     533IntegralFMTImpl( signed long int, "%    *l ", "%    *.*l " )
     534IntegralFMTImpl( unsigned long int, "%    *l ", "%    *.*l " )
     535IntegralFMTImpl( signed long long int, "%    *ll ", "%    *.*ll " )
     536IntegralFMTImpl( unsigned long long int, "%    *ll ", "%    *.*ll " )
     537
     538#if 0
     539#if defined( __SIZEOF_INT128__ )
     540// Default prefix for non-decimal prints is 0b, 0, 0x.
     541#define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \
     542forall( ostype & | ostream( ostype ) ) \
     543static void base10_128( ostype & os, _Ostream_Manip(T) f ) { \
     544        if ( f.val > UINT64_MAX ) { \
     545                unsigned long long int lsig = f.val % P10_UINT64; \
     546                f.val /= P10_UINT64; /* msig */ \
     547                base10_128( os, f ); /* recursion */ \
     548                _Ostream_Manip(unsigned long long int) fmt @= { lsig, 0, 19, 'u', { .all : 0 } }; \
     549                fmt.flags.nobsdp = true; \
     550                /* printf( "fmt1 %c %lld %d\n", fmt.base, fmt.val, fmt.all ); */ \
     551                sepOff( os ); \
     552                (ostype &)(os | fmt); \
     553        } else { \
     554                /* printf( "fmt2 %c %lld %d\n", f.base, (unsigned long long int)f.val, f.all ); */ \
     555                _Ostream_Manip(SIGNED long long int) fmt @= { (SIGNED long long int)f.val, f.wd, f.pc, f.base, { .all : f.all } }; \
     556                (ostype &)(os | fmt); \
     557        } /* if */ \
     558} /* base10_128 */ \
     559forall( ostype & | ostream( ostype ) ) { \
     560        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
     561                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     562\
     563                if ( f.base == 'b' | f.base == 'B' | f.base == 'o' | f.base == 'x' | f.base == 'X' ) { \
     564                        unsigned long long int msig = (unsigned long long int)(f.val >> 64); \
     565                        unsigned long long int lsig = (unsigned long long int)(f.val); \
     566                        _Ostream_Manip(SIGNED long long int) fmt @= { msig, f.wd, f.pc, f.base, { .all : f.all } }; \
     567                        _Ostream_Manip(unsigned long long int) fmt2 @= { lsig, 0, 0, f.base, { .all : 0 } }; \
     568                        if ( msig == 0 ) { \
     569                                fmt.val = lsig; \
     570                                (ostype &)(os | fmt); \
     571                        } else { \
     572                                fmt2.flags.pad0 = fmt2.flags.nobsdp = true;     \
     573                                if ( f.base == 'b' | f.base == 'B' ) { \
     574                                        if ( fmt.flags.pc && fmt.pc > 64 ) fmt.pc -= 64; else { fmt.flags.pc = false; fmt.pc = 0; } \
     575                                        if ( fmt.flags.left ) { \
     576                                                fmt.flags.left = false; \
     577                                                fmt.wd = 0; \
     578                                                /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
     579                                                fmt2.flags.left = true; \
     580                                                int msigd = high1( msig ); \
     581                                                fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
     582                                                if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0b base specifier */ \
     583                                                if ( (int)fmt2.wd < 64 ) fmt2.wd = 64; /* cast deals with negative value */ \
     584                                                fmt2.flags.pc = true; fmt2.pc = 64; \
     585                                        } else { \
     586                                                if ( fmt.wd > 64 ) fmt.wd -= 64; \
     587                                                else fmt.wd = 1; \
     588                                                /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
     589                                                fmt2.wd = 64; \
     590                                        } /* if */ \
     591                                        /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
     592                                        (ostype &)(os | fmt | "" | fmt2); \
     593                                } else if ( f.base == 'o' ) { \
     594                                        if ( fmt.flags.pc && fmt.pc > 22 ) fmt.pc -= 22; else { fmt.flags.pc = false; fmt.pc = 0; } \
     595                                        fmt.val = (unsigned long long int)fmt.val >> 2; \
     596                                        fmt2.val = ((msig & 0x3) << 1) + ((lsig & 0x8000000000000000U) != 0); \
     597                                        if ( fmt.flags.left ) { \
     598                                                fmt.flags.left = false; \
     599                                                fmt.wd = 0; \
     600                                                /* printf( "L %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
     601                                                (ostype &)(os | fmt | "" | fmt2); \
     602                                                sepOff( os ); \
     603                                                fmt2.flags.left = true; \
     604                                                int msigd = ceiling_div( high1( fmt.val ), 3 ); \
     605                                                fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
     606                                                if ( ! fmt.flags.nobsdp ) fmt2.wd -= 1; /* compensate for 0 base specifier */ \
     607                                                if ( (int)fmt2.wd < 21 ) fmt2.wd = 21; /* cast deals with negative value */ \
     608                                                fmt2.flags.pc = true; fmt2.pc = 21; \
     609                                        } else { \
     610                                                if ( fmt.wd > 22 ) fmt.wd -= 22; \
     611                                                else fmt.wd = 1; \
     612                                                /* printf( "R %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
     613                                                (ostype &)(os | fmt | "" | fmt2); \
     614                                                sepOff( os ); \
     615                                                fmt2.wd = 21; \
     616                                        } /* if */ \
     617                                        fmt2.val = lsig & 0x7fffffffffffffffU; \
     618                                        /* printf( "\nC %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
     619                                        (ostype &)(os | fmt2); \
     620                                } else { /* f.base == 'x'  | f.base == 'X' */ \
     621                                        if ( fmt.flags.pc && fmt.pc > 16 ) fmt.pc -= 16; else { fmt.flags.pc = false; fmt.pc = 0; } \
     622                                        if ( fmt.flags.left ) { \
     623                                                fmt.flags.left = false; \
     624                                                fmt.wd = 0; \
     625                                                /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
     626                                                fmt2.flags.left = true; \
     627                                                int msigd = high1( msig ); \
     628                                                fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
     629                                                if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0x base specifier */ \
     630                                                if ( (int)fmt2.wd < 16 ) fmt2.wd = 16; /* cast deals with negative value */ \
     631                                                fmt2.flags.pc = true; fmt2.pc = 16; \
     632                                        } else { \
     633                                                if ( fmt.wd > 16 ) fmt.wd -= 16; \
     634                                                else fmt.wd = 1; \
     635                                                /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
     636                                                fmt2.wd = 16; \
     637                                        } /* if */ \
     638                                        /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
     639                                        (ostype &)(os | fmt | "" | fmt2); \
     640                                } /* if */ \
     641                        } /* if */ \
     642                } else { \
     643                        if ( CODE == 'd' ) { \
     644                                if ( f.val < 0 )  { fmt( os, "-" ); sepOff( os ); f.val = -f.val; f.flags.sign = false; } \
     645                        } /* if */ \
     646                        base10_128( os, f ); \
     647                } /* if */ \
     648                return os; \
     649        } /* ?|? */ \
     650        void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
     651} // distribution
     652
     653IntegralFMTImpl128( int128, signed, 'd', "%    *ll ", "%    *.*ll " )
     654IntegralFMTImpl128( unsigned int128, unsigned, 'u', "%    *ll ", "%    *.*ll " )
     655#endif // __SIZEOF_INT128__
     656#endif // 0
     657
     658#if 1
    539659#if defined( __SIZEOF_INT128__ )
    540660// Default prefix for non-decimal prints is 0b, 0, 0x.
     
    626746IntegralFMTImpl128( unsigned int128 )
    627747#endif // __SIZEOF_INT128__
     748#endif // 0
    628749
    629750// *********************************** floating point ***********************************
    630751
    631 static const char *suffixes[] = {
    632         "y", "z", "a", "f", "p", "n", "u", "m", "",
    633         "K", "M", "G", "T", "P", "E", "Z", "Y"
    634 };
    635 #define SUFFIXES_START (-24) /* Smallest power for which there is a suffix defined. */
    636 #define SUFFIXES_END (SUFFIXES_START + (int)((sizeof(suffixes) / sizeof(char *) - 1) * 3))
    637 
    638 #define PrintWithDP2( os, format, ... ) \
     752#define PrintWithDP2( os, format, val, ... ) \
    639753        { \
    640                 if ( ! f.flags.eng ) { \
    641                         len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
    642                         if ( isfinite( f.val ) && ( f.pc != 0 || ! f.flags.nobsdp ) ) { /* if number, print decimal point when no fraction or exponent */ \
    643                                 for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */ \
    644                                 if ( i == len ) { \
    645                                         if ( ! f.flags.left ) { \
    646                                                 buf[i] = '.'; buf[i + 1] = '\0'; \
    647                                                 if ( buf[0] == ' ' ) bufbeg = 1; /* decimal point within width */ \
    648                                         } else { \
    649                                                 for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \
    650                                                 buf[i] = '.'; \
    651                                                 if ( i == len ) buf[i + 1] = '\0'; \
    652                                         } /* if */ \
     754                enum { size = 48 }; \
     755                char buf[size]; \
     756                int bufbeg = 0, i, len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
     757                if ( isfinite( val ) && (f.base != 'g' || f.pc != 0) ) { /* if number, print decimal point */ \
     758                        for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */ \
     759                        if ( i == len && ! f.flags.nobsdp ) { \
     760                                if ( ! f.flags.left ) { \
     761                                        buf[i] = '.'; buf[i + 1] = '\0'; \
     762                                        if ( buf[0] == ' ' ) bufbeg = 1;        /* decimal point within width */ \
     763                                } else { \
     764                                        for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \
     765                                        buf[i] = '.'; \
     766                                        if ( i == len ) buf[i + 1] = '\0'; \
    653767                                } /* if */ \
    654768                        } /* if */ \
    655                 } else { \
    656                         int exp10, len2; \
    657                         eng( f.val, f.pc, exp10 );                                      /* changes arguments */ \
    658                         if ( ! f.flags.left && f.wd > 1 ) { \
    659                                 /* Exponent size (number of digits, 'e', optional minus sign) */ \
    660                                 f.wd -= lrint( floor( log10( abs( exp10 ) ) ) ) + 1 + 1 + (exp10 < 0 ? 1 : 0); \
    661                                 if ( f.wd < 1 ) f.wd = 1; \
    662                         } /* if */ \
    663                         len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
    664                         if ( f.flags.left ) { \
    665                                 for ( len -= 1; len > 0 && buf[len] == ' '; len -= 1 ); \
    666                                 len += 1; \
    667                         } /* if */ \
    668                         if ( ! f.flags.nobsdp || (exp10 < SUFFIXES_START) || (exp10 > SUFFIXES_END) ) { \
    669                                 len2 = snprintf( &buf[len], size - len, "e%d", exp10 ); \
    670                         } else { \
    671                                 len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \
    672                         } /* if */ \
    673                         if ( f.flags.left && len + len2 < f.wd ) buf[len + len2] = ' '; \
    674769                } /* if */ \
    675770                fmt( os, "%s", &buf[bufbeg] ); \
     
    678773#define FloatingPointFMTImpl( T, DFMTNP, DFMTP ) \
    679774forall( ostype & | ostream( ostype ) ) { \
    680         static void eng( T &value, int & pc, int & exp10 ) { \
    681                 exp10 = lrint( floor( log10( abs( value ) ) ) ); /* round to desired precision */ \
    682                 if ( exp10 < 0 ) exp10 -= 2; \
    683                 exp10 = floor( exp10, 3 ); \
    684                 value *= pow( 10.0, -exp10 ); \
    685                 if ( pc <= 3 ) pc = 3; \
    686         } /* eng */ \
    687 \
    688775        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    689                 enum { size = 48 }; \
    690                 char buf[size]; \
    691                 int bufbeg = 0, i, len; \
    692 \
    693776                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
    694                 char fmtstr[sizeof(DFMTP) + 8];                                 /* sizeof includes '\0' */ \
     777                char fmtstr[sizeof(DFMTP)];                                             /* sizeof includes '\0' */ \
    695778                if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
    696779                else memcpy( &fmtstr, DFMTP, sizeof(DFMTP) ); \
     
    706789                        fmtstr[sizeof(DFMTNP)-2] = f.base;                      /* sizeof includes '\0' */ \
    707790                        /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star]); */ \
    708                         PrintWithDP2( os, &fmtstr[star], f.wd, f.val ) \
     791                        PrintWithDP2( os, &fmtstr[star], f.val, f.wd ) \
    709792                } else {                                                                                /* precision */ \
    710793                        fmtstr[sizeof(DFMTP)-2] = f.base;                       /* sizeof includes '\0' */ \
    711794                        /* printf( "%g %d %d %s\n", f.val, f.wd, f.pc, &fmtstr[star] ); */ \
    712                         PrintWithDP2( os, &fmtstr[star], f.wd, f.pc, f.val ) \
     795                        PrintWithDP2( os, &fmtstr[star], f.val, f.wd, f.pc ) \
    713796                } /* if */ \
    714797                return os; \
     
    718801} // distribution
    719802
    720 FloatingPointFMTImpl( double, "     * ", "     *.* " )
    721 FloatingPointFMTImpl( long double, "     *L ", "     *.*L " )
     803FloatingPointFMTImpl( double, "%    * ", "%    *.* " )
     804FloatingPointFMTImpl( long double, "%    *L ", "%    *.*L " )
    722805
    723806// *********************************** character ***********************************
  • libcfa/src/iostream.hfa

    rc8a0210 r857a1c6  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 13 13:05:11 2021
    13 // Update Count     : 384
     12// Last Modified On : Tue Mar  2 14:05:08 2021
     13// Update Count     : 369
    1414//
    1515
     
    158158struct _Ostream_Manip {
    159159        T val;                                                                                          // polymorphic base-type
    160         int wd, pc;                                                                                     // width, precision
     160        unsigned int wd, pc;                                                            // width, precision
    161161        char base;                                                                                      // numeric base / floating-point style
    162162        union {
    163163                unsigned char all;
    164164                struct {
    165                         unsigned char eng:1;                                            // engineering notation
    166165                        unsigned char neg:1;                                            // val is negative
    167166                        unsigned char pc:1;                                                     // precision specified
     
    223222        _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'a', { .all : 0 } }; } \
    224223        _Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'e', { .all : 0 } }; } \
    225         _Ostream_Manip(T) eng( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.eng : true } }; } \
    226         _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'g', { .all : 0 } }; } \
     224        _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .all : 0 } }; } \
    227225        _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
    228226        _Ostream_Manip(T) ws( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
    229         _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; return fmt; } \
    230         _Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
    231         _Ostream_Manip(T) & ws( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
     227        _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
     228        _Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
    232229        _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
    233230        _Ostream_Manip(T) upcase( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'G', { .all : 0 } }; } \
     
    238235        _Ostream_Manip(T) nodp( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
    239236        _Ostream_Manip(T) & nodp( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
    240         _Ostream_Manip(T) unit( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
    241         _Ostream_Manip(T) & unit( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
    242237} /* distribution */ \
    243238forall( ostype & | ostream( ostype ) ) { \
  • libcfa/src/math.hfa

    rc8a0210 r857a1c6  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // math.hfa --
     7// math --
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Mon Apr 18 23:37:04 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Apr 15 11:47:56 2021
    13 // Update Count     : 132
     12// Last Modified On : Mon Aug 24 08:56:20 2020
     13// Update Count     : 126
    1414//
    1515
     
    100100        long double _Complex log( long double _Complex x ) { return clogl( x ); }
    101101
    102         // O(1) polymorphic integer log2, using clz, which returns the number of leading 0-bits, starting at the most
    103         // significant bit (single instruction on x86)
    104         int log2( unsigned int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clz( n ); }
    105         long int log2( unsigned long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzl( n ); }
    106         long long int log2( unsigned long long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzll( n ); }
    107102        float log2( float x ) { return log2f( x ); }
    108103        // extern "C" { double log2( double ); }
  • libcfa/src/time.hfa

    rc8a0210 r857a1c6  
    1010// Created On       : Wed Mar 14 23:18:57 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 14 09:30:30 2021
    13 // Update Count     : 664
     12// Last Modified On : Wed Jun 17 16:13:00 2020
     13// Update Count     : 663
    1414//
    1515
     
    2929static inline {
    3030        Duration ?=?( Duration & dur, __attribute__((unused)) zero_t ) { return dur{ 0 }; }
    31 
    32         void ?{}( Duration & dur, timeval t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
    33         Duration ?=?( Duration & dur, timeval t ) with( dur ) {
    34                 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL);
    35                 return dur;
    36         } // ?=?
    37 
    38         void ?{}( Duration & dur, timespec t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
    39         Duration ?=?( Duration & dur, timespec t ) with( dur ) {
    40                 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
    41                 return dur;
    42         } // ?=?
    4331
    4432        Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tn }; }
  • libcfa/src/virtual.c

    rc8a0210 r857a1c6  
    1515
    1616#include "virtual.h"
    17 #include "assert.h"
    1817
    1918int __cfa__is_parent( struct __cfa__parent_vtable const * parent,
    2019        struct __cfa__parent_vtable const * child ) {
    21         assert( child );
    2220        do {
    2321                if ( parent == child )
     
    3028void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent,
    3129        struct __cfa__parent_vtable const * const * child ) {
    32         assert( child );
    3330        return (__cfa__is_parent(parent, *child)) ? (void *)child : (void *)0;
    3431}
  • src/AST/Expr.cpp

    rc8a0210 r857a1c6  
    260260}
    261261
    262 ConstantExpr * ConstantExpr::from_string( const CodeLocation & loc, const std::string & str ) {
    263         const Type * charType = new BasicType( BasicType::Char );
    264         // Adjust the length of the string for the terminator.
    265         const Expr * strSize = from_ulong( loc, str.size() + 1 );
    266         const Type * strType = new ArrayType( charType, strSize, FixedLen, StaticDim );
    267         const std::string strValue = "\"" + str + "\"";
    268         return new ConstantExpr( loc, strType, strValue, std::nullopt );
    269 }
    270 
    271262ConstantExpr * ConstantExpr::null( const CodeLocation & loc, const Type * ptrType ) {
    272263        return new ConstantExpr{
  • src/AST/Expr.hpp

    rc8a0210 r857a1c6  
    438438        long long int intValue() const;
    439439
    440         /// Generates a boolean constant of the given bool.
     440        /// generates a boolean constant of the given bool
    441441        static ConstantExpr * from_bool( const CodeLocation & loc, bool b );
    442         /// Generates an integer constant of the given int.
     442        /// generates an integer constant of the given int
    443443        static ConstantExpr * from_int( const CodeLocation & loc, int i );
    444         /// Generates an integer constant of the given unsigned long int.
     444        /// generates an integer constant of the given unsigned long int
    445445        static ConstantExpr * from_ulong( const CodeLocation & loc, unsigned long i );
    446         /// Generates a string constant from the given string (char type, unquoted string).
    447         static ConstantExpr * from_string( const CodeLocation & loc, const std::string & string );
    448         /// Generates a null pointer value for the given type. void * if omitted.
     446        /// generates a null pointer value for the given type. void * if omitted.
    449447        static ConstantExpr * null( const CodeLocation & loc, const Type * ptrType = nullptr );
    450448
  • src/Concurrency/Keywords.cc

    rc8a0210 r857a1c6  
    4242
    4343namespace Concurrency {
    44         inline static std::string getTypeIdName( std::string const & exception_name ) {
    45                 return exception_name.empty() ? std::string() : Virtual::typeIdType( exception_name );
    46         }
    4744        inline static std::string getVTableName( std::string const & exception_name ) {
    48                 return exception_name.empty() ? std::string() : Virtual::vtableTypeName( exception_name );
     45                return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name);
    4946        }
    5047
     
    7875                  type_name( type_name ), field_name( field_name ), getter_name( getter_name ),
    7976                  context_error( context_error ), exception_name( exception_name ),
    80                   typeid_name( getTypeIdName( exception_name ) ),
    8177                  vtable_name( getVTableName( exception_name ) ),
    8278                  needs_main( needs_main ), cast_target( cast_target ) {}
     
    8884
    8985                void handle( StructDecl * );
    90                 void addTypeId( StructDecl * );
    9186                void addVtableForward( StructDecl * );
    9287                FunctionDecl * forwardDeclare( StructDecl * );
     
    10499                const std::string context_error;
    105100                const std::string exception_name;
    106                 const std::string typeid_name;
    107101                const std::string vtable_name;
    108102                bool needs_main;
     
    112106                FunctionDecl * dtor_decl = nullptr;
    113107                StructDecl * except_decl = nullptr;
    114                 StructDecl * typeid_decl = nullptr;
    115108                StructDecl * vtable_decl = nullptr;
    116109        };
     
    399392                else if ( !except_decl && exception_name == decl->name && decl->body ) {
    400393                        except_decl = decl;
    401                 }
    402                 else if ( !typeid_decl && typeid_name == decl->name && decl->body ) {
    403                         typeid_decl = decl;
    404394                }
    405395                else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
     
    458448                if( !dtor_decl ) SemanticError( decl, context_error );
    459449
    460                 if ( !exception_name.empty() ) {
    461                         if( !typeid_decl ) SemanticError( decl, context_error );
    462                         if( !vtable_decl ) SemanticError( decl, context_error );
    463 
    464                         addTypeId( decl );
    465                         addVtableForward( decl );
    466                 }
     450                addVtableForward( decl );
    467451                FunctionDecl * func = forwardDeclare( decl );
    468452                ObjectDecl * field = addField( decl );
     
    470454        }
    471455
    472         void ConcurrentSueKeyword::addTypeId( StructDecl * decl ) {
    473                 assert( typeid_decl );
    474                 StructInstType typeid_type( Type::Const, typeid_decl );
    475                 typeid_type.parameters.push_back( new TypeExpr(
    476                         new StructInstType( noQualifiers, decl )
     456        void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
     457                if ( vtable_decl ) {
     458                        std::list< Expression * > poly_args = {
     459                                new TypeExpr( new StructInstType( noQualifiers, decl ) ),
     460                        };
     461                        declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
     462                                vtable_decl->makeInst( poly_args ),
     463                                except_decl->makeInst( poly_args )
    477464                        ) );
    478                 declsToAddBefore.push_back( Virtual::makeTypeIdInstance( &typeid_type ) );
    479         }
    480 
    481         void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
    482                 assert( vtable_decl );
    483                 std::list< Expression * > poly_args = {
    484                         new TypeExpr( new StructInstType( noQualifiers, decl ) ),
    485                 };
    486                 declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
    487                         vtable_decl->makeInst( poly_args ),
    488                         except_decl->makeInst( poly_args )
    489                 ) );
    490                 declsToAddBefore.push_back( Virtual::makeVtableForward(
    491                         vtable_decl->makeInst( move( poly_args ) ) ) );
     465                        declsToAddBefore.push_back( Virtual::makeVtableForward(
     466                                vtable_decl->makeInst( move( poly_args ) ) ) );
     467                // Its only an error if we want a vtable and don't have one.
     468                } else if ( ! vtable_name.empty() ) {
     469                        SemanticError( decl, context_error );
     470                }
    492471        }
    493472
  • src/Parser/parser.yy

    rc8a0210 r857a1c6  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 14 18:13:44 2021
    13 // Update Count     : 4983
     12// Last Modified On : Thu Apr  1 14:43:24 2021
     13// Update Count     : 4978
    1414//
    1515
     
    281281%token ATTRIBUTE EXTENSION                                                              // GCC
    282282%token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN
    283 %token CHOOSE FALLTHRU FALLTHROUGH WITH WHEN WAITFOR    // CFA
    284 %token DISABLE ENABLE TRY THROW THROWRESUME AT                  // CFA
     283%token CHOOSE DISABLE ENABLE FALLTHRU FALLTHROUGH TRY THROW THROWRESUME AT WITH WHEN WAITFOR // CFA
    285284%token ASM                                                                                              // C99, extension ISO/IEC 9899:1999 Section J.5.10(1)
    286285%token ALIGNAS ALIGNOF GENERIC STATICASSERT                             // C11
  • src/SynTree/Constant.cc

    rc8a0210 r857a1c6  
    4242}
    4343
    44 Constant Constant::from_string( const std::string & str ) {
    45         Type * charType = new BasicType( noQualifiers, BasicType::Char );
    46         // Adjust the length of the string for the terminator.
    47         Expression * strSize = new ConstantExpr( Constant::from_ulong( str.size() + 1 ) );
    48         Type * strType = new ArrayType( noQualifiers, charType, strSize, false, false );
    49         const std::string strValue = "\"" + str + "\"";
    50         return Constant( strType, strValue, std::nullopt );
    51 }
    52 
    5344Constant Constant::null( Type * ptrtype ) {
    5445        if ( nullptr == ptrtype ) {
  • src/SynTree/Constant.h

    rc8a0210 r857a1c6  
    4747        /// generates an integer constant of the given unsigned long int
    4848        static Constant from_ulong( unsigned long i );
    49         /// generates a string constant from the given string (char type, unquoted string)
    50         static Constant from_string( const std::string & string );
    5149
    5250        /// generates a null pointer value for the given type. void * if omitted.
  • src/Virtual/ExpandCasts.cc

    rc8a0210 r857a1c6  
    3232namespace Virtual {
    3333
    34 static bool is_prefix( const std::string & prefix, const std::string& entire ) {
    35         size_t const p_size = prefix.size();
    36         return (p_size < entire.size() && prefix == entire.substr(0, p_size));
    37 }
    38 
    39 static bool is_type_id_object( const ObjectDecl * objectDecl ) {
    40         const std::string & objectName = objectDecl->name;
    41         return is_prefix( "__cfatid_", objectName );
    42 }
    43 
    4434        // Indented until the new ast code gets added.
    4535
     
    7666        };
    7767
     68        /* Currently virtual depends on the rather brittle name matching between
     69         * a (strict/explicate) virtual type, its vtable type and the vtable
     70         * instance.
     71         * A stronger implementation, would probably keep track of those triads
     72         * and use that information to create better error messages.
     73         */
     74
     75        namespace {
     76
     77        std::string get_vtable_name( std::string const & name ) {
     78                return name + "_vtable";
     79        }
     80
     81        std::string get_vtable_inst_name( std::string const & name ) {
     82                return std::string("_") + get_vtable_name( name ) + "_instance";
     83        }
     84
     85        std::string get_vtable_name_root( std::string const & name ) {
     86                return name.substr(0, name.size() - 7 );
     87        }
     88
     89        std::string get_vtable_inst_name_root( std::string const & name ) {
     90                return get_vtable_name_root( name.substr(1, name.size() - 10 ) );
     91        }
     92
     93        bool is_vtable_inst_name( std::string const & name ) {
     94                return 17 < name.size() &&
     95                        name == get_vtable_inst_name( get_vtable_inst_name_root( name ) );
     96        }
     97
     98        } // namespace
     99
    78100        class VirtualCastCore {
    79                 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {
     101                Type * pointer_to_pvt(int level_of_indirection) {
    80102                        Type * type = new StructInstType(
    81103                                Type::Qualifiers( Type::Const ), pvt_decl );
     
    83105                                type = new PointerType( noQualifiers, type );
    84106                        }
    85                         return new CastExpr( expr, type );
     107                        return type;
    86108                }
    87109
     
    119141
    120142        void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
    121                 if ( is_type_id_object( objectDecl ) ) {
    122                         // Multiple definitions should be fine because of linkonce.
    123                         indexer.insert( objectDecl );
     143                if ( is_vtable_inst_name( objectDecl->get_name() ) ) {
     144                        if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) {
     145                                std::string msg = "Repeated instance of virtual table, original found at: ";
     146                                msg += existing->location.filename;
     147                                msg += ":" + toString( existing->location.first_line );
     148                                SemanticError( objectDecl->location, msg );
     149                        }
    124150                }
    125151        }
     
    144170        }
    145171
    146         /// Get the base type from a pointer or reference.
    147         const Type * getBaseType( const Type * type ) {
    148                 if ( auto target = dynamic_cast<const PointerType *>( type ) ) {
    149                         return target->base;
    150                 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {
    151                         return target->base;
     172        /// Get the virtual table type used in a virtual cast.
     173        Type * getVirtualTableType( const VirtualCastExpr * castExpr ) {
     174                const Type * objectType;
     175                if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) {
     176                        objectType = target->base;
     177                } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) {
     178                        objectType = target->base;
    152179                } else {
    153                         return nullptr;
    154                 }
    155         }
    156 
    157         /* Attempt to follow the "head" field of the structure to get the...
    158          * Returns nullptr on error, otherwise owner must free returned node.
    159          */
    160         StructInstType * followHeadPointerType(
    161                         const StructInstType * oldType,
    162                         const std::string& fieldName,
    163                         const CodeLocation& errorLocation ) {
    164 
    165                 // First section of the function is all about trying to fill this variable in.
    166                 StructInstType * newType = nullptr;
    167                 {
    168                         const StructDecl * oldDecl = oldType->baseStruct;
    169                         assert( oldDecl );
    170 
    171                         // Helper function for throwing semantic errors.
    172                         auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {
    173                                 const std::string& context = "While following head pointer of " +
    174                                         oldDecl->name + " named '" + fieldName + "': ";
    175                                 SemanticError( errorLocation, context + message );
    176                         };
    177 
    178                         if ( oldDecl->members.empty() ) {
    179                                 throwError( "Type has no fields." );
    180                         }
    181                         const Declaration * memberDecl = oldDecl->members.front();
     180                        castError( castExpr, "Virtual cast type must be a pointer or reference type." );
     181                }
     182                assert( objectType );
     183
     184                const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType );
     185                if ( nullptr == structType ) {
     186                        castError( castExpr, "Virtual cast type must refer to a structure type." );
     187                }
     188                const StructDecl * structDecl = structType->baseStruct;
     189                assert( structDecl );
     190
     191                const ObjectDecl * fieldDecl = nullptr;
     192                if ( 0 < structDecl->members.size() ) {
     193                        const Declaration * memberDecl = structDecl->members.front();
    182194                        assert( memberDecl );
    183                         const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
    184                         assert( fieldDecl );
    185                         if ( fieldName != fieldDecl->name ) {
    186                                 throwError( "Head field did not have expected name." );
    187                         }
    188 
    189                         const Type * fieldType = fieldDecl->type;
    190                         if ( nullptr == fieldType ) {
    191                                 throwError( "Could not get head field." );
    192                         }
    193                         const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );
    194                         if ( nullptr == ptrType ) {
    195                                 throwError( "First field is not a pointer type." );
    196                         }
    197                         assert( ptrType->base );
    198                         newType = dynamic_cast<StructInstType *>( ptrType->base );
    199                         if ( nullptr == newType ) {
    200                                 throwError( "First field does not point to a structure type." );
    201                         }
    202                 }
    203 
    204                 // Now we can look into copying it.
    205                 newType = newType->clone();
    206                 if ( ! oldType->parameters.empty() ) {
    207                         deleteAll( newType->parameters );
    208                         newType->parameters.clear();
    209                         cloneAll( oldType->parameters, newType->parameters );
    210                 }
    211                 return newType;
    212         }
    213 
    214         /// Get the type-id type from a virtual type.
    215         StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {
    216                 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );
    217                 if ( nullptr == typeInst ) {
    218                         return nullptr;
    219                 }
    220                 StructInstType * tableInst =
    221                         followHeadPointerType( typeInst, "virtual_table", errorLocation );
    222                 if ( nullptr == tableInst ) {
    223                         return nullptr;
    224                 }
    225                 StructInstType * typeIdInst =
    226                         followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );
    227                 delete tableInst;
    228                 return typeIdInst;
     195                        fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
     196                        if ( fieldDecl && fieldDecl->name != "virtual_table" ) {
     197                                fieldDecl = nullptr;
     198                        }
     199                }
     200                if ( nullptr == fieldDecl ) {
     201                        castError( castExpr, "Virtual cast type must have a leading virtual_table field." );
     202                }
     203                const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type );
     204                if ( nullptr == fieldType ) {
     205                        castError( castExpr, "Virtual cast type virtual_table field is not a pointer." );
     206                }
     207                assert( fieldType->base );
     208                auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base );
     209                assert( virtualStructType );
     210
     211                // Here is the type, but if it is polymorphic it will have lost information.
     212                // (Always a clone so that it may always be deleted.)
     213                StructInstType * virtualType = virtualStructType->clone();
     214                if ( ! structType->parameters.empty() ) {
     215                        deleteAll( virtualType->parameters );
     216                        virtualType->parameters.clear();
     217                        cloneAll( structType->parameters, virtualType->parameters );
     218                }
     219                return virtualType;
    229220        }
    230221
     
    237228                assert( pvt_decl );
    238229
    239                 const Type * base_type = getBaseType( castExpr->result );
    240                 if ( nullptr == base_type ) {
    241                         castError( castExpr, "Virtual cast target must be a pointer or reference type." );
    242                 }
    243                 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );
    244                 if ( nullptr == type_id_type ) {
    245                         castError( castExpr, "Ill formed virtual cast target type." );
    246                 }
    247                 ObjectDecl * type_id = indexer.lookup( type_id_type );
    248                 delete type_id_type;
    249                 if ( nullptr == type_id ) {
    250                         castError( castExpr, "Virtual cast does not target a virtual type." );
     230                const Type * vtable_type = getVirtualTableType( castExpr );
     231                ObjectDecl * table = indexer.lookup( vtable_type );
     232                if ( nullptr == table ) {
     233                        SemanticError( castLocation( castExpr ),
     234                                "Could not find virtual table instance." );
    251235                }
    252236
    253237                Expression * result = new CastExpr(
    254238                        new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
    255                                 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),
    256                                 cast_to_type_id( castExpr->get_arg(), 2 ),
     239                                        new CastExpr(
     240                                                new AddressExpr( new VariableExpr( table ) ),
     241                                                pointer_to_pvt(1)
     242                                        ),
     243                                        new CastExpr(
     244                                                castExpr->get_arg(),
     245                                                pointer_to_pvt(2)
     246                                        )
    257247                        } ),
    258248                        castExpr->get_result()->clone()
     
    262252                castExpr->set_result( nullptr );
    263253                delete castExpr;
     254                delete vtable_type;
    264255                return result;
    265256        }
  • src/Virtual/Tables.cc

    rc8a0210 r857a1c6  
    1010// Created On       : Mon Aug 31 11:11:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Apr  8 15:51:00 2021
    13 // Update Count     : 1
     12// Last Modified On : Tue Sep  3 14:56:00 2020
     13// Update Count     : 0
    1414//
    1515
     
    2222namespace Virtual {
    2323
    24 std::string typeIdType( std::string const & type_name ) {
    25         return "__cfatid_struct_" + type_name;
    26 }
    27 
    28 std::string typeIdName( std::string const & type_name ) {
    29         return "__cfatid_" + type_name;
    30 }
    31 
    32 static std::string typeIdTypeToInstance( std::string const & type_name ) {
    33         return typeIdName(type_name.substr(16));
    34 }
    35 
    3624std::string vtableTypeName( std::string const & name ) {
    3725        return name + "_vtable";
    38 }
    39 
    40 std::string baseTypeName( std::string const & vtable_type_name ) {
    41         return vtable_type_name.substr(0, vtable_type_name.size() - 7);
    4226}
    4327
     
    9781                                inits.push_back(
    9882                                                new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );
    99                         } else if ( std::string( "__cfavir_typeid" ) == field->name ) {
    100                                 std::string const & baseType = baseTypeName( vtableType->name );
    101                                 std::string const & typeId = typeIdName( baseType );
    102                                 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );
    10383                        } else if ( std::string( "size" ) == field->name ) {
    10484                                inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );
     
    167147}
    168148
    169 ObjectDecl * makeTypeIdForward() {
    170         return nullptr;
    171149}
    172 
    173 Attribute * linkonce( const std::string & subsection ) {
    174         const std::string section = ".gnu.linkonce." + subsection;
    175         return new Attribute( "section", {
    176                 new ConstantExpr( Constant::from_string( section ) ),
    177         } );
    178 }
    179 
    180 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
    181         assert( typeIdType );
    182         StructInstType * type = typeIdType->clone();
    183         type->tq.is_const = true;
    184         std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );
    185         return new ObjectDecl(
    186                 typeid_name,
    187                 noStorageClasses,
    188                 LinkageSpec::Cforall,
    189                 /* bitfieldWidth */ nullptr,
    190                 type,
    191                 new ListInit( { new SingleInit(
    192                         new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )
    193                         ) } ),
    194                 { linkonce( typeid_name ) },
    195                 noFuncSpecifiers
    196         );
    197 }
    198 
    199 }
  • src/Virtual/Tables.h

    rc8a0210 r857a1c6  
    1010// Created On       : Mon Aug 31 11:07:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Apr  8 15:55:00 2021
    13 // Update Count     : 1
     12// Last Modified On : Tue Sep  1 14:29:00 2020
     13// Update Count     : 0
    1414//
    1515
     
    2222namespace Virtual {
    2323
    24 std::string typeIdType( std::string const & type_name );
    25 std::string typeIdName( std::string const & type_name );
    2624std::string vtableTypeName( std::string const & type_name );
    2725std::string instanceName( std::string const & vtable_name );
     
    5250 */
    5351
    54 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
    55 /* Build an instance of the type-id from the type of the type-id.
    56  * TODO: Should take the parent type. Currently locked to the exception_t.
    57  */
    58 
    5952}
  • tests/.expect/KRfunctions.nast.arm64.txt

    rc8a0210 r857a1c6  
    104104    signed int _X1bi_2;
    105105    {
    106         signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1);
    107         ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     106        signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1);
     107        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
    108108    }
    109109
  • tests/.expect/KRfunctions.nast.x64.txt

    rc8a0210 r857a1c6  
    104104    signed int _X1bi_2;
    105105    {
    106         signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1);
    107         ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     106        signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1);
     107        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
    108108    }
    109109
  • tests/.expect/KRfunctions.nast.x86.txt

    rc8a0210 r857a1c6  
    104104    signed int _X1bi_2;
    105105    {
    106         signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1);
    107         ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     106        signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1);
     107        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
    108108    }
    109109
  • tests/.expect/KRfunctions.oast.x64.txt

    rc8a0210 r857a1c6  
    104104    signed int _X1bi_2;
    105105    {
    106         signed int *(*_tmp_cp_ret6)(signed int _X1xi_1, signed int _X1yi_1);
    107         ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     106        signed int *(*_tmp_cp_ret4)(signed int _X1xi_1, signed int _X1yi_1);
     107        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
    108108    }
    109109
  • tests/.expect/declarationSpecifier.arm64.txt

    rc8a0210 r857a1c6  
    11471147
    11481148    {
    1149         signed int _tmp_cp_ret6;
    1150         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     1149        signed int _tmp_cp_ret4;
     1150        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    11511151    }
    11521152
  • tests/.expect/declarationSpecifier.x64.txt

    rc8a0210 r857a1c6  
    11471147
    11481148    {
    1149         signed int _tmp_cp_ret6;
    1150         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     1149        signed int _tmp_cp_ret4;
     1150        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    11511151    }
    11521152
  • tests/.expect/declarationSpecifier.x86.txt

    rc8a0210 r857a1c6  
    11471147
    11481148    {
    1149         signed int _tmp_cp_ret6;
    1150         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     1149        signed int _tmp_cp_ret4;
     1150        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    11511151    }
    11521152
  • tests/.expect/extension.arm64.txt

    rc8a0210 r857a1c6  
    457457
    458458    {
    459         signed int _tmp_cp_ret6;
    460         ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));
     459        signed int _tmp_cp_ret4;
     460        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
    461461    }
    462462
  • tests/.expect/extension.x64.txt

    rc8a0210 r857a1c6  
    457457
    458458    {
    459         signed int _tmp_cp_ret6;
    460         ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));
     459        signed int _tmp_cp_ret4;
     460        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
    461461    }
    462462
  • tests/.expect/extension.x86.txt

    rc8a0210 r857a1c6  
    457457
    458458    {
    459         signed int _tmp_cp_ret6;
    460         ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));
     459        signed int _tmp_cp_ret4;
     460        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
    461461    }
    462462
  • tests/.expect/gccExtensions.arm64.txt

    rc8a0210 r857a1c6  
    339339
    340340    {
    341         signed int _tmp_cp_ret6;
    342         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     341        signed int _tmp_cp_ret4;
     342        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    343343    }
    344344
  • tests/.expect/gccExtensions.x64.txt

    rc8a0210 r857a1c6  
    339339
    340340    {
    341         signed int _tmp_cp_ret6;
    342         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     341        signed int _tmp_cp_ret4;
     342        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    343343    }
    344344
  • tests/.expect/gccExtensions.x86.txt

    rc8a0210 r857a1c6  
    317317
    318318    {
    319         signed int _tmp_cp_ret6;
    320         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     319        signed int _tmp_cp_ret4;
     320        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    321321    }
    322322
  • tests/.expect/math.nast.arm64.txt

    rc8a0210 r857a1c6  
    17174 16
    1818log:0. 0. 0. 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972654708616060729088+0.785398163397448309615660845819876i
    19 log2:10 17 23
    20 log2:10 17 23
    21 log2:10 17 23
    22 log2:10. 17. 23.
    2319log2:3. 3. 3.
    2420log10:2. 2. 2.
  • tests/.expect/math.nast.x64.txt

    rc8a0210 r857a1c6  
    17174 16
    1818log:0. 0. 0. 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i
    19 log2:10 17 23
    20 log2:10 17 23
    21 log2:10 17 23
    22 log2:10. 17. 23.
    2319log2:3. 3. 3.
    2420log10:2. 2. 2.
  • tests/.expect/math.nast.x86.txt

    rc8a0210 r857a1c6  
    17174 16
    1818log:0. 0. 0. 0.346574+0.785398i 0.346573590279973+0.785398163397448i 0.346573590279972655+0.78539816339744831i
    19 log2:10 17 23
    20 log2:10 17 23
    21 log2:10 17 23
    2219log2:3. 3. 3.
    2320log10:2. 2. 2.
  • tests/concurrent/futures/multi.cfa

    rc8a0210 r857a1c6  
    55
    66thread Server {
    7         int pending, done, iteration;
     7        int cnt, iteration;
    88        multi_future(int) * request;
    99};
    1010
    1111void ?{}( Server & this ) {
    12         ((thread&)this){"Server Thread"};
    13         this.pending = 0;
    14         this.done = 0;
     12        this.cnt = 0;
    1513        this.iteration = 0;
    1614        this.request = 0p;
     
    1816
    1917void ^?{}( Server & mutex this ) {
    20         assert(this.pending == 0);
    21         this.request = 0p;
     18        assert(this.cnt == 0);
     19    this.request = 0p;
    2220}
    2321
     
    2624}
    2725
    28 void call( Server & mutex this ) {
    29         this.pending++;
     26void process( Server & mutex this ) {
     27        fulfil( *this.request, this.iteration );
     28        this.iteration++;
    3029}
    3130
    32 void finish( Server & mutex this ) {
    33         this.done++;
     31void call( Server & mutex this ) {
     32        this.cnt++;
    3433}
    3534
     35void finish( Server & mutex this ) { }
     36
    3637void main( Server & this ) {
    37         MAIN_LOOP:
    3838        for() {
    3939                waitfor( ^?{} : this ) {
    4040                        break;
    4141                }
    42                 or waitfor( call: this ) {
    43                         if (this.pending != NFUTURES) { continue MAIN_LOOP; }
    44 
    45                         this.pending = 0;
    46                         fulfil( *this.request, this.iteration );
    47                         this.iteration++;
    48 
    49                         for(NFUTURES) {
    50                                 waitfor( finish: this );
     42                or when( this.cnt < NFUTURES ) waitfor( call: this ) {
     43                        if (this.cnt == NFUTURES) {
     44                                process(this);
    5145                        }
    52 
    53                         reset( *this.request );
    54                         this.done = 0;
     46                }
     47                or waitfor( finish: this ) {
     48                        if (this.cnt == NFUTURES) {
     49                                reset( *this.request );
     50                                this.cnt = 0;
     51                        }
    5552                }
    5653        }
     
    6057Server * the_server;
    6158thread Worker {};
    62 void ?{}(Worker & this) {
    63         ((thread&)this){"Worker Thread"};
    64 }
    65 
    6659multi_future(int) * shared_future;
    6760
  • tests/concurrent/spinaphore.cfa

    rc8a0210 r857a1c6  
    4949void main(Unblocker & this) {
    5050        this.sum = 0;
    51         unsigned me = (unsigned)(uintptr_t)&this;
     51        unsigned me = (unsigned)&this;
    5252        for(num_unblocks) {
    5353                $thread * t = V(sem, false);
    5454                Blocker * b = from_thread(t);
    5555                b->sum += me;
    56                 this.sum += (unsigned)(uintptr_t)b;
     56                this.sum += (unsigned)b;
    5757                unpark(t);
    5858                yield(random(10));
     
    7373                for(i;num_blockers) {
    7474                        for(num_blocks)
    75                                 usum += (unsigned)(uintptr_t)&blockers[i];
     75                                usum += (unsigned)&blockers[i];
    7676                }
    7777
    7878                for(i;num_unblockers) {
    7979                        for(num_unblocks)
    80                                 bsum += (unsigned)(uintptr_t)&unblockers[i];
     80                                bsum += (unsigned)&unblockers[i];
    8181                }
    8282
  • tests/errors/.expect/completeType.nast.arm64.txt

    rc8a0210 r857a1c6  
    1212      Application of
    1313        Variable Expression: *?: forall
    14           instance of type DT (not function type)
     14          DT: data type
    1515          function
    1616        ... with parameters
     
    2121        ... with resolved type:
    2222          pointer to forall
    23             instance of type [unbound] (not function type)
     23            [unbound]:data type
     24            function
     25          ... with parameters
     26            pointer to instance of type [unbound] (not function type)
     27          ... returning
     28            reference to instance of type [unbound] (not function type)
     29
     30        ... to arguments
     31        Variable Expression: x: pointer to instance of struct B with body
     32        ... with resolved type:
     33          pointer to instance of struct B with body
     34
     35      ... with resolved type:
     36        reference to instance of struct B with body
     37    ... to: nothing
     38    ... with resolved type:
     39      void
     40  (types:
     41    void
     42  )
     43  Environment:([unbound]) -> instance of struct B with body (no widening)
     44
     45
     46Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
     47      Application of
     48        Variable Expression: *?: forall
     49          DT: data type
     50          function
     51        ... with parameters
     52          pointer to instance of type DT (not function type)
     53        ... returning
     54          reference to instance of type DT (not function type)
     55
     56        ... with resolved type:
     57          pointer to forall
     58            [unbound]:data type
    2459            function
    2560          ... with parameters
     
    4176    void
    4277  )
    43   Environment:([unbound]DT) -> instance of struct A without body (no widening)
    44 
    45 
    46 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
    47       Application of
    48         Variable Expression: *?: forall
    49           instance of type DT (not function type)
    50           function
    51         ... with parameters
    52           pointer to instance of type DT (not function type)
    53         ... returning
    54           reference to instance of type DT (not function type)
    55 
    56         ... with resolved type:
    57           pointer to forall
    58             instance of type [unbound] (not function type)
    59             function
    60           ... with parameters
    61             pointer to instance of type [unbound] (not function type)
    62           ... returning
    63             reference to instance of type [unbound] (not function type)
    64 
    65         ... to arguments
    66         Variable Expression: x: pointer to instance of struct B with body
    67         ... with resolved type:
    68           pointer to instance of struct B with body
    69 
    70       ... with resolved type:
    71         reference to instance of struct B with body
    72     ... to: nothing
    73     ... with resolved type:
    74       void
    75   (types:
    76     void
    77   )
    78   Environment:([unbound]DT) -> instance of struct B with body (no widening)
     78  Environment:([unbound]) -> instance of struct A without body (no widening)
    7979
    8080
     
    113113Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
    114114            Variable Expression: baz: forall
    115               instance of type T (not function type)
    116               with assertions
    117               Variable Expression: ?=?: pointer to function
    118               ... with parameters
    119                 reference to instance of type T (not function type)
    120                 instance of type T (not function type)
    121               ... returning
    122                 instance of type T (not function type)
    123 
    124               ... with resolved type:
    125                 pointer to function
     115              T: sized data type
     116              ... with assertions
     117                ?=?: pointer to function
    126118                ... with parameters
    127119                  reference to instance of type T (not function type)
     
    130122                  instance of type T (not function type)
    131123
    132               Variable Expression: ?{}: pointer to function
    133               ... with parameters
    134                 reference to instance of type T (not function type)
    135               ... returning nothing
    136 
    137               ... with resolved type:
    138                 pointer to function
     124                ?{}: pointer to function
    139125                ... with parameters
    140126                  reference to instance of type T (not function type)
    141127                ... returning nothing
    142128
    143               Variable Expression: ?{}: pointer to function
    144               ... with parameters
    145                 reference to instance of type T (not function type)
    146                 instance of type T (not function type)
    147               ... returning nothing
    148 
    149               ... with resolved type:
    150                 pointer to function
     129                ?{}: pointer to function
    151130                ... with parameters
    152131                  reference to instance of type T (not function type)
     
    154133                ... returning nothing
    155134
    156               Variable Expression: ^?{}: pointer to function
    157               ... with parameters
    158                 reference to instance of type T (not function type)
    159               ... returning nothing
    160 
    161               ... with resolved type:
    162                 pointer to function
     135                ^?{}: pointer to function
    163136                ... with parameters
    164137                  reference to instance of type T (not function type)
    165138                ... returning nothing
     139
    166140
    167141              function
     
    172146            ... with resolved type:
    173147              pointer to forall
    174                 instance of type [unbound] (not function type)
    175                 with assertions
    176                 Variable Expression: ?=?: pointer to function
    177                 ... with parameters
    178                   reference to instance of type T (not function type)
    179                   instance of type T (not function type)
    180                 ... returning
    181                   instance of type T (not function type)
    182 
    183                 ... with resolved type:
    184                   pointer to function
     148                [unbound]:sized data type
     149                ... with assertions
     150                  ?=?: pointer to function
    185151                  ... with parameters
    186152                    reference to instance of type [unbound] (not function type)
     
    189155                    instance of type [unbound] (not function type)
    190156
    191                 Variable Expression: ?{}: pointer to function
    192                 ... with parameters
    193                   reference to instance of type T (not function type)
    194                 ... returning nothing
    195 
    196                 ... with resolved type:
    197                   pointer to function
     157                  ?{}: pointer to function
    198158                  ... with parameters
    199159                    reference to instance of type [unbound] (not function type)
    200160                  ... returning nothing
    201161
    202                 Variable Expression: ?{}: pointer to function
    203                 ... with parameters
    204                   reference to instance of type T (not function type)
    205                   instance of type T (not function type)
    206                 ... returning nothing
    207 
    208                 ... with resolved type:
    209                   pointer to function
     162                  ?{}: pointer to function
    210163                  ... with parameters
    211164                    reference to instance of type [unbound] (not function type)
     
    213166                  ... returning nothing
    214167
    215                 Variable Expression: ^?{}: pointer to function
    216                 ... with parameters
    217                   reference to instance of type T (not function type)
    218                 ... returning nothing
    219 
    220                 ... with resolved type:
    221                   pointer to function
     168                  ^?{}: pointer to function
    222169                  ... with parameters
    223170                    reference to instance of type [unbound] (not function type)
    224171                  ... returning nothing
     172
    225173
    226174                function
     
    240188          void
    241189        )
    242         Environment:([unbound]T) -> instance of type T (not function type) (no widening)
     190        Environment:([unbound]) -> instance of type T (not function type) (no widening)
    243191
    244192      Could not satisfy assertion:
    245 Variable Expression: ?=?: pointer to function
     193?=?: pointer to function
    246194        ... with parameters
    247           reference to instance of type T (not function type)
    248           instance of type T (not function type)
     195          reference to instance of type [unbound] (not function type)
     196          instance of type [unbound] (not function type)
    249197        ... returning
    250           instance of type T (not function type)
     198          instance of type [unbound] (not function type)
    251199
    252         ... with resolved type:
    253           pointer to function
    254           ... with parameters
    255             reference to instance of type [unbound] (not function type)
    256             instance of type [unbound] (not function type)
    257           ... returning
    258             instance of type [unbound] (not function type)
    259 
  • tests/exceptions/.expect/resume-threads.txt

    rc8a0210 r857a1c6  
    66
    77catch-all
     8
     9throwing child exception
     10inner parent match
    811
    912caught yin as yin
  • tests/exceptions/.expect/resume.txt

    rc8a0210 r857a1c6  
    66
    77catch-all
     8
     9throwing child exception
     10inner parent match
    811
    912caught yin as yin
  • tests/exceptions/.expect/terminate-threads.txt

    rc8a0210 r857a1c6  
    55
    66catch-all
     7
     8throwing child exception
     9inner parent match
    710
    811caught yin as yin
  • tests/exceptions/.expect/terminate.txt

    rc8a0210 r857a1c6  
    55
    66catch-all
     7
     8throwing child exception
     9inner parent match
    710
    811caught yin as yin
  • tests/exceptions/cancel/coroutine.cfa

    rc8a0210 r857a1c6  
    44#include <exception.hfa>
    55
    6 EHM_EXCEPTION(internal_error)();
    7 EHM_VIRTUAL_TABLE(internal_error, internal_vt);
     6TRIVIAL_EXCEPTION(internal_error);
    87
    98coroutine WillCancel {};
     
    1514void main(WillCancel & wc) {
    1615        printf("1");
    17         cancel_stack((internal_error){&internal_vt});
     16        cancel_stack((internal_error){});
    1817        printf("!");
    1918}
     
    2524                resume(cancel);
    2625                printf("4");
    27         } catchResume (SomeCoroutineCancelled * error) {
     26        } catchResume (CoroutineCancelled(WillCancel) * error) {
    2827                printf("2");
    2928                if ((virtual internal_error *)error->the_exception) {
  • tests/exceptions/cancel/thread.cfa

    rc8a0210 r857a1c6  
    44#include <exception.hfa>
    55
    6 EHM_EXCEPTION(internal_error)();
    7 EHM_VIRTUAL_TABLE(internal_error, internal_vt);
     6TRIVIAL_EXCEPTION(internal_error);
    87
    98thread WillCancel {};
     
    1514void main(WillCancel &) {
    1615        printf("1");
    17         cancel_stack((internal_error){&internal_vt});
     16        cancel_stack((internal_error){});
    1817        printf("!");
    1918}
     
    2625                join(cancel);
    2726                printf("4");
    28         } catchResume (SomeThreadCancelled * error) {
     27        } catchResume (ThreadCancelled(WillCancel) * error) {
    2928                printf("2");
    3029                if ((virtual internal_error *)error->the_exception) {
     
    4342                }
    4443                printf("4");
    45         } catchResume (SomeThreadCancelled * error) {
     44        } catchResume (ThreadCancelled(WillCancel) * error) {
    4645                printf("2");
    4746                if ((virtual internal_error *)error->the_exception) {
  • tests/exceptions/conditional.cfa

    rc8a0210 r857a1c6  
    66#include <exception.hfa>
    77
    8 EHM_EXCEPTION(num_error)(
    9         int num;
     8VTABLE_DECLARATION(num_error)(
     9        int (*code)(num_error *this);
    1010);
    1111
    12 EHM_VIRTUAL_TABLE(num_error, num_error_vt);
     12struct num_error {
     13        VTABLE_FIELD(num_error);
     14    char * msg;
     15    int num;
     16};
     17
     18const char * num_error_msg(num_error * this) {
     19    if ( ! this->msg ) {
     20        static const char * base = "Num Error with code: X";
     21        this->msg = (char *)malloc(22);
     22        for (int i = 0 ; (this->msg[i] = base[i]) ; ++i);
     23    }
     24    this->msg[21] = '0' + this->num;
     25    return this->msg;
     26}
     27void ?{}(num_error & this, int num) {
     28        VTABLE_INIT(this, num_error);
     29    this.msg = 0;
     30    this.num = num;
     31}
     32void ?{}(num_error & this, num_error & other) {
     33    this.virtual_table = other.virtual_table;
     34    this.msg = 0;
     35    this.num = other.num;
     36}
     37void ^?{}(num_error & this) {
     38    if( this.msg ) free( this.msg );
     39}
     40int num_error_code( num_error * this ) {
     41    return this->num;
     42}
     43
     44VTABLE_INSTANCE(num_error)(
     45        num_error_msg,
     46        num_error_code,
     47);
    1348
    1449void caught_num_error(int expect, num_error * actual) {
     
    1752
    1853int main(int argc, char * argv[]) {
    19         num_error exc = {&num_error_vt, 2};
     54        num_error exc = 2;
    2055
    2156        try {
    2257                throw exc;
    23         } catch (num_error * error ; 3 == error->num ) {
     58        } catch (num_error * error ; 3 == error->virtual_table->code( error )) {
    2459                caught_num_error(3, error);
    25         } catch (num_error * error ; 2 == error->num ) {
     60        } catch (num_error * error ; 2 == error->virtual_table->code( error )) {
    2661                caught_num_error(2, error);
    2762        }
     
    2964        try {
    3065                throwResume exc;
    31         } catchResume (num_error * error ; 3 == error->num ) {
     66        } catchResume (num_error * error ; 3 == error->virtual_table->code( error )) {
    3267                caught_num_error(3, error);
    33         } catchResume (num_error * error ; 2 == error->num ) {
     68        } catchResume (num_error * error ; 2 == error->virtual_table->code( error )) {
    3469                caught_num_error(2, error);
    3570        }
  • tests/exceptions/data-except.cfa

    rc8a0210 r857a1c6  
    33#include <exception.hfa>
    44
    5 EHM_EXCEPTION(paired)(
     5DATA_EXCEPTION(paired)(
    66        int first;
    77        int second;
    88);
    99
    10 EHM_VIRTUAL_TABLE(paired, paired_vt);
     10void ?{}(paired & this, int first, int second) {
     11        VTABLE_INIT(this, paired);
     12        this.first = first;
     13        this.second = second;
     14}
    1115
    12 const char * virtual_msg(paired * this) {
    13         return this->virtual_table->msg(this);
     16const char * paired_msg(paired * this) {
     17        return "paired";
     18}
     19
     20VTABLE_INSTANCE(paired)(paired_msg);
     21
     22void throwPaired(int first, int second) {
     23        paired exc = {first, second};
    1424}
    1525
    1626int main(int argc, char * argv[]) {
    17         paired except = {&paired_vt, 3, 13};
     27        paired except = {3, 13};
    1828
    1929        try {
    2030                throw except;
    2131        } catch (paired * exc) {
    22                 printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second);
     32                printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);
    2333                ++exc->first;
    2434        }
    2535
    26         printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second);
     36        printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);
    2737
    2838        try {
    2939                throwResume except;
    3040        } catchResume (paired * exc) {
    31                 printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second);
     41                printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);
    3242                ++exc->first;
    3343        }
    3444
    35         printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second);
     45        printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);
    3646}
  • tests/exceptions/defaults.cfa

    rc8a0210 r857a1c6  
    44#include <exception.hfa>
    55
    6 EHM_EXCEPTION(log_message)(
     6DATA_EXCEPTION(log_message)(
    77        char * msg;
    88);
    99
    10 _EHM_DEFINE_COPY(log_message, )
    11 const char * msg(log_message * this) {
     10void ?{}(log_message & this, char * msg) {
     11        VTABLE_INIT(this, log_message);
     12        this.msg = msg;
     13}
     14
     15const char * get_log_message(log_message * this) {
    1216        return this->msg;
    1317}
    14 _EHM_VIRTUAL_TABLE(log_message, , log_vt);
     18
     19VTABLE_INSTANCE(log_message)(get_log_message);
    1520
    1621// Logging messages don't have to be handled.
     
    2328        // We can catch log:
    2429        try {
    25                 throwResume (log_message){&log_vt, "Should be printed.\n"};
     30                throwResume (log_message){"Should be printed.\n"};
    2631        } catchResume (log_message * this) {
    2732                printf("%s", this->virtual_table->msg(this));
    2833        }
    2934        // But we don't have to:
    30         throwResume (log_message){&log_vt, "Should not be printed.\n"};
     35        throwResume (log_message){"Should not be printed.\n"};
    3136}
    3237
    3338// I don't have a good use case for doing the same with termination.
    34 EHM_EXCEPTION(jump)();
     39TRIVIAL_EXCEPTION(jump);
    3540void defaultTerminationHandler(jump &) {
    3641        printf("jump default handler.\n");
    3742}
    3843
    39 EHM_VIRTUAL_TABLE(jump, jump_vt);
    40 
    4144void jump_test(void) {
    4245        try {
    43                 throw (jump){&jump_vt};
     46                throw (jump){};
    4447        } catch (jump * this) {
    4548                printf("jump catch handler.\n");
    4649        }
    47         throw (jump){&jump_vt};
     50        throw (jump){};
    4851}
    4952
    50 EHM_EXCEPTION(first)();
    51 EHM_VIRTUAL_TABLE(first, first_vt);
    52 
    53 EHM_EXCEPTION(unhandled_exception)();
    54 EHM_VIRTUAL_TABLE(unhandled_exception, unhandled_vt);
     53TRIVIAL_EXCEPTION(first);
     54TRIVIAL_EXCEPTION(unhandled_exception);
    5555
    5656void unhandled_test(void) {
    5757        forall(T &, V & | is_exception(T, V))
    5858        void defaultTerminationHandler(T &) {
    59                 throw (unhandled_exception){&unhandled_vt};
     59                throw (unhandled_exception){};
    6060        }
    6161        void defaultTerminationHandler(unhandled_exception &) {
     
    6363        }
    6464        try {
    65                 throw (first){&first_vt};
     65                throw (first){};
    6666        } catch (unhandled_exception * t) {
    6767                printf("Catch unhandled_exception.\n");
     
    6969}
    7070
    71 EHM_EXCEPTION(second)();
    72 EHM_VIRTUAL_TABLE(second, second_vt);
     71TRIVIAL_EXCEPTION(second);
    7372
    7473void cross_test(void) {
    7574        void defaultTerminationHandler(first &) {
    7675                printf("cross terminate default\n");
    77                 throw (second){&second_vt};
     76                throw (second){};
    7877        }
    7978        void defaultResumptionHandler(first &) {
    8079                printf("cross resume default\n");
    81                 throwResume (second){&second_vt};
     80                throwResume (second){};
    8281        }
    8382        try {
    8483                printf("cross terminate throw\n");
    85                 throw (first){&first_vt};
     84                throw (first){};
    8685        } catch (second *) {
    8786                printf("cross terminate catch\n");
     
    8988        try {
    9089                printf("cross resume throw\n");
    91                 throwResume (first){&first_vt};
     90                throwResume (first){};
    9291        } catchResume (second *) {
    9392                printf("cross resume catch\n");
  • tests/exceptions/finally.cfa

    rc8a0210 r857a1c6  
    44#include "except-io.hfa"
    55
    6 EHM_EXCEPTION(myth)();
    7 
    8 EHM_VIRTUAL_TABLE(myth, myth_vt);
     6TRIVIAL_EXCEPTION(myth);
    97
    108int main(int argc, char * argv[]) {
    11         myth exc = {&myth_vt};
     9        myth exc;
    1210
    1311        try {
  • tests/exceptions/interact.cfa

    rc8a0210 r857a1c6  
    44#include "except-io.hfa"
    55
    6 EHM_EXCEPTION(star)();
    7 EHM_EXCEPTION(moon)();
    8 
    9 EHM_VIRTUAL_TABLE(star, star_vt);
    10 EHM_VIRTUAL_TABLE(moon, moon_vt);
     6TRIVIAL_EXCEPTION(star);
     7TRIVIAL_EXCEPTION(moon);
    118
    129int main(int argc, char * argv[]) {
    1310        // Resume falls back to terminate.
    1411        try {
    15                 throwResume (star){&star_vt};
     12                throwResume (star){};
    1613        } catch (star *) {
    1714                printf("caught as termination\n");
     
    2017        try {
    2118                loud_region a = "try block with resume throw";
    22                 throwResume (star){&star_vt};
     19                throwResume (star){};
    2320        } catch (star *) {
    2421                printf("caught as termination\n");
     
    3229        try {
    3330                try {
    34                         throw (star){&star_vt};
     31                        throw (star){};
    3532                } catchResume (star *) {
    3633                        printf("resume catch on terminate\n");
     
    4643        try {
    4744                try {
    48                         throwResume (star){&star_vt};
     45                        throwResume (star){};
    4946                } catch (star *) {
    5047                        printf("terminate catch on resume\n");
     
    6158                try {
    6259                        try {
    63                                 throw (star){&star_vt};
     60                                throw (star){};
    6461                        } catchResume (star *) {
    6562                                printf("inner resume catch (error)\n");
     
    7875                try {
    7976                        try {
    80                                 throwResume (star){&star_vt};
     77                                throwResume (star){};
    8178                        } catch (star *) {
    8279                                printf("inner termination catch\n");
     
    9794                                try {
    9895                                        printf("throwing resume moon\n");
    99                                         throwResume (moon){&moon_vt};
     96                                        throwResume (moon){};
    10097                                } catch (star *) {
    10198                                        printf("termination catch\n");
    10299                                }
    103100                                printf("throwing resume star\n");
    104                                 throwResume (star){&star_vt};
     101                                throwResume (star){};
    105102                        } catchResume (star *) {
    106103                                printf("resumption star catch\n");
     
    108105                } catchResume (moon *) {
    109106                        printf("resumption moon catch, will terminate\n");
    110                         throw (star){&star_vt};
     107                        throw (star){};
    111108                }
    112109        } catchResume (star *) {
  • tests/exceptions/polymorphic.cfa

    rc8a0210 r857a1c6  
    33#include <exception.hfa>
    44
    5 EHM_FORALL_EXCEPTION(proxy, (T&), (T))();
     5FORALL_TRIVIAL_EXCEPTION(proxy, (T), (T));
     6FORALL_TRIVIAL_INSTANCE(proxy, (U), (U))
    67
    7 EHM_FORALL_VIRTUAL_TABLE(proxy, (int), proxy_int);
    8 EHM_FORALL_VIRTUAL_TABLE(proxy, (char), proxy_char);
     8const char * msg(proxy(int) * this) { return "proxy(int)"; }
     9const char * msg(proxy(char) * this) { return "proxy(char)"; }
     10POLY_VTABLE_INSTANCE(proxy, int)(msg);
     11POLY_VTABLE_INSTANCE(proxy, char)(msg);
    912
    1013void proxy_test(void) {
    11         proxy(int) an_int = {&proxy_int};
    12         proxy(char) a_char = {&proxy_char};
    13 
    1414    try {
    15                 throw an_int;
     15                throw (proxy(int)){};
    1616        } catch (proxy(int) *) {
    1717                printf("terminate catch\n");
     
    1919
    2020        try {
    21                 throwResume a_char;
     21                throwResume (proxy(char)){};
    2222        } catchResume (proxy(char) *) {
    2323                printf("resume catch\n");
     
    2525
    2626        try {
    27                 throw a_char;
     27                throw (proxy(char)){};
    2828        } catch (proxy(int) *) {
    2929                printf("caught proxy(int)\n");
     
    3333}
    3434
    35 EHM_FORALL_EXCEPTION(cell, (T), (T))(
     35FORALL_DATA_EXCEPTION(cell, (T), (T))(
    3636        T data;
    3737);
    3838
    39 EHM_FORALL_VIRTUAL_TABLE(cell, (int), int_cell);
    40 EHM_FORALL_VIRTUAL_TABLE(cell, (char), char_cell);
    41 EHM_FORALL_VIRTUAL_TABLE(cell, (bool), bool_cell);
     39FORALL_DATA_INSTANCE(cell, (T), (T))
     40
     41const char * msg(cell(int) * this) { return "cell(int)"; }
     42const char * msg(cell(char) * this) { return "cell(char)"; }
     43const char * msg(cell(bool) * this) { return "cell(bool)"; }
     44POLY_VTABLE_INSTANCE(cell, int)(msg);
     45POLY_VTABLE_INSTANCE(cell, char)(msg);
     46POLY_VTABLE_INSTANCE(cell, bool)(msg);
    4247
    4348void cell_test(void) {
    4449        try {
    45                 cell(int) except = {&int_cell, -7};
     50                cell(int) except;
     51                except.data = -7;
    4652                throw except;
    4753        } catch (cell(int) * error) {
     
    5056
    5157        try {
    52                 cell(bool) ball = {&bool_cell, false};
     58                cell(bool) ball;
     59                ball.data = false;
    5360                throwResume ball;
    5461                printf("%i\n", ball.data);
  • tests/exceptions/resume.cfa

    rc8a0210 r857a1c6  
    44#include "except-io.hfa"
    55
    6 EHM_EXCEPTION(yin)();
    7 EHM_EXCEPTION(yang)();
    8 EHM_EXCEPTION(zen)();
    9 
    10 EHM_VIRTUAL_TABLE(yin, yin_vt);
    11 EHM_VIRTUAL_TABLE(yang, yang_vt);
    12 EHM_VIRTUAL_TABLE(zen, zen_vt);
     6TRIVIAL_EXCEPTION(yin);
     7TRIVIAL_EXCEPTION(yang);
     8TRIVIAL_EXCEPTION(zen);
     9TRIVIAL_EXCEPTION(moment_of, zen);
    1310
    1411void in_void(void);
    1512
    1613int main(int argc, char * argv[]) {
    17         yin a_yin = {&yin_vt};
    18         yang a_yang = {&yang_vt};
    19         zen a_zen = {&zen_vt};
    20 
    2114        // The simple throw catchResume test.
    2215        try {
    2316                loud_exit a = "simple try clause";
    2417                printf("simple throw\n");
    25                 throwResume a_zen;
     18                throwResume (zen){};
    2619                printf("end of try clause\n");
    2720        } catchResume (zen * error) {
     
    3326        // Throw catch-all test.
    3427        try {
    35                 throwResume a_zen;
     28                throwResume (zen){};
    3629        } catchResume (exception_t * error) {
    3730                printf("catch-all\n");
     31        }
     32        printf("\n");
     33
     34        // Catch a parent of the given exception.
     35        try {
     36                printf("throwing child exception\n");
     37                throwResume (moment_of){};
     38        } catchResume (zen *) {
     39                printf("inner parent match\n");
     40        } catchResume (moment_of *) {
     41                printf("outer exact match\n");
    3842        }
    3943        printf("\n");
     
    4246        try {
    4347                try {
    44                         throwResume a_yin;
     48                        throwResume (yin){};
    4549                } catchResume (zen *) {
    4650                        printf("caught yin as zen\n");
     
    5862                        loud_exit a = "rethrow inner try";
    5963                        printf("rethrow inner try\n");
    60                         throwResume a_zen;
     64                        throwResume (zen){};
    6165                } catchResume (zen *) {
    6266                        loud_exit a = "rethrowing catch clause";
     
    7377        try {
    7478                try {
    75                         throwResume a_yin;
     79                        throwResume (yin){};
    7680                } catchResume (yin *) {
    7781                        printf("caught yin, will throw yang\n");
    78                         throwResume a_yang;
     82                        throwResume (yang){};
    7983                } catchResume (yang *) {
    8084                        printf("caught exception from same try\n");
     
    8993                try {
    9094                        printf("throwing first exception\n");
    91                         throwResume a_yin;
     95                        throwResume (yin){};
    9296                } catchResume (yin *) {
    9397                        printf("caught first exception\n");
    9498                        try {
    9599                                printf("throwing second exception\n");
    96                                 throwResume a_yang;
     100                                throwResume (yang){};
    97101                        } catchResume (yang *) {
    98102                                printf("caught second exception\n");
     
    110114        try {
    111115                try {
    112                         throwResume a_zen;
    113                         throwResume a_zen;
     116                        throwResume (zen){};
     117                        throwResume (zen){};
    114118                } catchResume (zen *) {
    115119                        printf("inner catch\n");
    116120                }
    117                 throwResume a_zen;
     121                throwResume (zen){};
    118122        } catchResume (zen *) {
    119123                printf("outer catch\n");
     
    126130// Do a throw and rethrow in a void function.
    127131void in_void(void) {
    128     zen a_zen = {&zen_vt};
    129132        try {
    130133                try {
    131134                        printf("throw\n");
    132                         throwResume a_zen;
     135                        throwResume (zen){};
    133136                } catchResume (zen *) {
    134137                        printf("rethrow\n");
  • tests/exceptions/terminate.cfa

    rc8a0210 r857a1c6  
    44#include "except-io.hfa"
    55
    6 EHM_EXCEPTION(yin)();
    7 EHM_EXCEPTION(yang)();
    8 EHM_EXCEPTION(zen)();
    9 
    10 EHM_VIRTUAL_TABLE(yin, yin_vt);
    11 EHM_VIRTUAL_TABLE(yang, yang_vt);
    12 EHM_VIRTUAL_TABLE(zen, zen_vt);
     6TRIVIAL_EXCEPTION(yin);
     7TRIVIAL_EXCEPTION(yang);
     8TRIVIAL_EXCEPTION(zen);
     9TRIVIAL_EXCEPTION(moment_of, zen);
    1310
    1411void in_void(void);
    1512
    1613int main(int argc, char * argv[]) {
    17         yin a_yin = {&yin_vt};
    18         yang a_yang = {&yang_vt};
    19         zen a_zen = {&zen_vt};
    20 
    2114        // The simple throw catch test.
    2215        try {
    2316                loud_exit a = "simple try clause";
    2417                printf("simple throw\n");
    25                 throw a_zen;
     18                throw (zen){};
    2619                printf("end of try clause\n");
    2720        } catch (zen * error) {
     
    3326        // Throw catch-all test.
    3427        try {
    35                 throw a_zen;
     28                throw (zen){};
    3629        } catch (exception_t * error) {
    3730                printf("catch-all\n");
     31        }
     32        printf("\n");
     33
     34        // Catch a parent of the given exception.
     35        try {
     36                printf("throwing child exception\n");
     37                throw (moment_of){};
     38        } catch (zen *) {
     39                printf("inner parent match\n");
     40        } catch (moment_of *) {
     41                printf("outer exact match\n");
    3842        }
    3943        printf("\n");
     
    4246        try {
    4347                try {
    44                         throw a_yin;
     48                        throw (yin){};
    4549                } catch (zen *) {
    4650                        printf("caught yin as zen\n");
     
    5862                        loud_exit a = "rethrow inner try";
    5963                        printf("rethrow inner try\n");
    60                         throw a_zen;
     64                        throw (zen){};
    6165                } catch (zen *) {
    6266                        loud_exit a = "rethrowing catch clause";
     
    7377        try {
    7478                try {
    75                         throw a_yin;
     79                        throw (yin){};
    7680                } catch (yin *) {
    7781                        printf("caught yin, will throw yang\n");
    78                         throw a_yang;
     82                        throw (yang){};
    7983                } catch (yang *) {
    8084                        printf("caught exception from same try\n");
     
    8993                try {
    9094                        printf("throwing first exception\n");
    91                         throw a_yin;
     95                        throw (yin){};
    9296                } catch (yin *) {
    9397                        printf("caught first exception\n");
    9498                        try {
    9599                                printf("throwing second exception\n");
    96                                 throw a_yang;
     100                                throw (yang){};
    97101                        } catch (yang *) {
    98102                                printf("caught second exception\n");
     
    110114        try {
    111115                try {
    112                         throw a_zen;
    113                         throw a_zen;
     116                        throw (zen){};
     117                        throw (zen){};
    114118                } catch (zen *) {
    115119                        printf("inner catch\n");
    116120                }
    117                 throw a_zen;
     121                throw (zen){};
    118122        } catch (zen *) {
    119123                printf("outer catch\n");
     
    126130// Do a throw and rethrow in a void function.
    127131void in_void(void) {
    128         zen a_zen = {&zen_vt};
    129132        try {
    130133                try {
    131134                        printf("throw\n");
    132                         throw a_zen;
     135                        throw (zen){};
    133136                } catch (zen *) {
    134137                        printf("rethrow\n");
  • tests/exceptions/trash.cfa

    rc8a0210 r857a1c6  
    33#include <exception.hfa>
    44
    5 EHM_EXCEPTION(yin)();
    6 EHM_EXCEPTION(yang)();
    7 
    8 EHM_VIRTUAL_TABLE(yin, yin_vt);
    9 EHM_VIRTUAL_TABLE(yang, yang_vt);
     5TRIVIAL_EXCEPTION(yin);
     6TRIVIAL_EXCEPTION(yang);
    107
    118int main(int argc, char * argv[]) {
    129        try {
    1310                try {
    14                         throw (yin){&yin_vt};
     11                        throw (yin){};
    1512                } finally {
    1613                        try {
    17                                 throw (yang){&yang_vt};
     14                                throw (yang){};
    1815                        } catch (yin *) {
    1916                                printf("inner yin\n");
  • tests/exceptions/type-check.cfa

    rc8a0210 r857a1c6  
    33#include <exception.hfa>
    44
    5 EHM_EXCEPTION(truth)();
     5TRIVIAL_EXCEPTION(truth);
    66
    77int main(int argc, char * argv[]) {
  • tests/exceptions/virtual-cast.cfa

    rc8a0210 r857a1c6  
    1212#include <assert.h>
    1313
    14 
    15 
    16 // Hand defined alpha virtual type:
    17 struct __cfatid_struct_alpha {
    18         __cfa__parent_vtable const * parent;
    19 };
    20 
    21 __attribute__(( section(".gnu.linkonce.__cfatid_alpha") ))
    22 struct __cfatid_struct_alpha __cfatid_alpha = {
    23         (__cfa__parent_vtable *)0,
    24 };
    25 
    2614struct alpha_vtable {
    27         struct __cfatid_struct_alpha const * const __cfavir_typeid;
     15        alpha_vtable const * const parent;
    2816        char (*code)(void);
    2917};
     
    3927
    4028
    41 // Hand defined beta virtual type:
    42 struct __cfatid_struct_beta {
    43         __cfatid_struct_alpha const * parent;
    44 };
    45 
    46 __attribute__(( section(".gnu.linkonce.__cfatid_beta") ))
    47 struct __cfatid_struct_beta __cfatid_beta = {
    48         &__cfatid_alpha,
    49 };
    50 
    5129struct beta_vtable {
    52         struct __cfatid_struct_beta const * const __cfavir_typeid;
     30        alpha_vtable const * const parent;
    5331        char (*code)(void);
    5432};
     
    6442
    6543
    66 // Hand defined gamma virtual type:
    67 struct __cfatid_struct_gamma {
    68         __cfatid_struct_beta const * parent;
    69 };
    70 
    71 __attribute__(( section(".gnu.linkonce.__cfatid_gamma") ))
    72 struct __cfatid_struct_gamma __cfatid_gamma = {
    73         &__cfatid_beta,
    74 };
    75 
    7644struct gamma_vtable {
    77         struct __cfatid_struct_gamma const * const __cfavir_typeid;
     45        beta_vtable const * const parent;
    7846        char (*code)(void);
    7947};
     
    8957
    9058extern "C" {
    91         alpha_vtable _alpha_vtable_instance = { &__cfatid_alpha, ret_a };
    92         beta_vtable _beta_vtable_instance = { &__cfatid_beta, ret_b };
    93         gamma_vtable _gamma_vtable_instance = { &__cfatid_gamma, ret_g };
     59        alpha_vtable _alpha_vtable_instance = { 0, ret_a };
     60        beta_vtable _beta_vtable_instance = { &_alpha_vtable_instance, ret_b };
     61        gamma_vtable _gamma_vtable_instance = { &_beta_vtable_instance, ret_g };
    9462}
    9563
  • tests/exceptions/virtual-poly.cfa

    rc8a0210 r857a1c6  
    88#include <assert.h>
    99
    10 
    11 struct __cfatid_struct_mono_base {
    12     __cfa__parent_vtable const * parent;
    13 };
    14 
    15 __attribute__(( section(".gnu.linkonce.__cfatid_mono_base") ))
    16 struct __cfatid_struct_mono_base __cfatid_mono_base = {
    17     (__cfa__parent_vtable *)0,
    18 };
    19 
    2010struct mono_base_vtable {
    21         __cfatid_struct_mono_base const * const __cfavir_typeid;
     11        mono_base_vtable const * const parent;
    2212};
    2313
     
    2717
    2818forall(T)
    29 struct __cfatid_struct_mono_child {
    30     __cfatid_struct_mono_base const * parent;
    31 };
    32 
    33 forall(T)
    3419struct mono_child_vtable {
    35         __cfatid_struct_mono_child(T) const * const __cfavir_typeid;
     20        mono_base_vtable const * const parent;
    3621};
    3722
     
    4126};
    4227
    43 __cfatid_struct_mono_child(int) __cfatid_mono_child @= {
    44         &__cfatid_mono_base,
    45 };
    46 
     28mono_base_vtable _mono_base_vtable_instance @= { 0 };
    4729mono_child_vtable(int) _mono_child_vtable_instance @= {
    48         &__cfatid_mono_child,
     30        &_mono_base_vtable_instance
    4931};
    5032
     
    5537}
    5638
    57 
    58 forall(U)
    59 struct __cfatid_struct_poly_base {
    60     __cfa__parent_vtable const * parent;
    61 };
    62 
    6339forall(U)
    6440struct poly_base_vtable {
    65         __cfatid_struct_poly_base(U) const * const __cfavir_typeid;
     41        poly_base_vtable(U) const * const parent;
    6642};
    6743
     
    7248
    7349forall(V)
    74 struct __cfatid_struct_poly_child {
    75     __cfatid_struct_poly_base(V) const * parent;
    76 };
    77 
    78 forall(V)
    7950struct poly_child_vtable {
    80         __cfatid_struct_poly_child(V) const * const __cfavir_typeid;
     51        poly_base_vtable(V) const * const parent;
    8152};
    8253
     
    8657};
    8758
    88 __cfatid_struct_poly_base(int) __cfatid_poly_base @= {
    89         (__cfa__parent_vtable *)0,
     59poly_base_vtable(int) _poly_base_vtable_instance @= { 0 };
     60poly_child_vtable(int) _poly_child_vtable_instance @= {
     61        &_poly_base_vtable_instance
    9062};
    91 __cfatid_struct_poly_child(int) __cfatid_poly_child = {
    92     &__cfatid_poly_base,
     63/* Resolver bug keeps me from adding these.
     64poly_base_vtable(char) _poly_base_vtable_instance @= { 0 };
     65poly_child_vtable(char) _poly_child_vtable_instance @= {
     66        &_poly_base_vtable_instance
    9367};
    94 poly_child_vtable(int) _poly_child_vtable_instance @= {
    95         &__cfatid_poly_child,
    96 };
     68*/
    9769
    9870void poly_poly_test() {
     
    10577        mono_poly_test();
    10678        poly_poly_test();
    107         printf( "done\n" );
     79        printf( "done\n" );                             // non-empty .expect file
    10880}
  • tests/io/.expect/manipulatorsOutput1.arm64.txt

    rc8a0210 r857a1c6  
    2929float
    30300         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    31 0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     310. 3.000000 3.000000 3.537 3.537000        4        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    3232double
    33        3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    34 0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     333.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     340. 3.000000 3.537 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    3535long double
    36        3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    37 0.       3.        3 3.53699999999999992184029906638898    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     363.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     370. 3.000000 3.53699999999999992184029906638898 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    3838
    3939char
  • tests/io/.expect/manipulatorsOutput1.x64.txt

    rc8a0210 r857a1c6  
    2929float
    30300         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    31 0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     310. 3.000000 3.000000 3.537 3.537000        4        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    3232double
    33        3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    34 0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     333.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     340. 3.000000 3.537 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    3535long double
    36        3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
    37 0.       3.        3 3.53699999999999992    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
     363.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
     370. 3.000000 3.53699999999999992 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
    3838
    3939char
  • tests/io/.expect/manipulatorsOutput1.x86.txt

    rc8a0210 r857a1c6  
    2929float
    30300         3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    31 0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     310. 3.000000 3.000000 3.537 3.537000        4        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    3232double
    33        3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    34 0.       3.        3 3.537    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     333.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
     340. 3.000000 3.537 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0x1.c5p+1 0X1.C5P+1 3.54e+00
    3535long double
    36        3  3.00000 3.537    3.537        4       4.      3.5      3.5 3        3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
    37 0.       3.        3 3.53699999999999992    3.537       4.        4      3.5      3.5 3.       3.5      3.5      +3.5     +3.5     000003.5 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
     363.000000 3.537 3.537000       4.        4     3.54 3.54     +3.54    00003.54 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
     370. 3.000000 3.53699999999999992 3.537000        4       4.     3.54 3.54     +3.54    00003.54 3.54E+00 0xe.26p-2 0XE.26P-2 3.54e+00
    3838
    3939char
  • tests/io/.expect/manipulatorsOutput2.arm64.txt

    rc8a0210 r857a1c6  
    99-0x1.b8p+4 -0x1.b8p+4 -0x1.b8p+4
    10100.000000e+00 2.750000e+01 -2.750000e+01
    11 0e0 27.5e0 -27.5e0
    12110B11011 0X1B 2.75E-09 0X1.B8P+4
    131211011 33 1b
    14130. 0 27. 27 27.5
    15 +27 -27 +27. -27. +27.5 -27.5
     14+27 -27 +27 -27 +27.5 -27.5
    1615  34  34 34
    17         4.        4.       4.
     16  4.000000  4.000000 4.000000
    1817  ab  ab ab
    191834567 34567 34567
    20 3456. 3456. 3456.
     193456.000000 3456.000000 3456.000000
    2120abcde abcde abcde
    2221 034     0034 0000000034
     
    252427.500     27.5      28. 27.50000000
    262527.000 27.500     27.5      28. 27.50000000
    27 27   27.        27.5       027  27.500   
     2627   27.000000  27.500000  027  27.500   
    2827234.567 234.57  234.6   235.
    2928234567. 2.3457e+05 2.346e+05 2.35e+05
  • tests/io/.expect/manipulatorsOutput2.x64.txt

    rc8a0210 r857a1c6  
    99-0x1.b8p+4 -0x1.b8p+4 -0xd.cp+1
    10100.000000e+00 2.750000e+01 -2.750000e+01
    11 0e0 27.5e0 -27.5e0
    12110B11011 0X1B 2.75E-09 0X1.B8P+4
    131211011 33 1b
    14130. 0 27. 27 27.5
    15 +27 -27 +27. -27. +27.5 -27.5
     14+27 -27 +27 -27 +27.5 -27.5
    1615  34  34 34
    17         4.        4.       4.
     16  4.000000  4.000000 4.000000
    1817  ab  ab ab
    191834567 34567 34567
    20 3456. 3456. 3456.
     193456.000000 3456.000000 3456.000000
    2120abcde abcde abcde
    2221 034     0034 0000000034
     
    252427.500     27.5      28. 27.50000000
    262527.000 27.500     27.5      28. 27.50000000
    27 27   27.        27.5       027  27.500   
     2627   27.000000  27.500000  027  27.500   
    2827234.567 234.57  234.6   235.
    2928234567. 2.3457e+05 2.346e+05 2.35e+05
  • tests/io/.expect/manipulatorsOutput2.x86.txt

    rc8a0210 r857a1c6  
    99-0x1.b8p+4 -0x1.b8p+4 -0xd.cp+1
    10100.000000e+00 2.750000e+01 -2.750000e+01
    11 0e2147483646 27.5e0 -27.5e0
    12110B11011 0X1B 2.75E-09 0X1.B8P+4
    131211011 33 1b
    14130. 0 27. 27 27.5
    15 +27 -27 +27. -27. +27.5 -27.5
     14+27 -27 +27 -27 +27.5 -27.5
    1615  34  34 34
    17         4.        4.       4.
     16  4.000000  4.000000 4.000000
    1817  ab  ab ab
    191834567 34567 34567
    20 3456. 3456. 3456.
     193456.000000 3456.000000 3456.000000
    2120abcde abcde abcde
    2221 034     0034 0000000034
     
    252427.500     27.5      28. 27.50000000
    262527.000 27.500     27.5      28. 27.50000000
    27 27   27.        27.5       027  27.500   
     2627   27.000000  27.500000  027  27.500   
    2827234.567 234.57  234.6   235.
    2928234567. 2.3457e+05 2.346e+05 2.35e+05
  • tests/io/manipulatorsOutput1.cfa

    rc8a0210 r857a1c6  
    77// Created On       : Sat Jun  8 18:04:11 2019
    88// Last Modified By : Peter A. Buhr
    9 // Last Modified On : Sat Apr 10 08:42:15 2021
    10 // Update Count     : 18
     9// Last Modified On : Fri May  1 11:51:44 2020
     10// Update Count     : 9
    1111//
    1212
     
    8585        sout | "double";
    8686        double d = 3.537;
    87         printf( "%g  %8g %#8g %g %8g %8.0g %#8.0g %8.2g %#8.2g %-8.2g %-8.2g %-#8.2g %-+8.2g %-+#8.2g %08.2g %8.2E %8.2a %#8.2A %#8.2e\n",
    88                     0.0, 3.0, 3.0, d,  d,    d,     d,    d,     d,   3.0,     d,      d,      d,       d,     d,    d,    d,     d,     d );
    89         sout | 0.0 | wd(8, 3.0) | nodp(wd(8, 3.0)) | d | wd(8, d) | ws(8,0, d) | nodp(ws(8,0, d)) | ws(8,2, d) | nodp(ws(8,2, d)) | nonl;
    90         sout | left(ws(8,2, 3.0)) | left(ws(8,2, d)) | left(nodp(ws(8,2, d))) | left(sign(ws(8,2, d))) | left(sign(nodp(ws(8,2, d)))) | nonl;
    91         sout | pad0(ws(8,2, d)) | upcase(wd(8,2, sci(d))) | wd(8,2, hex(d)) | upcase(wd(8,2, hex(d))) | nodp(wd(8,2, sci(d)));
     87        printf( "%g  %#8f %g %8f %#8.0f %8.0f %8.2f %-8.2f %-+#8.2f %08.2F %8.2E %8.2a %8.2A %8.2e\n",
     88                        0.0,  3.0, d,  d,     d,    d,    d,     d,       d,     d,    d,    d,    d,    d );
     89        sout | 0.0 | wd(8, 3.0) | d | wd(8, d) | nodp(wd(8,0, d)) | wd(8,0, d) | wd(8,2, d) | nonl;
     90        sout | left(wd(8,2, d)) | left(sign(wd(8,2, d))) | pad0(upcase(wd(8,2, d))) | upcase(wd(8,2, sci(d))) | wd(8,2, hex(d)) | upcase(wd(8,2, hex(d))) | wd(8,2, sci(d));
    9291
    9392        sout | "long double";
    9493        long double ld = 3.537;
    95         printf( "%Lg  %8Lg %#8Lg %Lg %8Lg %8.0Lg %#8.0Lg %8.2Lg %#8.2Lg %-8.2Lg %-8.2Lg %-#8.2Lg %-+8.2Lg %-+#8.2Lg %08.2Lg %8.2LE %8.2La %#8.2LA %#8.2Le\n",
    96                     0.0L, 3.0L, 3.0L, ld,  ld,    ld,     ld,    ld,     ld,   3.0L,     ld,      ld,      ld,       ld,     ld,    ld,    ld,     ld,     ld );
    97         sout | 0.0L | wd(8, 3.0L) | nodp(wd(8, 3.0L)) | ld | wd(8, ld) | ws(8,0, ld) | nodp(ws(8,0, ld)) | ws(8,2, ld) | nodp(ws(8,2, ld)) | nonl;
    98         sout | left(ws(8,2, 3.0L)) | left(ws(8,2, ld)) | left(nodp(ws(8,2, ld))) | left(sign(ws(8,2, ld))) | left(sign(nodp(ws(8,2, ld)))) | nonl;
    99         sout | pad0(ws(8,2, ld)) | upcase(wd(8,2, sci(ld))) | wd(8,2, hex(ld)) | upcase(wd(8,2, hex(ld))) | nodp(wd(8,2, sci(ld)));
     94        printf( "%Lg  %#8Lf %Lg %8Lf %#8.0Lf %8.0Lf %8.2Lf %-8.2Lf %-+#8.2Lf %08.2LF %8.2LE %8.2La %8.2LA %8.2Le\n",
     95                        0.0L,  3.0L, ld,  ld,     ld,    ld,    ld,     ld,       ld,     ld,    ld,    ld,    ld,    ld );
     96        sout | 0.0L | wd(8, 3.0L) | ld | wd(8, ld) | nodp(wd(8,0, ld)) | wd(8,0, ld) | wd(8,2, ld) | nonl;
     97        sout | left(wd(8,2, ld)) | left(sign(wd(8,2, ld))) | pad0(upcase(wd(8,2, ld))) | upcase(wd(8,2, sci(ld))) | wd(8,2, hex(ld)) | upcase(wd(8,2, hex(ld))) | wd(8,2, sci(ld));
     98
    10099
    101100        sout | nl | "char";
     
    118117// Local Variables: //
    119118// tab-width: 4 //
    120 // compile-command: "cfa -Wall -Wextra manipulatorsOutput1.cfa" //
     119// compile-command: "cfa -Wall -Wextra amanipulatorsOutput1.cfa" //
    121120// End: //
  • tests/io/manipulatorsOutput2.cfa

    rc8a0210 r857a1c6  
    77// Created On       : Sat Jun  8 18:04:11 2019
    88// Last Modified By : Peter A. Buhr
    9 // Last Modified On : Sat Apr 10 09:16:09 2021
    10 // Update Count     : 11
     9// Last Modified On : Sun Nov 15 08:11:53 2020
     10// Update Count     : 9
    1111//
    1212
     
    2424    sout | hex(-27.5F) | hex(-27.5) | hex(-27.5L);
    2525        sout | sci(0.0) | sci(27.5) | sci(-27.5);
    26         sout | eng(0.0) | eng(27.5) | eng(-27.5);
    2726        sout | upcase(bin(27)) | upcase(hex(27)) | upcase(27.5e-10) | upcase(hex(27.5));
    2827        sout | nobase(bin(27)) | nobase(oct(27)) | nobase(hex(27));
  • tests/io/manipulatorsOutput3.cfa

    rc8a0210 r857a1c6  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
    3 //
    4 // manipulatorsOutput3.cfa --
    5 //
    6 // Author           : Peter A. Buhr
    7 // Created On       : Tue Apr 13 17:54:23 2021
    8 // Last Modified By : Peter A. Buhr
    9 // Last Modified On : Tue Apr 13 17:54:48 2021
    10 // Update Count     : 1
    11 //
    12 
    131#include <fstream.hfa>
    142
  • tests/linking/exception-nothreads.cfa

    rc8a0210 r857a1c6  
    1717#include <exception.hfa>
    1818
    19 EHM_EXCEPTION(ping)();
    20 EHM_VIRTUAL_TABLE(ping, ping_vt);
     19TRIVIAL_EXCEPTION(ping);
    2120
    2221int main(void) {
    2322        try {
    24                 throwResume (ping){&ping_vt};
     23                throwResume (ping){};
    2524        } catchResume (ping *) {
    2625                printf("%s threads\n", threading_enabled() ? "with" : "no");
  • tests/linking/exception-withthreads.cfa

    rc8a0210 r857a1c6  
    1818#include "../exceptions/with-threads.hfa"
    1919
    20 EHM_EXCEPTION(ping)();
    21 EHM_VIRTUAL_TABLE(ping, ping_vt);
     20TRIVIAL_EXCEPTION(ping);
    2221
    2322int main(void) {
    2423        try {
    25                 throwResume (ping){&ping_vt};
     24                throwResume (ping){};
    2625        } catchResume (ping *) {
    2726                printf("%s threads\n", threading_enabled() ? "with" : "no");
  • tests/math.cfa

    rc8a0210 r857a1c6  
    1010// Created On       : Fri Apr 22 14:59:21 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 13 21:04:48 2021
    13 // Update Count     : 123
     12// Last Modified On : Sat Feb 20 18:00:48 2021
     13// Update Count     : 115
    1414//
    1515
     
    6969        sout | "log:" | log( 1.0F ) | log( 1.0D ) | log( 1.0L ) | nonl;
    7070        sout | log( 1.0F+1.0FI ) | log( 1.0D+1.0DI ) | log( 1.0DL+1.0LI );
    71         sout | "log2:" | log2( 1024 ) | log2( 2 \ 17u ) | log2( 2 \ 23u );
    72         sout | "log2:" | log2( 1024l ) | log2( 2l \ 17u ) | log2( 2l \ 23u );
    73         sout | "log2:" | log2( 1024ll ) | log2( 2ll \ 17u ) | log2( 2ll \ 23u );
    74 #if defined( __SIZEOF_INT128__ )
    75         sout | "log2:" | log2( 1024l128 ) | log2( 2l128 \ 17u ) | log2( 2l128 \ 23u );
    76 #endif // __SIZEOF_INT128__
    7771        sout | "log2:" | log2( 8.0F ) | log2( 8.0D ) | log2( 8.0L );
    7872        sout | "log10:" | log10( 100.0F ) | log10( 100.0D ) | log10( 100.0L );
  • tests/meta/.expect/archVast.nast.arm64.txt

    rc8a0210 r857a1c6  
    77  char Alternatives are:
    88Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    9       Variable Expression: FA64: double
     9      Variable Expression: FA64: signed int
    1010      ... with resolved type:
    11         double
     11        signed int
    1212    ... to:
    1313      char
     
    3939
    4040Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    41       Variable Expression: FA64: signed int
     41      Variable Expression: FA64: double
    4242      ... with resolved type:
    43         signed int
     43        double
    4444    ... to:
    4545      char
  • tests/quasiKeyword.cfa

    rc8a0210 r857a1c6  
    1414#include <exception.hfa>
    1515
    16 EHM_EXCEPTION( E )();
     16TRIVIAL_EXCEPTION( E );
    1717
    1818void catch( int i ) {}
  • tests/vector_math/.expect/vec4_float.txt

    rc8a0210 r857a1c6  
    66zero-assign:<0.,0.,0.,0.>
    77fill-ctor:<1.23,1.23,1.23,1.23>
    8 ?-?:<0.02,0.43,-0.999998,-1e-06>
    9 ?-=?:<0.02,0.43,-0.999998,-1e-06>
    10 -?:<-0.02,-0.43,0.999998,1e-06>
     8?-?:<0.02,0.43,-0.999998,-1e-06.>
     9?-=?:<0.02,0.43,-0.999998,-1e-06.>
     10-?:<-0.02,-0.43,0.999998,1e-06.>
    1111?+?:<2.3,2.45,-9.2,-12.5>
    1212?+=?:<2.3,2.45,-9.2,-12.5>
  • tools/gdb/utils-gdb.py

    rc8a0210 r857a1c6  
    2323gdb.execute('handle SIGUSR1 nostop noprint pass')
    2424
    25 CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state yield_state')
     25CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state')
    2626
    2727class ThreadInfo:
     
    5252        # GDB types for various structures/types in CFA
    5353        return CfaTypes(cluster_ptr = gdb.lookup_type('struct cluster').pointer(),
    54                 processor_ptr = gdb.lookup_type('struct processor').pointer(),
    55                 thread_ptr = gdb.lookup_type('struct $thread').pointer(),
    56                 int_ptr = gdb.lookup_type('int').pointer(),
    57                 thread_state = gdb.lookup_type('enum __Coroutine_State'),
    58                 yield_state = gdb.lookup_type('enum __Preemption_Reason'))
     54                                  processor_ptr = gdb.lookup_type('struct processor').pointer(),
     55                                         thread_ptr = gdb.lookup_type('struct $thread').pointer(),
     56                                                int_ptr = gdb.lookup_type('int').pointer(),
     57                                   thread_state = gdb.lookup_type('enum __Coroutine_State'))
    5958
    6059def get_addr(addr):
     
    372371        def print_thread(self, thread, tid, marked):
    373372                cfa_t = get_cfa_types()
    374                 ys = str(thread['preempted'].cast(cfa_t.yield_state))
    375                 if ys == '_X15__NO_PREEMPTIONKM19__Preemption_Reason_1':
    376                         state = str(thread['state'].cast(cfa_t.thread_state))
    377                 elif ys == '_X18__ALARM_PREEMPTIONKM19__Preemption_Reason_1':
    378                         state = 'preempted'
    379                 elif ys == '_X19__MANUAL_PREEMPTIONKM19__Preemption_Reason_1':
    380                         state = 'yield'
    381                 elif ys == '_X17__POLL_PREEMPTIONKM19__Preemption_Reason_1':
    382                         state = 'poll'
    383                 else:
    384                         print("error: thread {} in undefined preemption state {}".format(thread, ys))
    385                         state = 'error'
    386                 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), state, str(thread))
     373                self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread))
    387374
    388375        def print_threads_by_cluster(self, cluster, print_system = False):
     
    493480                context = thread['context']
    494481
    495 
     482                # lookup for sp,fp and uSwitch
     483                xsp = context['SP'] + 48
     484                xfp = context['FP']
     485
     486                # convert string so we can strip out the address
     487                try:
     488                        xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address + 28)
     489                except:
     490                        print("here")
     491                        return
    496492
    497493                # must be at frame 0 to set pc register
    498494                gdb.execute('select-frame 0')
    499                 if gdb.selected_frame().architecture().name() != 'i386:x86-64':
    500                         print('gdb debugging only supported for i386:x86-64 for now')
    501                         return
    502 
    503                 # gdb seems to handle things much better if we pretend we just entered the context switch
    504                 # pretend the pc is __cfactx_switch and adjust the sp, base pointer doesn't need to change
    505                 # lookup for sp,fp and uSwitch
    506                 xsp = context['SP'] + 40 # 40 = 5 64bit registers : %r15, %r14, %r13, %r12, %rbx WARNING: x64 specific
    507                 xfp = context['FP']
    508 
    509                 # convert string so we can strip out the address
    510                 try:
    511                         xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address)
    512                 except:
    513                         print("here")
    514                         return
    515495
    516496                # push sp, fp, pc into a global stack
     
    523503
    524504                # update registers for new task
    525                 # print('switching to {} ({}) : [{}, {}, {}]'.format(thread['self_cor']['name'].string(), str(thread), str(xsp), str(xfp), str(xpc)))
    526                 print('switching to thread {} ({})'.format(str(thread), thread['self_cor']['name'].string()))
     505                print('switching to ')
    527506                gdb.execute('set $rsp={}'.format(xsp))
    528507                gdb.execute('set $rbp={}'.format(xfp))
     
    573552
    574553                argv = parse(arg)
     554                print(argv)
    575555                if argv[0].isdigit():
    576556                        cname = " ".join(argv[1:]) if len(argv) > 1 else None
Note: See TracChangeset for help on using the changeset viewer.