Changeset c8a0210


Ignore:
Timestamp:
Apr 16, 2021, 2:28:09 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
665edf40
Parents:
857a1c6 (diff), 5f6a172 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Files:
5 added
114 edited

Legend:

Unmodified
Added
Removed
  • benchmark/basic/ttst_lock.c

    r857a1c6 rc8a0210  
    99#define CALIGN __attribute__(( aligned (CACHE_ALIGN) ))
    1010#define CACHE_ALIGN 128
    11 #define Pause() __asm__ __volatile__ ( "pause" : : : )
     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
    1218
    1319typedef uintptr_t TYPE;                                                                 // addressable word-size
  • benchmark/benchcltr.hfa

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

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

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

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

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

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

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

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

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

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

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

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

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

    r857a1c6 rc8a0210  
    17971797}
    17981798
    1799 @article{Delisle20,
     1799@article{Delisle21,
    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,
    18051804    journal     = spe,
    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        = {},
     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}},
    18091811}
    18101812
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/links.hpp

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

    r857a1c6 rc8a0210  
    3939                while( __builtin_expect(ll.exchange(true),false) ) {
    4040                        while(ll.load(std::memory_order_relaxed))
    41                                 asm volatile("pause");
     41                                Pause();
    4242                }
    4343                /* paranoid */ assert(ll);
     
    9393                         && ready.compare_exchange_weak(copy, n + 1) )
    9494                                break;
    95                         asm volatile("pause");
     95                        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                         asm volatile("pause");
     135                        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                         asm volatile("pause");
     197                        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                                 asm volatile("pause");
     206                                Pause();
    207207                }
    208208
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp

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

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

    r857a1c6 rc8a0210  
    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);
     208                LIST_VARIANT<Node>::stats_print(std::cout, duration);
    209209        #endif
    210210}
     
    368368
    369369                for(Node * & node : nodes) {
    370                         node = list.pop();
    371                         assert(node);
     370                        node = nullptr;
     371                        while(!node) {
     372                                node = list.pop();
     373                        }
    372374                        local.crc_out += node->value;
    373375                        local.out++;
     
    691693
    692694                                for(const auto & n : nodes) {
    693                                         local.valmax = max(local.valmax, size_t(n.value));
    694                                         local.valmin = min(local.valmin, size_t(n.value));
     695                                        local.valmax = std::max(local.valmax, size_t(n.value));
     696                                        local.valmin = std::min(local.valmin, size_t(n.value));
    695697                                }
    696698
     
    773775                                                try {
    774776                                                        arg = optarg = argv[optind];
    775                                                         nnodes = stoul(optarg, &len);
     777                                                        nnodes = std::stoul(optarg, &len);
    776778                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    777779                                                } catch(std::invalid_argument &) {
     
    792794                                                try {
    793795                                                        arg = optarg = argv[optind];
    794                                                         nnodes = stoul(optarg, &len);
     796                                                        nnodes = std::stoul(optarg, &len);
    795797                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    796798                                                } catch(std::invalid_argument &) {
     
    812814                                                try {
    813815                                                        arg = optarg = argv[optind];
    814                                                         nnodes = stoul(optarg, &len);
     816                                                        nnodes = std::stoul(optarg, &len);
    815817                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    816818                                                        nslots = nnodes;
     
    823825                                                try {
    824826                                                        arg = optarg = argv[optind];
    825                                                         nnodes = stoul(optarg, &len);
     827                                                        nnodes = std::stoul(optarg, &len);
    826828                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    827829                                                } catch(std::invalid_argument &) {
     
    831833                                                try {
    832834                                                        arg = optarg = argv[optind + 1];
    833                                                         nslots = stoul(optarg, &len);
     835                                                        nslots = std::stoul(optarg, &len);
    834836                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    835837                                                } catch(std::invalid_argument &) {
     
    884886                        case 'd':
    885887                                try {
    886                                         duration = stod(optarg, &len);
     888                                        duration = std::stod(optarg, &len);
    887889                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    888890                                } catch(std::invalid_argument &) {
     
    893895                        case 't':
    894896                                try {
    895                                         nthreads = stoul(optarg, &len);
     897                                        nthreads = std::stoul(optarg, &len);
    896898                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    897899                                } catch(std::invalid_argument &) {
     
    902904                        case 'q':
    903905                                try {
    904                                         nqueues = stoul(optarg, &len);
     906                                        nqueues = std::stoul(optarg, &len);
    905907                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    906908                                } catch(std::invalid_argument &) {
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp

    r857a1c6 rc8a0210  
    168168        for(int i = 0; i < width; i++) {
    169169                int idx = i % hwdith;
    170                 std::cout << i << " -> " << idx + width << std::endl;
    171170                leafs[i].parent = &nodes[ idx ];
    172171        }
     
    174173        for(int i = 0; i < root; i++) {
    175174                int idx = (i / 2) + hwdith;
    176                 std::cout << i + width << " -> " << idx + width << std::endl;
    177175                nodes[i].parent = &nodes[ idx ];
    178176        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp

    r857a1c6 rc8a0210  
    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;
    162161                nodes[i].parent = &nodes[(i / base) + width];
    163162        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp

    r857a1c6 rc8a0210  
    1111#include <sys/sysinfo.h>
    1212
    13 #include <x86intrin.h>
    14 
    15 // Barrier from
    16 class barrier_t {
    17 public:
    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 
    32 private:
    33         std::atomic<size_t> waiting;
    34         size_t total;
    35 };
     13// #include <x86intrin.h>
    3614
    3715// class Random {
     
    10280};
    10381
    104 static 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 }
     82static 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
    109104
    110105static inline void affinity(int tid) {
     
    195190}
    196191
     192// Barrier from
     193class barrier_t {
     194public:
     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
     209private:
     210        std::atomic<size_t> waiting;
     211        size_t total;
     212};
     213
    197214struct spinlock_t {
    198215        std::atomic_bool ll = { false };
     
    201218                while( __builtin_expect(ll.exchange(true),false) ) {
    202219                        while(ll.load(std::memory_order_relaxed))
    203                                 asm volatile("pause");
     220                                Pause();
    204221                }
    205222        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp

    r857a1c6 rc8a0210  
    66#include <memory>
    77#include <mutex>
     8#include <thread>
    89#include <type_traits>
    910
     
    1112#include "utils.hpp"
    1213#include "links.hpp"
     14#include "links2.hpp"
    1315#include "snzi.hpp"
    1416
     17// #include <x86intrin.h>
     18
    1519using namespace std;
     20
     21static const long long lim = 2000;
     22static const unsigned nqueues = 2;
     23
     24struct __attribute__((aligned(128))) timestamp_t {
     25        volatile unsigned long long val = 0;
     26};
     27
     28template<typename node_t>
     29struct __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};
    1655
    1756template<typename node_t>
     
    2564
    2665        work_stealing(unsigned _numThreads, unsigned)
    27                 : numThreads(_numThreads)
    28                 , lists(new intrusive_queue_t<node_t>[numThreads])
    29                 , snzi( std::log2( numThreads / 2 ), 2 )
     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 )
    3071
    3172        {
     
    4081        __attribute__((noinline, hot)) void push(node_t * node) {
    4182                node->_links.ts = rdtscl();
    42                 if( node->_links.hint > numThreads ) {
    43                         node->_links.hint = tls.rng.next() % numThreads;
    44                         tls.stat.push.nhint++;
     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);
     97                                }
     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();
     107                #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;
    45148                }
    46149
    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);
     150                // try steal
     151                for(int i = 0; i < 25; i++) {
     152                        node_t * n = steal();
     153                        if(n) return n;
    53154                }
    54155
    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                                         }
    77                                 }
    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;
     156                return search();
     157        }
     158
     159private:
     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;
    100180                        }
    101181                }
    102182
    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++;
    111                 #endif
    112 
    113 
    114                 return node;
    115         }
    116 
    117 private:
    118         node_t * try_pop(unsigned i) {
     183                return nullptr;
     184        }
     185
     186private:
     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);
    119197                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; }
    120205
    121206                // If list is empty, unlock and retry
    122207                if( list.ts() == 0 ) {
    123                         list.lock.unlock();
     208                        list.unlock();
     209                        stat.eempty++;
    124210                        return nullptr;
    125211                }
    126212
    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;
     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
    140225        }
    141226
     
    144229
    145230        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
    146240        static __attribute__((aligned(128))) thread_local struct TLS {
    147                 Random     rng = { int(rdtscl()) };
    148                 unsigned   my_queue = ticket++;
     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;
    149247                #if defined(READ)
    150248                        unsigned it = 0;
     
    152250                struct {
    153251                        struct {
    154                                 std::size_t nhint = { 0 };
     252                                std::size_t attempt = { 0 };
     253                                std::size_t success = { 0 };
    155254                        } push;
    156255                        struct {
    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;
     256                                attempt_stat_t help;
     257                                attempt_stat_t local;
     258                                attempt_stat_t steal;
     259                                attempt_stat_t search;
    168260                        } pop;
    169                 } stat;
     261                        std::size_t help = { 0 };
     262                } stats;
    170263        } tls;
    171264
    172265private:
    173266        const unsigned numThreads;
    174         std::unique_ptr<intrusive_queue_t<node_t> []> lists;
    175         __attribute__((aligned(64))) snzi_t snzi;
     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;
    176271
    177272#ifndef NO_STATS
     
    179274        static struct GlobalStats {
    180275                struct {
    181                         std::atomic_size_t nhint = { 0 };
     276                        std::atomic_size_t attempt = { 0 };
     277                        std::atomic_size_t success = { 0 };
    182278                } push;
    183279                struct {
    184280                        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 };
    185285                                std::atomic_size_t success = { 0 };
    186                                 std::atomic_size_t espec = { 0 };
    187                                 std::atomic_size_t elock = { 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 };
    188293                        } local;
    189294                        struct {
    190                                 std::atomic_size_t tried   = { 0 };
    191                                 std::atomic_size_t locked  = { 0 };
    192                                 std::atomic_size_t empty   = { 0 };
     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 };
    193299                                std::atomic_size_t success = { 0 };
    194300                        } 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;
    195308                } pop;
     309                std::atomic_size_t help = { 0 };
    196310        } global_stats;
    197311
    198312public:
    199313        static void stats_tls_tally() {
    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 ) {
     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 ) {
    211340                std::cout << "----- Work Stealing Stats -----" << std::endl;
    212341
    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";
     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";
    219366        }
    220367private:
  • libcfa/prelude/builtins.c

    r857a1c6 rc8a0210  
    99// Author           : Peter A. Buhr
    1010// Created On       : Fri Jul 21 16:21:03 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct 27 14:42:00 2020
    13 // Update Count     : 111
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Tue Apr 13 17:26:32 2021
     13// Update Count     : 117
    1414//
    1515
     
    125125} // distribution
    126126
    127 #define __CFA_BASE_COMP_1__() if ( ep == 1 ) return 1
    128 #define __CFA_BASE_COMP_2__() if ( ep == 2 ) return ep << (y - 1)
     127#define __CFA_BASE_COMP_1__() if ( x == 1 ) return 1
     128#define __CFA_BASE_COMP_2__() if ( x == 2 ) return x << (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(ep) op = 1;                                                                      /* accumulate odd product */ \
     136        typeof(x) op = 1;                                                                       /* accumulate odd product */ \
    137137        for ( ; y > 1; y >>= 1 ) {                                                      /* squaring exponentiation, O(log2 y) */ \
    138                 if ( (y & 1) == 1 ) op = op * ep;                               /* odd ? */ \
    139                 ep = ep * ep; \
     138                if ( (y & 1) == 1 ) op = op * x;                                /* odd ? */ \
     139                x = x * x; \
    140140        } \
    141         return ep * op
     141        return x * op
    142142
    143143static inline {
    144         long int ?\?( int ep, unsigned int y ) { __CFA_EXP__(); }
    145         long int ?\?( long int ep, unsigned long int y ) { __CFA_EXP__(); }
     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__(); }
    146147        // unsigned computation may be faster and larger
    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__(); }
     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__(); }
    149151} // distribution
    150152
     
    157159
    158160static inline forall( OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) {
    159         OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); }
    160         OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); }
     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__(); }
    161164} // distribution
    162165
     
    166169
    167170static inline {
     171        long int ?\=?( int & x, unsigned int y ) { x = x \ y; return x; }
    168172        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; }
    169175        unsigned long int ?\=?( unsigned long int & x, unsigned 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; }
     176        unsigned long long int ?\=?( unsigned long long int & x, unsigned long long int y ) { x = x \ y; return x; }
    172177} // distribution
    173178
  • libcfa/src/bits/weakso_locks.cfa

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

    r857a1c6 rc8a0210  
    1010// Created On       : Thu Apr 12 14:36:06 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan  6 12:49:58 2020
    13 // Update Count     : 9
     12// Last Modified On : Wed Apr 14 17:48:25 2021
     13// Update Count     : 20
    1414//
    1515
     
    3232
    3333static inline {
    34         void resetClock( Clock & clk, Duration adj ) with( clk ) {
     34        void reset( Clock & clk, Duration adj ) with( clk ) {
    3535                offset = adj + __timezone`s;                                    // timezone (global) is (UTC - local time) in seconds
    36         } // resetClock
     36        } // reset
    3737
    38         void ?{}( Clock & clk, Duration adj ) { resetClock( clk, adj ); }
     38        void ?{}( Clock & clk ) { reset( clk, (Duration){ 0 } ); }
     39        void ?{}( Clock & clk, Duration adj ) { reset( clk, adj ); }
    3940
    40         Duration getResNsec() {
     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() {
    4145                struct timespec res;
    4246                clock_getres( CLOCK_REALTIME, &res );
    4347                return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns;
    44         } // getRes
     48        } // resolutionNsec
    4549
    46         Duration getRes() {
     50        Duration resolution() {
    4751                struct timespec res;
    4852                clock_getres( CLOCK_REALTIME_COARSE, &res );
    4953                return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns;
    50         } // getRes
     54        } // resolution
    5155
    52         Time getTimeNsec() {                                                            // with nanoseconds
     56        Time timeNsec() {                                                                       // with nanoseconds
    5357                timespec curr;
    5458                clock_gettime( CLOCK_REALTIME, &curr );
    5559                return (Time){ curr };
    56         } // getTimeNsec
     60        } // timeNsec
    5761
    58         Time getTime() {                                                                        // without nanoseconds
     62        Time time() {                                                                           // without nanoseconds
    5963                timespec curr;
    6064                clock_gettime( CLOCK_REALTIME_COARSE, &curr );
    6165                curr.tv_nsec = 0;
    6266                return (Time){ curr };
    63         } // getTime
     67        } // time
    6468
    65         Time getTime( Clock & clk ) with( clk ) {
    66                 return getTime() + offset;
    67         } // getTime
     69        Time time( Clock & clk ) with( clk ) {
     70                return time() + offset;
     71        } // time
    6872
    6973        Time ?()( Clock & clk ) with( clk ) {                           // alternative syntax
    70                 return getTime() + offset;
    71         } // getTime
     74                return time() + offset;
     75        } // ?()
    7276
    73         timeval getTime( Clock & clk ) {
     77        timeval time( Clock & clk ) {
    7478                return (timeval){ clk() };
    75         } // getTime
     79        } // time
    7680
    77         tm getTime( Clock & clk ) with( clk ) {
     81        tm time( Clock & clk ) with( clk ) {
    7882                tm ret;
    79                 localtime_r( getTime( clk ).tv_sec, &ret );
     83                localtime_r( time( clk ).tv_sec, &ret );
    8084                return ret;
    81         } // getTime
     85        } // time
    8286
    83         Time getCPUTime() {
     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() {
    8491                timespec ts;
    8592                clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts );
    86                 return (Time){ ts };
    87     } // getCPUTime
     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
    88114} // distribution
    89115
  • libcfa/src/concurrency/coroutine.cfa

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

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

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

    r857a1c6 rc8a0210  
    201201
    202202                sqe->opcode = IORING_OP_{op};
    203                 sqe->user_data = (__u64)(uintptr_t)&future;
     203                sqe->user_data = (uintptr_t)&future;
    204204                sqe->flags = sflags;
    205205                sqe->ioprio = 0;
     
    215215                asm volatile("": : :"memory");
    216216
    217                 verify( sqe->user_data == (__u64)(uintptr_t)&future );
     217                verify( sqe->user_data == (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': '(__u64)iov',
     240                'addr': '(uintptr_t)iov',
    241241                'len' : 'iovcnt',
    242242        }, define = 'CFA_HAVE_PREADV2'),
     
    245245                'fd'  : 'fd',
    246246                'off' : 'offset',
    247                 'addr': '(__u64)iov',
     247                'addr': '(uintptr_t)iov',
    248248                'len' : 'iovcnt'
    249249        }, define = 'CFA_HAVE_PWRITEV2'),
     
    257257                'addr': 'fd',
    258258                'len': 'op',
    259                 'off': '(__u64)event'
     259                'off': '(uintptr_t)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': '(__u64)(struct msghdr *)msg',
     271                'addr': '(uintptr_t)(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': '(__u64)(struct msghdr *)msg',
     278                'addr': '(uintptr_t)(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': '(__u64)buf',
     285                'addr': '(uintptr_t)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': '(__u64)buf',
     292                'addr': '(uintptr_t)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': '(__u64)addr',
    300                 'addr2': '(__u64)addrlen',
     299                'addr': '(uintptr_t)addr',
     300                'addr2': '(uintptr_t)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': '(__u64)addr',
     306                'addr': '(uintptr_t)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': '(__u64)len',
     312                'addr': '(uintptr_t)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': '(__u64)addr',
     325                'addr': '(uintptr_t)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': '(__u64)pathname',
     332                'addr': '(uintptr_t)pathname',
    333333                'len': 'mode',
    334334                'open_flags': 'flags;'
     
    339339                'addr': 'pathname',
    340340                'len': 'sizeof(*how)',
    341                 'off': '(__u64)how',
     341                'off': '(uintptr_t)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': '(__u64)statxbuf',
     350                'off': '(uintptr_t)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': '(__u64)buf',
     358                'addr': '(uintptr_t)buf',
    359359                'len': 'count'
    360360        }),
     
    362362        Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', {
    363363                'fd': 'fd',
    364                 'addr': '(__u64)buf',
     364                'addr': '(uintptr_t)buf',
    365365                'len': 'count'
    366366        }),
  • libcfa/src/concurrency/kernel.cfa

    r857a1c6 rc8a0210  
    113113static void __wake_one(cluster * cltr);
    114114
    115 static void push  (__cluster_idles & idles, processor & proc);
    116 static void remove(__cluster_idles & idles, processor & proc);
    117 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles );
     115static void mark_idle (__cluster_proc_list & idles, processor & proc);
     116static void mark_awake(__cluster_proc_list & idles, processor & proc);
     117static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list idles );
    118118
    119119extern void __cfa_io_start( processor * );
     
    189189
    190190                                // Push self to idle stack
    191                                 push(this->cltr->idles, * this);
     191                                mark_idle(this->cltr->procs, * this);
    192192
    193193                                // Confirm the ready-queue is empty
     
    195195                                if( readyThread ) {
    196196                                        // A thread was found, cancel the halt
    197                                         remove(this->cltr->idles, * this);
     197                                        mark_awake(this->cltr->procs, * this);
    198198
    199199                                        #if !defined(__CFA_NO_STATISTICS__)
     
    225225
    226226                                // We were woken up, remove self from idle
    227                                 remove(this->cltr->idles, * this);
     227                                mark_awake(this->cltr->procs, * 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 );
    361362                                #endif
    362363                                // This is case 2, the racy case, someone tried to run this thread before it finished blocking
     
    376377        #if !defined(__CFA_NO_STATISTICS__)
    377378                __tls_stats()->ready.threads.threads--;
     379                __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );
    378380        #endif
    379381
     
    455457                if( kernelTLS().this_stats ) {
    456458                        __tls_stats()->ready.threads.threads++;
     459                        __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", kernelTLS().this_processor );
    457460                }
    458461                else {
    459462                        __atomic_fetch_add(&cl->stats->ready.threads.threads, 1, __ATOMIC_RELAXED);
     463                        __push_stat( cl->stats, cl->stats->ready.threads.threads, true, "Cluster", cl );
    460464                }
    461465        #endif
     
    470474
    471475        ready_schedule_lock();
    472                 $thread * thrd = pop( this );
     476                $thread * thrd = pop_fast( this );
    473477        ready_schedule_unlock();
    474478
     
    613617        unsigned idle;
    614618        unsigned total;
    615         [idle, total, p] = query(this->idles);
     619        [idle, total, p] = query_idles(this->procs);
    616620
    617621        // If no one is sleeping, we are done
     
    650654}
    651655
    652 static void push  (__cluster_idles & this, processor & proc) {
     656static void mark_idle(__cluster_proc_list & this, processor & proc) {
    653657        /* paranoid */ verify( ! __preemption_enabled() );
    654658        lock( this );
    655659                this.idle++;
    656660                /* paranoid */ verify( this.idle <= this.total );
    657 
    658                 insert_first(this.list, proc);
     661                remove(proc);
     662                insert_first(this.idles, proc);
    659663        unlock( this );
    660664        /* paranoid */ verify( ! __preemption_enabled() );
    661665}
    662666
    663 static void remove(__cluster_idles & this, processor & proc) {
     667static void mark_awake(__cluster_proc_list & this, processor & proc) {
    664668        /* paranoid */ verify( ! __preemption_enabled() );
    665669        lock( this );
    666670                this.idle--;
    667671                /* paranoid */ verify( this.idle >= 0 );
    668 
    669672                remove(proc);
     673                insert_last(this.actives, proc);
    670674        unlock( this );
    671675        /* paranoid */ verify( ! __preemption_enabled() );
    672676}
    673677
    674 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) {
     678static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list this ) {
     679        /* paranoid */ verify( ! __preemption_enabled() );
     680        /* paranoid */ verify( ready_schedule_islocked() );
     681
    675682        for() {
    676683                uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
     
    678685                unsigned idle    = this.idle;
    679686                unsigned total   = this.total;
    680                 processor * proc = &this.list`first;
     687                processor * proc = &this.idles`first;
    681688                // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it
    682689                asm volatile("": : :"memory");
     
    684691                return [idle, total, proc];
    685692        }
     693
     694        /* paranoid */ verify( ready_schedule_islocked() );
     695        /* paranoid */ verify( ! __preemption_enabled() );
    686696}
    687697
  • libcfa/src/concurrency/kernel.hfa

    r857a1c6 rc8a0210  
    6969        struct cluster * cltr;
    7070
    71         // Id within the cluster
    72         unsigned cltr_id;
     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;
    7379
    7480        // Set to true to notify the processor should terminate
     
    140146// Cluster Tools
    141147
    142 // Intrusives lanes which are used by the relaxed ready queue
     148// Intrusives lanes which are used by the ready queue
    143149struct __attribute__((aligned(128))) __intrusive_lane_t;
    144150void  ?{}(__intrusive_lane_t & this);
    145151void ^?{}(__intrusive_lane_t & this);
    146152
    147 // Counter used for wether or not the lanes are all empty
    148 struct __attribute__((aligned(128))) __snzi_node_t;
    149 struct __snzi_t {
    150         unsigned mask;
    151         int root;
    152         __snzi_node_t * nodes;
    153 };
    154 
    155 void  ?{}( __snzi_t & this, unsigned depth );
    156 void ^?{}( __snzi_t & this );
     153// Aligned timestamps which are used by the relaxed ready queue
     154struct __attribute__((aligned(128))) __timestamp_t;
     155void  ?{}(__timestamp_t & this);
     156void ^?{}(__timestamp_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 
    165161        // Data tracking the actual lanes
    166162        // On a seperate cacheline from the used struct since
     
    171167                __intrusive_lane_t * volatile data;
    172168
     169                // Array of times
     170                __timestamp_t * volatile tscs;
     171
    173172                // Number of lanes (empty or not)
    174173                volatile size_t count;
     
    180179
    181180// Idle Sleep
    182 struct __cluster_idles {
     181struct __cluster_proc_list {
    183182        // Spin lock protecting the queue
    184183        volatile uint64_t lock;
     
    191190
    192191        // List of idle processors
    193         dlist(processor, processor) list;
     192        dlist(processor, processor) idles;
     193
     194        // List of active processors
     195        dlist(processor, processor) actives;
    194196};
    195197
     
    207209
    208210        // List of idle processors
    209         __cluster_idles idles;
     211        __cluster_proc_list procs;
    210212
    211213        // List of threads
  • libcfa/src/concurrency/kernel/startup.cfa

    r857a1c6 rc8a0210  
    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
    270273        #endif
    271274
     
    348351                        __print_stats( &local_stats, proc->print_stats, "Processor ", proc->name, (void*)proc );
    349352                }
     353                #if defined(CFA_STATS_ARRAY)
     354                        __flush_stat( &local_stats, "Processor", proc );
     355                #endif
    350356        #endif
    351357
     
    463469        this.name = name;
    464470        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;
    465476        do_terminate = false;
    466477        preemption_alarm = 0p;
     
    483494        #endif
    484495
    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 
     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);
     500
     501                // Adjust the ready queue size
     502                ready_queue_grow( cltr );
     503
     504        // Unlock the RWlock
     505        ready_mutate_unlock( last_size );
     506
     507        __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this);
     508}
     509
     510// Not a ctor, it just preps the destruction but should not destroy members
     511static void deinit(processor & this) {
    491512        // Lock the RWlock so no-one pushes/pops while we are changing the queue
    492513        uint_fast32_t last_size = ready_mutate_lock();
     514                this.cltr->procs.total -= 1u;
     515                remove(this);
    493516
    494517                // Adjust the ready queue size
    495                 this.cltr_id = ready_queue_grow( cltr, target );
    496 
    497         // Unlock the RWlock
    498         ready_mutate_unlock( last_size );
    499 
    500         __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this);
    501 }
    502 
    503 // Not a ctor, it just preps the destruction but should not destroy members
    504 static void deinit(processor & this) {
    505         lock( this.cltr->idles );
    506                 int target = this.cltr->idles.total -= 1u;
    507         unlock( this.cltr->idles );
    508 
    509         // Lock the RWlock so no-one pushes/pops while we are changing the queue
    510         uint_fast32_t last_size = ready_mutate_lock();
    511 
    512                 // Adjust the ready queue 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);
     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 );
    520522
    521523        close(this.idle);
     
    560562//-----------------------------------------------------------------------------
    561563// Cluster
    562 static void ?{}(__cluster_idles & this) {
     564static void ?{}(__cluster_proc_list & this) {
    563565        this.lock  = 0;
    564566        this.idle  = 0;
    565567        this.total = 0;
    566         (this.list){};
    567568}
    568569
     
    590591
    591592                // Adjust the ready queue size
    592                 ready_queue_grow( &this, 0 );
     593                ready_queue_grow( &this );
    593594
    594595        // Unlock the RWlock
     
    605606
    606607                // Adjust the ready queue size
    607                 ready_queue_shrink( &this, 0 );
     608                ready_queue_shrink( &this );
    608609
    609610        // Unlock the RWlock
     
    615616                        __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this );
    616617                }
     618                #if defined(CFA_STATS_ARRAY)
     619                        __flush_stat( this.stats, "Cluster", &this );
     620                #endif
    617621                free( this.stats );
    618622        #endif
  • libcfa/src/concurrency/kernel_private.hfa

    r857a1c6 rc8a0210  
    8383// Cluster lock API
    8484//=======================================================================
    85 // Cells use by the reader writer lock
    86 // while not generic it only relies on a opaque pointer
    87 struct __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 
    101 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
    102 
    10385// Lock-Free registering/unregistering of threads
    10486// Register a processor to a given cluster and get its unique id in return
    105 unsigned doregister( struct __processor_id_t * proc );
     87void register_proc_id( struct __processor_id_t * );
    10688
    10789// Unregister a processor from a given cluster using its id, getting back the original pointer
    108 void     unregister( struct __processor_id_t * proc );
    109 
    110 //-----------------------------------------------------------------------
    111 // Cluster idle lock/unlock
    112 static 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 
    123 static inline void unlock(__cluster_idles & this) {
    124         /* paranoid */ verify( 1 == (this.lock % 2) );
    125         __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
    126 }
     90void unregister_proc_id( struct __processor_id_t * proc );
    12791
    12892//=======================================================================
     
    152116        __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE);
    153117}
     118
     119// Cells use by the reader writer lock
     120// while not generic it only relies on a opaque pointer
     121struct __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
     135static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
    154136
    155137//-----------------------------------------------------------------------
     
    247229void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ );
    248230
     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
     235static 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
     242static 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
     249static 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
     270static 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
    249283//=======================================================================
    250284// Ready-Queue API
    251285//-----------------------------------------------------------------------
    252 // pop thread from the ready queue of a cluster
    253 // returns 0p if empty
    254 __attribute__((hot)) bool query(struct cluster * cltr);
    255 
    256 //-----------------------------------------------------------------------
    257286// push thread onto a ready queue for a cluster
    258287// returns true if the list was previously empty, false otherwise
    259 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd);
     288__attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd);
    260289
    261290//-----------------------------------------------------------------------
     
    263292// returns 0p if empty
    264293// May return 0p spuriously
    265 __attribute__((hot)) struct $thread * pop(struct cluster * cltr);
     294__attribute__((hot)) struct $thread * pop_fast(struct cluster * cltr);
    266295
    267296//-----------------------------------------------------------------------
     
    272301
    273302//-----------------------------------------------------------------------
    274 // remove thread from the ready queue of a cluster
    275 // returns bool if it wasn't found
    276 bool remove_head(struct cluster * cltr, struct $thread * thrd);
    277 
    278 //-----------------------------------------------------------------------
    279303// Increase the width of the ready queue (number of lanes) by 4
    280 unsigned ready_queue_grow  (struct cluster * cltr, int target);
     304void ready_queue_grow  (struct cluster * cltr);
    281305
    282306//-----------------------------------------------------------------------
    283307// Decrease the width of the ready queue (number of lanes) by 4
    284 void ready_queue_shrink(struct cluster * cltr, int target);
     308void ready_queue_shrink(struct cluster * cltr);
    285309
    286310
  • libcfa/src/concurrency/preemption.cfa

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

    r857a1c6 rc8a0210  
    1717// #define __CFA_DEBUG_PRINT_READY_QUEUE__
    1818
    19 // #define USE_SNZI
    2019// #define USE_MPSC
     20
     21#define USE_RELAXED_FIFO
     22// #define USE_WORK_STEALING
    2123
    2224#include "bits/defs.hfa"
     
    2931#include <unistd.h>
    3032
    31 #include "snzi.hfa"
    3233#include "ready_subqueue.hfa"
    3334
     
    4041#endif
    4142
    42 #define BIAS 4
     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
     54static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred);
     55static inline struct $thread * try_pop(struct cluster * cltr, unsigned w);
     56static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j);
     57static inline struct $thread * search(struct cluster * cltr);
     58
    4359
    4460// returns the maximum number of processors the RWLock support
     
    94110//=======================================================================
    95111// Lock-Free registering/unregistering of threads
    96 unsigned doregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     112void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
    97113        __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc);
    98114
     
    108124                        /*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size));
    109125                        /*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0);
    110                         return i;
     126                        proc->id = i;
    111127                }
    112128        }
     
    135151        /*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size));
    136152        /*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0);
    137         return n;
    138 }
    139 
    140 void unregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     153        proc->id = n;
     154}
     155
     156void unregister_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
    141157        unsigned id = proc->id;
    142158        /*paranoid*/ verify(id < ready);
     
    193209
    194210//=======================================================================
    195 // Cforall Reqdy Queue used for scheduling
     211// Cforall Ready Queue used for scheduling
    196212//=======================================================================
    197213void ?{}(__ready_queue_t & this) with (this) {
    198214        lanes.data  = 0p;
     215        lanes.tscs  = 0p;
    199216        lanes.count = 0;
    200217}
    201218
    202219void ^?{}(__ready_queue_t & this) with (this) {
    203         verify( 1 == lanes.count );
    204         #ifdef USE_SNZI
    205                 verify( !query( snzi ) );
    206         #endif
     220        verify( SEQUENTIAL_SHARD == lanes.count );
    207221        free(lanes.data);
     222        free(lanes.tscs);
    208223}
    209224
    210225//-----------------------------------------------------------------------
    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 
    218 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
    219         unsigned i;
    220         bool local;
    221         #if defined(BIAS)
     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;
    222232                unsigned rlow  = r % BIAS;
    223233                unsigned rhigh = r / BIAS;
     
    225235                        // (BIAS - 1) out of BIAS chances
    226236                        // Use perferred queues
    227                         i = preferred + (rhigh % 4);
     237                        i = preferred + (rhigh % READYQ_SHARD_FACTOR);
    228238                        local = true;
    229239                }
     
    234244                        local = false;
    235245                }
    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 
     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
    274303                #if !defined(__CFA_NO_STATISTICS__)
    275304                        if(external) {
    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);
     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);
    278307                        }
    279308                        else {
    280                                 if(local) __tls_stats()->ready.pick.push.local++;
    281                                 __tls_stats()->ready.pick.push.attempt++;
     309                                if(local) __tls_stats()->ready.pick.push.lsuccess++;
     310                                __tls_stats()->ready.pick.push.success++;
    282311                        }
    283312                #endif
    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);
     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
     455static 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);
    320480
    321481        // Update statistics
    322482        #if !defined(__CFA_NO_STATISTICS__)
    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                 }
     483                __tls_stats()->ready.pick.pop.success++;
    331484        #endif
    332485
    333         // return whether or not the list was empty before this push
    334         return first;
    335 }
    336 
    337 static struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j);
    338 static 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;
     486        #if defined(USE_WORK_STEALING)
     487                lanes.tscs[w].tv = thrd->link.ts;
    348488        #endif
    349489
    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) {
     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
     497static inline struct $thread * search(struct cluster * cltr) with (cltr->ready_queue) {
    392498        /* paranoid */ verify( lanes.count > 0 );
    393499        unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     
    405511}
    406512
    407 
    408513//-----------------------------------------------------------------------
    409 // Given 2 indexes, pick the list with the oldest push an try to pop from it
    410 static 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 
    424 static 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 
    471 bool 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 
     514// Check that all the intrusive queues in the data structure are still consistent
    500515static void check( __ready_queue_t & q ) with (q) {
    501516        #if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC)
     
    522537}
    523538
     539//-----------------------------------------------------------------------
     540// Given 2 indexes, pick the list with the oldest push an try to pop from it
     541static 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);
     553}
     554
    524555// Call this function of the intrusive list was moved using memcpy
    525556// fixes the list so that the pointers back to anchors aren't left dangling
     
    541572}
    542573
     574static 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
     585static 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
     591static 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
    543600// Grow the ready queue
    544 unsigned ready_queue_grow(struct cluster * cltr, int target) {
    545         unsigned preferred;
     601void ready_queue_grow(struct cluster * cltr) {
    546602        size_t ncount;
     603        int target = cltr->procs.total;
    547604
    548605        /* paranoid */ verify( ready_mutate_islocked() );
     
    554611        // grow the ready queue
    555612        with( cltr->ready_queue ) {
    556                 #ifdef USE_SNZI
    557                         ^(snzi){};
    558                 #endif
    559 
    560613                // Find new count
    561614                // Make sure we always have atleast 1 list
    562615                if(target >= 2) {
    563                         ncount = target * 4;
    564                         preferred = ncount - 4;
     616                        ncount = target * READYQ_SHARD_FACTOR;
    565617                } else {
    566                         ncount = 1;
    567                         preferred = 0;
     618                        ncount = SEQUENTIAL_SHARD;
    568619                }
    569620
     
    583634                // Update original
    584635                lanes.count = ncount;
    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         }
     636        }
     637
     638        fix_times(cltr);
     639
     640        reassign_cltr_id(cltr);
    596641
    597642        // Make sure that everything is consistent
     
    601646
    602647        /* paranoid */ verify( ready_mutate_islocked() );
    603         return preferred;
    604648}
    605649
    606650// Shrink the ready queue
    607 void ready_queue_shrink(struct cluster * cltr, int target) {
     651void ready_queue_shrink(struct cluster * cltr) {
    608652        /* paranoid */ verify( ready_mutate_islocked() );
    609653        __cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue\n");
     
    612656        /* paranoid */ check( cltr->ready_queue );
    613657
     658        int target = cltr->procs.total;
     659
    614660        with( cltr->ready_queue ) {
    615                 #ifdef USE_SNZI
    616                         ^(snzi){};
    617                 #endif
    618 
    619661                // Remember old count
    620662                size_t ocount = lanes.count;
     
    622664                // Find new count
    623665                // Make sure we always have atleast 1 list
    624                 lanes.count = target >= 2 ? target * 4: 1;
     666                lanes.count = target >= 2 ? target * READYQ_SHARD_FACTOR: SEQUENTIAL_SHARD;
    625667                /* paranoid */ verify( ocount >= lanes.count );
    626                 /* paranoid */ verify( lanes.count == target * 4 || target < 2 );
     668                /* paranoid */ verify( lanes.count == target * READYQ_SHARD_FACTOR || target < 2 );
    627669
    628670                // for printing count the number of displaced threads
     
    667709                        fix(lanes.data[idx]);
    668710                }
    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         }
     711        }
     712
     713        fix_times(cltr);
     714
     715        reassign_cltr_id(cltr);
    680716
    681717        // Make sure that everything is consistent
  • libcfa/src/concurrency/ready_subqueue.hfa

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

    r857a1c6 rc8a0210  
    55#include <inttypes.h>
    66#include "bits/debug.hfa"
     7#include "bits/locks.hfa"
    78#include "stats.hfa"
    89
     
    4445                        stats->io.calls.errors.busy = 0;
    4546                        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;
    4652                #endif
    4753        }
     
    151157                #endif
    152158        }
     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
    153204#endif
  • libcfa/src/concurrency/stats.hfa

    r857a1c6 rc8a0210  
    11#pragma once
     2
     3// #define CFA_STATS_ARRAY 10000
    24
    35#include <stdint.h>
     
    109111        #endif
    110112
     113        #if defined(CFA_STATS_ARRAY)
     114                struct __stats_elem_t {
     115                        long long int ts;
     116                        int64_t value;
     117                };
     118        #endif
     119
    111120        struct __attribute__((aligned(128))) __stats_t {
    112121                __stats_readQ_t ready;
     
    114123                        __stats_io_t    io;
    115124                #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
    116133        };
    117134
     
    119136        void __tally_stats( struct __stats_t *, struct __stats_t * );
    120137        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
    121145#endif
    122146
  • libcfa/src/concurrency/thread.cfa

    r857a1c6 rc8a0210  
    3939        link.next = 0p;
    4040        link.prev = 0p;
    41         link.preferred = -1;
    4241        #if defined( __CFA_WITH_VERIFY__ )
    4342                canary = 0x0D15EA5E0D15EA5Ep;
     
    6261}
    6362
    64 FORALL_DATA_INSTANCE(ThreadCancelled, (thread_t &), (thread_t))
     63EHM_VIRTUAL_TABLE(SomeThreadCancelled, std_thread_cancelled);
    6564
    6665forall(T &)
     
    7372forall(T &)
    7473const char * msg(ThreadCancelled(T) *) {
    75         return "ThreadCancelled";
     74        return "ThreadCancelled(...)";
    7675}
    7776
    7877forall(T &)
    7978static 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 forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)))
     83static void default_thread_cancel_handler(SomeThreadCancelled & ) {
     84        // Improve this error message, can I do formatting?
     85        abort( "Unhandled thread cancellation.\n" );
     86}
     87
     88forall(T & | is_thread(T) | IS_EXCEPTION(SomeThreadCancelled))
    8489void ?{}( thread_dtor_guard_t & this,
    85                 T & thrd, void(*cancelHandler)(ThreadCancelled(T) &)) {
    86         $monitor * m = get_monitor(thrd);
     90                T & thrd, void(*cancelHandler)(SomeThreadCancelled &)) {
     91        $monitor * m = get_monitor(thrd);
    8792        $thread * desc = get_thread(thrd);
    8893
    8994        // Setup the monitor guard
    9095        void (*dtor)(T& mutex this) = ^?{};
    91         bool join = cancelHandler != (void(*)(ThreadCancelled(T)&))0;
     96        bool join = cancelHandler != (void(*)(SomeThreadCancelled&))0;
    9297        (this.mg){&m, (void(*)())dtor, join};
    9398
     
    103108        }
    104109        desc->state = Cancelled;
    105         void(*defaultResumptionHandler)(ThreadCancelled(T) &) =
     110        void(*defaultResumptionHandler)(SomeThreadCancelled &) =
    106111                join ? cancelHandler : default_thread_cancel_handler;
    107112
    108         ThreadCancelled(T) except;
    109113        // TODO: Remove explitate vtable set once trac#186 is fixed.
    110         except.virtual_table = &get_exception_vtable(&except);
     114        SomeThreadCancelled except;
     115        except.virtual_table = &std_thread_cancelled;
    111116        except.the_thread = &thrd;
    112117        except.the_exception = __cfaehm_cancellation_exception( cancellation );
    113         throwResume except;
     118        // Why is this cast required?
     119        throwResume (SomeThreadCancelled &)except;
    114120
    115121        except.the_exception->virtual_table->free( except.the_exception );
     
    158164
    159165//-----------------------------------------------------------------------------
    160 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
     166forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(SomeThreadCancelled))
    161167T & join( T & this ) {
    162168        thread_dtor_guard_t guard = { this, defaultResumptionHandler };
  • libcfa/src/concurrency/thread.hfa

    r857a1c6 rc8a0210  
    3232};
    3333
    34 FORALL_DATA_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
     34EHM_EXCEPTION(SomeThreadCancelled) (
     35        void * the_thread;
     36        exception_t * the_exception;
     37);
     38
     39EHM_EXTERN_VTABLE(SomeThreadCancelled, std_thread_cancelled);
     40
     41EHM_FORALL_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
    3542        thread_t * the_thread;
    3643        exception_t * the_exception;
     
    7986};
    8087
    81 forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
    82 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
     88forall( T & | is_thread(T) | IS_EXCEPTION(SomeThreadCancelled) )
     89void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(SomeThreadCancelled &) );
    8390void ^?{}( thread_dtor_guard_t & this );
    8491
     
    125132//----------
    126133// join
    127 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
     134forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(SomeThreadCancelled) )
    128135T & join( T & this );
    129136
  • libcfa/src/exception.c

    r857a1c6 rc8a0210  
    1010// Created On       : Mon Jun 26 15:13:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct 27 16:27:00 2020
    13 // Update Count     : 35
     12// Last Modified On : Wed Feb 24 13:40:00 2021
     13// Update Count     : 36
    1414//
    1515
     
    2626#include "concurrency/invoke.h"
    2727#include "stdhdr/assert.h"
     28#include "virtual.h"
    2829
    2930#if defined( __ARM_ARCH )
     
    4647const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643;
    4748
    48 // Base exception vtable is abstract, you should not have base exceptions.
    49 struct __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
     49// Base Exception type id:
     50struct __cfa__parent_vtable __cfatid_exception_t = {
     51        NULL,
    5652};
    5753
  • libcfa/src/exception.h

    r857a1c6 rc8a0210  
    1010// Created On       : Mon Jun 26 15:11:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Oct 27 14:45:00 2020
    13 // Update Count     : 11
     12// Last Modified On : Thr Apr  8 15:20:00 2021
     13// Update Count     : 12
    1414//
    1515
     
    2929struct __cfaehm_base_exception_t;
    3030typedef struct __cfaehm_base_exception_t exception_t;
     31struct __cfa__parent_vtable;
    3132struct __cfaehm_base_exception_t_vtable {
    32         const struct __cfaehm_base_exception_t_vtable * parent;
     33        const struct __cfa__parent_vtable * __cfavir_typeid;
    3334        size_t size;
    3435        void (*copy)(struct __cfaehm_base_exception_t *this,
     
    4041        struct __cfaehm_base_exception_t_vtable const * virtual_table;
    4142};
    42 extern struct __cfaehm_base_exception_t_vtable
    43         ___cfaehm_base_exception_t_vtable_instance;
     43extern struct __cfa__parent_vtable __cfatid_exception_t;
    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.
    106108         */
    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

    r857a1c6 rc8a0210  
    1010// Created On       : Thu Apr  7 10:25:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Aug  4 16:22:00 2020
    13 // Update Count     : 3
     12// Last Modified On : Thr Apr  8 15:16:00 2021
     13// Update Count     : 4
    1414//
    1515
     
    1818// -----------------------------------------------------------------------------------------------
    1919
    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__)
     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, , )
    2528
    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__)
     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)
    3033
    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__)
     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)
    3840
    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, )
     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)
    4750
    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)
     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)
    5456
    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__)
     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)
    5965
    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, )
     66#define EHM_TYPE_ID(exception_name) _EHM_TYPE_ID_TYPE(exception_name)
    6767
    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); }
     68#define EHM_MATCH_ALL __cfa__parent_vtable
    12769
    12870// IS_EXCEPTION(exception_name [, (...parameters)])
     
    13577#define IS_TERMINATION_EXCEPTION(...) _IS_EXCEPTION(is_termination_exception, __VA_ARGS__, , ~)
    13678
    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__
     79// Macros starting with a leading underscore are internal.
    14380
    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)
     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
    15186
    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))
     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
    16090
    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); \
     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, \
    17899        }
    179100
    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
     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        }
    185107
    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
     108#define _EHM_DEFINE_COPY(exception_name, arguments) \
     109        void copy(exception_name arguments * this, exception_name arguments * that) { \
     110                *this = *that; \
     111        }
    194112
    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
     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        }
    207118
    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
     119#define _EHM_DEFINE_MSG(exception_name, arguments) \
     120        const char * msg(exception_name arguments * this) { \
     121                return #exception_name #arguments; \
     122        }
    219123
    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; \
     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; \
    225132                size_t size; \
    226133                void (*copy)(exception_name parameters * this, exception_name parameters * other); \
    227134                void (*^?{})(exception_name parameters & this); \
    228135                const char * (*msg)(exception_name parameters * this); \
    229                 _CLOSE
     136        }
    230137
    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
     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)
    245183
    246184#define _IS_EXCEPTION(kind, exception_name, parameters, ...) \
    247         kind(exception_name parameters, VTABLE_TYPE(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
  • libcfa/src/fstream.cfa

    r857a1c6 rc8a0210  
    321321
    322322
     323EHM_VIRTUAL_TABLE(Open_Failure, Open_Failure_main_table);
    323324void ?{}( Open_Failure & this, ofstream & ostream ) {
    324         VTABLE_INIT(this, Open_Failure);
     325        this.virtual_table = &Open_Failure_main_table;
    325326        this.ostream = &ostream;
    326327        this.tag = 1;
    327328}
    328329void ?{}( Open_Failure & this, ifstream & istream ) {
    329         VTABLE_INIT(this, Open_Failure);
     330        this.virtual_table = &Open_Failure_main_table;
    330331        this.istream = &istream;
    331332        this.tag = 0;
    332333}
    333 const char * Open_Failure_msg(Open_Failure * this) {
    334         return "Open_Failure";
    335 }
    336 VTABLE_INSTANCE(Open_Failure)(Open_Failure_msg);
    337334void throwOpen_Failure( ofstream & ostream ) {
    338335        Open_Failure exc = { ostream };
  • libcfa/src/fstream.hfa

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

    r857a1c6 rc8a0210  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar  2 14:51:30 2021
    13 // Update Count     : 1151
     12// Last Modified On : Tue Apr 13 13:05:24 2021
     13// Update Count     : 1324
    1414//
    1515
     
    195195                        int len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
    196196                        fmt( os, "%s", buf ); \
    197                         if ( isfinite( val ) ) {                                        /* if number, always print decimal point */ \
     197                        if ( isfinite( val ) ) { /* if number, print decimal point when no fraction or exponent */ \
    198198                                for ( int i = 0;; i += 1 ) { \
    199199                                        if ( i == len ) { fmt( os, "." ); break; } \
    200                                         if ( buf[i] == '.' ) break; \
     200                                        if ( buf[i] == '.' || buf[i] == 'e' || buf[i] == 'E' ) break; /* decimal point or scientific ? */ \
    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 #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 ) \
    542 forall( ostype & | ostream( ostype ) ) \
    543 static 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 */ \
    559 forall( 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 
    653 IntegralFMTImpl128( int128, signed, 'd', "%    *ll ", "%    *.*ll " )
    654 IntegralFMTImpl128( unsigned int128, unsigned, 'u', "%    *ll ", "%    *.*ll " )
    655 #endif // __SIZEOF_INT128__
    656 #endif // 0
    657 
    658 #if 1
     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
    659539#if defined( __SIZEOF_INT128__ )
    660540// Default prefix for non-decimal prints is 0b, 0, 0x.
     
    746626IntegralFMTImpl128( unsigned int128 )
    747627#endif // __SIZEOF_INT128__
    748 #endif // 0
    749628
    750629// *********************************** floating point ***********************************
    751630
    752 #define PrintWithDP2( os, format, val, ... ) \
     631static 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, ... ) \
    753639        { \
    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'; \
     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 */ \
    767653                                } /* if */ \
    768654                        } /* 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] = ' '; \
    769674                } /* if */ \
    770675                fmt( os, "%s", &buf[bufbeg] ); \
     
    773678#define FloatingPointFMTImpl( T, DFMTNP, DFMTP ) \
    774679forall( 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\
    775688        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
     689                enum { size = 48 }; \
     690                char buf[size]; \
     691                int bufbeg = 0, i, len; \
     692\
    776693                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
    777                 char fmtstr[sizeof(DFMTP)];                                             /* sizeof includes '\0' */ \
     694                char fmtstr[sizeof(DFMTP) + 8];                                 /* sizeof includes '\0' */ \
    778695                if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
    779696                else memcpy( &fmtstr, DFMTP, sizeof(DFMTP) ); \
     
    789706                        fmtstr[sizeof(DFMTNP)-2] = f.base;                      /* sizeof includes '\0' */ \
    790707                        /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star]); */ \
    791                         PrintWithDP2( os, &fmtstr[star], f.val, f.wd ) \
     708                        PrintWithDP2( os, &fmtstr[star], f.wd, f.val ) \
    792709                } else {                                                                                /* precision */ \
    793710                        fmtstr[sizeof(DFMTP)-2] = f.base;                       /* sizeof includes '\0' */ \
    794711                        /* printf( "%g %d %d %s\n", f.val, f.wd, f.pc, &fmtstr[star] ); */ \
    795                         PrintWithDP2( os, &fmtstr[star], f.val, f.wd, f.pc ) \
     712                        PrintWithDP2( os, &fmtstr[star], f.wd, f.pc, f.val ) \
    796713                } /* if */ \
    797714                return os; \
     
    801718} // distribution
    802719
    803 FloatingPointFMTImpl( double, "%    * ", "%    *.* " )
    804 FloatingPointFMTImpl( long double, "%    *L ", "%    *.*L " )
     720FloatingPointFMTImpl( double, "     * ", "     *.* " )
     721FloatingPointFMTImpl( long double, "     *L ", "     *.*L " )
    805722
    806723// *********************************** character ***********************************
  • libcfa/src/iostream.hfa

    r857a1c6 rc8a0210  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar  2 14:05:08 2021
    13 // Update Count     : 369
     12// Last Modified On : Tue Apr 13 13:05:11 2021
     13// Update Count     : 384
    1414//
    1515
     
    158158struct _Ostream_Manip {
    159159        T val;                                                                                          // polymorphic base-type
    160         unsigned int wd, pc;                                                            // width, precision
     160        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
    165166                        unsigned char neg:1;                                            // val is negative
    166167                        unsigned char pc:1;                                                     // precision specified
     
    222223        _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'a', { .all : 0 } }; } \
    223224        _Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'e', { .all : 0 } }; } \
    224         _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .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 } }; } \
    225227        _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
    226228        _Ostream_Manip(T) ws( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
    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; } \
     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; } \
    229232        _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
    230233        _Ostream_Manip(T) upcase( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'G', { .all : 0 } }; } \
     
    235238        _Ostream_Manip(T) nodp( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
    236239        _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; } \
    237242} /* distribution */ \
    238243forall( ostype & | ostream( ostype ) ) { \
  • libcfa/src/math.hfa

    r857a1c6 rc8a0210  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // math --
     7// math.hfa --
    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 : Mon Aug 24 08:56:20 2020
    13 // Update Count     : 126
     12// Last Modified On : Thu Apr 15 11:47:56 2021
     13// Update Count     : 132
    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 ); }
    102107        float log2( float x ) { return log2f( x ); }
    103108        // extern "C" { double log2( double ); }
  • libcfa/src/time.hfa

    r857a1c6 rc8a0210  
    1010// Created On       : Wed Mar 14 23:18:57 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 17 16:13:00 2020
    13 // Update Count     : 663
     12// Last Modified On : Wed Apr 14 09:30:30 2021
     13// Update Count     : 664
    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        } // ?=?
    3143
    3244        Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tn }; }
  • libcfa/src/virtual.c

    r857a1c6 rc8a0210  
    1515
    1616#include "virtual.h"
     17#include "assert.h"
    1718
    1819int __cfa__is_parent( struct __cfa__parent_vtable const * parent,
    1920        struct __cfa__parent_vtable const * child ) {
     21        assert( child );
    2022        do {
    2123                if ( parent == child )
     
    2830void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent,
    2931        struct __cfa__parent_vtable const * const * child ) {
     32        assert( child );
    3033        return (__cfa__is_parent(parent, *child)) ? (void *)child : (void *)0;
    3134}
  • src/AST/Expr.cpp

    r857a1c6 rc8a0210  
    260260}
    261261
     262ConstantExpr * 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
    262271ConstantExpr * ConstantExpr::null( const CodeLocation & loc, const Type * ptrType ) {
    263272        return new ConstantExpr{
  • src/AST/Expr.hpp

    r857a1c6 rc8a0210  
    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 null pointer value for the given type. void * if omitted.
     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.
    447449        static ConstantExpr * null( const CodeLocation & loc, const Type * ptrType = nullptr );
    448450
  • src/Concurrency/Keywords.cc

    r857a1c6 rc8a0210  
    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        }
    4447        inline static std::string getVTableName( std::string const & exception_name ) {
    45                 return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name);
     48                return exception_name.empty() ? std::string() : Virtual::vtableTypeName( exception_name );
    4649        }
    4750
     
    7578                  type_name( type_name ), field_name( field_name ), getter_name( getter_name ),
    7679                  context_error( context_error ), exception_name( exception_name ),
     80                  typeid_name( getTypeIdName( exception_name ) ),
    7781                  vtable_name( getVTableName( exception_name ) ),
    7882                  needs_main( needs_main ), cast_target( cast_target ) {}
     
    8488
    8589                void handle( StructDecl * );
     90                void addTypeId( StructDecl * );
    8691                void addVtableForward( StructDecl * );
    8792                FunctionDecl * forwardDeclare( StructDecl * );
     
    99104                const std::string context_error;
    100105                const std::string exception_name;
     106                const std::string typeid_name;
    101107                const std::string vtable_name;
    102108                bool needs_main;
     
    106112                FunctionDecl * dtor_decl = nullptr;
    107113                StructDecl * except_decl = nullptr;
     114                StructDecl * typeid_decl = nullptr;
    108115                StructDecl * vtable_decl = nullptr;
    109116        };
     
    392399                else if ( !except_decl && exception_name == decl->name && decl->body ) {
    393400                        except_decl = decl;
     401                }
     402                else if ( !typeid_decl && typeid_name == decl->name && decl->body ) {
     403                        typeid_decl = decl;
    394404                }
    395405                else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
     
    448458                if( !dtor_decl ) SemanticError( decl, context_error );
    449459
    450                 addVtableForward( decl );
     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                }
    451467                FunctionDecl * func = forwardDeclare( decl );
    452468                ObjectDecl * field = addField( decl );
     
    454470        }
    455471
     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 )
     477                        ) );
     478                declsToAddBefore.push_back( Virtual::makeTypeIdInstance( &typeid_type ) );
     479        }
     480
    456481        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 )
    464                         ) );
    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                 }
     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 ) ) ) );
    471492        }
    472493
  • src/Parser/parser.yy

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

    r857a1c6 rc8a0210  
    4242}
    4343
     44Constant 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
    4453Constant Constant::null( Type * ptrtype ) {
    4554        if ( nullptr == ptrtype ) {
  • src/SynTree/Constant.h

    r857a1c6 rc8a0210  
    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 );
    4951
    5052        /// generates a null pointer value for the given type. void * if omitted.
  • src/Virtual/ExpandCasts.cc

    r857a1c6 rc8a0210  
    3232namespace Virtual {
    3333
     34static 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
     39static bool is_type_id_object( const ObjectDecl * objectDecl ) {
     40        const std::string & objectName = objectDecl->name;
     41        return is_prefix( "__cfatid_", objectName );
     42}
     43
    3444        // Indented until the new ast code gets added.
    3545
     
    6676        };
    6777
    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 
    10078        class VirtualCastCore {
    101                 Type * pointer_to_pvt(int level_of_indirection) {
     79                CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {
    10280                        Type * type = new StructInstType(
    10381                                Type::Qualifiers( Type::Const ), pvt_decl );
     
    10583                                type = new PointerType( noQualifiers, type );
    10684                        }
    107                         return type;
     85                        return new CastExpr( expr, type );
    10886                }
    10987
     
    141119
    142120        void VirtualCastCore::premutate( ObjectDecl * 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                         }
     121                if ( is_type_id_object( objectDecl ) ) {
     122                        // Multiple definitions should be fine because of linkonce.
     123                        indexer.insert( objectDecl );
    150124                }
    151125        }
     
    170144        }
    171145
    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;
     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;
    179152                } else {
    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();
     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();
    194182                        assert( memberDecl );
    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;
     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;
    220229        }
    221230
     
    228237                assert( pvt_decl );
    229238
    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." );
     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." );
    235251                }
    236252
    237253                Expression * result = new CastExpr(
    238254                        new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
    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                                         )
     255                                cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),
     256                                cast_to_type_id( castExpr->get_arg(), 2 ),
    247257                        } ),
    248258                        castExpr->get_result()->clone()
     
    252262                castExpr->set_result( nullptr );
    253263                delete castExpr;
    254                 delete vtable_type;
    255264                return result;
    256265        }
  • src/Virtual/Tables.cc

    r857a1c6 rc8a0210  
    1010// Created On       : Mon Aug 31 11:11:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Sep  3 14:56:00 2020
    13 // Update Count     : 0
     12// Last Modified On : Thr Apr  8 15:51:00 2021
     13// Update Count     : 1
    1414//
    1515
     
    2222namespace Virtual {
    2323
     24std::string typeIdType( std::string const & type_name ) {
     25        return "__cfatid_struct_" + type_name;
     26}
     27
     28std::string typeIdName( std::string const & type_name ) {
     29        return "__cfatid_" + type_name;
     30}
     31
     32static std::string typeIdTypeToInstance( std::string const & type_name ) {
     33        return typeIdName(type_name.substr(16));
     34}
     35
    2436std::string vtableTypeName( std::string const & name ) {
    2537        return name + "_vtable";
     38}
     39
     40std::string baseTypeName( std::string const & vtable_type_name ) {
     41        return vtable_type_name.substr(0, vtable_type_name.size() - 7);
    2642}
    2743
     
    8197                                inits.push_back(
    8298                                                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 ) ) ) );
    83103                        } else if ( std::string( "size" ) == field->name ) {
    84104                                inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );
     
    147167}
    148168
     169ObjectDecl * makeTypeIdForward() {
     170        return nullptr;
    149171}
     172
     173Attribute * 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
     180ObjectDecl * 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

    r857a1c6 rc8a0210  
    1010// Created On       : Mon Aug 31 11:07:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Sep  1 14:29:00 2020
    13 // Update Count     : 0
     12// Last Modified On : Thr Apr  8 15:55:00 2021
     13// Update Count     : 1
    1414//
    1515
     
    2222namespace Virtual {
    2323
     24std::string typeIdType( std::string const & type_name );
     25std::string typeIdName( std::string const & type_name );
    2426std::string vtableTypeName( std::string const & type_name );
    2527std::string instanceName( std::string const & vtable_name );
     
    5052 */
    5153
     54ObjectDecl * 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
    5259}
  • tests/.expect/KRfunctions.nast.arm64.txt

    r857a1c6 rc8a0210  
    104104    signed int _X1bi_2;
    105105    {
    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)));
     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)));
    108108    }
    109109
  • tests/.expect/KRfunctions.nast.x64.txt

    r857a1c6 rc8a0210  
    104104    signed int _X1bi_2;
    105105    {
    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)));
     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)));
    108108    }
    109109
  • tests/.expect/KRfunctions.nast.x86.txt

    r857a1c6 rc8a0210  
    104104    signed int _X1bi_2;
    105105    {
    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)));
     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)));
    108108    }
    109109
  • tests/.expect/KRfunctions.oast.x64.txt

    r857a1c6 rc8a0210  
    104104    signed int _X1bi_2;
    105105    {
    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)));
     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)));
    108108    }
    109109
  • tests/.expect/declarationSpecifier.arm64.txt

    r857a1c6 rc8a0210  
    11471147
    11481148    {
    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)) /* ?{} */);
     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)) /* ?{} */);
    11511151    }
    11521152
  • tests/.expect/declarationSpecifier.x64.txt

    r857a1c6 rc8a0210  
    11471147
    11481148    {
    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)) /* ?{} */);
     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)) /* ?{} */);
    11511151    }
    11521152
  • tests/.expect/declarationSpecifier.x86.txt

    r857a1c6 rc8a0210  
    11471147
    11481148    {
    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)) /* ?{} */);
     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)) /* ?{} */);
    11511151    }
    11521152
  • tests/.expect/extension.arm64.txt

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

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

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

    r857a1c6 rc8a0210  
    339339
    340340    {
    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)) /* ?{} */);
     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)) /* ?{} */);
    343343    }
    344344
  • tests/.expect/gccExtensions.x64.txt

    r857a1c6 rc8a0210  
    339339
    340340    {
    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)) /* ?{} */);
     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)) /* ?{} */);
    343343    }
    344344
  • tests/.expect/gccExtensions.x86.txt

    r857a1c6 rc8a0210  
    317317
    318318    {
    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)) /* ?{} */);
     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)) /* ?{} */);
    321321    }
    322322
  • tests/.expect/math.nast.arm64.txt

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

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

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

    r857a1c6 rc8a0210  
    55
    66thread Server {
    7         int cnt, iteration;
     7        int pending, done, iteration;
    88        multi_future(int) * request;
    99};
    1010
    1111void ?{}( Server & this ) {
    12         this.cnt = 0;
     12        ((thread&)this){"Server Thread"};
     13        this.pending = 0;
     14        this.done = 0;
    1315        this.iteration = 0;
    1416        this.request = 0p;
     
    1618
    1719void ^?{}( Server & mutex this ) {
    18         assert(this.cnt == 0);
    19     this.request = 0p;
     20        assert(this.pending == 0);
     21        this.request = 0p;
    2022}
    2123
     
    2426}
    2527
    26 void process( Server & mutex this ) {
    27         fulfil( *this.request, this.iteration );
    28         this.iteration++;
     28void call( Server & mutex this ) {
     29        this.pending++;
    2930}
    3031
    31 void call( Server & mutex this ) {
    32         this.cnt++;
     32void finish( Server & mutex this ) {
     33        this.done++;
    3334}
    3435
    35 void finish( Server & mutex this ) { }
    36 
    3736void main( Server & this ) {
     37        MAIN_LOOP:
    3838        for() {
    3939                waitfor( ^?{} : this ) {
    4040                        break;
    4141                }
    42                 or when( this.cnt < NFUTURES ) waitfor( call: this ) {
    43                         if (this.cnt == NFUTURES) {
    44                                 process(this);
     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 );
    4551                        }
    46                 }
    47                 or waitfor( finish: this ) {
    48                         if (this.cnt == NFUTURES) {
    49                                 reset( *this.request );
    50                                 this.cnt = 0;
    51                         }
     52
     53                        reset( *this.request );
     54                        this.done = 0;
    5255                }
    5356        }
     
    5760Server * the_server;
    5861thread Worker {};
     62void ?{}(Worker & this) {
     63        ((thread&)this){"Worker Thread"};
     64}
     65
    5966multi_future(int) * shared_future;
    6067
  • tests/concurrent/spinaphore.cfa

    r857a1c6 rc8a0210  
    4949void main(Unblocker & this) {
    5050        this.sum = 0;
    51         unsigned me = (unsigned)&this;
     51        unsigned me = (unsigned)(uintptr_t)&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)b;
     56                this.sum += (unsigned)(uintptr_t)b;
    5757                unpark(t);
    5858                yield(random(10));
     
    7373                for(i;num_blockers) {
    7474                        for(num_blocks)
    75                                 usum += (unsigned)&blockers[i];
     75                                usum += (unsigned)(uintptr_t)&blockers[i];
    7676                }
    7777
    7878                for(i;num_unblockers) {
    7979                        for(num_unblocks)
    80                                 bsum += (unsigned)&unblockers[i];
     80                                bsum += (unsigned)(uintptr_t)&unblockers[i];
    8181                }
    8282
  • tests/errors/.expect/completeType.nast.arm64.txt

    r857a1c6 rc8a0210  
    1212      Application of
    1313        Variable Expression: *?: forall
    14           DT: data type
     14          instance of type DT (not function type)
    1515          function
    1616        ... with parameters
     
    2121        ... with resolved type:
    2222          pointer to forall
    23             [unbound]:data type
     23            instance of type [unbound] (not function 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 A without body
     32        ... with resolved type:
     33          pointer to instance of struct A without body
     34
     35      ... with resolved type:
     36        reference to instance of struct A without body
     37    ... to: nothing
     38    ... with resolved type:
     39      void
     40  (types:
     41    void
     42  )
     43  Environment:([unbound]DT) -> instance of struct A without body (no widening)
     44
     45
     46Cost ( 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)
    2459            function
    2560          ... with parameters
     
    4176    void
    4277  )
    43   Environment:([unbound]) -> instance of struct B with 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           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
    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 A without body
    67         ... with resolved type:
    68           pointer to instance of struct A without body
    69 
    70       ... with resolved type:
    71         reference to instance of struct A without body
    72     ... to: nothing
    73     ... with resolved type:
    74       void
    75   (types:
    76     void
    77   )
    78   Environment:([unbound]) -> instance of struct A without body (no widening)
     78  Environment:([unbound]DT) -> instance of struct B with body (no widening)
    7979
    8080
     
    113113Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
    114114            Variable Expression: baz: forall
    115               T: sized data type
    116               ... with assertions
    117                 ?=?: pointer to function
     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
    118126                ... with parameters
    119127                  reference to instance of type T (not function type)
     
    122130                  instance of type T (not function type)
    123131
    124                 ?{}: pointer to function
    125                 ... with parameters
    126                   reference to instance of type T (not function type)
    127                 ... returning nothing
    128 
    129                 ?{}: pointer to function
    130                 ... with parameters
    131                   reference to instance of type T (not function type)
    132                   instance of type T (not function type)
    133                 ... returning nothing
    134 
    135                 ^?{}: pointer to function
    136                 ... with parameters
    137                   reference to instance of type T (not function type)
    138                 ... returning nothing
    139 
     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
     139                ... with parameters
     140                  reference to instance of type T (not function type)
     141                ... returning nothing
     142
     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
     151                ... with parameters
     152                  reference to instance of type T (not function type)
     153                  instance of type T (not function type)
     154                ... returning nothing
     155
     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
     163                ... with parameters
     164                  reference to instance of type T (not function type)
     165                ... returning nothing
    140166
    141167              function
     
    146172            ... with resolved type:
    147173              pointer to forall
    148                 [unbound]:sized data type
    149                 ... with assertions
    150                   ?=?: pointer to function
     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
    151185                  ... with parameters
    152186                    reference to instance of type [unbound] (not function type)
     
    155189                    instance of type [unbound] (not function type)
    156190
    157                   ?{}: pointer to function
     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
    158198                  ... with parameters
    159199                    reference to instance of type [unbound] (not function type)
    160200                  ... returning nothing
    161201
    162                   ?{}: pointer to function
     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
    163210                  ... with parameters
    164211                    reference to instance of type [unbound] (not function type)
     
    166213                  ... returning nothing
    167214
    168                   ^?{}: pointer to function
     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
    169222                  ... with parameters
    170223                    reference to instance of type [unbound] (not function type)
    171224                  ... returning nothing
    172 
    173225
    174226                function
     
    188240          void
    189241        )
    190         Environment:([unbound]) -> instance of type T (not function type) (no widening)
     242        Environment:([unbound]T) -> instance of type T (not function type) (no widening)
    191243
    192244      Could not satisfy assertion:
    193 ?=?: pointer to function
     245Variable Expression: ?=?: pointer to function
    194246        ... with parameters
    195           reference to instance of type [unbound] (not function type)
    196           instance of type [unbound] (not function type)
     247          reference to instance of type T (not function type)
     248          instance of type T (not function type)
    197249        ... returning
    198           instance of type [unbound] (not function type)
    199 
     250          instance of type T (not function type)
     251
     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

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

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

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

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

    r857a1c6 rc8a0210  
    44#include <exception.hfa>
    55
    6 TRIVIAL_EXCEPTION(internal_error);
     6EHM_EXCEPTION(internal_error)();
     7EHM_VIRTUAL_TABLE(internal_error, internal_vt);
    78
    89coroutine WillCancel {};
     
    1415void main(WillCancel & wc) {
    1516        printf("1");
    16         cancel_stack((internal_error){});
     17        cancel_stack((internal_error){&internal_vt});
    1718        printf("!");
    1819}
     
    2425                resume(cancel);
    2526                printf("4");
    26         } catchResume (CoroutineCancelled(WillCancel) * error) {
     27        } catchResume (SomeCoroutineCancelled * error) {
    2728                printf("2");
    2829                if ((virtual internal_error *)error->the_exception) {
  • tests/exceptions/cancel/thread.cfa

    r857a1c6 rc8a0210  
    44#include <exception.hfa>
    55
    6 TRIVIAL_EXCEPTION(internal_error);
     6EHM_EXCEPTION(internal_error)();
     7EHM_VIRTUAL_TABLE(internal_error, internal_vt);
    78
    89thread WillCancel {};
     
    1415void main(WillCancel &) {
    1516        printf("1");
    16         cancel_stack((internal_error){});
     17        cancel_stack((internal_error){&internal_vt});
    1718        printf("!");
    1819}
     
    2526                join(cancel);
    2627                printf("4");
    27         } catchResume (ThreadCancelled(WillCancel) * error) {
     28        } catchResume (SomeThreadCancelled * error) {
    2829                printf("2");
    2930                if ((virtual internal_error *)error->the_exception) {
     
    4243                }
    4344                printf("4");
    44         } catchResume (ThreadCancelled(WillCancel) * error) {
     45        } catchResume (SomeThreadCancelled * error) {
    4546                printf("2");
    4647                if ((virtual internal_error *)error->the_exception) {
  • tests/exceptions/conditional.cfa

    r857a1c6 rc8a0210  
    66#include <exception.hfa>
    77
    8 VTABLE_DECLARATION(num_error)(
    9         int (*code)(num_error *this);
     8EHM_EXCEPTION(num_error)(
     9        int num;
    1010);
    1111
    12 struct num_error {
    13         VTABLE_FIELD(num_error);
    14     char * msg;
    15     int num;
    16 };
    17 
    18 const 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 }
    27 void ?{}(num_error & this, int num) {
    28         VTABLE_INIT(this, num_error);
    29     this.msg = 0;
    30     this.num = num;
    31 }
    32 void ?{}(num_error & this, num_error & other) {
    33     this.virtual_table = other.virtual_table;
    34     this.msg = 0;
    35     this.num = other.num;
    36 }
    37 void ^?{}(num_error & this) {
    38     if( this.msg ) free( this.msg );
    39 }
    40 int num_error_code( num_error * this ) {
    41     return this->num;
    42 }
    43 
    44 VTABLE_INSTANCE(num_error)(
    45         num_error_msg,
    46         num_error_code,
    47 );
     12EHM_VIRTUAL_TABLE(num_error, num_error_vt);
    4813
    4914void caught_num_error(int expect, num_error * actual) {
     
    5217
    5318int main(int argc, char * argv[]) {
    54         num_error exc = 2;
     19        num_error exc = {&num_error_vt, 2};
    5520
    5621        try {
    5722                throw exc;
    58         } catch (num_error * error ; 3 == error->virtual_table->code( error )) {
     23        } catch (num_error * error ; 3 == error->num ) {
    5924                caught_num_error(3, error);
    60         } catch (num_error * error ; 2 == error->virtual_table->code( error )) {
     25        } catch (num_error * error ; 2 == error->num ) {
    6126                caught_num_error(2, error);
    6227        }
     
    6429        try {
    6530                throwResume exc;
    66         } catchResume (num_error * error ; 3 == error->virtual_table->code( error )) {
     31        } catchResume (num_error * error ; 3 == error->num ) {
    6732                caught_num_error(3, error);
    68         } catchResume (num_error * error ; 2 == error->virtual_table->code( error )) {
     33        } catchResume (num_error * error ; 2 == error->num ) {
    6934                caught_num_error(2, error);
    7035        }
  • tests/exceptions/data-except.cfa

    r857a1c6 rc8a0210  
    33#include <exception.hfa>
    44
    5 DATA_EXCEPTION(paired)(
     5EHM_EXCEPTION(paired)(
    66        int first;
    77        int second;
    88);
    99
    10 void ?{}(paired & this, int first, int second) {
    11         VTABLE_INIT(this, paired);
    12         this.first = first;
    13         this.second = second;
    14 }
     10EHM_VIRTUAL_TABLE(paired, paired_vt);
    1511
    16 const char * paired_msg(paired * this) {
    17         return "paired";
    18 }
    19 
    20 VTABLE_INSTANCE(paired)(paired_msg);
    21 
    22 void throwPaired(int first, int second) {
    23         paired exc = {first, second};
     12const char * virtual_msg(paired * this) {
     13        return this->virtual_table->msg(this);
    2414}
    2515
    2616int main(int argc, char * argv[]) {
    27         paired except = {3, 13};
     17        paired except = {&paired_vt, 3, 13};
    2818
    2919        try {
    3020                throw except;
    3121        } catch (paired * exc) {
    32                 printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);
     22                printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second);
    3323                ++exc->first;
    3424        }
    3525
    36         printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);
     26        printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second);
    3727
    3828        try {
    3929                throwResume except;
    4030        } catchResume (paired * exc) {
    41                 printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);
     31                printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second);
    4232                ++exc->first;
    4333        }
    4434
    45         printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);
     35        printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second);
    4636}
  • tests/exceptions/defaults.cfa

    r857a1c6 rc8a0210  
    44#include <exception.hfa>
    55
    6 DATA_EXCEPTION(log_message)(
     6EHM_EXCEPTION(log_message)(
    77        char * msg;
    88);
    99
    10 void ?{}(log_message & this, char * msg) {
    11         VTABLE_INIT(this, log_message);
    12         this.msg = msg;
    13 }
    14 
    15 const char * get_log_message(log_message * this) {
     10_EHM_DEFINE_COPY(log_message, )
     11const char * msg(log_message * this) {
    1612        return this->msg;
    1713}
    18 
    19 VTABLE_INSTANCE(log_message)(get_log_message);
     14_EHM_VIRTUAL_TABLE(log_message, , log_vt);
    2015
    2116// Logging messages don't have to be handled.
     
    2823        // We can catch log:
    2924        try {
    30                 throwResume (log_message){"Should be printed.\n"};
     25                throwResume (log_message){&log_vt, "Should be printed.\n"};
    3126        } catchResume (log_message * this) {
    3227                printf("%s", this->virtual_table->msg(this));
    3328        }
    3429        // But we don't have to:
    35         throwResume (log_message){"Should not be printed.\n"};
     30        throwResume (log_message){&log_vt, "Should not be printed.\n"};
    3631}
    3732
    3833// I don't have a good use case for doing the same with termination.
    39 TRIVIAL_EXCEPTION(jump);
     34EHM_EXCEPTION(jump)();
    4035void defaultTerminationHandler(jump &) {
    4136        printf("jump default handler.\n");
    4237}
    4338
     39EHM_VIRTUAL_TABLE(jump, jump_vt);
     40
    4441void jump_test(void) {
    4542        try {
    46                 throw (jump){};
     43                throw (jump){&jump_vt};
    4744        } catch (jump * this) {
    4845                printf("jump catch handler.\n");
    4946        }
    50         throw (jump){};
     47        throw (jump){&jump_vt};
    5148}
    5249
    53 TRIVIAL_EXCEPTION(first);
    54 TRIVIAL_EXCEPTION(unhandled_exception);
     50EHM_EXCEPTION(first)();
     51EHM_VIRTUAL_TABLE(first, first_vt);
     52
     53EHM_EXCEPTION(unhandled_exception)();
     54EHM_VIRTUAL_TABLE(unhandled_exception, unhandled_vt);
    5555
    5656void unhandled_test(void) {
    5757        forall(T &, V & | is_exception(T, V))
    5858        void defaultTerminationHandler(T &) {
    59                 throw (unhandled_exception){};
     59                throw (unhandled_exception){&unhandled_vt};
    6060        }
    6161        void defaultTerminationHandler(unhandled_exception &) {
     
    6363        }
    6464        try {
    65                 throw (first){};
     65                throw (first){&first_vt};
    6666        } catch (unhandled_exception * t) {
    6767                printf("Catch unhandled_exception.\n");
     
    6969}
    7070
    71 TRIVIAL_EXCEPTION(second);
     71EHM_EXCEPTION(second)();
     72EHM_VIRTUAL_TABLE(second, second_vt);
    7273
    7374void cross_test(void) {
    7475        void defaultTerminationHandler(first &) {
    7576                printf("cross terminate default\n");
    76                 throw (second){};
     77                throw (second){&second_vt};
    7778        }
    7879        void defaultResumptionHandler(first &) {
    7980                printf("cross resume default\n");
    80                 throwResume (second){};
     81                throwResume (second){&second_vt};
    8182        }
    8283        try {
    8384                printf("cross terminate throw\n");
    84                 throw (first){};
     85                throw (first){&first_vt};
    8586        } catch (second *) {
    8687                printf("cross terminate catch\n");
     
    8889        try {
    8990                printf("cross resume throw\n");
    90                 throwResume (first){};
     91                throwResume (first){&first_vt};
    9192        } catchResume (second *) {
    9293                printf("cross resume catch\n");
  • tests/exceptions/finally.cfa

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

    r857a1c6 rc8a0210  
    44#include "except-io.hfa"
    55
    6 TRIVIAL_EXCEPTION(star);
    7 TRIVIAL_EXCEPTION(moon);
     6EHM_EXCEPTION(star)();
     7EHM_EXCEPTION(moon)();
     8
     9EHM_VIRTUAL_TABLE(star, star_vt);
     10EHM_VIRTUAL_TABLE(moon, moon_vt);
    811
    912int main(int argc, char * argv[]) {
    1013        // Resume falls back to terminate.
    1114        try {
    12                 throwResume (star){};
     15                throwResume (star){&star_vt};
    1316        } catch (star *) {
    1417                printf("caught as termination\n");
     
    1720        try {
    1821                loud_region a = "try block with resume throw";
    19                 throwResume (star){};
     22                throwResume (star){&star_vt};
    2023        } catch (star *) {
    2124                printf("caught as termination\n");
     
    2932        try {
    3033                try {
    31                         throw (star){};
     34                        throw (star){&star_vt};
    3235                } catchResume (star *) {
    3336                        printf("resume catch on terminate\n");
     
    4346        try {
    4447                try {
    45                         throwResume (star){};
     48                        throwResume (star){&star_vt};
    4649                } catch (star *) {
    4750                        printf("terminate catch on resume\n");
     
    5861                try {
    5962                        try {
    60                                 throw (star){};
     63                                throw (star){&star_vt};
    6164                        } catchResume (star *) {
    6265                                printf("inner resume catch (error)\n");
     
    7578                try {
    7679                        try {
    77                                 throwResume (star){};
     80                                throwResume (star){&star_vt};
    7881                        } catch (star *) {
    7982                                printf("inner termination catch\n");
     
    9497                                try {
    9598                                        printf("throwing resume moon\n");
    96                                         throwResume (moon){};
     99                                        throwResume (moon){&moon_vt};
    97100                                } catch (star *) {
    98101                                        printf("termination catch\n");
    99102                                }
    100103                                printf("throwing resume star\n");
    101                                 throwResume (star){};
     104                                throwResume (star){&star_vt};
    102105                        } catchResume (star *) {
    103106                                printf("resumption star catch\n");
     
    105108                } catchResume (moon *) {
    106109                        printf("resumption moon catch, will terminate\n");
    107                         throw (star){};
     110                        throw (star){&star_vt};
    108111                }
    109112        } catchResume (star *) {
  • tests/exceptions/polymorphic.cfa

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

    r857a1c6 rc8a0210  
    44#include "except-io.hfa"
    55
    6 TRIVIAL_EXCEPTION(yin);
    7 TRIVIAL_EXCEPTION(yang);
    8 TRIVIAL_EXCEPTION(zen);
    9 TRIVIAL_EXCEPTION(moment_of, zen);
     6EHM_EXCEPTION(yin)();
     7EHM_EXCEPTION(yang)();
     8EHM_EXCEPTION(zen)();
     9
     10EHM_VIRTUAL_TABLE(yin, yin_vt);
     11EHM_VIRTUAL_TABLE(yang, yang_vt);
     12EHM_VIRTUAL_TABLE(zen, zen_vt);
    1013
    1114void in_void(void);
    1215
    1316int main(int argc, char * argv[]) {
     17        yin a_yin = {&yin_vt};
     18        yang a_yang = {&yang_vt};
     19        zen a_zen = {&zen_vt};
     20
    1421        // The simple throw catchResume test.
    1522        try {
    1623                loud_exit a = "simple try clause";
    1724                printf("simple throw\n");
    18                 throwResume (zen){};
     25                throwResume a_zen;
    1926                printf("end of try clause\n");
    2027        } catchResume (zen * error) {
     
    2633        // Throw catch-all test.
    2734        try {
    28                 throwResume (zen){};
     35                throwResume a_zen;
    2936        } catchResume (exception_t * error) {
    3037                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");
    4238        }
    4339        printf("\n");
     
    4642        try {
    4743                try {
    48                         throwResume (yin){};
     44                        throwResume a_yin;
    4945                } catchResume (zen *) {
    5046                        printf("caught yin as zen\n");
     
    6258                        loud_exit a = "rethrow inner try";
    6359                        printf("rethrow inner try\n");
    64                         throwResume (zen){};
     60                        throwResume a_zen;
    6561                } catchResume (zen *) {
    6662                        loud_exit a = "rethrowing catch clause";
     
    7773        try {
    7874                try {
    79                         throwResume (yin){};
     75                        throwResume a_yin;
    8076                } catchResume (yin *) {
    8177                        printf("caught yin, will throw yang\n");
    82                         throwResume (yang){};
     78                        throwResume a_yang;
    8379                } catchResume (yang *) {
    8480                        printf("caught exception from same try\n");
     
    9389                try {
    9490                        printf("throwing first exception\n");
    95                         throwResume (yin){};
     91                        throwResume a_yin;
    9692                } catchResume (yin *) {
    9793                        printf("caught first exception\n");
    9894                        try {
    9995                                printf("throwing second exception\n");
    100                                 throwResume (yang){};
     96                                throwResume a_yang;
    10197                        } catchResume (yang *) {
    10298                                printf("caught second exception\n");
     
    114110        try {
    115111                try {
    116                         throwResume (zen){};
    117                         throwResume (zen){};
     112                        throwResume a_zen;
     113                        throwResume a_zen;
    118114                } catchResume (zen *) {
    119115                        printf("inner catch\n");
    120116                }
    121                 throwResume (zen){};
     117                throwResume a_zen;
    122118        } catchResume (zen *) {
    123119                printf("outer catch\n");
     
    130126// Do a throw and rethrow in a void function.
    131127void in_void(void) {
     128    zen a_zen = {&zen_vt};
    132129        try {
    133130                try {
    134131                        printf("throw\n");
    135                         throwResume (zen){};
     132                        throwResume a_zen;
    136133                } catchResume (zen *) {
    137134                        printf("rethrow\n");
  • tests/exceptions/terminate.cfa

    r857a1c6 rc8a0210  
    44#include "except-io.hfa"
    55
    6 TRIVIAL_EXCEPTION(yin);
    7 TRIVIAL_EXCEPTION(yang);
    8 TRIVIAL_EXCEPTION(zen);
    9 TRIVIAL_EXCEPTION(moment_of, zen);
     6EHM_EXCEPTION(yin)();
     7EHM_EXCEPTION(yang)();
     8EHM_EXCEPTION(zen)();
     9
     10EHM_VIRTUAL_TABLE(yin, yin_vt);
     11EHM_VIRTUAL_TABLE(yang, yang_vt);
     12EHM_VIRTUAL_TABLE(zen, zen_vt);
    1013
    1114void in_void(void);
    1215
    1316int main(int argc, char * argv[]) {
     17        yin a_yin = {&yin_vt};
     18        yang a_yang = {&yang_vt};
     19        zen a_zen = {&zen_vt};
     20
    1421        // The simple throw catch test.
    1522        try {
    1623                loud_exit a = "simple try clause";
    1724                printf("simple throw\n");
    18                 throw (zen){};
     25                throw a_zen;
    1926                printf("end of try clause\n");
    2027        } catch (zen * error) {
     
    2633        // Throw catch-all test.
    2734        try {
    28                 throw (zen){};
     35                throw a_zen;
    2936        } catch (exception_t * error) {
    3037                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");
    4238        }
    4339        printf("\n");
     
    4642        try {
    4743                try {
    48                         throw (yin){};
     44                        throw a_yin;
    4945                } catch (zen *) {
    5046                        printf("caught yin as zen\n");
     
    6258                        loud_exit a = "rethrow inner try";
    6359                        printf("rethrow inner try\n");
    64                         throw (zen){};
     60                        throw a_zen;
    6561                } catch (zen *) {
    6662                        loud_exit a = "rethrowing catch clause";
     
    7773        try {
    7874                try {
    79                         throw (yin){};
     75                        throw a_yin;
    8076                } catch (yin *) {
    8177                        printf("caught yin, will throw yang\n");
    82                         throw (yang){};
     78                        throw a_yang;
    8379                } catch (yang *) {
    8480                        printf("caught exception from same try\n");
     
    9389                try {
    9490                        printf("throwing first exception\n");
    95                         throw (yin){};
     91                        throw a_yin;
    9692                } catch (yin *) {
    9793                        printf("caught first exception\n");
    9894                        try {
    9995                                printf("throwing second exception\n");
    100                                 throw (yang){};
     96                                throw a_yang;
    10197                        } catch (yang *) {
    10298                                printf("caught second exception\n");
     
    114110        try {
    115111                try {
    116                         throw (zen){};
    117                         throw (zen){};
     112                        throw a_zen;
     113                        throw a_zen;
    118114                } catch (zen *) {
    119115                        printf("inner catch\n");
    120116                }
    121                 throw (zen){};
     117                throw a_zen;
    122118        } catch (zen *) {
    123119                printf("outer catch\n");
     
    130126// Do a throw and rethrow in a void function.
    131127void in_void(void) {
     128        zen a_zen = {&zen_vt};
    132129        try {
    133130                try {
    134131                        printf("throw\n");
    135                         throw (zen){};
     132                        throw a_zen;
    136133                } catch (zen *) {
    137134                        printf("rethrow\n");
  • tests/exceptions/trash.cfa

    r857a1c6 rc8a0210  
    33#include <exception.hfa>
    44
    5 TRIVIAL_EXCEPTION(yin);
    6 TRIVIAL_EXCEPTION(yang);
     5EHM_EXCEPTION(yin)();
     6EHM_EXCEPTION(yang)();
     7
     8EHM_VIRTUAL_TABLE(yin, yin_vt);
     9EHM_VIRTUAL_TABLE(yang, yang_vt);
    710
    811int main(int argc, char * argv[]) {
    912        try {
    1013                try {
    11                         throw (yin){};
     14                        throw (yin){&yin_vt};
    1215                } finally {
    1316                        try {
    14                                 throw (yang){};
     17                                throw (yang){&yang_vt};
    1518                        } catch (yin *) {
    1619                                printf("inner yin\n");
  • tests/exceptions/type-check.cfa

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

    r857a1c6 rc8a0210  
    1212#include <assert.h>
    1313
     14
     15
     16// Hand defined alpha virtual type:
     17struct __cfatid_struct_alpha {
     18        __cfa__parent_vtable const * parent;
     19};
     20
     21__attribute__(( section(".gnu.linkonce.__cfatid_alpha") ))
     22struct __cfatid_struct_alpha __cfatid_alpha = {
     23        (__cfa__parent_vtable *)0,
     24};
     25
    1426struct alpha_vtable {
    15         alpha_vtable const * const parent;
     27        struct __cfatid_struct_alpha const * const __cfavir_typeid;
    1628        char (*code)(void);
    1729};
     
    2739
    2840
     41// Hand defined beta virtual type:
     42struct __cfatid_struct_beta {
     43        __cfatid_struct_alpha const * parent;
     44};
     45
     46__attribute__(( section(".gnu.linkonce.__cfatid_beta") ))
     47struct __cfatid_struct_beta __cfatid_beta = {
     48        &__cfatid_alpha,
     49};
     50
    2951struct beta_vtable {
    30         alpha_vtable const * const parent;
     52        struct __cfatid_struct_beta const * const __cfavir_typeid;
    3153        char (*code)(void);
    3254};
     
    4264
    4365
     66// Hand defined gamma virtual type:
     67struct __cfatid_struct_gamma {
     68        __cfatid_struct_beta const * parent;
     69};
     70
     71__attribute__(( section(".gnu.linkonce.__cfatid_gamma") ))
     72struct __cfatid_struct_gamma __cfatid_gamma = {
     73        &__cfatid_beta,
     74};
     75
    4476struct gamma_vtable {
    45         beta_vtable const * const parent;
     77        struct __cfatid_struct_gamma const * const __cfavir_typeid;
    4678        char (*code)(void);
    4779};
     
    5789
    5890extern "C" {
    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 };
     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 };
    6294}
    6395
  • tests/exceptions/virtual-poly.cfa

    r857a1c6 rc8a0210  
    88#include <assert.h>
    99
     10
     11struct __cfatid_struct_mono_base {
     12    __cfa__parent_vtable const * parent;
     13};
     14
     15__attribute__(( section(".gnu.linkonce.__cfatid_mono_base") ))
     16struct __cfatid_struct_mono_base __cfatid_mono_base = {
     17    (__cfa__parent_vtable *)0,
     18};
     19
    1020struct mono_base_vtable {
    11         mono_base_vtable const * const parent;
     21        __cfatid_struct_mono_base const * const __cfavir_typeid;
    1222};
    1323
     
    1727
    1828forall(T)
     29struct __cfatid_struct_mono_child {
     30    __cfatid_struct_mono_base const * parent;
     31};
     32
     33forall(T)
    1934struct mono_child_vtable {
    20         mono_base_vtable const * const parent;
     35        __cfatid_struct_mono_child(T) const * const __cfavir_typeid;
    2136};
    2237
     
    2641};
    2742
    28 mono_base_vtable _mono_base_vtable_instance @= { 0 };
     43__cfatid_struct_mono_child(int) __cfatid_mono_child @= {
     44        &__cfatid_mono_base,
     45};
     46
    2947mono_child_vtable(int) _mono_child_vtable_instance @= {
    30         &_mono_base_vtable_instance
     48        &__cfatid_mono_child,
    3149};
    3250
     
    3755}
    3856
     57
     58forall(U)
     59struct __cfatid_struct_poly_base {
     60    __cfa__parent_vtable const * parent;
     61};
     62
    3963forall(U)
    4064struct poly_base_vtable {
    41         poly_base_vtable(U) const * const parent;
     65        __cfatid_struct_poly_base(U) const * const __cfavir_typeid;
    4266};
    4367
     
    4872
    4973forall(V)
     74struct __cfatid_struct_poly_child {
     75    __cfatid_struct_poly_base(V) const * parent;
     76};
     77
     78forall(V)
    5079struct poly_child_vtable {
    51         poly_base_vtable(V) const * const parent;
     80        __cfatid_struct_poly_child(V) const * const __cfavir_typeid;
    5281};
    5382
     
    5786};
    5887
    59 poly_base_vtable(int) _poly_base_vtable_instance @= { 0 };
     88__cfatid_struct_poly_base(int) __cfatid_poly_base @= {
     89        (__cfa__parent_vtable *)0,
     90};
     91__cfatid_struct_poly_child(int) __cfatid_poly_child = {
     92    &__cfatid_poly_base,
     93};
    6094poly_child_vtable(int) _poly_child_vtable_instance @= {
    61         &_poly_base_vtable_instance
     95        &__cfatid_poly_child,
    6296};
    63 /* Resolver bug keeps me from adding these.
    64 poly_base_vtable(char) _poly_base_vtable_instance @= { 0 };
    65 poly_child_vtable(char) _poly_child_vtable_instance @= {
    66         &_poly_base_vtable_instance
    67 };
    68 */
    6997
    7098void poly_poly_test() {
     
    77105        mono_poly_test();
    78106        poly_poly_test();
    79         printf( "done\n" );                             // non-empty .expect file
     107        printf( "done\n" );
    80108}
  • tests/io/.expect/manipulatorsOutput1.arm64.txt

    r857a1c6 rc8a0210  
    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.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
     310.       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
    3232double
    33 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
    34 0. 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
     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
     340.       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
    3535long double
    36 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
    37 0. 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
     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
     370.       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
    3838
    3939char
  • tests/io/.expect/manipulatorsOutput1.x64.txt

    r857a1c6 rc8a0210  
    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.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
     310.       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
    3232double
    33 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
    34 0. 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
     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
     340.       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
    3535long double
    36 3.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
    37 0. 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
     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
     370.       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
    3838
    3939char
  • tests/io/.expect/manipulatorsOutput1.x86.txt

    r857a1c6 rc8a0210  
    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.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
     310.       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
    3232double
    33 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
    34 0. 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
     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
     340.       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
    3535long double
    36 3.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
    37 0. 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
     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
     370.       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
    3838
    3939char
  • tests/io/.expect/manipulatorsOutput2.arm64.txt

    r857a1c6 rc8a0210  
    99-0x1.b8p+4 -0x1.b8p+4 -0x1.b8p+4
    10100.000000e+00 2.750000e+01 -2.750000e+01
     110e0 27.5e0 -27.5e0
    11120B11011 0X1B 2.75E-09 0X1.B8P+4
    121311011 33 1b
    13140. 0 27. 27 27.5
    14 +27 -27 +27 -27 +27.5 -27.5
     15+27 -27 +27. -27. +27.5 -27.5
    1516  34  34 34
    16   4.000000  4.000000 4.000000
     17        4.        4.       4.
    1718  ab  ab ab
    181934567 34567 34567
    19 3456.000000 3456.000000 3456.000000
     203456. 3456. 3456.
    2021abcde abcde abcde
    2122 034     0034 0000000034
     
    242527.500     27.5      28. 27.50000000
    252627.000 27.500     27.5      28. 27.50000000
    26 27   27.000000  27.500000  027  27.500   
     2727   27.        27.5       027  27.500   
    2728234.567 234.57  234.6   235.
    2829234567. 2.3457e+05 2.346e+05 2.35e+05
  • tests/io/.expect/manipulatorsOutput2.x64.txt

    r857a1c6 rc8a0210  
    99-0x1.b8p+4 -0x1.b8p+4 -0xd.cp+1
    10100.000000e+00 2.750000e+01 -2.750000e+01
     110e0 27.5e0 -27.5e0
    11120B11011 0X1B 2.75E-09 0X1.B8P+4
    121311011 33 1b
    13140. 0 27. 27 27.5
    14 +27 -27 +27 -27 +27.5 -27.5
     15+27 -27 +27. -27. +27.5 -27.5
    1516  34  34 34
    16   4.000000  4.000000 4.000000
     17        4.        4.       4.
    1718  ab  ab ab
    181934567 34567 34567
    19 3456.000000 3456.000000 3456.000000
     203456. 3456. 3456.
    2021abcde abcde abcde
    2122 034     0034 0000000034
     
    242527.500     27.5      28. 27.50000000
    252627.000 27.500     27.5      28. 27.50000000
    26 27   27.000000  27.500000  027  27.500   
     2727   27.        27.5       027  27.500   
    2728234.567 234.57  234.6   235.
    2829234567. 2.3457e+05 2.346e+05 2.35e+05
  • tests/io/.expect/manipulatorsOutput2.x86.txt

    r857a1c6 rc8a0210  
    99-0x1.b8p+4 -0x1.b8p+4 -0xd.cp+1
    10100.000000e+00 2.750000e+01 -2.750000e+01
     110e2147483646 27.5e0 -27.5e0
    11120B11011 0X1B 2.75E-09 0X1.B8P+4
    121311011 33 1b
    13140. 0 27. 27 27.5
    14 +27 -27 +27 -27 +27.5 -27.5
     15+27 -27 +27. -27. +27.5 -27.5
    1516  34  34 34
    16   4.000000  4.000000 4.000000
     17        4.        4.       4.
    1718  ab  ab ab
    181934567 34567 34567
    19 3456.000000 3456.000000 3456.000000
     203456. 3456. 3456.
    2021abcde abcde abcde
    2122 034     0034 0000000034
     
    242527.500     27.5      28. 27.50000000
    252627.000 27.500     27.5      28. 27.50000000
    26 27   27.000000  27.500000  027  27.500   
     2727   27.        27.5       027  27.500   
    2728234.567 234.57  234.6   235.
    2829234567. 2.3457e+05 2.346e+05 2.35e+05
  • tests/io/manipulatorsOutput1.cfa

    r857a1c6 rc8a0210  
    77// Created On       : Sat Jun  8 18:04:11 2019
    88// Last Modified By : Peter A. Buhr
    9 // Last Modified On : Fri May  1 11:51:44 2020
    10 // Update Count     : 9
     9// Last Modified On : Sat Apr 10 08:42:15 2021
     10// Update Count     : 18
    1111//
    1212
     
    8585        sout | "double";
    8686        double d = 3.537;
    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));
     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)));
    9192
    9293        sout | "long double";
    9394        long double ld = 3.537;
    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 
     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)));
    99100
    100101        sout | nl | "char";
     
    117118// Local Variables: //
    118119// tab-width: 4 //
    119 // compile-command: "cfa -Wall -Wextra amanipulatorsOutput1.cfa" //
     120// compile-command: "cfa -Wall -Wextra manipulatorsOutput1.cfa" //
    120121// End: //
  • tests/io/manipulatorsOutput2.cfa

    r857a1c6 rc8a0210  
    77// Created On       : Sat Jun  8 18:04:11 2019
    88// Last Modified By : Peter A. Buhr
    9 // Last Modified On : Sun Nov 15 08:11:53 2020
    10 // Update Count     : 9
     9// Last Modified On : Sat Apr 10 09:16:09 2021
     10// Update Count     : 11
    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);
    2627        sout | upcase(bin(27)) | upcase(hex(27)) | upcase(27.5e-10) | upcase(hex(27.5));
    2728        sout | nobase(bin(27)) | nobase(oct(27)) | nobase(hex(27));
  • tests/io/manipulatorsOutput3.cfa

    r857a1c6 rc8a0210  
     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
    113#include <fstream.hfa>
    214
  • tests/linking/exception-nothreads.cfa

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

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

    r857a1c6 rc8a0210  
    1010// Created On       : Fri Apr 22 14:59:21 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 20 18:00:48 2021
    13 // Update Count     : 115
     12// Last Modified On : Tue Apr 13 21:04:48 2021
     13// Update Count     : 123
    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__
    7177        sout | "log2:" | log2( 8.0F ) | log2( 8.0D ) | log2( 8.0L );
    7278        sout | "log10:" | log10( 100.0F ) | log10( 100.0D ) | log10( 100.0L );
  • tests/meta/.expect/archVast.nast.arm64.txt

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

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

    r857a1c6 rc8a0210  
    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

    r857a1c6 rc8a0210  
    2323gdb.execute('handle SIGUSR1 nostop noprint pass')
    2424
    25 CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state')
     25CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state yield_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'))
     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'))
    5859
    5960def get_addr(addr):
     
    371372        def print_thread(self, thread, tid, marked):
    372373                cfa_t = get_cfa_types()
    373                 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread))
     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))
    374387
    375388        def print_threads_by_cluster(self, cluster, print_system = False):
     
    480493                context = thread['context']
    481494
     495
     496
     497                # must be at frame 0 to set pc register
     498                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
    482505                # lookup for sp,fp and uSwitch
    483                 xsp = context['SP'] + 48
     506                xsp = context['SP'] + 40 # 40 = 5 64bit registers : %r15, %r14, %r13, %r12, %rbx WARNING: x64 specific
    484507                xfp = context['FP']
    485508
    486509                # convert string so we can strip out the address
    487510                try:
    488                         xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address + 28)
     511                        xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address)
    489512                except:
    490513                        print("here")
    491514                        return
    492 
    493                 # must be at frame 0 to set pc register
    494                 gdb.execute('select-frame 0')
    495515
    496516                # push sp, fp, pc into a global stack
     
    503523
    504524                # update registers for new task
    505                 print('switching to ')
     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()))
    506527                gdb.execute('set $rsp={}'.format(xsp))
    507528                gdb.execute('set $rbp={}'.format(xfp))
     
    552573
    553574                argv = parse(arg)
    554                 print(argv)
    555575                if argv[0].isdigit():
    556576                        cname = " ".join(argv[1:]) if len(argv) > 1 else None
Note: See TracChangeset for help on using the changeset viewer.