Changes in / [feacef9:5407cdc]


Ignore:
Files:
110 added
49 deleted
183 edited

Legend:

Unmodified
Added
Removed
  • Jenkins/FullBuild

    rfeacef9 r5407cdc  
    1818
    1919                                parallel (
    20                                         gcc_8_x86_old: { trigger_build( 'gcc-8',   'x86', false ) },
    21                                         gcc_7_x86_old: { trigger_build( 'gcc-7',   'x86', false ) },
    22                                         gcc_6_x86_old: { trigger_build( 'gcc-6',   'x86', false ) },
    23                                         gcc_9_x64_old: { trigger_build( 'gcc-9',   'x64', false ) },
    24                                         gcc_8_x64_old: { trigger_build( 'gcc-8',   'x64', false ) },
    25                                         gcc_7_x64_old: { trigger_build( 'gcc-7',   'x64', false ) },
    26                                         gcc_6_x64_old: { trigger_build( 'gcc-6',   'x64', false ) },
    27                                         gcc_5_x64_old: { trigger_build( 'gcc-5',   'x64', false ) },
     20                                        gcc_8_x86_new: { trigger_build( 'gcc-8',   'x86', true  ) },
     21                                        gcc_7_x86_new: { trigger_build( 'gcc-7',   'x86', true  ) },
     22                                        gcc_6_x86_new: { trigger_build( 'gcc-6',   'x86', true  ) },
     23                                        gcc_9_x64_new: { trigger_build( 'gcc-9',   'x64', true  ) },
     24                                        gcc_8_x64_new: { trigger_build( 'gcc-8',   'x64', true  ) },
     25                                        gcc_7_x64_new: { trigger_build( 'gcc-7',   'x64', true  ) },
     26                                        gcc_6_x64_new: { trigger_build( 'gcc-6',   'x64', true  ) },
     27                                        gcc_5_x64_new: { trigger_build( 'gcc-5',   'x64', true  ) },
     28                                        clang_x64_new: { trigger_build( 'clang',   'x64', true  ) },
    2829                                        clang_x64_old: { trigger_build( 'clang',   'x64', false ) },
    29                                         clang_x64_new: { trigger_build( 'clang',   'x64', true  ) },
    3030                                )
    3131                        }
     
    6666
    6767def trigger_build(String cc, String arch, boolean new_ast) {
     68        // Randomly delay the builds by a random amount to avoid hitting the SC server to hard
     69        sleep(time: 5 * Math.random(), unit:"MINUTES")
     70
     71        // Run the build
     72        // Don't propagate, it doesn't play nice with our email setup
    6873        def result = build job: 'Cforall/master',               \
    6974                parameters: [                                           \
  • Jenkinsfile

    rfeacef9 r5407cdc  
    148148def test() {
    149149        try {
     150                // Print potential limits before testing
     151                // in case jenkins messes with them
     152                sh 'free -h'
     153                sh 'ulimit -a'
     154
    150155                Tools.BuildStage('Test: short', !Settings.RunAllTests) {
    151156                        dir (BuildDir) {
  • benchmark/Makefile.am

    rfeacef9 r5407cdc  
    502502
    503503compile-io$(EXEEXT):
    504         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/io1.cfa
     504        $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/io/io.cfa
    505505
    506506compile-monitor$(EXEEXT):
  • benchmark/basic/ttst_lock.c

    rfeacef9 r5407cdc  
    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

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

    rfeacef9 r5407cdc  
    2020                socklen_t *addrlen;
    2121                int flags;
     22                unsigned cnt;
    2223        } acpt;
    2324
     
    6768thread_local stats_block_t stats;
    6869stats_block_t global_stats;
     70
     71thread_local struct __attribute__((aligned(128))) {
     72        size_t to_submit = 0;
     73} local;
    6974
    7075// Get an array of current connections
     
    192197        static void submit(struct io_uring * ring, struct io_uring_sqe * sqe, connection * conn) {
    193198                (void)ring;
     199                local.to_submit++;
    194200                #ifdef USE_ASYNC
    195201                        io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
     
    406412                switch(state) {
    407413                case ACCEPTING:
    408                         connection::accept(ring, opt);
     414                        // connection::accept(ring, opt);
    409415                        newconn(ring, res);
    410416                        break;
     
    420426
    421427//=========================================================
     428extern "C" {
     429        #include <sys/eventfd.h>  // use for termination
     430}
     431
    422432// Main loop of the WebServer
    423433// Effectively uses one thread_local copy of everything per kernel thread
     
    427437        struct io_uring * ring = opt.ring;
    428438
     439        int blockfd = eventfd(0, 0);
     440        if (blockfd < 0) {
     441                fprintf( stderr, "eventfd create error: (%d) %s\n", (int)errno, strerror(errno) );
     442                exit(EXIT_FAILURE);
     443        }
     444
     445        int ret = io_uring_register_eventfd(ring, blockfd);
     446        if (ret < 0) {
     447                fprintf( stderr, "io_uring S&W error: (%d) %s\n", (int)-ret, strerror(-ret) );
     448                exit(EXIT_FAILURE);
     449        }
     450
    429451        // Track the shutdown using a event_fd
    430452        char endfd_buf[8];
     
    433455        // Accept our first connection
    434456        // May not take effect until io_uring_submit_and_wait
    435         connection::accept(ring, opt);
     457        for(unsigned i = 0; i < opt.acpt.cnt; i++) {
     458                connection::accept(ring, opt);
     459        }
    436460
    437461        int reset = 1;       // Counter to print stats once in a while
     
    441465        while(!done) {
    442466                // Submit all the answers we have and wait for responses
    443                 int ret = io_uring_submit_and_wait(ring, 1);
     467                int ret = io_uring_submit(ring);
     468                local.to_submit = 0;
    444469
    445470                // check errors
     
    452477                sqes += ret;
    453478                call++;
     479
     480
     481                eventfd_t val;
     482                ret = eventfd_read(blockfd, &val);
     483
     484                // check errors
     485                if (ret < 0) {
     486                        fprintf( stderr, "eventfd read error: (%d) %s\n", (int)errno, strerror(errno) );
     487                        exit(EXIT_FAILURE);
     488                }
    454489
    455490                struct io_uring_cqe *cqe;
     
    463498                                break;
    464499                        }
     500
     501                        if(local.to_submit > 30) break;
    465502
    466503                        auto req = (class connection *)cqe->user_data;
     
    509546        #include <pthread.h>      // for pthreads
    510547        #include <signal.h>       // for signal(SIGPIPE, SIG_IGN);
    511         #include <sys/eventfd.h>  // use for termination
    512548        #include <sys/socket.h>   // for sockets in general
    513549        #include <netinet/in.h>   // for sockaddr_in, AF_INET
     
    528564        unsigned entries = 256;     // number of entries per ring/kernel thread
    529565        unsigned backlog = 262144;  // backlog argument to listen
     566        unsigned preaccept = 1;     // start by accepting X per threads
    530567        bool attach = false;        // Whether or not to attach all the rings
    531568        bool sqpoll = false;        // Whether or not to use SQ Polling
     
    534571        // Arguments Parsing
    535572        int c;
    536         while ((c = getopt (argc, argv, "t:p:e:b:aS")) != -1) {
     573        while ((c = getopt (argc, argv, "t:p:e:b:c:aS")) != -1) {
    537574                switch (c)
    538575                {
     
    548585                case 'b':
    549586                        backlog = atoi(optarg);
     587                        break;
     588                case 'c':
     589                        preaccept = atoi(optarg);
    550590                        break;
    551591                case 'a':
     
    681721                thrd_opts[i].acpt.addrlen = (socklen_t*)&addrlen;
    682722                thrd_opts[i].acpt.flags   = 0;
     723                thrd_opts[i].acpt.cnt     = preaccept;
    683724                thrd_opts[i].endfd        = efd;
    684725                thrd_opts[i].ring         = &thrd_rings[i].storage;
  • benchmark/io/http/main.cfa

    rfeacef9 r5407cdc  
    2929
    3030//=============================================================================================
    31 // Globals
    32 //=============================================================================================
    33 struct ServerProc {
    34         processor self;
    35 };
    36 
    37 void ?{}( ServerProc & this ) {
    38         /* paranoid */ assert( options.clopts.instance != 0p );
    39         (this.self){ "Benchmark Processor", *options.clopts.instance };
    40 
    41         #if !defined(__CFA_NO_STATISTICS__)
    42                 if( options.clopts.procstats ) {
    43                         print_stats_at_exit( this.self, options.clopts.instance->print_stats );
    44                 }
    45                 if( options.clopts.viewhalts ) {
    46                         print_halts( this.self );
    47                 }
    48         #endif
    49 }
    50 
    51 extern void init_protocol(void);
    52 extern void deinit_protocol(void);
    53 
    54 //=============================================================================================
    5531// Stats Printer
    5632//============================================================================================='
     
    5834thread StatsPrinter {};
    5935
    60 void ?{}( StatsPrinter & this ) {
    61         ((thread&)this){ "Stats Printer Thread" };
    62 }
     36void ?{}( StatsPrinter & this, cluster & cl ) {
     37        ((thread&)this){ "Stats Printer Thread", cl };
     38}
     39
     40void ^?{}( StatsPrinter & mutex this ) {}
    6341
    6442void main(StatsPrinter & this) {
     
    7149                sleep(10`s);
    7250
    73                 print_stats_now( *options.clopts.instance, CFA_STATS_READY_Q | CFA_STATS_IO );
    74         }
    75 }
     51                print_stats_now( *active_cluster(), CFA_STATS_READY_Q | CFA_STATS_IO );
     52        }
     53}
     54
     55//=============================================================================================
     56// Globals
     57//=============================================================================================
     58struct ServerCluster {
     59        cluster self;
     60        processor    * procs;
     61        // io_context   * ctxs;
     62        StatsPrinter * prnt;
     63
     64};
     65
     66void ?{}( ServerCluster & this ) {
     67        (this.self){ "Server Cluster", options.clopts.params };
     68
     69        this.procs = alloc(options.clopts.nprocs);
     70        for(i; options.clopts.nprocs) {
     71                (this.procs[i]){ "Benchmark Processor", this.self };
     72
     73                #if !defined(__CFA_NO_STATISTICS__)
     74                        if( options.clopts.procstats ) {
     75                                print_stats_at_exit( *this.procs, this.self.print_stats );
     76                        }
     77                        if( options.clopts.viewhalts ) {
     78                                print_halts( *this.procs );
     79                        }
     80                #endif
     81        }
     82
     83        if(options.stats) {
     84                this.prnt = alloc();
     85                (*this.prnt){ this.self };
     86        } else {
     87                this.prnt = 0p;
     88        }
     89
     90        #if !defined(__CFA_NO_STATISTICS__)
     91                print_stats_at_exit( this.self, CFA_STATS_READY_Q | CFA_STATS_IO );
     92        #endif
     93
     94        options.clopts.instance[options.clopts.cltr_cnt] = &this.self;
     95        options.clopts.cltr_cnt++;
     96}
     97
     98void ^?{}( ServerCluster & this ) {
     99        delete(this.prnt);
     100
     101        for(i; options.clopts.nprocs) {
     102                ^(this.procs[i]){};
     103        }
     104        free(this.procs);
     105
     106        ^(this.self){};
     107}
     108
     109extern void init_protocol(void);
     110extern void deinit_protocol(void);
    76111
    77112//=============================================================================================
     
    137172        // Run Server Cluster
    138173        {
    139                 cluster cl = { "Server Cluster", options.clopts.params };
    140                 #if !defined(__CFA_NO_STATISTICS__)
    141                         print_stats_at_exit( cl, CFA_STATS_READY_Q | CFA_STATS_IO );
    142                 #endif
    143                 options.clopts.instance = &cl;
    144 
    145 
    146174                int pipe_cnt = options.clopts.nworkers * 2;
    147175                int pipe_off;
     
    153181                }
    154182
    155                 if(options.file_cache.path && options.file_cache.fixed_fds) {
    156                         register_fixed_files(cl, fds, pipe_off);
    157                 }
     183                // if(options.file_cache.path && options.file_cache.fixed_fds) {
     184                //      register_fixed_files(cl, fds, pipe_off);
     185                // }
    158186
    159187                {
    160                         ServerProc procs[options.clopts.nprocs];
    161                         StatsPrinter printer;
     188                        ServerCluster cl[options.clopts.nclusters];
    162189
    163190                        init_protocol();
     
    180207                                        unpark( workers[i] );
    181208                                }
    182                                 sout | options.clopts.nworkers | "workers started on" | options.clopts.nprocs | "processors";
     209                                sout | options.clopts.nworkers | "workers started on" | options.clopts.nprocs | "processors /" | options.clopts.nclusters | "clusters";
     210                                for(i; options.clopts.nclusters) {
     211                                        sout | options.clopts.thrd_cnt[i] | nonl;
     212                                }
     213                                sout | nl;
    183214                                {
    184215                                        char buffer[128];
    185                                         while(int ret = cfa_read(0, buffer, 128, 0, -1`s, 0p, 0p); ret != 0) {
     216                                        for() {
     217                                                int ret = cfa_read(0, buffer, 128, 0);
     218                                                if(ret == 0) break;
    186219                                                if(ret < 0) abort( "main read error: (%d) %s\n", (int)errno, strerror(errno) );
     220                                                sout | "User wrote '" | "" | nonl;
     221                                                write(sout, buffer, ret - 1);
     222                                                sout | "'";
    187223                                        }
    188224
     
    193229                                for(i; options.clopts.nworkers) {
    194230                                        workers[i].done = true;
    195                                         cancel(workers[i].cancel);
    196231                                }
    197232                                sout | "done";
     
    221256                        sout | "done";
    222257
    223                         sout | "Stopping processors..." | nonl; flush( sout );
     258                        sout | "Stopping processors/clusters..." | nonl; flush( sout );
    224259                }
    225260                sout | "done";
  • benchmark/io/http/options.cfa

    rfeacef9 r5407cdc  
    1313#include <kernel.hfa>
    1414#include <parseargs.hfa>
     15#include <stdlib.hfa>
    1516
    1617#include <stdlib.h>
     
    1920Options options @= {
    2021        false, // log
     22        false, // stats
    2123
    2224        { // file_cache
     
    3638
    3739        { // cluster
     40                1,     // nclusters;
    3841                1,     // nprocs;
    3942                1,     // nworkers;
     
    4649
    4750void parse_options( int argc, char * argv[] ) {
    48         bool subthrd = false;
    49         bool eagrsub = false;
    50         bool fixedfd = false;
    51         bool sqkpoll = false;
    52         bool iokpoll = false;
    53         unsigned sublen = 16;
     51        // bool fixedfd = false;
     52        // bool sqkpoll = false;
     53        // bool iokpoll = false;
    5454        unsigned nentries = 16;
     55        bool isolate = false;
    5556
    5657
     
    5960                { 'c', "cpus",           "Number of processors to use", options.clopts.nprocs},
    6061                { 't', "threads",        "Number of worker threads to use", options.clopts.nworkers},
     62                {'\0', "isolate",        "Create one cluster per processor", isolate, parse_settrue},
    6163                {'\0', "log",            "Enable logs", options.log, parse_settrue},
     64                {'\0', "stats",          "Enable statistics", options.stats, parse_settrue},
    6265                {'\0', "accept-backlog", "Maximum number of pending accepts", options.socket.backlog},
    6366                {'\0', "request_len",    "Maximum number of bytes in the http request, requests with more data will be answered with Http Code 414", options.socket.buflen},
     
    6568                {'\0', "cache-size",     "Size of the cache to use, if set to small, will uses closes power of 2", options.file_cache.size },
    6669                {'\0', "list-files",     "List the files in the specified path and exit", options.file_cache.list, parse_settrue },
    67                 { 's', "submitthread",   "If set, cluster uses polling thread to submit I/O", subthrd, parse_settrue },
    68                 { 'e', "eagersubmit",    "If set, cluster submits I/O eagerly but still aggregates submits", eagrsub, parse_settrue},
    69                 { 'f', "fixed-fds",      "If set, files are open eagerly and pre-registered with the cluster", fixedfd, parse_settrue},
    70                 { 'k', "kpollsubmit",    "If set, cluster uses IORING_SETUP_SQPOLL, implies -f", sqkpoll, parse_settrue },
    71                 { 'i', "kpollcomplete",  "If set, cluster uses IORING_SETUP_IOPOLL", iokpoll, parse_settrue },
    72                 {'\0', "submitlength",   "Max number of submitions that can be submitted together", sublen },
    73                 {'\0', "numentries",     "Number of I/O entries", nentries },
     70                // { 'f', "fixed-fds",      "If set, files are open eagerly and pre-registered with the cluster", fixedfd, parse_settrue},
     71                // { 'k', "kpollsubmit",    "If set, cluster uses IORING_SETUP_SQPOLL, implies -f", sqkpoll, parse_settrue },
     72                // { 'i', "kpollcomplete",  "If set, cluster uses IORING_SETUP_IOPOLL", iokpoll, parse_settrue },
     73                {'e', "numentries",     "Number of I/O entries", nentries },
    7474
    7575        };
     
    9191                nentries = v;
    9292        }
     93        if(isolate) {
     94                options.clopts.nclusters = options.clopts.nprocs;
     95                options.clopts.nprocs = 1;
     96        }
    9397        options.clopts.params.num_entries = nentries;
    94 
    95         options.clopts.params.poller_submits = subthrd;
    96         options.clopts.params.eager_submits  = eagrsub;
    97 
    98         if( fixedfd ) {
    99                 options.file_cache.fixed_fds = true;
     98        options.clopts.instance = alloc(options.clopts.nclusters);
     99        options.clopts.thrd_cnt = alloc(options.clopts.nclusters);
     100        options.clopts.cltr_cnt = 0;
     101        for(i; options.clopts.nclusters) {
     102                options.clopts.thrd_cnt[i] = 0;
    100103        }
    101104
    102         if( sqkpoll ) {
    103                 options.clopts.params.poll_submit = true;
    104                 options.file_cache.fixed_fds = true;
    105         }
    106105
    107         if( iokpoll ) {
    108                 options.clopts.params.poll_complete = true;
    109                 options.file_cache.open_flags |= O_DIRECT;
    110         }
     106        // if( fixedfd ) {
     107        //      options.file_cache.fixed_fds = true;
     108        // }
    111109
    112         options.clopts.params.num_ready = sublen;
     110        // if( sqkpoll ) {
     111        //      options.file_cache.fixed_fds = true;
     112        // }
     113
     114        // if( iokpoll ) {
     115        //      options.file_cache.open_flags |= O_DIRECT;
     116        // }
    113117
    114118        if( left[0] == 0p ) { return; }
  • benchmark/io/http/options.hfa

    rfeacef9 r5407cdc  
    99struct Options {
    1010        bool log;
     11        bool stats;
    1112
    1213        struct {
     
    2627
    2728        struct {
     29                int nclusters;
    2830                int nprocs;
    2931                int nworkers;
     
    3133                bool procstats;
    3234                bool viewhalts;
    33                 cluster * instance;
     35                cluster ** instance;
     36                size_t   * thrd_cnt;
     37                size_t     cltr_cnt;
    3438        } clopts;
    3539};
  • benchmark/io/http/protocol.cfa

    rfeacef9 r5407cdc  
    55        #include <fcntl.h>
    66}
     7
     8#define xstr(s) str(s)
     9#define str(s) #s
    710
    811#include <fstream.hfa>
     
    2023#include "options.hfa"
    2124
    22 const char * volatile date = 0p;
    23 
    24 const char * http_msgs[] = {
    25         "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: %zu \n\n",
    26         "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    27         "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    28         "HTTP/1.1 405 Method Not Allowed\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    29         "HTTP/1.1 408 Request Timeout\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    30         "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    31         "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    32 };
     25#define PLAINTEXT_1WRITE
     26#define PLAINTEXT_MEMCPY
     27#define PLAINTEXT_NOCOPY
     28
     29struct https_msg_str {
     30        char msg[512];
     31        size_t len;
     32};
     33
     34const https_msg_str * volatile http_msgs[KNOWN_CODES] = { 0 };
    3335
    3436_Static_assert( KNOWN_CODES == (sizeof(http_msgs ) / sizeof(http_msgs [0])));
    3537
    36 const int http_codes[] = {
     38const int http_codes[KNOWN_CODES] = {
     39        200,
    3740        200,
    3841        400,
     
    5356        while(len > 0) {
    5457                // Call write
    55                 int ret = cfa_write(fd, it, len, 0, -1`s, 0p, 0p);
    56                 // int ret = write(fd, it, len);
     58                int ret = cfa_send(fd, it, len, 0, CFA_IO_LAZY);
    5759                if( ret < 0 ) {
    5860                        if( errno == ECONNRESET || errno == EPIPE ) return -ECONNRESET;
     
    7274        /* paranoid */ assert( code < KNOWN_CODES && code != OK200 );
    7375        int idx = (int)code;
    74         return answer( fd, http_msgs[idx], strlen( http_msgs[idx] ) );
     76        return answer( fd, http_msgs[idx]->msg, http_msgs[idx]->len );
    7577}
    7678
    7779int answer_header( int fd, size_t size ) {
    78         const char * fmt = http_msgs[OK200];
    79         int len = 200;
    80         char buffer[len];
    81         len = snprintf(buffer, len, fmt, date, size);
     80        char buffer[512];
     81        char * it = buffer;
     82        memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
     83        it += http_msgs[OK200]->len;
     84        int len = http_msgs[OK200]->len;
     85        len += snprintf(it, 512 - len, "%d \n\n", size);
    8286        return answer( fd, buffer, len );
    8387}
    8488
    85 int answer_plain( int fd, char buffer[], size_t size ) {
    86         int ret = answer_header(fd, size);
     89#if defined(PLAINTEXT_NOCOPY)
     90int answer_plaintext( int fd ) {
     91        return answer(fd, http_msgs[OK200_PlainText]->msg, http_msgs[OK200_PlainText]->len); // +1 cause snprintf doesn't count nullterminator
     92}
     93#elif defined(PLAINTEXT_MEMCPY)
     94#define TEXTSIZE 15
     95int answer_plaintext( int fd ) {
     96        char text[] = "Hello, World!\n\n";
     97        char ts[] = xstr(TEXTSIZE) " \n\n";
     98        _Static_assert(sizeof(text) - 1 == TEXTSIZE);
     99        char buffer[512 + TEXTSIZE];
     100        char * it = buffer;
     101        memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
     102        it += http_msgs[OK200]->len;
     103        int len = http_msgs[OK200]->len;
     104        memcpy(it, ts, sizeof(ts) - 1);
     105        it += sizeof(ts) - 1;
     106        len += sizeof(ts) - 1;
     107        memcpy(it, text, TEXTSIZE);
     108        return answer(fd, buffer, len + TEXTSIZE);
     109}
     110#elif defined(PLAINTEXT_1WRITE)
     111int answer_plaintext( int fd ) {
     112        char text[] = "Hello, World!\n\n";
     113        char buffer[512 + sizeof(text)];
     114        char * it = buffer;
     115        memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
     116        it += http_msgs[OK200]->len;
     117        int len = http_msgs[OK200]->len;
     118        int r = snprintf(it, 512 - len, "%d \n\n", sizeof(text));
     119        it += r;
     120        len += r;
     121        memcpy(it, text, sizeof(text));
     122        return answer(fd, buffer, len + sizeof(text));
     123}
     124#else
     125int answer_plaintext( int fd ) {
     126        char text[] = "Hello, World!\n\n";
     127        int ret = answer_header(fd, sizeof(text));
    87128        if( ret < 0 ) return ret;
    88         return answer(fd, buffer, size);
    89 }
     129        return answer(fd, text, sizeof(text));
     130}
     131#endif
    90132
    91133int answer_empty( int fd ) {
     
    94136
    95137
    96 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len, io_cancellation * cancel) {
     138[HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len) {
    97139        char * it = buffer;
    98140        size_t count = len - 1;
     
    100142        READ:
    101143        for() {
    102                 int ret = cfa_read(fd, (void*)it, count, 0, -1`s, cancel, 0p);
     144                int ret = cfa_recv(fd, (void*)it, count, 0, CFA_IO_LAZY);
    103145                // int ret = read(fd, (void*)it, count);
    104146                if(ret == 0 ) return [OK200, true, 0, 0];
     
    139181        ssize_t ret;
    140182        SPLICE1: while(count > 0) {
    141                 ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, sflags, 0, -1`s, 0p, 0p);
    142                 // ret = splice(ans_fd, &offset, pipe[1], 0p, count, sflags);
     183                ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, sflags, CFA_IO_LAZY);
    143184                if( ret < 0 ) {
    144185                        if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE1;
     
    152193                size_t in_pipe = ret;
    153194                SPLICE2: while(in_pipe > 0) {
    154                         ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, sflags, 0, -1`s, 0p, 0p);
    155                         // ret = splice(pipe[0], 0p, fd, 0p, in_pipe, sflags);
     195                        ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, sflags, CFA_IO_LAZY);
    156196                        if( ret < 0 ) {
    157197                                if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE2;
     
    173213#include <thread.hfa>
    174214
     215const char * original_http_msgs[] = {
     216        "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: ",
     217        "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 15\n\nHello, World!\n\n",
     218        "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     219        "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     220        "HTTP/1.1 405 Method Not Allowed\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     221        "HTTP/1.1 408 Request Timeout\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     222        "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     223        "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     224};
     225
    175226struct date_buffer {
    176         char buff[100];
     227        https_msg_str strs[KNOWN_CODES];
    177228};
    178229
     
    183234
    184235void ?{}( DateFormater & this ) {
    185         ((thread&)this){ "Server Date Thread", *options.clopts.instance };
     236        ((thread&)this){ "Server Date Thread", *options.clopts.instance[0] };
    186237        this.idx = 0;
    187         memset( this.buffers[0].buff, 0, sizeof(this.buffers[0]) );
    188         memset( this.buffers[1].buff, 0, sizeof(this.buffers[1]) );
     238        memset( &this.buffers[0], 0, sizeof(this.buffers[0]) );
     239        memset( &this.buffers[1], 0, sizeof(this.buffers[1]) );
    189240}
    190241
     
    196247                or else {}
    197248
    198                 Time now = getTimeNsec();
    199 
    200                 strftime( this.buffers[this.idx].buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now );
    201 
    202                 char * next = this.buffers[this.idx].buff;
    203                 __atomic_exchange_n((char * volatile *)&date, next, __ATOMIC_SEQ_CST);
     249
     250                char buff[100];
     251                Time now = timeHiRes();
     252                strftime( buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now );
     253                sout | "Updated date to '" | buff | "'";
     254
     255                for(i; KNOWN_CODES) {
     256                        size_t len = snprintf( this.buffers[this.idx].strs[i].msg, 512, original_http_msgs[i], buff );
     257                        this.buffers[this.idx].strs[i].len = len;
     258                }
     259
     260                for(i; KNOWN_CODES) {
     261                        https_msg_str * next = &this.buffers[this.idx].strs[i];
     262                        __atomic_exchange_n((https_msg_str * volatile *)&http_msgs[i], next, __ATOMIC_SEQ_CST);
     263                }
    204264                this.idx = (this.idx + 1) % 2;
     265
     266                sout | "Date thread sleeping";
    205267
    206268                sleep(1`s);
  • benchmark/io/http/protocol.hfa

    rfeacef9 r5407cdc  
    11#pragma once
    2 
    3 struct io_cancellation;
    42
    53enum HttpCode {
    64        OK200 = 0,
     5        OK200_PlainText,
    76        E400,
    87        E404,
     
    1817int answer_error( int fd, HttpCode code );
    1918int answer_header( int fd, size_t size );
    20 int answer_plain( int fd, char buffer [], size_t size );
     19int answer_plaintext( int fd );
    2120int answer_empty( int fd );
    2221
    23 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len, io_cancellation *);
     22[HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len);
    2423
    2524int sendfile( int pipe[2], int fd, int ans_fd, size_t count );
  • benchmark/io/http/worker.cfa

    rfeacef9 r5407cdc  
    1717//=============================================================================================
    1818void ?{}( Worker & this ) {
    19         ((thread&)this){ "Server Worker Thread", *options.clopts.instance };
     19        size_t cli = rand() % options.clopts.cltr_cnt;
     20        ((thread&)this){ "Server Worker Thread", *options.clopts.instance[cli], 512000 };
     21        options.clopts.thrd_cnt[cli]++;
    2022        this.pipe[0] = -1;
    2123        this.pipe[1] = -1;
     
    3537        for() {
    3638                if( options.log ) sout | "=== Accepting connection ===";
    37                 int fd = cfa_accept4( this.[sockfd, addr, addrlen, flags], 0, -1`s, &this.cancel, 0p );
    38                 // int fd = accept4( this.[sockfd, addr, addrlen, flags] );
     39                int fd = cfa_accept4( this.[sockfd, addr, addrlen, flags], CFA_IO_LAZY );
    3940                if(fd < 0) {
    4041                        if( errno == ECONNABORTED ) break;
     
    4243                        abort( "accept error: (%d) %s\n", (int)errno, strerror(errno) );
    4344                }
     45                if(this.done) break;
    4446
    4547                if( options.log ) sout | "=== New connection" | fd | "" | ", waiting for requests ===";
     
    5557                        char buffer[len];
    5658                        if( options.log ) sout | "=== Reading request ===";
    57                         [code, closed, file, name_size] = http_read(fd, buffer, len, &this.cancel);
     59                        [code, closed, file, name_size] = http_read(fd, buffer, len);
    5860
    5961                        // if we are done, break out of the loop
     
    7072                                if( options.log ) sout | "=== Request for /plaintext ===";
    7173
    72                                 char text[] = "Hello, World!\n";
    73 
    74                                 // Send the header
    75                                 int ret = answer_plain(fd, text, sizeof(text));
     74                                int ret = answer_plaintext(fd);
    7675                                if( ret == -ECONNRESET ) break REQUEST;
    7776
  • benchmark/io/http/worker.hfa

    rfeacef9 r5407cdc  
    1717        socklen_t * addrlen;
    1818        int flags;
    19         io_cancellation cancel;
    2019        volatile bool done;
    2120};
  • benchmark/io/readv-posix.c

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

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

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

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

    rfeacef9 r5407cdc  
    33#include <libfibre/fibre.h>
    44
    5 class __attribute__((aligned(128))) bench_sem {
    6         Fibre * volatile ptr = nullptr;
    7 public:
    8         inline bool wait() {
    9                 static Fibre * const ready  = reinterpret_cast<Fibre * const>(1ull);
    10                 for(;;) {
    11                         Fibre * expected = this->ptr;
    12                         if(expected == ready) {
    13                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    14                                         return false;
    15                                 }
    16                         }
    17                         else {
    18                                 /* paranoid */ assert( expected == nullptr );
    19                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    20                                         fibre_park();
    21                                         return true;
    22                                 }
    23                         }
    24 
    25                 }
    26         }
    27 
    28         inline bool post() {
    29                 static Fibre * const ready  = reinterpret_cast<Fibre * const>(1ull);
    30                 for(;;) {
    31                         Fibre * expected = this->ptr;
    32                         if(expected == ready) return false;
    33                         if(expected == nullptr) {
    34                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    35                                         return false;
    36                                 }
    37                         }
    38                         else {
    39                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    40                                         fibre_unpark( expected );
    41                                         return true;
    42                                 }
    43                         }
    44                 }
    45         }
    46 };
    475struct Partner {
    486        unsigned long long count  = 0;
     
    9351
    9452                        bool is_tty = isatty(STDOUT_FILENO);
    95                         start = getTimeNsec();
     53                        start = timeHiRes();
    9654
    9755                        for(int i = 0; i < nthreads; i++) {
     
    10159
    10260                        stop = true;
    103                         end = getTimeNsec();
     61                        end = timeHiRes();
    10462                        printf("\nDone\n");
    10563
  • benchmark/readyQ/locality.cfa

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

    rfeacef9 r5407cdc  
    99        uint64_t dmigs = 0;
    1010        uint64_t gmigs = 0;
    11 };
    12 
    13 class __attribute__((aligned(128))) bench_sem {
    14         Fibre * volatile ptr = nullptr;
    15 public:
    16         inline bool wait() {
    17                 static Fibre * const ready  = reinterpret_cast<Fibre * const>(1ull);
    18                 for(;;) {
    19                         Fibre * expected = this->ptr;
    20                         if(expected == ready) {
    21                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    22                                         return false;
    23                                 }
    24                         }
    25                         else {
    26                                 /* paranoid */ assert( expected == nullptr );
    27                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    28                                         fibre_park();
    29                                         return true;
    30                                 }
    31                         }
    32 
    33                 }
    34         }
    35 
    36         inline bool post() {
    37                 static Fibre * const ready  = reinterpret_cast<Fibre * const>(1ull);
    38                 for(;;) {
    39                         Fibre * expected = this->ptr;
    40                         if(expected == ready) return false;
    41                         if(expected == nullptr) {
    42                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    43                                         return false;
    44                                 }
    45                         }
    46                         else {
    47                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    48                                         fibre_unpark( expected );
    49                                         return true;
    50                                 }
    51                         }
    52                 }
    53         }
    5411};
    5512
     
    287244
    288245                        bool is_tty = isatty(STDOUT_FILENO);
    289                         start = getTimeNsec();
     246                        start = timeHiRes();
    290247
    291248                        for(size_t i = 0; i < nthreads; i++) {
     
    295252
    296253                        stop = true;
    297                         end = getTimeNsec();
     254                        end = timeHiRes();
    298255                        printf("\nDone\n");
    299256
  • benchmark/readyQ/rq_bench.hfa

    rfeacef9 r5407cdc  
    44#include <stdio.h>
    55#include <stdlib.hfa>
     6#include <stats.hfa>
    67#include <thread.hfa>
    78#include <time.hfa>
     
    6364                (*p){ "Benchmark Processor", this.cl };
    6465        }
     66        #if !defined(__CFA_NO_STATISTICS__)
     67                print_stats_at_exit( this.cl, CFA_STATS_READY_Q );
     68        #endif
    6569}
    6670
     
    7377        for() {
    7478                sleep(100`ms);
    75                 Time end = getTimeNsec();
     79                Time end = timeHiRes();
    7680                Duration delta = end - start;
    7781                if(is_tty) {
  • benchmark/readyQ/rq_bench.hpp

    rfeacef9 r5407cdc  
    66#include <time.h>                                                                               // timespec
    77#include <sys/time.h>                                                                   // timeval
     8
     9typedef __uint128_t __lehmer64_state_t;
     10static inline uint64_t __lehmer64( __lehmer64_state_t & state ) {
     11        state *= 0xda942042e4dd58b5;
     12        return state >> 64;
     13}
    814
    915enum { TIMEGRAN = 1000000000LL };                                       // nanosecond granularity, except for timeval
     
    4652        }
    4753
    48 uint64_t getTimeNsec() {
     54uint64_t timeHiRes() {
    4955        timespec curr;
    5056        clock_gettime( CLOCK_REALTIME, &curr );
     
    6066        for(;;) {
    6167                Sleeper::usleep(100000);
    62                 uint64_t end = getTimeNsec();
     68                uint64_t end = timeHiRes();
    6369                uint64_t delta = end - start;
    6470                if(is_tty) {
     
    7480        }
    7581}
     82
     83class Fibre;
     84int fibre_park();
     85int fibre_unpark( Fibre * );
     86Fibre * fibre_self();
     87
     88class __attribute__((aligned(128))) bench_sem {
     89        Fibre * volatile ptr = nullptr;
     90public:
     91        inline bool wait() {
     92                static Fibre * const ready  = reinterpret_cast<Fibre *>(1ull);
     93                for(;;) {
     94                        Fibre * expected = this->ptr;
     95                        if(expected == ready) {
     96                                if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     97                                        return false;
     98                                }
     99                        }
     100                        else {
     101                                /* paranoid */ assert( expected == nullptr );
     102                                if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     103                                        fibre_park();
     104                                        return true;
     105                                }
     106                        }
     107
     108                }
     109        }
     110
     111        inline bool post() {
     112                static Fibre * const ready  = reinterpret_cast<Fibre *>(1ull);
     113                for(;;) {
     114                        Fibre * expected = this->ptr;
     115                        if(expected == ready) return false;
     116                        if(expected == nullptr) {
     117                                if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     118                                        return false;
     119                                }
     120                        }
     121                        else {
     122                                if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     123                                        fibre_unpark( expected );
     124                                        return true;
     125                                }
     126                        }
     127                }
     128        }
     129};
    76130
    77131// ==========================================================================================
     
    188242                this->help       = help;
    189243                this->variable   = reinterpret_cast<void*>(&variable);
    190                 this->parse_fun  = reinterpret_cast<bool (*)(const char *, void * )>(static_cast<bool (*)(const char *, T & )>(parse));
     244                #pragma GCC diagnostic push
     245                #pragma GCC diagnostic ignored "-Wcast-function-type"
     246                                this->parse_fun  = reinterpret_cast<bool (*)(const char *, void * )>(static_cast<bool (*)(const char *, T & )>(parse));
     247                #pragma GCC diagnostic pop
    191248        }
    192249
     
    197254                this->help       = help;
    198255                this->variable   = reinterpret_cast<void*>(&variable);
    199                 this->parse_fun  = reinterpret_cast<bool (*)(const char *, void * )>(parse);
     256                #pragma GCC diagnostic push
     257                #pragma GCC diagnostic ignored "-Wcast-function-type"
     258                        this->parse_fun  = reinterpret_cast<bool (*)(const char *, void * )>(parse);
     259                #pragma GCC diagnostic pop
    200260        }
    201261};
  • benchmark/readyQ/yield.cfa

    rfeacef9 r5407cdc  
    6666
    6767                                bool is_tty = isatty(STDOUT_FILENO);
    68                                 start = getTimeNsec();
     68                                start = timeHiRes();
    6969                                run = true;
    7070
     
    7575
    7676                                run = false;
    77                                 end = getTimeNsec();
     77                                end = timeHiRes();
    7878                                printf("\nDone\n");
    7979                        }
  • doc/LaTeXmacros/lstlang.sty

    rfeacef9 r5407cdc  
    88%% Created On       : Sat May 13 16:34:42 2017
    99%% Last Modified By : Peter A. Buhr
    10 %% Last Modified On : Wed Sep 23 22:40:04 2020
    11 %% Update Count     : 24
     10%% Last Modified On : Wed Feb 17 09:21:15 2021
     11%% Update Count     : 27
    1212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1313
     
    113113        morekeywords={
    114114                _Alignas, _Alignof, __alignof, __alignof__, asm, __asm, __asm__, __attribute, __attribute__,
    115                 auto, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__,
    116                 coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally,
     115                auto, basetypeof, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__,
     116                coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally, fixup,
    117117                __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__,
    118118                inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or,
    119                 otype, restrict, __restrict, __restrict__, __signed, __signed__, _Static_assert, suspend, thread,
    120                 _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,
     119                otype, restrict, __restrict, __restrict__, recover, report, __signed, __signed__, _Static_assert, suspend,
     120                thread, _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,
    121121                virtual, __volatile, __volatile__, waitfor, when, with, zero_t,
    122122    },
  • doc/bibliography/pl.bib

    rfeacef9 r5407cdc  
    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
     
    33003302    month       = jan,
    33013303    address     = {Waterloo, Ontario, Canada, N2L 3G1},
    3302     note        = {\textsf{http://uwspace.uwaterloo.ca/\-bitstream/\-10012/\-3501/\-1/\-Thesis.pdf}},
     3304    note        = {\href{http://uwspace.uwaterloo.ca/bitstream/10012/3501/1/Thesis.pdf}{http://\-uwspace.uwaterloo.ca/\-bitstream/\-10012/\-3501/\-1/\-Thesis.pdf}},
    33033305}
    33043306
  • doc/theses/andrew_beach_MMath/Makefile

    rfeacef9 r5407cdc  
    44BUILD=out
    55TEXSRC=$(wildcard *.tex)
     6FIGSRC=$(wildcard *.fig)
    67BIBSRC=$(wildcard *.bib)
    78STYSRC=$(wildcard *.sty)
     
    1314BASE= ${DOC:%.pdf=%}
    1415
     16RAWSRC=${TEXSRC} ${BIBSRC} ${STYSRC} ${CLSSRC}
     17FIGTEX=${FIGSRC:%.fig=${BUILD}/%.tex}
     18
    1519### Special Rules:
    1620
     
    1822
    1923### Commands:
    20 LATEX=TEXINPUTS=${TEXLIB} pdflatex -halt-on-error -output-directory=${BUILD}
     24LATEX=TEXINPUTS=${TEXLIB} latex -halt-on-error -output-directory=${BUILD}
    2125BIBTEX=BIBINPUTS=${BIBLIB} bibtex
    2226GLOSSARY=INDEXSTYLE=${BUILD} makeglossaries-lite
     
    2630all: ${DOC}
    2731
    28 ${BUILD}/${DOC}: ${TEXSRC} ${BIBSRC} ${STYSRC} ${CLSSRC} Makefile | ${BUILD}
     32# The main rule, it does all the tex/latex processing.
     33${BUILD}/${BASE}.dvi: ${RAWSRC} ${FIGTEX} Makefile | ${BUILD}
    2934        ${LATEX} ${BASE}
    3035        ${BIBTEX} ${BUILD}/${BASE}
     
    3338        ${LATEX} ${BASE}
    3439
    35 ${DOC}: ${BUILD}/${DOC}
    36         cp $< $@
     40# Convert xfig output to tex. (Generates \special declarations.)
     41${FIGTEX}: ${BUILD}/%.tex: %.fig | ${BUILD}
     42        fig2dev -L eepic $< > $@
     43
     44# Step through dvi & postscript to handle xfig specials.
     45%.pdf : ${BUILD}/%.dvi
     46        dvipdf $^ $@
    3747
    3848${BUILD}:
  • doc/theses/andrew_beach_MMath/existing.tex

    rfeacef9 r5407cdc  
    1414\section{Overloading and \lstinline{extern}}
    1515\CFA has extensive overloading, allowing multiple definitions of the same name
    16 to be defined.~\cite{Moss18}
     16to be defined~\cite{Moss18}.
    1717\begin{cfa}
    1818char i; int i; double i;                        $\C[3.75in]{// variable overload}$
     
    4646pointers using the ampersand (@&@) instead of the pointer asterisk (@*@). \CFA
    4747references may also be mutable or non-mutable. If mutable, a reference variable
    48 may be assigned to using the address-of operator (@&@), which converts the
     48may be assigned using the address-of operator (@&@), which converts the
    4949reference to a pointer.
    5050\begin{cfa}
     
    5858\section{Constructors and Destructors}
    5959
    60 Both constructors and destructors are operators, which means they are just
     60Both constructors and destructors are operators, which means they are
    6161functions with special operator names rather than type names in \Cpp. The
    6262special operator names may be used to call the functions explicitly (not
     
    6464
    6565In general, operator names in \CFA are constructed by bracketing an operator
    66 token with @?@, which indicates where the arguments. For example, infixed
     66token with @?@, which indicates the position of the arguments. For example, infixed
    6767multiplication is @?*?@ while prefix dereference is @*?@. This syntax make it
    6868easy to tell the difference between prefix operations (such as @++?@) and
     
    8989definition, \CFA creates a default and copy constructor, destructor and
    9090assignment (like \Cpp). It is possible to define constructors/destructors for
    91 basic and existing types.
     91basic and existing types (unlike \Cpp).
    9292
    9393\section{Polymorphism}
     
    120120        do_once(value);
    121121}
    122 void do_once(int i) { ... }  // provide assertion
    123 int i;
     122void do_once(@int@ i) { ... }  // provide assertion
     123@int@ i;
    124124do_twice(i); // implicitly pass assertion do_once to do_twice
    125125\end{cfa}
     
    172172declarations instead of parameters, returns, and local variable declarations.
    173173\begin{cfa}
    174 forall(dtype T)
     174forall(dtype @T@)
    175175struct node {
    176         node(T) * next;  // generic linked node
    177         T * data;
    178 }
     176        node(@T@) * next;  // generic linked node
     177        @T@ * data;
     178}
     179node(@int@) inode;
    179180\end{cfa}
    180181The generic type @node(T)@ is an example of a polymorphic-type usage.  Like \Cpp
    181 templates usage, a polymorphic-type usage must specify a type parameter.
     182template usage, a polymorphic-type usage must specify a type parameter.
    182183
    183184There are many other polymorphism features in \CFA but these are the ones used
    184185by the exception system.
    185186
    186 \section{Concurrency}
    187 \CFA has a number of concurrency features: @thread@, @monitor@, @mutex@
    188 parameters, @coroutine@ and @generator@. The two features that interact with
    189 the exception system are @thread@ and @coroutine@; they and their supporting
     187\section{Control Flow}
     188\CFA has a number of advanced control-flow features: @generator@, @coroutine@, @monitor@, @mutex@ parameters, and @thread@.
     189The two features that interact with
     190the exception system are @coroutine@ and @thread@; they and their supporting
    190191constructs are described here.
    191192
     
    216217CountUp countup;
    217218\end{cfa}
    218 Each coroutine has @main@ function, which takes a reference to a coroutine
     219Each coroutine has a @main@ function, which takes a reference to a coroutine
    219220object and returns @void@.
    220221\begin{cfa}[numbers=left]
     
    230231In this function, or functions called by this function (helper functions), the
    231232@suspend@ statement is used to return execution to the coroutine's caller
    232 without terminating the coroutine.
     233without terminating the coroutine's function.
    233234
    234235A coroutine is resumed by calling the @resume@ function, \eg @resume(countup)@.
     
    242243@resume(countup).next@.
    243244
    244 \subsection{Monitors and Mutex}
     245\subsection{Monitor and Mutex Parameter}
    245246Concurrency does not guarantee ordering; without ordering results are
    246247non-deterministic. To claw back ordering, \CFA uses monitors and @mutex@
     
    260261and only one runs at a time.
    261262
    262 \subsection{Threads}
     263\subsection{Thread}
    263264Functions, generators, and coroutines are sequential so there is only a single
    264265(but potentially sophisticated) execution path in a program. Threads introduce
     
    268269monitors and mutex parameters. For threads to work safely with other threads,
    269270also requires mutual exclusion in the form of a communication rendezvous, which
    270 also supports internal synchronization as for mutex objects. For exceptions
    271 only the basic two basic operations are important: thread fork and join.
     271also supports internal synchronization as for mutex objects. For exceptions,
     272only two basic thread operations are important: fork and join.
    272273
    273274Threads are created like coroutines with an associated @main@ function:
  • doc/theses/andrew_beach_MMath/features.tex

    rfeacef9 r5407cdc  
    22
    33This chapter covers the design and user interface of the \CFA
    4 exception-handling mechanism.
     4exception-handling mechanism (EHM). % or exception system.
     5
     6We will begin with an overview of EHMs in general. It is not a strict
     7definition of all EHMs nor an exaustive list of all possible features.
     8However it does cover the most common structure and features found in them.
     9
     10% We should cover what is an exception handling mechanism and what is an
     11% exception before this. Probably in the introduction. Some of this could
     12% move there.
     13\paragraph{Raise / Handle}
     14An exception operation has two main parts: raise and handle.
     15These terms are sometimes also known as throw and catch but this work uses
     16throw/catch as a particular kind of raise/handle.
     17These are the two parts that the user will write themselves and may
     18be the only two pieces of the EHM that have any syntax in the language.
     19
     20\subparagraph{Raise}
     21The raise is the starting point for exception handling. It marks the beginning
     22of exception handling by \newterm{raising} an excepion, which passes it to
     23the EHM.
     24
     25Some well known examples include the @throw@ statements of \Cpp and Java and
     26the \codePy{raise} statement from Python. In real systems a raise may preform
     27some other work (such as memory management) but for the purposes of this
     28overview that can be ignored.
     29
     30\subparagraph{Handle}
     31The purpose of most exception operations is to run some user code to handle
     32that exception. This code is given, with some other information, in a handler.
     33
     34A handler has three common features: the previously mentioned user code, a
     35region of code they cover and an exception label/condition that matches
     36certain exceptions.
     37Only raises inside the covered region and raising exceptions that match the
     38label can be handled by a given handler.
     39Different EHMs will have different rules to pick a handler
     40if multipe handlers could be used such as ``best match" or ``first found".
     41
     42The @try@ statements of \Cpp, Java and Python are common examples. All three
     43also show another common feature of handlers, they are grouped by the covered
     44region.
     45
     46\paragraph{Propagation}
     47After an exception is raised comes what is usually the biggest step for the
     48EHM: finding and setting up the handler. The propogation from raise to
     49handler can be broken up into three different tasks: searching for a handler,
     50matching against the handler and installing the handler.
     51
     52\subparagraph{Searching}
     53The EHM begins by searching for handlers that might be used to handle
     54the exception. Searching is usually independent of the exception that was
     55thrown as it looks for handlers that have the raise site in their covered
     56region.
     57This includes handlers in the current function, as well as any in callers
     58on the stack that have the function call in their covered region.
     59
     60\subparagraph{Matching}
     61Each handler found has to be matched with the raised exception. The exception
     62label defines a condition that be use used with exception and decides if
     63there is a match or not.
     64
     65In languages where the first match is used this step is intertwined with
     66searching, a match check is preformed immediately after the search finds
     67a possible handler.
     68
     69\subparagraph{Installing}
     70After a handler is chosen it must be made ready to run.
     71The implementation can vary widely to fit with the rest of the
     72design of the EHM. The installation step might be trivial or it could be
     73the most expensive step in handling an exception. The latter tends to be the
     74case when stack unwinding is involved.
     75
     76If a matching handler is not guarantied to be found the EHM will need a
     77different course of action here in the cases where no handler matches.
     78This is only required with unchecked exceptions as checked exceptions
     79(such as in Java) can make than guaranty.
     80This different action can also be installing a handler but it is usually an
     81implicat and much more general one.
     82
     83\subparagraph{Hierarchy}
     84A common way to organize exceptions is in a hierarchical structure.
     85This is especially true in object-orientated languages where the
     86exception hierarchy is a natural extension of the object hierarchy.
     87
     88Consider the following hierarchy of exceptions:
     89\begin{center}
     90\input{exception-hierarchy}
     91\end{center}
     92
     93A handler labelled with any given exception can handle exceptions of that
     94type or any child type of that exception. The root of the exception hierarchy
     95(here \codeC{exception}) acts as a catch-all, leaf types catch single types
     96and the exceptions in the middle can be used to catch different groups of
     97related exceptions.
     98
     99This system has some notable advantages, such as multiple levels of grouping,
     100the ability for libraries to add new exception types and the isolation
     101between different sub-hierarchies.
     102This design is used in \CFA even though it is not a object-orientated
     103language using different tools to create the hierarchy.
     104
     105% Could I cite the rational for the Python IO exception rework?
     106
     107\paragraph{Completion}
     108After the handler has finished the entire exception operation has to complete
     109and continue executing somewhere else. This step is usually simple,
     110both logically and in its implementation, as the installation of the handler
     111is usually set up to do most of the work.
     112
     113The EHM can return control to many different places,
     114the most common are after the handler definition and after the raise.
     115
     116\paragraph{Communication}
     117For effective exception handling, additional information is usually passed
     118from the raise to the handler.
     119So far only communication of the exceptions' identity has been covered.
     120A common method is putting fields into the exception instance and giving the
     121handler access to them.
    5122
    6123\section{Virtuals}
    7 Virtual types and casts are not part of the exception system nor are they
    8 required for an exception system. But an object-oriented style hierarchy is a
    9 great way of organizing exceptions so a minimal virtual system has been added
    10 to \CFA.
    11 
    12 The pattern of a simple hierarchy was borrowed from object-oriented
    13 programming was chosen for several reasons.
    14 The first is that it allows new exceptions to be added in user code
    15 and in libraries independently of each other. Another is it allows for
    16 different levels of exception grouping (all exceptions, all IO exceptions or
    17 a particular IO exception). Also it also provides a simple way of passing
    18 data back and forth across the throw.
    19 
    20 Virtual types and casts are not required for a basic exception-system but are
    21 useful for advanced exception features. However, \CFA is not object-oriented so
    22 there is no obvious concept of virtuals. Hence, to create advanced exception
    23 features for this work, I needed to design and implement a virtual-like
    24 system for \CFA.
    25 
    26 % NOTE: Maybe we should but less of the rational here.
    27 Object-oriented languages often organized exceptions into a simple hierarchy,
    28 \eg Java.
    29 \begin{center}
    30 \setlength{\unitlength}{4000sp}%
    31 \begin{picture}(1605,612)(2011,-1951)
    32 \put(2100,-1411){\vector(1, 0){225}}
    33 \put(3450,-1411){\vector(1, 0){225}}
    34 \put(3550,-1411){\line(0,-1){225}}
    35 \put(3550,-1636){\vector(1, 0){150}}
    36 \put(3550,-1636){\line(0,-1){225}}
    37 \put(3550,-1861){\vector(1, 0){150}}
    38 \put(2025,-1490){\makebox(0,0)[rb]{\LstBasicStyle{exception}}}
    39 \put(2400,-1460){\makebox(0,0)[lb]{\LstBasicStyle{arithmetic}}}
    40 \put(3750,-1460){\makebox(0,0)[lb]{\LstBasicStyle{underflow}}}
    41 \put(3750,-1690){\makebox(0,0)[lb]{\LstBasicStyle{overflow}}}
    42 \put(3750,-1920){\makebox(0,0)[lb]{\LstBasicStyle{zerodivide}}}
    43 \end{picture}%
    44 \end{center}
    45 The hierarchy provides the ability to handle an exception at different degrees
    46 of specificity (left to right). Hence, it is possible to catch a more general
    47 exception-type in higher-level code where the implementation details are
    48 unknown, which reduces tight coupling to the lower-level implementation.
    49 Otherwise, low-level code changes require higher-level code changes, \eg,
    50 changing from raising @underflow@ to @overflow@ at the low level means changing
    51 the matching catch at the high level versus catching the general @arithmetic@
    52 exception. In detail, each virtual type may have a parent and can have any
    53 number of children. A type's descendants are its children and its children's
    54 descendants. A type may not be its own descendant.
    55 
    56 The exception hierarchy allows a handler (@catch@ clause) to match multiple
    57 exceptions, \eg a base-type handler catches both base and derived
    58 exception-types.
    59 \begin{cfa}
    60 try {
    61         ...
    62 } catch(arithmetic &) {
    63         ... // handle arithmetic, underflow, overflow, zerodivide
    64 }
    65 \end{cfa}
    66 Most exception mechanisms perform a linear search of the handlers and select
    67 the first matching handler, so the order of handers is now important because
    68 matching is many to one.
    69 
    70 Each virtual type needs an associated virtual table. A virtual table is a
    71 structure with fields for all the virtual members of a type. A virtual type has
    72 all the virtual members of its parent and can add more. It may also update the
    73 values of the virtual members and often does.
     124Virtual types and casts are not part of \CFA's EHM nor are they required for
     125any EHM. But \CFA uses a hierarchial system of exceptions and this feature
     126is leveraged to create that.
     127
     128% Maybe talk about why the virtual system is so minimal.
     129% Created for but not a part of the exception system.
     130
     131The virtual system supports multiple ``trees" of types. Each tree is
     132a simple hierarchy with a single root type. Each type in a tree has exactly
     133one parent -- except for the root type which has zero parents -- and any
     134number of children.
     135Any type that belongs to any of these trees is called a virtual type.
     136
     137% A type's ancestors are its parent and its parent's ancestors.
     138% The root type has no ancestors.
     139% A type's decendents are its children and its children's decendents.
     140
     141Every virtual type also has a list of virtual members. Children inherit
     142their parent's list of virtual members but may add new members to it.
     143It is important to note that these are virtual members, not virtual methods
     144of object-orientated programming, and can be of any type.
     145However, since \CFA has function pointers and they are allowed, virtual
     146members can be used to mimic virtual methods.
     147
     148Each virtual type has a unique id.
     149This unique id and all the virtual members are combined
     150into a virtual table type. Each virtual type has a pointer to a virtual table
     151as a hidden field.
     152
     153Up until this point the virtual system is similar to ones found in
     154object-orientated languages but this where \CFA diverges. Objects encapsulate a
     155single set of behaviours in each type, universally across the entire program,
     156and indeed all programs that use that type definition. In this sense the
     157types are ``closed" and cannot be altered.
     158
     159In \CFA types do not encapsulate any behaviour. Traits are local and
     160types can begin to statify a trait, stop satifying a trait or satify the same
     161trait in a different way at any lexical location in the program.
     162In this sense they are ``open" as they can change at any time. This means it
     163is implossible to pick a single set of functions that repersent the type's
     164implementation across the program.
     165
     166\CFA side-steps this issue by not having a single virtual table for each
     167type. A user can define virtual tables which are filled in at their
     168declaration and given a name. Anywhere that name is visible, even if it was
     169defined locally inside a function (although that means it will not have a
     170static lifetime), it can be used.
     171Specifically, a virtual type is ``bound" to a virtual table which
     172sets the virtual members for that object. The virtual members can be accessed
     173through the object.
    74174
    75175While much of the virtual infrastructure is created, it is currently only used
     
    83183\Cpp syntax for special casts. Both the type of @EXPRESSION@ and @TYPE@ must be
    84184a pointer to a virtual type.
    85 The cast dynamically checks if the @EXPRESSION@ type is the same or a subtype
     185The cast dynamically checks if the @EXPRESSION@ type is the same or a sub-type
    86186of @TYPE@, and if true, returns a pointer to the
    87187@EXPRESSION@ object, otherwise it returns @0p@ (null pointer).
     
    101201\end{cfa}
    102202The trait is defined over two types, the exception type and the virtual table
    103 type. This should be one-to-one, each exception type has only one virtual
     203type. This should be one-to-one: each exception type has only one virtual
    104204table type and vice versa. The only assertion in the trait is
    105205@get_exception_vtable@, which takes a pointer of the exception type and
    106206returns a reference to the virtual table type instance.
    107207
     208% TODO: This section, and all references to get_exception_vtable, are
     209% out-of-data. Perhaps wait until the update is finished before rewriting it.
    108210The function @get_exception_vtable@ is actually a constant function.
    109 Recardless of the value passed in (including the null pointer) it should
     211Regardless of the value passed in (including the null pointer) it should
    110212return a reference to the virtual table instance for that type.
    111213The reason it is a function instead of a constant is that it make type
     
    119221% similar system I know of (except Agda's I guess) so I took it out.
    120222
    121 There are two more traits for exceptions @is_termination_exception@ and
    122 @is_resumption_exception@. They are defined as follows:
    123 
     223There are two more traits for exceptions defined as follows:
    124224\begin{cfa}
    125225trait is_termination_exception(
     
    133233};
    134234\end{cfa}
    135 
    136 In other words they make sure that a given type and virtual type is an
    137 exception and defines one of the two default handlers. These default handlers
    138 are used in the main exception handling operations \see{Exception Handling}
    139 and their use will be detailed there.
    140 
    141 However all three of these traits can be trickly to use directly.
    142 There is a bit of repetition required but
     235Both traits ensure a pair of types are an exception type and its virtual table
     236and defines one of the two default handlers. The default handlers are used
     237as fallbacks and are discussed in detail in \VRef{s:ExceptionHandling}.
     238
     239However, all three of these traits can be tricky to use directly.
     240While there is a bit of repetition required,
    143241the largest issue is that the virtual table type is mangled and not in a user
    144 facing way. So there are three macros that can be used to wrap these traits
    145 when you need to refer to the names:
     242facing way. So these three macros are provided to wrap these traits to
     243simplify referring to the names:
    146244@IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@ and @IS_RESUMPTION_EXCEPTION@.
    147245
    148 All take one or two arguments. The first argument is the name of the
    149 exception type. Its unmangled and mangled form are passed to the trait.
     246All three take one or two arguments. The first argument is the name of the
     247exception type. The macro passes its unmangled and mangled form to the trait.
    150248The second (optional) argument is a parenthesized list of polymorphic
    151 arguments. This argument should only with polymorphic exceptions and the
    152 list will be passed to both types.
    153 In the current set-up the base name and the polymorphic arguments have to
    154 match so these macros can be used without losing flexability.
     249arguments. This argument is only used with polymorphic exceptions and the
     250list is be passed to both types.
     251In the current set-up, the two types always have the same polymorphic
     252arguments so these macros can be used without losing flexibility.
    155253
    156254For example consider a function that is polymorphic over types that have a
     
    162260
    163261\section{Exception Handling}
    164 \CFA provides two kinds of exception handling, termination and resumption.
    165 These twin operations are the core of the exception handling mechanism and
    166 are the reason for the features of exceptions.
     262\label{s:ExceptionHandling}
     263\CFA provides two kinds of exception handling: termination and resumption.
     264These twin operations are the core of \CFA's exception handling mechanism.
    167265This section will cover the general patterns shared by the two operations and
    168266then go on to cover the details each individual operation.
    169267
    170 Both operations follow the same set of steps to do their operation. They both
    171 start with the user preforming a throw on an exception.
    172 Then there is the search for a handler, if one is found than the exception
    173 is caught and the handler is run. After that control returns to normal
    174 execution.
    175 
     268Both operations follow the same set of steps.
     269Both start with the user preforming a raise on an exception.
     270Then the exception propogates up the stack.
     271If a handler is found the exception is caught and the handler is run.
     272After that control returns to normal execution.
    176273If the search fails a default handler is run and then control
    177 returns to normal execution immediately. That is where the default handlers
    178 @defaultTermiationHandler@ and @defaultResumptionHandler@ are used.
     274returns to normal execution after the raise.
     275
     276This general description covers what the two kinds have in common.
     277Differences include how propogation is preformed, where exception continues
     278after an exception is caught and handled and which default handler is run.
    179279
    180280\subsection{Termination}
    181281\label{s:Termination}
    182 
    183 Termination handling is more familiar kind and used in most programming
     282Termination handling is the familiar kind and used in most programming
    184283languages with exception handling.
    185 It is dynamic, non-local goto. If a throw is successful then the stack will
    186 be unwound and control will (usually) continue in a different function on
    187 the call stack. They are commonly used when an error has occured and recovery
    188 is impossible in the current function.
     284It is dynamic, non-local goto. If the raised exception is matched and
     285handled the stack is unwound and control will (usually) continue the function
     286on the call stack that defined the handler.
     287Termination is commonly used when an error has occurred and recovery is
     288impossible locally.
    189289
    190290% (usually) Control can continue in the current function but then a different
    191291% control flow construct should be used.
    192292
    193 A termination throw is started with the @throw@ statement:
     293A termination raise is started with the @throw@ statement:
    194294\begin{cfa}
    195295throw EXPRESSION;
    196296\end{cfa}
    197297The expression must return a reference to a termination exception, where the
    198 termination exception is any type that satifies @is_termination_exception@
    199 at the call site.
    200 Through \CFA's trait system the functions in the traits are passed into the
    201 throw code. A new @defaultTerminationHandler@ can be defined in any scope to
     298termination exception is any type that satisfies the trait
     299@is_termination_exception@ at the call site.
     300Through \CFA's trait system the trait functions are implicity passed into the
     301throw code and the EHM.
     302A new @defaultTerminationHandler@ can be defined in any scope to
    202303change the throw's behavior (see below).
    203304
    204 The throw will copy the provided exception into managed memory. It is the
    205 user's responcibility to ensure the original exception is cleaned up if the
    206 stack is unwound (allocating it on the stack should be sufficient).
    207 
    208 Then the exception system searches the stack using the copied exception.
    209 It starts starts from the throw and proceeds to the base of the stack,
     305The throw will copy the provided exception into managed memory to ensure
     306the exception is not destroyed if the stack is unwound.
     307It is the user's responsibility to ensure the original exception is cleaned
     308up wheither the stack is unwound or not. Allocating it on the stack is
     309usually sufficient.
     310
     311Then propogation starts with the search. \CFA uses a ``first match" rule so
     312matching is preformed with the copied exception as the search continues.
     313It starts from the throwing function and proceeds to the base of the stack,
    210314from callee to caller.
    211315At each stack frame, a check is made for resumption handlers defined by the
     
    214318try {
    215319        GUARDED_BLOCK
    216 } catch (EXCEPTION_TYPE$\(_1\)$ * NAME$\(_1\)$) {
     320} catch (EXCEPTION_TYPE$\(_1\)$ * [NAME$\(_1\)$]) {
    217321        HANDLER_BLOCK$\(_1\)$
    218 } catch (EXCEPTION_TYPE$\(_2\)$ * NAME$\(_2\)$) {
     322} catch (EXCEPTION_TYPE$\(_2\)$ * [NAME$\(_2\)$]) {
    219323        HANDLER_BLOCK$\(_2\)$
    220324}
    221325\end{cfa}
    222 When viewed on its own a try statement will simply exceute the statements in
    223 @GUARDED_BLOCK@ and when those are finished the try statement finishes.
     326When viewed on its own, a try statement will simply execute the statements
     327in @GUARDED_BLOCK@ and when those are finished the try statement finishes.
    224328
    225329However, while the guarded statements are being executed, including any
    226 functions they invoke, all the handlers following the try block are now
    227 or any functions invoked from those
    228 statements, throws an exception, and the exception
    229 is not handled by a try statement further up the stack, the termination
    230 handlers are searched for a matching exception type from top to bottom.
    231 
    232 Exception matching checks the representation of the thrown exception-type is
    233 the same or a descendant type of the exception types in the handler clauses. If
    234 it is the same of a descendent of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$ is
     330invoked functions, all the handlers in the statement are now on the search
     331path. If a termination exception is thrown and not handled further up the
     332stack they will be matched against the exception.
     333
     334Exception matching checks the handler in each catch clause in the order
     335they appear, top to bottom. If the representation of the thrown exception type
     336is the same or a descendant of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$
     337(if provided) is
    235338bound to a pointer to the exception and the statements in @HANDLER_BLOCK@$_i$
    236339are executed. If control reaches the end of the handler, the exception is
    237340freed and control continues after the try statement.
    238341
    239 If no handler is found during the search then the default handler is run.
     342If no termination handler is found during the search then the default handler
     343(@defaultTerminationHandler@) is run.
    240344Through \CFA's trait system the best match at the throw sight will be used.
    241345This function is run and is passed the copied exception. After the default
    242346handler is run control continues after the throw statement.
    243347
    244 There is a global @defaultTerminationHandler@ that cancels the current stack
    245 with the copied exception. However it is generic over all exception types so
    246 new default handlers can be defined for different exception types and so
    247 different exception types can have different default handlers.
     348There is a global @defaultTerminationHandler@ that is polymorphic over all
     349exception types. Since it is so general a more specific handler can be
     350defined and will be used for those types, effectively overriding the handler
     351for particular exception type.
     352The global default termination handler performs a cancellation
     353\see{\VRef{s:Cancellation}} on the current stack with the copied exception.
    248354
    249355\subsection{Resumption}
    250356\label{s:Resumption}
    251357
    252 Resumption exception handling is a less common form than termination but is
    253 just as old~\cite{Goodenough75} and is in some sense simpler.
    254 It is a dynamic, non-local function call. If the throw is successful a
    255 closure will be taken from up the stack and executed, after which the throwing
    256 function will continue executing.
    257 These are most often used when an error occured and if the error is repaired
     358Resumption exception handling is less common than termination but is
     359just as old~\cite{Goodenough75} and is simpler in many ways.
     360It is a dynamic, non-local function call. If the raised exception is
     361matched a closure will be taken from up the stack and executed,
     362after which the raising function will continue executing.
     363These are most often used when an error occurred and if the error is repaired
    258364then the function can continue.
    259365
     
    262368throwResume EXPRESSION;
    263369\end{cfa}
    264 The semantics of the @throwResume@ statement are like the @throw@, but the
    265 expression has return a reference a type that satifies the trait
    266 @is_resumption_exception@. The assertions from this trait are available to
     370It works much the same way as the termination throw.
     371The expression must return a reference to a resumption exception,
     372where the resumption exception is any type that satisfies the trait
     373@is_resumption_exception@ at the call site.
     374The assertions from this trait are available to
    267375the exception system while handling the exception.
    268376
    269 At runtime, no copies are made. As the stack is not unwound the exception and
     377At run-time, no exception copy is made.
     378As the stack is not unwound the exception and
    270379any values on the stack will remain in scope while the resumption is handled.
    271380
    272 Then the exception system searches the stack using the provided exception.
    273 It starts starts from the throw and proceeds to the base of the stack,
    274 from callee to caller.
     381The EHM then begins propogation. The search starts from the raise in the
     382resuming function and proceeds to the base of the stack, from callee to caller.
    275383At each stack frame, a check is made for resumption handlers defined by the
    276384@catchResume@ clauses of a @try@ statement.
     
    278386try {
    279387        GUARDED_BLOCK
    280 } catchResume (EXCEPTION_TYPE$\(_1\)$ * NAME$\(_1\)$) {
     388} catchResume (EXCEPTION_TYPE$\(_1\)$ * [NAME$\(_1\)$]) {
    281389        HANDLER_BLOCK$\(_1\)$
    282 } catchResume (EXCEPTION_TYPE$\(_2\)$ * NAME$\(_2\)$) {
     390} catchResume (EXCEPTION_TYPE$\(_2\)$ * [NAME$\(_2\)$]) {
    283391        HANDLER_BLOCK$\(_2\)$
    284392}
    285393\end{cfa}
    286 If the handlers are not involved in a search this will simply execute the
    287 @GUARDED_BLOCK@ and then continue to the next statement.
    288 Its purpose is to add handlers onto the stack.
    289 (Note, termination and resumption handlers may be intermixed in a @try@
    290 statement but the kind of throw must be the same as the handler for it to be
    291 considered as a possible match.)
    292 
    293 If a search for a resumption handler reaches a try block it will check each
    294 @catchResume@ clause, top-to-bottom.
    295 At each handler if the thrown exception is or is a child type of
    296 @EXCEPTION_TYPE@$_i$ then the a pointer to the exception is bound to
    297 @NAME@$_i$ and then @HANDLER_BLOCK@$_i$ is executed. After the block is
    298 finished control will return to the @throwResume@ statement.
     394% I wonder if there would be some good central place for this.
     395Note that termination handlers and resumption handlers may be used together
     396in a single try statement, intermixing @catch@ and @catchResume@ freely.
     397Each type of handler will only interact with exceptions from the matching
     398type of raise.
     399When a try statement is executed it simply executes the statements in the
     400@GUARDED_BLOCK@ and then finishes.
     401
     402However, while the guarded statements are being executed, including any
     403invoked functions, all the handlers in the statement are now on the search
     404path. If a resumption exception is reported and not handled further up the
     405stack they will be matched against the exception.
     406
     407Exception matching checks the handler in each catch clause in the order
     408they appear, top to bottom. If the representation of the thrown exception type
     409is the same or a descendant of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$
     410(if provided) is bound to a pointer to the exception and the statements in
     411@HANDLER_BLOCK@$_i$ are executed.
     412If control reaches the end of the handler, execution continues after the
     413the raise statement that raised the handled exception.
    299414
    300415Like termination, if no resumption handler is found, the default handler
     
    302417call sight according to \CFA's overloading rules. The default handler is
    303418passed the exception given to the throw. When the default handler finishes
    304 execution continues after the throw statement.
     419execution continues after the raise statement.
    305420
    306421There is a global @defaultResumptionHandler@ is polymorphic over all
    307422termination exceptions and preforms a termination throw on the exception.
    308 The @defaultTerminationHandler@ for that throw is matched at the original
    309 throw statement (the resumption @throwResume@) and it can be customized by
     423The @defaultTerminationHandler@ for that raise is matched at the original
     424raise statement (the resumption @throwResume@) and it can be customized by
    310425introducing a new or better match as well.
    311426
    312 % \subsubsection?
    313 
     427\subsubsection{Resumption Marking}
    314428A key difference between resumption and termination is that resumption does
    315429not unwind the stack. A side effect that is that when a handler is matched
     
    331445search and match the handler in the @catchResume@ clause. This will be
    332446call and placed on the stack on top of the try-block. The second throw then
    333 throws and will seach the same try block and put call another instance of the
     447throws and will search the same try block and put call another instance of the
    334448same handler leading to an infinite loop.
    335449
     
    337451can form with multiple handlers and different exception types.
    338452
    339 To prevent all of these cases we mask sections of the stack, or equvilantly
    340 the try statements on the stack, so that the resumption seach skips over
    341 them and continues with the next unmasked section of the stack.
    342 
    343 A section of the stack is marked when it is searched to see if it contains
    344 a handler for an exception and unmarked when that exception has been handled
    345 or the search was completed without finding a handler.
    346 
    347 % This might need a diagram. But it is an important part of the justification
    348 % of the design of the traversal order.
    349 \begin{verbatim}
    350        throwResume2 ----------.
    351             |                 |
    352  generated from handler       |
    353             |                 |
    354          handler              |
    355             |                 |
    356         throwResume1 -----.   :
    357             |             |   :
    358            try            |   : search skip
    359             |             |   :
    360         catchResume  <----'   :
    361             |                 |
    362 \end{verbatim}
    363 
    364 The rules can be remembered as thinking about what would be searched in
    365 termination. So when a throw happens in a handler; a termination handler
    366 skips everything from the original throw to the original catch because that
    367 part of the stack has been unwound, a resumption handler skips the same
    368 section of stack because it has been masked.
    369 A throw in a default handler will preform the same search as the original
    370 throw because; for termination nothing has been unwound, for resumption
    371 the mask will be the same.
    372 
    373 The symmetry with termination is why this pattern was picked. Other patterns,
    374 such as marking just the handlers that caught, also work but lack the
    375 symmetry whih means there is more to remember.
     453To prevent all of these cases we mark try statements on the stack.
     454A try statement is marked when a match check is preformed with it and an
     455exception. The statement will be unmarked when the handling of that exception
     456is completed or the search completes without finding a handler.
     457While a try statement is marked its handlers are never matched, effectify
     458skipping over it to the next try statement.
     459
     460\begin{center}
     461\input{stack-marking}
     462\end{center}
     463
     464These rules mirror what happens with termination.
     465When a termination throw happens in a handler the search will not look at
     466any handlers from the original throw to the original catch because that
     467part of the stack has been unwound.
     468A resumption raise in the same situation wants to search the entire stack,
     469but it will not try to match the exception with try statements in the section
     470that would have been unwound as they are marked.
     471
     472The symmetry between resumption termination is why this pattern was picked.
     473Other patterns, such as marking just the handlers that caught, also work but
     474lack the symmetry means there are less rules to remember.
    376475
    377476\section{Conditional Catch}
     
    379478condition to further control which exceptions they handle:
    380479\begin{cfa}
    381 catch (EXCEPTION_TYPE * NAME ; CONDITION)
     480catch (EXCEPTION_TYPE * [NAME] ; CONDITION)
    382481\end{cfa}
    383482First, the same semantics is used to match the exception type. Second, if the
     
    387486matches. Otherwise, the exception search continues as if the exception type
    388487did not match.
    389 \begin{cfa}
    390 try {
    391         f1 = open( ... );
    392         f2 = open( ... );
     488
     489The condition matching allows finer matching by allowing the match to check
     490more kinds of information than just the exception type.
     491\begin{cfa}
     492try {
     493        handle1 = open( f1, ... );
     494        handle2 = open( f2, ... );
     495        handle3 = open( f3, ... );
    393496        ...
    394497} catch( IOFailure * f ; fd( f ) == f1 ) {
    395         // only handle IO failure for f1
    396 }
    397 \end{cfa}
    398 Note, catching @IOFailure@, checking for @f1@ in the handler, and reraising the
    399 exception if not @f1@ is different because the reraise does not examine any of
    400 remaining handlers in the current try statement.
    401 
    402 \section{Rethrowing}
    403 \colour{red}{From Andrew: I recomend we talk about why the language doesn't
    404 have rethrows/reraises instead.}
    405 
    406 \label{s:Rethrowing}
     498        // Only handle IO failure for f1.
     499} catch( IOFailure * f ; fd( f ) == f3 ) {
     500        // Only handle IO failure for f3.
     501}
     502// Can't handle a failure relating to f2 here.
     503\end{cfa}
     504In this example the file that experianced the IO error is used to decide
     505which handler should be run, if any at all.
     506
     507\begin{comment}
     508% I know I actually haven't got rid of them yet, but I'm going to try
     509% to write it as if I had and see if that makes sense:
     510\section{Reraising}
     511\label{s:Reraising}
    407512Within the handler block or functions called from the handler block, it is
    408513possible to reraise the most recently caught exception with @throw@ or
     
    423528is part of an unwound stack frame. To prevent this problem, a new default
    424529handler is generated that does a program-level abort.
     530\end{comment}
     531
     532\subsection{Comparison with Reraising}
     533A more popular way to allow handlers to match in more detail is to reraise
     534the exception after it has been caught if it could not be handled here.
     535On the surface these two features seem interchangable.
     536
     537If we used @throw;@ to start a termination reraise then these two statements
     538would have the same behaviour:
     539\begin{cfa}
     540try {
     541    do_work_may_throw();
     542} catch(exception_t * exc ; can_handle(exc)) {
     543    handle(exc);
     544}
     545\end{cfa}
     546
     547\begin{cfa}
     548try {
     549    do_work_may_throw();
     550} catch(exception_t * exc) {
     551    if (can_handle(exc)) {
     552        handle(exc);
     553    } else {
     554        throw;
     555    }
     556}
     557\end{cfa}
     558If there are further handlers after this handler only the first version will
     559check them. If multiple handlers on a single try block could handle the same
     560exception the translations get more complex but they are equivilantly
     561powerful.
     562
     563Until stack unwinding comes into the picture. In termination handling, a
     564conditional catch happens before the stack is unwound, but a reraise happens
     565afterwards. Normally this might only cause you to loose some debug
     566information you could get from a stack trace (and that can be side stepped
     567entirely by collecting information during the unwind). But for \CFA there is
     568another issue, if the exception isn't handled the default handler should be
     569run at the site of the original raise.
     570
     571There are two problems with this: the site of the original raise doesn't
     572exist anymore and the default handler might not exist anymore. The site will
     573always be removed as part of the unwinding, often with the entirety of the
     574function it was in. The default handler could be a stack allocated nested
     575function removed during the unwind.
     576
     577This means actually trying to pretend the catch didn't happening, continuing
     578the original raise instead of starting a new one, is infeasible.
     579That is the expected behaviour for most languages and we can't replicate
     580that behaviour.
    425581
    426582\section{Finally Clauses}
     583\label{s:FinallyClauses}
    427584Finally clauses are used to preform unconditional clean-up when leaving a
    428 scope. They are placed at the end of a try statement:
     585scope and are placed at the end of a try statement after any handler clauses:
    429586\begin{cfa}
    430587try {
     
    442599
    443600Execution of the finally block should always finish, meaning control runs off
    444 the end of the block. This requirement ensures always continues as if the
    445 finally clause is not present, \ie finally is for cleanup not changing control
    446 flow. Because of this requirement, local control flow out of the finally block
     601the end of the block. This requirement ensures control always continues as if
     602the finally clause is not present, \ie finally is for cleanup not changing
     603control flow.
     604Because of this requirement, local control flow out of the finally block
    447605is forbidden. The compiler precludes any @break@, @continue@, @fallthru@ or
    448606@return@ that causes control to leave the finally block. Other ways to leave
    449607the finally block, such as a long jump or termination are much harder to check,
    450 and at best requiring additional run-time overhead, and so are mearly
     608and at best requiring additional run-time overhead, and so are only
    451609discouraged.
    452610
    453 Not all languages with exceptions have finally clauses. Notably \Cpp does
     611Not all languages with unwinding have finally clauses. Notably \Cpp does
    454612without it as descructors serve a similar role. Although destructors and
    455613finally clauses can be used in many of the same areas they have their own
    456614use cases like top-level functions and lambda functions with closures.
    457615Destructors take a bit more work to set up but are much easier to reuse while
    458 finally clauses are good for once offs and can include local information.
     616finally clauses are good for one-off uses and
     617can easily include local information.
    459618
    460619\section{Cancellation}
     620\label{s:Cancellation}
    461621Cancellation is a stack-level abort, which can be thought of as as an
    462 uncatchable termination. It unwinds the entirety of the current stack, and if
     622uncatchable termination. It unwinds the entire current stack, and if
    463623possible forwards the cancellation exception to a different stack.
    464624
     
    466626There is no special statement for starting a cancellation; instead the standard
    467627library function @cancel_stack@ is called passing an exception. Unlike a
    468 throw, this exception is not used in matching only to pass information about
     628raise, this exception is not used in matching only to pass information about
    469629the cause of the cancellation.
    470 (This also means matching cannot fail so there is no default handler either.)
    471 
    472 After @cancel_stack@ is called the exception is copied into the exception
    473 handling mechanism's memory. Then the entirety of the current stack is
     630(This also means matching cannot fail so there is no default handler.)
     631
     632After @cancel_stack@ is called the exception is copied into the EHM's memory
     633and the current stack is
    474634unwound. After that it depends one which stack is being cancelled.
    475635\begin{description}
    476636\item[Main Stack:]
    477637The main stack is the one used by the program main at the start of execution,
    478 and is the only stack in a sequential program. Even in a concurrent program
    479 the main stack is only dependent on the environment that started the program.
    480 Hence, when the main stack is cancelled there is nowhere else in the program
    481 to notify. After the stack is unwound, there is a program-level abort.
     638and is the only stack in a sequential program.
     639After the main stack is unwound there is a program-level abort.
     640
     641There are two reasons for this. The first is that it obviously had to do this
     642in a sequential program as there is nothing else to notify and the simplicity
     643of keeping the same behaviour in sequential and concurrent programs is good.
     644Also, even in concurrent programs there is no stack that an innate connection
     645to, so it would have be explicitly managed.
    482646
    483647\item[Thread Stack:]
    484 A thread stack is created for a @thread@ object or object that satisfies the
    485 @is_thread@ trait. A thread only has two points of communication that must
    486 happen: start and join. As the thread must be running to perform a
    487 cancellation, it must occur after start and before join, so join is used
    488 for communication here.
    489 After the stack is unwound, the thread halts and waits for
    490 another thread to join with it. The joining thread checks for a cancellation,
    491 and if present, resumes exception @ThreadCancelled@.
    492 
    493 There is a subtle difference between the explicit join (@join@ function) and
    494 implicit join (from a destructor call). The explicit join takes the default
    495 handler (@defaultResumptionHandler@) from its calling context, which is used if
    496 the exception is not caught. The implicit join does a program abort instead.
    497 
    498 This semantics is for safety. If an unwind is triggered while another unwind
    499 is underway only one of them can proceed as they both want to ``consume'' the
    500 stack. Letting both try to proceed leads to very undefined behaviour.
    501 Both termination and cancellation involve unwinding and, since the default
    502 @defaultResumptionHandler@ preforms a termination that could more easily
    503 happen in an implicate join inside a destructor. So there is an error message
    504 and an abort instead.
    505 \todo{Perhaps have a more general disucssion of unwind collisions before
    506 this point.}
    507 
    508 The recommended way to avoid the abort is to handle the intial resumption
    509 from the implicate join. If required you may put an explicate join inside a
    510 finally clause to disable the check and use the local
    511 @defaultResumptionHandler@ instead.
    512 
    513 \item[Coroutine Stack:] A coroutine stack is created for a @coroutine@ object
    514 or object that satisfies the @is_coroutine@ trait. A coroutine only knows of
    515 two other coroutines, its starter and its last resumer. Of the two the last
    516 resumer has the tightest coupling to the coroutine it activated and the most
    517 up-to-date information.
    518 
    519 Hence, cancellation of the active coroutine is forwarded to the last resumer
    520 after the stack is unwound. When the resumer restarts, it resumes exception
    521 @CoroutineCancelled@, which is polymorphic over the coroutine type and has a
    522 pointer to the cancelled coroutine.
    523 
    524 The resume function also has an assertion that the @defaultResumptionHandler@
    525 for the exception. So it will use the default handler like a regular throw.
     648A thread stack is created for a \CFA @thread@ object or object that satisfies
     649the @is_thread@ trait.
     650After a thread stack is unwound there exception is stored until another
     651thread attempts to join with it. Then the exception @ThreadCancelled@,
     652which stores a reference to the thread and to the exception passed to the
     653cancellation, is reported from the join.
     654There is one difference between an explicit join (with the @join@ function)
     655and an implicit join (from a destructor call). The explicit join takes the
     656default handler (@defaultResumptionHandler@) from its calling context while
     657the implicit join provides its own which does a program abort if the
     658@ThreadCancelled@ exception cannot be handled.
     659
     660Communication is done at join because a thread only has to have to points of
     661communication with other threads: start and join.
     662Since a thread must be running to perform a cancellation (and cannot be
     663cancelled from another stack), the cancellation must be after start and
     664before the join. So join is the one that we will use.
     665
     666% TODO: Find somewhere to discuss unwind collisions.
     667The difference between the explicit and implicit join is for safety and
     668debugging. It helps prevent unwinding collisions by avoiding throwing from
     669a destructor and prevents cascading the error across multiple threads if
     670the user is not equipped to deal with it.
     671Also you can always add an explicit join if that is the desired behaviour.
     672
     673\item[Coroutine Stack:]
     674A coroutine stack is created for a @coroutine@ object or object that
     675satisfies the @is_coroutine@ trait.
     676After a coroutine stack is unwound control returns to the resume function
     677that most recently resumed it. The resume statement reports a
     678@CoroutineCancelled@ exception, which contains a references to the cancelled
     679coroutine and the exception used to cancel it.
     680The resume function also takes the @defaultResumptionHandler@ from the
     681caller's context and passes it to the internal report.
     682
     683A coroutine knows of two other coroutines, its starter and its last resumer.
     684The starter has a much more distant connection while the last resumer just
     685(in terms of coroutine state) called resume on this coroutine, so the message
     686is passed to the latter.
    526687\end{description}
  • doc/theses/andrew_beach_MMath/future.tex

    rfeacef9 r5407cdc  
    8383patterns to find the handler.
    8484
     85\section{Checked Exceptions}
     86Checked exceptions make exceptions part of a function's type by adding the
     87exception signature. An exception signature must declare all checked
     88exceptions that could propogate from the function (either because they were
     89raised inside the function or came from a sub-function). This improves safety
     90by making sure every checked exception is either handled or consciously
     91passed on.
     92
     93However checked exceptions were never seriously considered for this project
     94for two reasons. The first is due to time constraints, even copying an
     95existing checked exception system would be pushing the remaining time and
     96trying to address the second problem would take even longer. The second
     97problem is that checked exceptions have some real usability trade-offs in
     98exchange for the increased safety.
     99
     100These trade-offs are most problematic when trying to pass exceptions through
     101higher-order functions from the functions the user passed into the
     102higher-order function. There are no well known solutions to this problem
     103that were statifactory for \CFA (which carries some of C's flexability
     104over safety design) so one would have to be researched and developed.
     105
     106Follow-up work might add checked exceptions to \CFA, possibly using
     107polymorphic exception signatures, a form of tunneling\cite{Zhang19} or
     108checked and unchecked raises.
     109
    85110\section{Zero-Cost Try}
    86111\CFA does not have zero-cost try-statements because the compiler generates C
  • doc/theses/andrew_beach_MMath/implement.tex

    rfeacef9 r5407cdc  
    1313library.
    1414
     15\subsection{Virtual Type}
     16Virtual types only have one change to their structure, the addition of a
     17pointer to the virtual table. This is always the first field so that
     18if it is cast to a supertype the field's location is still known.
     19
     20This field is set as part of all new generated constructors.
     21\todo{They only come as part exceptions and don't work.}
     22After the object is created the field is constant.
     23
     24However it can be read from, internally it is just a regular field called
     25@virtual_table@. Dereferencing it gives the virtual table and access to the
     26type's virtual members.
     27
    1528\subsection{Virtual Table}
     29Every time a virtual type is defined the new virtual table type must also be
     30defined.
     31
     32The unique instance is important because the address of the virtual table
     33instance is used as the identifier for the virtual type. So a pointer to the
     34virtual table and the ID for the virtual type are interchangable.
     35\todo{Unique instances might be going so we will have to talk about the new
     36system instead.}
     37
     38The first step in putting it all together is to create the virtual table type.
     39The virtual table type is just a structure and can be described in terms of
     40its fields. The first field is always the parent type ID (or a pointer to
     41the parent virtual table) or 0 (the null pointer).
     42Next are other fields on the parent virtual table are repeated.
     43Finally are the fields used to store any new virtual members of the new
     44The virtual type
     45
    1646The virtual system is accessed through a private constant field inserted at the
    1747beginning of every virtual type, called the virtual-table pointer. This field
    1848points at a type's virtual table and is assigned during the object's
    19 construction.  The address of a virtual table acts as the unique identifier for
     49construction. The address of a virtual table acts as the unique identifier for
    2050the virtual type, and the first field of a virtual table is a pointer to the
    21 parent virtual-table or @0p@.  The remaining fields are duplicated from the
     51parent virtual-table or @0p@. The remaining fields are duplicated from the
    2252parent tables in this type's inheritance chain, followed by any fields this type
    23 introduces. Parent fields are duplicated so they can be changed (\CC
    24 \lstinline[language=c++]|override|), so that references to the dispatched type
     53introduces. Parent fields are duplicated so they can be changed (all virtual
     54members are overridable), so that references to the dispatched type
    2555are replaced with the current virtual type.
    26 \PAB{Can you create a simple diagram of the layout?}
    2756% These are always taken by pointer or reference.
     57
     58% Simple ascii diragram:
     59\begin{verbatim}
     60parent_pointer  \
     61parent_field0   |
     62...             | Same layout as parent.
     63parent_fieldN   /
     64child_field0
     65...
     66child_fieldN
     67\end{verbatim}
     68\todo{Refine the diagram}
    2869
    2970% For each virtual type, a virtual table is constructed. This is both a new type
     
    3475A virtual table is created when the virtual type is created. The name of the
    3576type is created by mangling the name of the base type. The name of the instance
    36 is also generated by name mangling.  The fields are initialized automatically.
     77is also generated by name mangling. The fields are initialized automatically.
    3778The parent field is initialized by getting the type of the parent field and
    3879using that to calculate the mangled name of the parent's virtual table type.
     
    67108\begin{sloppypar}
    68109Coroutines and threads need instances of @CoroutineCancelled@ and
    69 @ThreadCancelled@ respectively to use all of their functionality.  When a new
     110@ThreadCancelled@ respectively to use all of their functionality. When a new
    70111data type is declared with @coroutine@ or @thread@ the forward declaration for
    71112the instance is created as well. The definition of the virtual table is created
     
    80121The function is
    81122\begin{cfa}
    82 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent,
     123void * __cfa__virtual_cast(
     124        struct __cfa__parent_vtable const * parent,
    83125        struct __cfa__parent_vtable const * const * child );
    84 }
    85126\end{cfa}
    86 and it is implemented in the standard library. It takes a pointer to the target
    87 type's virtual table and the object pointer being cast. The function performs a
    88 linear search starting at the object's virtual-table and walking through the
    89 the parent pointers, checking to if it or any of its ancestors are the same as
    90 the target-type virtual table-pointer.
    91 
    92 For the generated code, a forward declaration of the virtual works as follows.
    93 There is a forward declaration of @__cfa__virtual_cast@ in every \CFA file so
    94 it can just be used. The object argument is the expression being cast so that
    95 is just placed in the argument list.
    96 
    97 To build the target type parameter, the compiler creates a mapping from
    98 concrete type-name -- so for polymorphic types the parameters are filled in --
    99 to virtual table address. Every virtual table declaration is added to the this
    100 table; repeats are ignored unless they have conflicting definitions.  Note,
    101 these declarations do not have to be in scope, but they should usually be
    102 introduced as part of the type definition.
    103 
    104 \PAB{I do not understood all of \VRef{s:VirtualSystem}. I think you need to
    105 write more to make it clear.}
    106 
     127and it is implemented in the standard library. The structure reperents the
     128head of a vtable which is the pointer to the parent virtual table. The
     129@parent@ points directly at the parent type virtual table while the @child@
     130points at the object of the (possibe) child type.
     131
     132In terms of the virtual cast expression, @parent@ comes from looking up the
     133type being cast to and @child@ is the result of the expression being cast.
     134Because the complier outputs C code, some type C type casts are also used.
     135The last bit of glue is an map that saves every virtual type the compiler
     136sees. This is used to check the type used in a virtual cast is a virtual
     137type and to get its virtual table.
     138(It also checks for conflicting definitions.)
     139
     140Inside the function it is a simple conditional. If the type repersented by
     141@parent@ is or is an ancestor of the type repersented by @*child@ (it
     142requires one more level of derefence to pass through the object) then @child@
     143is returned, otherwise the null pointer is returned.
     144
     145The check itself is preformed is a simple linear search. If the child
     146virtual table or any of its ancestors (which are retreved through the first
     147field of every virtual table) are the same as the parent virtual table then
     148the cast succeeds.
    107149
    108150\section{Exceptions}
     
    121163stack. On function entry and return, unwinding is handled directly by the code
    122164embedded in the function. Usually, the stack-frame size is known statically
    123 based on parameter and local variable declarations.  For dynamically-sized
     165based on parameter and local variable declarations. For dynamically-sized
    124166local variables, a runtime computation is necessary to know the frame
    125167size. Finally, a function's frame-size may change during execution as local
     
    179221
    180222To use libunwind, each function must have a personality function and a Language
    181 Specific Data Area (LSDA).  The LSDA has the unique information for each
     223Specific Data Area (LSDA). The LSDA has the unique information for each
    182224function to tell the personality function where a function is executing, its
    183 current stack frame, and what handlers should be checked.  Theoretically, the
     225current stack frame, and what handlers should be checked. Theoretically, the
    184226LSDA can contain any information but conventionally it is a table with entries
    185227representing regions of the function and what has to be done there during
     
    196238
    197239The GCC compilation flag @-fexceptions@ causes the generation of an LSDA and
    198 attaches its personality function. \PAB{to what is it attached?}  However, this
    199 flag only handles the cleanup attribute
     240attaches its personality function. However, this
     241flag only handles the cleanup attribute:
     242\todo{Peter: What is attached? Andrew: It uses the .cfi\_personality directive
     243and that's all I know.}
    200244\begin{cfa}
    201245void clean_up( int * var ) { ... }
    202 int avar __attribute__(( __cleanup(clean_up) ));
     246int avar __attribute__(( cleanup(clean_up) ));
    203247\end{cfa}
    204 which is used on a variable and specifies a function, \eg @clean_up@, run when
    205 the variable goes out of scope. The function is passed a pointer to the object
    206 so it can be used to mimic destructors. However, this feature cannot be used to
    207 mimic @try@ statements.
     248which is used on a variable and specifies a function, in this case @clean_up@,
     249run when the variable goes out of scope.
     250The function is passed a pointer to the object being removed from the stack
     251so it can be used to mimic destructors.
     252However, this feature cannot be used to mimic @try@ statements as it cannot
     253control the unwinding.
    208254
    209255\subsection{Personality Functions}
    210 Personality functions have a complex interface specified by libunwind.  This
     256Personality functions have a complex interface specified by libunwind. This
    211257section covers some of the important parts of the interface.
    212258
    213 A personality function performs four tasks, although not all have to be
    214 present.
     259A personality function can preform different actions depending on how it is
     260called.
    215261\begin{lstlisting}[language=C,{moredelim=**[is][\color{red}]{@}{@}}]
    216262typedef _Unwind_Reason_Code (*@_Unwind_Personality_Fn@) (
     
    225271\item
    226272@_UA_SEARCH_PHASE@ specifies a search phase and tells the personality function
    227 to check for handlers.  If there is a handler in a stack frame, as defined by
     273to check for handlers. If there is a handler in a stack frame, as defined by
    228274the language, the personality function returns @_URC_HANDLER_FOUND@; otherwise
    229275it return @_URC_CONTINUE_UNWIND@.
     
    296342\end{cfa}
    297343It also unwinds the stack but it does not use the search phase. Instead another
    298 function, the stop function, is used to stop searching.  The exception is the
     344function, the stop function, is used to stop searching. The exception is the
    299345same as the one passed to raise exception. The extra arguments are the stop
    300346function and the stop parameter. The stop function has a similar interface as a
     
    318364
    319365\begin{sloppypar}
    320 Its arguments are the same as the paired personality function.  The actions
     366Its arguments are the same as the paired personality function. The actions
    321367@_UA_CLEANUP_PHASE@ and @_UA_FORCE_UNWIND@ are always set when it is
    322368called. Beyond the libunwind standard, both GCC and Clang add an extra action
     
    343389strong symbol replacing the sequential version.
    344390
    345 % The version of the function defined in @libcfa@ is very simple. It returns a
    346 % pointer to a global static variable. With only one stack this global instance
    347 % is associated with the only stack.
    348 
    349 For coroutines, @this_exception_context@ accesses the exception context stored
    350 at the base of the stack. For threads, @this_exception_context@ uses the
    351 concurrency library to access the current stack of the thread or coroutine
    352 being executed by the thread, and then accesses the exception context stored at
    353 the base of this stack.
     391The sequential @this_exception_context@ returns a hard-coded pointer to the
     392global execption context.
     393The concurrent version adds the exception context to the data stored at the
     394base of each stack. When @this_exception_context@ is called it retrieves the
     395active stack and returns the address of the context saved there.
    354396
    355397\section{Termination}
     
    369411per-exception storage.
    370412
    371 Exceptions are stored in variable-sized blocks. \PAB{Show a memory layout
    372 figure.} The first component is a fixed sized data structure that contains the
     413[Quick ASCII diagram to get started.]
     414\begin{verbatim}
     415Fixed Header  | _Unwind_Exception   <- pointer target
     416              |
     417              | Cforall storage
     418              |
     419Variable Body | the exception       <- fixed offset
     420              V ...
     421\end{verbatim}
     422
     423Exceptions are stored in variable-sized blocks.
     424The first component is a fixed sized data structure that contains the
    373425information for libunwind and the exception system. The second component is an
    374426area of memory big enough to store the exception. Macros with pointer arthritic
     
    388440exception type. The size and copy function are used immediately to copy an
    389441exception into managed memory. After the exception is handled the free function
    390 is used to clean up the exception and then the entire node is passed to free.
     442is used to clean up the exception and then the entire node is passed to free
     443so the memory can be given back to the heap.
    391444
    392445\subsection{Try Statements and Catch Clauses}
     
    399452library. The contents of a try block and the termination handlers are converted
    400453into functions. These are then passed to the try terminate function and it
    401 calls them. This approach puts a try statement in its own functions so that no
    402 function has to deal with both termination handlers and destructors. \PAB{I do
    403 not understand the previous sentence.}
    404 
    405 This function has some custom embedded assembly that defines \emph{its}
    406 personality function and LSDA. The assembly is created with handcrafted C @asm@
    407 statements, which is why there is only one version of it. The personality
    408 function is structured so that it can be expanded, but currently it only
    409 handles this one function.  Notably, it does not handle any destructors so the
    410 function is constructed so that it does need to run it. \PAB{I do not
    411 understand the previous sentence.}
     454calls them.
     455Because this function is known and fixed (and not an arbitrary function that
     456happens to contain a try statement) this means the LSDA can be generated ahead
     457of time.
     458
     459Both the LSDA and the personality function are set ahead of time using
     460embedded assembly. This is handcrafted using C @asm@ statements and contains
     461enough information for the single try statement the function repersents.
    412462
    413463The three functions passed to try terminate are:
     
    419469
    420470\item[match function:] This function is called during the search phase and
    421 decides if a catch clause matches the termination exception.  It is constructed
     471decides if a catch clause matches the termination exception. It is constructed
    422472from the conditional part of each handler and runs each check, top to bottom,
    423473in turn, first checking to see if the exception type matches and then if the
     
    428478\item[handler function:] This function handles the exception. It takes a
    429479pointer to the exception and the handler's id and returns nothing. It is called
    430 after the cleanup phase.  It is constructed by stitching together the bodies of
     480after the cleanup phase. It is constructed by stitching together the bodies of
    431481each handler and dispatches to the selected handler.
    432482\end{description}
     
    434484can be used to create closures, functions that can refer to the state of other
    435485functions on the stack. This approach allows the functions to refer to all the
    436 variables in scope for the function containing the @try@ statement.  These
     486variables in scope for the function containing the @try@ statement. These
    437487nested functions and all other functions besides @__cfaehm_try_terminate@ in
    438488\CFA use the GCC personality function and the @-fexceptions@ flag to generate
     
    455505handler that matches. If no handler matches then the function returns
    456506false. Otherwise the matching handler is run; if it completes successfully, the
    457 function returns true. Reresume, through the @throwResume;@ statement, cause
    458 the function to return true.
     507function returns true. Rethrowing, through the @throwResume;@ statement,
     508causes the function to return true.
    459509
    460510% Recursive Resumption Stuff:
     
    482532providing zero-cost enter/exit using the LSDA. Unfortunately, there is no way
    483533to return from a libunwind search without installing a handler or raising an
    484 error.  Although workarounds might be possible, they are beyond the scope of
     534error. Although workarounds might be possible, they are beyond the scope of
    485535this thesis. The current resumption implementation has simplicity in its
    486536favour.
     
    503553
    504554Cancellation also uses libunwind to do its stack traversal and unwinding,
    505 however it uses a different primary function @_Unwind_ForcedUnwind@.  Details
     555however it uses a different primary function @_Unwind_ForcedUnwind@. Details
    506556of its interface can be found in the \VRef{s:ForcedUnwind}.
    507557
     
    511561its main coroutine and the coroutine it is currently executing.
    512562
    513 The first check is if the current thread's main and current coroutine do not
    514 match, implying a coroutine cancellation; otherwise, it is a thread
    515 cancellation. Otherwise it is a main thread cancellation. \PAB{Previous
    516 sentence does not make sense.}
     563So if the active thread's main and current coroutine are the same. If they
     564are then the current stack is a thread stack, otherwise it is a coroutine
     565stack. If it is a thread stack then an equality check with the stored main
     566thread pointer and current thread pointer is enough to tell if the current
     567thread is the main thread or not.
    517568
    518569However, if the threading library is not linked, the sequential execution is on
  • doc/theses/andrew_beach_MMath/uw-ethesis.tex

    rfeacef9 r5407cdc  
    7474% ======================================================================
    7575%   D O C U M E N T   P R E A M B L E
    76 % Specify the document class, default style attributes, page dimensions, etc.
    77 % For hyperlinked PDF, suitable for viewing on a computer, use this:
    78 \documentclass[letterpaper,12pt,titlepage,oneside,final]{book}
    79 
    80 % For PDF, suitable for double-sided printing, change the PrintVersion
    81 % variable below to "true" and use this \documentclass line instead of the
    82 % one above:
    83 %\documentclass[letterpaper,12pt,titlepage,openright,twoside,final]{book}
    84 
    85 \usepackage{etoolbox}
     76\RequirePackage{etoolbox}
     77
     78% Control if this for print (set true) or will stay digital (default).
     79% Print is two sided, digital uses more colours.
     80\newtoggle{printversion}
     81%\toggletrue{printversion}
     82
     83\iftoggle{printversion}{%
     84  \documentclass[letterpaper,12pt,titlepage,openright,twoside,final]{book}
     85}{%
     86  \documentclass[letterpaper,12pt,titlepage,oneside,final]{book}
     87}
    8688
    8789% Some LaTeX commands I define for my own nomenclature.
     
    9496% Anything defined here may be redefined by packages added below...
    9597
    96 % This package allows if-then-else control structures.
    97 \usepackage{ifthen}
    98 \newboolean{PrintVersion}
    99 \setboolean{PrintVersion}{false}
    100 % CHANGE THIS VALUE TO "true" as necessary, to improve printed results for
    101 % hard copies by overriding some options of the hyperref package, called below.
    102 
    103 %\usepackage{nomencl} % For a nomenclature (optional; available from ctan.org)
     98% For a nomenclature (optional; available from ctan.org)
     99%\usepackage{nomencl}
    104100% Lots of math symbols and environments
    105101\usepackage{amsmath,amssymb,amstext}
    106 % For including graphics N.B. pdftex graphics driver
    107 \usepackage[pdftex]{graphicx}
     102% For including graphics (must match graphics driver)
     103\usepackage{epic,eepic}
     104\usepackage{graphicx}
    108105% Removes large sections of the document.
    109106\usepackage{comment}
    110107% Adds todos (Must be included after comment.)
    111108\usepackage{todonotes}
    112 
    113109
    114110% Hyperlinks make it very easy to navigate an electronic document.
     
    117113% Use the "hyperref" package
    118114% N.B. HYPERREF MUST BE THE LAST PACKAGE LOADED; ADD ADDITIONAL PKGS ABOVE
    119 \usepackage[pdftex,pagebackref=true]{hyperref} % with basic options
    120 %\usepackage[pdftex,pagebackref=true]{hyperref}
     115\usepackage[pagebackref=true]{hyperref}
    121116% N.B. pagebackref=true provides links back from the References to the body
    122117% text. This can cause trouble for printing.
     
    128123    pdffitwindow=false,     % window fit to page when opened
    129124    pdfstartview={FitH},    % fits the width of the page to the window
    130 %    pdftitle={uWaterloo\ LaTeX\ Thesis\ Template}, % title: CHANGE THIS TEXT!
    131 %    pdfauthor={Author},    % author: CHANGE THIS TEXT! and uncomment this line
    132 %    pdfsubject={Subject},  % subject: CHANGE THIS TEXT! and uncomment this line
    133 %    pdfkeywords={keyword1} {key2} {key3}, % optional list of keywords
    134125    pdfnewwindow=true,      % links in new window
    135126    colorlinks=true,        % false: boxed links; true: colored links
    136     linkcolor=blue,         % color of internal links
    137     citecolor=green,        % color of links to bibliography
    138     filecolor=magenta,      % color of file links
    139     urlcolor=cyan           % color of external links
    140127}
    141 % for improved print quality, change some hyperref options
    142 \ifthenelse{\boolean{PrintVersion}}{
    143 \hypersetup{    % override some previously defined hyperref options
    144 %    colorlinks,%
    145     citecolor=black,%
    146     filecolor=black,%
    147     linkcolor=black,%
    148     urlcolor=black}
    149 }{} % end of ifthenelse (no else)
     128\iftoggle{printversion}{
     129  \hypersetup{
     130    citecolor=black,        % colour of links to bibliography
     131    filecolor=black,        % colour of file links
     132    linkcolor=black,        % colour of internal links
     133    urlcolor=black,         % colour of external links
     134  }
     135}{ % Digital Version
     136  \hypersetup{
     137    citecolor=green,
     138    filecolor=magenta,
     139    linkcolor=blue,
     140    urlcolor=cyan,
     141  }
     142}
     143
     144\hypersetup{
     145  pdftitle={Exception Handling in Cforall},
     146  pdfauthor={Andrew James Beach},
     147  pdfsubject={Computer Science},
     148  pdfkeywords={programming languages} {exceptions}
     149      {language design} {language implementation},
     150}
    150151
    151152% Exception to the rule of hyperref being the last add-on package
     
    217218\pdfstringdefDisableCommands{\def\Cpp{C++}}
    218219
     220% Wrappers for inline code snippits.
     221\newrobustcmd*\codeCFA[1]{\lstinline[language=CFA]{#1}}
     222\newrobustcmd*\codeC[1]{\lstinline[language=C]{#1}}
     223\newrobustcmd*\codeCpp[1]{\lstinline[language=C++]{#1}}
     224\newrobustcmd*\codePy[1]{\lstinline[language=Python]{#1}}
     225
    219226% Colour text, formatted in LaTeX style instead of TeX style.
    220227\newcommand*\colour[2]{{\color{#1}#2}}
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/links.hpp

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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:
  • doc/user/figures/Cdecl.fig

    rfeacef9 r5407cdc  
    1 #FIG 3.2  Produced by xfig version 3.2.5b
     1#FIG 3.2  Produced by xfig version 3.2.7b
    22Landscape
    33Center
    44Inches
    5 Letter 
     5Letter
    66100.00
    77Single
     
    19192 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    2020         2850 1200 3600 1200 3600 1350 2850 1350 2850 1200
    21 4 1 0 50 -1 4 11 0.0000 2 120 90 2925 1325 0\001
    22 4 1 0 50 -1 4 11 0.0000 2 120 90 3075 1325 1\001
    23 4 1 0 50 -1 4 11 0.0000 2 120 90 3225 1325 2\001
    24 4 1 0 50 -1 4 11 0.0000 2 120 90 3375 1325 3\001
    25 4 1 0 50 -1 4 11 0.0000 2 120 90 3525 1325 4\001
     214 1 0 50 -1 4 11 0.0000 2 120 105 3075 1335 1\001
     224 1 0 50 -1 4 11 0.0000 2 120 105 3225 1335 2\001
     234 1 0 50 -1 4 11 0.0000 2 120 105 3375 1335 3\001
     244 1 0 50 -1 4 11 0.0000 2 120 105 3525 1335 4\001
     254 1 0 50 -1 4 11 0.0000 2 120 105 2925 1335 0\001
    2626-6
    27272 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
     
    5555        1 1 1.00 45.00 60.00
    5656         2550 1275 2850 1275
    57 4 1 0 50 -1 4 11 0.0000 2 120 90 1350 1650 0\001
    58 4 1 0 50 -1 4 11 0.0000 2 120 90 1500 1650 1\001
    59 4 1 0 50 -1 4 11 0.0000 2 120 90 1650 1650 2\001
    60 4 1 0 50 -1 4 11 0.0000 2 120 90 1800 1650 3\001
    61 4 1 0 50 -1 4 11 0.0000 2 120 90 1950 1650 4\001
     574 1 0 50 -1 4 11 0.0000 2 120 105 1350 1650 0\001
     584 1 0 50 -1 4 11 0.0000 2 120 105 1500 1650 1\001
     594 1 0 50 -1 4 11 0.0000 2 120 105 1650 1650 2\001
     604 1 0 50 -1 4 11 0.0000 2 120 105 1800 1650 3\001
     614 1 0 50 -1 4 11 0.0000 2 120 105 1950 1650 4\001
    62624 1 0 50 -1 4 11 0.0000 2 90 90 1200 1325 x\001
    63634 1 0 50 -1 4 11 0.0000 2 90 90 2400 1325 x\001
  • doc/user/user.tex

    rfeacef9 r5407cdc  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon Feb 15 13:48:53 2021
    14 %% Update Count     : 4452
     13%% Last Modified On : Sun Apr 25 19:03:03 2021
     14%% Update Count     : 4951
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    6666% math escape $...$ (dollar symbol)
    6767\input{common}                                          % common CFA document macros
     68\setlength{\gcolumnposn}{3in}
    6869\CFAStyle                                                                                               % use default CFA format-style
    6970\lstset{language=CFA}                                                                   % CFA default lnaguage
    7071\lstnewenvironment{C++}[1][]                            % use C++ style
    71 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{@}{@},#1}}
     72{\lstset{language=C++,moredelim=**[is][\protect\color{red}]{®}{®},#1}}
    7273{}
    7374
     
    8182\newcommand{\Textbf}[2][red]{{\color{#1}{\textbf{#2}}}}
    8283\newcommand{\Emph}[2][red]{{\color{#1}\textbf{\emph{#2}}}}
    83 \newcommand{\R}[1]{\Textbf{#1}}
    84 \newcommand{\RC}[1]{\Textbf{\LstBasicStyle{#1}}}
     84\newcommand{\R}[1]{{\color{red}#1}}
     85\newcommand{\RB}[1]{\Textbf{#1}}
    8586\newcommand{\B}[1]{{\Textbf[blue]{#1}}}
    8687\newcommand{\G}[1]{{\Textbf[OliveGreen]{#1}}}
     
    176177int main( void ) {
    177178        int x = 0, y = 1, z = 2;
    178         @printf( "%d %d %d\n", x, y, z );@
     179        ®printf( "%d %d %d\n", x, y, z );®
    179180}
    180181\end{cfa}
     
    185186int main( void ) {
    186187        int x = 0, y = 1, z = 2;
    187         @sout | x | y | z;@$\indexc{sout}$
     188        ®sout | x | y | z;®$\indexc{sout}$
    188189}
    189190\end{cfa}
     
    194195int main() {
    195196        int x = 0, y = 1, z = 2;
    196         @cout<<x<<" "<<y<<" "<<z<<endl;@
     197        ®cout<<x<<" "<<y<<" "<<z<<endl;®
    197198}
    198199\end{cfa}
     
    224225\begin{tabular}{@{}rcccccccc@{}}
    225226                & 2021  & 2016  & 2011  & 2006  & 2001  & 1996  & 1991  & 1986  \\ \hline
    226 \R{C}   & \R{1} & \R{2} & \R{2} & \R{1} & \R{1} & \R{1} & \R{1} & \R{1} \\
     227\RB{C}  & \RB{1}& \RB{2}& \RB{2}& \RB{1}& \RB{1}& \RB{1}& \RB{1}& \RB{1}\\
    227228Java    & 2             & 1             & 1             & 2             & 3             & 28    & -             & -             \\
    228229Python  & 3             & 5             & 6             & 7             & 23    & 13    & -             & -             \\
     
    258259The signature feature of \CFA is \emph{\Index{overload}able} \Index{parametric-polymorphic} functions~\cite{forceone:impl,Cormack90,Duggan96} with functions generalized using a ©forall© clause (giving the language its name):
    259260\begin{cfa}
    260 @forall( otype T )@ T identity( T val ) { return val; }
     261®forall( otype T )® T identity( T val ) { return val; }
    261262int forty_two = identity( 42 ); $\C{// T is bound to int, forty\_two == 42}$
    262263\end{cfa}
     
    322323Whereas, \CFA wraps each of these routines into one overloaded name ©abs©:
    323324\begin{cfa}
    324 char @abs@( char );
    325 extern "C" { int @abs@( int ); } $\C{// use default C routine for int}$
    326 long int @abs@( long int );
    327 long long int @abs@( long long int );
    328 float @abs@( float );
    329 double @abs@( double );
    330 long double @abs@( long double );
    331 float _Complex @abs@( float _Complex );
    332 double _Complex @abs@( double _Complex );
    333 long double _Complex @abs@( long double _Complex );
     325char ®abs®( char );
     326extern "C" { int ®abs®( int ); } $\C{// use default C routine for int}$
     327long int ®abs®( long int );
     328long long int ®abs®( long long int );
     329float ®abs®( float );
     330double ®abs®( double );
     331long double ®abs®( long double );
     332float _Complex ®abs®( float _Complex );
     333double _Complex ®abs®( double _Complex );
     334long double _Complex ®abs®( long double _Complex );
    334335\end{cfa}
    335336The problem is \Index{name clash} between the C name ©abs© and the \CFA names ©abs©, resulting in two name linkages\index{C linkage}: ©extern "C"© and ©extern "Cforall"© (default).
     
    358359The 2011 C standard plus GNU extensions.
    359360\item
    360 \Indexc[deletekeywords=inline]{-fgnu89-inline}\index{compilation option!-fgnu89-inline@{\lstinline[deletekeywords=inline]$-fgnu89-inline$}}
     361\Indexc[deletekeywords=inline]{-fgnu89-inline}\index{compilation option!-fgnu89-inline@{\lstinline[deletekeywords=inline]{-fgnu89-inline}}}
    361362Use the traditional GNU semantics for inline routines in C11 mode, which allows inline routines in header files.
    362363\end{description}
     
    530531Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism:
    531532\begin{cfa}
    532 int @``@otype = 3; $\C{// make keyword an identifier}$
    533 double @``@forall = 3.5;
     533int ®``®otype = 3; $\C{// make keyword an identifier}$
     534double ®``®forall = 3.5;
    534535\end{cfa}
    535536
     
    542543// include file uses the CFA keyword "with".
    543544#if ! defined( with )                                                   $\C{// nesting ?}$
    544 #define with @``@with                                                   $\C{// make keyword an identifier}$
     545#define with ®``®with                                                   $\C{// make keyword an identifier}$
    545546#define __CFA_BFD_H__
    546547#endif
     
    560561Numeric constants are extended to allow \Index{underscore}s\index{constant!underscore} as a separator, \eg:
    561562\begin{cfa}
    562 2@_@147@_@483@_@648; $\C{// decimal constant}$
    563 56@_@ul; $\C{// decimal unsigned long constant}$
    564 0@_@377; $\C{// octal constant}$
    565 0x@_@ff@_@ff; $\C{// hexadecimal constant}$
    566 0x@_@ef3d@_@aa5c; $\C{// hexadecimal constant}$
    567 3.141@_@592@_@654; $\C{// floating constant}$
    568 10@_@e@_@+1@_@00; $\C{// floating constant}$
    569 0x@_@ff@_@ff@_@p@_@3; $\C{// hexadecimal floating}$
    570 0x@_@1.ffff@_@ffff@_@p@_@128@_@l; $\C{// hexadecimal floating long constant}$
    571 L@_@$"\texttt{\textbackslash{x}}$@_@$\texttt{ff}$@_@$\texttt{ee}"$; $\C{// wide character constant}$
     5632®_®147®_®483®_®648; $\C{// decimal constant}$
     56456®_®ul; $\C{// decimal unsigned long constant}$
     5650®_®377; $\C{// octal constant}$
     5660x®_®ff®_®ff; $\C{// hexadecimal constant}$
     5670x®_®ef3d®_®aa5c; $\C{// hexadecimal constant}$
     5683.141®_®592®_®654; $\C{// floating constant}$
     56910®_®e®_®+1®_®00; $\C{// floating constant}$
     5700x®_®ff®_®ff®_®p®_®3; $\C{// hexadecimal floating}$
     5710x®_®1.ffff®_®ffff®_®p®_®128®_®l; $\C{// hexadecimal floating long constant}$
     572L®_®$"\texttt{\textbackslash{x}}$®_®$\texttt{ff}$®_®$\texttt{ee}"$; $\C{// wide character constant}$
    572573\end{cfa}
    573574The rules for placement of underscores are:
     
    602603Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative.
    603604\begin{cfa}
    604 sout | 1 @\@ 0 | 1 @\@ 1 | 2 @\@ 8 | -4 @\@ 3 | 5 @\@ 3 | 5 @\@ 32 | 5L @\@ 32 | 5L @\@ 64 | -4 @\@ -3 | -4.0 @\@ -3 | 4.0 @\@ 2.1
    605            | (1.0f+2.0fi) @\@ (3.0f+2.0fi);
    606 1 1 256 -64 125 @0@ 3273344365508751233 @0@ @0@ -0.015625 18.3791736799526 0.264715-1.1922i
     605sout | 1 ®\® 0 | 1 ®\® 1 | 2 ®\® 8 | -4 ®\® 3 | 5 ®\® 3 | 5 ®\® 32 | 5L ®\® 32 | 5L ®\® 64 | -4 ®\® -3 | -4.0 ®\® -3 | 4.0 ®\® 2.1
     606           | (1.0f+2.0fi) ®\® (3.0f+2.0fi);
     6071 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i
    607608\end{cfa}
    608609Note, ©5 \ 32© and ©5L \ 64© overflow, and ©-4 \ -3© is a fraction but stored in an integer so all three computations generate an integral zero.
     
    612613\begin{cfa}
    613614forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } )
    614 T ?@\@?( T ep, unsigned int y );
     615T ?®\®?( T ep, unsigned int y );
    615616forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } )
    616 T ?@\@?( T ep, unsigned long int y );
     617T ?®\®?( T ep, unsigned long int y );
    617618\end{cfa}
    618619The user type ©T© must define multiplication, one (©1©), and ©*©.
     
    624625
    625626
    626 %\subsection{\texorpdfstring{\protect\lstinline@if@/\protect\lstinline@while@ Statement}{if Statement}}
     627%\subsection{\texorpdfstring{\protect\lstinline{if}/\protect\lstinline{while} Statement}{if Statement}}
    627628\subsection{\texorpdfstring{\LstKeywordStyle{if} / \LstKeywordStyle{while} Statement}{if / while Statement}}
    628629
     
    630631Declarations in the ©do©-©while© condition are not useful because they appear after the loop body.}
    631632\begin{cfa}
    632 if ( @int x = f()@ ) ... $\C{// x != 0}$
    633 if ( @int x = f(), y = g()@ ) ... $\C{// x != 0 \&\& y != 0}$
    634 if ( @int x = f(), y = g(); x < y@ ) ... $\C{// relational expression}$
    635 if ( @struct S { int i; } x = { f() }; x.i < 4@ ) $\C{// relational expression}$
    636 
    637 while ( @int x = f()@ ) ... $\C{// x != 0}$
    638 while ( @int x = f(), y = g()@ ) ... $\C{// x != 0 \&\& y != 0}$
    639 while ( @int x = f(), y = g(); x < y@ ) ... $\C{// relational expression}$
    640 while ( @struct S { int i; } x = { f() }; x.i < 4@ ) ... $\C{// relational expression}$
     633if ( ®int x = f()® ) ... $\C{// x != 0}$
     634if ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$
     635if ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$
     636if ( ®struct S { int i; } x = { f() }; x.i < 4® ) $\C{// relational expression}$
     637
     638while ( ®int x = f()® ) ... $\C{// x != 0}$
     639while ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$
     640while ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$
     641while ( ®struct S { int i; } x = { f() }; x.i < 4® ) ... $\C{// relational expression}$
    641642\end{cfa}
    642643Unless a relational expression is specified, each variable is compared not equal to 0, which is the standard semantics for the ©if©/©while© expression, and the results are combined using the logical ©&&© operator.
     
    645646
    646647
    647 %\section{\texorpdfstring{\protect\lstinline@case@ Clause}{case Clause}}
     648%\section{\texorpdfstring{\protect\lstinline{case} Clause}{case Clause}}
    648649\subsection{\texorpdfstring{\LstKeywordStyle{case} Clause}{case Clause}}
    649650\label{s:caseClause}
     
    658659\begin{cfa}
    659660switch ( i ) {
    660   case @1, 3, 5@:
     661  case ®1, 3, 5®:
    661662        ...
    662   case @2, 4, 6@:
     663  case ®2, 4, 6®:
    663664        ...
    664665}
     
    685686\end{cquote}
    686687In addition, subranges are allowed to specify case values.\footnote{
    687 gcc has the same mechanism but awkward syntax, \lstinline@2 ...42@, because a space is required after a number, otherwise the period is a decimal point.}
     688gcc has the same mechanism but awkward syntax, \lstinline{2 ...42}, because a space is required after a number, otherwise the period is a decimal point.}
    688689\begin{cfa}
    689690switch ( i ) {
    690   case @1~5:@ $\C{// 1, 2, 3, 4, 5}$
     691  case ®1~5:® $\C{// 1, 2, 3, 4, 5}$
    691692        ...
    692   case @10~15:@ $\C{// 10, 11, 12, 13, 14, 15}$
     693  case ®10~15:® $\C{// 10, 11, 12, 13, 14, 15}$
    693694        ...
    694695}
     
    696697Lists of subranges are also allowed.
    697698\begin{cfa}
    698 case @1~5, 12~21, 35~42@:
    699 \end{cfa}
    700 
    701 
    702 %\section{\texorpdfstring{\protect\lstinline@switch@ Statement}{switch Statement}}
     699case ®1~5, 12~21, 35~42®:
     700\end{cfa}
     701
     702
     703%\section{\texorpdfstring{\protect\lstinline{switch} Statement}{switch Statement}}
    703704\subsection{\texorpdfstring{\LstKeywordStyle{switch} Statement}{switch Statement}}
    704705
     
    740741if ( argc == 3 ) {
    741742        // open output file
    742         @// open input file
    743 @} else if ( argc == 2 ) {
    744         @// open input file (duplicate)
    745 
    746 @} else {
     743        ®// open input file
     744®} else if ( argc == 2 ) {
     745        ®// open input file (duplicate)
     746
     747®} else {
    747748        // usage message
    748749}
     
    755756\begin{cfa}
    756757switch ( i ) {
    757   @case 1: case 3: case 5:@     // odd values
     758  ®case 1: case 3: case 5:®     // odd values
    758759        // odd action
    759760        break;
    760   @case 2: case 4: case 6:@     // even values
     761  ®case 2: case 4: case 6:®     // even values
    761762        // even action
    762763        break;
     
    774775        if ( j < k ) {
    775776                ...
    776           @case 1:@             // transfer into "if" statement
     777          ®case 1:®             // transfer into "if" statement
    777778                ...
    778779        } // if
     
    780781        while ( j < 5 ) {
    781782                ...
    782           @case 3:@             // transfer into "while" statement
     783          ®case 3:®             // transfer into "while" statement
    783784                ...
    784785        } // while
     
    821822\begin{cfa}
    822823switch ( x ) {
    823         @int y = 1;@ $\C{// unreachable initialization}$
    824         @x = 7;@ $\C{// unreachable code without label/branch}$
     824        ®int y = 1;® $\C{// unreachable initialization}$
     825        ®x = 7;® $\C{// unreachable code without label/branch}$
    825826  case 0: ...
    826827        ...
    827         @int z = 0;@ $\C{// unreachable initialization, cannot appear after case}$
     828        ®int z = 0;® $\C{// unreachable initialization, cannot appear after case}$
    828829        z = 2;
    829830  case 1:
    830         @x = z;@ $\C{// without fall through, z is uninitialized}$
     831        ®x = z;® $\C{// without fall through, z is uninitialized}$
    831832}
    832833\end{cfa}
     
    860861Therefore, to preserve backwards compatibility, it is necessary to introduce a new kind of ©switch© statement, called ©choose©, with no implicit fall-through semantics and an explicit fall-through if the last statement of a case-clause ends with the new keyword ©fallthrough©/©fallthru©, \eg:
    861862\begin{cfa}
    862 @choose@ ( i ) {
     863®choose® ( i ) {
    863864  case 1:  case 2:  case 3:
    864865        ...
    865         @// implicit end of switch (break)
    866   @case 5:
     866        ®// implicit end of switch (break)
     867  ®case 5:
    867868        ...
    868         @fallthru@; $\C{// explicit fall through}$
     869        ®fallthru®; $\C{// explicit fall through}$
    869870  case 7:
    870871        ...
    871         @break@ $\C{// explicit end of switch (redundant)}$
     872        ®break® $\C{// explicit end of switch (redundant)}$
    872873  default:
    873874        j = 3;
     
    890891\begin{cfa}
    891892switch ( x ) {
    892         @int i = 0;@ $\C{// allowed only at start}$
     893        ®int i = 0;® $\C{// allowed only at start}$
    893894  case 0:
    894895        ...
    895         @int j = 0;@ $\C{// disallowed}$
     896        ®int j = 0;® $\C{// disallowed}$
    896897  case 1:
    897898        {
    898                 @int k = 0;@ $\C{// allowed at different nesting levels}$
     899                ®int k = 0;® $\C{// allowed at different nesting levels}$
    899900                ...
    900           @case 2:@ $\C{// disallow case in nested statements}$
     901          ®case 2:® $\C{// disallow case in nested statements}$
    901902        }
    902903  ...
     
    915916  case 3:
    916917        if ( ... ) {
    917                 ... @fallthru;@ // goto case 4
     918                ... ®fallthru;® // goto case 4
    918919        } else {
    919920                ...
     
    930931choose ( ... ) {
    931932  case 3:
    932         ... @fallthrough common;@
     933        ... ®fallthrough common;®
    933934  case 4:
    934         ... @fallthrough common;@
    935 
    936   @common:@ // below fallthrough
     935        ... ®fallthrough common;®
     936
     937  ®common:® // below fallthrough
    937938                          // at case-clause level
    938939        ...     // common code for cases 3/4
     
    950951                for ( ... ) {
    951952                        // multi-level transfer
    952                         ... @fallthru common;@
     953                        ... ®fallthru common;®
    953954                }
    954955                ...
    955956        }
    956957        ...
    957   @common:@ // below fallthrough
     958  ®common:® // below fallthrough
    958959                          // at case-clause level
    959960\end{cfa}
     
    970971\hline
    971972\begin{cfa}
    972 while @($\,$)@ { sout | "empty"; break; }
    973 do { sout | "empty"; break; } while @($\,$)@;
    974 for @($\,$)@ { sout | "empty"; break; }
    975 for ( @0@ ) { sout | "A"; } sout | "zero";
    976 for ( @1@ ) { sout | "A"; }
    977 for ( @10@ ) { sout | "A"; }
    978 for ( @= 10@ ) { sout | "A"; }
    979 for ( @1 ~= 10 ~ 2@ ) { sout | "B"; }
    980 for ( @10 -~= 1 ~ 2@ ) { sout | "C"; }
    981 for ( @0.5 ~ 5.5@ ) { sout | "D"; }
    982 for ( @5.5 -~ 0.5@ ) { sout | "E"; }
    983 for ( @i; 10@ ) { sout | i; }
    984 for ( @i; = 10@ ) { sout | i; }
    985 for ( @i; 1 ~= 10 ~ 2@ ) { sout | i; }
    986 for ( @i; 10 -~= 1 ~ 2@ ) { sout | i; }
    987 for ( @i; 0.5 ~ 5.5@ ) { sout | i; }
    988 for ( @i; 5.5 -~ 0.5@ ) { sout | i; }
    989 for ( @ui; 2u ~= 10u ~ 2u@ ) { sout | ui; }
    990 for ( @ui; 10u -~= 2u ~ 2u@ ) { sout | ui; }
     973while ®($\,$)® { sout | "empty"; break; }
     974do { sout | "empty"; break; } while ®($\,$)®;
     975for ®($\,$)® { sout | "empty"; break; }
     976for ( ®0® ) { sout | "A"; } sout | "zero";
     977for ( ®1® ) { sout | "A"; }
     978for ( ®10® ) { sout | "A"; }
     979for ( ®= 10® ) { sout | "A"; }
     980for ( ®1 ~= 10 ~ 2® ) { sout | "B"; }
     981for ( ®10 -~= 1 ~ 2® ) { sout | "C"; }
     982for ( ®0.5 ~ 5.5® ) { sout | "D"; }
     983for ( ®5.5 -~ 0.5® ) { sout | "E"; }
     984for ( ®i; 10® ) { sout | i; }
     985for ( ®i; = 10® ) { sout | i; }
     986for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; }
     987for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; }
     988for ( ®i; 0.5 ~ 5.5® ) { sout | i; }
     989for ( ®i; 5.5 -~ 0.5® ) { sout | i; }
     990for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; }
     991for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; }
    991992enum { N = 10 };
    992 for ( @N@ ) { sout | "N"; }
    993 for ( @i; N@ ) { sout | i; }
    994 for ( @i; N -~ 0@ ) { sout | i; }
     993for ( ®N® ) { sout | "N"; }
     994for ( ®i; N® ) { sout | i; }
     995for ( ®i; N -~ 0® ) { sout | i; }
    995996const int start = 3, comp = 10, inc = 2;
    996 for ( @i; start ~ comp ~ inc + 1@ ) { sout | i; }
    997 for ( i; 1 ~ $\R{@}$ ) { if ( i > 10 ) break; sout | i; }
    998 for ( i; 10 -~ $\R{@}$ ) { if ( i < 0 ) break; sout | i; }
    999 for ( i; 2 ~ $\R{@}$ ~ 2 ) { if ( i > 10 ) break; sout | i; }
    1000 for ( i; 2.1 ~ $\R{@}$ ~ $\R{@}$ ) { if ( i > 10.5 ) break; sout | i; i += 1.7; }
    1001 for ( i; 10 -~ $\R{@}$ ~ 2 ) { if ( i < 0 ) break; sout | i; }
    1002 for ( i; 12.1 ~ $\R{@}$ ~ $\R{@}$ ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; }
    1003 for ( i; 5 @:@ j; -5 ~ $@$ ) { sout | i | j; }
    1004 for ( i; 5 @:@ j; -5 -~ $@$ ) { sout | i | j; }
    1005 for ( i; 5 @:@ j; -5 ~ $@$ ~ 2 ) { sout | i | j; }
    1006 for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 ) { sout | i | j; }
    1007 for ( i; 5 @:@ j; -5 ~ $@$ ) { sout | i | j; }
    1008 for ( i; 5 @:@ j; -5 -~ $@$ ) { sout | i | j; }
    1009 for ( i; 5 @:@ j; -5 ~ $@$ ~ 2 ) { sout | i | j; }
    1010 for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 ) { sout | i | j; }
    1011 for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 @:@ k; 1.5 ~ $@$ ) { sout | i | j | k; }
    1012 for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 @:@ k; 1.5 ~ $@$ ) { sout | i | j | k; }
    1013 for ( i; 5 @:@ k; 1.5 ~ $@$ @:@ j; -5 -~ $@$ ~ 2 ) { sout | i | j | k; }
     997for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; }
     998for ( i; 1 ~ ®@® ) { if ( i > 10 ) break; sout | i; }
     999for ( i; 10 -~ ®@® ) { if ( i < 0 ) break; sout | i; }
     1000for ( i; 2 ~ ®@® ~ 2 ) { if ( i > 10 ) break; sout | i; }
     1001for ( i; 2.1 ~ ®@® ~ ®@® ) { if ( i > 10.5 ) break; sout | i; i += 1.7; }
     1002for ( i; 10 -~ ®@® ~ 2 ) { if ( i < 0 ) break; sout | i; }
     1003for ( i; 12.1 ~ ®@® ~ ®@® ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; }
     1004for ( i; 5 ®:® j; -5 ~ @ ) { sout | i | j; }
     1005for ( i; 5 ®:® j; -5 -~ @ ) { sout | i | j; }
     1006for ( i; 5 ®:® j; -5 ~ @ ~ 2 ) { sout | i | j; }
     1007for ( i; 5 ®:® j; -5 -~ @ ~ 2 ) { sout | i | j; }
     1008for ( i; 5 ®:® j; -5 ~ @ ) { sout | i | j; }
     1009for ( i; 5 ®:® j; -5 -~ @ ) { sout | i | j; }
     1010for ( i; 5 ®:® j; -5 ~ @ ~ 2 ) { sout | i | j; }
     1011for ( i; 5 ®:® j; -5 -~ @ ~ 2 ) { sout | i | j; }
     1012for ( i; 5 ®:® j; -5 -~ @ ~ 2 ®:® k; 1.5 ~ @ ) { sout | i | j | k; }
     1013for ( i; 5 ®:® j; -5 -~ @ ~ 2 ®:® k; 1.5 ~ @ ) { sout | i | j | k; }
     1014for ( i; 5 ®:® k; 1.5 ~ @ ®:® j; -5 -~ @ ~ 2 ) { sout | i | j | k; }
    10141015\end{cfa}
    10151016&
     
    10891090The loop index is polymorphic in the type of the comparison value N (when the start value is implicit) or the start value M.
    10901091\begin{cfa}
    1091 for ( i; @5@ )                                  $\C[2.5in]{// typeof(5) i; 5 is comparison value}$
    1092 for ( i; @1.5@~5.5~0.5 )                $\C{// typeof(1.5) i; 1.5 is start value}$
     1092for ( i; ®5® )                                  $\C[2.5in]{// typeof(5) i; 5 is comparison value}$
     1093for ( i; ®1.5®~5.5~0.5 )                $\C{// typeof(1.5) i; 1.5 is start value}$
    10931094\end{cfa}
    10941095\item
    10951096An empty conditional implies comparison value of ©1© (true).
    10961097\begin{cfa}
    1097 while ( $\R{/*empty*/}$ )               $\C{// while ( true )}$
    1098 for ( $\R{/*empty*/}$ )                 $\C{// for ( ; true; )}$
    1099 do ... while ( $\R{/*empty*/}$ ) $\C{// do ... while ( true )}$
     1098while ( ®/*empty*/®  )                  $\C{// while ( true )}$
     1099for ( ®/*empty*/® )                    $\C{// for ( ; true; )}$
     1100do ... while ( ®/*empty*/®  )    $\C{// do ... while ( true )}$
    11001101\end{cfa}
    11011102\item
    11021103A comparison N is implicit up-to exclusive range [0,N\R{)}.
    11031104\begin{cfa}
    1104 for ( @5@ )                                             $\C{// for ( typeof(5) i; i < 5; i += 1 )}$
     1105for ( ®5® )                                             $\C{// for ( typeof(5) i; i < 5; i += 1 )}$
    11051106\end{cfa}
    11061107\item
    11071108A comparison ©=© N is implicit up-to inclusive range [0,N\R{]}.
    11081109\begin{cfa}
    1109 for ( @=@5 )                                    $\C{// for ( typeof(5) i; i <= 5; i += 1 )}$
     1110for ( ®=®5 )                                    $\C{// for ( typeof(5) i; i <= 5; i += 1 )}$
    11101111\end{cfa}
    11111112\item
    11121113The up-to range M ©~©\index{~@©~©} N means exclusive range [M,N\R{)}.
    11131114\begin{cfa}
    1114 for ( 1@~@5 )                                   $\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$
     1115for ( 1®~®5 )                                   $\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$
    11151116\end{cfa}
    11161117\item
    11171118The up-to range M ©~=©\index{~=@©~=©} N means inclusive range [M,N\R{]}.
    11181119\begin{cfa}
    1119 for ( 1@~=@5 )                                  $\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$
     1120for ( 1®~=®5 )                                  $\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$
    11201121\end{cfa}
    11211122\item
    11221123The down-to range M ©-~©\index{-~@©-~©} N means exclusive range [N,M\R{)}.
    11231124\begin{cfa}
    1124 for ( 1@-~@5 )                                  $\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$
     1125for ( 1®-~®5 )                                  $\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$
    11251126\end{cfa}
    11261127\item
    11271128The down-to range M ©-~=©\index{-~=@©-~=©} N means inclusive range [N,M\R{]}.
    11281129\begin{cfa}
    1129 for ( 1@-~=@5 )                                 $\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$
     1130for ( 1®-~=®5 )                                 $\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$
    11301131\end{cfa}
    11311132\item
    11321133©@© means put nothing in this field.
    11331134\begin{cfa}
    1134 for ( 1~$\R{@}$~2 )                             $\C{// for ( typeof(1) i = 1; /*empty*/; i += 2 )}$
     1135for ( 1~®@®~2 )                                 $\C{// for ( typeof(1) i = 1; /*empty*/; i += 2 )}$
    11351136\end{cfa}
    11361137\item
    11371138©:© means start another index.
    11381139\begin{cfa}
    1139 for ( i; 5 @:@ j; 2~12~3 )              $\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}\CRT$
     1140for ( i; 5 ®:® j; 2~12~3 )              $\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}\CRT$
    11401141\end{cfa}
    11411142\end{itemize}
    11421143
    11431144
    1144 %\subsection{\texorpdfstring{Labelled \protect\lstinline@continue@ / \protect\lstinline@break@}{Labelled continue / break}}
     1145%\subsection{\texorpdfstring{Labelled \protect\lstinline{continue} / \protect\lstinline{break}}{Labelled continue / break}}
    11451146\subsection{\texorpdfstring{Labelled \LstKeywordStyle{continue} / \LstKeywordStyle{break} Statement}{Labelled continue / break Statement}}
    11461147
     
    11571158\begin{lrbox}{\myboxA}
    11581159\begin{cfa}[tabsize=3]
    1159 @Compound:@ {
    1160         @Try:@ try {
    1161                 @For:@ for ( ... ) {
    1162                         @While:@ while ( ... ) {
    1163                                 @Do:@ do {
    1164                                         @If:@ if ( ... ) {
    1165                                                 @Switch:@ switch ( ... ) {
     1160®Compound:® {
     1161        ®Try:® try {
     1162                ®For:® for ( ... ) {
     1163                        ®While:® while ( ... ) {
     1164                                ®Do:® do {
     1165                                        ®If:® if ( ... ) {
     1166                                                ®Switch:® switch ( ... ) {
    11661167                                                        case 3:
    1167                                                                 @break Compound@;
    1168                                                                 @break Try@;
    1169                                                                 @break For@;      /* or */  @continue For@;
    1170                                                                 @break While@;  /* or */  @continue While@;
    1171                                                                 @break Do@;      /* or */  @continue Do@;
    1172                                                                 @break If@;
    1173                                                                 @break Switch@;
     1168                                                                ®break Compound®;
     1169                                                                ®break Try®;
     1170                                                                ®break For®;      /* or */  ®continue For®;
     1171                                                                ®break While®;  /* or */  ®continue While®;
     1172                                                                ®break Do®;      /* or */  ®continue Do®;
     1173                                                                ®break If®;
     1174                                                                ®break Switch®;
    11741175                                                        } // switch
    11751176                                                } else {
    1176                                                         ... @break If@; ...     // terminate if
     1177                                                        ... ®break If®; ...     // terminate if
    11771178                                                } // if
    11781179                                } while ( ... ); // do
    11791180                        } // while
    11801181                } // for
    1181         } @finally@ { // always executed
     1182        } ®finally® { // always executed
    11821183        } // try
    11831184} // compound
     
    11891190{
    11901191
    1191                 @ForC:@ for ( ... ) {
    1192                         @WhileC:@ while ( ... ) {
    1193                                 @DoC:@ do {
     1192                ®ForC:® for ( ... ) {
     1193                        ®WhileC:® while ( ... ) {
     1194                                ®DoC:® do {
    11941195                                        if ( ... ) {
    11951196                                                switch ( ... ) {
    11961197                                                        case 3:
    1197                                                                 @goto Compound@;
    1198                                                                 @goto Try@;
    1199                                                                 @goto ForB@;      /* or */  @goto ForC@;
    1200                                                                 @goto WhileB@;  /* or */  @goto WhileC@;
    1201                                                                 @goto DoB@;      /* or */  @goto DoC@;
    1202                                                                 @goto If@;
    1203                                                                 @goto Switch@;
    1204                                                         } @Switch:@ ;
     1198                                                                ®goto Compound®;
     1199                                                                ®goto Try®;
     1200                                                                ®goto ForB®;      /* or */  ®goto ForC®;
     1201                                                                ®goto WhileB®;  /* or */  ®goto WhileC®;
     1202                                                                ®goto DoB®;      /* or */  ®goto DoC®;
     1203                                                                ®goto If®;
     1204                                                                ®goto Switch®;
     1205                                                        } ®Switch:® ;
    12051206                                                } else {
    1206                                                         ... @goto If@; ...      // terminate if
    1207                                                 } @If:@;
    1208                                 } while ( ... ); @DoB:@ ;
    1209                         } @WhileB:@ ;
    1210                 } @ForB:@ ;
    1211 
    1212 
    1213 } @Compound:@ ;
     1207                                                        ... ®goto If®; ...      // terminate if
     1208                                                } ®If:®;
     1209                                } while ( ... ); ®DoB:® ;
     1210                        } ®WhileB:® ;
     1211                } ®ForB:® ;
     1212
     1213
     1214} ®Compound:® ;
    12141215\end{cfa}
    12151216\end{lrbox}
     
    12401241
    12411242
    1242 %\subsection{\texorpdfstring{\protect\lstinline@with@ Statement}{with Statement}}
     1243%\subsection{\texorpdfstring{\protect\lstinline{with} Statement}{with Statement}}
    12431244\subsection{\texorpdfstring{\LstKeywordStyle{with} Statement}{with Statement}}
    12441245\label{s:WithStatement}
     
    12551256\begin{cfa}
    12561257Person p
    1257 @p.@name; @p.@address; @p.@sex; $\C{// access containing fields}$
     1258®p.®name; ®p.®address; ®p.®sex; $\C{// access containing fields}$
    12581259\end{cfa}
    12591260which extends to multiple levels of qualification for nested aggregates and multiple aggregates.
    12601261\begin{cfa}
    12611262struct Ticket { ... } t;
    1262 @p.name@.first; @p.address@.street;             $\C{// access nested fields}$
    1263 @t.@departure; @t.@cost;                                $\C{// access multiple aggregate}$
     1263®p.name®.first; ®p.address®.street;             $\C{// access nested fields}$
     1264®t.®departure; ®t.®cost;                                $\C{// access multiple aggregate}$
    12641265\end{cfa}
    12651266Repeated aggregate qualification is tedious and makes code difficult to read.
     
    12841285\begin{C++}
    12851286struct S {
    1286         char @c@;   int @i@;   double @d@;
     1287        char ®c®;   int ®i®;   double ®d®;
    12871288        void f( /* S * this */ ) {                              $\C{// implicit ``this'' parameter}$
    1288                 @c@;   @i@;   @d@;                                      $\C{// this->c; this->i; this->d;}$
     1289                ®c®;   ®i®;   ®d®;                                      $\C{// this->c; this->i; this->d;}$
    12891290        }
    12901291}
     
    12941295\begin{cfa}
    12951296struct T {
    1296         char @m@;   int @i@;   double @n@;              $\C{// derived class variables}$
     1297        char ®m®;   int ®i®;   double ®n®;              $\C{// derived class variables}$
    12971298};
    12981299struct S : public T {
    1299         char @c@;   int @i@;   double @d@;              $\C{// class variables}$
    1300         void g( double @d@, T & t ) {
    1301                 d;   @t@.m;   @t@.i;   @t@.n;           $\C{// function parameter}$
    1302                 c;   i;   @this->@d;   @S::@d;          $\C{// class S variables}$
    1303                 m;   @T::@i;   n;                                       $\C{// class T variables}$
     1300        char ®c®;   int ®i®;   double ®d®;              $\C{// class variables}$
     1301        void g( double ®d®, T & t ) {
     1302                d;   ®t®.m;   ®t®.i;   ®t®.n;           $\C{// function parameter}$
     1303                c;   i;   ®this->®d;   ®S::®d;          $\C{// class S variables}$
     1304                m;   ®T::®i;   n;                                       $\C{// class T variables}$
    13041305        }
    13051306};
     
    13111312Hence, the qualified fields become variables with the side-effect that it is simpler to write, easier to read, and optimize field references in a block.
    13121313\begin{cfa}
    1313 void f( S & this ) @with ( this )@ {            $\C{// with statement}$
    1314         @c@;   @i@;   @d@;                                              $\C{// this.c, this.i, this.d}$
     1314void f( S & this ) ®with ( this )® {            $\C{// with statement}$
     1315        ®c®;   ®i®;   ®d®;                                              $\C{// this.c, this.i, this.d}$
    13151316}
    13161317\end{cfa}
    13171318with the generality of opening multiple aggregate-parameters:
    13181319\begin{cfa}
    1319 void g( S & s, T & t ) @with ( s, t )@ {        $\C{// multiple aggregate parameters}$
    1320         c;   @s.@i;   d;                                                $\C{// s.c, s.i, s.d}$
    1321         m;   @t.@i;   n;                                                $\C{// t.m, t.i, t.n}$
     1320void g( S & s, T & t ) ®with ( s, t )® {        $\C{// multiple aggregate parameters}$
     1321        c;   ®s.®i;   d;                                                $\C{// s.c, s.i, s.d}$
     1322        m;   ®t.®i;   n;                                                $\C{// t.m, t.i, t.n}$
    13221323}
    13231324\end{cfa}
     
    13381339The difference between parallel and nesting occurs for fields with the same name and type:
    13391340\begin{cfa}
    1340 struct Q { int @i@; int k; int @m@; } q, w;
    1341 struct R { int @i@; int j; double @m@; } r, w;
     1341struct Q { int ®i®; int k; int ®m®; } q, w;
     1342struct R { int ®i®; int j; double ®m®; } r, w;
    13421343with ( r, q ) {
    13431344        j + k;                                                                  $\C{// unambiguous, r.j + q.k}$
     
    13721373\begin{cfa}
    13731374void ?{}( S & s, int i ) with ( s ) { $\C{// constructor}$
    1374         @s.i = i;@  j = 3;  m = 5.5; $\C{// initialize fields}$
     1375        ®s.i = i;®  j = 3;  m = 5.5; $\C{// initialize fields}$
    13751376}
    13761377\end{cfa}
     
    13851386and implicitly opened \emph{after} a function-body open, to give them higher priority:
    13861387\begin{cfa}
    1387 void ?{}( S & s, int @i@ ) with ( s ) @with( $\emph{\R{params}}$ )@ { // syntax not allowed, illustration only
    1388         s.i = @i@; j = 3; m = 5.5;
     1388void ?{}( S & s, int ®i® ) with ( s ) ®with( $\emph{\R{params}}$ )® { // syntax not allowed, illustration only
     1389        s.i = ®i®; j = 3; m = 5.5;
    13891390}
    13901391\end{cfa}
     
    14691470For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way:
    14701471\begin{cfa}
    1471 int @(*@f@())[@5@]@ {...}; $\C{// definition}$
    1472  ... @(*@f@())[@3@]@ += 1; $\C{// usage}$
     1472int ®(*®f®())[®5®]® {...}; $\C{// definition}$
     1473 ... ®(*®f®())[®3®]® += 1; $\C{// usage}$
    14731474\end{cfa}
    14741475Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).
     
    14861487\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c}{\textbf{C}}        \\
    14871488\begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}]
    1488 #[5] *# @int@ x1;
    1489 #* [5]# @int@ x2;
    1490 #[* [5] int]# f@( int p )@;
     1489#[5] *# ®int® x1;
     1490#* [5]# ®int® x2;
     1491#[* [5] int]# f®( int p )®;
    14911492\end{cfa}
    14921493&
    14931494\begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}]
    1494 @int@ #*# x1 #[5]#;
    1495 @int@ #(*#x2#)[5]#;
    1496 #int (*#f@( int p )@#)[5]#;
     1495®int® #*# x1 #[5]#;
     1496®int® #(*#x2#)[5]#;
     1497#int (*#f®( int p )®#)[5]#;
    14971498\end{cfa}
    14981499\end{tabular}
     
    15061507\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c}{\textbf{C}}        \\
    15071508\begin{cfa}
    1508 @*@ int x, y;
     1509®*® int x, y;
    15091510\end{cfa}
    15101511&
    15111512\begin{cfa}
    1512 int @*@x, @*@y;
     1513int ®*®x, ®*®y;
    15131514\end{cfa}
    15141515\end{tabular}
     
    15191520\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c}{\textbf{C}}        \\
    15201521\begin{cfa}
    1521 @*@ int x;
     1522®*® int x;
    15221523int y;
    15231524\end{cfa}
    15241525&
    15251526\begin{cfa}
    1526 int @*@x, y;
     1527int ®*®x, y;
    15271528
    15281529\end{cfa}
     
    16601661&
    16611662\begin{cfa}
    1662 int * @const@ x = (int *)100
     1663int * ®const® x = (int *)100
    16631664*x = 3;                 // implicit dereference
    1664 int * @const@ y = (int *)104;
     1665int * ®const® y = (int *)104;
    16651666*y = *x;                        // implicit dereference
    16661667\end{cfa}
     
    17001701\begin{tabular}{@{}l@{\hspace{2em}}l@{}}
    17011702\begin{cfa}
    1702 int x, y, @*@ p1, @*@ p2, @**@ p3;
    1703 p1 = @&@x;     // p1 points to x
     1703int x, y, ®*® p1, ®*® p2, ®**® p3;
     1704p1 = ®&®x;     // p1 points to x
    17041705p2 = p1;     // p2 points to x
    1705 p1 = @&@y;     // p1 points to y
     1706p1 = ®&®y;     // p1 points to y
    17061707p3 = &p2;  // p3 points to p2
    17071708\end{cfa}
     
    17291730\begin{cfa}
    17301731p1 = p2; $\C{// pointer address assignment}$
    1731 @*@p2 = @*@p1 + x; $\C{// pointed-to value assignment / operation}$
     1732®*®p2 = ®*®p1 + x; $\C{// pointed-to value assignment / operation}$
    17321733\end{cfa}
    17331734The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©).
     
    17451746To support this common case, a reference type is introduced in \CFA, denoted by ©&©, which is the opposite dereference semantics to a pointer type, making the value at the pointed-to location the implicit semantics for dereferencing (similar but not the same as \CC \Index{reference type}s).
    17461747\begin{cfa}
    1747 int x, y, @&@ r1, @&@ r2, @&&@ r3;
    1748 @&@r1 = &x; $\C{// r1 points to x}$
    1749 @&@r2 = &r1; $\C{// r2 points to x}$
    1750 @&@r1 = &y; $\C{// r1 points to y}$
    1751 @&&@r3 = @&@&r2; $\C{// r3 points to r2}$
     1748int x, y, ®&® r1, ®&® r2, ®&&® r3;
     1749®&®r1 = &x; $\C{// r1 points to x}$
     1750®&®r2 = &r1; $\C{// r2 points to x}$
     1751®&®r1 = &y; $\C{// r1 points to y}$
     1752®&&®r3 = ®&®&r2; $\C{// r3 points to r2}$
    17521753r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); $\C{// implicit dereferencing}$
    17531754\end{cfa}
     
    17561757One way to conceptualize a reference is via a rewrite rule, where the compiler inserts a dereference operator before the reference variable for each reference qualifier in a declaration, so the previous example becomes:
    17571758\begin{cfa}
    1758 @*@r2 = ((@*@r1 + @*@r2) @*@ (@**@r3 - @*@r1)) / (@**@r3 - 15);
     1759®*®r2 = ((®*®r1 + ®*®r2) ®*® (®**®r3 - ®*®r1)) / (®**®r3 - 15);
    17591760\end{cfa}
    17601761When a reference operation appears beside a dereference operation, \eg ©&*©, they cancel out.
     
    17651766For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}):
    17661767\begin{cfa}
    1767 (&@*@)r1 = &x; $\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}$
     1768(&®*®)r1 = &x; $\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}$
    17681769\end{cfa}
    17691770Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}):
    17701771\begin{cfa}
    1771 (&(&@*@)@*@)r3 = &(&@*@)r2; $\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}$
     1772(&(&®*®)®*®)r3 = &(&®*®)r2; $\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}$
    17721773\end{cfa}
    17731774Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth.
     
    17921793const int cx = 5; $\C{// cannot change cx;}$
    17931794const int & cr = cx; $\C{// cannot change what cr points to}$
    1794 @&@cr = &cx; $\C{// can change cr}$
     1795®&®cr = &cx; $\C{// can change cr}$
    17951796cr = 7; $\C{// error, cannot change cx}$
    17961797int & const rc = x; $\C{// must be initialized}$
    1797 @&@rc = &x; $\C{// error, cannot change rc}$
     1798®&®rc = &x; $\C{// error, cannot change rc}$
    17981799const int & const crc = cx; $\C{// must be initialized}$
    17991800crc = 7; $\C{// error, cannot change cx}$
    1800 @&@crc = &cx; $\C{// error, cannot change crc}$
     1801®&®crc = &cx; $\C{// error, cannot change crc}$
    18011802\end{cfa}
    18021803Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}:
     
    18191820\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c}{\textbf{C}}        \\
    18201821\begin{cfa}
    1821 @const@ * @const@ * const int ccp;
    1822 @const@ & @const@ & const int ccr;
     1822®const® * ®const® * const int ccp;
     1823®const® & ®const® & const int ccr;
    18231824\end{cfa}
    18241825&
    18251826\begin{cfa}
    1826 const int * @const@ * @const@ ccp;
     1827const int * ®const® * ®const® ccp;
    18271828
    18281829\end{cfa}
     
    18561857\begin{cfa}
    18571858int * p = &x; $\C{// assign address of x}$
    1858 @int * p = x;@ $\C{// assign value of x}$
     1859®int * p = x;® $\C{// assign value of x}$
    18591860int & r = x; $\C{// must have address of x}$
    18601861\end{cfa}
     
    18801881When a pointer/reference parameter has a ©const© value (immutable), it is possible to pass literals and expressions.
    18811882\begin{cfa}
    1882 void f( @const@ int & cr );
    1883 void g( @const@ int * cp );
    1884 f( 3 );                   g( @&@3 );
    1885 f( x + y );             g( @&@(x + y) );
     1883void f( ®const® int & cr );
     1884void g( ®const® int * cp );
     1885f( 3 );                   g( ®&®3 );
     1886f( x + y );             g( ®&®(x + y) );
    18861887\end{cfa}
    18871888Here, the compiler passes the address to the literal 3 or the temporary for the expression ©x + y©, knowing the argument cannot be changed through the parameter.
     
    18941895void f( int & r );
    18951896void g( int * p );
    1896 f( 3 );                   g( @&@3 ); $\C{// compiler implicit generates temporaries}$
    1897 f( x + y );             g( @&@(x + y) ); $\C{// compiler implicit generates temporaries}$
     1897f( 3 );                   g( ®&®3 ); $\C{// compiler implicit generates temporaries}$
     1898f( x + y );             g( ®&®(x + y) ); $\C{// compiler implicit generates temporaries}$
    18981899\end{cfa}
    18991900Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{
     
    19161917Instead, a routine object should be referenced by a ©const© reference:
    19171918\begin{cfa}
    1918 @const@ void (@&@ fr)( int ) = f; $\C{// routine reference}$
     1919®const® void (®&® fr)( int ) = f; $\C{// routine reference}$
    19191920fr = ... $\C{// error, cannot change code}$
    19201921&fr = ...; $\C{// changing routine reference}$
     
    19781979\begin{cfa}
    19791980int x, &r = x, f( int p );
    1980 x = @r@ + f( @r@ ); $\C{// lvalue reference converts to rvalue}$
     1981x = ®r® + f( ®r® ); $\C{// lvalue reference converts to rvalue}$
    19811982\end{cfa}
    19821983An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped.
    19831984
    19841985\item
    1985 lvalue to reference conversion: \lstinline[deletekeywords=lvalue]@lvalue-type cv1 T@ converts to ©cv2 T &©, which allows implicitly converting variables to references.
    1986 \begin{cfa}
    1987 int x, &r = @x@, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$
    1988 f( @x@ ); $\C{// lvalue variable (int) convert to reference (int \&)}$
     1986lvalue to reference conversion: \lstinline[deletekeywords=lvalue]{lvalue-type cv1 T} converts to ©cv2 T &©, which allows implicitly converting variables to references.
     1987\begin{cfa}
     1988int x, &r = ®x®, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$
     1989f( ®x® ); $\C{// lvalue variable (int) convert to reference (int \&)}$
    19891990\end{cfa}
    19901991Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost.
     
    19961997\begin{cfa}
    19971998int x, & f( int & p );
    1998 f( @x + 3@ );   $\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}$
    1999 @&f@(...) = &x; $\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT$
     1999f( ®x + 3® );   $\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}$
     2000®&f®(...) = &x; $\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT$
    20002001\end{cfa}
    20012002In both case, modifications to the temporary are inaccessible (\Index{warning}).
     
    21642165
    21652166
     2167\section{Enumeration}
     2168
     2169An \newterm{enumeration} is a compile-time mechanism to alias names to constants, like ©typedef© is a mechanism to alias names to types.
     2170Its purpose is to define a restricted-value type providing code-readability and maintenance -- changing an enum's value automatically updates all name usages during compilation.
     2171
     2172An enumeration type is a set of names, each called an \newterm{enumeration constant} (shortened to \newterm{enum}) aliased to a fixed value (constant).
     2173\begin{cfa}
     2174enum Days { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; // enumeration type definition, set of 7 names & values
     2175Days days = Mon; // enumeration type declaration and initialization
     2176\end{cfa}
     2177The set of enums are injected into the variable namespace at the definition scope.
     2178Hence, enums may be overloaded with enum/variable/function names.
     2179\begin{cfa}
     2180enum Foo { Bar };
     2181enum Goo { Bar };       $\C[1.75in]{// overload Foo.Bar}$
     2182int Foo;                        $\C{// type/variable separate namespace}$
     2183double Bar;                     $\C{// overload Foo.Bar, Goo.Bar}\CRT$
     2184\end{cfa}
     2185An anonymous enumeration injects enums with specific values into a scope.
     2186\begin{cfa}
     2187enum { Prime = 103, BufferSize = 1024 };
     2188\end{cfa}
     2189An enumeration is better than using C \Index{preprocessor} or constant declarations.
     2190\begin{cquote}
     2191\begin{tabular}{@{}l@{\hspace{4em}}l@{}}
     2192\begin{cfa}
     2193#define Mon 0
     2194...
     2195#define Sun 6
     2196\end{cfa}
     2197&
     2198\begin{cfa}
     2199const int Mon = 0,
     2200                         ...,
     2201                         Sun = 6;
     2202\end{cfa}
     2203\end{tabular}
     2204\end{cquote}
     2205because the enumeration is succinct, has automatic numbering, can appear in ©case© labels, does not use storage, and is part of the language type-system.
     2206Finally, the type of an enum is implicitly or explicitly specified and the constant value can be implicitly or explicitly specified.
     2207Note, enum values may be repeated in an enumeration.
     2208
     2209
     2210\subsection{Enum type}
     2211
     2212The type of enums can be any type, and an enum's value comes from this type.
     2213Because an enum is a constant, it cannot appear in a mutable context, \eg ©Mon = Sun© is disallowed, and has no address (it is an rvalue).
     2214Therefore, an enum is automatically converted to its constant's base-type, \eg comparing/printing an enum compares/prints its value rather than the enum name;
     2215there is no mechanism to print the enum name.
     2216
     2217The default enum type is ©int©.
     2218Hence, ©Days© is the set type ©Mon©, ©Tue©, ...\,, ©Sun©, while the type of each enum is ©int© and each enum represents a fixed integral value.
     2219If no values are specified for an integral enum type, the enums are automatically numbered by one from left to right starting at zero.
     2220Hence, the value of enum ©Mon© is 0, ©Tue© is 1, ...\,, ©Sun© is 6.
     2221If an enum value is specified, numbering continues by one from that value for subsequent unnumbered enums.
     2222If an enum value is an expression, the compiler performs constant-folding to obtain a constant value.
     2223
     2224\CFA allows other integral types with associated values.
     2225\begin{cfa}
     2226enum( ®char® ) Letter { A ®= 'A'®,  B,  C,  I ®= 'I'®,  J,  K };
     2227enum( ®long long int® ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
     2228\end{cfa}
     2229For enumeration ©Letter©, enum ©A©'s value is explicitly set to ©'A'©, with ©B© and ©C© implicitly numbered with increasing values from ©'A'©, and similarly for enums ©I©, ©J©, and ©K©.
     2230
     2231Non-integral enum types must be explicitly initialized, \eg ©double© is not automatically numbered by one.
     2232\begin{cfa}
     2233// non-integral numeric
     2234enum( ®double® ) Math { PI_2 = 1.570796, PI = 3.141597,  E = 2.718282 }
     2235// pointer
     2236enum( ®char *® ) Name { Fred = "Fred",  Mary = "Mary",  Jane = "Jane" };
     2237int i, j, k;
     2238enum( ®int *® ) ptr { I = &i,  J = &j,  K = &k };
     2239enum( ®int &® ) ref { I = i,  J = j,  K = k };
     2240// tuple
     2241enum( ®[int, int]® ) { T = [ 1, 2 ] };
     2242// function
     2243void f() {...}   void g() {...}
     2244enum( ®void (*)()® ) funs { F = f,  F = g };
     2245// aggregate
     2246struct S { int i, j; };
     2247enum( ®S® ) s { A = { 3,  4 }, B = { 7,  8 } };
     2248// enumeration
     2249enum( ®Letter® ) Greek { Alph = A, Beta = B, /* more enums */  }; // alphabet intersection
     2250\end{cfa}
     2251Enumeration ©Greek© may have more or less enums than ©Letter©, but the enum values \emph{must} be from ©Letter©.
     2252Therefore, ©Greek© enums are a subset of type ©Letter© and are type compatible with enumeration ©Letter©, but ©Letter© enums are not type compatible with enumeration ©Greek©.
     2253
     2254The following examples illustrate the difference between the enumeration type and the type of its enums.
     2255\begin{cfa}
     2256Math m = PI;    $\C[1.5in]{// allowed}$
     2257double d = PI;  $\C{// allowed, conversion to base type}$
     2258m = E;                  $\C{// allowed}$
     2259m = Alph;               $\C{// {\color{red}disallowed}}$
     2260m = 3.141597;   $\C{// {\color{red}disallowed}}$
     2261d = m;                  $\C{// allowed}$
     2262d = Alph;               $\C{// {\color{red}disallowed}}$
     2263Letter l = A;   $\C{// allowed}$
     2264Greek g = Alph; $\C{// allowed}$
     2265l = Alph;               $\C{// allowed, conversion to base type}$
     2266g = A;                  $\C{// {\color{red}disallowed}}\CRT$
     2267\end{cfa}
     2268
     2269A constructor \emph{cannot} be used to initialize enums because a constructor executes at runtime.
     2270A fallback is explicit C-style initialization using ©@=©.
     2271\begin{cfa}
     2272enum( struct vec3 ) Axis { Up @= { 1, 0, 0 }, Left @= { 0, 1, 0 }, Front @= { 0, 0, 1 } }
     2273\end{cfa}
     2274Finally, enumeration variables are assignable and comparable only if the appropriate operators are defined for its enum type.
     2275
     2276
     2277\subsection{Inheritance}
     2278
     2279\Index{Plan-9}\index{inheritance!enumeration} inheritance may be used with enumerations.
     2280\begin{cfa}
     2281enum( char * ) Name2 { ®inline Name®, Jack = "Jack", Jill = "Jill" };
     2282enum ®/* inferred */®  Name3 { ®inline Name2®, Sue = "Sue", Tom = "Tom" };
     2283\end{cfa}
     2284Enumeration ©Name2© inherits all the enums and their values from enumeration ©Name© by containment, and a ©Name© enumeration is a subtype of enumeration ©Name2©.
     2285Note, enums must be unique in inheritance but enum values may be repeated.
     2286The enum type for the inheriting type must be the same as the inherited type;
     2287hence the enum type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for ©Name3©.
     2288When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important, \eg the placement of ©Sue© and ©Tom© before or after ©inline Name2©.
     2289
     2290Specifically, the inheritance relationship for ©Name©s is:
     2291\begin{cfa}
     2292Name $\(\subseteq\)$ Name2 $\(\subseteq\)$ Name3 $\(\subseteq\)$ const char * // enum type of Name
     2293\end{cfa}
     2294Hence, given
     2295\begin{cfa}
     2296void f( Name );
     2297void g( Name2 );
     2298void h( Name3 );
     2299void j( const char * );
     2300\end{cfa}
     2301the following calls are valid
     2302\begin{cfa}
     2303f( Fred );
     2304g( Fred );   g( Jill );
     2305h( Fred );   h( Jill );   h( Sue );
     2306j( Fred );    j( Jill );    j( Sue );    j( 'W' );
     2307\end{cfa}
     2308Note, the validity of calls is the same for call-by-reference as for call-by-value, and ©const© restrictions are the same as for other types.
     2309
     2310Enums cannot be created at runtime, so inheritence problems, such as contra-variance do not apply.
     2311Only instances of the enum base-type may be created at runtime.
     2312
     2313\begin{comment}
     2314The invariance of references, as I show at the bottom, is easy to overlook.  Not shown, but on the same topic, is that returns work in the opposite direction as parameters.  Hopefully our existing type rules already know both those facts, so that we'd only have to provide the rules that I suggest using the by-value parameters.
     2315
     2316The Fred, Jack, and Mary declarations are picked verbatim from our earlier whiteboard, just repeated here for reference.
     2317
     2318\begin{cfa}
     2319// Fred is a subset of char *
     2320enum( char *) Fred { A = "A", B = "B", C = "C" };
     2321// Jack is a subset of Fred
     2322enum( enum Fred ) Jack { W = A, Y = C};
     2323// Mary is a superset of Fred
     2324enum Mary { inline Fred, D = "hello" };
     2325
     2326// Demonstrating invariance of references
     2327
     2328[void] frcs( & * char x ) { char * x0 = x; x = "bye"; }
     2329[void] frf ( & Fred   x ) { Fred   x0 = x; x = B;     }
     2330[void] frj ( & Jack   x ) { Jack   x0 = x; x = W;     }
     2331[void] frm ( & Mary   x ) { Mary   x0 = x; x = D;     }
     2332
     2333char * vcs;
     2334Fred   vf;
     2335Jack   vj;
     2336Mary   vm;
     2337
     2338// all variant calls: bad  (here are noteworthy examples)
     2339             frcs( vf  );  // can't assign "bye" to vf
     2340             frm ( vf  );  // can't assign D     to vf
     2341             frf ( vj  );  // can't assign B     to vj
     2342vf  = B    ; frj ( vf  );  // can't assign B     to frj.x0
     2343vcs = "bye"; frf ( vcs );  // can't assign "bye" to frf.x0
     2344\end{cfa}
     2345
     2346This example is really great. However, I think it's work explicitly doing one with ©const &©.
     2347\end{comment}
     2348
     2349
    21662350\section{Routine Definition}
    21672351
    2168 \CFA also supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax.
     2352\CFA supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax.
    21692353The point of the new syntax is to allow returning multiple values from a routine~\cite{Galletly96,CLU}, \eg:
    21702354\begin{cfa}
    2171 @[ int o1, int o2, char o3 ]@ f( int i1, char i2, char i3 ) {
     2355®[ int o1, int o2, char o3 ]® f( int i1, char i2, char i3 ) {
    21722356        $\emph{routine body}$
    21732357}
    21742358\end{cfa}
    21752359where routine ©f© has three output (return values) and three input parameters.
    2176 Existing C syntax cannot be extended with multiple return types because it is impossible to embed a single routine name within multiple return type specifications.
     2360Existing C syntax cannot be extended with multiple return types because it is impossible to embed a single routine name within multiple return type-specifications.
    21772361
    21782362In detail, the brackets, ©[]©, enclose the result type, where each return value is named and that name is a local variable of the particular return type.\footnote{
     
    21812365Declaration qualifiers can only appear at the start of a routine definition, \eg:
    21822366\begin{cfa}
    2183 @extern@ [ int x ] g( int y ) {$\,$}
     2367®extern® [ int x ] g( int y ) {$\,$}
    21842368\end{cfa}
    21852369Lastly, if there are no output parameters or input parameters, the brackets and/or parentheses must still be specified;
     
    22002384int (*f(x))[ 5 ] int x; {}
    22012385\end{cfa}
    2202 The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter x of type array of 5 integers.
     2386The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter ©x© of type array of 5 integers.
    22032387Since the strings overlap starting with the open bracket, ©[©, there is an ambiguous interpretation for the string.
    22042388As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity:
     
    22392423\begin{minipage}{\linewidth}
    22402424\begin{cfa}
    2241 @[ int x, int y ]@ f() {
     2425®[ int x, int y ]® f() {
    22422426        int z;
    22432427        ... x = 0; ... y = z; ...
    2244         @return;@ $\C{// implicitly return x, y}$
     2428        ®return;® $\C{// implicitly return x, y}$
    22452429}
    22462430\end{cfa}
     
    25742758
    25752759int fred() {
    2576         s.t.c = @S.@R;  // type qualification
    2577         struct @S.@T t = { @S.@R, 1, 2 };
    2578         enum @S.@C c;
    2579         union @S.T.@U u;
     2760        s.t.c = ®S.®R;  // type qualification
     2761        struct ®S.®T t = { ®S.®R, 1, 2 };
     2762        enum ®S.®C c;
     2763        union ®S.T.®U u;
    25802764}
    25812765\end{cfa}
     
    26032787qsort( ia, size ); $\C{// sort ascending order using builtin ?<?}$
    26042788{
    2605         @int ?<?( int x, int y ) { return x > y; }@ $\C{// nested routine}$
     2789        ®int ?<?( int x, int y ) { return x > y; }® $\C{// nested routine}$
    26062790        qsort( ia, size ); $\C{// sort descending order by local redefinition}$
    26072791}
     
    26132797\begin{cfa}
    26142798[* [int]( int )] foo() { $\C{// int (* foo())( int )}$
    2615         int @i@ = 7;
     2799        int ®i® = 7;
    26162800        int bar( int p ) {
    2617                 @i@ += 1; $\C{// dependent on local variable}$
    2618                 sout | @i@;
     2801                ®i® += 1; $\C{// dependent on local variable}$
     2802                sout | ®i®;
    26192803        }
    26202804        return bar; $\C{// undefined because of local dependence}$
     
    26342818In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call.
    26352819\begin{cfa}
    2636 f( @2, x, 3 + i@ ); $\C{// element list}$
     2820f( ®2, x, 3 + i® ); $\C{// element list}$
    26372821\end{cfa}
    26382822A list of elements is called a \newterm{tuple}, and is different from a \Index{comma expression}.
     
    27472931In \CFA, it is possible to overcome this restriction by declaring a \newterm{tuple variable}.
    27482932\begin{cfa}
    2749 [int, int] @qr@ = div( 13, 5 ); $\C{// initialize tuple variable}$
    2750 printf( "%d %d\n", @qr@ ); $\C{// print quotient/remainder}$
     2933[int, int] ®qr® = div( 13, 5 ); $\C{// initialize tuple variable}$
     2934printf( "%d %d\n", ®qr® ); $\C{// print quotient/remainder}$
    27512935\end{cfa}
    27522936It is now possible to match the multiple return-values to a single variable, in much the same way as \Index{aggregation}.
     
    34123596\begin{cfa}
    34133597int x = 1, y = 2, z = 3;
    3414 sout | x @|@ y @|@ z;
     3598sout | x ®|® y ®|® z;
    34153599\end{cfa}
    34163600&
    34173601\begin{cfa}
    34183602
    3419 cout << x @<< " "@ << y @<< " "@ << z << endl;
     3603cout << x ®<< " "® << y ®<< " "® << z << endl;
    34203604\end{cfa}
    34213605&
     
    34263610\\
    34273611\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3428 1@ @2@ @3
     36121® ®2® ®3
    34293613\end{cfa}
    34303614&
    34313615\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3432 1@ @2@ @3
     36161® ®2® ®3
    34333617\end{cfa}
    34343618&
    34353619\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3436 1@ @2@ @3
     36201® ®2® ®3
    34373621\end{cfa}
    34383622\end{tabular}
    34393623\end{cquote}
    34403624The \CFA form has half the characters of the \CC form, and is similar to \Index*{Python} I/O with respect to implicit separators and newline.
    3441 Similar simplification occurs for \Index{tuple} I/O, which flattens the tuple and prints each value separated by ``\lstinline[showspaces=true]@, @''.
     3625Similar simplification occurs for \Index{tuple} I/O, which flattens the tuple and prints each value separated by ``\lstinline[showspaces=true]{, }''.
    34423626\begin{cfa}
    34433627[int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 4, [ 5, 6 ] ];
     
    34453629\end{cfa}
    34463630\begin{cfa}[showspaces=true,aboveskip=0pt]
    3447 1@, @2@, @3 4@, @5@, @6
     36311®, ®2®, ®3 4®, ®5®, ®6
    34483632\end{cfa}
    34493633Finally, \CFA uses the logical-or operator for I/O as it is the lowest-priority \emph{overloadable} operator, other than assignment.
     
    34543638&
    34553639\begin{cfa}
    3456 sout | x * 3 | y + 1 | z << 2 | x == y | @(@x | y@)@ | @(@x || y@)@ | @(@x > z ? 1 : 2@)@;
     3640sout | x * 3 | y + 1 | z << 2 | x == y | ®(®x | y®)® | ®(®x || y®)® | ®(®x > z ? 1 : 2®)®;
    34573641\end{cfa}
    34583642\\
     
    34603644&
    34613645\begin{cfa}
    3462 cout << x * 3 << y + 1 << @(@z << 2@)@ << @(@x == y@)@ << @(@x | y@)@ << @(@x || y@)@ << @(@x > z ? 1 : 2@)@ << endl;
     3646cout << x * 3 << y + 1 << ®(®z << 2®)® << ®(®x == y®)® << ®(®x | y®)® << ®(®x || y®)® << ®(®x > z ? 1 : 2®)® << endl;
    34633647\end{cfa}
    34643648\\
     
    34953679\\
    34963680\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3497 @1@ @2.5@ @A@
     3681®1® ®2.5® ®A®
    34983682
    34993683
     
    35013685&
    35023686\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3503 @1@ @2.5@ @A@
     3687®1® ®2.5® ®A®
    35043688
    35053689
     
    35073691&
    35083692\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3509 @1@
    3510 @2.5@
    3511 @A@
     3693®1®
     3694®2.5®
     3695®A®
    35123696\end{cfa}
    35133697\end{tabular}
     
    35453729
    35463730\item
    3547 A separator does not appear before a C string starting with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \LstStringStyle{,.;!?)]\}\%\textcent\guillemotright}, where \LstStringStyle{\guillemotright} a closing citation mark.
     3731A separator does not appear before a C string starting with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \LstStringStyle{,.;!?)]\}\%\textcent\guillemotright}, where \LstStringStyle{\guillemotright} is a closing citation mark.
    35483732\begin{cfa}
    35493733sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x"
     
    35513735\end{cfa}
    35523736\begin{cfa}[showspaces=true]
    3553 1@,@ x 2@.@ x 3@;@ x 4@!@ x 5@?@ x 6@%@ x 7$\R{\LstStringStyle{\textcent}}$ x 8$\R{\LstStringStyle{\guillemotright}}$ x 9@)@ x 10@]@ x 11@}@ x
     37371®,® x 2®.® x 3®;® x 4®!® x 5®?® x 6®%® x 7$\R{\LstStringStyle{\textcent}}$ x 8$\R{\LstStringStyle{\guillemotright}}$ x 9®)® x 10®]® x 11®}® x
    35543738\end{cfa}
    35553739
     
    35583742%$
    35593743\begin{cfa}
    3560 sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x $\LstStringStyle{\textsterling}$" | 6 | "x $\LstStringStyle{\textyen}$"
     3744sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $\LstStringStyle{\textdollar}$" | 5 | "x $\LstStringStyle{\textsterling}$" | 6 | "x $\LstStringStyle{\textyen}$"
    35613745           | 7 | "x $\LstStringStyle{\textexclamdown}$" | 8 | "x $\LstStringStyle{\textquestiondown}$" | 9 | "x $\LstStringStyle{\guillemotleft}$" | 10;
    35623746\end{cfa}
    35633747%$
    35643748\begin{cfa}[showspaces=true]
    3565 x @(@1 x @[@2 x @{@3 x @=@4 x $\LstStringStyle{\textdollar}$5 x $\R{\LstStringStyle{\textsterling}}$6 x $\R{\LstStringStyle{\textyen}}$7 x $\R{\LstStringStyle{\textexclamdown}}$8 x $\R{\LstStringStyle{\textquestiondown}}$9 x $\R{\LstStringStyle{\guillemotleft}}$10
     3749x ®(®1 x ®[®2 x ®{®3 x ®=®4 x $\LstStringStyle{\textdollar}$5 x $\R{\LstStringStyle{\textsterling}}$6 x $\R{\LstStringStyle{\textyen}}$7 x $\R{\LstStringStyle{\textexclamdown}}$8 x $\R{\LstStringStyle{\textquestiondown}}$9 x $\R{\LstStringStyle{\guillemotleft}}$10
    35663750\end{cfa}
    35673751%$
    35683752
    35693753\item
    3570 A seperator does not appear before/after a C string starting/ending with the \Index*{ASCII} quote or whitespace characters: \lstinline[basicstyle=\tt,showspaces=true]{`'": \t\v\f\r\n}
     3754A separator does not appear before/after a C string starting/ending with the \Index*{ASCII} quote or whitespace characters: \lstinline[basicstyle=\tt,showspaces=true]{`'": \t\v\f\r\n}
    35713755\begin{cfa}
    35723756sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx";
    35733757\end{cfa}
    35743758\begin{cfa}[showspaces=true,showtabs=true]
    3575 x@`@1@`@x$\R{\texttt{'}}$2$\R{\texttt{'}}$x$\R{\texttt{"}}$3$\R{\texttt{"}}$x@:@4@:@x@ @5@ @x@  @6@     @x
     3759x®`®1®`®x$\R{\texttt{'}}$2$\R{\texttt{'}}$x$\R{\texttt{"}}$3$\R{\texttt{"}}$x®:®4®:®x® ®5® ®x®  ®6®     ®x
    35763760\end{cfa}
    35773761
     
    35823766\end{cfa}
    35833767\begin{cfa}[showspaces=true,showtabs=true]
    3584 x (@ @1@ @) x 2@ @, x 3@ @:x:@ @4
     3768x (® ®1® ®) x 2® ®, x 3® ®:x:® ®4
    35853769\end{cfa}
    35863770\end{enumerate}
     
    35953779\Indexc{sepSet}\index{manipulator!sepSet@©sepSet©} and \Indexc{sep}\index{manipulator!sep@©sep©}/\Indexc{sepGet}\index{manipulator!sepGet@©sepGet©} set and get the separator string.
    35963780The separator string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters).
    3597 \begin{cfa}[escapechar=off,belowskip=0pt]
    3598 sepSet( sout, ", $" ); $\C{// set separator from " " to ", \$"}$
    3599 sout | 1 | 2 | 3 | " \"" | @sep@ | "\"";
    3600 \end{cfa}
    3601 %$
    3602 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt]
    3603 1@, $@2@, $@3 @", $"@
    3604 \end{cfa}
    3605 %$
     3781\begin{cfa}[belowskip=0pt]
     3782sepSet( sout, ", $\LstStringStyle{\textdollar}$" ); $\C{// set separator from " " to ", \$"}$
     3783sout | 1 | 2 | 3 | " \"" | ®sep® | "\"";
     3784\end{cfa}
     3785\begin{cfa}[showspaces=true,aboveskip=0pt]
     37861®, $\LstStringStyle{\textdollar}$®2®, $\LstStringStyle{\textdollar}$®3 ®", $\LstStringStyle{\textdollar}$"®
     3787\end{cfa}
    36063788\begin{cfa}[belowskip=0pt]
    36073789sepSet( sout, " " ); $\C{// reset separator to " "}$
    3608 sout | 1 | 2 | 3 | " \"" | @sepGet( sout )@ | "\"";
     3790sout | 1 | 2 | 3 | " \"" | ®sepGet( sout )® | "\"";
    36093791\end{cfa}
    36103792\begin{cfa}[showspaces=true,aboveskip=0pt]
    3611 1@ @2@ @3 @" "@
     37931® ®2® ®3 ®" "®
    36123794\end{cfa}
    36133795©sepGet© can be used to store a separator and then restore it:
    36143796\begin{cfa}[belowskip=0pt]
    3615 char store[@sepSize@]; $\C{// sepSize is the maximum separator size}$
     3797char store[®sepSize®]; $\C{// sepSize is the maximum separator size}$
    36163798strcpy( store, sepGet( sout ) ); $\C{// copy current separator}$
    36173799sepSet( sout, "_" ); $\C{// change separator to underscore}$
     
    36193801\end{cfa}
    36203802\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3621 1@_@2@_@3
     38031®_®2®_®3
    36223804\end{cfa}
    36233805\begin{cfa}[belowskip=0pt]
     
    36263808\end{cfa}
    36273809\begin{cfa}[showspaces=true,aboveskip=0pt]
    3628 1@ @2@ @3
     38101® ®2® ®3
    36293811\end{cfa}
    36303812
     
    36343816\begin{cfa}[belowskip=0pt]
    36353817sepSetTuple( sout, " " ); $\C{// set tuple separator from ", " to " "}$
    3636 sout | t1 | t2 | " \"" | @sepTuple@ | "\"";
     3818sout | t1 | t2 | " \"" | ®sepTuple® | "\"";
    36373819\end{cfa}
    36383820\begin{cfa}[showspaces=true,aboveskip=0pt]
    3639 1 2 3 4 5 6 @" "@
     38211 2 3 4 5 6 ®" "®
    36403822\end{cfa}
    36413823\begin{cfa}[belowskip=0pt]
    36423824sepSetTuple( sout, ", " ); $\C{// reset tuple separator to ", "}$
    3643 sout | t1 | t2 | " \"" | @sepGetTuple( sout )@ | "\"";
     3825sout | t1 | t2 | " \"" | ®sepGetTuple( sout )® | "\"";
    36443826\end{cfa}
    36453827\begin{cfa}[showspaces=true,aboveskip=0pt]
    3646 1, 2, 3 4, 5, 6 @", "@
     38281, 2, 3 4, 5, 6 ®", "®
    36473829\end{cfa}
    36483830As for ©sepGet©, ©sepGetTuple© can be use to store a tuple separator and then restore it.
     
    36963878\end{cfa}
    36973879\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3698 @ @1 2 3@ @
     3880® ®1 2 3® ®
    36993881\end{cfa}
    37003882\end{enumerate}
     
    37163898For example, in:
    37173899\begin{cfa}
    3718 sin | i | @nl@ | j;
    3719 1 @2@
     3900sin | i | ®nl® | j;
     39011 ®2®
    372039023
    37213903\end{cfa}
     
    375839400b0 0b11011 0b11011 0b11011 0b11011
    37593941sout | bin( -27HH ) | bin( -27H ) | bin( -27 ) | bin( -27L );
    3760 0b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b@(58 1s)@100101
     39420b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b®(58 1s)®100101
    37613943\end{cfa}
    37623944
     
    37943976
    37953977\item
     3978\Indexc{eng}( floating-point )\index{manipulator!eng@©eng©} print value in engineering notation with exponent, which means the exponent is adjusted to a multiple of 3.
     3979\begin{cfa}[belowskip=0pt]
     3980sout | eng( 0.0 ) | eng( 27000.5 ) | eng( -27.5e7 );
     39810®e0® 27.0005®e3® -275®e6®
     3982\end{cfa}
     3983
     3984\item
     3985\Indexc{unit}( engineering-notation )\index{manipulator!unit@©unit©} print engineering exponent as a letter between the range $10^{-24}$ and $10^{24}$:
     3986©y© $\Rightarrow 10^{-24}$, ©z© $\Rightarrow 10^{-21}$, ©a© $\Rightarrow 10^{-18}$, ©f© $\Rightarrow 10^{-15}$, ©p© $\Rightarrow 10^{-12}$, ©n© $\Rightarrow 10^{-9}$, ©u© $\Rightarrow 10^{-6}$, ©m© $\Rightarrow 10^{-3}$, ©K© $\Rightarrow 10^{3}$, ©M© $\Rightarrow 10^{6}$, ©G© $\Rightarrow 10^{9}$, ©T© $\Rightarrow 10^{12}$, ©P© $\Rightarrow 10^{15}$, ©E© $\Rightarrow 10^{18}$, ©Z© $\Rightarrow 10^{21}$, ©Y© $\Rightarrow 10^{24}$.
     3987For exponent $10^{0}$, no decimal point or letter is printed.
     3988\begin{cfa}[belowskip=0pt]
     3989sout | unit(eng( 0.0 )) | unit(eng( 27000.5 )) | unit(eng( -27.5e7 ));
     39900 27.0005®K® -275®M®
     3991\end{cfa}
     3992
     3993\item
    37963994\Indexc{upcase}( bin / hex / floating-point )\index{manipulator!upcase@©upcase©} print letters in a value in upper case. Lower case is the default.
    37973995\begin{cfa}[belowskip=0pt]
    37983996sout | upcase( bin( 27 ) ) | upcase( hex( 27 ) ) | upcase( 27.5e-10 ) | upcase( hex( 27.5 ) );
    3799 0@B@11011 0@X@1@B@ 2.75@E@-09 0@X@1.@B@8@P@+4
     39970®B®11011 0®X®1®B® 2.75®E®-09 0®X®1.®B®8®P®+4
    38003998\end{cfa}
    38013999
     
    38134011\begin{cfa}[belowskip=0pt]
    38144012sout | 0. | nodp( 0. ) | 27.0 | nodp( 27.0 ) | nodp( 27.5 );
    3815 0.0 @0@ 27.0 @27@ 27.5
     40130.0 ®0® 27.0 ®27® 27.5
    38164014\end{cfa}
    38174015
     
    38204018\begin{cfa}[belowskip=0pt]
    38214019sout | sign( 27 ) | sign( -27 ) | sign( 27. ) | sign( -27. ) | sign( 27.5 ) | sign( -27.5 );
    3822 @+@27 -27 @+@27.0 -27.0 @+@27.5 -27.5
    3823 \end{cfa}
    3824 
    3825 \item
    3826 \Indexc{wd}©( unsigned char minimum, T val )©\index{manipulator!wd@©wd©}, ©wd( unsigned char minimum, unsigned char precision, T val )©
    3827 For all types, ©minimum© is the minimum number of printed characters.
     4020®+®27 -27 ®+®27.0 -27.0 ®+®27.5 -27.5
     4021\end{cfa}
     4022
     4023\item
     4024\Indexc{wd}( minimum, value )\index{manipulator!wd@©wd©}, ©wd©( minimum, precision, value )
     4025For all types, minimum is the number of printed characters.
    38284026If the value is shorter than the minimum, it is padded on the right with spaces.
    38294027\begin{cfa}[belowskip=0pt]
     
    38334031\end{cfa}
    38344032\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3835 @  @34 @ @34 34
    3836 @  @4.000000 @ @4.000000 4.000000
    3837 @  @ab @ @ab ab
    3838 \end{cfa}
    3839 If the value is larger, it is printed without truncation, ignoring the ©minimum©.
     4033®  ®34 ® ®34 34
     4034®  ®4.000000 ® ®4.000000 4.000000
     4035®  ®ab ® ®ab ab
     4036\end{cfa}
     4037If the value is larger, it is printed without truncation, ignoring the minimum.
    38404038\begin{cfa}[belowskip=0pt]
    38414039sout | wd( 4, 34567 ) | wd( 3, 34567 ) | wd( 2, 34567 );
     
    38444042\end{cfa}
    38454043\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3846 3456@7@ 345@67@ 34@567@
    3847 3456@.@ 345@6.@ 34@56.@
    3848 abcd@e@ abc@de@ ab@cde@
    3849 \end{cfa}
    3850 
    3851 For integer types, ©precision© is the minimum number of printed digits.
     40443456®7® 345®67® 34®567®
     40453456®.® 345®6.® 34®56.®
     4046abcd®e® abc®de® ab®cde®
     4047\end{cfa}
     4048
     4049For integer types, precision is the minimum number of printed digits.
    38524050If the value is shorter, it is padded on the left with leading zeros.
    38534051\begin{cfa}[belowskip=0pt]
     
    38554053\end{cfa}
    38564054\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3857  @0@34     @00@34 @00000000@34
    3858 \end{cfa}
    3859 If the value is larger, it is printed without truncation, ignoring the ©precision©.
     4055 ®0®34     ®00®34 ®00000000®34
     4056\end{cfa}
     4057If the value is larger, it is printed without truncation, ignoring the precision.
    38604058\begin{cfa}[belowskip=0pt]
    38614059sout | wd( 4,1, 3456 ) | wd( 8,2, 3456 ) | wd( 10,3, 3456 );
     
    386440623456     3456       3456
    38654063\end{cfa}
    3866 If ©precision© is 0, nothing is printed for zero.
    3867 If ©precision© is greater than the minimum, it becomes the minimum.
     4064If precision is 0, nothing is printed for zero.
     4065If precision is greater than the minimum, it becomes the minimum.
    38684066\begin{cfa}[belowskip=0pt]
    38694067sout | wd( 4,0, 0 ) | wd( 3,10, 34 );
    38704068\end{cfa}
    38714069\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3872 @    @ @00000000@34
    3873 \end{cfa}
    3874 For floating-point types, ©precision© is the minimum number of digits after the decimal point.
     4070®    ® ®00000000®34
     4071\end{cfa}
     4072For floating-point types, precision is the minimum number of digits after the decimal point.
    38754073\begin{cfa}[belowskip=0pt]
    38764074sout | wd( 6,3, 27.5 ) | wd( 8,1, 27.5 ) | wd( 8,0, 27.5 ) | wd( 3,8, 27.5 );
    38774075\end{cfa}
    38784076\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3879 27.@500@     27.@5@      28. 27.@50000000@
    3880 \end{cfa}
    3881 For the C-string type, ©precision© is the maximum number of printed characters, so the string is truncated if it exceeds the maximum.
     407727.®500®     27.®5®      28. 27.®50000000®
     4078\end{cfa}
     4079For the C-string type, precision is the maximum number of printed characters, so the string is truncated if it exceeds the maximum.
    38824080\begin{cfa}[belowskip=0pt]
    38834081sout | wd( 6,8, "abcd" ) | wd( 6,8, "abcdefghijk" ) | wd( 6,3, "abcd" );
     
    38884086
    38894087\item
    3890 \Indexc{ws( unsigned char minimum, unsigned char significant, floating-point )}\index{manipulator!ws@©ws©}
    3891 For floating-point type, ©minimum© is the same as for manipulator ©wd©, but ©significant© is the maximum number of significant digits to be printed for both the integer and fractions (versus only the fraction for ©wd©).
    3892 If a value's significant digits is greater than ©significant©, the last significant digit is rounded up.
     4088\begin{sloppypar}
     4089\Indexc{ws}( minimum, significant, floating-point )\index{manipulator!ws@©ws©}
     4090For floating-point types, minimum is the same as for manipulator ©wd©, but significant is the maximum number of significant digits to be printed for both the integer and fractions (versus only the fraction for ©wd©).
     4091If a value's significant digits is greater than significant, the last significant digit is rounded up.
     4092\end{sloppypar}
    38934093\begin{cfa}[belowskip=0pt]
    38944094sout | ws(6,6, 234.567) | ws(6,5, 234.567) | ws(6,4, 234.567) | ws(6,3, 234.567);
    38954095\end{cfa}
    38964096\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3897 234.567 234.5@7@  234.@6@    23@5@
    3898 \end{cfa}
    3899 If a value's magnitude is greater than ©significant©, the value is printed in scientific notation with the specified number of significant digits.
     4097234.567 234.5®7®  234.®6®    23®5®
     4098\end{cfa}
     4099If a value's magnitude is greater than significant, the value is printed in scientific notation with the specified number of significant digits.
    39004100\begin{cfa}[belowskip=0pt]
    39014101sout | ws(6,6, 234567.) | ws(6,5, 234567.) | ws(6,4, 234567.) | ws(6,3, 234567.);
    39024102\end{cfa}
    39034103\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3904 234567. 2.3457@e+05@ 2.346@e+05@ 2.35@e+05@
    3905 \end{cfa}
    3906 If ©significant© is greater than ©minimum©, it defines the number of printed characters.
     4104234567. 2.3457®e+05® 2.346®e+05® 2.35®e+05®
     4105\end{cfa}
     4106If significant is greater than minimum, it defines the number of printed characters.
    39074107\begin{cfa}[belowskip=0pt]
    39084108sout | ws(3,6, 234567.) | ws(4,6, 234567.) | ws(5,6, 234567.) | ws(6,6, 234567.);
     
    39184118\end{cfa}
    39194119\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3920 27@  @ 27.000000  27.500000  027  27.500@    @
     412027®  ® 27.000000  27.500000  027  27.500®    ®
    39214121\end{cfa}
    39224122
     
    39254125\begin{cfa}[belowskip=0pt]
    39264126sout | pad0( wd( 4, 27 ) ) | pad0( wd( 4,3, 27 ) ) | pad0( wd( 8,3, 27.5 ) );
    3927 @00@27  @0@27 @00@27.500
     4127®00®27  ®0®27 ®00®27.500
    39284128\end{cfa}
    39294129\end{enumerate}
     
    39894189
    39904190The format of numeric input values in the same as C constants without a trailing type suffix, as the input value-type is denoted by the input variable.
    3991 For ©_Bool© type, the constants are ©true© and ©false©.
     4191For ©bool© type, the constants are ©true© and ©false©.
    39924192For integral types, any number of digits, optionally preceded by a sign (©+© or ©-©), where a
    39934193\begin{itemize}
     
    40104210\begin{enumerate}
    40114211\item
    4012 \Indexc{skip( const char * pattern )}\index{manipulator!skip@©skip©} / ©skip( unsigned int length )© / ©const char * pattern©
    4013 The argument defines a ©pattern© or ©length©.
    4014 The ©pattern© is composed of white-space and non-white-space characters, where \emph{any} white-space character matches 0 or more input white-space characters (hence, consecutive white-space characters in the pattern are combined), and each non-white-space character matches exactly with an input character.
    4015 The ©length© is composed of the next $N$ characters, including the newline character.
     4212\Indexc{skip}( pattern )\index{manipulator!skip@©skip©}, ©skip©( length )
     4213The pattern is composed of white-space and non-white-space characters, where \emph{any} white-space character matches 0 or more input white-space characters (hence, consecutive white-space characters in the pattern are combined), and each non-white-space character matches exactly with an input character.
     4214The length is composed of the next $N$ characters, including the newline character.
    40164215If the match successes, the input characters are discarded, and input continues with the next character.
    40174216If the match fails, the input characters are left unread.
     
    40214220\end{cfa}
    40224221\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4023 @abc   @
    4024 @abc  @
    4025 @xx@
    4026 \end{cfa}
    4027 
    4028 \item
    4029 \Indexc{wdi}©( unsigned int maximum, T & val )©\index{manipulator!wdi@©wdi©}
    4030 For all types except ©char©, ©maximum© is the maximum number of characters read for the current operation.
     4222®abc   ®
     4223®abc  ®
     4224®xx®
     4225\end{cfa}
     4226
     4227\item
     4228\Indexc{wdi}( maximum, reference-value )\index{manipulator!wdi@©wdi©}
     4229For all types except ©char©, maximum is the maximum number of characters read for the current operation.
    40314230\begin{cfa}[belowskip=0pt]
    40324231char s[10];   int i;   double d;   
     
    40344233\end{cfa}
    40354234\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4036 @abcd1233.456E+2@
     4235®abcd1233.456E+2®
    40374236\end{cfa}
    40384237Note, input ©wdi© cannot be overloaded with output ©wd© because both have the same parameters but return different types.
     
    40404239
    40414240\item
    4042 \Indexc{ignore( T & val )}\index{manipulator!ignore@©ignore©}
     4241\Indexc{ignore}( reference-value )\index{manipulator!ignore@©ignore©}
    40434242For all types, the data is read from the stream depending on the argument type but ignored, \ie it is not stored in the argument.
    40444243\begin{cfa}[belowskip=0pt]
     
    40474246\end{cfa}
    40484247\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4049 @  -75.35e-4@ 25
    4050 \end{cfa}
    4051 
    4052 \item
    4053 \Indexc{incl( const char * scanset, char * s )}\index{manipulator!incl@©incl©}
    4054 For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{in} the set.
    4055 Matching characters are read into the C string and null terminated.
     4248®  -75.35e-4® 25
     4249\end{cfa}
     4250
     4251\item
     4252\Indexc{incl}( scanset, input-string )\index{manipulator!incl@©incl©}
     4253For C-string types, the scanset matches any number of characters \emph{in} the set.
     4254Matching characters are read into the C input-string and null terminated.
    40564255\begin{cfa}[belowskip=0pt]
    40574256char s[10];
     
    40594258\end{cfa}
    40604259\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4061 @bca@xyz
    4062 \end{cfa}
    4063 
    4064 \item
    4065 \Indexc{excl( const char * scanset, char * s )}\index{manipulator!excl@©excl©}
    4066 For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{not in} the set.
    4067 Non-matching characters are read into the C string and null terminated.
     4260®bca®xyz
     4261\end{cfa}
     4262
     4263\item
     4264\Indexc{excl}( scanset, input-string )\index{manipulator!excl@©excl©}
     4265For C-string types, the scanset matches any number of characters \emph{not in} the set.
     4266Non-matching characters are read into the C input-string and null terminated.
    40684267\begin{cfa}[belowskip=0pt]
    40694268char s[10];
     
    40714270\end{cfa}
    40724271\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4073 @xyz@bca
     4272®xyz®bca
    40744273\end{cfa}
    40754274\end{enumerate}
    40764275
    40774276
     4277\subsection{Concurrent Stream Access}
     4278
     4279When a stream is shared by multiple threads, input or output characters can be intermixed or cause failure.
     4280For example, if two threads execute the following:
     4281\begin{cfa}
     4282$\emph{thread\(_1\)}$ : sout | "abc " | "def ";
     4283$\emph{thread\(_2\)}$ : sout | "uvw " | "xyz ";
     4284\end{cfa}
     4285possible outputs are:
     4286\begin{cquote}
     4287\begin{tabular}{@{}l|l|l|l|l@{}}
     4288\begin{cfa}
     4289abc def
     4290uvw xyz
     4291\end{cfa}
     4292&
     4293\begin{cfa}
     4294abc uvw xyz
     4295def
     4296\end{cfa}
     4297&
     4298\begin{cfa}
     4299uvw abc xyz def
     4300
     4301\end{cfa}
     4302&
     4303\begin{cfa}
     4304abuvwc dexf
     4305yz
     4306\end{cfa}
     4307&
     4308\begin{cfa}
     4309uvw abc def
     4310xyz
     4311\end{cfa}
     4312\end{tabular}
     4313\end{cquote}
     4314Concurrent operations can even corrupt the internal state of the stream resulting in failure.
     4315As a result, some form of mutual exclusion is required for concurrent stream access.
     4316
     4317A coarse-grained solution is to perform all stream operations via a single thread or within a monitor providing the necessary mutual exclusion for the stream.
     4318A fine-grained solution is to have a lock for each stream, which is acquired and released around stream operations by each thread.
     4319\CFA provides a fine-grained solution where a \Index{recursive lock} is acquired and released indirectly via a manipulator ©acquire© or instantiating an \Index{RAII} type specific for the kind of stream: ©osacquire©\index{ostream@©ostream©!osacquire@©osacquire©} for output streams and ©isacquire©\index{isacquire@©isacquire©}\index{istream@©istream©!isacquire@©isacquire©} for input streams.
     4320
     4321The common usage is manipulator ©acquire©\index{ostream@©ostream©!acquire@©acquire©} to lock a stream during a single cascaded I/O expression, with the manipulator appearing as the first item in a cascade list, \eg:
     4322\begin{cfa}
     4323$\emph{thread\(_1\)}$ : sout | ®acquire® | "abc " | "def ";   // manipulator
     4324$\emph{thread\(_2\)}$ : sout | ®acquire® | "uvw " | "xyz ";
     4325\end{cfa}
     4326Now, the order of the thread execution is still non-deterministic, but the output is constrained to two possible lines in either order.
     4327\begin{cquote}
     4328\def\VRfont{\fontfamily{pcr}\upshape\selectfont}
     4329\begin{tabular}{@{}l|l@{}}
     4330\begin{cfa}
     4331abc def
     4332uvw xyz
     4333\end{cfa}
     4334&
     4335\begin{cfa}
     4336uvw xyz
     4337abc def
     4338\end{cfa}
     4339\end{tabular}
     4340\end{cquote}
     4341In summary, the stream lock is acquired by the ©acquire© manipulator and implicitly released at the end of the cascaded I/O expression ensuring all operations in the expression occur atomically.
     4342
     4343To lock a stream across multiple I/O operations, an object of type ©osacquire© or ©isacquire© is declared to implicitly acquire/release the stream lock providing mutual exclusion for the object's duration, \eg:
     4344\begin{cfa}
     4345{       // acquire sout for block duration
     4346        ®osacquire® acq = { sout };                             $\C{// named stream locker}$
     4347        sout | 1;
     4348        sout | ®acquire® | 2 | 3;                               $\C{// unnecessary, but ok to acquire and release again}$
     4349        sout | 4;
     4350}       // implicitly release the lock when "acq" is deallocated
     4351\end{cfa}
     4352Note, the unnecessary ©acquire© manipulator works because the recursive stream-lock can be acquired/released multiple times by the owner thread.
     4353Hence, calls to functions that also acquire a stream lock for their output do not result in \Index{deadlock}.
     4354
     4355The previous values written by threads 1 and 2 can be read in concurrently:
     4356\begin{cfa}
     4357{       // acquire sin lock for block duration
     4358        ®isacquire acq = { sin };®                              $\C{// named stream locker}$
     4359        int x, y, z, w;
     4360        sin | x;
     4361        sin | ®acquire® | y | z;                                $\C{// unnecessary, but ok to acquire and release again}$
     4362        sin | w;
     4363}       // implicitly release the lock when "acq" is deallocated
     4364\end{cfa}
     4365Again, the order of the reading threads is non-deterministic.
     4366Note, non-deterministic reading is rare.
     4367
     4368\Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg:
     4369\begin{cfa}
     4370sout | ®acquire® | "data:" | rtn( mon );        $\C{// mutex call on monitor}$
     4371\end{cfa}
     4372If the thread executing the I/O expression blocks in the monitor with the ©sout© lock, other threads writing to ©sout© also block until the thread holding the lock is unblocked and releases it.
     4373This scenario can lead to \Index{deadlock}, if the thread that is going to unblock the thread waiting in the monitor first writes to ©sout© (deadly embrace).
     4374To prevent nested locking, a simple precaution is to factor out the blocking call from the expression, \eg:
     4375\begin{cfa}
     4376int ®data® = rtn( mon );
     4377sout | acquire | "data:" | ®data®;
     4378\end{cfa}
     4379
     4380\Textbf{WARNING:} ©printf©\index{printf@©printf©}, ©scanf©\index{scanf@©scanf©} and their derivatives are unsafe when used with user-level threading, as in \CFA.
     4381These stream routines use kernel-thread locking (©futex©\index{futex@©futex©}), which block kernel threads, to prevent interleaving of I/O.
     4382However, the following simple example illustrates how a deadlock can occur (other complex scenarios are possible).
     4383Assume a single kernel thread and two user-level threads calling ©printf©.
     4384One user-level thread acquires the I/O lock and is time-sliced while performing ©printf©.
     4385The other user-level thread then starts execution, calls ©printf©, and blocks the only kernel thread because it cannot acquire the I/O lock.
     4386It does not help if the kernel lock is multiple acquisition, \ie, the lock owner can acquire it multiple times, because it then results in two user threads in the ©printf© critical section, corrupting the stream.
     4387
     4388
     4389\begin{comment}
    40784390\section{Types}
    40794391
     
    41544466process((int) s); // type is converted, no function is called
    41554467\end{cfa}
     4468\end{comment}
    41564469
    41574470
     
    42874600In C, the integer constants 0 and 1 suffice because the integer promotion rules can convert them to any arithmetic type, and the rules for pointer expressions treat constant expressions evaluating to 0 as a special case.
    42884601However, user-defined arithmetic types often need the equivalent of a 1 or 0 for their functions or operators, polymorphic functions often need 0 and 1 constants of a type matching their polymorphic parameters, and user-defined pointer-like types may need a null value.
    4289 Defining special constants for a user-defined type is more efficient than defining a conversion to the type from ©_Bool©.
     4602Defining special constants for a user-defined type is more efficient than defining a conversion to the type from ©bool©.
    42904603
    42914604Why just 0 and 1? Why not other integers? No other integers have special status in C.
     
    43694682\begin{table}[hbt]
    43704683\centering
    4371 \input{../refrat/operidents}
     4684\begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}}
     4685\begin{tabular}{@{}ll@{}}
     4686©?[?]©  & subscripting \impl{?[?]}                                      \\
     4687©?()©   & function call \impl{?()}                                      \\
     4688©?++©   & postfix increment \impl{?++}                          \\
     4689©?--©   & postfix decrement \impl{?--}                          \\
     4690©++?©   & prefix increment \impl{++?}                           \\
     4691©--?©   & prefix decrement \impl{--?}                           \\
     4692©*?©    & dereference \impl{*?}                                         \\
     4693©+?©    & unary plus \impl{+?}                                          \\
     4694©-?©    & arithmetic negation \impl{-?}                         \\
     4695©~?©    & bitwise negation \impl{~?}                            \\
     4696©!?©    & logical complement \impl{"!?}                         \\
     4697©?\?©   & exponentiation \impl{?\?}                                     \\
     4698©?*?©   & multiplication \impl{?*?}                                     \\
     4699©?/?©   & division \impl{?/?}                                           \\
     4700©?%?©   & remainder \impl{?%?}                                          \\
     4701\end{tabular}
     4702&
     4703\begin{tabular}{@{}ll@{}}
     4704©?+?©   & addition \impl{?+?}                                           \\
     4705©?-?©   & subtraction \impl{?-?}                                        \\
     4706©?<<?©  & left shift \impl{?<<?}                                        \\
     4707©?>>?©  & right shift \impl{?>>?}                                       \\
     4708©?<?©   & less than \impl{?<?}                                          \\
     4709©?<=?©  & less than or equal \impl{?<=?}                        \\
     4710©?>=?©  & greater than or equal \impl{?>=?}                     \\
     4711©?>?©   & greater than \impl{?>?}                                       \\
     4712©?==?©  & equality \impl{?==?}                                          \\
     4713©?!=?©  & inequality \impl{?"!=?}                                       \\
     4714©?&?©   & bitwise AND \impl{?&?}                                        \\
     4715©?^?©   & exclusive OR \impl{?^?}                                       \\
     4716©?|?©   & inclusive OR \impl{?"|?}                                      \\
     4717                                                                                                        \\
     4718                                                                                                        \\
     4719\end{tabular}
     4720&
     4721\begin{tabular}{@{}ll@{}}
     4722©?=?©   & simple assignment \impl{?=?}                          \\
     4723©?\=?©  & exponentiation assignment \impl{?\=?}         \\
     4724©?*=?©  & multiplication assignment \impl{?*=?}         \\
     4725©?/=?©  & division assignment \impl{?/=?}                       \\
     4726©?%=?©  & remainder assignment \impl{?%=?}                      \\
     4727©?+=?©  & addition assignment \impl{?+=?}                       \\
     4728©?-=?©  & subtraction assignment \impl{?-=?}            \\
     4729©?<<=?© & left-shift assignment \impl{?<<=?}            \\
     4730©?>>=?© & right-shift assignment \impl{?>>=?}           \\
     4731©?&=?©  & bitwise AND assignment \impl{?&=?}            \\
     4732©?^=?©  & exclusive OR assignment \impl{?^=?}           \\
     4733©?|=?©  & inclusive OR assignment \impl{?"|=?}          \\
     4734                                                                                                        \\
     4735                                                                                                        \\
     4736                                                                                                        \\
     4737\end{tabular}
     4738\end{tabular}
    43724739\caption{Operator Identifiers}
    43734740\label{opids}
     
    44574824For example, given
    44584825\begin{cfa}
    4459 auto j = @...@
     4826auto j = ®...®
    44604827\end{cfa}
    44614828and the need to write a routine to compute using ©j©
    44624829\begin{cfa}
    4463 void rtn( @...@ parm );
     4830void rtn( ®...® parm );
    44644831rtn( j );
    44654832\end{cfa}
     
    46985065\begin{figure}
    46995066\begin{cfa}
    4700 #include <fstream>
    4701 #include <coroutine>
    4702 
    4703 coroutine Fibonacci {
     5067#include <fstream.hfa>
     5068#include ®<coroutine.hfa>®
     5069
     5070®coroutine® Fibonacci {
    47045071        int fn; $\C{// used for communication}$
    47055072};
    4706 void ?{}( Fibonacci * this ) {
    4707         this->fn = 0;
    4708 }
    4709 void main( Fibonacci * this ) {
     5073
     5074void main( Fibonacci & fib ) with( fib ) { $\C{// called on first resume}$
    47105075        int fn1, fn2; $\C{// retained between resumes}$
    4711         this->fn = 0; $\C{// case 0}$
    4712         fn1 = this->fn;
    4713         suspend(); $\C{// return to last resume}$
    4714 
    4715         this->fn = 1; $\C{// case 1}$
    4716         fn2 = fn1;
    4717         fn1 = this->fn;
    4718         suspend(); $\C{// return to last resume}$
    4719 
    4720         for ( ;; ) { $\C{// general case}$
    4721                 this->fn = fn1 + fn2;
    4722                 fn2 = fn1;
    4723                 fn1 = this->fn;
    4724                 suspend(); $\C{// return to last resume}$
    4725         } // for
    4726 }
    4727 int next( Fibonacci * this ) {
    4728         resume( this ); $\C{// transfer to last suspend}$
    4729         return this->fn;
     5076        fn = 0;  fn1 = fn; $\C{// 1st case}$
     5077        ®suspend;® $\C{// restart last resume}$
     5078        fn = 1;  fn2 = fn1;  fn1 = fn; $\C{// 2nd case}$
     5079        ®suspend;® $\C{// restart last resume}$
     5080        for () {
     5081                fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn; $\C{// general case}$
     5082                ®suspend;® $\C{// restart last resume}$
     5083        }
     5084}
     5085int next( Fibonacci & fib ) with( fib ) {
     5086        ®resume( fib );® $\C{// restart last suspend}$
     5087        return fn;
    47305088}
    47315089int main() {
    47325090        Fibonacci f1, f2;
    4733         for ( int i = 1; i <= 10; i += 1 ) {
    4734                 sout | next( &f1 ) | ' ' | next( &f2 );
    4735         } // for
    4736 }
    4737 \end{cfa}
     5091        for ( 10 ) { $\C{// print N Fibonacci values}$
     5092                sout | next( f1 ) | next( f2 );
     5093        }
     5094}
     5095\end{cfa}
     5096\vspace*{-5pt}
    47385097\caption{Fibonacci Coroutine}
    47395098\label{f:FibonacciCoroutine}
     
    47615120\begin{figure}
    47625121\begin{cfa}
    4763 #include <fstream>
    4764 #include <kernel>
    4765 #include <monitor>
    4766 #include <thread>
    4767 
    4768 monitor global_t {
    4769         int value;
    4770 };
    4771 
    4772 void ?{}(global_t * this) {
    4773         this->value = 0;
    4774 }
    4775 
    4776 static global_t global;
    4777 
    4778 void increment3( global_t * mutex this ) {
    4779         this->value += 1;
    4780 }
    4781 void increment2( global_t * mutex this ) {
    4782         increment3( this );
    4783 }
    4784 void increment( global_t * mutex this ) {
    4785         increment2( this );
    4786 }
     5122#include <fstream.hfa>
     5123#include ®<thread.hfa>®
     5124
     5125®monitor® AtomicCnt { int counter; };
     5126void ?{}( AtomicCnt & c, int init = 0 ) with(c) { counter = init; }
     5127int inc( AtomicCnt & ®mutex® c, int inc = 1 ) with(c) { return counter += inc; }
     5128int dec( AtomicCnt & ®mutex® c, int dec = 1 ) with(c) { return counter -= dec; }
     5129forall( ostype & | ostream( ostype ) ) { $\C{// print any stream}$
     5130        ostype & ?|?( ostype & os, AtomicCnt c ) { return os | c.counter; }
     5131        void ?|?( ostype & os, AtomicCnt c ) { (ostype &)(os | c.counter); ends( os ); }
     5132}
     5133
     5134AtomicCnt global; $\C{// shared}$
    47875135
    47885136thread MyThread {};
    4789 
    4790 void main( MyThread* this ) {
    4791         for(int i = 0; i < 1_000_000; i++) {
    4792                 increment( &global );
     5137void main( MyThread & ) {
     5138        for ( i; 100_000 ) {
     5139                inc( global );
     5140                dec( global );
    47935141        }
    47945142}
    4795 int main(int argc, char* argv[]) {
    4796         processor p;
     5143int main() {
     5144        enum { Threads = 4 };
     5145        processor p[Threads - 1]; $\C{// + starting processor}$
    47975146        {
    4798                 MyThread f[4];
     5147                MyThread t[Threads];
    47995148        }
    4800         sout | global.value;
     5149        sout | global; $\C{// print 0}$
    48015150}
    48025151\end{cfa}
    48035152\caption{Atomic-Counter Monitor}
    4804 \caption{f:AtomicCounterMonitor}
     5153\label{f:AtomicCounterMonitor}
    48055154\end{figure}
    48065155
     
    62656614
    62666615C has a number of syntax ambiguities, which are resolved by taking the longest sequence of overlapping characters that constitute a token.
    6267 For example, the program fragment ©x+++++y© is parsed as \lstinline[showspaces=true]@x ++ ++ + y@ because operator tokens ©++© and ©+© overlap.
    6268 Unfortunately, the longest sequence violates a constraint on increment operators, even though the parse \lstinline[showspaces=true]@x ++ + ++ y@ might yield a correct expression.
     6616For example, the program fragment ©x+++++y© is parsed as \lstinline[showspaces=true]{x ++ ++ + y} because operator tokens ©++© and ©+© overlap.
     6617Unfortunately, the longest sequence violates a constraint on increment operators, even though the parse \lstinline[showspaces=true]{x ++ + ++ y} might yield a correct expression.
    62696618Hence, C programmers are aware that spaces have to added to disambiguate certain syntactic cases.
    62706619
     
    62866635requiring arbitrary whitespace look-ahead for the routine-call parameter-list to disambiguate.
    62876636However, the dereference operator \emph{must} have a parameter/argument to dereference ©*?(...)©.
    6288 Hence, always interpreting the string ©*?()© as \lstinline[showspaces=true]@* ?()@ does not preclude any meaningful program.
     6637Hence, always interpreting the string ©*?()© as \lstinline[showspaces=true]{* ?()} does not preclude any meaningful program.
    62896638
    62906639The remaining cases are with the increment/decrement operators and conditional expression, \eg:
     
    63946743\begin{cfa}
    63956744int i; $\C{// forward definition}$
    6396 int *j = @&i@; $\C{// forward reference, valid in C, invalid in \CFA}$
     6745int *j = ®&i®; $\C{// forward reference, valid in C, invalid in \CFA}$
    63976746int i = 0; $\C{// definition}$
    63986747\end{cfa}
     
    64026751struct X { int i; struct X *next; };
    64036752static struct X a; $\C{// forward definition}$
    6404 static struct X b = { 0, @&a@ };$\C{// forward reference, valid in C, invalid in \CFA}$
     6753static struct X b = { 0, ®&a® };$\C{// forward reference, valid in C, invalid in \CFA}$
    64056754static struct X a = { 1, &b }; $\C{// definition}$
    64066755\end{cfa}
     
    64156764\item[Change:] have ©struct© introduce a scope for nested types:
    64166765\begin{cfa}
    6417 enum @Colour@ { R, G, B, Y, C, M };
     6766enum ®Colour® { R, G, B, Y, C, M };
    64186767struct Person {
    6419         enum @Colour@ { R, G, B };      $\C[7cm]{// nested type}$
     6768        enum ®Colour® { R, G, B };      $\C[7cm]{// nested type}$
    64206769        struct Face { $\C{// nested type}$
    6421                 @Colour@ Eyes, Hair; $\C{// type defined outside (1 level)}$
     6770                ®Colour® Eyes, Hair; $\C{// type defined outside (1 level)}$
    64226771        };
    6423         @.Colour@ shirt; $\C{// type defined outside (top level)}$
    6424         @Colour@ pants; $\C{// type defined same level}$
     6772        ®.Colour® shirt; $\C{// type defined outside (top level)}$
     6773        ®Colour® pants; $\C{// type defined same level}$
    64256774        Face looks[10]; $\C{// type defined same level}$
    64266775};
    6427 @Colour@ c = R; $\C{// type/enum defined same level}$
    6428 Person@.Colour@ pc = Person@.@R;$\C{// type/enum defined inside}$
    6429 Person@.@Face pretty; $\C{// type defined inside}\CRT$
     6776®Colour® c = R; $\C{// type/enum defined same level}$
     6777Person®.Colour® pc = Person®.®R;$\C{// type/enum defined inside}$
     6778Person®.®Face pretty; $\C{// type defined inside}\CRT$
    64306779\end{cfa}
    64316780In C, the name of the nested types belongs to the same scope as the name of the outermost enclosing structure, \ie the nested types are hoisted to the scope of the outer-most type, which is not useful and confusing.
     
    65026851\label{s:CFAKeywords}
    65036852
    6504 \CFA introduces the following new keywords.
     6853\CFA introduces the following new \Index{keyword}s, which cannot be used as identifiers.
    65056854
    65066855\begin{cquote}
    6507 \input{../refrat/keywords}
     6856\begin{tabular}{@{}lllllll@{}}
     6857\begin{tabular}{@{}l@{}}
     6858\Indexc{basetypeof}             \\
     6859\Indexc{choose}                 \\
     6860\Indexc{coroutine}              \\
     6861\Indexc{disable}                \\
     6862\end{tabular}
     6863&
     6864\begin{tabular}{@{}l@{}}
     6865\Indexc{enable}                 \\
     6866\Indexc{exception}              \\
     6867\Indexc{fallthrough}    \\
     6868\Indexc{fallthru}               \\
     6869\end{tabular}
     6870&
     6871\begin{tabular}{@{}l@{}}
     6872\Indexc{finally}                \\
     6873\Indexc{fixup}                  \\
     6874\Indexc{forall}                 \\
     6875\Indexc{generator}              \\
     6876\end{tabular}
     6877&
     6878\begin{tabular}{@{}l@{}}
     6879\Indexc{int128}                 \\
     6880\Indexc{monitor}                \\
     6881\Indexc{mutex}                  \\
     6882\Indexc{one_t}                  \\
     6883\end{tabular}
     6884&
     6885\begin{tabular}{@{}l@{}}
     6886\Indexc{report}                 \\
     6887\Indexc{suspend}                \\
     6888\Indexc{throw}                  \\
     6889\Indexc{throwResume}    \\
     6890\end{tabular}
     6891&
     6892\begin{tabular}{@{}l@{}}
     6893\Indexc{trait}                  \\
     6894\Indexc{try}                    \\
     6895\Indexc{virtual}                \\
     6896\Indexc{waitfor}                \\
     6897\end{tabular}
     6898&
     6899\begin{tabular}{@{}l@{}}
     6900\Indexc{when}                   \\
     6901\Indexc{with}                   \\
     6902\Indexc{zero_t}                 \\
     6903                                                \\
     6904\end{tabular}
     6905\end{tabular}
    65086906\end{cquote}
    6509 
     6907\CFA introduces the following new \Index{quasi-keyword}s, which can be used as identifiers.
     6908\begin{cquote}
     6909\begin{tabular}{@{}ll@{}}
     6910\begin{tabular}{@{}l@{}}
     6911\Indexc{catch}                  \\
     6912\Indexc{catchResume}    \\
     6913\Indexc{finally}                \\
     6914\end{tabular}
     6915&
     6916\begin{tabular}{@{}l@{}}
     6917\Indexc{fixup}                  \\
     6918\Indexc{or}                             \\
     6919\Indexc{timeout}                \\
     6920\end{tabular}
     6921\end{tabular}
     6922\end{cquote}
    65106923
    65116924\section{Standard Headers}
     
    66667079// assume ?|? operator for printing an S
    66677080
    6668 S & sp = *@new@( 3 );                                                   $\C{// call constructor after allocation}$
     7081S & sp = *®new®( 3 );                                                   $\C{// call constructor after allocation}$
    66697082sout | sp.i;
    6670 @delete@( &sp );
    6671 
    6672 S * spa = @anew@( 10, 5 );                                              $\C{// allocate array and initialize each array element}$
     7083®delete®( &sp );
     7084
     7085S * spa = ®anew®( 10, 5 );                                              $\C{// allocate array and initialize each array element}$
    66737086for ( i; 10 ) sout | spa[i] | nonl;
    66747087sout | nl;
    6675 @adelete@( 10, spa );
     7088®adelete®( 10, spa );
    66767089\end{cfa}
    66777090Allocation routines ©new©/©anew© allocate a variable/array and initialize storage using the allocated type's constructor.
     
    69097322[ int, long double ] remquo( long double, long double );
    69107323
    6911 float div( float, float, int * );$\indexc{div}$ $\C{// alternative name for remquo}$
    6912 double div( double, double, int * );
    6913 long double div( long double, long double, int * );
    69147324[ int, float ] div( float, float );
    69157325[ int, double ] div( double, double );
     
    69727382long double _Complex log( long double _Complex );
    69737383
    6974 float log2( float );$\indexc{log2}$
     7384int log2( unsigned int );$\indexc{log2}$
     7385long int log2( unsigned long int );
     7386long long int log2( unsigned long long int )
     7387float log2( float );
    69757388double log2( double );
    69767389long double log2( long double );
     
    71547567\leavevmode
    71557568\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     7569// n / align * align
     7570signed char floor( signed char n, signed char align );
     7571unsigned char floor( unsigned char n, unsigned char align );
     7572short int floor( short int n, short int align );
     7573unsigned short int floor( unsigned short int n, unsigned short int align );
     7574int floor( int n, int align );
     7575unsigned int floor( unsigned int n, unsigned int align );
     7576long int floor( long int n, long int align );
     7577unsigned long int floor( unsigned long int n, unsigned long int align );
     7578long long int floor( long long int n, long long int align );
     7579unsigned long long int floor( unsigned long long int n, unsigned long long int align );
     7580
     7581// (n + (align - 1)) / align
     7582signed char ceiling_div( signed char n, char align );
     7583unsigned char ceiling_div( unsigned char n, unsigned char align );
     7584short int ceiling_div( short int n, short int align );
     7585unsigned short int ceiling_div( unsigned short int n, unsigned short int align );
     7586int ceiling_div( int n, int align );
     7587unsigned int ceiling_div( unsigned int n, unsigned int align );
     7588long int ceiling_div( long int n, long int align );
     7589unsigned long int ceiling_div( unsigned long int n, unsigned long int align );
     7590long long int ceiling_div( long long int n, long long int align );
     7591unsigned long long int ceiling_div( unsigned long long int n, unsigned long long int align );
     7592
     7593// floor( n + (n % align != 0 ? align - 1 : 0), align )
     7594signed char ceiling( signed char n, signed char align );
     7595unsigned char ceiling( unsigned char n, unsigned char align );
     7596short int ceiling( short int n, short int align );
     7597unsigned short int ceiling( unsigned short int n, unsigned short int align );
     7598int ceiling( int n, int align );
     7599unsigned int ceiling( unsigned int n, unsigned int align );
     7600long int ceiling( long int n, long int align );
     7601unsigned long int ceiling( unsigned long int n, unsigned long int align );
     7602long long int ceiling( long long int n, long long int align );
     7603unsigned long long int ceiling( unsigned long long int n, unsigned long long int align );
     7604
    71567605float floor( float );$\indexc{floor}$
    71577606double floor( double );
     
    72497698
    72507699
    7251 %\subsection{\texorpdfstring{\protect\lstinline@Duration@}{Duration}}
     7700%\subsection{\texorpdfstring{\protect\lstinline{Duration}}{Duration}}
    72527701\subsection{\texorpdfstring{\LstBasicStyle{Duration}}{Duration}}
    72537702\label{s:Duration}
     
    72567705\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    72577706struct Duration {
    7258         int64_t tv; $\C{// nanoseconds}$
     7707        int64_t tn; $\C{// nanoseconds}$
    72597708};
    72607709
    72617710void ?{}( Duration & dur );
    72627711void ?{}( Duration & dur, zero_t );
     7712void ?{}( Duration & dur, timeval t )
     7713void ?{}( Duration & dur, timespec t )
    72637714
    72647715Duration ?=?( Duration & dur, zero_t );
     7716Duration ?=?( Duration & dur, timeval t )
     7717Duration ?=?( Duration & dur, timespec t )
    72657718
    72667719Duration +?( Duration rhs );
     
    72847737Duration ?%=?( Duration & lhs, Duration rhs );
    72857738
    7286 _Bool ?==?( Duration lhs, Duration rhs );
    7287 _Bool ?!=?( Duration lhs, Duration rhs );
    7288 _Bool ?<? ( Duration lhs, Duration rhs );
    7289 _Bool ?<=?( Duration lhs, Duration rhs );
    7290 _Bool ?>? ( Duration lhs, Duration rhs );
    7291 _Bool ?>=?( Duration lhs, Duration rhs );
    7292 
    7293 _Bool ?==?( Duration lhs, zero_t );
    7294 _Bool ?!=?( Duration lhs, zero_t );
    7295 _Bool ?<? ( Duration lhs, zero_t );
    7296 _Bool ?<=?( Duration lhs, zero_t );
    7297 _Bool ?>? ( Duration lhs, zero_t );
    7298 _Bool ?>=?( Duration lhs, zero_t );
     7739bool ?==?( Duration lhs, zero_t );
     7740bool ?!=?( Duration lhs, zero_t );
     7741bool ?<? ( Duration lhs, zero_t );
     7742bool ?<=?( Duration lhs, zero_t );
     7743bool ?>? ( Duration lhs, zero_t );
     7744bool ?>=?( Duration lhs, zero_t );
     7745
     7746bool ?==?( Duration lhs, Duration rhs );
     7747bool ?!=?( Duration lhs, Duration rhs );
     7748bool ?<? ( Duration lhs, Duration rhs );
     7749bool ?<=?( Duration lhs, Duration rhs );
     7750bool ?>? ( Duration lhs, Duration rhs );
     7751bool ?>=?( Duration lhs, Duration rhs );
    72997752
    73007753Duration abs( Duration rhs );
     
    73237776int64_t ?`w( Duration dur );
    73247777
     7778double ?`dns( Duration dur );
     7779double ?`dus( Duration dur );
     7780double ?`dms( Duration dur );
     7781double ?`ds( Duration dur );
     7782double ?`dm( Duration dur );
     7783double ?`dh( Duration dur );
     7784double ?`dd( Duration dur );
     7785double ?`dw( Duration dur );
     7786
    73257787Duration max( Duration lhs, Duration rhs );
    73267788Duration min( Duration lhs, Duration rhs );
    7327 \end{cfa}
    7328 
    7329 
    7330 %\subsection{\texorpdfstring{\protect\lstinline@\timeval@}{timeval}}
     7789
     7790forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype & os, Duration dur );
     7791\end{cfa}
     7792
     7793
     7794%\subsection{\texorpdfstring{\protect\lstinline{timeval}}{timeval}}
    73317795\subsection{\texorpdfstring{\LstBasicStyle{timeval}}{timeval}}
    73327796\label{s:timeval}
     
    73357799\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    73367800void ?{}( timeval & t );
     7801void ?{}( timeval & t, zero_t );
    73377802void ?{}( timeval & t, time_t sec, suseconds_t usec );
    73387803void ?{}( timeval & t, time_t sec );
    7339 void ?{}( timeval & t, zero_t );
    73407804void ?{}( timeval & t, Time time );
    73417805
     
    73437807timeval ?+?( timeval & lhs, timeval rhs );
    73447808timeval ?-?( timeval & lhs, timeval rhs );
    7345 _Bool ?==?( timeval lhs, timeval rhs );
    7346 _Bool ?!=?( timeval lhs, timeval rhs );
    7347 \end{cfa}
    7348 
    7349 
    7350 %\subsection{\texorpdfstring{\protect\lstinline@timespec@}{timespec}}
     7809bool ?==?( timeval lhs, timeval rhs );
     7810bool ?!=?( timeval lhs, timeval rhs );
     7811\end{cfa}
     7812
     7813
     7814%\subsection{\texorpdfstring{\protect\lstinline{timespec}}{timespec}}
    73517815\subsection{\texorpdfstring{\LstBasicStyle{timespec}}{timespec}}
    73527816\label{s:timespec}
     
    73557819\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    73567820void ?{}( timespec & t );
     7821void ?{}( timespec & t, zero_t );
    73577822void ?{}( timespec & t, time_t sec, __syscall_slong_t nsec );
    73587823void ?{}( timespec & t, time_t sec );
    7359 void ?{}( timespec & t, zero_t );
    73607824void ?{}( timespec & t, Time time );
    73617825
     
    73637827timespec ?+?( timespec & lhs, timespec rhs );
    73647828timespec ?-?( timespec & lhs, timespec rhs );
    7365 _Bool ?==?( timespec lhs, timespec rhs );
    7366 _Bool ?!=?( timespec lhs, timespec rhs );
    7367 \end{cfa}
    7368 
    7369 
    7370 %\subsection{\texorpdfstring{\protect\lstinline@itimerval@}{itimerval}}
     7829bool ?==?( timespec lhs, timespec rhs );
     7830bool ?!=?( timespec lhs, timespec rhs );
     7831\end{cfa}
     7832
     7833
     7834%\subsection{\texorpdfstring{\protect\lstinline{itimerval}}{itimerval}}
    73717835\subsection{\texorpdfstring{\LstBasicStyle{itimerval}}{itimerval}}
    73727836\label{s:itimerval}
     
    73797843
    73807844
    7381 %\subsection{\texorpdfstring{\protect\lstinline@Time@}{Time}}
     7845%\subsection{\texorpdfstring{\protect\lstinline{Time}}{Time}}
    73827846\subsection{\texorpdfstring{\LstBasicStyle{Time}}{Time}}
    73837847\label{s:Time}
     
    73867850\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    73877851struct Time {
    7388         uint64_t tv; $\C{// nanoseconds since UNIX epoch}$
     7852        uint64_t tn; $\C{// nanoseconds since UNIX epoch}$
    73897853};
    73907854
    73917855void ?{}( Time & time );
    73927856void ?{}( Time & time, zero_t );
     7857void ?{}( Time & time, timeval t );
     7858void ?{}( Time & time, timespec t );
    73937859
    73947860Time ?=?( Time & time, zero_t );
    7395 
    7396 void ?{}( Time & time, timeval t );
    73977861Time ?=?( Time & time, timeval t );
    7398 
    7399 void ?{}( Time & time, timespec t );
    74007862Time ?=?( Time & time, timespec t );
    74017863
     
    74077869Time ?-?( Time lhs, Duration rhs );
    74087870Time ?-=?( Time & lhs, Duration rhs );
    7409 _Bool ?==?( Time lhs, Time rhs );
    7410 _Bool ?!=?( Time lhs, Time rhs );
    7411 _Bool ?<?( Time lhs, Time rhs );
    7412 _Bool ?<=?( Time lhs, Time rhs );
    7413 _Bool ?>?( Time lhs, Time rhs );
    7414 _Bool ?>=?( Time lhs, Time rhs );
     7871bool ?==?( Time lhs, Time rhs );
     7872bool ?!=?( Time lhs, Time rhs );
     7873bool ?<?( Time lhs, Time rhs );
     7874bool ?<=?( Time lhs, Time rhs );
     7875bool ?>?( Time lhs, Time rhs );
     7876bool ?>=?( Time lhs, Time rhs );
     7877
     7878int64_t ?`ns( Time t );
    74157879
    74167880char * yy_mm_dd( Time time, char * buf );
    7417 char * ?`ymd( Time time, char * buf ) { // short form
    7418         return yy_mm_dd( time, buf );
    7419 } // ymd
     7881char * ?`ymd( Time time, char * buf ); // short form
    74207882
    74217883char * mm_dd_yy( Time time, char * buf );
    7422 char * ?`mdy( Time time, char * buf ) { // short form
    7423         return mm_dd_yy( time, buf );
    7424 } // mdy
     7884char * ?`mdy( Time time, char * buf ); // short form
    74257885
    74267886char * dd_mm_yy( Time time, char * buf );
    7427 char * ?`dmy( Time time, char * buf ) { // short form
    7428         return dd_mm_yy( time, buf );;
    7429 } // dmy
     7887char * ?`dmy( Time time, char * buf ); // short form
    74307888
    74317889size_t strftime( char * buf, size_t size, const char * fmt, Time time );
    7432 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype & os, Time time );
     7890
     7891forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype & os, Time time );
    74337892\end{cfa}
    74347893
     
    74507909
    74517910
    7452 %\subsection{\texorpdfstring{\protect\lstinline@Clock@}{Clock}}
     7911%\subsection{\texorpdfstring{\protect\lstinline{Clock}}{Clock}}
    74537912\subsection{\texorpdfstring{\LstBasicStyle{Clock}}{Clock}}
    74547913\label{s:Clock}
     
    74567915\leavevmode
    74577916\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    7458 struct Clock {
    7459         Duration offset; $\C{// for virtual clock: contains offset from real-time}$
    7460         int clocktype; $\C{// implementation only -1 (virtual), CLOCK\_REALTIME}$
     7917struct Clock { $\C{// virtual clock}$
     7918        Duration offset; $\C{// offset from computer real-time}$
    74617919};
    74627920
    7463 void resetClock( Clock & clk );
    7464 void resetClock( Clock & clk, Duration adj );
    7465 void ?{}( Clock & clk );
    7466 void ?{}( Clock & clk, Duration adj );
    7467 
    7468 Duration getResNsec(); $\C{// with nanoseconds}$
    7469 Duration getRes(); $\C{// without nanoseconds}$
    7470 
    7471 Time getTimeNsec(); $\C{// with nanoseconds}$
    7472 Time getTime(); $\C{// without nanoseconds}$
    7473 Time getTime( Clock & clk );
    7474 Time ?()( Clock & clk );
    7475 timeval getTime( Clock & clk );
    7476 tm getTime( Clock & clk );
     7921void ?{}( Clock & clk ); $\C{// create no offset}$
     7922void ?{}( Clock & clk, Duration adj ); $\C{// create with offset}$
     7923void reset( Clock & clk, Duration adj ); $\C{// change offset}$
     7924
     7925Duration resolutionHi(); $\C{// clock resolution in nanoseconds (fine)}$
     7926Duration resolution(); $\C{// clock resolution without nanoseconds (coarse)}$
     7927
     7928Time timeHiRes(); $\C{// real time with nanoseconds}$
     7929Time time(); $\C{// real time without nanoseconds}$
     7930Time time( Clock & clk ); $\C{// real time for given clock}$
     7931Time ?()( Clock & clk ); $\C{//\ \ \ \ alternative syntax}$
     7932timeval time( Clock & clk ); $\C{// convert to C time format}$
     7933tm time( Clock & clk );
     7934Duration processor(); $\C{// non-monotonic duration of kernel thread}$
     7935Duration program(); $\C{// non-monotonic duration of program CPU}$
     7936Duration boot(); $\C{// monotonic duration since computer boot}$
    74777937\end{cfa}
    74787938
     
    76458105forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
    76468106\end{cfa}
    7647 
    7648 The following factorial programs contrast using GMP with the \CFA and C interfaces, where the output from these programs appears in \VRef[Figure]{f:MultiPrecisionFactorials}.
     8107\VRef[Figure]{f:MultiPrecisionFactorials} shows \CFA and C factorial programs using the GMP interfaces.
    76498108(Compile with flag \Indexc{-lgmp} to link with the GMP library.)
     8109
     8110\begin{figure}
    76508111\begin{cquote}
    76518112\begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}}
    7652 \multicolumn{1}{c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}}    & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}}      \\
     8113\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}@{}}   \\
    76538114\hline
    76548115\begin{cfa}
     
    76598120
    76608121        sout | 0 | fact;
    7661         for ( unsigned int i = 1; i <= 40; i += 1 ) {
     8122        for ( i; 40 ) {
    76628123                fact *= i;
    76638124                sout | i | fact;
     
    76698130#include <gmp.h>$\indexc{gmp.h}$
    76708131int main( void ) {
    7671         @gmp_printf@( "Factorial Numbers\n" );
    7672         @mpz_t@ fact;
    7673         @mpz_init_set_ui@( fact, 1 );
    7674         @gmp_printf@( "%d %Zd\n", 0, fact );
     8132        ®gmp_printf®( "Factorial Numbers\n" );
     8133        ®mpz_t® fact;
     8134        ®mpz_init_set_ui®( fact, 1 );
     8135        ®gmp_printf®( "%d %Zd\n", 0, fact );
    76758136        for ( unsigned int i = 1; i <= 40; i += 1 ) {
    7676                 @mpz_mul_ui@( fact, fact, i );
    7677                 @gmp_printf@( "%d %Zd\n", i, fact );
     8137                ®mpz_mul_ui®( fact, fact, i );
     8138                ®gmp_printf®( "%d %Zd\n", i, fact );
    76788139        }
    76798140}
     
    76818142\end{tabular}
    76828143\end{cquote}
    7683 
    7684 \begin{figure}
     8144\small
    76858145\begin{cfa}
    76868146Factorial Numbers
  • example/io/batch-readv.c

    rfeacef9 r5407cdc  
    6666}
    6767
    68 uint64_t getTimeNsec() {
     68uint64_t timeHiRes() {
    6969        timespec curr;
    7070        clock_gettime( CLOCK_REALTIME, &curr );
     
    163163
    164164        printf("Running for %f second, reading %d bytes in batches of %d\n", duration, buflen, batch);
    165         uint64_t start = getTimeNsec();
    166         uint64_t end   = getTimeNsec();
    167         uint64_t prev  = getTimeNsec();
     165        uint64_t start = timeHiRes();
     166        uint64_t end   = timeHiRes();
     167        uint64_t prev  = timeHiRes();
    168168        for(;;) {
    169169                submit_and_drain(&iov, batch);
    170                 end = getTimeNsec();
     170                end = timeHiRes();
    171171                uint64_t delta = end - start;
    172172                if( to_fseconds(end - prev) > 0.1 ) {
  • libcfa/configure.ac

    rfeacef9 r5407cdc  
    169169AH_TEMPLATE([CFA_HAVE_IOSQE_FIXED_FILE],[Defined if io_uring support is present when compiling libcfathread and supports the flag FIXED_FILE.])
    170170AH_TEMPLATE([CFA_HAVE_IOSQE_IO_DRAIN],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_DRAIN.])
    171 AH_TEMPLATE([CFA_HAVE_IOSQE_ASYNC],[Defined if io_uring support is present when compiling libcfathread and supports the flag ASYNC.])
    172171AH_TEMPLATE([CFA_HAVE_IOSQE_IO_LINK],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_LINK.])
    173172AH_TEMPLATE([CFA_HAVE_IOSQE_IO_HARDLINK],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_HARDLINK.])
     173AH_TEMPLATE([CFA_HAVE_IOSQE_ASYNC],[Defined if io_uring support is present when compiling libcfathread and supports the flag ASYNC.])
     174AH_TEMPLATE([CFA_HAVE_IOSQE_BUFFER_SELECT],[Defined if io_uring support is present when compiling libcfathread and supports the flag BUFFER_SELEC.])
    174175AH_TEMPLATE([CFA_HAVE_SPLICE_F_FD_IN_FIXED],[Defined if io_uring support is present when compiling libcfathread and supports the flag SPLICE_F_FD_IN_FIXED.])
    175176AH_TEMPLATE([CFA_HAVE_IORING_SETUP_ATTACH_WQ],[Defined if io_uring support is present when compiling libcfathread and supports the flag IORING_SETUP_ATTACH_WQ.])
     
    182183
    183184define(ioring_ops, [IORING_OP_NOP,IORING_OP_READV,IORING_OP_WRITEV,IORING_OP_FSYNC,IORING_OP_READ_FIXED,IORING_OP_WRITE_FIXED,IORING_OP_POLL_ADD,IORING_OP_POLL_REMOVE,IORING_OP_SYNC_FILE_RANGE,IORING_OP_SENDMSG,IORING_OP_RECVMSG,IORING_OP_TIMEOUT,IORING_OP_TIMEOUT_REMOVE,IORING_OP_ACCEPT,IORING_OP_ASYNC_CANCEL,IORING_OP_LINK_TIMEOUT,IORING_OP_CONNECT,IORING_OP_FALLOCATE,IORING_OP_OPENAT,IORING_OP_CLOSE,IORING_OP_FILES_UPDATE,IORING_OP_STATX,IORING_OP_READ,IORING_OP_WRITE,IORING_OP_FADVISE,IORING_OP_MADVISE,IORING_OP_SEND,IORING_OP_RECV,IORING_OP_OPENAT2,IORING_OP_EPOLL_CTL,IORING_OP_SPLICE,IORING_OP_PROVIDE_BUFFERS,IORING_OP_REMOVE_BUFFER,IORING_OP_TEE])
    184 define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_ASYNC,IOSQE_IO_LINK,IOSQE_IO_HARDLINK,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ])
     185define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_IO_LINK,IOSQE_IO_HARDLINK,IOSQE_ASYNC,IOSQE_BUFFER_SELECT,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ])
    185186
    186187define(ioring_from_decls, [
  • libcfa/prelude/builtins.c

    rfeacef9 r5407cdc  
    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/prelude/defines.hfa.in

    rfeacef9 r5407cdc  
    149149
    150150/* Defined if io_uring support is present when compiling libcfathread and
     151   supports the flag BUFFER_SELEC. */
     152#undef CFA_HAVE_IOSQE_BUFFER_SELECT
     153
     154/* Defined if io_uring support is present when compiling libcfathread and
    151155   supports the flag FIXED_FILE. */
    152156#undef CFA_HAVE_IOSQE_FIXED_FILE
  • libcfa/src/Makefile.am

    rfeacef9 r5407cdc  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Wed Dec  9 22:46:14 2020
    14 ## Update Count     : 250
     13## Last Modified On : Sat Apr 24 09:09:56 2021
     14## Update Count     : 254
    1515###############################################################################
    1616
     
    5656        bits/queue.hfa \
    5757        bits/sequence.hfa \
     58        containers/array.hfa \
    5859        concurrency/iofwd.hfa \
    5960        containers/list.hfa \
     61        containers/queueLockFree.hfa \
    6062        containers/stackLockFree.hfa \
    6163        vec/vec.hfa \
     
    6769        common.hfa \
    6870        fstream.hfa \
     71        strstream.hfa \
    6972        heap.hfa \
    7073        iostream.hfa \
  • libcfa/src/bits/debug.hfa

    rfeacef9 r5407cdc  
    101101        __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_print_buffer(STDERR_FILENO, __VA_ARGS__))
    102102#define __cfadbg_print_buffer_decl(group, ...) \
    103         __CFADBG_PRINT_GROUP_##group(char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( __dbg_text, __dbg_len ))
     103        __CFADBG_PRINT_GROUP_##group(char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( STDERR_FILENO, __dbg_text, __dbg_len ))
    104104#define __cfadbg_print_buffer_local(group, ...) \
    105105        __CFADBG_PRINT_GROUP_##group(__dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write(STDERR_FILENO, __dbg_text, __dbg_len))
  • libcfa/src/bits/defs.hfa

    rfeacef9 r5407cdc  
    7474        #error unsupported architecture
    7575#endif
     76
     77#define CFA_IO_LAZY (1_l64u << 32_l64u)
  • libcfa/src/bits/locks.hfa

    rfeacef9 r5407cdc  
    3737        extern "C" {
    3838                extern void disable_interrupts() OPTIONAL_THREAD;
    39                 extern void enable_interrupts_noPoll() OPTIONAL_THREAD;
     39                extern void enable_interrupts( bool poll = true ) OPTIONAL_THREAD;
    4040
    4141                #ifdef __CFA_DEBUG__
     
    5757                        __cfaabi_dbg_record_lock( this, caller );
    5858                } else {
    59                         enable_interrupts_noPoll();
     59                        enable_interrupts( false );
    6060                }
    6161                return result;
     
    9090        static inline void unlock( __spinlock_t & this ) {
    9191                __atomic_clear( &this.lock, __ATOMIC_RELEASE );
    92                 enable_interrupts_noPoll();
     92                enable_interrupts( false );
    9393        }
    9494#endif
  • libcfa/src/bits/queue.hfa

    rfeacef9 r5407cdc  
    1515        };
    1616
    17         inline {
     17        static inline {
    1818                // wrappers to make Collection have T
    1919                T & head( Queue(T) & q ) with( q ) {
     
    154154        struct QueueIter {
    155155                inline ColIter;                                                                 // Plan 9 inheritance
    156         };     
     156        };
    157157
    158         inline {
     158        static inline {
    159159                void ?{}( QueueIter(T) & qi ) with( qi ) {
    160160                        ((ColIter &)qi){};
  • libcfa/src/bits/weakso_locks.cfa

    rfeacef9 r5407cdc  
    1818#include "bits/weakso_locks.hfa"
    1919
    20 void  ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) {}
    21 void ^?{}( blocking_lock & this ) {}
     20void  ?{}( blocking_lock &, bool, bool ) {}
     21void ^?{}( blocking_lock & ) {}
    2222
    23 void lock( blocking_lock & this ) {}
    24 bool try_lock( blocking_lock & this ) { return false; }
    25 void unlock( blocking_lock & this ) {}
    26 void on_notify( blocking_lock & this, struct $thread * t ) {}
    27 void on_wait( blocking_lock & this ) {}
    28 size_t wait_count( blocking_lock & this ) { return 0; }
    29 void set_recursion_count( blocking_lock & this, size_t recursion ) {}
    30 size_t get_recursion_count( blocking_lock & this ) { return 0; }
     23void lock( blocking_lock & ) {}
     24bool try_lock( blocking_lock & ) { return false; }
     25void unlock( blocking_lock & ) {}
     26void on_notify( blocking_lock &, struct $thread * ) {}
     27size_t on_wait( blocking_lock & ) { return 0; }
     28void on_wakeup( blocking_lock &, size_t ) {}
     29size_t wait_count( blocking_lock & ) { return 0; }
  • libcfa/src/bits/weakso_locks.hfa

    rfeacef9 r5407cdc  
    5656void unlock( blocking_lock & this ) OPTIONAL_THREAD;
    5757void on_notify( blocking_lock & this, struct $thread * t ) OPTIONAL_THREAD;
    58 void on_wait( blocking_lock & this ) OPTIONAL_THREAD;
     58size_t on_wait( blocking_lock & this ) OPTIONAL_THREAD;
     59void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD;
    5960size_t wait_count( blocking_lock & this ) OPTIONAL_THREAD;
    60 void set_recursion_count( blocking_lock & this, size_t recursion ) OPTIONAL_THREAD;
    61 size_t get_recursion_count( blocking_lock & this ) OPTIONAL_THREAD;
    6261
    6362//----------
     
    6968static inline void  ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };}
    7069static inline void ^?{}( multiple_acquisition_lock & this ) {}
    71 static inline void   lock     ( multiple_acquisition_lock & this ) { lock   ( (blocking_lock &)this ); }
    72 static inline void   unlock   ( multiple_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); }
    73 static inline void   on_wait  ( multiple_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); }
     70static inline void   lock     ( multiple_acquisition_lock & this ) { lock    ( (blocking_lock &)this ); }
     71static inline bool   try_lock ( multiple_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); }
     72static inline void   unlock   ( multiple_acquisition_lock & this ) { unlock  ( (blocking_lock &)this ); }
     73static inline size_t on_wait  ( multiple_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); }
     74static inline void   on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    7475static inline void   on_notify( multiple_acquisition_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); }
    75 static inline void   set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
    76 static inline size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
  • libcfa/src/clock.hfa

    rfeacef9 r5407cdc  
    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 : Sun Apr 18 08:12:16 2021
     13// Update Count     : 28
    1414//
    1515
     
    2727//######################### Clock #########################
    2828
    29 struct Clock {                                                                                  // private
    30         Duration offset;                                                                        // for virtual clock: contains offset from real-time
     29struct Clock {                                                                                  // virtual clock
     30        // private
     31        Duration offset;                                                                        // offset from computer real-time
    3132};
    3233
    3334static inline {
    34         void resetClock( Clock & clk, Duration adj ) with( clk ) {
     35        void reset( Clock & clk, Duration adj ) with( clk ) { // change offset
    3536                offset = adj + __timezone`s;                                    // timezone (global) is (UTC - local time) in seconds
    36         } // resetClock
     37        } // reset
    3738
    38         void ?{}( Clock & clk, Duration adj ) { resetClock( clk, adj ); }
     39        void ?{}( Clock & clk ) { reset( clk, (Duration){ 0 } ); } // create no offset
     40        void ?{}( Clock & clk, Duration adj ) { reset( clk, adj ); } // create with offset
    3941
    40         Duration getResNsec() {
     42        // System-wide clock that measures real, i.e., wall-clock) time. This clock is affected by discontinuous jumps in
     43        // the system time. For example, manual changes of the clock, and incremental adjustments performed by adjtime(3)
     44        // and NTP (daylight saving (Fall back).
     45        Duration resolutionHi() {                                                       // clock resolution in nanoseconds (fine)
    4146                struct timespec res;
    4247                clock_getres( CLOCK_REALTIME, &res );
    4348                return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns;
    44         } // getRes
     49        } // resolutionHi
    4550
    46         Duration getRes() {
     51        Duration resolution() {                                                         // clock resolution without nanoseconds (coarse)
    4752                struct timespec res;
    4853                clock_getres( CLOCK_REALTIME_COARSE, &res );
    4954                return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns;
    50         } // getRes
     55        } // resolution
    5156
    52         Time getTimeNsec() {                                                            // with nanoseconds
     57        Time timeHiRes() {                                                                      // real time with nanoseconds
    5358                timespec curr;
    5459                clock_gettime( CLOCK_REALTIME, &curr );
    5560                return (Time){ curr };
    56         } // getTimeNsec
     61        } // timeHiRes
    5762
    58         Time getTime() {                                                                        // without nanoseconds
     63        Time time() {                                                                           // real time without nanoseconds
    5964                timespec curr;
    6065                clock_gettime( CLOCK_REALTIME_COARSE, &curr );
    6166                curr.tv_nsec = 0;
    6267                return (Time){ curr };
    63         } // getTime
     68        } // time
    6469
    65         Time getTime( Clock & clk ) with( clk ) {
    66                 return getTime() + offset;
    67         } // getTime
     70        Time time( Clock & clk ) with( clk ) {                          // real time for given clock
     71                return time() + offset;
     72        } // time
    6873
    6974        Time ?()( Clock & clk ) with( clk ) {                           // alternative syntax
    70                 return getTime() + offset;
    71         } // getTime
     75                return time() + offset;
     76        } // ?()
    7277
    73         timeval getTime( Clock & clk ) {
     78        timeval time( Clock & clk ) {                                           // convert to C time format
    7479                return (timeval){ clk() };
    75         } // getTime
     80        } // time
    7681
    77         tm getTime( Clock & clk ) with( clk ) {
     82        tm time( Clock & clk ) with( clk ) {
    7883                tm ret;
    79                 localtime_r( getTime( clk ).tv_sec, &ret );
     84                localtime_r( time( clk ).tv_sec, &ret );
    8085                return ret;
    81         } // getTime
     86        } // time
    8287
    83         Time getCPUTime() {
     88        // CFA processor CPU-time watch that ticks when the processor (kernel thread) is running. This watch is affected by
     89        // discontinuous jumps when the OS is not running the kernal thread. A duration is returned because the value is
     90        // relative and cannot be converted to real-time (wall-clock) time.
     91        Duration processor() {                                                          // non-monotonic duration of kernel thread
    8492                timespec ts;
    8593                clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts );
    86                 return (Time){ ts };
    87     } // getCPUTime
     94                return (Duration){ ts };
     95        } // processor
     96
     97        // Program CPU-time watch measures CPU time consumed by all processors (kernel threads) in the UNIX process.  This
     98        // watch is affected by discontinuous jumps when the OS is not running the kernel threads. A duration is returned
     99        // because the value is relative and cannot be converted to real-time (wall-clock) time.
     100        Duration program() {                                                            // non-monotonic duration of program CPU
     101                timespec ts;
     102                clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &ts );
     103                return (Duration){ ts };
     104        } // program
     105
     106        // Monotonic duration from machine boot and including system suspension. This watch is unaffected by discontinuous
     107        // jumps resulting from manual changes of the clock, and incremental adjustments performed by adjtime(3) and NTP
     108        // (Fall back). A duration is returned because the value is relative and cannot be converted to real-time
     109        // (wall-clock) time.
     110        Duration boot() {                                                                       // monotonic duration since computer boot
     111                timespec ts;
     112                clock_gettime( CLOCK_BOOTTIME, &ts );
     113                return (Duration){ ts };
     114        } // boot
    88115} // distribution
    89116
  • libcfa/src/concurrency/alarm.cfa

    rfeacef9 r5407cdc  
    1515
    1616#define __cforall_thread__
     17// #define __CFA_DEBUG_PRINT_PREEMPTION__
    1718
    1819#include <errno.h>
     
    107108                bool first = ! & alarms`first;
    108109
     110                __cfadbg_print_safe( preemption, " KERNEL: alarm inserting %p (%lu).\n", this, this->alarm.tn );
    109111                insert( &alarms, this );
    110112                if( first ) {
     
    114116        unlock( event_kernel->lock );
    115117        this->set = true;
    116         enable_interrupts( __cfaabi_dbg_ctx );
     118        enable_interrupts();
    117119}
    118120
     
    125127        }
    126128        unlock( event_kernel->lock );
    127         enable_interrupts( __cfaabi_dbg_ctx );
     129        enable_interrupts();
    128130        this->set = false;
    129131}
  • libcfa/src/concurrency/clib/cfathread.cfa

    rfeacef9 r5407cdc  
    1414//
    1515
     16#include "fstream.hfa"
     17#include "locks.hfa"
    1618#include "kernel.hfa"
     19#include "stats.hfa"
    1720#include "thread.hfa"
    18 
    19 thread CRunner {
    20         void (*themain)( CRunner * );
     21#include "time.hfa"
     22
     23#include "cfathread.h"
     24
     25extern void ?{}(processor &, const char[], cluster &, $thread *);
     26extern "C" {
     27      extern void __cfactx_invoke_thread(void (*main)(void *), void * this);
     28}
     29
     30//================================================================================
     31// Thread run y the C Interface
     32
     33struct cfathread_object {
     34        $thread self;
     35        void * (*themain)( void * );
     36        void * arg;
     37        void * ret;
    2138};
    22 
    23 static void ?{}( CRunner & this, void (*themain)( CRunner * ) ) {
     39void main(cfathread_object & this);
     40void ^?{}(cfathread_object & mutex this);
     41
     42static inline $thread * get_thread( cfathread_object & this ) { return &this.self; }
     43
     44typedef ThreadCancelled(cfathread_object) cfathread_exception;
     45typedef ThreadCancelled_vtable(cfathread_object) cfathread_vtable;
     46
     47void defaultResumptionHandler(ThreadCancelled(cfathread_object) & except) {
     48        abort | "A thread was cancelled";
     49}
     50
     51cfathread_vtable _cfathread_vtable_instance;
     52
     53cfathread_vtable & const _default_vtable = _cfathread_vtable_instance;
     54
     55cfathread_vtable const & get_exception_vtable(cfathread_exception *) {
     56        return _cfathread_vtable_instance;
     57}
     58
     59static void ?{}( cfathread_object & this, cluster & cl, void *(*themain)( void * ), void * arg ) {
    2460        this.themain = themain;
    25 }
    26 
    27 void main( CRunner & this ) {
    28         this.themain( &this );
    29 }
    30 
    31 processor * procs = 0p;
    32 int proc_cnt = 1;
    33 
     61        this.arg = arg;
     62        (this.self){"C-thread", cl};
     63        __thrd_start(this, main);
     64}
     65
     66void ^?{}(cfathread_object & mutex this) {
     67        ^(this.self){};
     68}
     69
     70void main( cfathread_object & this ) {
     71        __attribute__((unused)) void * const thrd_obj = (void*)&this;
     72        __attribute__((unused)) void * const thrd_hdl = (void*)active_thread();
     73        /* paranoid */ verify( thrd_obj == thrd_hdl );
     74
     75        this.ret = this.themain( this.arg );
     76}
     77
     78//================================================================================
     79// Special Init Thread responsible for the initialization or processors
     80struct __cfainit {
     81        $thread self;
     82        void (*init)( void * );
     83        void * arg;
     84};
     85void main(__cfainit & this);
     86void ^?{}(__cfainit & mutex this);
     87
     88static inline $thread * get_thread( __cfainit & this ) { return &this.self; }
     89
     90typedef ThreadCancelled(__cfainit) __cfainit_exception;
     91typedef ThreadCancelled_vtable(__cfainit) __cfainit_vtable;
     92
     93void defaultResumptionHandler(ThreadCancelled(__cfainit) & except) {
     94        abort | "The init thread was cancelled";
     95}
     96
     97__cfainit_vtable ___cfainit_vtable_instance;
     98
     99__cfainit_vtable const & get_exception_vtable(__cfainit_exception *) {
     100        return ___cfainit_vtable_instance;
     101}
     102
     103static void ?{}( __cfainit & this, void (*init)( void * ), void * arg ) {
     104        this.init = init;
     105        this.arg = arg;
     106        (this.self){"Processir Init"};
     107
     108        // Don't use __thrd_start! just prep the context manually
     109        $thread * this_thrd = get_thread(this);
     110        void (*main_p)(__cfainit &) = main;
     111
     112        disable_interrupts();
     113        __cfactx_start(main_p, get_coroutine(this), this, __cfactx_invoke_thread);
     114
     115        this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP];
     116        /* paranoid */ verify( this_thrd->context.SP );
     117
     118        this_thrd->state = Ready;
     119        enable_interrupts();
     120}
     121
     122void ^?{}(__cfainit & mutex this) {
     123        ^(this.self){};
     124}
     125
     126void main( __cfainit & this ) {
     127        __attribute__((unused)) void * const thrd_obj = (void*)&this;
     128        __attribute__((unused)) void * const thrd_hdl = (void*)active_thread();
     129        /* paranoid */ verify( thrd_obj == thrd_hdl );
     130
     131        this.init( this.arg );
     132}
     133
     134//================================================================================
     135// Main Api
    34136extern "C" {
    35         //--------------------
    36         // Basic thread management
    37         CRunner * cfathread_create( void (*main)( CRunner * ) ) {
    38                 return new( main );
    39         }
    40 
    41         void cfathread_join( CRunner * thrd ) {
    42                 delete( thrd );
     137        int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) {
     138                *cl = new();
     139                return 0;
     140        }
     141
     142        cfathread_cluster_t cfathread_cluster_self(void) {
     143                return active_cluster();
     144        }
     145
     146        int cfathread_cluster_print_stats( cfathread_cluster_t cl ) {
     147                #if !defined(__CFA_NO_STATISTICS__)
     148                        print_stats_at_exit( *cl, CFA_STATS_READY_Q | CFA_STATS_IO );
     149                        print_stats_now( *cl, CFA_STATS_READY_Q | CFA_STATS_IO );
     150                #endif
     151                return 0;
     152        }
     153
     154        int cfathread_cluster_add_worker(cfathread_cluster_t cl, pthread_t* tid, void (*init_routine) (void *), void * arg) {
     155                __cfainit * it = 0p;
     156                if(init_routine) {
     157                        it = alloc();
     158                        (*it){init_routine, arg};
     159                }
     160                processor * proc = alloc();
     161                (*proc){ "C-processor", *cl, get_thread(*it) };
     162
     163                // Wait for the init thread to return before continuing
     164                if(it) {
     165                        ^(*it){};
     166                        free(it);
     167                }
     168
     169                if(tid) *tid = proc->kernel_thread;
     170                return 0;
     171        }
     172
     173        int cfathread_cluster_pause (cfathread_cluster_t) {
     174                abort | "Pausing clusters is not supported";
     175                exit(1);
     176        }
     177
     178        int cfathread_cluster_resume(cfathread_cluster_t) {
     179                abort | "Resuming clusters is not supported";
     180                exit(1);
     181        }
     182
     183        //--------------------
     184        // Thread attributes
     185        int cfathread_attr_init(cfathread_attr_t *attr) __attribute__((nonnull (1))) {
     186                attr->cl = active_cluster();
     187                return 0;
     188        }
     189
     190        //--------------------
     191        // Thread
     192        int cfathread_create( cfathread_t * handle, const cfathread_attr_t * attr, void *(*main)( void * ), void * arg ) __attribute__((nonnull (1))) {
     193                cluster * cl = attr ? attr->cl : active_cluster();
     194                cfathread_t thrd = alloc();
     195                (*thrd){ *cl, main, arg };
     196                *handle = thrd;
     197                return 0;
     198        }
     199
     200        int cfathread_join( cfathread_t thrd, void ** retval ) {
     201                void * ret = join( *thrd ).ret;
     202                ^( *thrd ){};
     203                free(thrd);
     204                if(retval) {
     205                        *retval = ret;
     206                }
     207                return 0;
     208        }
     209
     210        int cfathread_get_errno(void) {
     211                return errno;
     212        }
     213
     214        cfathread_t cfathread_self(void) {
     215                return (cfathread_t)active_thread();
     216        }
     217
     218        int cfathread_usleep(useconds_t usecs) {
     219                sleep(usecs`us);
     220                return 0;
     221        }
     222
     223        int cfathread_sleep(unsigned int secs) {
     224                sleep(secs`s);
     225                return 0;
    43226        }
    44227
     
    47230        }
    48231
    49         void cfathread_unpark( CRunner * thrd ) {
     232        void cfathread_unpark( cfathread_t thrd ) {
    50233                unpark( *thrd );
    51234        }
     
    55238        }
    56239
    57         //--------------------
    58         // Basic kernel features
    59         void cfathread_setproccnt( int ncnt ) {
    60                 assert( ncnt >= 1 );
    61                 adelete( procs );
    62 
    63                 proc_cnt = ncnt - 1;
    64                 procs = anew(proc_cnt);
    65         }
    66 }
     240        typedef struct cfathread_mutex * cfathread_mutex_t;
     241
     242        //--------------------
     243        // Mutex
     244        struct cfathread_mutex {
     245                fast_lock impl;
     246        };
     247        int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict) __attribute__((nonnull (1))) { *mut = new(); return 0; }
     248        int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1))) { delete( *mut ); return 0; }
     249        int cfathread_mutex_lock   (cfathread_mutex_t *mut) __attribute__((nonnull (1))) { lock( (*mut)->impl ); return 0; }
     250        int cfathread_mutex_unlock (cfathread_mutex_t *mut) __attribute__((nonnull (1))) { unlock( (*mut)->impl ); return 0; }
     251        int cfathread_mutex_trylock(cfathread_mutex_t *mut) __attribute__((nonnull (1))) {
     252                bool ret = try_lock( (*mut)->impl );
     253                if( ret ) return 0;
     254                else return EBUSY;
     255        }
     256
     257        //--------------------
     258        // Condition
     259        struct cfathread_condition {
     260                condition_variable(fast_lock) impl;
     261        };
     262        int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict) __attribute__((nonnull (1))) { *cond = new(); return 0; }
     263        int cfathread_cond_signal(cfathread_cond_t *cond) __attribute__((nonnull (1)))  { notify_one( (*cond)->impl ); return 0; }
     264        int cfathread_cond_wait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut) __attribute__((nonnull (1,2))) { wait( (*cond)->impl, (*mut)->impl ); return 0; }
     265        int cfathread_cond_timedwait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut, const struct timespec *restrict abstime) __attribute__((nonnull (1,2,3))) {
     266                Time t = { *abstime };
     267                if( wait( (*cond)->impl, (*mut)->impl, t ) ) {
     268                        return 0;
     269                }
     270                errno = ETIMEDOUT;
     271                return ETIMEDOUT;
     272        }
     273}
     274
     275#include <iofwd.hfa>
     276
     277extern "C" {
     278        #include <unistd.h>
     279        #include <sys/types.h>
     280        #include <sys/socket.h>
     281
     282        //--------------------
     283        // IO operations
     284        int cfathread_socket(int domain, int type, int protocol) {
     285                return socket(domain, type, protocol);
     286        }
     287        int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) {
     288                return bind(socket, address, address_len);
     289        }
     290
     291        int cfathread_listen(int socket, int backlog) {
     292                return listen(socket, backlog);
     293        }
     294
     295        int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) {
     296                return cfa_accept4(socket, address, address_len, 0, CFA_IO_LAZY);
     297        }
     298
     299        int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) {
     300                return cfa_connect(socket, address, address_len, CFA_IO_LAZY);
     301        }
     302
     303        int cfathread_dup(int fildes) {
     304                return dup(fildes);
     305        }
     306
     307        int cfathread_close(int fildes) {
     308                return cfa_close(fildes, CFA_IO_LAZY);
     309        }
     310
     311        ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags) {
     312                return cfa_sendmsg(socket, message, flags, CFA_IO_LAZY);
     313        }
     314
     315        ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte) {
     316                // Use send rather then write for socket since it's faster
     317                return cfa_send(fildes, buf, nbyte, 0, CFA_IO_LAZY);
     318        }
     319
     320        ssize_t cfathread_recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len)  {
     321                struct iovec iov;
     322                iov.iov_base = buffer;
     323                iov.iov_len = length;
     324
     325                struct msghdr msg;
     326                msg.msg_name = address;
     327                msg.msg_namelen = address_len ? (socklen_t)*address_len : (socklen_t)0;
     328                msg.msg_iov = &iov;
     329                msg.msg_iovlen = 1;
     330                msg.msg_control = 0p;
     331                msg.msg_controllen = 0;
     332
     333                ssize_t ret = cfa_recvmsg(socket, &msg, flags, CFA_IO_LAZY);
     334
     335                if(address_len) *address_len = msg.msg_namelen;
     336                return ret;
     337        }
     338
     339        ssize_t cfathread_read(int fildes, void *buf, size_t nbyte) {
     340                // Use recv rather then read for socket since it's faster
     341                return cfa_recv(fildes, buf, nbyte, 0, CFA_IO_LAZY);
     342        }
     343
     344}
  • libcfa/src/concurrency/clib/cfathread.h

    rfeacef9 r5407cdc  
    1414//
    1515
    16 #include "stddef.h"
    17 #include "invoke.h"
    18 
    1916#if defined(__cforall) || defined(__cplusplus)
    2017extern "C" {
    2118#endif
     19        #include <asm/types.h>
     20        #include <errno.h>
     21        #include <unistd.h>
     22
     23
    2224        //--------------------
    2325        // Basic types
    24         struct cfathread_CRunner_t;
    25         typedef struct cfathread_CRunner_t * cfathread_t;
     26
     27        typedef struct cluster * cfathread_cluster_t;
     28
     29        int cfathread_cluster_create(cfathread_cluster_t * cluster);
     30        cfathread_cluster_t cfathread_cluster_self(void);
     31        int cfathread_cluster_print_stats(cfathread_cluster_t cluster);
     32        int cfathread_cluster_add_worker(cfathread_cluster_t cluster, pthread_t* tid, void (*init_routine) (void *), void * arg);
     33        int cfathread_cluster_pause (cfathread_cluster_t cluster);
     34        int cfathread_cluster_resume(cfathread_cluster_t cluster);
    2635
    2736        //--------------------
    28         // Basic thread support
    29         cfathread_t cfathread_create( void (*main)( cfathread_t ) );
    30         void cfathread_join( cfathread_t );
     37        // thread attribute
     38        typedef struct cfathread_attr {
     39                cfathread_cluster_t cl;
     40        } cfathread_attr_t;
     41
     42        int cfathread_attr_init(cfathread_attr_t * attr) __attribute__((nonnull (1)));
     43        static inline int cfathread_attr_destroy(cfathread_attr_t * attr) __attribute__((nonnull (1)));
     44        static inline int cfathread_attr_destroy(cfathread_attr_t * attr) { return 0; }
     45        static inline int cfathread_attr_setbackground(cfathread_attr_t * attr, int background) __attribute__((nonnull (1)));
     46        static inline int cfathread_attr_setbackground(cfathread_attr_t * attr, int background) { return 0; }
     47        static inline int cfathread_attr_setcluster(cfathread_attr_t * attr, cfathread_cluster_t cl) __attribute__((nonnull (1)));
     48        static inline int cfathread_attr_setcluster(cfathread_attr_t * attr, cfathread_cluster_t cl) { attr->cl = cl; return 0; }
     49
     50        //--------------------
     51        // thread type
     52        struct cfathread_object;
     53        typedef struct cfathread_object * cfathread_t;
     54
     55        int cfathread_create( cfathread_t * h, const cfathread_attr_t * a, void *(*main)( void * ), void * arg ) __attribute__((nonnull (1)));
     56        int cfathread_join( cfathread_t, void ** retval );
     57
     58        int cfathread_get_errno(void);
     59        cfathread_t cfathread_self(void);
     60
     61        int cfathread_usleep(useconds_t usecs);
     62        int cfathread_sleep(unsigned int secs);
    3163
    3264        void cfathread_park( void );
     
    3567
    3668        //--------------------
    37         // Basic kernel features
    38         void cfathread_setproccnt( int );
     69        // mutex and condition
     70        struct timespec;
    3971
     72        typedef struct cfathread_mutex_attr {
     73        } cfathread_mutexattr_t;
     74        typedef struct cfathread_mutex * cfathread_mutex_t;
     75        int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict attr) __attribute__((nonnull (1)));
     76        int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
     77        int cfathread_mutex_lock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
     78        int cfathread_mutex_trylock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
     79        int cfathread_mutex_unlock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
     80
     81        typedef struct cfathread_cond_attr {
     82        } cfathread_condattr_t;
     83        typedef struct cfathread_condition * cfathread_cond_t;
     84        int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict attr) __attribute__((nonnull (1)));
     85        int cfathread_cond_wait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut) __attribute__((nonnull (1,2)));
     86        int cfathread_cond_timedwait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut, const struct timespec *restrict abstime) __attribute__((nonnull (1,2,3)));
     87        int cfathread_cond_signal(cfathread_cond_t *cond) __attribute__((nonnull (1)));
     88
     89        //--------------------
     90        // IO operations
     91        struct sockaddr;
     92        struct msghdr;
     93        int cfathread_socket(int domain, int type, int protocol);
     94        int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len);
     95        int cfathread_listen(int socket, int backlog);
     96        int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
     97        int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len);
     98        int cfathread_dup(int fildes);
     99        int cfathread_close(int fildes);
     100        ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags);
     101        ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte);
     102        ssize_t cfathread_recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len);
     103        ssize_t cfathread_read(int fildes, void *buf, size_t nbyte);
    40104
    41105#if defined(__cforall) || defined(__cplusplus)
  • libcfa/src/concurrency/coroutine.cfa

    rfeacef9 r5407cdc  
    4646
    4747//-----------------------------------------------------------------------------
    48 FORALL_DATA_INSTANCE(CoroutineCancelled, (coroutine_t &), (coroutine_t))
    49 
    50 forall(T &)
    51 void mark_exception(CoroutineCancelled(T) *) {}
    52 
    5348forall(T &)
    5449void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
     
    6560// This code should not be inlined. It is the error path on resume.
    6661forall(T & | is_coroutine(T))
    67 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ) {
     62void __cfaehm_cancelled_coroutine(
     63                T & cor, $coroutine * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ) {
    6864        verify( desc->cancellation );
    6965        desc->state = Cancelled;
     
    7268        // TODO: Remove explitate vtable set once trac#186 is fixed.
    7369        CoroutineCancelled(T) except;
    74         except.virtual_table = &get_exception_vtable(&except);
     70        except.virtual_table = &_default_vtable;
    7571        except.the_coroutine = &cor;
    7672        except.the_exception = except;
    77         throwResume except;
     73        // Why does this need a cast?
     74        throwResume (CoroutineCancelled(T) &)except;
    7875
    7976        except->virtual_table->free( except );
     
    148145// Part of the Public API
    149146// Not inline since only ever called once per coroutine
    150 forall(T & | is_coroutine(T))
     147forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })
    151148void prime(T& cor) {
    152149        $coroutine* this = get_coroutine(cor);
     
    196193
    197194void __stack_clean  ( __stack_info_t * this ) {
    198         size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t);
    199195        void * storage = this->storage->limit;
    200196
    201197        #if CFA_COROUTINE_USE_MMAP
     198                size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t);
    202199                storage = (void *)(((intptr_t)storage) - __page_size);
    203200                if(munmap(storage, size + __page_size) == -1) {
  • libcfa/src/concurrency/coroutine.hfa

    rfeacef9 r5407cdc  
    2222//-----------------------------------------------------------------------------
    2323// Exception thrown from resume when a coroutine stack is cancelled.
    24 FORALL_DATA_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (
     24EHM_FORALL_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (
    2525        coroutine_t * the_coroutine;
    2626        exception_t * the_exception;
     
    6060//-----------------------------------------------------------------------------
    6161// Public coroutine API
    62 forall(T & | is_coroutine(T))
     62forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })
    6363void prime(T & cor);
    6464
     
    130130
    131131forall(T & | is_coroutine(T))
    132 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc );
     132void __cfaehm_cancelled_coroutine(
     133        T & cor, $coroutine * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) );
    133134
    134135// Resume implementation inlined for performance
    135 forall(T & | is_coroutine(T))
     136forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })
    136137static inline T & resume(T & cor) {
    137138        // optimization : read TLS once and reuse it
     
    163164        $ctx_switch( src, dst );
    164165        if ( unlikely(dst->cancellation) ) {
    165                 __cfaehm_cancelled_coroutine( cor, dst );
     166                __cfaehm_cancelled_coroutine( cor, dst, _default_vtable );
    166167        }
    167168
  • libcfa/src/concurrency/future.hfa

    rfeacef9 r5407cdc  
    3737
    3838                // Fulfil the future, returns whether or not someone was unblocked
    39                 bool fulfil( future(T) & this, T result ) {
     39                $thread * fulfil( future(T) & this, T result ) {
    4040                        this.result = result;
    4141                        return fulfil( (future_t&)this );
     
    9696                bool fulfil( multi_future(T) & this, T result ) {
    9797                        this.result = result;
    98                         return fulfil( (future_t&)this );
     98                        return fulfil( (future_t&)this ) != 0p;
    9999                }
    100100
  • libcfa/src/concurrency/invoke.c

    rfeacef9 r5407cdc  
    3434
    3535extern void disable_interrupts() OPTIONAL_THREAD;
    36 extern void enable_interrupts( __cfaabi_dbg_ctx_param );
     36extern void enable_interrupts( _Bool poll );
    3737
    3838void __cfactx_invoke_coroutine(
     
    8282) {
    8383        // Officially start the thread by enabling preemption
    84         enable_interrupts( __cfaabi_dbg_ctx );
     84        enable_interrupts( true );
    8585
    8686        // Call the main of the thread
  • libcfa/src/concurrency/invoke.h

    rfeacef9 r5407cdc  
    148148                struct $thread * prev;
    149149                volatile unsigned long long ts;
    150                 int preferred;
     150                unsigned preferred;
    151151        };
    152152
     
    200200                } node;
    201201
     202                struct processor * last_proc;
     203
    202204                #if defined( __CFA_WITH_VERIFY__ )
    203205                        void * canary;
     
    224226                }
    225227
     228                static inline $thread * volatile & ?`next ( $thread * this )  __attribute__((const)) {
     229                        return this->seqable.next;
     230                }
     231
    226232                static inline $thread *& Back( $thread * this ) __attribute__((const)) {
    227233                        return this->seqable.back;
  • libcfa/src/concurrency/io.cfa

    rfeacef9 r5407cdc  
    3232        extern "C" {
    3333                #include <sys/syscall.h>
     34                #include <sys/eventfd.h>
    3435
    3536                #include <linux/io_uring.h>
     
    3940        #include "kernel.hfa"
    4041        #include "kernel/fwd.hfa"
     42        #include "kernel_private.hfa"
    4143        #include "io/types.hfa"
    4244
     
    7981        };
    8082
    81         // returns true of acquired as leader or second leader
    82         static inline bool try_lock( __leaderlock_t & this ) {
    83                 const uintptr_t thrd = 1z | (uintptr_t)active_thread();
    84                 bool block;
    85                 disable_interrupts();
    86                 for() {
    87                         struct $thread * expected = this.value;
    88                         if( 1p != expected && 0p != expected ) {
    89                                 /* paranoid */ verify( thrd != (uintptr_t)expected ); // We better not already be the next leader
    90                                 enable_interrupts( __cfaabi_dbg_ctx );
    91                                 return false;
    92                         }
    93                         struct $thread * desired;
    94                         if( 0p == expected ) {
    95                                 // If the lock isn't locked acquire it, no need to block
    96                                 desired = 1p;
    97                                 block = false;
    98                         }
    99                         else {
    100                                 // If the lock is already locked try becomming the next leader
    101                                 desired = (struct $thread *)thrd;
    102                                 block = true;
    103                         }
    104                         if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break;
    105                 }
    106                 if( block ) {
    107                         enable_interrupts( __cfaabi_dbg_ctx );
    108                         park();
    109                         disable_interrupts();
    110                 }
    111                 return true;
    112         }
    113 
    114         static inline bool next( __leaderlock_t & this ) {
     83        static $io_context * __ioarbiter_allocate( $io_arbiter & this, __u32 idxs[], __u32 want );
     84        static void __ioarbiter_submit( $io_context * , __u32 idxs[], __u32 have, bool lazy );
     85        static void __ioarbiter_flush ( $io_context & );
     86        static inline void __ioarbiter_notify( $io_context & ctx );
     87//=============================================================================================
     88// I/O Polling
     89//=============================================================================================
     90        static inline unsigned __flush( struct $io_context & );
     91        static inline __u32 __release_sqes( struct $io_context & );
     92        extern void __kernel_unpark( $thread * thrd );
     93
     94        bool __cfa_io_drain( processor * proc ) {
    11595                /* paranoid */ verify( ! __preemption_enabled() );
    116                 struct $thread * nextt;
    117                 for() {
    118                         struct $thread * expected = this.value;
    119                         /* paranoid */ verify( (1 & (uintptr_t)expected) == 1 ); // The lock better be locked
    120 
    121                         struct $thread * desired;
    122                         if( 1p == expected ) {
    123                                 // No next leader, just unlock
    124                                 desired = 0p;
    125                                 nextt   = 0p;
    126                         }
    127                         else {
    128                                 // There is a next leader, remove but keep locked
    129                                 desired = 1p;
    130                                 nextt   = (struct $thread *)(~1z & (uintptr_t)expected);
    131                         }
    132                         if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break;
    133                 }
    134 
    135                 if(nextt) {
    136                         unpark( nextt );
    137                         enable_interrupts( __cfaabi_dbg_ctx );
    138                         return true;
    139                 }
    140                 enable_interrupts( __cfaabi_dbg_ctx );
    141                 return false;
    142         }
    143 
    144 //=============================================================================================
    145 // I/O Syscall
    146 //=============================================================================================
    147         static int __io_uring_enter( struct __io_data & ring, unsigned to_submit, bool get ) {
    148                 bool need_sys_to_submit = false;
    149                 bool need_sys_to_complete = false;
    150                 unsigned flags = 0;
    151 
    152                 TO_SUBMIT:
    153                 if( to_submit > 0 ) {
    154                         if( !(ring.ring_flags & IORING_SETUP_SQPOLL) ) {
    155                                 need_sys_to_submit = true;
    156                                 break TO_SUBMIT;
    157                         }
    158                         if( (*ring.submit_q.flags) & IORING_SQ_NEED_WAKEUP ) {
    159                                 need_sys_to_submit = true;
    160                                 flags |= IORING_ENTER_SQ_WAKEUP;
    161                         }
    162                 }
    163 
    164                 if( get && !(ring.ring_flags & IORING_SETUP_SQPOLL) ) {
    165                         flags |= IORING_ENTER_GETEVENTS;
    166                         if( (ring.ring_flags & IORING_SETUP_IOPOLL) ) {
    167                                 need_sys_to_complete = true;
    168                         }
    169                 }
    170 
    171                 int ret = 0;
    172                 if( need_sys_to_submit || need_sys_to_complete ) {
    173                         __cfadbg_print_safe(io_core, "Kernel I/O : IO_URING enter %d %u %u\n", ring.fd, to_submit, flags);
    174                         ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, 0, flags, (sigset_t *)0p, _NSIG / 8);
    175                         __cfadbg_print_safe(io_core, "Kernel I/O : IO_URING %d returned %d\n", ring.fd, ret);
    176 
    177                         if( ret < 0 ) {
    178                                 switch((int)errno) {
    179                                 case EAGAIN:
    180                                 case EINTR:
    181                                 case EBUSY:
    182                                         ret = -1;
    183                                         break;
    184                                 default:
    185                                         abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) );
    186                                 }
    187                         }
    188                 }
    189 
    190                 // Memory barrier
    191                 __atomic_thread_fence( __ATOMIC_SEQ_CST );
    192                 return ret;
    193         }
    194 
    195 //=============================================================================================
    196 // I/O Polling
    197 //=============================================================================================
    198         static unsigned __collect_submitions( struct __io_data & ring );
    199         static __u32 __release_consumed_submission( struct __io_data & ring );
    200         static inline void __clean( volatile struct io_uring_sqe * sqe );
    201 
    202         // Process a single completion message from the io_uring
    203         // This is NOT thread-safe
    204         static inline void process( volatile struct io_uring_cqe & cqe ) {
    205                 struct io_future_t * future = (struct io_future_t *)(uintptr_t)cqe.user_data;
    206                 __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future );
    207 
    208                 fulfil( *future, cqe.res );
    209         }
    210 
    211         static [int, bool] __drain_io( & struct __io_data ring ) {
    212                 /* paranoid */ verify( ! __preemption_enabled() );
    213 
    214                 unsigned to_submit = 0;
    215                 if( ring.poller_submits ) {
    216                         // If the poller thread also submits, then we need to aggregate the submissions which are ready
    217                         to_submit = __collect_submitions( ring );
    218                 }
    219 
    220                 int ret = __io_uring_enter(ring, to_submit, true);
    221                 if( ret < 0 ) {
    222                         return [0, true];
    223                 }
    224 
    225                 // update statistics
    226                 if (to_submit > 0) {
    227                         __STATS__( true,
    228                                 if( to_submit > 0 ) {
    229                                         io.submit_q.submit_avg.rdy += to_submit;
    230                                         io.submit_q.submit_avg.csm += ret;
    231                                         io.submit_q.submit_avg.cnt += 1;
    232                                 }
    233                         )
    234                 }
    235 
    236                 __atomic_thread_fence( __ATOMIC_SEQ_CST );
    237 
    238                 // Release the consumed SQEs
    239                 __release_consumed_submission( ring );
     96                /* paranoid */ verify( ready_schedule_islocked() );
     97                /* paranoid */ verify( proc );
     98                /* paranoid */ verify( proc->io.ctx );
    24099
    241100                // Drain the queue
    242                 unsigned head = *ring.completion_q.head;
    243                 unsigned tail = *ring.completion_q.tail;
    244                 const __u32 mask = *ring.completion_q.mask;
    245 
    246                 // Nothing was new return 0
    247                 if (head == tail) {
    248                         return [0, to_submit > 0];
    249                 }
     101                $io_context * ctx = proc->io.ctx;
     102                unsigned head = *ctx->cq.head;
     103                unsigned tail = *ctx->cq.tail;
     104                const __u32 mask = *ctx->cq.mask;
    250105
    251106                __u32 count = tail - head;
    252                 /* paranoid */ verify( count != 0 );
     107                __STATS__( false, io.calls.drain++; io.calls.completed += count; )
     108
     109                if(count == 0) return false;
     110
    253111                for(i; count) {
    254112                        unsigned idx = (head + i) & mask;
    255                         volatile struct io_uring_cqe & cqe = ring.completion_q.cqes[idx];
     113                        volatile struct io_uring_cqe & cqe = ctx->cq.cqes[idx];
    256114
    257115                        /* paranoid */ verify(&cqe);
    258116
    259                         process( cqe );
    260                 }
     117                        struct io_future_t * future = (struct io_future_t *)(uintptr_t)cqe.user_data;
     118                        __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future );
     119
     120                        __kernel_unpark( fulfil( *future, cqe.res, false ) );
     121                }
     122
     123                __cfadbg_print_safe(io, "Kernel I/O : %u completed\n", count);
    261124
    262125                // Mark to the kernel that the cqe has been seen
    263126                // Ensure that the kernel only sees the new value of the head index after the CQEs have been read.
    264                 __atomic_fetch_add( ring.completion_q.head, count, __ATOMIC_SEQ_CST );
    265 
    266                 return [count, count > 0 || to_submit > 0];
    267         }
    268 
    269         void main( $io_ctx_thread & this ) {
    270                 __ioctx_register( this );
    271 
    272                 __cfadbg_print_safe(io_core, "Kernel I/O : IO poller %d (%p) ready\n", this.ring->fd, &this);
    273 
    274                 const int reset_cnt = 5;
    275                 int reset = reset_cnt;
    276                 // Then loop until we need to start
    277                 LOOP:
    278                 while(!__atomic_load_n(&this.done, __ATOMIC_SEQ_CST)) {
    279                         // Drain the io
    280                         int count;
    281                         bool again;
    282                         disable_interrupts();
    283                                 [count, again] = __drain_io( *this.ring );
    284 
    285                                 if(!again) reset--;
    286 
     127                __atomic_store_n( ctx->cq.head, head + count, __ATOMIC_SEQ_CST );
     128
     129                /* paranoid */ verify( ready_schedule_islocked() );
     130                /* paranoid */ verify( ! __preemption_enabled() );
     131
     132                return true;
     133        }
     134
     135        void __cfa_io_flush( processor * proc ) {
     136                /* paranoid */ verify( ! __preemption_enabled() );
     137                /* paranoid */ verify( proc );
     138                /* paranoid */ verify( proc->io.ctx );
     139
     140                $io_context & ctx = *proc->io.ctx;
     141
     142                __ioarbiter_flush( ctx );
     143
     144                __STATS__( true, io.calls.flush++; )
     145                int ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, 0, 0, (sigset_t *)0p, _NSIG / 8);
     146                if( ret < 0 ) {
     147                        switch((int)errno) {
     148                        case EAGAIN:
     149                        case EINTR:
     150                        case EBUSY:
    287151                                // Update statistics
    288                                 __STATS__( true,
    289                                         io.complete_q.completed_avg.val += count;
    290                                         io.complete_q.completed_avg.cnt += 1;
    291                                 )
    292                         enable_interrupts( __cfaabi_dbg_ctx );
    293 
    294                         // If we got something, just yield and check again
    295                         if(reset > 1) {
    296                                 yield();
    297                                 continue LOOP;
     152                                __STATS__( false, io.calls.errors.busy ++; )
     153                                return;
     154                        default:
     155                                abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) );
    298156                        }
    299 
    300                         // We alread failed to find completed entries a few time.
    301                         if(reset == 1) {
    302                                 // Rearm the context so it can block
    303                                 // but don't block right away
    304                                 // we need to retry one last time in case
    305                                 // something completed *just now*
    306                                 __ioctx_prepare_block( this );
    307                                 continue LOOP;
    308                         }
    309 
    310                                 __STATS__( false,
    311                                         io.complete_q.blocks += 1;
    312                                 )
    313                                 __cfadbg_print_safe(io_core, "Kernel I/O : Parking io poller %d (%p)\n", this.ring->fd, &this);
    314 
    315                                 // block this thread
    316                                 wait( this.sem );
    317 
    318                         // restore counter
    319                         reset = reset_cnt;
    320                 }
    321 
    322                 __cfadbg_print_safe(io_core, "Kernel I/O : Fast poller %d (%p) stopping\n", this.ring->fd, &this);
    323 
    324                 __ioctx_unregister( this );
     157                }
     158
     159                __cfadbg_print_safe(io, "Kernel I/O : %u submitted to io_uring %d\n", ret, ctx.fd);
     160                __STATS__( true, io.calls.submitted += ret; )
     161                /* paranoid */ verify( ctx.sq.to_submit <= *ctx.sq.num );
     162                /* paranoid */ verify( ctx.sq.to_submit >= ret );
     163
     164                ctx.sq.to_submit -= ret;
     165
     166                /* paranoid */ verify( ctx.sq.to_submit <= *ctx.sq.num );
     167
     168                // Release the consumed SQEs
     169                __release_sqes( ctx );
     170
     171                /* paranoid */ verify( ! __preemption_enabled() );
     172
     173                ctx.proc->io.pending = false;
    325174        }
    326175
     
    344193//         head and tail must be fully filled and shouldn't ever be touched again.
    345194//
     195        //=============================================================================================
     196        // Allocation
     197        // for user's convenience fill the sqes from the indexes
     198        static inline void __fill(struct io_uring_sqe * out_sqes[], __u32 want, __u32 idxs[], struct $io_context * ctx)  {
     199                struct io_uring_sqe * sqes = ctx->sq.sqes;
     200                for(i; want) {
     201                        __cfadbg_print_safe(io, "Kernel I/O : filling loop\n");
     202                        out_sqes[i] = &sqes[idxs[i]];
     203                }
     204        }
     205
     206        // Try to directly allocate from the a given context
     207        // Not thread-safe
     208        static inline bool __alloc(struct $io_context * ctx, __u32 idxs[], __u32 want) {
     209                __sub_ring_t & sq = ctx->sq;
     210                const __u32 mask  = *sq.mask;
     211                __u32 fhead = sq.free_ring.head;    // get the current head of the queue
     212                __u32 ftail = sq.free_ring.tail;    // get the current tail of the queue
     213
     214                // If we don't have enough sqes, fail
     215                if((ftail - fhead) < want) { return false; }
     216
     217                // copy all the indexes we want from the available list
     218                for(i; want) {
     219                        __cfadbg_print_safe(io, "Kernel I/O : allocating loop\n");
     220                        idxs[i] = sq.free_ring.array[(fhead + i) & mask];
     221                }
     222
     223                // Advance the head to mark the indexes as consumed
     224                __atomic_store_n(&sq.free_ring.head, fhead + want, __ATOMIC_RELEASE);
     225
     226                // return success
     227                return true;
     228        }
    346229
    347230        // Allocate an submit queue entry.
     
    350233        // for convenience, return both the index and the pointer to the sqe
    351234        // sqe == &sqes[idx]
    352         [* volatile struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ) {
    353                 /* paranoid */ verify( data != 0 );
    354 
    355                 // Prepare the data we need
    356                 __attribute((unused)) int len   = 0;
    357                 __attribute((unused)) int block = 0;
    358                 __u32 cnt = *ring.submit_q.num;
    359                 __u32 mask = *ring.submit_q.mask;
    360 
    361                 __u32 off = thread_rand();
    362 
    363                 // Loop around looking for an available spot
    364                 for() {
    365                         // Look through the list starting at some offset
    366                         for(i; cnt) {
    367                                 __u64 expected = 3;
    368                                 __u32 idx = (i + off) & mask; // Get an index from a random
    369                                 volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx];
    370                                 volatile __u64 * udata = &sqe->user_data;
    371 
    372                                 // Allocate the entry by CASing the user_data field from 0 to the future address
    373                                 if( *udata == expected &&
    374                                         __atomic_compare_exchange_n( udata, &expected, data, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) )
    375                                 {
    376                                         // update statistics
    377                                         __STATS__( false,
    378                                                 io.submit_q.alloc_avg.val   += len;
    379                                                 io.submit_q.alloc_avg.block += block;
    380                                                 io.submit_q.alloc_avg.cnt   += 1;
    381                                         )
    382 
    383                                         // debug log
    384                                         __cfadbg_print_safe( io, "Kernel I/O : allocated [%p, %u] for %p (%p)\n", sqe, idx, active_thread(), (void*)data );
    385 
    386                                         // Success return the data
    387                                         return [sqe, idx];
    388                                 }
    389                                 verify(expected != data);
    390 
    391                                 // This one was used
    392                                 len ++;
    393                         }
    394 
    395                         block++;
    396 
    397                         yield();
    398                 }
    399         }
    400 
    401         static inline __u32 __submit_to_ready_array( struct __io_data & ring, __u32 idx, const __u32 mask ) {
    402                 /* paranoid */ verify( idx <= mask   );
    403                 /* paranoid */ verify( idx != -1ul32 );
    404 
    405                 // We need to find a spot in the ready array
    406                 __attribute((unused)) int len   = 0;
    407                 __attribute((unused)) int block = 0;
    408                 __u32 ready_mask = ring.submit_q.ready_cnt - 1;
    409 
    410                 __u32 off = thread_rand();
    411 
    412                 __u32 picked;
    413                 LOOKING: for() {
    414                         for(i; ring.submit_q.ready_cnt) {
    415                                 picked = (i + off) & ready_mask;
    416                                 __u32 expected = -1ul32;
    417                                 if( __atomic_compare_exchange_n( &ring.submit_q.ready[picked], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) {
    418                                         break LOOKING;
    419                                 }
    420                                 verify(expected != idx);
    421 
    422                                 len ++;
    423                         }
    424 
    425                         block++;
    426 
    427                         __u32 released = __release_consumed_submission( ring );
    428                         if( released == 0 ) {
    429                                 yield();
    430                         }
    431                 }
    432 
    433                 // update statistics
    434                 __STATS__( false,
    435                         io.submit_q.look_avg.val   += len;
    436                         io.submit_q.look_avg.block += block;
    437                         io.submit_q.look_avg.cnt   += 1;
    438                 )
    439 
    440                 return picked;
    441         }
    442 
    443         void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1))) {
    444                 __io_data & ring = *ctx->thrd.ring;
    445 
     235        struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) {
     236                __cfadbg_print_safe(io, "Kernel I/O : attempting to allocate %u\n", want);
     237
     238                disable_interrupts();
     239                processor * proc = __cfaabi_tls.this_processor;
     240                $io_context * ctx = proc->io.ctx;
     241                /* paranoid */ verify( __cfaabi_tls.this_processor );
     242                /* paranoid */ verify( ctx );
     243
     244                __cfadbg_print_safe(io, "Kernel I/O : attempting to fast allocation\n");
     245
     246                // We can proceed to the fast path
     247                if( __alloc(ctx, idxs, want) ) {
     248                        // Allocation was successful
     249                        __STATS__( true, io.alloc.fast += 1; )
     250                        enable_interrupts();
     251
     252                        __cfadbg_print_safe(io, "Kernel I/O : fast allocation successful from ring %d\n", ctx->fd);
     253
     254                        __fill( sqes, want, idxs, ctx );
     255                        return ctx;
     256                }
     257                // The fast path failed, fallback
     258                __STATS__( true, io.alloc.fail += 1; )
     259
     260                // Fast path failed, fallback on arbitration
     261                __STATS__( true, io.alloc.slow += 1; )
     262                enable_interrupts();
     263
     264                $io_arbiter * ioarb = proc->cltr->io.arbiter;
     265                /* paranoid */ verify( ioarb );
     266
     267                __cfadbg_print_safe(io, "Kernel I/O : falling back on arbiter for allocation\n");
     268
     269                struct $io_context * ret = __ioarbiter_allocate(*ioarb, idxs, want);
     270
     271                __cfadbg_print_safe(io, "Kernel I/O : slow allocation completed from ring %d\n", ret->fd);
     272
     273                __fill( sqes, want, idxs,ret );
     274                return ret;
     275        }
     276
     277
     278        //=============================================================================================
     279        // submission
     280        static inline void __submit( struct $io_context * ctx, __u32 idxs[], __u32 have, bool lazy) {
     281                // We can proceed to the fast path
     282                // Get the right objects
     283                __sub_ring_t & sq = ctx->sq;
     284                const __u32 mask  = *sq.mask;
     285                __u32 tail = *sq.kring.tail;
     286
     287                // Add the sqes to the array
     288                for( i; have ) {
     289                        __cfadbg_print_safe(io, "Kernel I/O : __submit loop\n");
     290                        sq.kring.array[ (tail + i) & mask ] = idxs[i];
     291                }
     292
     293                // Make the sqes visible to the submitter
     294                __atomic_store_n(sq.kring.tail, tail + have, __ATOMIC_RELEASE);
     295                sq.to_submit++;
     296
     297                ctx->proc->io.pending = true;
     298                ctx->proc->io.dirty   = true;
     299                if(sq.to_submit > 30 || !lazy) {
     300                        __cfa_io_flush( ctx->proc );
     301                }
     302        }
     303
     304        void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) {
     305                __cfadbg_print_safe(io, "Kernel I/O : attempting to submit %u (%s)\n", have, lazy ? "lazy" : "eager");
     306
     307                disable_interrupts();
     308                processor * proc = __cfaabi_tls.this_processor;
     309                $io_context * ctx = proc->io.ctx;
     310                /* paranoid */ verify( __cfaabi_tls.this_processor );
     311                /* paranoid */ verify( ctx );
     312
     313                // Can we proceed to the fast path
     314                if( ctx == inctx )              // We have the right instance?
    446315                {
    447                         __attribute__((unused)) volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx];
    448                         __cfadbg_print_safe( io,
    449                                 "Kernel I/O : submitting %u (%p) for %p\n"
    450                                 "    data: %p\n"
    451                                 "    opcode: %s\n"
    452                                 "    fd: %d\n"
    453                                 "    flags: %d\n"
    454                                 "    prio: %d\n"
    455                                 "    off: %p\n"
    456                                 "    addr: %p\n"
    457                                 "    len: %d\n"
    458                                 "    other flags: %d\n"
    459                                 "    splice fd: %d\n"
    460                                 "    pad[0]: %llu\n"
    461                                 "    pad[1]: %llu\n"
    462                                 "    pad[2]: %llu\n",
    463                                 idx, sqe,
    464                                 active_thread(),
    465                                 (void*)sqe->user_data,
    466                                 opcodes[sqe->opcode],
    467                                 sqe->fd,
    468                                 sqe->flags,
    469                                 sqe->ioprio,
    470                                 (void*)sqe->off,
    471                                 (void*)sqe->addr,
    472                                 sqe->len,
    473                                 sqe->accept_flags,
    474                                 sqe->splice_fd_in,
    475                                 sqe->__pad2[0],
    476                                 sqe->__pad2[1],
    477                                 sqe->__pad2[2]
    478                         );
    479                 }
    480 
    481 
    482                 // Get now the data we definetely need
    483                 volatile __u32 * const tail = ring.submit_q.tail;
    484                 const __u32 mask  = *ring.submit_q.mask;
    485 
    486                 // There are 2 submission schemes, check which one we are using
    487                 if( ring.poller_submits ) {
    488                         // If the poller thread submits, then we just need to add this to the ready array
    489                         __submit_to_ready_array( ring, idx, mask );
    490 
    491                         post( ctx->thrd.sem );
    492 
    493                         __cfadbg_print_safe( io, "Kernel I/O : Added %u to ready for %p\n", idx, active_thread() );
    494                 }
    495                 else if( ring.eager_submits ) {
    496                         __attribute__((unused)) __u32 picked = __submit_to_ready_array( ring, idx, mask );
    497 
    498                         #if defined(LEADER_LOCK)
    499                                 if( !try_lock(ring.submit_q.submit_lock) ) {
    500                                         __STATS__( false,
    501                                                 io.submit_q.helped += 1;
    502                                         )
    503                                         return;
    504                                 }
    505                                 /* paranoid */ verify( ! __preemption_enabled() );
    506                                 __STATS__( true,
    507                                         io.submit_q.leader += 1;
    508                                 )
    509                         #else
    510                                 for() {
    511                                         yield();
    512 
    513                                         if( try_lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2) ) {
    514                                                 __STATS__( false,
    515                                                         io.submit_q.leader += 1;
    516                                                 )
    517                                                 break;
    518                                         }
    519 
    520                                         // If some one else collected our index, we are done
    521                                         #warning ABA problem
    522                                         if( ring.submit_q.ready[picked] != idx ) {
    523                                                 __STATS__( false,
    524                                                         io.submit_q.helped += 1;
    525                                                 )
    526                                                 return;
    527                                         }
    528 
    529                                         __STATS__( false,
    530                                                 io.submit_q.busy += 1;
    531                                         )
    532                                 }
    533                         #endif
    534 
    535                         // We got the lock
    536                         // Collect the submissions
    537                         unsigned to_submit = __collect_submitions( ring );
    538 
    539                         // Actually submit
    540                         int ret = __io_uring_enter( ring, to_submit, false );
    541 
    542                         #if defined(LEADER_LOCK)
    543                                 /* paranoid */ verify( ! __preemption_enabled() );
    544                                 next(ring.submit_q.submit_lock);
    545                         #else
    546                                 unlock(ring.submit_q.submit_lock);
    547                         #endif
    548                         if( ret < 0 ) {
    549                                 return;
    550                         }
    551 
    552                         // Release the consumed SQEs
    553                         __release_consumed_submission( ring );
    554 
    555                         // update statistics
    556                         __STATS__( false,
    557                                 io.submit_q.submit_avg.rdy += to_submit;
    558                                 io.submit_q.submit_avg.csm += ret;
    559                                 io.submit_q.submit_avg.cnt += 1;
    560                         )
    561 
    562                         __cfadbg_print_safe( io, "Kernel I/O : submitted %u (among %u) for %p\n", idx, ret, active_thread() );
    563                 }
    564                 else
    565                 {
    566                         // get mutual exclusion
    567                         #if defined(LEADER_LOCK)
    568                                 while(!try_lock(ring.submit_q.submit_lock));
    569                         #else
    570                                 lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2);
    571                         #endif
    572 
    573                         /* paranoid */ verifyf( ring.submit_q.sqes[ idx ].user_data != 3ul64,
    574                         /* paranoid */  "index %u already reclaimed\n"
    575                         /* paranoid */  "head %u, prev %u, tail %u\n"
    576                         /* paranoid */  "[-0: %u,-1: %u,-2: %u,-3: %u]\n",
    577                         /* paranoid */  idx,
    578                         /* paranoid */  *ring.submit_q.head, ring.submit_q.prev_head, *tail
    579                         /* paranoid */  ,ring.submit_q.array[ ((*ring.submit_q.head) - 0) & (*ring.submit_q.mask) ]
    580                         /* paranoid */  ,ring.submit_q.array[ ((*ring.submit_q.head) - 1) & (*ring.submit_q.mask) ]
    581                         /* paranoid */  ,ring.submit_q.array[ ((*ring.submit_q.head) - 2) & (*ring.submit_q.mask) ]
    582                         /* paranoid */  ,ring.submit_q.array[ ((*ring.submit_q.head) - 3) & (*ring.submit_q.mask) ]
    583                         /* paranoid */ );
    584 
    585                         // Append to the list of ready entries
    586 
    587                         /* paranoid */ verify( idx <= mask );
    588                         ring.submit_q.array[ (*tail) & mask ] = idx;
    589                         __atomic_fetch_add(tail, 1ul32, __ATOMIC_SEQ_CST);
    590 
    591                         // Submit however, many entries need to be submitted
    592                         int ret = __io_uring_enter( ring, 1, false );
    593                         if( ret < 0 ) {
    594                                 switch((int)errno) {
    595                                 default:
    596                                         abort( "KERNEL ERROR: IO_URING SUBMIT - %s\n", strerror(errno) );
    597                                 }
    598                         }
    599 
    600                         /* paranoid */ verify(ret == 1);
    601 
    602                         // update statistics
    603                         __STATS__( false,
    604                                 io.submit_q.submit_avg.csm += 1;
    605                                 io.submit_q.submit_avg.cnt += 1;
    606                         )
    607 
    608                         {
    609                                 __attribute__((unused)) volatile __u32 * const head = ring.submit_q.head;
    610                                 __attribute__((unused)) __u32 last_idx = ring.submit_q.array[ ((*head) - 1) & mask ];
    611                                 __attribute__((unused)) volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[last_idx];
    612 
    613                                 __cfadbg_print_safe( io,
    614                                         "Kernel I/O : last submitted is %u (%p)\n"
    615                                         "    data: %p\n"
    616                                         "    opcode: %s\n"
    617                                         "    fd: %d\n"
    618                                         "    flags: %d\n"
    619                                         "    prio: %d\n"
    620                                         "    off: %p\n"
    621                                         "    addr: %p\n"
    622                                         "    len: %d\n"
    623                                         "    other flags: %d\n"
    624                                         "    splice fd: %d\n"
    625                                         "    pad[0]: %llu\n"
    626                                         "    pad[1]: %llu\n"
    627                                         "    pad[2]: %llu\n",
    628                                         last_idx, sqe,
    629                                         (void*)sqe->user_data,
    630                                         opcodes[sqe->opcode],
    631                                         sqe->fd,
    632                                         sqe->flags,
    633                                         sqe->ioprio,
    634                                         (void*)sqe->off,
    635                                         (void*)sqe->addr,
    636                                         sqe->len,
    637                                         sqe->accept_flags,
    638                                         sqe->splice_fd_in,
    639                                         sqe->__pad2[0],
    640                                         sqe->__pad2[1],
    641                                         sqe->__pad2[2]
    642                                 );
    643                         }
    644 
    645                         __atomic_thread_fence( __ATOMIC_SEQ_CST );
    646                         // Release the consumed SQEs
    647 
    648                         __release_consumed_submission( ring );
    649                         // ring.submit_q.sqes[idx].user_data = 3ul64;
    650 
    651                         #if defined(LEADER_LOCK)
    652                                 next(ring.submit_q.submit_lock);
    653                         #else
    654                                 unlock(ring.submit_q.submit_lock);
    655                         #endif
    656 
    657                         __cfadbg_print_safe( io, "Kernel I/O : submitted %u for %p\n", idx, active_thread() );
    658                 }
    659         }
    660 
    661         // #define PARTIAL_SUBMIT 32
    662 
    663         // go through the list of submissions in the ready array and moved them into
    664         // the ring's submit queue
    665         static unsigned __collect_submitions( struct __io_data & ring ) {
    666                 /* paranoid */ verify( ring.submit_q.ready != 0p );
    667                 /* paranoid */ verify( ring.submit_q.ready_cnt > 0 );
    668 
    669                 unsigned to_submit = 0;
    670                 __u32 tail = *ring.submit_q.tail;
    671                 const __u32 mask = *ring.submit_q.mask;
    672                 #if defined(PARTIAL_SUBMIT)
    673                         #if defined(LEADER_LOCK)
    674                                 #error PARTIAL_SUBMIT and LEADER_LOCK cannot co-exist
    675                         #endif
    676                         const __u32 cnt = ring.submit_q.ready_cnt > PARTIAL_SUBMIT ? PARTIAL_SUBMIT : ring.submit_q.ready_cnt;
    677                         const __u32 offset = ring.submit_q.prev_ready;
    678                         ring.submit_q.prev_ready += cnt;
    679                 #else
    680                         const __u32 cnt = ring.submit_q.ready_cnt;
    681                         const __u32 offset = 0;
    682                 #endif
    683 
    684                 // Go through the list of ready submissions
    685                 for( c; cnt ) {
    686                         __u32 i = (offset + c) % ring.submit_q.ready_cnt;
    687 
    688                         // replace any submission with the sentinel, to consume it.
    689                         __u32 idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED);
    690 
    691                         // If it was already the sentinel, then we are done
    692                         if( idx == -1ul32 ) continue;
    693 
    694                         // If we got a real submission, append it to the list
    695                         ring.submit_q.array[ (tail + to_submit) & mask ] = idx & mask;
    696                         to_submit++;
    697                 }
    698 
    699                 // Increment the tail based on how many we are ready to submit
    700                 __atomic_fetch_add(ring.submit_q.tail, to_submit, __ATOMIC_SEQ_CST);
    701 
    702                 return to_submit;
    703         }
    704 
     316                        __submit(ctx, idxs, have, lazy);
     317
     318                        // Mark the instance as no longer in-use, re-enable interrupts and return
     319                        __STATS__( true, io.submit.fast += 1; )
     320                        enable_interrupts();
     321
     322                        __cfadbg_print_safe(io, "Kernel I/O : submitted on fast path\n");
     323                        return;
     324                }
     325
     326                // Fast path failed, fallback on arbitration
     327                __STATS__( true, io.submit.slow += 1; )
     328                enable_interrupts();
     329
     330                __cfadbg_print_safe(io, "Kernel I/O : falling back on arbiter for submission\n");
     331
     332                __ioarbiter_submit(inctx, idxs, have, lazy);
     333        }
     334
     335        //=============================================================================================
     336        // Flushing
    705337        // Go through the ring's submit queue and release everything that has already been consumed
    706338        // by io_uring
    707         static __u32 __release_consumed_submission( struct __io_data & ring ) {
    708                 const __u32 smask = *ring.submit_q.mask;
    709 
    710                 // We need to get the lock to copy the old head and new head
    711                 if( !try_lock(ring.submit_q.release_lock __cfaabi_dbg_ctx2) ) return 0;
     339        // This cannot be done by multiple threads
     340        static __u32 __release_sqes( struct $io_context & ctx ) {
     341                const __u32 mask = *ctx.sq.mask;
     342
    712343                __attribute__((unused))
    713                 __u32 ctail = *ring.submit_q.tail;        // get the current tail of the queue
    714                 __u32 chead = *ring.submit_q.head;              // get the current head of the queue
    715                 __u32 phead = ring.submit_q.prev_head;  // get the head the last time we were here
    716                 ring.submit_q.prev_head = chead;                // note up to were we processed
    717                 unlock(ring.submit_q.release_lock);
     344                __u32 ctail = *ctx.sq.kring.tail;    // get the current tail of the queue
     345                __u32 chead = *ctx.sq.kring.head;        // get the current head of the queue
     346                __u32 phead = ctx.sq.kring.released; // get the head the last time we were here
     347
     348                __u32 ftail = ctx.sq.free_ring.tail;  // get the current tail of the queue
    718349
    719350                // the 3 fields are organized like this diagram
     
    734365                __u32 count = chead - phead;
    735366
     367                if(count == 0) {
     368                        return 0;
     369                }
     370
    736371                // We acquired an previous-head/current-head range
    737372                // go through the range and release the sqes
    738373                for( i; count ) {
    739                         __u32 idx = ring.submit_q.array[ (phead + i) & smask ];
    740 
    741                         /* paranoid */ verify( 0 != ring.submit_q.sqes[ idx ].user_data );
    742                         __clean( &ring.submit_q.sqes[ idx ] );
    743                 }
     374                        __cfadbg_print_safe(io, "Kernel I/O : release loop\n");
     375                        __u32 idx = ctx.sq.kring.array[ (phead + i) & mask ];
     376                        ctx.sq.free_ring.array[ (ftail + i) & mask ] = idx;
     377                }
     378
     379                ctx.sq.kring.released = chead;          // note up to were we processed
     380                __atomic_store_n(&ctx.sq.free_ring.tail, ftail + count, __ATOMIC_SEQ_CST);
     381
     382                __ioarbiter_notify(ctx);
     383
    744384                return count;
    745385        }
    746386
    747         void __sqe_clean( volatile struct io_uring_sqe * sqe ) {
    748                 __clean( sqe );
    749         }
    750 
    751         static inline void __clean( volatile struct io_uring_sqe * sqe ) {
    752                 // If we are in debug mode, thrash the fields to make sure we catch reclamation errors
    753                 __cfaabi_dbg_debug_do(
    754                         memset(sqe, 0xde, sizeof(*sqe));
    755                         sqe->opcode = (sizeof(opcodes) / sizeof(const char *)) - 1;
    756                 );
    757 
    758                 // Mark the entry as unused
    759                 __atomic_store_n(&sqe->user_data, 3ul64, __ATOMIC_SEQ_CST);
     387//=============================================================================================
     388// I/O Arbiter
     389//=============================================================================================
     390        static inline void block(__outstanding_io_queue & queue, __outstanding_io & item) {
     391                // Lock the list, it's not thread safe
     392                lock( queue.lock __cfaabi_dbg_ctx2 );
     393                {
     394                        // Add our request to the list
     395                        add( queue.queue, item );
     396
     397                        // Mark as pending
     398                        __atomic_store_n( &queue.empty, false, __ATOMIC_SEQ_CST );
     399                }
     400                unlock( queue.lock );
     401
     402                wait( item.sem );
     403        }
     404
     405        static inline bool empty(__outstanding_io_queue & queue ) {
     406                return __atomic_load_n( &queue.empty, __ATOMIC_SEQ_CST);
     407        }
     408
     409        static $io_context * __ioarbiter_allocate( $io_arbiter & this, __u32 idxs[], __u32 want ) {
     410                __cfadbg_print_safe(io, "Kernel I/O : arbiter allocating\n");
     411
     412                __STATS__( false, io.alloc.block += 1; )
     413
     414                // No one has any resources left, wait for something to finish
     415                // We need to add ourself to a list of pending allocs and wait for an answer
     416                __pending_alloc pa;
     417                pa.idxs = idxs;
     418                pa.want = want;
     419
     420                block(this.pending, (__outstanding_io&)pa);
     421
     422                return pa.ctx;
     423
     424        }
     425
     426        static void __ioarbiter_notify( $io_arbiter & this, $io_context * ctx ) {
     427                /* paranoid */ verify( !empty(this.pending.queue) );
     428
     429                lock( this.pending.lock __cfaabi_dbg_ctx2 );
     430                {
     431                        while( !empty(this.pending.queue) ) {
     432                                __cfadbg_print_safe(io, "Kernel I/O : notifying\n");
     433                                __u32 have = ctx->sq.free_ring.tail - ctx->sq.free_ring.head;
     434                                __pending_alloc & pa = (__pending_alloc&)head( this.pending.queue );
     435
     436                                if( have > pa.want ) goto DONE;
     437                                drop( this.pending.queue );
     438
     439                                /* paranoid */__attribute__((unused)) bool ret =
     440
     441                                __alloc(ctx, pa.idxs, pa.want);
     442
     443                                /* paranoid */ verify( ret );
     444
     445                                pa.ctx = ctx;
     446
     447                                post( pa.sem );
     448                        }
     449
     450                        this.pending.empty = true;
     451                        DONE:;
     452                }
     453                unlock( this.pending.lock );
     454        }
     455
     456        static void __ioarbiter_notify( $io_context & ctx ) {
     457                if(!empty( ctx.arbiter->pending )) {
     458                        __ioarbiter_notify( *ctx.arbiter, &ctx );
     459                }
     460        }
     461
     462        // Simply append to the pending
     463        static void __ioarbiter_submit( $io_context * ctx, __u32 idxs[], __u32 have, bool lazy ) {
     464                __cfadbg_print_safe(io, "Kernel I/O : submitting %u from the arbiter to context %u\n", have, ctx->fd);
     465
     466                __cfadbg_print_safe(io, "Kernel I/O : waiting to submit %u\n", have);
     467
     468                __external_io ei;
     469                ei.idxs = idxs;
     470                ei.have = have;
     471                ei.lazy = lazy;
     472
     473                block(ctx->ext_sq, (__outstanding_io&)ei);
     474
     475                __cfadbg_print_safe(io, "Kernel I/O : %u submitted from arbiter\n", have);
     476        }
     477
     478        static void __ioarbiter_flush( $io_context & ctx ) {
     479                if(!empty( ctx.ext_sq )) {
     480                        __STATS__( false, io.flush.external += 1; )
     481
     482                        __cfadbg_print_safe(io, "Kernel I/O : arbiter flushing\n");
     483
     484                        lock( ctx.ext_sq.lock __cfaabi_dbg_ctx2 );
     485                        {
     486                                while( !empty(ctx.ext_sq.queue) ) {
     487                                        __external_io & ei = (__external_io&)drop( ctx.ext_sq.queue );
     488
     489                                        __submit(&ctx, ei.idxs, ei.have, ei.lazy);
     490
     491                                        post( ei.sem );
     492                                }
     493
     494                                ctx.ext_sq.empty = true;
     495                        }
     496                        unlock(ctx.ext_sq.lock );
     497                }
    760498        }
    761499#endif
  • libcfa/src/concurrency/io/call.cfa.in

    rfeacef9 r5407cdc  
    5454                        | IOSQE_IO_DRAIN
    5555                #endif
     56                #if defined(CFA_HAVE_IOSQE_IO_LINK)
     57                        | IOSQE_IO_LINK
     58                #endif
     59                #if defined(CFA_HAVE_IOSQE_IO_HARDLINK)
     60                        | IOSQE_IO_HARDLINK
     61                #endif
    5662                #if defined(CFA_HAVE_IOSQE_ASYNC)
    5763                        | IOSQE_ASYNC
    5864                #endif
    59         ;
    60 
    61         static const __u32 LINK_FLAGS = 0
    62                 #if defined(CFA_HAVE_IOSQE_IO_LINK)
    63                         | IOSQE_IO_LINK
    64                 #endif
    65                 #if defined(CFA_HAVE_IOSQE_IO_HARDLINK)
    66                         | IOSQE_IO_HARDLINK
     65                #if defined(CFA_HAVE_IOSQE_BUFFER_SELECTED)
     66                        | IOSQE_BUFFER_SELECTED
    6767                #endif
    6868        ;
     
    7474        ;
    7575
    76         extern [* volatile struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data );
    77         extern void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1)));
    78 
    79         static inline io_context * __get_io_context( void ) {
    80                 cluster * cltr = active_cluster();
    81 
    82                 /* paranoid */ verifyf( cltr, "No active cluster for io operation\\n");
    83                 assertf( cltr->io.cnt > 0, "Cluster %p has no default io contexts and no context was specified\\n", cltr );
    84 
    85                 /* paranoid */ verifyf( cltr->io.ctxs, "default io contexts for cluster %p are missing\\n", cltr);
    86                 return &cltr->io.ctxs[ thread_rand() % cltr->io.cnt ];
    87         }
     76        extern struct $io_context * cfa_io_allocate(struct io_uring_sqe * out_sqes[], __u32 out_idxs[], __u32 want)  __attribute__((nonnull (1,2)));
     77        extern void cfa_io_submit( struct $io_context * in_ctx, __u32 in_idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1,2)));
    8878#endif
    8979
     
    9888
    9989extern "C" {
    100         #include <sys/types.h>
     90        #include <asm/types.h>
    10191        #include <sys/socket.h>
    10292        #include <sys/syscall.h>
     
    142132        extern int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    143133
    144         extern ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);
     134        extern ssize_t splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags);
    145135        extern ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);
    146136}
     
    195185                return ', '.join(args_a)
    196186
    197 AsyncTemplate = """inline void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context) {{
     187AsyncTemplate = """inline void async_{name}(io_future_t & future, {params}, __u64 submit_flags) {{
    198188        #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_{op})
    199189                ssize_t res = {name}({args});
     
    205195                }}
    206196        #else
    207                 // we don't support LINK yet
    208                 if( 0 != (submit_flags & LINK_FLAGS) ) {{
    209                         errno = ENOTSUP; return -1;
    210                 }}
    211 
    212                 if( !context ) {{
    213                         context = __get_io_context();
    214                 }}
    215                 if(cancellation) {{
    216                         cancellation->target = (__u64)(uintptr_t)&future;
    217                 }}
    218 
    219197                __u8 sflags = REGULAR_FLAGS & submit_flags;
    220                 struct __io_data & ring = *context->thrd.ring;
    221 
    222198                __u32 idx;
    223199                struct io_uring_sqe * sqe;
    224                 [(volatile struct io_uring_sqe *) sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&future );
     200                struct $io_context * ctx = cfa_io_allocate( &sqe, &idx, 1 );
    225201
    226202                sqe->opcode = IORING_OP_{op};
     203                sqe->user_data = (uintptr_t)&future;
    227204                sqe->flags = sflags;
    228205                sqe->ioprio = 0;
     
    238215                asm volatile("": : :"memory");
    239216
    240                 verify( sqe->user_data == (__u64)(uintptr_t)&future );
    241                 __submit( context, idx );
     217                verify( sqe->user_data == (uintptr_t)&future );
     218                cfa_io_submit( ctx, &idx, 1, 0 != (submit_flags & CFA_IO_LAZY) );
    242219        #endif
    243220}}"""
    244221
    245 SyncTemplate = """{ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {{
    246         if( timeout >= 0 ) {{
    247                 errno = ENOTSUP;
    248                 return -1;
    249         }}
     222SyncTemplate = """{ret} cfa_{name}({params}, __u64 submit_flags) {{
    250223        io_future_t future;
    251224
    252         async_{name}( future, {args}, submit_flags, cancellation, context );
     225        async_{name}( future, {args}, submit_flags );
    253226
    254227        wait( future );
     
    265238                'fd'  : 'fd',
    266239                'off' : 'offset',
    267                 'addr': '(__u64)iov',
     240                'addr': '(uintptr_t)iov',
    268241                'len' : 'iovcnt',
    269242        }, define = 'CFA_HAVE_PREADV2'),
     
    272245                'fd'  : 'fd',
    273246                'off' : 'offset',
    274                 'addr': '(__u64)iov',
     247                'addr': '(uintptr_t)iov',
    275248                'len' : 'iovcnt'
    276249        }, define = 'CFA_HAVE_PWRITEV2'),
     
    284257                'addr': 'fd',
    285258                'len': 'op',
    286                 'off': '(__u64)event'
     259                'off': '(uintptr_t)event'
    287260        }),
    288261        # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE
     
    296269        Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)', {
    297270                'fd': 'sockfd',
    298                 'addr': '(__u64)(struct msghdr *)msg',
     271                'addr': '(uintptr_t)(struct msghdr *)msg',
    299272                'len': '1',
    300273                'msg_flags': 'flags'
     
    303276        Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)', {
    304277                'fd': 'sockfd',
    305                 'addr': '(__u64)(struct msghdr *)msg',
     278                'addr': '(uintptr_t)(struct msghdr *)msg',
    306279                'len': '1',
    307280                'msg_flags': 'flags'
     
    310283        Call('SEND', 'ssize_t send(int sockfd, const void *buf, size_t len, int flags)', {
    311284                'fd': 'sockfd',
    312                 'addr': '(__u64)buf',
     285                'addr': '(uintptr_t)buf',
    313286                'len': 'len',
    314287                'msg_flags': 'flags'
     
    317290        Call('RECV', 'ssize_t recv(int sockfd, void *buf, size_t len, int flags)', {
    318291                'fd': 'sockfd',
    319                 'addr': '(__u64)buf',
     292                'addr': '(uintptr_t)buf',
    320293                'len': 'len',
    321294                'msg_flags': 'flags'
     
    324297        Call('ACCEPT', 'int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)', {
    325298                'fd': 'sockfd',
    326                 'addr': '(__u64)addr',
    327                 'addr2': '(__u64)addrlen',
     299                'addr': '(uintptr_t)addr',
     300                'addr2': '(uintptr_t)addrlen',
    328301                'accept_flags': 'flags'
    329302        }),
     
    331304        Call('CONNECT', 'int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)', {
    332305                'fd': 'sockfd',
    333                 'addr': '(__u64)addr',
     306                'addr': '(uintptr_t)addr',
    334307                'off': 'addrlen'
    335308        }),
     
    337310        Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', {
    338311                'fd': 'fd',
    339                 'addr': '(__u64)len',
     312                'addr': '(uintptr_t)len',
    340313                'len': 'mode',
    341314                'off': 'offset'
     
    350323        # CFA_HAVE_IORING_OP_MADVISE
    351324        Call('MADVISE', 'int madvise(void *addr, size_t length, int advice)', {
    352                 'addr': '(__u64)addr',
     325                'addr': '(uintptr_t)addr',
    353326                'len': 'length',
    354327                'fadvise_advice': 'advice'
     
    357330        Call('OPENAT', 'int openat(int dirfd, const char *pathname, int flags, mode_t mode)', {
    358331                'fd': 'dirfd',
    359                 'addr': '(__u64)pathname',
     332                'addr': '(uintptr_t)pathname',
    360333                'len': 'mode',
    361334                'open_flags': 'flags;'
     
    366339                'addr': 'pathname',
    367340                'len': 'sizeof(*how)',
    368                 'off': '(__u64)how',
     341                'off': '(uintptr_t)how',
    369342        }, define = 'CFA_HAVE_OPENAT2'),
    370343        # CFA_HAVE_IORING_OP_CLOSE
     
    375348        Call('STATX', 'int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf)', {
    376349                'fd': 'dirfd',
    377                 'off': '(__u64)statxbuf',
     350                'off': '(uintptr_t)statxbuf',
    378351                'addr': 'pathname',
    379352                'len': 'mask',
     
    383356        Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', {
    384357                'fd': 'fd',
    385                 'addr': '(__u64)buf',
     358                'addr': '(uintptr_t)buf',
    386359                'len': 'count'
    387360        }),
     
    389362        Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', {
    390363                'fd': 'fd',
    391                 'addr': '(__u64)buf',
     364                'addr': '(uintptr_t)buf',
    392365                'len': 'count'
    393366        }),
    394367        # CFA_HAVE_IORING_OP_SPLICE
    395         Call('SPLICE', 'ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags)', {
     368        Call('SPLICE', 'ssize_t splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags)', {
    396369                'splice_fd_in': 'fd_in',
    397370                'splice_off_in': 'off_in ? (__u64)*off_in : (__u64)-1',
     
    415388        if c.define:
    416389                print("""#if defined({define})
    417         {ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     390        {ret} cfa_{name}({params}, __u64 submit_flags);
    418391#endif""".format(define=c.define,ret=c.ret, name=c.name, params=c.params))
    419392        else:
    420                 print("{ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);"
     393                print("{ret} cfa_{name}({params}, __u64 submit_flags);"
    421394                .format(ret=c.ret, name=c.name, params=c.params))
    422395
     
    426399        if c.define:
    427400                print("""#if defined({define})
    428         void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context);
     401        void async_{name}(io_future_t & future, {params}, __u64 submit_flags);
    429402#endif""".format(define=c.define,name=c.name, params=c.params))
    430403        else:
    431                 print("void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context);"
     404                print("void async_{name}(io_future_t & future, {params}, __u64 submit_flags);"
    432405                .format(name=c.name, params=c.params))
    433406print("\n")
     
    474447
    475448print("""
    476 //-----------------------------------------------------------------------------
    477 bool cancel(io_cancellation & this) {
    478         #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_ASYNC_CANCEL)
    479                 return false;
    480         #else
    481                 io_future_t future;
    482 
    483                 io_context * context = __get_io_context();
    484 
    485                 __u8 sflags = 0;
    486                 struct __io_data & ring = *context->thrd.ring;
    487 
    488                 __u32 idx;
    489                 volatile struct io_uring_sqe * sqe;
    490                 [sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&future );
    491 
    492                 sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
    493                 sqe->opcode = IORING_OP_ASYNC_CANCEL;
    494                 sqe->flags = sflags;
    495                 sqe->addr = this.target;
    496 
    497                 verify( sqe->user_data == (__u64)(uintptr_t)&future );
    498                 __submit( context, idx );
    499 
    500                 wait(future);
    501 
    502                 if( future.result == 0 ) return true; // Entry found
    503                 if( future.result == -EALREADY) return true; // Entry found but in progress
    504                 if( future.result == -ENOENT ) return false; // Entry not found
    505                 return false;
    506         #endif
    507 }
    508 
    509449//-----------------------------------------------------------------------------
    510450// Check if a function is has asynchronous
  • libcfa/src/concurrency/io/setup.cfa

    rfeacef9 r5407cdc  
    2626
    2727#if !defined(CFA_HAVE_LINUX_IO_URING_H)
    28         void __kernel_io_startup() {
    29                 // Nothing to do without io_uring
    30         }
    31 
    32         void __kernel_io_shutdown() {
    33                 // Nothing to do without io_uring
    34         }
    35 
    3628        void ?{}(io_context_params & this) {}
    3729
    38         void ?{}(io_context & this, struct cluster & cl) {}
    39         void ?{}(io_context & this, struct cluster & cl, const io_context_params & params) {}
    40 
    41         void ^?{}(io_context & this) {}
    42         void ^?{}(io_context & this, bool cluster_context) {}
    43 
    44         void register_fixed_files( io_context &, int *, unsigned ) {}
    45         void register_fixed_files( cluster    &, int *, unsigned ) {}
     30        void  ?{}($io_context & this, struct cluster & cl) {}
     31        void ^?{}($io_context & this) {}
     32
     33        void __cfa_io_start( processor * proc ) {}
     34        void __cfa_io_flush( processor * proc ) {}
     35        void __cfa_io_stop ( processor * proc ) {}
     36
     37        $io_arbiter * create(void) { return 0p; }
     38        void destroy($io_arbiter *) {}
    4639
    4740#else
     
    6861        void ?{}(io_context_params & this) {
    6962                this.num_entries = 256;
    70                 this.num_ready = 256;
    71                 this.submit_aff = -1;
    72                 this.eager_submits = false;
    73                 this.poller_submits = false;
    74                 this.poll_submit = false;
    75                 this.poll_complete = false;
    7663        }
    7764
     
    10693
    10794//=============================================================================================
    108 // I/O Startup / Shutdown logic + Master Poller
    109 //=============================================================================================
    110 
    111         // IO Master poller loop forward
    112         static void * iopoll_loop( __attribute__((unused)) void * args );
    113 
    114         static struct {
    115                       pthread_t  thrd;    // pthread handle to io poller thread
    116                       void *     stack;   // pthread stack for io poller thread
    117                       int        epollfd; // file descriptor to the epoll instance
    118                 volatile     bool run;     // Whether or not to continue
    119                 volatile     bool stopped; // Whether the poller has finished running
    120                 volatile uint64_t epoch;   // Epoch used for memory reclamation
    121         } iopoll;
    122 
    123         void __kernel_io_startup(void) {
    124                 __cfadbg_print_safe(io_core, "Kernel : Creating EPOLL instance\n" );
    125 
    126                 iopoll.epollfd = epoll_create1(0);
    127                 if (iopoll.epollfd == -1) {
    128                         abort( "internal error, epoll_create1\n");
    129                 }
    130 
    131                 __cfadbg_print_safe(io_core, "Kernel : Starting io poller thread\n" );
    132 
    133                 iopoll.stack   = __create_pthread( &iopoll.thrd, iopoll_loop, 0p );
    134                 iopoll.run     = true;
    135                 iopoll.stopped = false;
    136                 iopoll.epoch   = 0;
    137         }
    138 
    139         void __kernel_io_shutdown(void) {
    140                 // Notify the io poller thread of the shutdown
    141                 iopoll.run = false;
    142                 sigval val = { 1 };
    143                 pthread_sigqueue( iopoll.thrd, SIGUSR1, val );
    144 
    145                 // Wait for the io poller thread to finish
    146 
    147                 __destroy_pthread( iopoll.thrd, iopoll.stack, 0p );
    148 
    149                 int ret = close(iopoll.epollfd);
    150                 if (ret == -1) {
    151                         abort( "internal error, close epoll\n");
    152                 }
    153 
    154                 // Io polling is now fully stopped
    155 
    156                 __cfadbg_print_safe(io_core, "Kernel : IO poller stopped\n" );
    157         }
    158 
    159         static void * iopoll_loop( __attribute__((unused)) void * args ) {
    160                 __processor_id_t id;
    161                 id.full_proc = false;
    162                 id.id = doregister(&id);
    163                 __cfaabi_tls.this_proc_id = &id;
    164                 __cfadbg_print_safe(io_core, "Kernel : IO poller thread starting\n" );
    165 
    166                 // Block signals to control when they arrive
    167                 sigset_t mask;
    168                 sigfillset(&mask);
    169                 if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
    170                 abort( "internal error, pthread_sigmask" );
    171                 }
    172 
    173                 sigdelset( &mask, SIGUSR1 );
    174 
    175                 // Create sufficient events
    176                 struct epoll_event events[10];
    177                 // Main loop
    178                 while( iopoll.run ) {
    179                         __cfadbg_print_safe(io_core, "Kernel I/O - epoll : waiting on io_uring contexts\n");
    180 
    181                         // increment the epoch to notify any deleters we are starting a new cycle
    182                         __atomic_fetch_add(&iopoll.epoch, 1, __ATOMIC_SEQ_CST);
    183 
    184                         // Wait for events
    185                         int nfds = epoll_pwait( iopoll.epollfd, events, 10, -1, &mask );
    186 
    187                         __cfadbg_print_safe(io_core, "Kernel I/O - epoll : %d io contexts events, waking up\n", nfds);
    188 
    189                         // Check if an error occured
    190                         if (nfds == -1) {
    191                                 if( errno == EINTR ) continue;
    192                                 abort( "internal error, pthread_sigmask" );
    193                         }
    194 
    195                         for(i; nfds) {
    196                                 $io_ctx_thread * io_ctx = ($io_ctx_thread *)(uintptr_t)events[i].data.u64;
    197                                 /* paranoid */ verify( io_ctx );
    198                                 __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Unparking io poller %d (%p)\n", io_ctx->ring->fd, io_ctx);
    199                                 #if !defined( __CFA_NO_STATISTICS__ )
    200                                         __cfaabi_tls.this_stats = io_ctx->self.curr_cluster->stats;
    201                                 #endif
    202 
    203                                 eventfd_t v;
    204                                 eventfd_read(io_ctx->ring->efd, &v);
    205 
    206                                 post( io_ctx->sem );
    207                         }
    208                 }
    209 
    210                 __atomic_store_n(&iopoll.stopped, true, __ATOMIC_SEQ_CST);
    211 
    212                 __cfadbg_print_safe(io_core, "Kernel : IO poller thread stopping\n" );
    213                 unregister(&id);
    214                 return 0p;
    215         }
    216 
    217 //=============================================================================================
    21895// I/O Context Constrution/Destruction
    21996//=============================================================================================
    22097
    221         void ?{}($io_ctx_thread & this, struct cluster & cl) { (this.self){ "IO Poller", cl }; }
    222         void main( $io_ctx_thread & this );
    223         static inline $thread * get_thread( $io_ctx_thread & this ) { return &this.self; }
    224         void ^?{}( $io_ctx_thread & mutex this ) {}
    225 
    226         static void __io_create ( __io_data & this, const io_context_params & params_in );
    227         static void __io_destroy( __io_data & this );
    228 
    229         void ?{}(io_context & this, struct cluster & cl, const io_context_params & params) {
    230                 (this.thrd){ cl };
    231                 this.thrd.ring = malloc();
    232                 __cfadbg_print_safe(io_core, "Kernel I/O : Creating ring for io_context %p\n", &this);
    233                 __io_create( *this.thrd.ring, params );
    234 
    235                 __cfadbg_print_safe(io_core, "Kernel I/O : Starting poller thread for io_context %p\n", &this);
    236                 this.thrd.done = false;
    237                 __thrd_start( this.thrd, main );
    238 
    239                 __cfadbg_print_safe(io_core, "Kernel I/O : io_context %p ready\n", &this);
    240         }
    241 
    242         void ?{}(io_context & this, struct cluster & cl) {
    243                 io_context_params params;
    244                 (this){ cl, params };
    245         }
    246 
    247         void ^?{}(io_context & this, bool cluster_context) {
    248                 __cfadbg_print_safe(io_core, "Kernel I/O : tearing down io_context %p\n", &this);
    249 
    250                 // Notify the thread of the shutdown
    251                 __atomic_store_n(&this.thrd.done, true, __ATOMIC_SEQ_CST);
    252 
    253                 // If this is an io_context within a cluster, things get trickier
    254                 $thread & thrd = this.thrd.self;
    255                 if( cluster_context ) {
    256                         // We are about to do weird things with the threads
    257                         // we don't need interrupts to complicate everything
    258                         disable_interrupts();
    259 
    260                         // Get cluster info
    261                         cluster & cltr = *thrd.curr_cluster;
    262                         /* paranoid */ verify( cltr.idles.total == 0 || &cltr == mainCluster );
    263                         /* paranoid */ verify( !ready_mutate_islocked() );
    264 
    265                         // We need to adjust the clean-up based on where the thread is
    266                         if( thrd.state == Ready || thrd.preempted != __NO_PREEMPTION ) {
    267                                 // This is the tricky case
    268                                 // The thread was preempted or ready to run and now it is on the ready queue
    269                                 // but the cluster is shutting down, so there aren't any processors to run the ready queue
    270                                 // the solution is to steal the thread from the ready-queue and pretend it was blocked all along
    271 
    272                                 ready_schedule_lock();
    273                                         // The thread should on the list
    274                                         /* paranoid */ verify( thrd.link.next != 0p );
    275 
    276                                         // Remove the thread from the ready queue of this cluster
    277                                         // The thread should be the last on the list
    278                                         __attribute__((unused)) bool removed = remove_head( &cltr, &thrd );
    279                                         /* paranoid */ verify( removed );
    280                                         thrd.link.next = 0p;
    281                                         thrd.link.prev = 0p;
    282 
    283                                         // Fixup the thread state
    284                                         thrd.state = Blocked;
    285                                         thrd.ticket = TICKET_BLOCKED;
    286                                         thrd.preempted = __NO_PREEMPTION;
    287 
    288                                 ready_schedule_unlock();
    289 
    290                                 // Pretend like the thread was blocked all along
    291                         }
    292                         // !!! This is not an else if !!!
    293                         // Ok, now the thread is blocked (whether we cheated to get here or not)
    294                         if( thrd.state == Blocked ) {
    295                                 // This is the "easy case"
    296                                 // The thread is parked and can easily be moved to active cluster
    297                                 verify( thrd.curr_cluster != active_cluster() || thrd.curr_cluster == mainCluster );
    298                                 thrd.curr_cluster = active_cluster();
    299 
    300                                 // unpark the fast io_poller
    301                                 unpark( &thrd );
    302                         }
    303                         else {
    304                                 // The thread is in a weird state
    305                                 // I don't know what to do here
    306                                 abort("io_context poller thread is in unexpected state, cannot clean-up correctly\n");
    307                         }
    308 
    309                         // The weird thread kidnapping stuff is over, restore interrupts.
    310                         enable_interrupts( __cfaabi_dbg_ctx );
    311                 } else {
    312                         post( this.thrd.sem );
    313                 }
    314 
    315                 ^(this.thrd){};
    316                 __cfadbg_print_safe(io_core, "Kernel I/O : Stopped poller thread for io_context %p\n", &this);
    317 
    318                 __io_destroy( *this.thrd.ring );
    319                 __cfadbg_print_safe(io_core, "Kernel I/O : Destroyed ring for io_context %p\n", &this);
    320 
    321                 free(this.thrd.ring);
    322         }
    323 
    324         void ^?{}(io_context & this) {
    325                 ^(this){ false };
     98
     99
     100        static void __io_uring_setup ( $io_context & this, const io_context_params & params_in, int procfd );
     101        static void __io_uring_teardown( $io_context & this );
     102        static void __epoll_register($io_context & ctx);
     103        static void __epoll_unregister($io_context & ctx);
     104        void __ioarbiter_register( $io_arbiter & mutex, $io_context & ctx );
     105        void __ioarbiter_unregister( $io_arbiter & mutex, $io_context & ctx );
     106
     107        void ?{}($io_context & this, processor * proc, struct cluster & cl) {
     108                /* paranoid */ verify( cl.io.arbiter );
     109                this.proc = proc;
     110                this.arbiter = cl.io.arbiter;
     111                this.ext_sq.empty = true;
     112                (this.ext_sq.queue){};
     113                __io_uring_setup( this, cl.io.params, proc->idle );
     114                __cfadbg_print_safe(io_core, "Kernel I/O : Created ring for io_context %u (%p)\n", this.fd, &this);
     115        }
     116
     117        void ^?{}($io_context & this) {
     118                __cfadbg_print_safe(io_core, "Kernel I/O : tearing down io_context %u\n", this.fd);
     119
     120                __io_uring_teardown( this );
     121                __cfadbg_print_safe(io_core, "Kernel I/O : Destroyed ring for io_context %u\n", this.fd);
    326122        }
    327123
     
    329125        extern void __enable_interrupts_hard();
    330126
    331         static void __io_create( __io_data & this, const io_context_params & params_in ) {
     127        static void __io_uring_setup( $io_context & this, const io_context_params & params_in, int procfd ) {
    332128                // Step 1 : call to setup
    333129                struct io_uring_params params;
    334130                memset(&params, 0, sizeof(params));
    335                 if( params_in.poll_submit   ) params.flags |= IORING_SETUP_SQPOLL;
    336                 if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL;
     131                // if( params_in.poll_submit   ) params.flags |= IORING_SETUP_SQPOLL;
     132                // if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL;
    337133
    338134                __u32 nentries = params_in.num_entries != 0 ? params_in.num_entries : 256;
     
    340136                        abort("ERROR: I/O setup 'num_entries' must be a power of 2\n");
    341137                }
    342                 if( params_in.poller_submits && params_in.eager_submits ) {
    343                         abort("ERROR: I/O setup 'poller_submits' and 'eager_submits' cannot be used together\n");
    344                 }
    345138
    346139                int fd = syscall(__NR_io_uring_setup, nentries, &params );
     
    350143
    351144                // Step 2 : mmap result
    352                 memset( &this, 0, sizeof(struct __io_data) );
    353                 struct __submition_data  & sq = this.submit_q;
    354                 struct __completion_data & cq = this.completion_q;
     145                struct __sub_ring_t & sq = this.sq;
     146                struct __cmp_ring_t & cq = this.cq;
    355147
    356148                // calculate the right ring size
     
    401193                // Get the pointers from the kernel to fill the structure
    402194                // submit queue
    403                 sq.head    = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
    404                 sq.tail    = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
    405                 sq.mask    = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
    406                 sq.num     = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
    407                 sq.flags   = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
    408                 sq.dropped = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
    409                 sq.array   = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
    410                 sq.prev_head = *sq.head;
    411 
    412                 {
    413                         const __u32 num = *sq.num;
    414                         for( i; num ) {
    415                                 __sqe_clean( &sq.sqes[i] );
    416                         }
    417                 }
    418 
    419                 (sq.submit_lock){};
    420                 (sq.release_lock){};
    421 
    422                 if( params_in.poller_submits || params_in.eager_submits ) {
    423                         /* paranoid */ verify( is_pow2( params_in.num_ready ) || (params_in.num_ready < 8) );
    424                         sq.ready_cnt = max( params_in.num_ready, 8 );
    425                         sq.ready = alloc( sq.ready_cnt, 64`align );
    426                         for(i; sq.ready_cnt) {
    427                                 sq.ready[i] = -1ul32;
    428                         }
    429                         sq.prev_ready = 0;
    430                 }
    431                 else {
    432                         sq.ready_cnt = 0;
    433                         sq.ready = 0p;
    434                         sq.prev_ready = 0;
    435                 }
     195                sq.kring.head  = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
     196                sq.kring.tail  = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
     197                sq.kring.array = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
     198                sq.mask        = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
     199                sq.num         = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
     200                sq.flags       = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
     201                sq.dropped     = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
     202
     203                sq.kring.released = 0;
     204
     205                sq.free_ring.head = 0;
     206                sq.free_ring.tail = *sq.num;
     207                sq.free_ring.array = alloc( *sq.num, 128`align );
     208                for(i; (__u32)*sq.num) {
     209                        sq.free_ring.array[i] = i;
     210                }
     211
     212                sq.to_submit = 0;
    436213
    437214                // completion queue
     
    446223                // io_uring_register is so f*cking slow on some machine that it
    447224                // will never succeed if preemption isn't hard blocked
     225                __cfadbg_print_safe(io_core, "Kernel I/O : registering %d for completion with ring %d\n", procfd, fd);
     226
    448227                __disable_interrupts_hard();
    449228
    450                 int efd = eventfd(0, 0);
    451                 if (efd < 0) {
    452                         abort("KERNEL ERROR: IO_URING EVENTFD - %s\n", strerror(errno));
    453                 }
    454 
    455                 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &efd, 1);
     229                int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1);
    456230                if (ret < 0) {
    457231                        abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno));
     
    459233
    460234                __enable_interrupts_hard();
     235
     236                __cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd);
    461237
    462238                // some paranoid checks
     
    468244                /* paranoid */ verifyf( (*sq.mask) == ((*sq.num) - 1ul32), "IO_URING Expected mask to be %u (%u entries), was %u", (*sq.num) - 1ul32, *sq.num, *sq.mask );
    469245                /* paranoid */ verifyf( (*sq.num) >= nentries, "IO_URING Expected %u entries, got %u", nentries, *sq.num );
    470                 /* paranoid */ verifyf( (*sq.head) == 0, "IO_URING Expected head to be 0, got %u", *sq.head );
    471                 /* paranoid */ verifyf( (*sq.tail) == 0, "IO_URING Expected tail to be 0, got %u", *sq.tail );
     246                /* paranoid */ verifyf( (*sq.kring.head) == 0, "IO_URING Expected head to be 0, got %u", *sq.kring.head );
     247                /* paranoid */ verifyf( (*sq.kring.tail) == 0, "IO_URING Expected tail to be 0, got %u", *sq.kring.tail );
    472248
    473249                // Update the global ring info
    474                 this.ring_flags = params.flags;
     250                this.ring_flags = 0;
    475251                this.fd         = fd;
    476                 this.efd        = efd;
    477                 this.eager_submits  = params_in.eager_submits;
    478                 this.poller_submits = params_in.poller_submits;
    479         }
    480 
    481         static void __io_destroy( __io_data & this ) {
     252        }
     253
     254        static void __io_uring_teardown( $io_context & this ) {
    482255                // Shutdown the io rings
    483                 struct __submition_data  & sq = this.submit_q;
    484                 struct __completion_data & cq = this.completion_q;
     256                struct __sub_ring_t & sq = this.sq;
     257                struct __cmp_ring_t & cq = this.cq;
    485258
    486259                // unmap the submit queue entries
     
    497270                // close the file descriptor
    498271                close(this.fd);
    499                 close(this.efd);
    500 
    501                 free( this.submit_q.ready ); // Maybe null, doesn't matter
     272
     273                free( this.sq.free_ring.array ); // Maybe null, doesn't matter
     274        }
     275
     276        void __cfa_io_start( processor * proc ) {
     277                proc->io.ctx = alloc();
     278                (*proc->io.ctx){proc, *proc->cltr};
     279        }
     280        void __cfa_io_stop ( processor * proc ) {
     281                ^(*proc->io.ctx){};
     282                free(proc->io.ctx);
    502283        }
    503284
     
    505286// I/O Context Sleep
    506287//=============================================================================================
    507         static inline void __ioctx_epoll_ctl($io_ctx_thread & ctx, int op, const char * error) {
    508                 struct epoll_event ev;
    509                 ev.events = EPOLLIN | EPOLLONESHOT;
    510                 ev.data.u64 = (__u64)&ctx;
    511                 int ret = epoll_ctl(iopoll.epollfd, op, ctx.ring->efd, &ev);
    512                 if (ret < 0) {
    513                         abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) );
    514                 }
    515         }
    516 
    517         void __ioctx_register($io_ctx_thread & ctx) {
    518                 __ioctx_epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD");
    519         }
    520 
    521         void __ioctx_prepare_block($io_ctx_thread & ctx) {
    522                 __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.ring->fd, &ctx);
    523                 __ioctx_epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM");
    524         }
    525 
    526         void __ioctx_unregister($io_ctx_thread & ctx) {
    527                 // Read the current epoch so we know when to stop
    528                 size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST);
    529 
    530                 // Remove the fd from the iopoller
    531                 __ioctx_epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE");
    532 
    533                 // Notify the io poller thread of the shutdown
    534                 iopoll.run = false;
    535                 sigval val = { 1 };
    536                 pthread_sigqueue( iopoll.thrd, SIGUSR1, val );
    537 
    538                 // Make sure all this is done
    539                 __atomic_thread_fence(__ATOMIC_SEQ_CST);
    540 
    541                 // Wait for the next epoch
    542                 while(curr == iopoll.epoch && !iopoll.stopped) Pause();
    543         }
     288        // static inline void __epoll_ctl($io_context & ctx, int op, const char * error) {
     289        //      struct epoll_event ev;
     290        //      ev.events = EPOLLIN | EPOLLONESHOT;
     291        //      ev.data.u64 = (__u64)&ctx;
     292        //      int ret = epoll_ctl(iopoll.epollfd, op, ctx.efd, &ev);
     293        //      if (ret < 0) {
     294        //              abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) );
     295        //      }
     296        // }
     297
     298        // static void __epoll_register($io_context & ctx) {
     299        //      __epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD");
     300        // }
     301
     302        // static void __epoll_unregister($io_context & ctx) {
     303        //      // Read the current epoch so we know when to stop
     304        //      size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST);
     305
     306        //      // Remove the fd from the iopoller
     307        //      __epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE");
     308
     309        //      // Notify the io poller thread of the shutdown
     310        //      iopoll.run = false;
     311        //      sigval val = { 1 };
     312        //      pthread_sigqueue( iopoll.thrd, SIGUSR1, val );
     313
     314        //      // Make sure all this is done
     315        //      __atomic_thread_fence(__ATOMIC_SEQ_CST);
     316
     317        //      // Wait for the next epoch
     318        //      while(curr == iopoll.epoch && !iopoll.stopped) Pause();
     319        // }
     320
     321        // void __ioctx_prepare_block($io_context & ctx) {
     322        //      __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.fd, &ctx);
     323        //      __epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM");
     324        // }
     325
    544326
    545327//=============================================================================================
    546328// I/O Context Misc Setup
    547329//=============================================================================================
    548         void register_fixed_files( io_context & ctx, int * files, unsigned count ) {
    549                 int ret = syscall( __NR_io_uring_register, ctx.thrd.ring->fd, IORING_REGISTER_FILES, files, count );
    550                 if( ret < 0 ) {
    551                         abort( "KERNEL ERROR: IO_URING REGISTER - (%d) %s\n", (int)errno, strerror(errno) );
    552                 }
    553 
    554                 __cfadbg_print_safe( io_core, "Kernel I/O : Performed io_register for %p, returned %d\n", active_thread(), ret );
    555         }
    556 
    557         void register_fixed_files( cluster & cltr, int * files, unsigned count ) {
    558                 for(i; cltr.io.cnt) {
    559                         register_fixed_files( cltr.io.ctxs[i], files, count );
    560                 }
    561         }
     330        void ?{}( $io_arbiter & this ) {
     331                this.pending.empty = true;
     332        }
     333
     334        void ^?{}( $io_arbiter & this ) {}
     335
     336        $io_arbiter * create(void) {
     337                return new();
     338        }
     339        void destroy($io_arbiter * arbiter) {
     340                delete(arbiter);
     341        }
     342
     343//=============================================================================================
     344// I/O Context Misc Setup
     345//=============================================================================================
     346
    562347#endif
  • libcfa/src/concurrency/io/types.hfa

    rfeacef9 r5407cdc  
    2222
    2323#include "bits/locks.hfa"
     24#include "bits/queue.hfa"
    2425#include "kernel/fwd.hfa"
    2526
    2627#if defined(CFA_HAVE_LINUX_IO_URING_H)
    27         #define LEADER_LOCK
    28         struct __leaderlock_t {
    29                 struct $thread * volatile value;        // ($thread) next_leader | (bool:1) is_locked
    30         };
     28        #include "bits/sequence.hfa"
     29        #include "monitor.hfa"
    3130
    32         static inline void ?{}( __leaderlock_t & this ) { this.value = 0p; }
     31        struct processor;
     32        monitor $io_arbiter;
    3333
    3434        //-----------------------------------------------------------------------
    3535        // Ring Data structure
    36       struct __submition_data {
    37                 // Head and tail of the ring (associated with array)
    38                 volatile __u32 * head;
    39                 volatile __u32 * tail;
    40                 volatile __u32 prev_head;
     36      struct __sub_ring_t {
     37                struct {
     38                        // Head and tail of the ring (associated with array)
     39                        volatile __u32 * head;   // one passed last index consumed by the kernel
     40                        volatile __u32 * tail;   // one passed last index visible to the kernel
     41                        volatile __u32 released; // one passed last index released back to the free list
    4142
    42                 // The actual kernel ring which uses head/tail
    43                 // indexes into the sqes arrays
    44                 __u32 * array;
     43                        // The actual kernel ring which uses head/tail
     44                        // indexes into the sqes arrays
     45                        __u32 * array;
     46                } kring;
     47
     48                struct {
     49                        volatile __u32 head;
     50                        volatile __u32 tail;
     51                        // The ring which contains free allocations
     52                        // indexes into the sqes arrays
     53                        __u32 * array;
     54                } free_ring;
     55
     56                // number of sqes to submit on next system call.
     57                __u32 to_submit;
    4558
    4659                // number of entries and mask to go with it
     
    4861                const __u32 * mask;
    4962
    50                 // Submission flags (Not sure what for)
     63                // Submission flags, currently only IORING_SETUP_SQPOLL
    5164                __u32 * flags;
    5265
    53                 // number of sqes not submitted (whatever that means)
     66                // number of sqes not submitted
     67                // From documentation : [dropped] is incremented for each invalid submission queue entry encountered in the ring buffer.
    5468                __u32 * dropped;
    5569
    56                 // Like head/tail but not seen by the kernel
    57                 volatile __u32 * ready;
    58                 __u32 ready_cnt;
    59                 __u32 prev_ready;
    60 
    61                 #if defined(LEADER_LOCK)
    62                         __leaderlock_t submit_lock;
    63                 #else
    64                         __spinlock_t submit_lock;
    65                 #endif
    66                 __spinlock_t  release_lock;
    67 
    6870                // A buffer of sqes (not the actual ring)
    69                 volatile struct io_uring_sqe * sqes;
     71                struct io_uring_sqe * sqes;
    7072
    7173                // The location and size of the mmaped area
     
    7476        };
    7577
    76         struct __completion_data {
     78        struct __cmp_ring_t {
    7779                // Head and tail of the ring
    7880                volatile __u32 * head;
     
    8385                const __u32 * num;
    8486
    85                 // number of cqes not submitted (whatever that means)
     87                // I don't know what this value is for
    8688                __u32 * overflow;
    8789
     
    9496        };
    9597
    96         struct __io_data {
    97                 struct __submition_data submit_q;
    98                 struct __completion_data completion_q;
     98        struct __outstanding_io {
     99                inline Colable;
     100                single_sem sem;
     101        };
     102        static inline __outstanding_io *& Next( __outstanding_io * n ) { return (__outstanding_io *)Next( (Colable *)n ); }
     103
     104        struct __outstanding_io_queue {
     105                __spinlock_t lock;
     106                Queue(__outstanding_io) queue;
     107                volatile bool empty;
     108        };
     109
     110        struct __external_io {
     111                inline __outstanding_io;
     112                __u32 * idxs;
     113                __u32 have;
     114                bool lazy;
     115        };
     116
     117
     118        struct __attribute__((aligned(128))) $io_context {
     119                $io_arbiter * arbiter;
     120                processor * proc;
     121
     122                __outstanding_io_queue ext_sq;
     123
     124                struct __sub_ring_t sq;
     125                struct __cmp_ring_t cq;
    99126                __u32 ring_flags;
    100127                int fd;
    101                 int efd;
    102                 bool eager_submits:1;
    103                 bool poller_submits:1;
     128        };
     129
     130        struct __pending_alloc {
     131                inline __outstanding_io;
     132                __u32 * idxs;
     133                __u32 want;
     134                $io_context * ctx;
     135        };
     136
     137        struct __attribute__((aligned(128))) $io_arbiter {
     138                __outstanding_io_queue pending;
    104139        };
    105140
     
    133168        #endif
    134169
    135         struct $io_ctx_thread;
    136         void __ioctx_register($io_ctx_thread & ctx);
    137         void __ioctx_unregister($io_ctx_thread & ctx);
    138         void __ioctx_prepare_block($io_ctx_thread & ctx);
    139         void __sqe_clean( volatile struct io_uring_sqe * sqe );
     170        // void __ioctx_prepare_block($io_context & ctx);
    140171#endif
    141172
     
    148179
    149180static inline {
    150         bool fulfil( io_future_t & this, __s32 result ) {
     181        $thread * fulfil( io_future_t & this, __s32 result, bool do_unpark = true ) {
    151182                this.result = result;
    152                 return fulfil(this.self);
     183                return fulfil(this.self, do_unpark);
    153184        }
    154185
  • libcfa/src/concurrency/iofwd.hfa

    rfeacef9 r5407cdc  
    1818#include <unistd.h>
    1919extern "C" {
    20         #include <sys/types.h>
     20        #include <asm/types.h>
    2121        #if CFA_HAVE_LINUX_IO_URING_H
    2222                #include <linux/io_uring.h>
     
    4848struct cluster;
    4949struct io_future_t;
    50 struct io_context;
    51 struct io_cancellation;
     50struct $io_context;
    5251
    5352struct iovec;
     
    5554struct sockaddr;
    5655struct statx;
     56struct epoll_event;
     57
     58struct io_uring_sqe;
     59
     60//----------
     61// underlying calls
     62extern struct $io_context * cfa_io_allocate(struct io_uring_sqe * out_sqes[], __u32 out_idxs[], __u32 want)  __attribute__((nonnull (1,2)));
     63extern void cfa_io_submit( struct $io_context * in_ctx, __u32 in_idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1,2)));
    5764
    5865//----------
    5966// synchronous calls
    6067#if defined(CFA_HAVE_PREADV2)
    61         extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     68        extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
    6269#endif
    6370#if defined(CFA_HAVE_PWRITEV2)
    64         extern ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     71        extern ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
    6572#endif
    66 extern int cfa_fsync(int fd, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    67 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    68 extern int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    69 extern  ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    70 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    71 extern ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    72 extern ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    73 extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    74 extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    75 extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    76 extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    77 extern int cfa_madvise(void *addr, size_t length, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    78 extern int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     73extern int cfa_fsync(int fd, __u64 submit_flags);
     74extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags);
     75extern int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags);
     76extern  ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags);
     77extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags, __u64 submit_flags);
     78extern ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags);
     79extern ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags, __u64 submit_flags);
     80extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);
     81extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);
     82extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, __u64 submit_flags);
     83extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, __u64 submit_flags);
     84extern int cfa_madvise(void *addr, size_t length, int advice, __u64 submit_flags);
     85extern int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags);
    7986#if defined(CFA_HAVE_OPENAT2)
    80         extern int cfa_openat2(int dirfd, const char *pathname, struct open_how * how, size_t size, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     87        extern int cfa_openat2(int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags);
    8188#endif
    82 extern int cfa_close(int fd, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     89extern int cfa_close(int fd, __u64 submit_flags);
    8390#if defined(CFA_HAVE_STATX)
    84         extern int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     91        extern int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);
    8592#endif
    86 extern ssize_t cfa_read(int fd, void * buf, size_t count, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    87 extern ssize_t cfa_write(int fd, void * buf, size_t count, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    88 extern ssize_t cfa_splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    89 extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     93extern ssize_t cfa_read(int fd, void * buf, size_t count, __u64 submit_flags);
     94extern ssize_t cfa_write(int fd, void * buf, size_t count, __u64 submit_flags);
     95extern ssize_t cfa_splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags);
     96extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);
    9097
    9198//----------
    9299// asynchronous calls
    93100#if defined(CFA_HAVE_PREADV2)
    94         extern void async_preadv2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
     101        extern void async_preadv2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
    95102#endif
    96103#if defined(CFA_HAVE_PWRITEV2)
    97         extern void async_pwritev2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
     104        extern void async_pwritev2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
    98105#endif
    99 extern void async_fsync(io_future_t & future, int fd, int submit_flags, io_cancellation * cancellation, io_context * context);
    100 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event *event, int submit_flags, io_cancellation * cancellation, io_context * context);
    101 extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
    102 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr *msg, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
    103 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr *msg, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
    104 extern void async_send(io_future_t & future, int sockfd, const void *buf, size_t len, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
    105 extern void async_recv(io_future_t & future, int sockfd, void *buf, size_t len, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
    106 extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
    107 extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, int submit_flags, io_cancellation * cancellation, io_context * context);
    108 extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, int submit_flags, io_cancellation * cancellation, io_context * context);
    109 extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, int submit_flags, io_cancellation * cancellation, io_context * context);
    110 extern void async_madvise(io_future_t & future, void *addr, size_t length, int advice, int submit_flags, io_cancellation * cancellation, io_context * context);
    111 extern void async_openat(io_future_t & future, int dirfd, const char *pathname, int flags, mode_t mode, int submit_flags, io_cancellation * cancellation, io_context * context);
     106extern void async_fsync(io_future_t & future, int fd, __u64 submit_flags);
     107extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags);
     108extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags);
     109extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags);
     110extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr *msg, int flags, __u64 submit_flags);
     111extern void async_send(io_future_t & future, int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags);
     112extern void async_recv(io_future_t & future, int sockfd, void *buf, size_t len, int flags, __u64 submit_flags);
     113extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);
     114extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);
     115extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, __u64 submit_flags);
     116extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, __u64 submit_flags);
     117extern void async_madvise(io_future_t & future, void *addr, size_t length, int advice, __u64 submit_flags);
     118extern void async_openat(io_future_t & future, int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags);
    112119#if defined(CFA_HAVE_OPENAT2)
    113         extern void async_openat2(io_future_t & future, int dirfd, const char *pathname, struct open_how * how, size_t size, int submit_flags, io_cancellation * cancellation, io_context * context);
     120        extern void async_openat2(io_future_t & future, int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags);
    114121#endif
    115 extern void async_close(io_future_t & future, int fd, int submit_flags, io_cancellation * cancellation, io_context * context);
     122extern void async_close(io_future_t & future, int fd, __u64 submit_flags);
    116123#if defined(CFA_HAVE_STATX)
    117         extern void async_statx(io_future_t & future, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, int submit_flags, io_cancellation * cancellation, io_context * context);
     124        extern void async_statx(io_future_t & future, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);
    118125#endif
    119 void async_read(io_future_t & future, int fd, void * buf, size_t count, int submit_flags, io_cancellation * cancellation, io_context * context);
    120 extern void async_write(io_future_t & future, int fd, void * buf, size_t count, int submit_flags, io_cancellation * cancellation, io_context * context);
    121 extern void async_splice(io_future_t & future, int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
    122 extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
     126void async_read(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);
     127extern void async_write(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);
     128extern void async_splice(io_future_t & future, int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags);
     129extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);
    123130
    124131
     
    126133// Check if a function is blocks a only the user thread
    127134bool has_user_level_blocking( fptr_t func );
    128 
    129 //-----------------------------------------------------------------------------
    130 void register_fixed_files( io_context & ctx , int * files, unsigned count );
    131 void register_fixed_files( cluster    & cltr, int * files, unsigned count );
  • libcfa/src/concurrency/kernel.cfa

    rfeacef9 r5407cdc  
    2222#include <signal.h>
    2323#include <unistd.h>
     24extern "C" {
     25        #include <sys/eventfd.h>
     26}
    2427
    2528//CFA Includes
     
    3134#include "invoke.h"
    3235
     36#if !defined(__CFA_NO_STATISTICS__)
     37        #define __STATS( ...) __VA_ARGS__
     38#else
     39        #define __STATS( ...)
     40#endif
    3341
    3442//-----------------------------------------------------------------------------
     
    107115static $thread * __next_thread(cluster * this);
    108116static $thread * __next_thread_slow(cluster * this);
     117static inline bool __must_unpark( $thread * thrd ) __attribute((nonnull(1)));
    109118static void __run_thread(processor * this, $thread * dst);
    110119static void __wake_one(cluster * cltr);
    111120
    112 static void push  (__cluster_idles & idles, processor & proc);
    113 static void remove(__cluster_idles & idles, processor & proc);
    114 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles );
    115 
     121static void mark_idle (__cluster_proc_list & idles, processor & proc);
     122static void mark_awake(__cluster_proc_list & idles, processor & proc);
     123static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list idles );
     124
     125extern void __cfa_io_start( processor * );
     126extern bool __cfa_io_drain( processor * );
     127extern void __cfa_io_flush( processor * );
     128extern void __cfa_io_stop ( processor * );
     129static inline bool __maybe_io_drain( processor * );
     130
     131extern void __disable_interrupts_hard();
     132extern void __enable_interrupts_hard();
     133
     134static inline void __disable_interrupts_checked() {
     135        /* paranoid */ verify( __preemption_enabled() );
     136        disable_interrupts();
     137        /* paranoid */ verify( ! __preemption_enabled() );
     138}
     139
     140static inline void __enable_interrupts_checked( bool poll = true ) {
     141        /* paranoid */ verify( ! __preemption_enabled() );
     142        enable_interrupts( poll );
     143        /* paranoid */ verify( __preemption_enabled() );
     144}
    116145
    117146//=============================================================================================
     
    129158        verify(this);
    130159
     160        __cfa_io_start( this );
     161
    131162        __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this);
    132163        #if !defined(__CFA_NO_STATISTICS__)
     
    140171                preemption_scope scope = { this };
    141172
    142                 #if !defined(__CFA_NO_STATISTICS__)
    143                         unsigned long long last_tally = rdtscl();
    144                 #endif
    145 
     173                __STATS( unsigned long long last_tally = rdtscl(); )
     174
     175                // if we need to run some special setup, now is the time to do it.
     176                if(this->init.thrd) {
     177                        this->init.thrd->curr_cluster = this->cltr;
     178                        __run_thread(this, this->init.thrd);
     179                }
    146180
    147181                __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this);
     
    150184                MAIN_LOOP:
    151185                for() {
     186                        // Check if there is pending io
     187                        __maybe_io_drain( this );
     188
    152189                        // Try to get the next thread
    153190                        readyThread = __next_thread( this->cltr );
    154191
    155192                        if( !readyThread ) {
     193                                __cfa_io_flush( this );
    156194                                readyThread = __next_thread_slow( this->cltr );
    157195                        }
     
    167205
    168206                                // Push self to idle stack
    169                                 push(this->cltr->idles, * this);
     207                                mark_idle(this->cltr->procs, * this);
    170208
    171209                                // Confirm the ready-queue is empty
     
    173211                                if( readyThread ) {
    174212                                        // A thread was found, cancel the halt
    175                                         remove(this->cltr->idles, * this);
     213                                        mark_awake(this->cltr->procs, * this);
    176214
    177215                                        #if !defined(__CFA_NO_STATISTICS__)
     
    189227                                #endif
    190228
    191                                 wait( this->idle );
     229                                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
     230
     231                                __disable_interrupts_hard();
     232                                eventfd_t val;
     233                                eventfd_read( this->idle, &val );
     234                                __enable_interrupts_hard();
    192235
    193236                                #if !defined(__CFA_NO_STATISTICS__)
     
    198241
    199242                                // We were woken up, remove self from idle
    200                                 remove(this->cltr->idles, * this);
     243                                mark_awake(this->cltr->procs, * this);
    201244
    202245                                // DON'T just proceed, start looking again
     
    205248
    206249                        /* paranoid */ verify( readyThread );
     250
     251                        // Reset io dirty bit
     252                        this->io.dirty = false;
    207253
    208254                        // We found a thread run it
     
    219265                                }
    220266                        #endif
     267
     268                        if(this->io.pending && !this->io.dirty) {
     269                                __cfa_io_flush( this );
     270                        }
     271
     272                //      SEARCH: {
     273                //              /* paranoid */ verify( ! __preemption_enabled() );
     274                //              /* paranoid */ verify( kernelTLS().this_proc_id );
     275
     276                //              // First, lock the scheduler since we are searching for a thread
     277
     278                //              // Try to get the next thread
     279                //              ready_schedule_lock();
     280                //              readyThread = pop_fast( this->cltr );
     281                //              ready_schedule_unlock();
     282                //              if(readyThread) {  break SEARCH; }
     283
     284                //              // If we can't find a thread, might as well flush any outstanding I/O
     285                //              if(this->io.pending) { __cfa_io_flush( this ); }
     286
     287                //              // Spin a little on I/O, just in case
     288                //              for(25) {
     289                //                      __maybe_io_drain( this );
     290                //                      ready_schedule_lock();
     291                //                      readyThread = pop_fast( this->cltr );
     292                //                      ready_schedule_unlock();
     293                //                      if(readyThread) {  break SEARCH; }
     294                //              }
     295
     296                //              // no luck, try stealing a few times
     297                //              for(25) {
     298                //                      if( __maybe_io_drain( this ) ) {
     299                //                              ready_schedule_lock();
     300                //                              readyThread = pop_fast( this->cltr );
     301                //                      } else {
     302                //                              ready_schedule_lock();
     303                //                              readyThread = pop_slow( this->cltr );
     304                //                      }
     305                //                      ready_schedule_unlock();
     306                //                      if(readyThread) {  break SEARCH; }
     307                //              }
     308
     309                //              // still no luck, search for a thread
     310                //              ready_schedule_lock();
     311                //              readyThread = pop_search( this->cltr );
     312                //              ready_schedule_unlock();
     313                //              if(readyThread) { break SEARCH; }
     314
     315                //              // Don't block if we are done
     316                //              if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     317
     318                //              __STATS( __tls_stats()->ready.sleep.halts++; )
     319
     320                //              // Push self to idle stack
     321                //              mark_idle(this->cltr->procs, * this);
     322
     323                //              // Confirm the ready-queue is empty
     324                //              __maybe_io_drain( this );
     325                //              ready_schedule_lock();
     326                //              readyThread = pop_search( this->cltr );
     327                //              ready_schedule_unlock();
     328
     329                //              if( readyThread ) {
     330                //                      // A thread was found, cancel the halt
     331                //                      mark_awake(this->cltr->procs, * this);
     332
     333                //                      __STATS( __tls_stats()->ready.sleep.cancels++; )
     334
     335                //                      // continue the main loop
     336                //                      break SEARCH;
     337                //              }
     338
     339                //              __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); )
     340                //              __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
     341
     342                //              // __disable_interrupts_hard();
     343                //              eventfd_t val;
     344                //              eventfd_read( this->idle, &val );
     345                //              // __enable_interrupts_hard();
     346
     347                //              __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); )
     348
     349                //              // We were woken up, remove self from idle
     350                //              mark_awake(this->cltr->procs, * this);
     351
     352                //              // DON'T just proceed, start looking again
     353                //              continue MAIN_LOOP;
     354                //      }
     355
     356                // RUN_THREAD:
     357                //      /* paranoid */ verify( kernelTLS().this_proc_id );
     358                //      /* paranoid */ verify( ! __preemption_enabled() );
     359                //      /* paranoid */ verify( readyThread );
     360
     361                //      // Reset io dirty bit
     362                //      this->io.dirty = false;
     363
     364                //      // We found a thread run it
     365                //      __run_thread(this, readyThread);
     366
     367                //      // Are we done?
     368                //      if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     369
     370                //      #if !defined(__CFA_NO_STATISTICS__)
     371                //              unsigned long long curr = rdtscl();
     372                //              if(curr > (last_tally + 500000000)) {
     373                //                      __tally_stats(this->cltr->stats, __cfaabi_tls.this_stats);
     374                //                      last_tally = curr;
     375                //              }
     376                //      #endif
     377
     378                //      if(this->io.pending && !this->io.dirty) {
     379                //              __cfa_io_flush( this );
     380                //      }
     381
     382                //      // Check if there is pending io
     383                //      __maybe_io_drain( this );
    221384                }
    222385
     
    224387        }
    225388
     389        __cfa_io_stop( this );
     390
    226391        post( this->terminated );
     392
    227393
    228394        if(this == mainProcessor) {
     
    247413        /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next );
    248414        __builtin_prefetch( thrd_dst->context.SP );
     415
     416        __cfadbg_print_safe(runtime_core, "Kernel : core %p running thread %p (%s)\n", this, thrd_dst, thrd_dst->self_cor.name);
    249417
    250418        $coroutine * proc_cor = get_coroutine(this->runner);
     
    297465                if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) {
    298466                        // The thread was preempted, reschedule it and reset the flag
    299                         __schedule_thread( thrd_dst );
     467                        schedule_thread$( thrd_dst );
    300468                        break RUNNING;
    301469                }
     
    318486                                break RUNNING;
    319487                        case TICKET_UNBLOCK:
     488                                #if !defined(__CFA_NO_STATISTICS__)
     489                                        __tls_stats()->ready.threads.threads++;
     490                                        __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );
     491                                #endif
    320492                                // This is case 2, the racy case, someone tried to run this thread before it finished blocking
    321493                                // In this case, just run it again.
     
    330502        proc_cor->state = Active;
    331503
     504        __cfadbg_print_safe(runtime_core, "Kernel : core %p finished running thread %p\n", this, thrd_dst);
     505
     506        #if !defined(__CFA_NO_STATISTICS__)
     507                __tls_stats()->ready.threads.threads--;
     508                __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );
     509        #endif
     510
    332511        /* paranoid */ verify( ! __preemption_enabled() );
    333512}
     
    339518        $thread * thrd_src = kernelTLS().this_thread;
    340519
    341         #if !defined(__CFA_NO_STATISTICS__)
    342                 struct processor * last_proc = kernelTLS().this_processor;
    343         #endif
     520        __STATS( thrd_src->last_proc = kernelTLS().this_processor; )
    344521
    345522        // Run the thread on this processor
     
    360537
    361538        #if !defined(__CFA_NO_STATISTICS__)
    362                 if(last_proc != kernelTLS().this_processor) {
     539                /* paranoid */ verify( thrd_src->last_proc != 0p );
     540                if(thrd_src->last_proc != kernelTLS().this_processor) {
    363541                        __tls_stats()->ready.threads.migration++;
    364542                }
     
    373551// Scheduler routines
    374552// KERNEL ONLY
    375 void __schedule_thread( $thread * thrd ) {
     553static void __schedule_thread( $thread * thrd ) {
    376554        /* paranoid */ verify( ! __preemption_enabled() );
    377555        /* paranoid */ verify( kernelTLS().this_proc_id );
     556        /* paranoid */ verify( ready_schedule_islocked());
    378557        /* paranoid */ verify( thrd );
    379558        /* paranoid */ verify( thrd->state != Halted );
     
    391570        if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready;
    392571
     572        // Dereference the thread now because once we push it, there is not guaranteed it's still valid.
     573        struct cluster * cl = thrd->curr_cluster;
     574        __STATS(bool outside = thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
     575
     576        // push the thread to the cluster ready-queue
     577        push( cl, thrd );
     578
     579        // variable thrd is no longer safe to use
     580        thrd = 0xdeaddeaddeaddeadp;
     581
     582        // wake the cluster using the save variable.
     583        __wake_one( cl );
     584
     585        #if !defined(__CFA_NO_STATISTICS__)
     586                if( kernelTLS().this_stats ) {
     587                        __tls_stats()->ready.threads.threads++;
     588                        if(outside) {
     589                                __tls_stats()->ready.threads.extunpark++;
     590                        }
     591                        __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", kernelTLS().this_processor );
     592                }
     593                else {
     594                        __atomic_fetch_add(&cl->stats->ready.threads.threads, 1, __ATOMIC_RELAXED);
     595                        __atomic_fetch_add(&cl->stats->ready.threads.extunpark, 1, __ATOMIC_RELAXED);
     596                        __push_stat( cl->stats, cl->stats->ready.threads.threads, true, "Cluster", cl );
     597                }
     598        #endif
     599
     600        /* paranoid */ verify( ready_schedule_islocked());
     601        /* paranoid */ verify( ! __preemption_enabled() );
     602}
     603
     604void schedule_thread$( $thread * thrd ) {
    393605        ready_schedule_lock();
    394                 // Dereference the thread now because once we push it, there is not guaranteed it's still valid.
    395                 struct cluster * cl = thrd->curr_cluster;
    396 
    397                 // push the thread to the cluster ready-queue
    398                 push( cl, thrd );
    399 
    400                 // variable thrd is no longer safe to use
    401 
    402                 // wake the cluster using the save variable.
    403                 __wake_one( cl );
     606                __schedule_thread( thrd );
    404607        ready_schedule_unlock();
    405 
    406         /* paranoid */ verify( ! __preemption_enabled() );
    407608}
    408609
     
    413614
    414615        ready_schedule_lock();
    415                 $thread * thrd = pop( this );
     616                $thread * thrd = pop_fast( this );
    416617        ready_schedule_unlock();
    417618
     
    427628
    428629        ready_schedule_lock();
    429                 $thread * thrd = pop_slow( this );
     630                $thread * thrd;
     631                for(25) {
     632                        thrd = pop_slow( this );
     633                        if(thrd) goto RET;
     634                }
     635                thrd = pop_search( this );
     636
     637                RET:
    430638        ready_schedule_unlock();
    431639
     
    435643}
    436644
    437 void unpark( $thread * thrd ) {
    438         if( !thrd ) return;
    439 
     645static inline bool __must_unpark( $thread * thrd ) {
    440646        int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST);
    441647        switch(old_ticket) {
    442648                case TICKET_RUNNING:
    443649                        // Wake won the race, the thread will reschedule/rerun itself
    444                         break;
     650                        return false;
    445651                case TICKET_BLOCKED:
    446652                        /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION );
    447653                        /* paranoid */ verify( thrd->state == Blocked );
    448 
    449                         {
    450                                 /* paranoid */ verify( publicTLS_get(this_proc_id) );
    451                                 bool full = publicTLS_get(this_proc_id)->full_proc;
    452                                 if(full) disable_interrupts();
    453 
    454                                 /* paranoid */ verify( ! __preemption_enabled() );
    455 
    456                                 // Wake lost the race,
    457                                 __schedule_thread( thrd );
    458 
    459                                 /* paranoid */ verify( ! __preemption_enabled() );
    460 
    461                                 if(full) enable_interrupts( __cfaabi_dbg_ctx );
    462                                 /* paranoid */ verify( publicTLS_get(this_proc_id) );
    463                         }
    464 
    465                         break;
     654                        return true;
    466655                default:
    467656                        // This makes no sense, something is wrong abort
     
    470659}
    471660
     661void __kernel_unpark( $thread * thrd ) {
     662        /* paranoid */ verify( ! __preemption_enabled() );
     663        /* paranoid */ verify( ready_schedule_islocked());
     664
     665        if( !thrd ) return;
     666
     667        if(__must_unpark(thrd)) {
     668                // Wake lost the race,
     669                __schedule_thread( thrd );
     670        }
     671
     672        /* paranoid */ verify( ready_schedule_islocked());
     673        /* paranoid */ verify( ! __preemption_enabled() );
     674}
     675
     676void unpark( $thread * thrd ) {
     677        if( !thrd ) return;
     678
     679        if(__must_unpark(thrd)) {
     680                disable_interrupts();
     681                        // Wake lost the race,
     682                        schedule_thread$( thrd );
     683                enable_interrupts(false);
     684        }
     685}
     686
    472687void park( void ) {
    473         /* paranoid */ verify( __preemption_enabled() );
    474         disable_interrupts();
    475         /* paranoid */ verify( ! __preemption_enabled() );
    476         /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION );
    477 
    478         returnToKernel();
    479 
    480         /* paranoid */ verify( ! __preemption_enabled() );
    481         enable_interrupts( __cfaabi_dbg_ctx );
    482         /* paranoid */ verify( __preemption_enabled() );
     688        __disable_interrupts_checked();
     689                /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION );
     690                returnToKernel();
     691        __enable_interrupts_checked();
    483692
    484693}
     
    520729// KERNEL ONLY
    521730bool force_yield( __Preemption_Reason reason ) {
    522         /* paranoid */ verify( __preemption_enabled() );
    523         disable_interrupts();
    524         /* paranoid */ verify( ! __preemption_enabled() );
    525 
    526         $thread * thrd = kernelTLS().this_thread;
    527         /* paranoid */ verify(thrd->state == Active);
    528 
    529         // SKULLDUGGERY: It is possible that we are preempting this thread just before
    530         // it was going to park itself. If that is the case and it is already using the
    531         // intrusive fields then we can't use them to preempt the thread
    532         // If that is the case, abandon the preemption.
    533         bool preempted = false;
    534         if(thrd->link.next == 0p) {
    535                 preempted = true;
    536                 thrd->preempted = reason;
    537                 returnToKernel();
    538         }
    539 
    540         /* paranoid */ verify( ! __preemption_enabled() );
    541         enable_interrupts_noPoll();
    542         /* paranoid */ verify( __preemption_enabled() );
    543 
     731        __disable_interrupts_checked();
     732                $thread * thrd = kernelTLS().this_thread;
     733                /* paranoid */ verify(thrd->state == Active);
     734
     735                // SKULLDUGGERY: It is possible that we are preempting this thread just before
     736                // it was going to park itself. If that is the case and it is already using the
     737                // intrusive fields then we can't use them to preempt the thread
     738                // If that is the case, abandon the preemption.
     739                bool preempted = false;
     740                if(thrd->link.next == 0p) {
     741                        preempted = true;
     742                        thrd->preempted = reason;
     743                        returnToKernel();
     744                }
     745        __enable_interrupts_checked( false );
    544746        return preempted;
    545747}
     
    557759        unsigned idle;
    558760        unsigned total;
    559         [idle, total, p] = query(this->idles);
     761        [idle, total, p] = query_idles(this->procs);
    560762
    561763        // If no one is sleeping, we are done
     
    563765
    564766        // We found a processor, wake it up
    565         post( p->idle );
     767        eventfd_t val;
     768        val = 1;
     769        eventfd_write( p->idle, val );
    566770
    567771        #if !defined(__CFA_NO_STATISTICS__)
    568                 __tls_stats()->ready.sleep.wakes++;
     772                if( kernelTLS().this_stats ) {
     773                        __tls_stats()->ready.sleep.wakes++;
     774                }
     775                else {
     776                        __atomic_fetch_add(&this->stats->ready.sleep.wakes, 1, __ATOMIC_RELAXED);
     777                }
    569778        #endif
    570779
     
    579788        __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
    580789
    581         disable_interrupts();
     790        __disable_interrupts_checked();
    582791                /* paranoid */ verify( ! __preemption_enabled() );
    583                 post( this->idle );
    584         enable_interrupts( __cfaabi_dbg_ctx );
    585 }
    586 
    587 static void push  (__cluster_idles & this, processor & proc) {
     792                eventfd_t val;
     793                val = 1;
     794                eventfd_write( this->idle, val );
     795        __enable_interrupts_checked();
     796}
     797
     798static void mark_idle(__cluster_proc_list & this, processor & proc) {
    588799        /* paranoid */ verify( ! __preemption_enabled() );
    589800        lock( this );
    590801                this.idle++;
    591802                /* paranoid */ verify( this.idle <= this.total );
    592 
    593                 insert_first(this.list, proc);
     803                remove(proc);
     804                insert_first(this.idles, proc);
    594805        unlock( this );
    595806        /* paranoid */ verify( ! __preemption_enabled() );
    596807}
    597808
    598 static void remove(__cluster_idles & this, processor & proc) {
     809static void mark_awake(__cluster_proc_list & this, processor & proc) {
    599810        /* paranoid */ verify( ! __preemption_enabled() );
    600811        lock( this );
    601812                this.idle--;
    602813                /* paranoid */ verify( this.idle >= 0 );
    603 
    604814                remove(proc);
     815                insert_last(this.actives, proc);
    605816        unlock( this );
    606817        /* paranoid */ verify( ! __preemption_enabled() );
    607818}
    608819
    609 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) {
     820static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list this ) {
     821        /* paranoid */ verify( ! __preemption_enabled() );
     822        /* paranoid */ verify( ready_schedule_islocked() );
     823
    610824        for() {
    611825                uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
     
    613827                unsigned idle    = this.idle;
    614828                unsigned total   = this.total;
    615                 processor * proc = &this.list`first;
     829                processor * proc = &this.idles`first;
    616830                // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it
    617831                asm volatile("": : :"memory");
     
    619833                return [idle, total, proc];
    620834        }
     835
     836        /* paranoid */ verify( ready_schedule_islocked() );
     837        /* paranoid */ verify( ! __preemption_enabled() );
    621838}
    622839
     
    664881// Kernel Utilities
    665882//=============================================================================================
     883#if defined(CFA_HAVE_LINUX_IO_URING_H)
     884#include "io/types.hfa"
     885#endif
     886
     887static inline bool __maybe_io_drain( processor * proc ) {
     888        bool ret = false;
     889        #if defined(CFA_HAVE_LINUX_IO_URING_H)
     890                __cfadbg_print_safe(runtime_core, "Kernel : core %p checking io for ring %d\n", proc, proc->io.ctx->fd);
     891
     892                // Check if we should drain the queue
     893                $io_context * ctx = proc->io.ctx;
     894                unsigned head = *ctx->cq.head;
     895                unsigned tail = *ctx->cq.tail;
     896                if(head == tail) return false;
     897                ready_schedule_lock();
     898                ret = __cfa_io_drain( proc );
     899                ready_schedule_unlock();
     900        #endif
     901        return ret;
     902}
     903
    666904//-----------------------------------------------------------------------------
    667905// Debug
     
    691929                __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this );
    692930        }
    693 
    694         extern int __print_alarm_stats;
    695         void print_alarm_stats() {
    696                 __print_alarm_stats = -1;
    697         }
    698931#endif
    699932// Local Variables: //
  • libcfa/src/concurrency/kernel.hfa

    rfeacef9 r5407cdc  
    2828}
    2929
    30 //-----------------------------------------------------------------------------
    31 // Underlying Locks
    3230#ifdef __CFA_WITH_VERIFY__
    3331        extern bool __cfaabi_dbg_in_kernel();
    3432#endif
    3533
    36 extern "C" {
    37         char * strerror(int);
    38 }
    39 #define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); }
    40 
    41 struct __bin_sem_t {
    42         pthread_mutex_t         lock;
    43         pthread_cond_t          cond;
    44         int                     val;
    45 };
    46 
    47 static inline void ?{}(__bin_sem_t & this) with( this ) {
    48         // Create the mutex with error checking
    49         pthread_mutexattr_t mattr;
    50         pthread_mutexattr_init( &mattr );
    51         pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP);
    52         pthread_mutex_init(&lock, &mattr);
    53 
    54         pthread_cond_init (&cond, (const pthread_condattr_t *)0p);  // workaround trac#208: cast should not be required
    55         val = 0;
    56 }
    57 
    58 static inline void ^?{}(__bin_sem_t & this) with( this ) {
    59         CHECKED( pthread_mutex_destroy(&lock) );
    60         CHECKED( pthread_cond_destroy (&cond) );
    61 }
    62 
    63 static inline void wait(__bin_sem_t & this) with( this ) {
    64         verify(__cfaabi_dbg_in_kernel());
    65         CHECKED( pthread_mutex_lock(&lock) );
    66                 while(val < 1) {
    67                         pthread_cond_wait(&cond, &lock);
    68                 }
    69                 val -= 1;
    70         CHECKED( pthread_mutex_unlock(&lock) );
    71 }
    72 
    73 static inline bool post(__bin_sem_t & this) with( this ) {
    74         bool needs_signal = false;
    75 
    76         CHECKED( pthread_mutex_lock(&lock) );
    77                 if(val < 1) {
    78                         val += 1;
    79                         pthread_cond_signal(&cond);
    80                         needs_signal = true;
    81                 }
    82         CHECKED( pthread_mutex_unlock(&lock) );
    83 
    84         return needs_signal;
    85 }
    86 
    87 #undef CHECKED
    88 
     34//-----------------------------------------------------------------------------
     35// I/O
     36struct cluster;
     37struct $io_context;
     38struct $io_arbiter;
     39
     40struct io_context_params {
     41        int num_entries;
     42};
     43
     44void  ?{}(io_context_params & this);
    8945
    9046//-----------------------------------------------------------------------------
     
    9551struct __processor_id_t {
    9652        unsigned id:24;
    97         bool full_proc:1;
    9853
    9954        #if !defined(__CFA_NO_STATISTICS__)
     
    11469        struct cluster * cltr;
    11570
     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;
     79
    11680        // Set to true to notify the processor should terminate
    11781        volatile bool do_terminate;
     
    12589        // Handle to pthreads
    12690        pthread_t kernel_thread;
     91
     92        struct {
     93                $io_context * ctx;
     94                bool pending;
     95                bool dirty;
     96        } io;
    12797
    12898        // Preemption data
     
    134104
    135105        // Idle lock (kernel semaphore)
    136         __bin_sem_t idle;
     106        int idle;
    137107
    138108        // Termination synchronisation (user semaphore)
     
    144114        // Link lists fields
    145115        DLISTED_MGD_IMPL_IN(processor)
     116
     117        // special init fields
     118        // This is needed for memcached integration
     119        // once memcached experiments are done this should probably be removed
     120        // it is not a particularly safe scheme as it can make processors less homogeneous
     121        struct {
     122                $thread * thrd;
     123        } init;
    146124
    147125        #if !defined(__CFA_NO_STATISTICS__)
     
    159137void ^?{}(processor & this);
    160138
    161 static inline void  ?{}(processor & this)                    { this{ "Anonymous Processor", *mainCluster}; }
    162 static inline void  ?{}(processor & this, struct cluster & cltr)    { this{ "Anonymous Processor", cltr}; }
    163 static inline void  ?{}(processor & this, const char name[]) { this{name, *mainCluster }; }
     139static inline void  ?{}(processor & this)                        { this{ "Anonymous Processor", *mainCluster}; }
     140static inline void  ?{}(processor & this, struct cluster & cltr) { this{ "Anonymous Processor", cltr}; }
     141static inline void  ?{}(processor & this, const char name[])     { this{name, *mainCluster}; }
    164142
    165143DLISTED_MGD_IMPL_OUT(processor)
    166144
    167145//-----------------------------------------------------------------------------
    168 // I/O
    169 struct __io_data;
    170 
    171 // IO poller user-thread
    172 // Not using the "thread" keyword because we want to control
    173 // more carefully when to start/stop it
    174 struct $io_ctx_thread {
    175         struct __io_data * ring;
    176         single_sem sem;
    177         volatile bool done;
    178         $thread self;
    179 };
    180 
    181 
    182 struct io_context {
    183         $io_ctx_thread thrd;
    184 };
    185 
    186 struct io_context_params {
    187         int num_entries;
    188         int num_ready;
    189         int submit_aff;
    190         bool eager_submits:1;
    191         bool poller_submits:1;
    192         bool poll_submit:1;
    193         bool poll_complete:1;
    194 };
    195 
    196 void  ?{}(io_context_params & this);
    197 
    198 void  ?{}(io_context & this, struct cluster & cl);
    199 void  ?{}(io_context & this, struct cluster & cl, const io_context_params & params);
    200 void ^?{}(io_context & this);
    201 
    202 struct io_cancellation {
    203         __u64 target;
    204 };
    205 
    206 static inline void  ?{}(io_cancellation & this) { this.target = -1u; }
    207 static inline void ^?{}(io_cancellation &) {}
    208 bool cancel(io_cancellation & this);
    209 
    210 //-----------------------------------------------------------------------------
    211146// Cluster Tools
    212147
    213 // Intrusives lanes which are used by the relaxed ready queue
     148// Intrusives lanes which are used by the ready queue
    214149struct __attribute__((aligned(128))) __intrusive_lane_t;
    215150void  ?{}(__intrusive_lane_t & this);
    216151void ^?{}(__intrusive_lane_t & this);
    217152
    218 // Counter used for wether or not the lanes are all empty
    219 struct __attribute__((aligned(128))) __snzi_node_t;
    220 struct __snzi_t {
    221         unsigned mask;
    222         int root;
    223         __snzi_node_t * nodes;
    224 };
    225 
    226 void  ?{}( __snzi_t & this, unsigned depth );
    227 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);
    228157
    229158//TODO adjust cache size to ARCHITECTURE
    230159// Structure holding the relaxed ready queue
    231160struct __ready_queue_t {
    232         // Data tracking how many/which lanes are used
    233         // Aligned to 128 for cache locality
    234         __snzi_t snzi;
    235 
    236161        // Data tracking the actual lanes
    237162        // On a seperate cacheline from the used struct since
     
    242167                __intrusive_lane_t * volatile data;
    243168
     169                // Array of times
     170                __timestamp_t * volatile tscs;
     171
    244172                // Number of lanes (empty or not)
    245173                volatile size_t count;
     
    251179
    252180// Idle Sleep
    253 struct __cluster_idles {
     181struct __cluster_proc_list {
    254182        // Spin lock protecting the queue
    255183        volatile uint64_t lock;
     
    262190
    263191        // List of idle processors
    264         dlist(processor, processor) list;
     192        dlist(processor, processor) idles;
     193
     194        // List of active processors
     195        dlist(processor, processor) actives;
    265196};
    266197
     
    278209
    279210        // List of idle processors
    280         __cluster_idles idles;
     211        __cluster_proc_list procs;
    281212
    282213        // List of threads
     
    292223
    293224        struct {
    294                 io_context * ctxs;
    295                 unsigned cnt;
     225                $io_arbiter * arbiter;
     226                io_context_params params;
    296227        } io;
    297228
  • libcfa/src/concurrency/kernel/fwd.hfa

    rfeacef9 r5407cdc  
    108108
    109109        extern void disable_interrupts();
    110         extern void enable_interrupts_noPoll();
    111         extern void enable_interrupts( __cfaabi_dbg_ctx_param );
     110        extern void enable_interrupts( bool poll = false );
    112111
    113112        extern "Cforall" {
     
    220219                        // Mark as fulfilled, wake thread if needed
    221220                        // return true if a thread was unparked
    222                         bool post(oneshot & this) {
     221                        $thread * post(oneshot & this, bool do_unpark = true) {
    223222                                struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
    224                                 if( got == 0p ) return false;
    225                                 unpark( got );
    226                                 return true;
     223                                if( got == 0p ) return 0p;
     224                                if(do_unpark) unpark( got );
     225                                return got;
    227226                        }
    228227                }
     
    336335                        // from the server side, mark the future as fulfilled
    337336                        // delete it if needed
    338                         bool fulfil( future_t & this ) {
     337                        $thread * fulfil( future_t & this, bool do_unpark = true ) {
    339338                                for() {
    340339                                        struct oneshot * expected = this.ptr;
     
    344343                                                #pragma GCC diagnostic ignored "-Wfree-nonheap-object"
    345344                                        #endif
    346                                                 if( expected == 3p ) { free( &this ); return false; }
     345                                                if( expected == 3p ) { free( &this ); return 0p; }
    347346                                        #if defined(__GNUC__) && __GNUC__ >= 7
    348347                                                #pragma GCC diagnostic pop
     
    356355                                        struct oneshot * want = expected == 0p ? 1p : 2p;
    357356                                        if(__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    358                                                 if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return false; }
    359                                                 bool ret = post( *expected );
     357                                                if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return 0p; }
     358                                                $thread * ret = post( *expected, do_unpark );
    360359                                                __atomic_store_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
    361360                                                return ret;
     
    403402                                        __VA_ARGS__ \
    404403                                } \
    405                                 if( !(in_kernel) ) enable_interrupts( __cfaabi_dbg_ctx ); \
     404                                if( !(in_kernel) ) enable_interrupts(); \
    406405                        }
    407406                #else
  • libcfa/src/concurrency/kernel/startup.cfa

    rfeacef9 r5407cdc  
    2222extern "C" {
    2323      #include <limits.h>       // PTHREAD_STACK_MIN
     24        #include <sys/eventfd.h>  // eventfd
    2425      #include <sys/mman.h>     // mprotect
    2526      #include <sys/resource.h> // getrlimit
     
    7273static void __kernel_first_resume( processor * this );
    7374static void __kernel_last_resume ( processor * this );
    74 static void init(processor & this, const char name[], cluster & _cltr);
     75static void init(processor & this, const char name[], cluster & _cltr, $thread * initT);
    7576static void deinit(processor & this);
    7677static void doregister( struct cluster & cltr );
     
    8990extern void __kernel_alarm_startup(void);
    9091extern void __kernel_alarm_shutdown(void);
    91 extern void __kernel_io_startup (void);
    92 extern void __kernel_io_shutdown(void);
    9392
    9493//-----------------------------------------------------------------------------
     
    102101KERNEL_STORAGE($thread,              mainThread);
    103102KERNEL_STORAGE(__stack_t,            mainThreadCtx);
    104 KERNEL_STORAGE(io_context,           mainPollerThread);
    105103KERNEL_STORAGE(__scheduler_RWLock_t, __scheduler_lock);
    106104#if !defined(__CFA_NO_STATISTICS__)
     
    198196
    199197        void ?{}(processor & this) with( this ) {
    200                 ( this.idle ){};
    201198                ( this.terminated ){};
    202199                ( this.runner ){};
    203                 init( this, "Main Processor", *mainCluster );
     200                init( this, "Main Processor", *mainCluster, 0p );
    204201                kernel_thread = pthread_self();
    205202
     
    226223        __kernel_alarm_startup();
    227224
    228         // Start IO
    229         __kernel_io_startup();
    230 
    231225        // Add the main thread to the ready queue
    232226        // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
    233         __schedule_thread(mainThread);
     227        schedule_thread$(mainThread);
    234228
    235229        // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
     
    241235        // THE SYSTEM IS NOW COMPLETELY RUNNING
    242236
    243 
    244         // SKULLDUGGERY: The constructor for the mainCluster will call alloc with a dimension of 0
    245         // malloc *can* return a non-null value, we should free it if that is the case
    246         free( mainCluster->io.ctxs );
    247 
    248         // Now that the system is up, finish creating systems that need threading
    249         mainCluster->io.ctxs = (io_context *)&storage_mainPollerThread;
    250         mainCluster->io.cnt  = 1;
    251         (*mainCluster->io.ctxs){ *mainCluster };
    252 
    253237        __cfadbg_print_safe(runtime_core, "Kernel : Started\n--------------------------------------------------\n\n");
    254238
    255239        /* paranoid */ verify( ! __preemption_enabled() );
    256         enable_interrupts( __cfaabi_dbg_ctx );
     240        enable_interrupts();
    257241        /* paranoid */ verify( __preemption_enabled() );
    258242
     
    260244
    261245static void __kernel_shutdown(void) {
    262         //Before we start shutting things down, wait for systems that need threading to shutdown
    263         ^(*mainCluster->io.ctxs){};
    264         mainCluster->io.cnt  = 0;
    265         mainCluster->io.ctxs = 0p;
    266 
    267246        /* paranoid */ verify( __preemption_enabled() );
    268247        disable_interrupts();
     
    283262        __kernel_alarm_shutdown();
    284263
    285         // Stop IO
    286         __kernel_io_shutdown();
     264        #if !defined( __CFA_NO_STATISTICS__ )
     265                __stats_t * st = (__stats_t *)& storage_mainProcStats;
     266                __tally_stats(mainCluster->stats, st);
     267                if( 0 != mainProcessor->print_stats ) {
     268                        __print_stats( st, mainProcessor->print_stats, "Processor ", mainProcessor->name, (void*)mainProcessor );
     269                }
     270                #if defined(CFA_STATS_ARRAY)
     271                        __flush_stat( st, "Processor", mainProcessor );
     272                #endif
     273        #endif
    287274
    288275        // Destroy the main processor and its context in reverse order of construction
     
    364351                        __print_stats( &local_stats, proc->print_stats, "Processor ", proc->name, (void*)proc );
    365352                }
     353                #if defined(CFA_STATS_ARRAY)
     354                        __flush_stat( &local_stats, "Processor", proc );
     355                #endif
    366356        #endif
    367357
     
    457447        link.next = 0p;
    458448        link.prev = 0p;
     449        link.preferred = -1u;
     450        last_proc = 0p;
    459451        #if defined( __CFA_WITH_VERIFY__ )
    460452                canary = 0x0D15EA5E0D15EA5Ep;
     
    476468}
    477469
    478 static void init(processor & this, const char name[], cluster & _cltr) with( this ) {
     470static void init(processor & this, const char name[], cluster & _cltr, $thread * initT) with( this ) {
    479471        this.name = name;
    480472        this.cltr = &_cltr;
    481         full_proc = true;
     473        this.rdq.its = 0;
     474        this.rdq.itr = 0;
     475        this.rdq.id  = -1u;
     476        this.rdq.target = -1u;
     477        this.rdq.cutoff = -1ull;
    482478        do_terminate = false;
    483479        preemption_alarm = 0p;
    484480        pending_preemption = false;
    485481
     482        this.io.ctx = 0p;
     483        this.io.pending = false;
     484        this.io.dirty   = false;
     485
     486        this.init.thrd = initT;
     487
     488        this.idle = eventfd(0, 0);
     489        if (idle < 0) {
     490                abort("KERNEL ERROR: PROCESSOR EVENTFD - %s\n", strerror(errno));
     491        }
     492
    486493        #if !defined(__CFA_NO_STATISTICS__)
    487494                print_stats = 0;
     
    489496        #endif
    490497
    491         lock( this.cltr->idles );
    492                 int target = this.cltr->idles.total += 1u;
    493         unlock( this.cltr->idles );
    494 
    495         id = doregister((__processor_id_t*)&this);
    496 
     498        // Register and Lock the RWlock so no-one pushes/pops while we are changing the queue
     499        uint_fast32_t last_size = ready_mutate_register((__processor_id_t*)&this);
     500                this.cltr->procs.total += 1u;
     501                insert_last(this.cltr->procs.actives, this);
     502
     503                // Adjust the ready queue size
     504                ready_queue_grow( cltr );
     505
     506        // Unlock the RWlock
     507        ready_mutate_unlock( last_size );
     508
     509        __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this);
     510}
     511
     512// Not a ctor, it just preps the destruction but should not destroy members
     513static void deinit(processor & this) {
    497514        // Lock the RWlock so no-one pushes/pops while we are changing the queue
    498515        uint_fast32_t last_size = ready_mutate_lock();
     516                this.cltr->procs.total -= 1u;
     517                remove(this);
    499518
    500519                // Adjust the ready queue size
    501                 ready_queue_grow( cltr, target );
    502 
    503         // Unlock the RWlock
    504         ready_mutate_unlock( last_size );
    505 
    506         __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this);
    507 }
    508 
    509 // Not a ctor, it just preps the destruction but should not destroy members
    510 static void deinit(processor & this) {
    511         lock( this.cltr->idles );
    512                 int target = this.cltr->idles.total -= 1u;
    513         unlock( this.cltr->idles );
    514 
    515         // Lock the RWlock so no-one pushes/pops while we are changing the queue
    516         uint_fast32_t last_size = ready_mutate_lock();
    517 
    518                 // Adjust the ready queue size
    519                 ready_queue_shrink( this.cltr, target );
    520 
    521         // Unlock the RWlock
    522         ready_mutate_unlock( last_size );
    523 
    524         // Finally we don't need the read_lock any more
    525         unregister((__processor_id_t*)&this);
    526 }
    527 
    528 void ?{}(processor & this, const char name[], cluster & _cltr) {
    529         ( this.idle ){};
     520                ready_queue_shrink( this.cltr );
     521
     522        // Unlock the RWlock and unregister: we don't need the read_lock any more
     523        ready_mutate_unregister((__processor_id_t*)&this, last_size );
     524
     525        close(this.idle);
     526}
     527
     528void ?{}(processor & this, const char name[], cluster & _cltr, $thread * initT) {
    530529        ( this.terminated ){};
    531530        ( this.runner ){};
    532531
    533532        disable_interrupts();
    534                 init( this, name, _cltr );
    535         enable_interrupts( __cfaabi_dbg_ctx );
     533                init( this, name, _cltr, initT );
     534        enable_interrupts();
    536535
    537536        __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this);
    538537
    539538        this.stack = __create_pthread( &this.kernel_thread, __invoke_processor, (void *)&this );
    540 
     539}
     540
     541void ?{}(processor & this, const char name[], cluster & _cltr) {
     542        (this){name, _cltr, 0p};
    541543}
    542544
     
    557559        disable_interrupts();
    558560                deinit( this );
    559         enable_interrupts( __cfaabi_dbg_ctx );
     561        enable_interrupts();
    560562}
    561563
    562564//-----------------------------------------------------------------------------
    563565// Cluster
    564 static void ?{}(__cluster_idles & this) {
     566static void ?{}(__cluster_proc_list & this) {
    565567        this.lock  = 0;
    566568        this.idle  = 0;
    567569        this.total = 0;
    568         (this.list){};
    569570}
    570571
     
    582583        threads{ __get };
    583584
     585        io.arbiter = create();
     586        io.params = io_params;
     587
    584588        doregister(this);
    585589
     
    589593
    590594                // Adjust the ready queue size
    591                 ready_queue_grow( &this, 0 );
     595                ready_queue_grow( &this );
    592596
    593597        // Unlock the RWlock
    594598        ready_mutate_unlock( last_size );
    595         enable_interrupts_noPoll(); // Don't poll, could be in main cluster
    596 
    597 
    598         this.io.cnt  = num_io;
    599         this.io.ctxs = aalloc(num_io);
    600         for(i; this.io.cnt) {
    601                 (this.io.ctxs[i]){ this, io_params };
    602         }
     599        enable_interrupts( false ); // Don't poll, could be in main cluster
    603600}
    604601
    605602void ^?{}(cluster & this) {
    606         for(i; this.io.cnt) {
    607                 ^(this.io.ctxs[i]){ true };
    608         }
    609         free(this.io.ctxs);
     603        destroy(this.io.arbiter);
    610604
    611605        // Lock the RWlock so no-one pushes/pops while we are changing the queue
     
    614608
    615609                // Adjust the ready queue size
    616                 ready_queue_shrink( &this, 0 );
     610                ready_queue_shrink( &this );
    617611
    618612        // Unlock the RWlock
    619613        ready_mutate_unlock( last_size );
    620         enable_interrupts_noPoll(); // Don't poll, could be in main cluster
     614        enable_interrupts( false ); // Don't poll, could be in main cluster
    621615
    622616        #if !defined(__CFA_NO_STATISTICS__)
     
    624618                        __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this );
    625619                }
     620                #if defined(CFA_STATS_ARRAY)
     621                        __flush_stat( this.stats, "Cluster", &this );
     622                #endif
    626623                free( this.stats );
    627624        #endif
     
    736733}
    737734
    738 
    739735#if defined(__CFA_WITH_VERIFY__)
    740736static bool verify_fwd_bck_rng(void) {
  • libcfa/src/concurrency/kernel_private.hfa

    rfeacef9 r5407cdc  
    2929extern "C" {
    3030        void disable_interrupts() OPTIONAL_THREAD;
    31         void enable_interrupts_noPoll();
    32         void enable_interrupts( __cfaabi_dbg_ctx_param );
    33 }
    34 
    35 void __schedule_thread( $thread * )
    36 #if defined(NDEBUG) || (!defined(__CFA_DEBUG__) && !defined(__CFA_VERIFY__))
    37         __attribute__((nonnull (1)))
    38 #endif
    39 ;
     31        void enable_interrupts( bool poll = true );
     32}
     33
     34void schedule_thread$( $thread * ) __attribute__((nonnull (1)));
    4035
    4136extern bool __preemption_enabled();
     
    7772//-----------------------------------------------------------------------------
    7873// I/O
    79 void ^?{}(io_context & this, bool );
     74$io_arbiter * create(void);
     75void destroy($io_arbiter *);
    8076
    8177//=======================================================================
    8278// Cluster lock API
    8379//=======================================================================
    84 // Cells use by the reader writer lock
    85 // while not generic it only relies on a opaque pointer
    86 struct __attribute__((aligned(128))) __scheduler_lock_id_t {
    87         // Spin lock used as the underlying lock
    88         volatile bool lock;
    89 
    90         // Handle pointing to the proc owning this cell
    91         // Used for allocating cells and debugging
    92         __processor_id_t * volatile handle;
    93 
    94         #ifdef __CFA_WITH_VERIFY__
    95                 // Debug, check if this is owned for reading
    96                 bool owned;
    97         #endif
    98 };
    99 
    100 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
    101 
    10280// Lock-Free registering/unregistering of threads
    10381// Register a processor to a given cluster and get its unique id in return
    104 unsigned doregister( struct __processor_id_t * proc );
     82void register_proc_id( struct __processor_id_t * );
    10583
    10684// Unregister a processor from a given cluster using its id, getting back the original pointer
    107 void     unregister( struct __processor_id_t * proc );
    108 
    109 //-----------------------------------------------------------------------
    110 // Cluster idle lock/unlock
    111 static inline void lock(__cluster_idles & this) {
    112         for() {
    113                 uint64_t l = this.lock;
    114                 if(
    115                         (0 == (l % 2))
    116                         && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
    117                 ) return;
    118                 Pause();
    119         }
    120 }
    121 
    122 static inline void unlock(__cluster_idles & this) {
    123         /* paranoid */ verify( 1 == (this.lock % 2) );
    124         __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
    125 }
     85void unregister_proc_id( struct __processor_id_t * proc );
    12686
    12787//=======================================================================
     
    151111        __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE);
    152112}
     113
     114// Cells use by the reader writer lock
     115// while not generic it only relies on a opaque pointer
     116struct __attribute__((aligned(128))) __scheduler_lock_id_t {
     117        // Spin lock used as the underlying lock
     118        volatile bool lock;
     119
     120        // Handle pointing to the proc owning this cell
     121        // Used for allocating cells and debugging
     122        __processor_id_t * volatile handle;
     123
     124        #ifdef __CFA_WITH_VERIFY__
     125                // Debug, check if this is owned for reading
     126                bool owned;
     127        #endif
     128};
     129
     130static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
    153131
    154132//-----------------------------------------------------------------------
     
    246224void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ );
    247225
     226//-----------------------------------------------------------------------
     227// Lock-Free registering/unregistering of threads
     228// Register a processor to a given cluster and get its unique id in return
     229// For convenience, also acquires the lock
     230static inline uint_fast32_t ready_mutate_register( struct __processor_id_t * proc ) {
     231        register_proc_id( proc );
     232        return ready_mutate_lock();
     233}
     234
     235// Unregister a processor from a given cluster using its id, getting back the original pointer
     236// assumes the lock is acquired
     237static inline void ready_mutate_unregister( struct __processor_id_t * proc, uint_fast32_t last_s ) {
     238        ready_mutate_unlock( last_s );
     239        unregister_proc_id( proc );
     240}
     241
     242//-----------------------------------------------------------------------
     243// Cluster idle lock/unlock
     244static inline void lock(__cluster_proc_list & this) {
     245        /* paranoid */ verify( ! __preemption_enabled() );
     246
     247        // Start by locking the global RWlock so that we know no-one is
     248        // adding/removing processors while we mess with the idle lock
     249        ready_schedule_lock();
     250
     251        // Simple counting lock, acquired, acquired by incrementing the counter
     252        // to an odd number
     253        for() {
     254                uint64_t l = this.lock;
     255                if(
     256                        (0 == (l % 2))
     257                        && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
     258                ) return;
     259                Pause();
     260        }
     261
     262        /* paranoid */ verify( ! __preemption_enabled() );
     263}
     264
     265static inline void unlock(__cluster_proc_list & this) {
     266        /* paranoid */ verify( ! __preemption_enabled() );
     267
     268        /* paranoid */ verify( 1 == (this.lock % 2) );
     269        // Simple couting lock, release by incrementing to an even number
     270        __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
     271
     272        // Release the global lock, which we acquired when locking
     273        ready_schedule_unlock();
     274
     275        /* paranoid */ verify( ! __preemption_enabled() );
     276}
     277
    248278//=======================================================================
    249279// Ready-Queue API
    250280//-----------------------------------------------------------------------
    251 // pop thread from the ready queue of a cluster
    252 // returns 0p if empty
    253 __attribute__((hot)) bool query(struct cluster * cltr);
    254 
    255 //-----------------------------------------------------------------------
    256281// push thread onto a ready queue for a cluster
    257282// returns true if the list was previously empty, false otherwise
    258 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd);
    259 
    260 //-----------------------------------------------------------------------
    261 // pop thread from the ready queue of a cluster
     283__attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd);
     284
     285//-----------------------------------------------------------------------
     286// pop thread from the local queues of a cluster
    262287// returns 0p if empty
    263288// May return 0p spuriously
    264 __attribute__((hot)) struct $thread * pop(struct cluster * cltr);
    265 
    266 //-----------------------------------------------------------------------
    267 // pop thread from the ready queue of a cluster
     289__attribute__((hot)) struct $thread * pop_fast(struct cluster * cltr);
     290
     291//-----------------------------------------------------------------------
     292// pop thread from any ready queue of a cluster
     293// returns 0p if empty
     294// May return 0p spuriously
     295__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr);
     296
     297//-----------------------------------------------------------------------
     298// search all ready queues of a cluster for any thread
    268299// returns 0p if empty
    269300// guaranteed to find any threads added before this call
    270 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr);
    271 
    272 //-----------------------------------------------------------------------
    273 // remove thread from the ready queue of a cluster
    274 // returns bool if it wasn't found
    275 bool remove_head(struct cluster * cltr, struct $thread * thrd);
     301__attribute__((hot)) struct $thread * pop_search(struct cluster * cltr);
    276302
    277303//-----------------------------------------------------------------------
    278304// Increase the width of the ready queue (number of lanes) by 4
    279 void ready_queue_grow  (struct cluster * cltr, int target);
     305void ready_queue_grow  (struct cluster * cltr);
    280306
    281307//-----------------------------------------------------------------------
    282308// Decrease the width of the ready queue (number of lanes) by 4
    283 void ready_queue_shrink(struct cluster * cltr, int target);
     309void ready_queue_shrink(struct cluster * cltr);
    284310
    285311
  • libcfa/src/concurrency/locks.cfa

    rfeacef9 r5407cdc  
    134134        lock( lock __cfaabi_dbg_ctx2 );
    135135        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
    136         /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this );
     136        /* paranoid */ verifyf( owner == active_thread() || !strict_owner , "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this );
     137        /* paranoid */ verifyf( recursion_count == 1 || multi_acquisition, "Thread %p attempted to release owner lock %p which is not recursive but has a recursive count of %zu", active_thread(), &this, recursion_count );
    137138
    138139        // if recursion count is zero release lock and set new owner if one is waiting
     
    146147size_t wait_count( blocking_lock & this ) with( this ) {
    147148        return wait_count;
    148 }
    149 
    150 void set_recursion_count( blocking_lock & this, size_t recursion ) with( this ) {
    151         recursion_count = recursion;
    152 }
    153 
    154 size_t get_recursion_count( blocking_lock & this ) with( this ) {
    155         return recursion_count;
    156149}
    157150
     
    173166}
    174167
    175 void on_wait( blocking_lock & this ) with( this ) {
     168size_t on_wait( blocking_lock & this ) with( this ) {
    176169        lock( lock __cfaabi_dbg_ctx2 );
    177170        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
    178171        /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this );
    179172
     173        size_t ret = recursion_count;
     174
    180175        pop_and_set_new_owner( this );
    181176        unlock( lock );
     177        return ret;
     178}
     179
     180void on_wakeup( blocking_lock & this, size_t recursion ) with( this ) {
     181        recursion_count = recursion;
    182182}
    183183
     
    274274        }
    275275
    276         bool empty( condition_variable(L) & this ) with(this) { return empty(blocked_threads); }
     276        bool empty( condition_variable(L) & this ) with(this) {
     277                lock( lock __cfaabi_dbg_ctx2 );
     278                bool ret = empty(blocked_threads);
     279                unlock( lock );
     280                return ret;
     281        }
    277282
    278283        int counter( condition_variable(L) & this ) with(this) { return count; }
     
    285290                if (i->lock) {
    286291                        // if lock was passed get recursion count to reset to after waking thread
    287                         recursion_count = get_recursion_count(*i->lock);
    288                         on_wait( *i->lock );
     292                        recursion_count = on_wait( *i->lock );
    289293                }
    290294                return recursion_count;
     
    301305
    302306                // resets recursion count here after waking
    303                 if (i.lock) set_recursion_count(*i.lock, recursion_count);
     307                if (i.lock) on_wakeup(*i.lock, recursion_count);
    304308        }
    305309
     
    323327
    324328                // resets recursion count here after waking
    325                 if (info.lock) set_recursion_count(*info.lock, recursion_count);
     329                if (info.lock) on_wakeup(*info.lock, recursion_count);
    326330        }
    327331
     
    373377}
    374378
    375 bool V(semaphore & this) with( this ) {
     379$thread * V (semaphore & this, const bool doUnpark ) with( this ) {
    376380        $thread * thrd = 0p;
    377381        lock( lock __cfaabi_dbg_ctx2 );
     
    385389
    386390        // make new owner
    387         unpark( thrd );
    388 
     391        if( doUnpark ) unpark( thrd );
     392
     393        return thrd;
     394}
     395
     396bool V(semaphore & this) with( this ) {
     397        $thread * thrd = V(this, true);
    389398        return thrd != 0p;
    390399}
  • libcfa/src/concurrency/locks.hfa

    rfeacef9 r5407cdc  
    2020
    2121#include "bits/weakso_locks.hfa"
     22#include "containers/queueLockFree.hfa"
     23
     24#include "thread.hfa"
    2225
    2326#include "time_t.hfa"
    2427#include "time.hfa"
     28
     29//-----------------------------------------------------------------------------
     30// Semaphores
     31
     32// '0-nary' semaphore
     33// Similar to a counting semaphore except the value of one is never reached
     34// as a consequence, a V() that would bring the value to 1 *spins* until
     35// a P consumes it
     36struct Semaphore0nary {
     37        __spinlock_t lock; // needed to protect
     38        mpsc_queue($thread) queue;
     39};
     40
     41static inline bool P(Semaphore0nary & this, $thread * thrd) {
     42        /* paranoid */ verify(!(thrd->seqable.next));
     43        /* paranoid */ verify(!(thrd`next));
     44
     45        push(this.queue, thrd);
     46        return true;
     47}
     48
     49static inline bool P(Semaphore0nary & this) {
     50    $thread * thrd = active_thread();
     51    P(this, thrd);
     52    park();
     53    return true;
     54}
     55
     56static inline $thread * V(Semaphore0nary & this, bool doUnpark = true) {
     57        $thread * next;
     58        lock(this.lock __cfaabi_dbg_ctx2);
     59                for (;;) {
     60                        next = pop(this.queue);
     61                        if (next) break;
     62                        Pause();
     63                }
     64        unlock(this.lock);
     65
     66        if (doUnpark) unpark(next);
     67        return next;
     68}
     69
     70// Wrapper used on top of any sempahore to avoid potential locking
     71struct BinaryBenaphore {
     72        volatile ssize_t counter;
     73};
     74
     75static inline {
     76        void ?{}(BinaryBenaphore & this) { this.counter = 0; }
     77        void ?{}(BinaryBenaphore & this, zero_t) { this.counter = 0; }
     78        void ?{}(BinaryBenaphore & this, one_t ) { this.counter = 1; }
     79
     80        // returns true if no blocking needed
     81        bool P(BinaryBenaphore & this) {
     82                return __atomic_fetch_sub(&this.counter, 1, __ATOMIC_SEQ_CST) > 0;
     83        }
     84
     85        bool tryP(BinaryBenaphore & this) {
     86                ssize_t c = this.counter;
     87                return (c >= 1) && __atomic_compare_exchange_n(&this.counter, &c, c-1, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
     88        }
     89
     90        // returns true if notify needed
     91        bool V(BinaryBenaphore & this) {
     92                ssize_t c = 0;
     93                for () {
     94                        if (__atomic_compare_exchange_n(&this.counter, &c, c+1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     95                                if (c == 0) return true;
     96                                /* paranoid */ verify(c < 0);
     97                                return false;
     98                        } else {
     99                                if (c == 1) return true;
     100                                /* paranoid */ verify(c < 1);
     101                                Pause();
     102                        }
     103                }
     104        }
     105}
     106
     107// Binary Semaphore based on the BinaryBenaphore on top of the 0-nary Semaphore
     108struct ThreadBenaphore {
     109        BinaryBenaphore ben;
     110        Semaphore0nary  sem;
     111};
     112
     113static inline void ?{}(ThreadBenaphore & this) {}
     114static inline void ?{}(ThreadBenaphore & this, zero_t) { (this.ben){ 0 }; }
     115static inline void ?{}(ThreadBenaphore & this, one_t ) { (this.ben){ 1 }; }
     116
     117static inline bool P(ThreadBenaphore & this)              { return P(this.ben) ? false : P(this.sem); }
     118static inline bool tryP(ThreadBenaphore & this)           { return tryP(this.ben); }
     119static inline bool P(ThreadBenaphore & this, bool wait)   { return wait ? P(this) : tryP(this); }
     120
     121static inline $thread * V(ThreadBenaphore & this, bool doUnpark = true) {
     122        if (V(this.ben)) return 0p;
     123        return V(this.sem, doUnpark);
     124}
     125
     126//-----------------------------------------------------------------------------
     127// Semaphore
     128struct semaphore {
     129        __spinlock_t lock;
     130        int count;
     131        __queue_t($thread) waiting;
     132};
     133
     134void  ?{}(semaphore & this, int count = 1);
     135void ^?{}(semaphore & this);
     136bool   P (semaphore & this);
     137bool   V (semaphore & this);
     138bool   V (semaphore & this, unsigned count);
     139$thread * V (semaphore & this, bool );
    25140
    26141//----------
     
    31146static inline void  ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}
    32147static inline void ^?{}( single_acquisition_lock & this ) {}
    33 static inline void   lock      ( single_acquisition_lock & this ) { lock   ( (blocking_lock &)this ); }
    34 static inline void   unlock    ( single_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); }
    35 static inline void   on_wait   ( single_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); }
    36 static inline void   on_notify ( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
    37 static inline void   set_recursion_count( single_acquisition_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }
    38 static inline size_t get_recursion_count( single_acquisition_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }
     148static inline void   lock     ( single_acquisition_lock & this ) { lock    ( (blocking_lock &)this ); }
     149static inline bool   try_lock ( single_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); }
     150static inline void   unlock   ( single_acquisition_lock & this ) { unlock  ( (blocking_lock &)this ); }
     151static inline size_t on_wait  ( single_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); }
     152static inline void   on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
     153static inline void   on_notify( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
    39154
    40155//----------
     
    45160static inline void  ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}
    46161static inline void ^?{}( owner_lock & this ) {}
    47 static inline void   lock     ( owner_lock & this ) { lock   ( (blocking_lock &)this ); }
    48 static inline void   unlock   ( owner_lock & this ) { unlock ( (blocking_lock &)this ); }
    49 static inline void   on_wait  ( owner_lock & this ) { on_wait( (blocking_lock &)this ); }
     162static inline void   lock     ( owner_lock & this ) { lock    ( (blocking_lock &)this ); }
     163static inline bool   try_lock ( owner_lock & this ) { return try_lock( (blocking_lock &)this ); }
     164static inline void   unlock   ( owner_lock & this ) { unlock  ( (blocking_lock &)this ); }
     165static inline size_t on_wait  ( owner_lock & this ) { return on_wait ( (blocking_lock &)this ); }
     166static inline void   on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    50167static inline void   on_notify( owner_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
    51 static inline void   set_recursion_count( owner_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }
    52 static inline size_t get_recursion_count( owner_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }
     168
     169struct fast_lock {
     170        $thread * volatile owner;
     171        ThreadBenaphore sem;
     172};
     173
     174static inline bool $try_lock(fast_lock & this, $thread * thrd) {
     175    $thread * exp = 0p;
     176    return __atomic_compare_exchange_n(&this.owner, &exp, thrd, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
     177}
     178
     179static inline void lock( fast_lock & this ) __attribute__((artificial));
     180static inline void lock( fast_lock & this ) {
     181        $thread * thrd = active_thread();
     182        /* paranoid */verify(thrd != this.owner);
     183
     184        for (;;) {
     185                if ($try_lock(this, thrd)) return;
     186                P(this.sem);
     187        }
     188}
     189
     190static inline bool try_lock( fast_lock & this ) __attribute__((artificial));
     191static inline bool try_lock ( fast_lock & this ) {
     192        $thread * thrd = active_thread();
     193        /* paranoid */ verify(thrd != this.owner);
     194        return $try_lock(this, thrd);
     195}
     196
     197static inline $thread * unlock( fast_lock & this ) __attribute__((artificial));
     198static inline $thread * unlock( fast_lock & this ) {
     199        /* paranoid */ verify(active_thread() == this.owner);
     200
     201        // open 'owner' before unlocking anyone
     202        // so new and unlocked threads don't park incorrectly.
     203        // This may require additional fencing on ARM.
     204        this.owner = 0p;
     205
     206        return V(this.sem);
     207}
     208
     209static inline size_t on_wait( fast_lock & this ) { unlock(this); return 0; }
     210static inline void on_wakeup( fast_lock & this, size_t ) { lock(this); }
     211static inline void on_notify( fast_lock &, struct $thread * t ) { unpark(t); }
     212
     213struct mcs_node {
     214        mcs_node * volatile next;
     215        single_sem sem;
     216};
     217
     218static inline void ?{}(mcs_node & this) { this.next = 0p; }
     219
     220static inline mcs_node * volatile & ?`next ( mcs_node * node ) {
     221        return node->next;
     222}
     223
     224struct mcs_lock {
     225        mcs_queue(mcs_node) queue;
     226};
     227
     228static inline void lock(mcs_lock & l, mcs_node & n) {
     229        if(push(l.queue, &n))
     230                wait(n.sem);
     231}
     232
     233static inline void unlock(mcs_lock & l, mcs_node & n) {
     234        mcs_node * next = advance(l.queue, &n);
     235        if(next) post(next->sem);
     236}
    53237
    54238//-----------------------------------------------------------------------------
     
    59243
    60244        // For synchronization locks to use when releasing
    61         void on_wait( L & );
    62 
    63         // to get recursion count for cond lock to reset after waking
    64         size_t get_recursion_count( L & );
     245        size_t on_wait( L & );
    65246
    66247        // to set recursion count after getting signalled;
    67         void set_recursion_count( L &, size_t recursion );
     248        void on_wakeup( L &, size_t recursion );
    68249};
    69250
     
    119300        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time );
    120301}
    121 
    122 //-----------------------------------------------------------------------------
    123 // Semaphore
    124 struct semaphore {
    125         __spinlock_t lock;
    126         int count;
    127         __queue_t($thread) waiting;
    128 };
    129 
    130 void  ?{}(semaphore & this, int count = 1);
    131 void ^?{}(semaphore & this);
    132 bool   P (semaphore & this);
    133 bool   V (semaphore & this);
    134 bool   V (semaphore & this, unsigned count);
  • libcfa/src/concurrency/monitor.hfa

    rfeacef9 r5407cdc  
    6161static inline forall( T & | sized(T) | { void ^?{}( T & mutex ); } )
    6262void delete( T * th ) {
    63         ^(*th){};
     63        if(th) ^(*th){};
    6464        free( th );
    6565}
  • libcfa/src/concurrency/preemption.cfa

    rfeacef9 r5407cdc  
    1515
    1616#define __cforall_thread__
     17// #define __CFA_DEBUG_PRINT_PREEMPTION__
    1718
    1819#include "preemption.hfa"
     
    2829#include "kernel_private.hfa"
    2930
     31
    3032#if !defined(__CFA_DEFAULT_PREEMPTION__)
    3133#define __CFA_DEFAULT_PREEMPTION__ 10`ms
    3234#endif
    3335
    34 Duration default_preemption() __attribute__((weak)) {
    35         return __CFA_DEFAULT_PREEMPTION__;
     36__attribute__((weak)) Duration default_preemption() {
     37        const char * preempt_rate_s = getenv("CFA_DEFAULT_PREEMPTION");
     38        if(!preempt_rate_s) {
     39                __cfadbg_print_safe(preemption, "No CFA_DEFAULT_PREEMPTION in ENV\n");
     40                return __CFA_DEFAULT_PREEMPTION__;
     41        }
     42
     43        char * endptr = 0p;
     44        long int preempt_rate_l = strtol(preempt_rate_s, &endptr, 10);
     45        if(preempt_rate_l < 0 || preempt_rate_l > 65535) {
     46                __cfadbg_print_safe(preemption, "CFA_DEFAULT_PREEMPTION out of range : %ld\n", preempt_rate_l);
     47                return __CFA_DEFAULT_PREEMPTION__;
     48        }
     49        if('\0' != *endptr) {
     50                __cfadbg_print_safe(preemption, "CFA_DEFAULT_PREEMPTION not a decimal number : %s\n", preempt_rate_s);
     51                return __CFA_DEFAULT_PREEMPTION__;
     52        }
     53
     54        return preempt_rate_l`ms;
    3655}
    3756
     
    98117        //Loop throught every thing expired
    99118        while( node = get_expired( alarms, currtime ) ) {
    100                 // __cfaabi_dbg_print_buffer_decl( " KERNEL: preemption tick.\n" );
     119                __cfadbg_print_buffer_decl( preemption, " KERNEL: preemption tick %lu\n", currtime.tn);
    101120                Duration period = node->period;
    102121                if( period == 0) {
     
    104123                }
    105124
     125                __cfadbg_print_buffer_local( preemption, " KERNEL: alarm ticking node %p.\n", node );
     126
     127
    106128                // Check if this is a kernel
    107129                if( node->type == Kernel ) {
     
    109131                }
    110132                else if( node->type == User ) {
     133                        __cfadbg_print_buffer_local( preemption, " KERNEL: alarm unparking %p.\n", node->thrd );
    111134                        timeout( node->thrd );
    112135                }
     
    117140                // Check if this is a periodic alarm
    118141                if( period > 0 ) {
    119                         // __cfaabi_dbg_print_buffer_local( " KERNEL: alarm period is %lu.\n", period.tv );
     142                        __cfadbg_print_buffer_local( preemption, " KERNEL: alarm period is %lu.\n", period`ns );
    120143                        node->alarm = currtime + period;    // Alarm is periodic, add currtime to it (used cached current time)
    121144                        insert( alarms, node );             // Reinsert the node for the next time it triggers
     
    125148        // If there are still alarms pending, reset the timer
    126149        if( & (*alarms)`first ) {
    127                 __cfadbg_print_buffer_decl(preemption, " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);
    128150                Duration delta = (*alarms)`first.alarm - currtime;
    129151                Duration capped = max(delta, 50`us);
    130                 // itimerval tim  = { caped };
    131                 // __cfaabi_dbg_print_buffer_local( "    Values are %lu, %lu, %lu %lu.\n", delta.tv, caped.tv, tim.it_value.tv_sec, tim.it_value.tv_usec);
    132 
    133152                __kernel_set_timer( capped );
    134153        }
     
    296315        // Enable interrupts by decrementing the counter
    297316        // If counter reaches 0, execute any pending __cfactx_switch
    298         void enable_interrupts( __cfaabi_dbg_ctx_param ) {
     317        void enable_interrupts( bool poll ) {
    299318                // Cache the processor now since interrupts can start happening after the atomic store
    300319                processor   * proc = __cfaabi_tls.this_processor;
    301                 /* paranoid */ verify( proc );
     320                /* paranoid */ verify( !poll || proc );
    302321
    303322                with( __cfaabi_tls.preemption_state ){
     
    321340                                // Signal the compiler that a fence is needed but only for signal handlers
    322341                                __atomic_signal_fence(__ATOMIC_RELEASE);
    323                                 if( proc->pending_preemption ) {
     342                                if( poll && proc->pending_preemption ) {
    324343                                        proc->pending_preemption = false;
    325344                                        force_yield( __POLL_PREEMPTION );
    326345                                }
    327346                        }
    328                 }
    329 
    330                 // For debugging purposes : keep track of the last person to enable the interrupts
    331                 __cfaabi_dbg_debug_do( proc->last_enable = caller; )
    332         }
    333 
    334         // Disable interrupts by incrementint the counter
    335         // Don't execute any pending __cfactx_switch even if counter reaches 0
    336         void enable_interrupts_noPoll() {
    337                 unsigned short prev = __cfaabi_tls.preemption_state.disable_count;
    338                 __cfaabi_tls.preemption_state.disable_count -= 1;
    339                 // If this triggers someone is enabled already enabled interrupts
    340                 /* paranoid */ verifyf( prev != 0u, "Incremented from %u\n", prev );
    341                 if( prev == 1 ) {
    342                         #if GCC_VERSION > 50000
    343                                 static_assert(__atomic_always_lock_free(sizeof(__cfaabi_tls.preemption_state.enabled), &__cfaabi_tls.preemption_state.enabled), "Must be lock-free");
    344                         #endif
    345                         // Set enabled flag to true
    346                         // should be atomic to avoid preemption in the middle of the operation.
    347                         // use memory order RELAXED since there is no inter-thread on this variable requirements
    348                         __atomic_store_n(&__cfaabi_tls.preemption_state.enabled, true, __ATOMIC_RELAXED);
    349 
    350                         // Signal the compiler that a fence is needed but only for signal handlers
    351                         __atomic_signal_fence(__ATOMIC_RELEASE);
    352347                }
    353348        }
     
    585580
    586581        // Setup proper signal handlers
    587         __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler
    588         __cfaabi_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO | SA_RESTART ); // debug handler
     582        __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO ); // __cfactx_switch handler
     583        __cfaabi_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO ); // debug handler
    589584
    590585        signal_block( SIGALRM );
     
    689684}
    690685
    691 #if !defined(__CFA_NO_STATISTICS__)
    692         int __print_alarm_stats = 0;
    693 #endif
    694 
    695686// Main of the alarm thread
    696687// Waits on SIGALRM and send SIGUSR1 to whom ever needs it
    697688static void * alarm_loop( __attribute__((unused)) void * args ) {
    698689        __processor_id_t id;
    699         id.full_proc = false;
    700         id.id = doregister(&id);
     690        register_proc_id(&id);
    701691        __cfaabi_tls.this_proc_id = &id;
    702692
    703         #if !defined(__CFA_NO_STATISTICS__)
    704                 struct __stats_t local_stats;
    705                 __cfaabi_tls.this_stats = &local_stats;
    706                 __init_stats( &local_stats );
    707         #endif
    708693
    709694        // Block sigalrms to control when they arrive
     
    764749EXIT:
    765750        __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" );
    766         unregister(&id);
    767 
    768         #if !defined(__CFA_NO_STATISTICS__)
    769                 if( 0 != __print_alarm_stats ) {
    770                         __print_stats( &local_stats, __print_alarm_stats, "Alarm", "Thread", 0p );
    771                 }
    772         #endif
     751        register_proc_id(&id);
     752
    773753        return 0p;
    774754}
  • libcfa/src/concurrency/ready_queue.cfa

    rfeacef9 r5407cdc  
    1717// #define __CFA_DEBUG_PRINT_READY_QUEUE__
    1818
    19 // #define USE_SNZI
     19// #define USE_MPSC
     20
     21#define USE_RELAXED_FIFO
     22// #define USE_WORK_STEALING
    2023
    2124#include "bits/defs.hfa"
     
    2831#include <unistd.h>
    2932
    30 #include "snzi.hfa"
    3133#include "ready_subqueue.hfa"
    3234
    3335static const size_t cache_line_size = 64;
     36
     37#if !defined(__CFA_NO_STATISTICS__)
     38        #define __STATS(...) __VA_ARGS__
     39#else
     40        #define __STATS(...)
     41#endif
    3442
    3543// No overriden function, no environment variable, no define
     
    3947#endif
    4048
    41 #define BIAS 16
     49#if   defined(USE_RELAXED_FIFO)
     50        #define BIAS 4
     51        #define READYQ_SHARD_FACTOR 4
     52        #define SEQUENTIAL_SHARD 1
     53#elif defined(USE_WORK_STEALING)
     54        #define READYQ_SHARD_FACTOR 2
     55        #define SEQUENTIAL_SHARD 2
     56#else
     57        #error no scheduling strategy selected
     58#endif
     59
     60static inline struct $thread * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats));
     61static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats));
     62static inline struct $thread * search(struct cluster * cltr);
     63static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred);
     64
    4265
    4366// returns the maximum number of processors the RWLock support
     
    93116//=======================================================================
    94117// Lock-Free registering/unregistering of threads
    95 unsigned doregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     118void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
    96119        __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc);
    97120
     
    107130                        /*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size));
    108131                        /*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0);
    109                         return i;
     132                        proc->id = i;
    110133                }
    111134        }
     
    134157        /*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size));
    135158        /*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0);
    136         return n;
    137 }
    138 
    139 void unregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     159        proc->id = n;
     160}
     161
     162void unregister_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
    140163        unsigned id = proc->id;
    141164        /*paranoid*/ verify(id < ready);
     
    192215
    193216//=======================================================================
    194 // Cforall Reqdy Queue used for scheduling
     217// Cforall Ready Queue used for scheduling
    195218//=======================================================================
    196219void ?{}(__ready_queue_t & this) with (this) {
    197220        lanes.data  = 0p;
     221        lanes.tscs  = 0p;
    198222        lanes.count = 0;
    199223}
    200224
    201225void ^?{}(__ready_queue_t & this) with (this) {
    202         verify( 1 == lanes.count );
    203         #ifdef USE_SNZI
    204                 verify( !query( snzi ) );
    205         #endif
     226        verify( SEQUENTIAL_SHARD == lanes.count );
    206227        free(lanes.data);
     228        free(lanes.tscs);
    207229}
    208230
    209231//-----------------------------------------------------------------------
    210 __attribute__((hot)) bool query(struct cluster * cltr) {
    211         #ifdef USE_SNZI
    212                 return query(cltr->ready_queue.snzi);
    213         #endif
    214         return true;
    215 }
    216 
    217 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
    218         unsigned i;
    219         bool local;
    220         #if defined(BIAS)
     232#if defined(USE_RELAXED_FIFO)
     233        //-----------------------------------------------------------------------
     234        // get index from random number with or without bias towards queues
     235        static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
     236                unsigned i;
     237                bool local;
    221238                unsigned rlow  = r % BIAS;
    222239                unsigned rhigh = r / BIAS;
     
    224241                        // (BIAS - 1) out of BIAS chances
    225242                        // Use perferred queues
    226                         i = preferred + (rhigh % 4);
     243                        i = preferred + (rhigh % READYQ_SHARD_FACTOR);
    227244                        local = true;
    228245                }
     
    233250                        local = false;
    234251                }
    235         #else
    236                 i = r;
    237                 local = false;
     252                return [i, local];
     253        }
     254
     255        __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
     256                __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
     257
     258                const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
     259                /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
     260
     261                // write timestamp
     262                thrd->link.ts = rdtscl();
     263
     264                bool local;
     265                int preferred = external ? -1 : kernelTLS().this_processor->rdq.id;
     266
     267                // Try to pick a lane and lock it
     268                unsigned i;
     269                do {
     270                        // Pick the index of a lane
     271                        unsigned r = __tls_rand_fwd();
     272                        [i, local] = idx_from_r(r, preferred);
     273
     274                        i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     275
     276                        #if !defined(__CFA_NO_STATISTICS__)
     277                                if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED);
     278                                else if(local) __tls_stats()->ready.push.local.attempt++;
     279                                else __tls_stats()->ready.push.share.attempt++;
     280                        #endif
     281
     282                #if defined(USE_MPSC)
     283                        // mpsc always succeeds
     284                } while( false );
     285                #else
     286                        // If we can't lock it retry
     287                } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
     288                #endif
     289
     290                // Actually push it
     291                push(lanes.data[i], thrd);
     292
     293                #if !defined(USE_MPSC)
     294                        // Unlock and return
     295                        __atomic_unlock( &lanes.data[i].lock );
     296                #endif
     297
     298                // Mark the current index in the tls rng instance as having an item
     299                __tls_rand_advance_bck();
     300
     301                __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);
     302
     303                // Update statistics
     304                #if !defined(__CFA_NO_STATISTICS__)
     305                        if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED);
     306                        else if(local) __tls_stats()->ready.push.local.success++;
     307                        else __tls_stats()->ready.push.share.success++;
     308                #endif
     309        }
     310
     311        // Pop from the ready queue from a given cluster
     312        __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
     313                /* paranoid */ verify( lanes.count > 0 );
     314                /* paranoid */ verify( kernelTLS().this_processor );
     315                /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
     316
     317                unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     318                int preferred = kernelTLS().this_processor->rdq.id;
     319
     320
     321                // As long as the list is not empty, try finding a lane that isn't empty and pop from it
     322                for(25) {
     323                        // Pick two lists at random
     324                        unsigned ri = __tls_rand_bck();
     325                        unsigned rj = __tls_rand_bck();
     326
     327                        unsigned i, j;
     328                        __attribute__((unused)) bool locali, localj;
     329                        [i, locali] = idx_from_r(ri, preferred);
     330                        [j, localj] = idx_from_r(rj, preferred);
     331
     332                        i %= count;
     333                        j %= count;
     334
     335                        // try popping from the 2 picked lists
     336                        struct $thread * thrd = try_pop(cltr, i, j __STATS(, *(locali || localj ? &__tls_stats()->ready.pop.local : &__tls_stats()->ready.pop.help)));
     337                        if(thrd) {
     338                                return thrd;
     339                        }
     340                }
     341
     342                // All lanes where empty return 0p
     343                return 0p;
     344        }
     345
     346        __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) { return pop_fast(cltr); }
     347        __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr) {
     348                return search(cltr);
     349        }
     350#endif
     351#if defined(USE_WORK_STEALING)
     352        __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
     353                __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
     354
     355                const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
     356                /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
     357
     358                // write timestamp
     359                thrd->link.ts = rdtscl();
     360
     361                // Try to pick a lane and lock it
     362                unsigned i;
     363                do {
     364                        #if !defined(__CFA_NO_STATISTICS__)
     365                                if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED);
     366                                else __tls_stats()->ready.push.local.attempt++;
     367                        #endif
     368
     369                        if(unlikely(external)) {
     370                                i = __tls_rand() % lanes.count;
     371                        }
     372                        else {
     373                                processor * proc = kernelTLS().this_processor;
     374                                unsigned r = proc->rdq.its++;
     375                                i =  proc->rdq.id + (r % READYQ_SHARD_FACTOR);
     376                        }
     377
     378
     379                #if defined(USE_MPSC)
     380                        // mpsc always succeeds
     381                } while( false );
     382                #else
     383                        // If we can't lock it retry
     384                } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
     385                #endif
     386
     387                // Actually push it
     388                push(lanes.data[i], thrd);
     389
     390                #if !defined(USE_MPSC)
     391                        // Unlock and return
     392                        __atomic_unlock( &lanes.data[i].lock );
     393                #endif
     394
     395                #if !defined(__CFA_NO_STATISTICS__)
     396                        if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED);
     397                        else __tls_stats()->ready.push.local.success++;
     398                #endif
     399
     400                __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);
     401        }
     402
     403        // Pop from the ready queue from a given cluster
     404        __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
     405                /* paranoid */ verify( lanes.count > 0 );
     406                /* paranoid */ verify( kernelTLS().this_processor );
     407                /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
     408
     409                processor * proc = kernelTLS().this_processor;
     410
     411                if(proc->rdq.target == -1u) {
     412                        proc->rdq.target = __tls_rand() % lanes.count;
     413                        unsigned it1  = proc->rdq.itr;
     414                        unsigned it2  = proc->rdq.itr + 1;
     415                        unsigned idx1 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR);
     416                        unsigned idx2 = proc->rdq.id + (it2 % READYQ_SHARD_FACTOR);
     417                        unsigned long long tsc1 = ts(lanes.data[idx1]);
     418                        unsigned long long tsc2 = ts(lanes.data[idx2]);
     419                        proc->rdq.cutoff = min(tsc1, tsc2);
     420                        if(proc->rdq.cutoff == 0) proc->rdq.cutoff = -1ull;
     421                }
     422                else {
     423                        unsigned target = proc->rdq.target;
     424                        proc->rdq.target = -1u;
     425                        if(lanes.tscs[target].tv < proc->rdq.cutoff) {
     426                                $thread * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help));
     427                                if(t) return t;
     428                        }
     429                }
     430
     431                for(READYQ_SHARD_FACTOR) {
     432                        unsigned i = proc->rdq.id + (--proc->rdq.itr % READYQ_SHARD_FACTOR);
     433                        if($thread * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t;
     434                }
     435                return 0p;
     436        }
     437
     438        __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
     439                unsigned i = __tls_rand() % lanes.count;
     440                return try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.steal));
     441        }
     442
     443        __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr) with (cltr->ready_queue) {
     444                return search(cltr);
     445        }
     446#endif
     447
     448//=======================================================================
     449// Various Ready Queue utilities
     450//=======================================================================
     451// these function work the same or almost the same
     452// whether they are using work-stealing or relaxed fifo scheduling
     453
     454//-----------------------------------------------------------------------
     455// try to pop from a lane given by index w
     456static inline struct $thread * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) {
     457        __STATS( stats.attempt++; )
     458
     459        // Get relevant elements locally
     460        __intrusive_lane_t & lane = lanes.data[w];
     461
     462        // If list looks empty retry
     463        if( is_empty(lane) ) {
     464                __STATS( stats.espec++; )
     465                return 0p;
     466        }
     467
     468        // If we can't get the lock retry
     469        if( !__atomic_try_acquire(&lane.lock) ) {
     470                __STATS( stats.elock++; )
     471                return 0p;
     472        }
     473
     474        // If list is empty, unlock and retry
     475        if( is_empty(lane) ) {
     476                __atomic_unlock(&lane.lock);
     477                __STATS( stats.eempty++; )
     478                return 0p;
     479        }
     480
     481        // Actually pop the list
     482        struct $thread * thrd;
     483        thrd = pop(lane);
     484
     485        /* paranoid */ verify(thrd);
     486        /* paranoid */ verify(lane.lock);
     487
     488        // Unlock and return
     489        __atomic_unlock(&lane.lock);
     490
     491        // Update statistics
     492        __STATS( stats.success++; )
     493
     494        #if defined(USE_WORK_STEALING)
     495                lanes.tscs[w].tv = thrd->link.ts;
    238496        #endif
    239         return [i, local];
     497
     498        // return the popped thread
     499        return thrd;
    240500}
    241501
    242502//-----------------------------------------------------------------------
    243 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
    244         __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    245 
    246         // write timestamp
    247         thrd->link.ts = rdtscl();
    248 
    249         __attribute__((unused)) bool local;
    250         __attribute__((unused)) int preferred;
    251         #if defined(BIAS)
    252                 preferred =
    253                         //*
    254                         kernelTLS().this_processor ? kernelTLS().this_processor->id * 4 : -1;
    255                         /*/
    256                         thrd->link.preferred * 4;
    257                         //*/
    258         #endif
    259 
    260         // Try to pick a lane and lock it
    261         unsigned i;
    262         do {
    263                 // Pick the index of a lane
    264                 // unsigned r = __tls_rand();
    265                 unsigned r = __tls_rand_fwd();
    266                 [i, local] = idx_from_r(r, preferred);
    267 
    268                 #if !defined(__CFA_NO_STATISTICS__)
    269                         if(local) {
    270                                 __tls_stats()->ready.pick.push.local++;
    271                         }
    272                 #endif
    273 
    274                 i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    275 
    276                 #if !defined(__CFA_NO_STATISTICS__)
    277                         __tls_stats()->ready.pick.push.attempt++;
    278                 #endif
    279 
    280                 // If we can't lock it retry
    281         } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
    282 
    283         bool first = false;
    284 
    285         // Actually push it
    286         #ifdef USE_SNZI
    287                 bool lane_first =
    288         #endif
    289 
    290         push(lanes.data[i], thrd);
    291 
    292         #ifdef USE_SNZI
    293                 // If this lane used to be empty we need to do more
    294                 if(lane_first) {
    295                         // Check if the entire queue used to be empty
    296                         first = !query(snzi);
    297 
    298                         // Update the snzi
    299                         arrive( snzi, i );
    300                 }
    301         #endif
    302 
    303         __tls_rand_advance_bck();
    304 
    305         // Unlock and return
    306         __atomic_unlock( &lanes.data[i].lock );
    307 
    308         __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);
    309 
    310         // Update statistics
    311         #if !defined(__CFA_NO_STATISTICS__)
    312                 #if defined(BIAS)
    313                         if( local ) __tls_stats()->ready.pick.push.lsuccess++;
    314                 #endif
    315                 __tls_stats()->ready.pick.push.success++;
    316         #endif
    317 
    318         // return whether or not the list was empty before this push
    319         return first;
    320 }
    321 
    322 static struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j);
    323 static struct $thread * try_pop(struct cluster * cltr, unsigned i);
    324 
    325 // Pop from the ready queue from a given cluster
    326 __attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) {
    327         /* paranoid */ verify( lanes.count > 0 );
    328         unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    329         int preferred;
    330         #if defined(BIAS)
    331                 // Don't bother trying locally too much
    332                 int local_tries = 8;
    333                 preferred = kernelTLS().this_processor->id * 4;
    334         #endif
    335 
    336 
    337         // As long as the list is not empty, try finding a lane that isn't empty and pop from it
    338         #ifdef USE_SNZI
    339                 while( query(snzi) ) {
    340         #else
    341                 for(25) {
    342         #endif
    343                 // Pick two lists at random
    344                 // unsigned ri = __tls_rand();
    345                 // unsigned rj = __tls_rand();
    346                 unsigned ri = __tls_rand_bck();
    347                 unsigned rj = __tls_rand_bck();
    348 
    349                 unsigned i, j;
    350                 __attribute__((unused)) bool locali, localj;
    351                 [i, locali] = idx_from_r(ri, preferred);
    352                 [j, localj] = idx_from_r(rj, preferred);
    353 
    354                 #if !defined(__CFA_NO_STATISTICS__)
    355                         if(locali) {
    356                                 __tls_stats()->ready.pick.pop.local++;
    357                         }
    358                         if(localj) {
    359                                 __tls_stats()->ready.pick.pop.local++;
    360                         }
    361                 #endif
    362 
    363                 i %= count;
    364                 j %= count;
    365 
    366                 // try popping from the 2 picked lists
    367                 struct $thread * thrd = try_pop(cltr, i, j);
    368                 if(thrd) {
    369                         #if defined(BIAS) && !defined(__CFA_NO_STATISTICS__)
    370                                 if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++;
    371                         #endif
    372                         return thrd;
    373                 }
    374         }
    375 
    376         // All lanes where empty return 0p
    377         return 0p;
    378 }
    379 
    380 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
     503// try to pop from any lanes making sure you don't miss any threads push
     504// before the start of the function
     505static inline struct $thread * search(struct cluster * cltr) with (cltr->ready_queue) {
    381506        /* paranoid */ verify( lanes.count > 0 );
    382507        unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     
    384509        for(i; count) {
    385510                unsigned idx = (offset + i) % count;
    386                 struct $thread * thrd = try_pop(cltr, idx);
     511                struct $thread * thrd = try_pop(cltr, idx __STATS(, __tls_stats()->ready.pop.search));
    387512                if(thrd) {
    388513                        return thrd;
     
    394519}
    395520
    396 
    397521//-----------------------------------------------------------------------
    398 // Given 2 indexes, pick the list with the oldest push an try to pop from it
    399 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j) with (cltr->ready_queue) {
    400         #if !defined(__CFA_NO_STATISTICS__)
    401                 __tls_stats()->ready.pick.pop.attempt++;
    402         #endif
    403 
    404         // Pick the bet list
    405         int w = i;
    406         if( __builtin_expect(!is_empty(lanes.data[j]), true) ) {
    407                 w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j;
    408         }
    409 
    410         return try_pop(cltr, w);
    411 }
    412 
    413 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w) with (cltr->ready_queue) {
    414         // Get relevant elements locally
    415         __intrusive_lane_t & lane = lanes.data[w];
    416 
    417         // If list looks empty retry
    418         if( is_empty(lane) ) return 0p;
    419 
    420         // If we can't get the lock retry
    421         if( !__atomic_try_acquire(&lane.lock) ) return 0p;
    422 
    423 
    424         // If list is empty, unlock and retry
    425         if( is_empty(lane) ) {
    426                 __atomic_unlock(&lane.lock);
    427                 return 0p;
    428         }
    429 
    430         // Actually pop the list
    431         struct $thread * thrd;
    432         thrd = pop(lane);
    433 
    434         /* paranoid */ verify(thrd);
    435         /* paranoid */ verify(lane.lock);
    436 
    437         #ifdef USE_SNZI
    438                 // If this was the last element in the lane
    439                 if(emptied) {
    440                         depart( snzi, w );
    441                 }
    442         #endif
    443 
    444         // Unlock and return
    445         __atomic_unlock(&lane.lock);
    446 
    447         // Update statistics
    448         #if !defined(__CFA_NO_STATISTICS__)
    449                 __tls_stats()->ready.pick.pop.success++;
    450         #endif
    451 
    452         // Update the thread bias
    453         thrd->link.preferred = w / 4;
    454 
    455         // return the popped thread
    456         return thrd;
    457 }
    458 //-----------------------------------------------------------------------
    459 
    460 bool remove_head(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
    461         for(i; lanes.count) {
    462                 __intrusive_lane_t & lane = lanes.data[i];
    463 
    464                 bool removed = false;
    465 
    466                 __atomic_acquire(&lane.lock);
    467                         if(head(lane)->link.next == thrd) {
    468                                 $thread * pthrd;
    469                                 pthrd = pop(lane);
    470 
    471                                 /* paranoid */ verify( pthrd == thrd );
    472 
    473                                 removed = true;
    474                                 #ifdef USE_SNZI
    475                                         if(emptied) {
    476                                                 depart( snzi, i );
    477                                         }
    478                                 #endif
    479                         }
    480                 __atomic_unlock(&lane.lock);
    481 
    482                 if( removed ) return true;
    483         }
    484         return false;
    485 }
    486 
    487 //-----------------------------------------------------------------------
    488 
     522// Check that all the intrusive queues in the data structure are still consistent
    489523static void check( __ready_queue_t & q ) with (q) {
    490         #if defined(__CFA_WITH_VERIFY__)
     524        #if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC)
    491525                {
    492526                        for( idx ; lanes.count ) {
     
    499533                                assert(tail(sl)->link.prev->link.next == tail(sl) );
    500534
    501                                 if(sl.before.link.ts == 0l) {
     535                                if(is_empty(sl)) {
    502536                                        assert(tail(sl)->link.prev == head(sl));
    503537                                        assert(head(sl)->link.next == tail(sl));
     
    511545}
    512546
     547//-----------------------------------------------------------------------
     548// Given 2 indexes, pick the list with the oldest push an try to pop from it
     549static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) {
     550        // Pick the bet list
     551        int w = i;
     552        if( __builtin_expect(!is_empty(lanes.data[j]), true) ) {
     553                w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j;
     554        }
     555
     556        return try_pop(cltr, w __STATS(, stats));
     557}
     558
    513559// Call this function of the intrusive list was moved using memcpy
    514560// fixes the list so that the pointers back to anchors aren't left dangling
    515561static inline void fix(__intrusive_lane_t & ll) {
    516         // if the list is not empty then follow he pointer and fix its reverse
    517         if(!is_empty(ll)) {
    518                 head(ll)->link.next->link.prev = head(ll);
    519                 tail(ll)->link.prev->link.next = tail(ll);
    520         }
    521         // Otherwise just reset the list
    522         else {
    523                 verify(tail(ll)->link.next == 0p);
    524                 tail(ll)->link.prev = head(ll);
    525                 head(ll)->link.next = tail(ll);
    526                 verify(head(ll)->link.prev == 0p);
    527         }
     562        #if !defined(USE_MPSC)
     563                // if the list is not empty then follow he pointer and fix its reverse
     564                if(!is_empty(ll)) {
     565                        head(ll)->link.next->link.prev = head(ll);
     566                        tail(ll)->link.prev->link.next = tail(ll);
     567                }
     568                // Otherwise just reset the list
     569                else {
     570                        verify(tail(ll)->link.next == 0p);
     571                        tail(ll)->link.prev = head(ll);
     572                        head(ll)->link.next = tail(ll);
     573                        verify(head(ll)->link.prev == 0p);
     574                }
     575        #endif
     576}
     577
     578static void assign_list(unsigned & value, dlist(processor, processor) & list, unsigned count) {
     579        processor * it = &list`first;
     580        for(unsigned i = 0; i < count; i++) {
     581                /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
     582                it->rdq.id = value;
     583                it->rdq.target = -1u;
     584                value += READYQ_SHARD_FACTOR;
     585                it = &(*it)`next;
     586        }
     587}
     588
     589static void reassign_cltr_id(struct cluster * cltr) {
     590        unsigned preferred = 0;
     591        assign_list(preferred, cltr->procs.actives, cltr->procs.total - cltr->procs.idle);
     592        assign_list(preferred, cltr->procs.idles  , cltr->procs.idle );
     593}
     594
     595static void fix_times( struct cluster * cltr ) with( cltr->ready_queue ) {
     596        #if defined(USE_WORK_STEALING)
     597                lanes.tscs = alloc(lanes.count, lanes.tscs`realloc);
     598                for(i; lanes.count) {
     599                        lanes.tscs[i].tv = ts(lanes.data[i]);
     600                }
     601        #endif
    528602}
    529603
    530604// Grow the ready queue
    531 void ready_queue_grow  (struct cluster * cltr, int target) {
     605void ready_queue_grow(struct cluster * cltr) {
     606        size_t ncount;
     607        int target = cltr->procs.total;
     608
    532609        /* paranoid */ verify( ready_mutate_islocked() );
    533610        __cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue\n");
     
    538615        // grow the ready queue
    539616        with( cltr->ready_queue ) {
    540                 #ifdef USE_SNZI
    541                         ^(snzi){};
    542                 #endif
    543 
    544617                // Find new count
    545618                // Make sure we always have atleast 1 list
    546                 size_t ncount = target >= 2 ? target * 4: 1;
     619                if(target >= 2) {
     620                        ncount = target * READYQ_SHARD_FACTOR;
     621                } else {
     622                        ncount = SEQUENTIAL_SHARD;
     623                }
    547624
    548625                // Allocate new array (uses realloc and memcpies the data)
     
    561638                // Update original
    562639                lanes.count = ncount;
    563 
    564                 #ifdef USE_SNZI
    565                         // Re-create the snzi
    566                         snzi{ log2( lanes.count / 8 ) };
    567                         for( idx; (size_t)lanes.count ) {
    568                                 if( !is_empty(lanes.data[idx]) ) {
    569                                         arrive(snzi, idx);
    570                                 }
    571                         }
    572                 #endif
    573         }
     640        }
     641
     642        fix_times(cltr);
     643
     644        reassign_cltr_id(cltr);
    574645
    575646        // Make sure that everything is consistent
     
    582653
    583654// Shrink the ready queue
    584 void ready_queue_shrink(struct cluster * cltr, int target) {
     655void ready_queue_shrink(struct cluster * cltr) {
    585656        /* paranoid */ verify( ready_mutate_islocked() );
    586657        __cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue\n");
     
    589660        /* paranoid */ check( cltr->ready_queue );
    590661
     662        int target = cltr->procs.total;
     663
    591664        with( cltr->ready_queue ) {
    592                 #ifdef USE_SNZI
    593                         ^(snzi){};
    594                 #endif
    595 
    596665                // Remember old count
    597666                size_t ocount = lanes.count;
     
    599668                // Find new count
    600669                // Make sure we always have atleast 1 list
    601                 lanes.count = target >= 2 ? target * 4: 1;
     670                lanes.count = target >= 2 ? target * READYQ_SHARD_FACTOR: SEQUENTIAL_SHARD;
    602671                /* paranoid */ verify( ocount >= lanes.count );
    603                 /* paranoid */ verify( lanes.count == target * 4 || target < 2 );
     672                /* paranoid */ verify( lanes.count == target * READYQ_SHARD_FACTOR || target < 2 );
    604673
    605674                // for printing count the number of displaced threads
     
    644713                        fix(lanes.data[idx]);
    645714                }
    646 
    647                 #ifdef USE_SNZI
    648                         // Re-create the snzi
    649                         snzi{ log2( lanes.count / 8 ) };
    650                         for( idx; (size_t)lanes.count ) {
    651                                 if( !is_empty(lanes.data[idx]) ) {
    652                                         arrive(snzi, idx);
    653                                 }
    654                         }
    655                 #endif
    656         }
     715        }
     716
     717        fix_times(cltr);
     718
     719        reassign_cltr_id(cltr);
    657720
    658721        // Make sure that everything is consistent
  • libcfa/src/concurrency/ready_subqueue.hfa

    rfeacef9 r5407cdc  
    22
    33#define __CFA_NO_SCHED_STATS__
     4
     5#include "containers/queueLockFree.hfa"
    46
    57// Intrusives lanes which are used by the relaxed ready queue
    68struct __attribute__((aligned(128))) __intrusive_lane_t {
    79
    8         // anchor for the head and the tail of the queue
    9         __attribute__((aligned(128))) struct __sentinel_t {
    10                 // Link lists fields
    11                 // instrusive link field for threads
    12                 // must be exactly as in $thread
    13                 __thread_desc_link link;
    14         } before, after;
     10        #if defined(USE_MPSC)
     11                mpsc_queue($thread) queue;
     12                __attribute__((aligned(128)))
     13        #else
     14                // anchor for the head and the tail of the queue
     15                __attribute__((aligned(128))) struct __sentinel_t {
     16                        // Link lists fields
     17                        // instrusive link field for threads
     18                        // must be exactly as in $thread
     19                        __thread_desc_link link;
     20                } before, after;
     21        #endif
    1522
    1623        // spin lock protecting the queue
     
    3542// Get the head pointer (one before the first element) from the anchor
    3643static inline $thread * head(const __intrusive_lane_t & this) {
    37         $thread * rhead = ($thread *)(
    38                 (uintptr_t)( &this.before ) - offsetof( $thread, link )
    39         );
    40         /* paranoid */ verify(rhead);
    41         return rhead;
     44        #if defined(USE_MPSC)
     45                return this.queue.head;
     46        #else
     47                $thread * rhead = ($thread *)(
     48                        (uintptr_t)( &this.before ) - offsetof( $thread, link )
     49                );
     50                /* paranoid */ verify(rhead);
     51                return rhead;
     52        #endif
    4253}
    4354
    4455// Get the tail pointer (one after the last element) from the anchor
    4556static inline $thread * tail(const __intrusive_lane_t & this) {
    46         $thread * rtail = ($thread *)(
    47                 (uintptr_t)( &this.after ) - offsetof( $thread, link )
    48         );
    49         /* paranoid */ verify(rtail);
    50         return rtail;
     57        #if defined(USE_MPSC)
     58                return this.queue.tail;
     59        #else
     60                $thread * rtail = ($thread *)(
     61                        (uintptr_t)( &this.after ) - offsetof( $thread, link )
     62                );
     63                /* paranoid */ verify(rtail);
     64                return rtail;
     65        #endif
    5166}
    5267
     
    5570        this.lock = false;
    5671
    57         this.before.link.prev = 0p;
    58         this.before.link.next = tail(this);
    59         this.before.link.ts   = 0;
    60 
    61         this.after .link.prev = head(this);
    62         this.after .link.next = 0p;
    63         this.after .link.ts   = 0;
    64 
    65         #if !defined(__CFA_NO_SCHED_STATS__)
    66                 this.stat.diff = 0;
    67                 this.stat.push = 0;
    68                 this.stat.pop  = 0;
    69         #endif
    70 
    71         // We add a boat-load of assertions here because the anchor code is very fragile
    72         /* paranoid */ verify(((uintptr_t)( head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.before));
    73         /* paranoid */ verify(((uintptr_t)( tail(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.after ));
    74         /* paranoid */ verify(head(this)->link.prev == 0p );
    75         /* paranoid */ verify(head(this)->link.next == tail(this) );
    76         /* paranoid */ verify(tail(this)->link.next == 0p );
    77         /* paranoid */ verify(tail(this)->link.prev == head(this) );
    78         /* paranoid */ verify(&head(this)->link.prev == &this.before.link.prev );
    79         /* paranoid */ verify(&head(this)->link.next == &this.before.link.next );
    80         /* paranoid */ verify(&tail(this)->link.prev == &this.after .link.prev );
    81         /* paranoid */ verify(&tail(this)->link.next == &this.after .link.next );
    82         /* paranoid */ verify(__alignof__(__intrusive_lane_t) == 128);
    83         /* paranoid */ verify(__alignof__(this) == 128);
    84         /* paranoid */ verifyf(((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128));
     72        #if !defined(USE_MPSC)
     73                this.before.link.prev = 0p;
     74                this.before.link.next = tail(this);
     75                this.before.link.ts   = 0;
     76
     77                this.after .link.prev = head(this);
     78                this.after .link.next = 0p;
     79                this.after .link.ts   = 0;
     80
     81                #if !defined(__CFA_NO_SCHED_STATS__)
     82                        this.stat.diff = 0;
     83                        this.stat.push = 0;
     84                        this.stat.pop  = 0;
     85                #endif
     86
     87                // We add a boat-load of assertions here because the anchor code is very fragile
     88                /* paranoid */ verify(((uintptr_t)( head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.before));
     89                /* paranoid */ verify(((uintptr_t)( tail(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.after ));
     90                /* paranoid */ verify(head(this)->link.prev == 0p );
     91                /* paranoid */ verify(head(this)->link.next == tail(this) );
     92                /* paranoid */ verify(tail(this)->link.next == 0p );
     93                /* paranoid */ verify(tail(this)->link.prev == head(this) );
     94                /* paranoid */ verify(&head(this)->link.prev == &this.before.link.prev );
     95                /* paranoid */ verify(&head(this)->link.next == &this.before.link.next );
     96                /* paranoid */ verify(&tail(this)->link.prev == &this.after .link.prev );
     97                /* paranoid */ verify(&tail(this)->link.next == &this.after .link.next );
     98                /* paranoid */ verify(__alignof__(__intrusive_lane_t) == 128);
     99                /* paranoid */ verify(__alignof__(this) == 128);
     100                /* paranoid */ verifyf(((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128));
     101        #endif
    85102}
    86103
    87104// Dtor is trivial
    88105void ^?{}( __intrusive_lane_t & this ) {
    89         // Make sure the list is empty
    90         /* paranoid */ verify(head(this)->link.prev == 0p );
    91         /* paranoid */ verify(head(this)->link.next == tail(this) );
    92         /* paranoid */ verify(tail(this)->link.next == 0p );
    93         /* paranoid */ verify(tail(this)->link.prev == head(this) );
     106        #if !defined(USE_MPSC)
     107                // Make sure the list is empty
     108                /* paranoid */ verify(head(this)->link.prev == 0p );
     109                /* paranoid */ verify(head(this)->link.next == tail(this) );
     110                /* paranoid */ verify(tail(this)->link.next == 0p );
     111                /* paranoid */ verify(tail(this)->link.prev == head(this) );
     112        #endif
    94113}
    95114
     
    97116// returns true of lane was empty before push, false otherwise
    98117bool push(__intrusive_lane_t & this, $thread * node) {
    99         #if defined(__CFA_WITH_VERIFY__)
    100                 /* paranoid */ verify(this.lock);
    101                 /* paranoid */ verify(node->link.ts != 0);
    102                 /* paranoid */ verify(node->link.next == 0p);
    103                 /* paranoid */ verify(node->link.prev == 0p);
    104                 /* paranoid */ verify(tail(this)->link.next == 0p);
    105                 /* paranoid */ verify(head(this)->link.prev == 0p);
    106 
     118        #if defined(USE_MPSC)
     119                inline $thread * volatile & ?`next ( $thread * this )  __attribute__((const)) {
     120                        return this->link.next;
     121                }
     122                push(this.queue, node);
     123        #else
     124                #if defined(__CFA_WITH_VERIFY__)
     125                        /* paranoid */ verify(this.lock);
     126                        /* paranoid */ verify(node->link.ts != 0);
     127                        /* paranoid */ verify(node->link.next == 0p);
     128                        /* paranoid */ verify(node->link.prev == 0p);
     129                        /* paranoid */ verify(tail(this)->link.next == 0p);
     130                        /* paranoid */ verify(head(this)->link.prev == 0p);
     131
     132                        if(this.before.link.ts == 0l) {
     133                                /* paranoid */ verify(tail(this)->link.prev == head(this));
     134                                /* paranoid */ verify(head(this)->link.next == tail(this));
     135                        } else {
     136                                /* paranoid */ verify(tail(this)->link.prev != head(this));
     137                                /* paranoid */ verify(head(this)->link.next != tail(this));
     138                        }
     139                #endif
     140
     141                // Get the relevant nodes locally
     142                $thread * tail = tail(this);
     143                $thread * prev = tail->link.prev;
     144
     145                // Do the push
     146                node->link.next = tail;
     147                node->link.prev = prev;
     148                prev->link.next = node;
     149                tail->link.prev = node;
     150
     151                // Update stats
     152                #if !defined(__CFA_NO_SCHED_STATS__)
     153                        this.stat.diff++;
     154                        this.stat.push++;
     155                #endif
     156
     157                verify(node->link.next == tail(this));
     158
     159                // Check if the queue used to be empty
    107160                if(this.before.link.ts == 0l) {
    108                         /* paranoid */ verify(tail(this)->link.prev == head(this));
    109                         /* paranoid */ verify(head(this)->link.next == tail(this));
    110                 } else {
    111                         /* paranoid */ verify(tail(this)->link.prev != head(this));
    112                         /* paranoid */ verify(head(this)->link.next != tail(this));
    113                 }
    114         #endif
    115 
    116         // Get the relevant nodes locally
    117         $thread * tail = tail(this);
    118         $thread * prev = tail->link.prev;
    119 
    120         // Do the push
    121         node->link.next = tail;
    122         node->link.prev = prev;
    123         prev->link.next = node;
    124         tail->link.prev = node;
    125 
    126         // Update stats
    127         #if !defined(__CFA_NO_SCHED_STATS__)
    128                 this.stat.diff++;
    129                 this.stat.push++;
    130         #endif
    131 
    132         verify(node->link.next == tail(this));
    133 
    134         // Check if the queue used to be empty
    135         if(this.before.link.ts == 0l) {
    136                 this.before.link.ts = node->link.ts;
    137                 /* paranoid */ verify(node->link.prev == head(this));
    138                 return true;
    139         }
    140         return false;
     161                        this.before.link.ts = node->link.ts;
     162                        /* paranoid */ verify(node->link.prev == head(this));
     163                        return true;
     164                }
     165                return false;
     166        #endif
    141167}
    142168
     
    146172$thread * pop(__intrusive_lane_t & this) {
    147173        /* paranoid */ verify(this.lock);
    148         /* paranoid */ verify(this.before.link.ts != 0ul);
    149 
    150         // Get anchors locally
    151         $thread * head = head(this);
    152         $thread * tail = tail(this);
    153 
    154         // Get the relevant nodes locally
    155         $thread * node = head->link.next;
    156         $thread * next = node->link.next;
    157 
    158         /* paranoid */ verify(node != tail);
    159         /* paranoid */ verify(node);
    160 
    161         // Do the pop
    162         head->link.next = next;
    163         next->link.prev = head;
    164         node->link.next = 0p;
    165         node->link.prev = 0p;
    166 
    167         // Update head time stamp
    168         this.before.link.ts = next->link.ts;
    169 
    170         // Update stats
    171         #ifndef __CFA_NO_SCHED_STATS__
    172                 this.stat.diff--;
    173                 this.stat.pop ++;
    174         #endif
    175 
    176         // Check if we emptied list and return accordingly
    177         /* paranoid */ verify(tail(this)->link.next == 0p);
    178         /* paranoid */ verify(head(this)->link.prev == 0p);
    179         if(next == tail) {
    180                 /* paranoid */ verify(this.before.link.ts == 0);
    181                 /* paranoid */ verify(tail(this)->link.prev == head(this));
    182                 /* paranoid */ verify(head(this)->link.next == tail(this));
    183                 return node;
    184         }
    185         else {
    186                 /* paranoid */ verify(next->link.ts != 0);
    187                 /* paranoid */ verify(tail(this)->link.prev != head(this));
    188                 /* paranoid */ verify(head(this)->link.next != tail(this));
    189                 /* paranoid */ verify(this.before.link.ts != 0);
    190                 return node;
    191         }
     174        #if defined(USE_MPSC)
     175                inline $thread * volatile & ?`next ( $thread * this )  __attribute__((const)) {
     176                        return this->link.next;
     177                }
     178                return pop(this.queue);
     179        #else
     180                /* paranoid */ verify(this.before.link.ts != 0ul);
     181
     182                // Get anchors locally
     183                $thread * head = head(this);
     184                $thread * tail = tail(this);
     185
     186                // Get the relevant nodes locally
     187                $thread * node = head->link.next;
     188                $thread * next = node->link.next;
     189
     190                /* paranoid */ verify(node != tail);
     191                /* paranoid */ verify(node);
     192
     193                // Do the pop
     194                head->link.next = next;
     195                next->link.prev = head;
     196                node->link.next = 0p;
     197                node->link.prev = 0p;
     198
     199                // Update head time stamp
     200                this.before.link.ts = next->link.ts;
     201
     202                // Update stats
     203                #ifndef __CFA_NO_SCHED_STATS__
     204                        this.stat.diff--;
     205                        this.stat.pop ++;
     206                #endif
     207
     208                // Check if we emptied list and return accordingly
     209                /* paranoid */ verify(tail(this)->link.next == 0p);
     210                /* paranoid */ verify(head(this)->link.prev == 0p);
     211                if(next == tail) {
     212                        /* paranoid */ verify(this.before.link.ts == 0);
     213                        /* paranoid */ verify(tail(this)->link.prev == head(this));
     214                        /* paranoid */ verify(head(this)->link.next == tail(this));
     215                        return node;
     216                }
     217                else {
     218                        /* paranoid */ verify(next->link.ts != 0);
     219                        /* paranoid */ verify(tail(this)->link.prev != head(this));
     220                        /* paranoid */ verify(head(this)->link.next != tail(this));
     221                        /* paranoid */ verify(this.before.link.ts != 0);
     222                        return node;
     223                }
     224        #endif
    192225}
    193226
    194227// Check whether or not list is empty
    195228static inline bool is_empty(__intrusive_lane_t & this) {
    196         // Cannot verify here since it may not be locked
    197         return this.before.link.ts == 0;
     229        #if defined(USE_MPSC)
     230                return this.queue.head == 0p;
     231        #else
     232                // Cannot verify here since it may not be locked
     233                return this.before.link.ts == 0;
     234        #endif
    198235}
    199236
    200237// Return the timestamp
    201238static inline unsigned long long ts(__intrusive_lane_t & this) {
    202         // Cannot verify here since it may not be locked
    203         return this.before.link.ts;
    204 }
     239        #if defined(USE_MPSC)
     240                $thread * tl = this.queue.head;
     241                if(!tl) return -1ull;
     242                return tl->link.ts;
     243        #else
     244                // Cannot verify here since it may not be locked
     245                return this.before.link.ts;
     246        #endif
     247}
     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

    rfeacef9 r5407cdc  
    55#include <inttypes.h>
    66#include "bits/debug.hfa"
     7#include "bits/locks.hfa"
    78#include "stats.hfa"
     9#include "strstream.hfa"
    810
    911#if !defined(__CFA_NO_STATISTICS__)
    1012        void __init_stats( struct __stats_t * stats ) {
    11                 stats->ready.pick.push.attempt  = 0;
    12                 stats->ready.pick.push.success  = 0;
    13                 stats->ready.pick.push.local    = 0;
    14                 stats->ready.pick.push.lsuccess = 0;
    15                 stats->ready.pick.pop .probe    = 0;
    16                 stats->ready.pick.pop .attempt  = 0;
    17                 stats->ready.pick.pop .success  = 0;
    18                 stats->ready.pick.pop .local    = 0;
    19                 stats->ready.pick.pop .lsuccess = 0;
     13                stats->ready.push.local.attempt = 0;
     14                stats->ready.push.local.success = 0;
     15                stats->ready.push.share.attempt = 0;
     16                stats->ready.push.share.success = 0;
     17                stats->ready.push.extrn.attempt = 0;
     18                stats->ready.push.extrn.success = 0;
     19                stats->ready.pop.local .attempt = 0;
     20                stats->ready.pop.local .success = 0;
     21                stats->ready.pop.local .elock   = 0;
     22                stats->ready.pop.local .eempty  = 0;
     23                stats->ready.pop.local .espec   = 0;
     24                stats->ready.pop.help  .attempt = 0;
     25                stats->ready.pop.help  .success = 0;
     26                stats->ready.pop.help  .elock   = 0;
     27                stats->ready.pop.help  .eempty  = 0;
     28                stats->ready.pop.help  .espec   = 0;
     29                stats->ready.pop.steal .attempt = 0;
     30                stats->ready.pop.steal .success = 0;
     31                stats->ready.pop.steal .elock   = 0;
     32                stats->ready.pop.steal .eempty  = 0;
     33                stats->ready.pop.steal .espec   = 0;
     34                stats->ready.pop.search.attempt = 0;
     35                stats->ready.pop.search.success = 0;
     36                stats->ready.pop.search.elock   = 0;
     37                stats->ready.pop.search.eempty  = 0;
     38                stats->ready.pop.search.espec   = 0;
    2039                stats->ready.threads.migration = 0;
     40                stats->ready.threads.extunpark = 0;
     41                stats->ready.threads.threads   = 0;
    2142                stats->ready.sleep.halts   = 0;
    2243                stats->ready.sleep.cancels = 0;
     
    2546
    2647                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    27                         stats->io.submit_q.submit_avg.rdy = 0;
    28                         stats->io.submit_q.submit_avg.csm = 0;
    29                         stats->io.submit_q.submit_avg.cnt = 0;
    30                         stats->io.submit_q.look_avg.val   = 0;
    31                         stats->io.submit_q.look_avg.cnt   = 0;
    32                         stats->io.submit_q.look_avg.block = 0;
    33                         stats->io.submit_q.alloc_avg.val   = 0;
    34                         stats->io.submit_q.alloc_avg.cnt   = 0;
    35                         stats->io.submit_q.alloc_avg.block = 0;
    36                         stats->io.submit_q.helped = 0;
    37                         stats->io.submit_q.leader = 0;
    38                         stats->io.submit_q.busy   = 0;
    39                         stats->io.complete_q.completed_avg.val = 0;
    40                         stats->io.complete_q.completed_avg.cnt = 0;
    41                         stats->io.complete_q.blocks = 0;
     48                        stats->io.alloc.fast        = 0;
     49                        stats->io.alloc.slow        = 0;
     50                        stats->io.alloc.fail        = 0;
     51                        stats->io.alloc.revoke      = 0;
     52                        stats->io.alloc.block       = 0;
     53                        stats->io.submit.fast       = 0;
     54                        stats->io.submit.slow       = 0;
     55                        stats->io.flush.external    = 0;
     56                        stats->io.calls.flush       = 0;
     57                        stats->io.calls.submitted   = 0;
     58                        stats->io.calls.drain       = 0;
     59                        stats->io.calls.completed   = 0;
     60                        stats->io.calls.errors.busy = 0;
     61                        stats->io.poller.sleeps     = 0;
     62                #endif
     63
     64                #if defined(CFA_STATS_ARRAY)
     65                        stats->array.values = alloc(CFA_STATS_ARRAY);
     66                        stats->array.cnt = 0;
    4267                #endif
    4368        }
    4469
    4570        void __tally_stats( struct __stats_t * cltr, struct __stats_t * proc ) {
    46                 __atomic_fetch_add( &cltr->ready.pick.push.attempt , proc->ready.pick.push.attempt , __ATOMIC_SEQ_CST ); proc->ready.pick.push.attempt  = 0;
    47                 __atomic_fetch_add( &cltr->ready.pick.push.success , proc->ready.pick.push.success , __ATOMIC_SEQ_CST ); proc->ready.pick.push.success  = 0;
    48                 __atomic_fetch_add( &cltr->ready.pick.push.local   , proc->ready.pick.push.local   , __ATOMIC_SEQ_CST ); proc->ready.pick.push.local    = 0;
    49                 __atomic_fetch_add( &cltr->ready.pick.push.lsuccess, proc->ready.pick.push.lsuccess, __ATOMIC_SEQ_CST ); proc->ready.pick.push.lsuccess = 0;
    50                 __atomic_fetch_add( &cltr->ready.pick.pop .probe   , proc->ready.pick.pop .probe   , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .probe    = 0;
    51                 __atomic_fetch_add( &cltr->ready.pick.pop .attempt , proc->ready.pick.pop .attempt , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .attempt  = 0;
    52                 __atomic_fetch_add( &cltr->ready.pick.pop .success , proc->ready.pick.pop .success , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .success  = 0;
    53                 __atomic_fetch_add( &cltr->ready.pick.pop .local   , proc->ready.pick.pop .local   , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .local    = 0;
    54                 __atomic_fetch_add( &cltr->ready.pick.pop .lsuccess, proc->ready.pick.pop .lsuccess, __ATOMIC_SEQ_CST ); proc->ready.pick.pop .lsuccess = 0;
     71                __atomic_fetch_add( &cltr->ready.push.local.attempt, proc->ready.push.local.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.local.attempt = 0;
     72                __atomic_fetch_add( &cltr->ready.push.local.success, proc->ready.push.local.success, __ATOMIC_SEQ_CST ); proc->ready.push.local.success = 0;
     73                __atomic_fetch_add( &cltr->ready.push.share.attempt, proc->ready.push.share.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.share.attempt = 0;
     74                __atomic_fetch_add( &cltr->ready.push.share.success, proc->ready.push.share.success, __ATOMIC_SEQ_CST ); proc->ready.push.share.success = 0;
     75                __atomic_fetch_add( &cltr->ready.push.extrn.attempt, proc->ready.push.extrn.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.attempt = 0;
     76                __atomic_fetch_add( &cltr->ready.push.extrn.success, proc->ready.push.extrn.success, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.success = 0;
     77                __atomic_fetch_add( &cltr->ready.pop.local .attempt, proc->ready.pop.local .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.local .attempt = 0;
     78                __atomic_fetch_add( &cltr->ready.pop.local .success, proc->ready.pop.local .success, __ATOMIC_SEQ_CST ); proc->ready.pop.local .success = 0;
     79                __atomic_fetch_add( &cltr->ready.pop.local .elock  , proc->ready.pop.local .elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.local .elock   = 0;
     80                __atomic_fetch_add( &cltr->ready.pop.local .eempty , proc->ready.pop.local .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.local .eempty  = 0;
     81                __atomic_fetch_add( &cltr->ready.pop.local .espec  , proc->ready.pop.local .espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.local .espec   = 0;
     82                __atomic_fetch_add( &cltr->ready.pop.help  .attempt, proc->ready.pop.help  .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.help  .attempt = 0;
     83                __atomic_fetch_add( &cltr->ready.pop.help  .success, proc->ready.pop.help  .success, __ATOMIC_SEQ_CST ); proc->ready.pop.help  .success = 0;
     84                __atomic_fetch_add( &cltr->ready.pop.help  .elock  , proc->ready.pop.help  .elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.help  .elock   = 0;
     85                __atomic_fetch_add( &cltr->ready.pop.help  .eempty , proc->ready.pop.help  .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.help  .eempty  = 0;
     86                __atomic_fetch_add( &cltr->ready.pop.help  .espec  , proc->ready.pop.help  .espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.help  .espec   = 0;
     87                __atomic_fetch_add( &cltr->ready.pop.steal .attempt, proc->ready.pop.steal .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .attempt = 0;
     88                __atomic_fetch_add( &cltr->ready.pop.steal .success, proc->ready.pop.steal .success, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .success = 0;
     89                __atomic_fetch_add( &cltr->ready.pop.steal .elock  , proc->ready.pop.steal .elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .elock   = 0;
     90                __atomic_fetch_add( &cltr->ready.pop.steal .eempty , proc->ready.pop.steal .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .eempty  = 0;
     91                __atomic_fetch_add( &cltr->ready.pop.steal .espec  , proc->ready.pop.steal .espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .espec   = 0;
     92                __atomic_fetch_add( &cltr->ready.pop.search.attempt, proc->ready.pop.search.attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.search.attempt = 0;
     93                __atomic_fetch_add( &cltr->ready.pop.search.success, proc->ready.pop.search.success, __ATOMIC_SEQ_CST ); proc->ready.pop.search.success = 0;
     94                __atomic_fetch_add( &cltr->ready.pop.search.elock  , proc->ready.pop.search.elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.search.elock   = 0;
     95                __atomic_fetch_add( &cltr->ready.pop.search.eempty , proc->ready.pop.search.eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.search.eempty  = 0;
     96                __atomic_fetch_add( &cltr->ready.pop.search.espec  , proc->ready.pop.search.espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.search.espec   = 0;
    5597                __atomic_fetch_add( &cltr->ready.threads.migration , proc->ready.threads.migration , __ATOMIC_SEQ_CST ); proc->ready.threads.migration  = 0;
     98                __atomic_fetch_add( &cltr->ready.threads.extunpark , proc->ready.threads.extunpark , __ATOMIC_SEQ_CST ); proc->ready.threads.extunpark  = 0;
     99                __atomic_fetch_add( &cltr->ready.threads.threads   , proc->ready.threads.threads   , __ATOMIC_SEQ_CST ); proc->ready.threads.threads    = 0;
    56100                __atomic_fetch_add( &cltr->ready.sleep.halts       , proc->ready.sleep.halts       , __ATOMIC_SEQ_CST ); proc->ready.sleep.halts        = 0;
    57101                __atomic_fetch_add( &cltr->ready.sleep.cancels     , proc->ready.sleep.cancels     , __ATOMIC_SEQ_CST ); proc->ready.sleep.cancels      = 0;
     
    60104
    61105                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    62                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.rdy     , proc->io.submit_q.submit_avg.rdy     , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.rdy      = 0;
    63                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.csm     , proc->io.submit_q.submit_avg.csm     , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.csm      = 0;
    64                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.avl     , proc->io.submit_q.submit_avg.avl     , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.avl      = 0;
    65                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.cnt     , proc->io.submit_q.submit_avg.cnt     , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.cnt      = 0;
    66                         __atomic_fetch_add( &cltr->io.submit_q.look_avg.val       , proc->io.submit_q.look_avg.val       , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.val        = 0;
    67                         __atomic_fetch_add( &cltr->io.submit_q.look_avg.cnt       , proc->io.submit_q.look_avg.cnt       , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.cnt        = 0;
    68                         __atomic_fetch_add( &cltr->io.submit_q.look_avg.block     , proc->io.submit_q.look_avg.block     , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.block      = 0;
    69                         __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.val      , proc->io.submit_q.alloc_avg.val      , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.val       = 0;
    70                         __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.cnt      , proc->io.submit_q.alloc_avg.cnt      , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.cnt       = 0;
    71                         __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.block    , proc->io.submit_q.alloc_avg.block    , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.block     = 0;
    72                         __atomic_fetch_add( &cltr->io.submit_q.helped             , proc->io.submit_q.helped             , __ATOMIC_SEQ_CST ); proc->io.submit_q.helped              = 0;
    73                         __atomic_fetch_add( &cltr->io.submit_q.leader             , proc->io.submit_q.leader             , __ATOMIC_SEQ_CST ); proc->io.submit_q.leader              = 0;
    74                         __atomic_fetch_add( &cltr->io.submit_q.busy               , proc->io.submit_q.busy               , __ATOMIC_SEQ_CST ); proc->io.submit_q.busy                = 0;
    75                         __atomic_fetch_add( &cltr->io.complete_q.completed_avg.val, proc->io.complete_q.completed_avg.val, __ATOMIC_SEQ_CST ); proc->io.complete_q.completed_avg.val = 0;
    76                         __atomic_fetch_add( &cltr->io.complete_q.completed_avg.cnt, proc->io.complete_q.completed_avg.cnt, __ATOMIC_SEQ_CST ); proc->io.complete_q.completed_avg.cnt = 0;
    77                         __atomic_fetch_add( &cltr->io.complete_q.blocks           , proc->io.complete_q.blocks           , __ATOMIC_SEQ_CST ); proc->io.complete_q.blocks            = 0;
     106                        __atomic_fetch_add( &cltr->io.alloc.fast       , proc->io.alloc.fast       , __ATOMIC_SEQ_CST ); proc->io.alloc.fast        = 0;
     107                        __atomic_fetch_add( &cltr->io.alloc.slow       , proc->io.alloc.slow       , __ATOMIC_SEQ_CST ); proc->io.alloc.slow        = 0;
     108                        __atomic_fetch_add( &cltr->io.alloc.fail       , proc->io.alloc.fail       , __ATOMIC_SEQ_CST ); proc->io.alloc.fail        = 0;
     109                        __atomic_fetch_add( &cltr->io.alloc.revoke     , proc->io.alloc.revoke     , __ATOMIC_SEQ_CST ); proc->io.alloc.revoke      = 0;
     110                        __atomic_fetch_add( &cltr->io.alloc.block      , proc->io.alloc.block      , __ATOMIC_SEQ_CST ); proc->io.alloc.block       = 0;
     111                        __atomic_fetch_add( &cltr->io.submit.fast      , proc->io.submit.fast      , __ATOMIC_SEQ_CST ); proc->io.submit.fast       = 0;
     112                        __atomic_fetch_add( &cltr->io.submit.slow      , proc->io.submit.slow      , __ATOMIC_SEQ_CST ); proc->io.submit.slow       = 0;
     113                        __atomic_fetch_add( &cltr->io.flush.external   , proc->io.flush.external   , __ATOMIC_SEQ_CST ); proc->io.flush.external    = 0;
     114                        __atomic_fetch_add( &cltr->io.calls.flush      , proc->io.calls.flush      , __ATOMIC_SEQ_CST ); proc->io.calls.flush       = 0;
     115                        __atomic_fetch_add( &cltr->io.calls.submitted  , proc->io.calls.submitted  , __ATOMIC_SEQ_CST ); proc->io.calls.submitted   = 0;
     116                        __atomic_fetch_add( &cltr->io.calls.drain      , proc->io.calls.drain      , __ATOMIC_SEQ_CST ); proc->io.calls.drain       = 0;
     117                        __atomic_fetch_add( &cltr->io.calls.completed  , proc->io.calls.completed  , __ATOMIC_SEQ_CST ); proc->io.calls.completed   = 0;
     118                        __atomic_fetch_add( &cltr->io.calls.errors.busy, proc->io.calls.errors.busy, __ATOMIC_SEQ_CST ); proc->io.calls.errors.busy = 0;
     119                        __atomic_fetch_add( &cltr->io.poller.sleeps    , proc->io.poller.sleeps    , __ATOMIC_SEQ_CST ); proc->io.poller.sleeps     = 0;
    78120                #endif
    79121        }
    80122
     123        #define eng3(X) (ws(3, 3, unit(eng( X ))))
     124
    81125        void __print_stats( struct __stats_t * stats, int flags, const char * type, const char * name, void * id ) with( *stats ) {
    82126
     127                char buf[1024];
     128                ostrstream sstr = { buf, 1024 };
     129
    83130                if( flags & CFA_STATS_READY_Q ) {
    84                         double push_sur = (100.0 * ((double)ready.pick.push.success) / ready.pick.push.attempt);
    85                         double pop_sur  = (100.0 * ((double)ready.pick.pop .success) / ready.pick.pop .attempt);
    86 
    87                         double push_len = ((double)ready.pick.push.attempt) / ready.pick.push.success;
    88                         double pop_len  = ((double)ready.pick.pop .attempt) / ready.pick.pop .success;
    89 
    90                         double lpush_sur = (100.0 * ((double)ready.pick.push.lsuccess) / ready.pick.push.local);
    91                         double lpop_sur  = (100.0 * ((double)ready.pick.pop .lsuccess) / ready.pick.pop .local);
    92 
    93                         double lpush_len = ((double)ready.pick.push.local) / ready.pick.push.lsuccess;
    94                         double lpop_len  = ((double)ready.pick.pop .local) / ready.pick.pop .lsuccess;
    95 
    96                         __cfaabi_bits_print_safe( STDOUT_FILENO,
    97                                 "----- %s \"%s\" (%p) - Ready Q Stats -----\n"
    98                                 "- total threads run      : %'15" PRIu64 "\n"
    99                                 "- total threads scheduled: %'15" PRIu64 "\n"
    100                                 "- push average probe len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n"
    101                                 "- pop  average probe len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n"
    102                                 "- local push avg prb len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n"
    103                                 "- local pop  avg prb len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n"
    104                                 "- thread migrations      : %'15" PRIu64 "\n"
    105                                 "- Idle Sleep -\n"
    106                                 "-- halts                 : %'15" PRIu64 "\n"
    107                                 "-- cancelled halts       : %'15" PRIu64 "\n"
    108                                 "-- schedule wake         : %'15" PRIu64 "\n"
    109                                 "-- wake on exit          : %'15" PRIu64 "\n"
    110                                 "\n"
    111                                 , type, name, id
    112                                 , ready.pick.pop.success
    113                                 , ready.pick.push.success
    114                                 , push_len, push_sur, ready.pick.push.attempt
    115                                 , pop_len , pop_sur , ready.pick.pop .attempt
    116                                 , lpush_len, lpush_sur, ready.pick.push.local
    117                                 , lpop_len , lpop_sur , ready.pick.pop .local
    118                                 , ready.threads.migration
    119                                 , ready.sleep.halts, ready.sleep.cancels, ready.sleep.wakes, ready.sleep.exits
    120                         );
     131
     132                        sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - Ready Q Stats -----";
     133
     134                        uint64_t totalR = ready.pop.local.success + ready.pop.help.success + ready.pop.steal.success + ready.pop.search.success;
     135                        uint64_t totalS = ready.push.local.success + ready.push.share.success + ready.push.extrn.success;
     136                        sstr | "- totals   : " | eng3(totalR) | "run," | eng3(totalS) | "schd (" | eng3(ready.push.extrn.success) | "ext," | eng3(ready.threads.migration) | "mig," | eng3(ready.threads.extunpark) | " eupk)";
     137
     138                        double push_len = ((double)ready.push.local.attempt + ready.push.share.attempt + ready.push.extrn.attempt) / totalS;
     139                        double sLcl_len = ready.push.local.success ? ((double)ready.push.local.attempt) / ready.push.local.success : 0;
     140                        double sOth_len = ready.push.share.success ? ((double)ready.push.share.attempt) / ready.push.share.success : 0;
     141                        double sExt_len = ready.push.extrn.success ? ((double)ready.push.extrn.attempt) / ready.push.extrn.success : 0;
     142                        sstr | "- push avg : " | ws(3, 3, push_len)
     143                             | "- l: " | eng3(ready.push.local.attempt) | " (" | ws(3, 3, sLcl_len) | ")"
     144                             | ", s: " | eng3(ready.push.share.attempt) | " (" | ws(3, 3, sOth_len) | ")"
     145                             | ", e: " | eng3(ready.push.extrn.attempt) | " (" | ws(3, 3, sExt_len) | ")";
     146
     147                        double rLcl_pc = (100.0 * (double)ready.pop.local .success) / totalR;
     148                        sstr | "- local    : " | eng3(ready.pop.local .success) | "-"| ws(3, 3, rLcl_pc) | '%'
     149                             | " (" | eng3(ready.pop.local .attempt) | " try," | eng3(ready.pop.local .espec) | " spc," | eng3(ready.pop.local .elock) | " lck," | eng3(ready.pop.local .eempty) | " ept)";
     150                        double rHlp_pc = (100.0 * (double)ready.pop.help  .success) / totalR;
     151                        sstr | "- help     : " | eng3(ready.pop.help  .success) | "-"| ws(3, 3, rHlp_pc) | '%'
     152                             | " (" | eng3(ready.pop.help  .attempt) | " try," | eng3(ready.pop.help  .espec) | " spc," | eng3(ready.pop.help  .elock) | " lck," | eng3(ready.pop.help  .eempty) | " ept)";
     153                        double rStl_pc = (100.0 * (double)ready.pop.steal .success) / totalR;
     154                        sstr | "- steal    : " | eng3(ready.pop.steal .success) | "-"| ws(3, 3, rStl_pc) | '%'
     155                             | " (" | eng3(ready.pop.steal .attempt) | " try," | eng3(ready.pop.steal .espec) | " spc," | eng3(ready.pop.steal .elock) | " lck," | eng3(ready.pop.steal .eempty) | " ept)";
     156                        double rSch_pc = (100.0 * (double)ready.pop.search.success) / totalR;
     157                        sstr | "- search   : " | eng3(ready.pop.search.success) | "-"| ws(3, 3, rSch_pc) | '%'
     158                             | " (" | eng3(ready.pop.search.attempt) | " try," | eng3(ready.pop.search.espec) | " spc," | eng3(ready.pop.search.elock) | " lck," | eng3(ready.pop.search.eempty) | " ept)";
     159
     160                        sstr | "- Idle Slp : " | eng3(ready.sleep.halts) | "halt," | eng3(ready.sleep.cancels) | "cancel," | eng3(ready.sleep.wakes) | "wake," | eng3(ready.sleep.exits) | "exit";
     161                        sstr | nl;
    121162                }
    122163
    123164                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    124165                        if( flags & CFA_STATS_IO ) {
    125                                 double avgrdy = ((double)io.submit_q.submit_avg.rdy) / io.submit_q.submit_avg.cnt;
    126                                 double avgcsm = ((double)io.submit_q.submit_avg.csm) / io.submit_q.submit_avg.cnt;
    127 
    128                                 double lavgv = 0;
    129                                 double lavgb = 0;
    130                                 if(io.submit_q.look_avg.cnt != 0) {
    131                                         lavgv = ((double)io.submit_q.look_avg.val  ) / io.submit_q.look_avg.cnt;
    132                                         lavgb = ((double)io.submit_q.look_avg.block) / io.submit_q.look_avg.cnt;
    133                                 }
    134 
    135                                 double aavgv = 0;
    136                                 double aavgb = 0;
    137                                 if(io.submit_q.alloc_avg.cnt != 0) {
    138                                         aavgv = ((double)io.submit_q.alloc_avg.val  ) / io.submit_q.alloc_avg.cnt;
    139                                         aavgb = ((double)io.submit_q.alloc_avg.block) / io.submit_q.alloc_avg.cnt;
    140                                 }
    141 
    142                                 __cfaabi_bits_print_safe( STDOUT_FILENO,
    143                                         "----- %s \"%s\" (%p) - I/O Stats -----\n"
    144                                         "- total submit calls     : %'15" PRIu64 "\n"
    145                                         "- avg ready entries      : %'18.2lf\n"
    146                                         "- avg submitted entries  : %'18.2lf\n"
    147                                         "- total helped entries   : %'15" PRIu64 "\n"
    148                                         "- total leader entries   : %'15" PRIu64 "\n"
    149                                         "- total busy submit      : %'15" PRIu64 "\n"
    150                                         "- total ready search     : %'15" PRIu64 "\n"
    151                                         "- avg ready search len   : %'18.2lf\n"
    152                                         "- avg ready search block : %'18.2lf\n"
    153                                         "- total alloc search     : %'15" PRIu64 "\n"
    154                                         "- avg alloc search len   : %'18.2lf\n"
    155                                         "- avg alloc search block : %'18.2lf\n"
    156                                         "- total wait calls       : %'15" PRIu64 "\n"
    157                                         "- avg completion/wait    : %'18.2lf\n"
    158                                         "- total completion blocks: %'15" PRIu64 "\n"
    159                                         "\n"
    160                                         , type,  name, id
    161                                         , io.submit_q.submit_avg.cnt
    162                                         , avgrdy, avgcsm
    163                                         , io.submit_q.helped, io.submit_q.leader, io.submit_q.busy
    164                                         , io.submit_q.look_avg.cnt
    165                                         , lavgv, lavgb
    166                                         , io.submit_q.alloc_avg.cnt
    167                                         , aavgv, aavgb
    168                                         , io.complete_q.completed_avg.cnt
    169                                         , ((double)io.complete_q.completed_avg.val) / io.complete_q.completed_avg.cnt
    170                                         , io.complete_q.blocks
    171                                 );
     166                                sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - I/O Stats -----";
     167
     168                                uint64_t total_allocs = io.alloc.fast + io.alloc.slow;
     169                                double avgfasta = (100.0 * (double)io.alloc.fast) / total_allocs;
     170                                sstr | "- total allocations : " | eng3(io.alloc.fast) | "fast," | eng3(io.alloc.slow) | "slow (" | ws(3, 3, avgfasta) | "%)";
     171                                sstr | "-     failures      : " | eng3(io.alloc.fail) | "oom, " | eng3(io.alloc.revoke) | "rvk, " | eng3(io.alloc.block) | "blk";
     172
     173                                uint64_t total_submits = io.submit.fast + io.submit.slow;
     174                                double avgfasts = (100.0 * (double)io.submit.fast) / total_submits;
     175                                sstr | "- total submits     : " | eng3(io.submit.fast) | "fast," | eng3(io.submit.slow) | "slow (" | ws(3, 3, avgfasts) | "%)";
     176                                sstr | "- flush external    : " | eng3(io.flush.external);
     177
     178                                sstr | "- io_uring_enter    : " | eng3(io.calls.flush) | " (" | eng3(io.calls.drain) | ", " | eng3(io.calls.errors.busy) | " EBUSY)";
     179
     180                                double avgsubs = ((double)io.calls.submitted) / io.calls.flush;
     181                                double avgcomp = ((double)io.calls.completed) / io.calls.drain;
     182                                sstr | "-     submits       : " | eng3(io.calls.submitted) | "(" | ws(3, 3, avgsubs) | "/flush)";
     183                                sstr | "-     completes     : " | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)";
     184
     185                                sstr | "- poller sleeping   : " | eng3(io.poller.sleeps);
     186                                sstr | nl;
    172187                        }
    173188                #endif
     189
     190                if(flags) write( sstr, stdout );
    174191        }
     192
     193        #if defined(CFA_STATS_ARRAY)
     194                extern "C" {
     195                        #include <stdio.h>
     196                        #include <errno.h>
     197                        #include <sys/stat.h>
     198                        #include <fcntl.h>
     199                }
     200
     201                void __flush_stat( struct __stats_t * this, const char * name, void * handle) {
     202                        int ret = mkdir(".cfadata", 0755);
     203                        if(ret < 0 && errno != EEXIST) abort("Failed to create directory .cfadata: %d\n", errno);
     204
     205                        char filename[100];
     206                        snprintf(filename, 100, ".cfadata/%s%p.data", name, handle);
     207
     208                        int fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0644);
     209                        if(fd < 0) abort("Failed to create file %s: %d\n", filename, errno);
     210
     211                        for(i; this->array.cnt) {
     212                                char line[100];
     213                                size_t n = snprintf(line, 100, "%llu, %lld\n", this->array.values[i].ts, this->array.values[i].value);
     214                                write(fd, line, n);
     215                        }
     216
     217                        this->array.cnt = 0;
     218                        close(fd);
     219                }
     220
     221                static __spinlock_t stats_lock;
     222
     223                void __push_stat( struct __stats_t * this, int64_t value, bool external, const char * name, void * handle ) {
     224                        if(external) lock(stats_lock __cfaabi_dbg_ctx2);
     225
     226                        if( this->array.cnt >= CFA_STATS_ARRAY ) __flush_stat( this, name, handle );
     227
     228                        size_t idx = this->array.cnt;
     229                        this->array.cnt++;
     230
     231                        if(external) unlock(stats_lock);
     232
     233                        this->array.values[idx].ts = rdtscl();
     234                        this->array.values[idx].value = value;
     235                }
     236        #endif
    175237#endif
  • libcfa/src/concurrency/stats.hfa

    rfeacef9 r5407cdc  
    11#pragma once
     2
     3// #define CFA_STATS_ARRAY 10000
    24
    35#include <stdint.h>
     
    1416        static inline void __print_stats( struct __stats_t *, int, const char *, const char *, void * ) {}
    1517#else
     18        struct __stats_readyQ_pop_t {
     19                // number of attemps at poping something
     20                volatile uint64_t attempt;
    1621
    17         struct __attribute__((aligned(64))) __stats_readQ_t {
     22                // number of successes at poping
     23                volatile uint64_t success;
     24
     25                // number of attempts failed due to the lock being held
     26                volatile uint64_t elock;
     27
     28                // number of attempts failed due to the queue being empty (lock held)
     29                volatile uint64_t eempty;
     30
     31                // number of attempts failed due to the queue looking empty (lock not held)
     32                volatile uint64_t espec;
     33        };
     34
     35        struct __attribute__((aligned(64))) __stats_readyQ_t {
     36                // Push statistic
    1837                struct {
    19                         // Push statistic
    2038                        struct {
    21                                 // number of attemps at pushing something
     39                                // number of attemps at pushing something to preferred queues
    2240                                volatile uint64_t attempt;
    2341
    24                                 // number of successes at pushing
     42                                // number of successes at pushing to preferred queues
    2543                                volatile uint64_t success;
     44                        }
     45                        // Stats for local queue within cluster
     46                        local,
    2647
    27                                 // number of attemps at pushing something to preferred queues
    28                                 volatile uint64_t local;
     48                        // Stats for non-local queues within cluster
     49                        share,
    2950
    30                                 // number of successes at pushing to preferred queues
    31                                 volatile uint64_t lsuccess;
    32                         } push;
     51                        // Stats from outside cluster
     52                        extrn;
     53                } push;
    3354
    34                         // Pop statistic
    35                         struct {
    36                                 // number of reads of the mask
    37                                 // picking an empty __cfa_readyQ_mask_t counts here
    38                                 // but not as an attempt
    39                                 volatile uint64_t probe;
     55                // Pop statistic
     56                struct {
     57                        // pop from local queue
     58                        __stats_readyQ_pop_t local;
    4059
    41                                 // number of attemps at poping something
    42                                 volatile uint64_t attempt;
     60                        // pop before looking at local queue
     61                        __stats_readyQ_pop_t help;
    4362
    44                                 // number of successes at poping
    45                                 volatile uint64_t success;
     63                        // pop from some other queue
     64                        __stats_readyQ_pop_t steal;
    4665
    47                                 // number of attemps at poping something to preferred queues
    48                                 volatile uint64_t local;
     66                        // pop when searching queues sequentially
     67                        __stats_readyQ_pop_t search;
     68                } pop;
    4969
    50                                 // number of successes at poping to preferred queues
    51                                 volatile uint64_t lsuccess;
    52                         } pop;
    53                 } pick;
    5470                struct {
    5571                        volatile uint64_t migration;
     72                        volatile uint64_t extunpark;
     73                        volatile  int64_t threads; // number of threads in the system, includes only local change
    5674                } threads;
    5775                struct {
     
    6684                struct __attribute__((aligned(64))) __stats_io_t{
    6785                        struct {
     86                                volatile uint64_t fast;
     87                                volatile uint64_t slow;
     88                                volatile uint64_t fail;
     89                                volatile uint64_t revoke;
     90                                volatile uint64_t block;
     91                        } alloc;
     92                        struct {
     93                                volatile uint64_t fast;
     94                                volatile uint64_t slow;
     95                        } submit;
     96                        struct {
     97                                volatile uint64_t external;
     98                        } flush;
     99                        struct {
     100                                volatile uint64_t drain;
     101                                volatile uint64_t completed;
     102                                volatile uint64_t flush;
     103                                volatile uint64_t submitted;
    68104                                struct {
    69                                         volatile uint64_t rdy;
    70                                         volatile uint64_t csm;
    71                                         volatile uint64_t avl;
    72                                         volatile uint64_t cnt;
    73                                 } submit_avg;
    74                                 struct {
    75                                         volatile uint64_t val;
    76                                         volatile uint64_t cnt;
    77                                         volatile uint64_t block;
    78                                 } look_avg;
    79                                 struct {
    80                                         volatile uint64_t val;
    81                                         volatile uint64_t cnt;
    82                                         volatile uint64_t block;
    83                                 } alloc_avg;
    84                                 volatile uint64_t helped;
    85                                 volatile uint64_t leader;
    86                                 volatile uint64_t busy;
    87                         } submit_q;
     105                                        volatile uint64_t busy;
     106                                } errors;
     107                        } calls;
    88108                        struct {
    89                                 struct {
    90                                         volatile uint64_t val;
    91                                         volatile uint64_t cnt;
    92                                 } completed_avg;
    93                                 volatile uint64_t blocks;
    94                         } complete_q;
     109                                volatile uint64_t sleeps;
     110                        } poller;
     111                };
     112        #endif
     113
     114        #if defined(CFA_STATS_ARRAY)
     115                struct __stats_elem_t {
     116                        long long int ts;
     117                        int64_t value;
    95118                };
    96119        #endif
    97120
    98121        struct __attribute__((aligned(128))) __stats_t {
    99                 __stats_readQ_t ready;
     122                __stats_readyQ_t ready;
    100123                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    101124                        __stats_io_t    io;
    102125                #endif
     126
     127                #if defined(CFA_STATS_ARRAY)
     128                        struct {
     129                                __stats_elem_t * values;
     130                                volatile size_t cnt;
     131                        } array;
     132                #endif
     133
    103134        };
    104135
     
    106137        void __tally_stats( struct __stats_t *, struct __stats_t * );
    107138        void __print_stats( struct __stats_t *, int, const char *, const char *, void * );
     139        #if defined(CFA_STATS_ARRAY)
     140                void __push_stat ( struct __stats_t *, int64_t value, bool external, const char * name, void * handle);
     141                void __flush_stat( struct __stats_t *, const char *, void * );
     142        #else
     143                static inline void __push_stat ( struct __stats_t *, int64_t, bool, const char *, void * ) {}
     144                static inline void __flush_stat( struct __stats_t *, const char *, void * ) {}
     145        #endif
    108146#endif
    109147
  • libcfa/src/concurrency/thread.cfa

    rfeacef9 r5407cdc  
    3939        link.next = 0p;
    4040        link.prev = 0p;
    41         link.preferred = -1;
     41        link.preferred = -1u;
     42        last_proc = 0p;
    4243        #if defined( __CFA_WITH_VERIFY__ )
    4344                canary = 0x0D15EA5E0D15EA5Ep;
     
    6263}
    6364
    64 FORALL_DATA_INSTANCE(ThreadCancelled, (thread_t &), (thread_t))
    65 
    6665forall(T &)
    6766void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src) {
     
    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)))
     83forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))
     84    | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
    8485void ?{}( thread_dtor_guard_t & this,
    8586                T & thrd, void(*cancelHandler)(ThreadCancelled(T) &)) {
    86         $monitor * m = get_monitor(thrd);
     87        $monitor * m = get_monitor(thrd);
    8788        $thread * desc = get_thread(thrd);
    8889
     
    103104        }
    104105        desc->state = Cancelled;
    105         void(*defaultResumptionHandler)(ThreadCancelled(T) &) = 
     106        void(*defaultResumptionHandler)(ThreadCancelled(T) &) =
    106107                join ? cancelHandler : default_thread_cancel_handler;
    107108
     109        // TODO: Remove explitate vtable set once trac#186 is fixed.
    108110        ThreadCancelled(T) except;
    109         // TODO: Remove explitate vtable set once trac#186 is fixed.
    110         except.virtual_table = &get_exception_vtable(&except);
     111        except.virtual_table = &_default_vtable;
    111112        except.the_thread = &thrd;
    112113        except.the_exception = __cfaehm_cancellation_exception( cancellation );
    113         throwResume except;
     114        // Why is this cast required?
     115        throwResume (ThreadCancelled(T) &)except;
    114116
    115117        except.the_exception->virtual_table->free( except.the_exception );
     
    134136        /* paranoid */ verify( this_thrd->context.SP );
    135137
    136         __schedule_thread( this_thrd );
    137         enable_interrupts( __cfaabi_dbg_ctx );
     138        schedule_thread$( this_thrd );
     139        enable_interrupts();
    138140}
    139141
     
    158160
    159161//-----------------------------------------------------------------------------
    160 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
     162forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))
     163    | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
    161164T & join( T & this ) {
    162165        thread_dtor_guard_t guard = { this, defaultResumptionHandler };
     
    167170        disable_interrupts();
    168171        uint64_t ret = __tls_rand();
    169         enable_interrupts( __cfaabi_dbg_ctx );
     172        enable_interrupts();
    170173        return ret;
    171174}
  • libcfa/src/concurrency/thread.hfa

    rfeacef9 r5407cdc  
    3232};
    3333
    34 FORALL_DATA_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
     34EHM_FORALL_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
    3535        thread_t * the_thread;
    3636        exception_t * the_exception;
     
    4242forall(T &)
    4343const char * msg(ThreadCancelled(T) *);
    44 
    45 // define that satisfies the trait without using the thread keyword
    46 #define DECL_THREAD(X) $thread* get_thread(X& this) __attribute__((const)) { return &this.__thrd; } void main(X& this)
    4744
    4845// Inline getters for threads/coroutines/monitors
     
    8279};
    8380
    84 forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
     81forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))
     82    | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
    8583void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
    8684void ^?{}( thread_dtor_guard_t & this );
     
    128126//----------
    129127// join
    130 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
     128forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))
     129    | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
    131130T & join( T & this );
    132131
  • libcfa/src/containers/list.hfa

    rfeacef9 r5407cdc  
    8383                (this.is_terminator){ 1 };
    8484        }
    85         forall ( tInit | { void ?{}( $mgd_link(tE) &, tInit); } )
    86         static inline void ?=?( $mgd_link(tE) &this, tInit i ) {
    87                 ^?{}( this );
    88                 ?{}( this, i );
     85        static inline void ?=?( $mgd_link(tE) &this, tE* elem ) {
     86                this.elem = elem ;
     87                this.terminator = 0p;
     88                this.is_terminator = 0;
     89        }
     90        static inline void ?=?( $mgd_link(tE) &this, void * terminator ) {
     91                this.elem = 0p;
     92                this.terminator = terminator;
     93                this.is_terminator = 1;
    8994        }
    9095        struct $dlinks {
     
    181186
    182187        static inline void insert_after(Tnode &list_pos, Telem &to_insert) {
    183                 assert (&list_pos != 0p);
    184                 assert (&to_insert != 0p);
     188                verify (&list_pos != 0p);
     189                verify (&to_insert != 0p);
    185190                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
    186                 assert($prev_link(singleton_to_insert).elem == 0p);
    187                 assert($next_link(singleton_to_insert).elem == 0p);
     191                verify($prev_link(singleton_to_insert).elem == 0p);
     192                verify($next_link(singleton_to_insert).elem == 0p);
    188193                $prev_link(singleton_to_insert) = & $tempcv_n2e(list_pos);
    189194                $next_link(singleton_to_insert) = $next_link(list_pos);
     
    204209
    205210        static inline void insert_before(Tnode &list_pos, Telem &to_insert) {
    206                 assert (&list_pos != 0p);
    207                 assert (&to_insert != 0p);
     211                verify (&list_pos != 0p);
     212                verify (&to_insert != 0p);
    208213                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
    209                 assert($prev_link(singleton_to_insert).elem == 0p);
    210                 assert($next_link(singleton_to_insert).elem == 0p);
     214                verify($prev_link(singleton_to_insert).elem == 0p);
     215                verify($next_link(singleton_to_insert).elem == 0p);
    211216                $next_link(singleton_to_insert) = & $tempcv_n2e(list_pos);
    212217                $prev_link(singleton_to_insert) = $prev_link(list_pos);
     
    227232
    228233    static inline void insert_first(dlist(Tnode, Telem) &list, Telem &to_insert) {
    229                 assert (&list != 0p);
    230                 assert (&to_insert != 0p);
     234                verify (&list != 0p);
     235                verify (&to_insert != 0p);
    231236                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
    232                 assert($prev_link(singleton_to_insert).elem == 0p);
    233                 assert($next_link(singleton_to_insert).elem == 0p);
     237                verify($prev_link(singleton_to_insert).elem == 0p);
     238                verify($next_link(singleton_to_insert).elem == 0p);
    234239
    235240                $prev_link(singleton_to_insert) = (void*) &list;
     
    249254
    250255    static inline void insert_last(dlist(Tnode, Telem) &list, Telem &to_insert) {
    251                 assert (&list != 0p);
    252                 assert (&to_insert != 0p);
     256                verify (&list != 0p);
     257                verify (&to_insert != 0p);
    253258                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
    254                 assert($next_link(singleton_to_insert).elem == 0p);
    255                 assert($prev_link(singleton_to_insert).elem == 0p);
     259                verify($next_link(singleton_to_insert).elem == 0p);
     260                verify($prev_link(singleton_to_insert).elem == 0p);
    256261
    257262                $next_link(singleton_to_insert) = (void*) &list;
     
    271276
    272277    static inline void remove(Tnode &list_pos) {
    273                 assert( &list_pos != 0p );
     278                verify( &list_pos != 0p );
    274279
    275280                $mgd_link(Telem) &incoming_from_prev = *0p;
     
    308313
    309314        static inline bool ?`is_empty(dlist(Tnode, Telem) &list) {
    310                 assert( &list != 0p );
     315                verify( &list != 0p );
    311316                $dlinks(Telem) *listLinks = & list.$links;
    312317                if (listLinks->next.is_terminator) {
    313                         assert(listLinks->prev.is_terminator);
    314                         assert(listLinks->next.terminator);
    315                         assert(listLinks->prev.terminator);
     318                        verify(listLinks->prev.is_terminator);
     319                        verify(listLinks->next.terminator);
     320                        verify(listLinks->prev.terminator);
    316321                        return true;
    317322                } else {
    318                         assert(!listLinks->prev.is_terminator);
    319                         assert(listLinks->next.elem);
    320                         assert(listLinks->prev.elem);
     323                        verify(!listLinks->prev.is_terminator);
     324                        verify(listLinks->next.elem);
     325                        verify(listLinks->prev.elem);
    321326                        return false;
    322327                }
     
    324329
    325330        static inline Telem & pop_first(dlist(Tnode, Telem) &list) {
    326                 assert( &list != 0p );
    327                 assert( !list`is_empty );
     331                verify( &list != 0p );
     332                verify( !list`is_empty );
    328333                $dlinks(Telem) *listLinks = & list.$links;
    329334                Telem & first = *listLinks->next.elem;
     
    334339
    335340        static inline Telem & pop_last(dlist(Tnode, Telem) &list) {
    336                 assert( &list != 0p );
    337                 assert( !list`is_empty );
     341                verify( &list != 0p );
     342                verify( !list`is_empty );
    338343                $dlinks(Telem) *listLinks = & list.$links;
    339344                Telem & last = *listLinks->prev.elem;
  • libcfa/src/exception.c

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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, )
    67 
    68 // FORALL_DATA_INSTANCE(exception_name, (assertions...), (parameters...))
    69 // Create a polymorphic data exception. The assertion list and parameters must match. This should
    70 // appear once in each program. This just generates the polymorphic framework, see
    71 // POLY_VTABLE_INSTANCE to allow instantiations.
    72 #define FORALL_DATA_INSTANCE(exception_name, assertions, parameters) \
    73         _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters)
    74 
    75 // VTABLE_DECLARATION(exception_name)([new_features...]);
    76 // Declare a virtual table type for an exception with exception_name. You may also add features
    77 // (fields on the virtual table) by including them in the second list.
    78 #define VTABLE_DECLARATION(...) _EXC_DISPATCH(_VTABLE_DECLARATION, __VA_ARGS__)
    79 
    80 // VTABLE_INSTANCE(exception_name)(msg [, others...]);
    81 // Create the instance of the virtual table. There must be exactly one instance of a virtual table
    82 // for each exception type. This fills in most of the fields of the virtual table (uses ?=? and
    83 // ^?{}) but you must provide the message function and any other fields added in the declaration.
    84 #define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__)
    85 
    86 // FORALL_VTABLE_DECLARATION(exception_name, (assertions...), (parameters...))([new_features...]);
    87 // Declare a polymorphic virtual table type for an exception with exception_name, the given
    88 // assertions and parameters. You may also add features (fields on the virtual table). This just
    89 // generates the polymorphic framework, see POLY_VTABLE_DECLARATION to allow instantiations.
    90 #define FORALL_VTABLE_DECLARATION(exception_name, assertions, parameters) \
    91         _FORALL_VTABLE_DECLARATION(exception_name, __cfaehm_base_exception_t, assertions, parameters, )
    92 
    93 // POLY_VTABLE_DECLARATION(exception_name, types...);
    94 // Declares that an instantiation for this exception exists for the given types. This should be
    95 // visible anywhere you use the instantiation of the exception is used.
    96 #define POLY_VTABLE_DECLARATION(exception_name, ...) \
    97         VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable(exception_name(__VA_ARGS__) *); \
    98         extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name)
    99 
    100 // POLY_VTABLE_INSTANCE(exception_name, types...)(msg [, others...]);
    101 // Creates an instantiation for the given exception for the given types. This should occur only
    102 // once in the entire program. You must fill in all features, message and any others given in the
    103 // initial declaration.
    104 #define POLY_VTABLE_INSTANCE(exception_name, ...) \
    105         _POLY_VTABLE_INSTANCE(exception_name, __cfaehm_base_exception_t, __VA_ARGS__)
    106 
    107 // VTABLE_TYPE(exception_name) | VTABLE_NAME(exception_name)
    108 // Get the name of the vtable type or the name of the vtable instance for an exception type.
    109 #define VTABLE_TYPE(exception_name) struct _GLUE2(exception_name,_vtable)
    110 #define VTABLE_NAME(exception_name) _GLUE3(_,exception_name,_vtable_instance)
    111 
    112 // VTABLE_FIELD(exception_name);
    113 // FORALL_VTABLE_FIELD(exception_name, (parameters-or-types));
    114 // The declaration of the virtual table field. Should be the first declaration in a virtual type.
    115 #define VTABLE_FIELD(exception_name) VTABLE_TYPE(exception_name) const * virtual_table
    116 #define FORALL_VTABLE_FIELD(exception_name, parameters) \
    117         VTABLE_TYPE(exception_name) parameters const * virtual_table
    118 
    119 // VTABLE_INIT(object_reference, exception_name);
    120 // Sets a virtual table field on an object to the virtual table instance for the type.
    121 #define VTABLE_INIT(this, exception_name) (this).virtual_table = &VTABLE_NAME(exception_name)
    122 
    123 // VTABLE_ASSERTION(exception_name, (parameters...))
    124 // The assertion that there is an instantiation of the vtable for the exception and types.
    125 #define VTABLE_ASSERTION(exception_name, parameters) \
    126         { VTABLE_TYPE(exception_name) parameters VTABLE_NAME(exception_name); }
     66// EHM_DEFAULT_VTABLE(exception_name, (arguments))
     67// Create a declaration for a (possibly polymorphic) default vtable.
     68#define EHM_DEFAULT_VTABLE(exception_name, arguments) \
     69        _EHM_VTABLE_TYPE(exception_name) arguments & const _default_vtable
    12770
    12871// IS_EXCEPTION(exception_name [, (...parameters)])
     
    13578#define IS_TERMINATION_EXCEPTION(...) _IS_EXCEPTION(is_termination_exception, __VA_ARGS__, , ~)
    13679
    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__
     80// Macros starting with a leading underscore are internal.
    14381
    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)
     82// Create an exception type definition. must be tailing, can be polymorphic.
     83#define _EHM_EXCEPTION_STRUCT(exception_name, forall_clause, parameters) \
     84        forall_clause struct exception_name { \
     85                _EHM_VTABLE_TYPE(exception_name) parameters const * virtual_table; \
     86                _CLOSE
    15187
    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))
     88// Create a (possibly polymorphic) virtual table forward declaration.
     89#define _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) \
     90        extern const _EHM_VTABLE_TYPE(exception_name) arguments table_name
    16091
    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); \
     92// Create a (possibly polymorphic) virtual table definition.
     93#define _EHM_VIRTUAL_TABLE(exception_type, arguments, table_name) \
     94        const _EHM_VTABLE_TYPE(exception_type) arguments table_name @= { \
     95                .__cfavir_typeid : &_EHM_TYPE_ID_NAME(exception_type), \
     96                .size : sizeof(struct exception_type arguments), \
     97                .copy : copy, \
     98                .^?{} : ^?{}, \
     99                .msg : msg, \
    178100        }
    179101
    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
     102// Create a (possibly polymorphic) copy function from an assignment operator.
     103#define _EHM_DEFINE_FORALL_COPY(exception_name, forall_clause, parameters) \
     104        forall_clause void copy(exception_name parameters * this, \
     105                        exception_name parameters * that) { \
     106                *this = *that; \
     107        }
    185108
    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
     109#define _EHM_DEFINE_COPY(exception_name, arguments) \
     110        void copy(exception_name arguments * this, exception_name arguments * that) { \
     111                *this = *that; \
     112        }
    194113
    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
     114// Create a (possibly polymorphic) msg function
     115#define _EHM_DEFINE_FORALL_MSG(exception_name, forall_clause, parameters) \
     116        forall_clause const char * msg(exception_name parameters * this) { \
     117                return #exception_name #parameters; \
     118        }
    207119
    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
     120#define _EHM_DEFINE_MSG(exception_name, arguments) \
     121        const char * msg(exception_name arguments * this) { \
     122                return #exception_name #arguments; \
     123        }
    219124
    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; \
     125// Produces the C compatable name of the virtual table type for a virtual type.
     126#define _EHM_VTABLE_TYPE(type_name) struct _GLUE2(type_name,_vtable)
     127
     128// Create the vtable type for exception name.
     129#define _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall_clause, parameters) \
     130        forall_clause struct exception_name; \
     131        forall_clause _EHM_VTABLE_TYPE(exception_name) { \
     132                _EHM_TYPE_ID_TYPE(exception_name) parameters const * __cfavir_typeid; \
    225133                size_t size; \
    226134                void (*copy)(exception_name parameters * this, exception_name parameters * other); \
    227135                void (*^?{})(exception_name parameters & this); \
    228136                const char * (*msg)(exception_name parameters * this); \
    229                 _CLOSE
     137        }
    230138
    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
     139// Define the function required to satify the trait for exceptions.
     140#define _EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \
     141        forall_clause inline void mark_exception( \
     142                exception_name parameters const &, \
     143                _EHM_VTABLE_TYPE(exception_name) parameters const &) {} \
     144
     145#define __EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \
     146        forall_clause inline _EHM_VTABLE_TYPE(exception_name) parameters const & \
     147                        get_exception_vtable(exception_name parameters const & this) { \
     148                /* This comes before the structure definition, but we know the offset. */ \
     149                /* return (_EHM_VTABLE_TYPE(exception_name) parameters const &)this; */ \
     150                assert(false); \
     151        }
     152
     153// Generates a new type-id structure. This is used to mangle the name of the
     154// type-id instance so it also includes polymorphic information. Must be the
     155// direct decendent of exception_t.
     156// The second field is used to recover type information about the exception.
     157#define _EHM_TYPE_ID_STRUCT(exception_name, forall_clause) \
     158        forall_clause _EHM_TYPE_ID_TYPE(exception_name) { \
     159                __cfa__parent_vtable const * parent; \
     160        }
     161
     162// Generate a new type-id value.
     163#define _EHM_TYPE_ID_VALUE(exception_name, arguments) \
     164        __attribute__(( section(".gnu.linkonce." "__cfatid_" #exception_name) )) \
     165        _EHM_TYPE_ID_TYPE(exception_name) arguments const \
     166                        _EHM_TYPE_ID_NAME(exception_name) = { \
     167                &__cfatid_exception_t, \
     168        }
     169
     170// _EHM_TYPE_ID_STRUCT and _EHM_TYPE_ID_VALUE are the two that would need to
     171// be updated to extend the hierarchy if we are still using macros when that
     172// is added.
     173
     174// Produce the C compatable name of the type-id type for an exception type.
     175#define _EHM_TYPE_ID_TYPE(exception_name) \
     176        struct _GLUE2(__cfatid_struct_, exception_name)
     177
     178// Produce the name of the instance of the type-id for an exception type.
     179#define _EHM_TYPE_ID_NAME(exception_name) _GLUE2(__cfatid_,exception_name)
    245180
    246181#define _IS_EXCEPTION(kind, exception_name, parameters, ...) \
    247         kind(exception_name parameters, VTABLE_TYPE(exception_name) parameters)
     182        kind(exception_name parameters, _EHM_VTABLE_TYPE(exception_name) parameters)
     183
     184// Internal helper macros:
     185#define _CLOSE(...) __VA_ARGS__ }
     186#define _GLUE2(left, right) left##right
  • libcfa/src/fstream.cfa

    rfeacef9 r5407cdc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 19 16:24:54 2020
    13 // Update Count     : 384
    14 //
    15 
    16 #include "fstream.hfa"
     12// Last Modified On : Tue Apr 27 22:08:57 2021
     13// Update Count     : 442
     14//
     15
     16#include "fstream.hfa"                                                                  // also includes iostream.hfa
    1717
    1818#include <stdio.h>                                                                              // vfprintf, vfscanf
    1919#include <stdlib.h>                                                                             // exit
    2020#include <stdarg.h>                                                                             // varargs
    21 #include <string.h>                                                                             // strlen
    22 #include <float.h>                                                                              // DBL_DIG, LDBL_DIG
    23 #include <complex.h>                                                                    // creal, cimag
     21#include <string.h>                                                                             // strncpy, strerror
    2422#include <assert.h>
    2523#include <errno.h>                                                                              // errno
    2624
    27 
    2825// *********************************** ofstream ***********************************
    2926
     
    3229
    3330void ?{}( ofstream & os, void * file ) {
    34         os.$file = file;
    35         os.$sepDefault = true;
    36         os.$sepOnOff = false;
    37         os.$nlOnOff = true;
    38         os.$prt = false;
    39         os.$sawNL = false;
    40         $sepSetCur( os, sepGet( os ) );
     31        os.file$ = file;
     32        os.sepDefault$ = true;
     33        os.sepOnOff$ = false;
     34        os.nlOnOff$ = true;
     35        os.prt$ = false;
     36        os.sawNL$ = false;
     37        os.acquired$ = false;
     38        sepSetCur$( os, sepGet( os ) );
    4139        sepSet( os, " " );
    4240        sepSetTuple( os, ", " );
     
    4442
    4543// private
    46 bool $sepPrt( ofstream & os ) { $setNL( os, false ); return os.$sepOnOff; }
    47 void $sepReset( ofstream & os ) { os.$sepOnOff = os.$sepDefault; }
    48 void $sepReset( ofstream & os, bool reset ) { os.$sepDefault = reset; os.$sepOnOff = os.$sepDefault; }
    49 const char * $sepGetCur( ofstream & os ) { return os.$sepCur; }
    50 void $sepSetCur( ofstream & os, const char sepCur[] ) { os.$sepCur = sepCur; }
    51 bool $getNL( ofstream & os ) { return os.$sawNL; }
    52 void $setNL( ofstream & os, bool state ) { os.$sawNL = state; }
    53 bool $getANL( ofstream & os ) { return os.$nlOnOff; }
    54 bool $getPrt( ofstream & os ) { return os.$prt; }
    55 void $setPrt( ofstream & os, bool state ) { os.$prt = state; }
     44bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
     45void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }
     46void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
     47const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }
     48void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
     49bool getNL$( ofstream & os ) { return os.sawNL$; }
     50void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; }
     51bool getANL$( ofstream & os ) { return os.nlOnOff$; }
     52bool getPrt$( ofstream & os ) { return os.prt$; }
     53void setPrt$( ofstream & os, bool state ) { os.prt$ = state; }
    5654
    5755// public
    58 void ?{}( ofstream & os ) { os.$file = 0p; }
     56void ?{}( ofstream & os ) { os.file$ = 0p; }
    5957
    6058void ?{}( ofstream & os, const char name[], const char mode[] ) {
     
    7068} // ^?{}
    7169
    72 void sepOn( ofstream & os ) { os.$sepOnOff = ! $getNL( os ); }
    73 void sepOff( ofstream & os ) { os.$sepOnOff = false; }
     70void sepOn( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); }
     71void sepOff( ofstream & os ) { os.sepOnOff$ = false; }
    7472
    7573bool sepDisable( ofstream & os ) {
    76         bool temp = os.$sepDefault;
    77         os.$sepDefault = false;
    78         $sepReset( os );
     74        bool temp = os.sepDefault$;
     75        os.sepDefault$ = false;
     76        sepReset$( os );
    7977        return temp;
    8078} // sepDisable
    8179
    8280bool sepEnable( ofstream & os ) {
    83         bool temp = os.$sepDefault;
    84         os.$sepDefault = true;
    85         if ( os.$sepOnOff ) $sepReset( os );                            // start of line ?
     81        bool temp = os.sepDefault$;
     82        os.sepDefault$ = true;
     83        if ( os.sepOnOff$ ) sepReset$( os );                            // start of line ?
    8684        return temp;
    8785} // sepEnable
    8886
    89 void nlOn( ofstream & os ) { os.$nlOnOff = true; }
    90 void nlOff( ofstream & os ) { os.$nlOnOff = false; }
    91 
    92 const char * sepGet( ofstream & os ) { return os.$separator; }
     87void nlOn( ofstream & os ) { os.nlOnOff$ = true; }
     88void nlOff( ofstream & os ) { os.nlOnOff$ = false; }
     89
     90const char * sepGet( ofstream & os ) { return os.separator$; }
    9391void sepSet( ofstream & os, const char s[] ) {
    9492        assert( s );
    95         strncpy( os.$separator, s, sepSize - 1 );
    96         os.$separator[sepSize - 1] = '\0';
     93        strncpy( os.separator$, s, ofstream_sepSize - 1 );
     94        os.separator$[ofstream_sepSize - 1] = '\0';
    9795} // sepSet
    9896
    99 const char * sepGetTuple( ofstream & os ) { return os.$tupleSeparator; }
     97const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator$; }
    10098void sepSetTuple( ofstream & os, const char s[] ) {
    10199        assert( s );
    102         strncpy( os.$tupleSeparator, s, sepSize - 1 );
    103         os.$tupleSeparator[sepSize - 1] = '\0';
     100        strncpy( os.tupleSeparator$, s, ofstream_sepSize - 1 );
     101        os.tupleSeparator$[ofstream_sepSize - 1] = '\0';
    104102} // sepSet
    105103
    106104void ends( ofstream & os ) {
    107         if ( $getANL( os ) ) nl( os );
    108         else $setPrt( os, false );                                                      // turn off
     105        if ( getANL$( os ) ) nl( os );
     106        else setPrt$( os, false );                                                      // turn off
    109107        if ( &os == &exit ) exit( EXIT_FAILURE );
    110108        if ( &os == &abort ) abort();
     109        if ( os.acquired$ ) { os.acquired$ = false; release( os ); }
    111110} // ends
    112111
    113 int fail( ofstream & os ) {
    114         return os.$file == 0 || ferror( (FILE *)(os.$file) );
     112bool fail( ofstream & os ) {
     113        return os.file$ == 0 || ferror( (FILE *)(os.file$) );
    115114} // fail
    116115
    117116int flush( ofstream & os ) {
    118         return fflush( (FILE *)(os.$file) );
     117        return fflush( (FILE *)(os.file$) );
    119118} // flush
    120119
     
    135134
    136135void close( ofstream & os ) {
    137   if ( (FILE *)(os.$file) == 0p ) return;
    138   if ( (FILE *)(os.$file) == (FILE *)stdout || (FILE *)(os.$file) == (FILE *)stderr ) return;
    139 
    140         if ( fclose( (FILE *)(os.$file) ) == EOF ) {
     136  if ( (FILE *)(os.file$) == 0p ) return;
     137  if ( (FILE *)(os.file$) == (FILE *)stdout || (FILE *)(os.file$) == (FILE *)stderr ) return;
     138
     139        if ( fclose( (FILE *)(os.file$) ) == EOF ) {
    141140                abort | IO_MSG "close output" | nl | strerror( errno );
    142141        } // if
    143         os.$file = 0p;
     142        os.file$ = 0p;
    144143} // close
    145144
     
    149148        } // if
    150149
    151         if ( fwrite( data, 1, size, (FILE *)(os.$file) ) != size ) {
     150        if ( fwrite( data, 1, size, (FILE *)(os.file$) ) != size ) {
    152151                abort | IO_MSG "write" | nl | strerror( errno );
    153152        } // if
     
    158157        va_list args;
    159158        va_start( args, format );
    160         int len = vfprintf( (FILE *)(os.$file), format, args );
     159        int len = vfprintf( (FILE *)(os.file$), format, args );
    161160        if ( len == EOF ) {
    162                 if ( ferror( (FILE *)(os.$file) ) ) {
     161                if ( ferror( (FILE *)(os.file$) ) ) {
    163162                        abort | IO_MSG "invalid write";
    164163                } // if
     
    166165        va_end( args );
    167166
    168         $setPrt( os, true );                                                            // called in output cascade
    169         $sepReset( os );                                                                        // reset separator
     167        setPrt$( os, true );                                                            // called in output cascade
     168        sepReset$( os );                                                                        // reset separator
    170169        return len;
    171170} // fmt
     171
     172inline void acquire( ofstream & os ) {
     173        lock( os.lock$ );
     174        if ( ! os.acquired$ ) os.acquired$ = true;
     175        else unlock( os.lock$ );
     176} // acquire
     177
     178inline void release( ofstream & os ) {
     179        unlock( os.lock$ );
     180} // release
     181
     182void ?{}( osacquire & acq, ofstream & os ) { &acq.os = &os; lock( os.lock$ ); }
     183void ^?{}( osacquire & acq ) { release( acq.os ); }
    172184
    173185static ofstream soutFile = { (FILE *)stdout };
     
    176188ofstream & serr = serrFile, & stderr = serrFile;
    177189
     190static ofstream lsoutFile = { (FILE *)stdout };
     191ofstream & lsout = lsoutFile;
     192
    178193static ofstream exitFile = { (FILE *)stdout };
    179194ofstream & exit = exitFile;
     
    181196ofstream & abort = abortFile;
    182197
     198ofstream & nl( ofstream & os ) {
     199        nl$( os );                                                                                      // call basic_ostream nl
     200        flush( os );
     201        return os;
     202        // (ofstream &)(os | '\n');
     203        // setPrt$( os, false );                                                        // turn off
     204        // setNL$( os, true );
     205        // flush( os );
     206        // return sepOff( os );                                                 // prepare for next line
     207} // nl
    183208
    184209// *********************************** ifstream ***********************************
     
    187212// private
    188213void ?{}( ifstream & is, void * file ) {
    189         is.$file = file;
    190         is.$nlOnOff = false;
     214        is.file$ = file;
     215        is.nlOnOff$ = false;
     216        is.acquired$ = false;
    191217} // ?{}
    192218
    193219// public
    194 void ?{}( ifstream & is ) { is.$file = 0p; }
     220void ?{}( ifstream & is ) { is.file$ = 0p; }
    195221
    196222void ?{}( ifstream & is, const char name[], const char mode[] ) {
     
    206232} // ^?{}
    207233
    208 void nlOn( ifstream & os ) { os.$nlOnOff = true; }
    209 void nlOff( ifstream & os ) { os.$nlOnOff = false; }
    210 bool getANL( ifstream & os ) { return os.$nlOnOff; }
    211 
    212 int fail( ifstream & is ) {
    213         return is.$file == 0p || ferror( (FILE *)(is.$file) );
     234void nlOn( ifstream & os ) { os.nlOnOff$ = true; }
     235void nlOff( ifstream & os ) { os.nlOnOff$ = false; }
     236bool getANL( ifstream & os ) { return os.nlOnOff$; }
     237
     238bool fail( ifstream & is ) {
     239        return is.file$ == 0p || ferror( (FILE *)(is.file$) );
    214240} // fail
    215241
     242void ends( ifstream & is ) {
     243        if ( is.acquired$ ) { is.acquired$ = false; release( is ); }
     244} // ends
     245
    216246int eof( ifstream & is ) {
    217         return feof( (FILE *)(is.$file) );
     247        return feof( (FILE *)(is.file$) );
    218248} // eof
    219249
     
    226256        } // if
    227257        #endif // __CFA_DEBUG__
    228         is.$file = file;
     258        is.file$ = file;
    229259} // open
    230260
     
    234264
    235265void close( ifstream & is ) {
    236   if ( (FILE *)(is.$file) == 0p ) return;
    237   if ( (FILE *)(is.$file) == (FILE *)stdin ) return;
    238 
    239         if ( fclose( (FILE *)(is.$file) ) == EOF ) {
     266  if ( (FILE *)(is.file$) == 0p ) return;
     267  if ( (FILE *)(is.file$) == (FILE *)stdin ) return;
     268
     269        if ( fclose( (FILE *)(is.file$) ) == EOF ) {
    240270                abort | IO_MSG "close input" | nl | strerror( errno );
    241271        } // if
    242         is.$file = 0p;
     272        is.file$ = 0p;
    243273} // close
    244274
     
    248278        } // if
    249279
    250         if ( fread( data, size, 1, (FILE *)(is.$file) ) == 0 ) {
     280        if ( fread( data, size, 1, (FILE *)(is.file$) ) == 0 ) {
    251281                abort | IO_MSG "read" | nl | strerror( errno );
    252282        } // if
     
    259289        } // if
    260290
    261         if ( ungetc( c, (FILE *)(is.$file) ) == EOF ) {
     291        if ( ungetc( c, (FILE *)(is.file$) ) == EOF ) {
    262292                abort | IO_MSG "ungetc" | nl | strerror( errno );
    263293        } // if
     
    269299
    270300        va_start( args, format );
    271         int len = vfscanf( (FILE *)(is.$file), format, args );
     301        int len = vfscanf( (FILE *)(is.file$), format, args );
    272302        if ( len == EOF ) {
    273                 if ( ferror( (FILE *)(is.$file) ) ) {
     303                if ( ferror( (FILE *)(is.file$) ) ) {
    274304                        abort | IO_MSG "invalid read";
    275305                } // if
     
    279309} // fmt
    280310
     311inline void acquire( ifstream & is ) {
     312        lock( is.lock$ );
     313        if ( ! is.acquired$ ) is.acquired$ = true;
     314        else unlock( is.lock$ );
     315} // acquire
     316
     317inline void release( ifstream & is ) {
     318        unlock( is.lock$ );
     319} // release
     320
     321void ?{}( isacquire & acq, ifstream & is ) { &acq.is = &is; lock( is.lock$ ); }
     322void ^?{}( isacquire & acq ) { release( acq.is ); }
     323
    281324static ifstream sinFile = { (FILE *)stdin };
    282325ifstream & sin = sinFile, & stdin = sinFile;
     
    286329
    287330
     331EHM_VIRTUAL_TABLE(Open_Failure, Open_Failure_main_table);
    288332void ?{}( Open_Failure & this, ofstream & ostream ) {
    289         VTABLE_INIT(this, Open_Failure);
     333        this.virtual_table = &Open_Failure_main_table;
    290334        this.ostream = &ostream;
    291335        this.tag = 1;
    292336}
    293337void ?{}( Open_Failure & this, ifstream & istream ) {
    294         VTABLE_INIT(this, Open_Failure);
     338        this.virtual_table = &Open_Failure_main_table;
    295339        this.istream = &istream;
    296340        this.tag = 0;
    297341}
    298 const char * Open_Failure_msg(Open_Failure * this) {
    299         return "Open_Failure";
    300 }
    301 VTABLE_INSTANCE(Open_Failure)(Open_Failure_msg);
    302342void throwOpen_Failure( ofstream & ostream ) {
    303343        Open_Failure exc = { ostream };
  • libcfa/src/fstream.hfa

    rfeacef9 r5407cdc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jun 19 16:29:17 2020
    13 // Update Count     : 189
     12// Last Modified On : Tue Apr 27 22:00:30 2021
     13// Update Count     : 226
    1414//
    1515
    1616#pragma once
    1717
    18 #include "bits/weakso_locks.hfa"
     18#include "bits/weakso_locks.hfa"                                                // mutex_lock
    1919#include "iostream.hfa"
    2020#include <exception.hfa>
     
    2424
    2525
    26 enum { sepSize = 16 };
     26enum { ofstream_sepSize = 16 };
    2727struct ofstream {
    28         void * $file;
    29         bool $sepDefault;
    30         bool $sepOnOff;
    31         bool $nlOnOff;
    32         bool $prt;                                                                                      // print text
    33         bool $sawNL;
    34         const char * $sepCur;
    35         char $separator[sepSize];
    36         char $tupleSeparator[sepSize];
    37 //      multiple_acquisition_lock lock;
     28        void * file$;
     29        bool sepDefault$;
     30        bool sepOnOff$;
     31        bool nlOnOff$;
     32        bool prt$;                                                                                      // print text
     33        bool sawNL$;
     34        const char * sepCur$;
     35        char separator$[ofstream_sepSize];
     36        char tupleSeparator$[ofstream_sepSize];
     37        multiple_acquisition_lock lock$;
     38        bool acquired$;
    3839}; // ofstream
    3940
     41// Satisfies ostream
     42
    4043// private
    41 bool $sepPrt( ofstream & );
    42 void $sepReset( ofstream & );
    43 void $sepReset( ofstream &, bool );
    44 const char * $sepGetCur( ofstream & );
    45 void $sepSetCur( ofstream &, const char [] );
    46 bool $getNL( ofstream & );
    47 void $setNL( ofstream &, bool );
    48 bool $getANL( ofstream & );
    49 bool $getPrt( ofstream & );
    50 void $setPrt( ofstream &, bool );
     44bool sepPrt$( ofstream & );
     45void sepReset$( ofstream & );
     46void sepReset$( ofstream &, bool );
     47const char * sepGetCur$( ofstream & );
     48void sepSetCur$( ofstream &, const char [] );
     49bool getNL$( ofstream & );
     50void setNL$( ofstream &, bool );
     51bool getANL$( ofstream & );
     52bool getPrt$( ofstream & );
     53void setPrt$( ofstream &, bool );
    5154
    5255// public
     
    6366void sepSetTuple( ofstream &, const char [] );
    6467
    65 void ends( ofstream & os );
    66 int fail( ofstream & );
     68void ends( ofstream & );
     69int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
     70
     71bool fail( ofstream & );
    6772int flush( ofstream & );
    68 void open( ofstream &, const char name[], const char mode[] );
     73void open( ofstream &, const char name[], const char mode[] ); // FIX ME: use default = "w"
    6974void open( ofstream &, const char name[] );
    7075void close( ofstream & );
    7176ofstream & write( ofstream &, const char data[], size_t size );
    72 int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
    7377
    74 void ?{}( ofstream & os );
    75 void ?{}( ofstream & os, const char name[], const char mode[] );
    76 void ?{}( ofstream & os, const char name[] );
    77 void ^?{}( ofstream & os );
     78void acquire( ofstream & );
     79void release( ofstream & );
     80
     81struct osacquire {
     82        ofstream & os;
     83};
     84void ?{}( osacquire & acq, ofstream & );
     85void ^?{}( osacquire & acq );
     86
     87void ?{}( ofstream & );
     88void ?{}( ofstream &, const char name[], const char mode[] ); // FIX ME: use default = "w"
     89void ?{}( ofstream &, const char name[] );
     90void ^?{}( ofstream & );
     91
     92// private
     93static inline ofstream & nl$( ofstream & os ) { return nl( os ); } // remember basic_ostream nl
     94// public
     95ofstream & nl( ofstream & os );                                                 // override basic_ostream nl
    7896
    7997extern ofstream & sout, & stdout, & serr, & stderr;             // aliases
     
    85103
    86104struct ifstream {
    87         void * $file;
    88         bool $nlOnOff;
     105        void * file$;
     106        bool nlOnOff$;
     107        multiple_acquisition_lock lock$;
     108        bool acquired$;
    89109}; // ifstream
     110
     111// Satisfies istream
    90112
    91113// public
     
    93115void nlOff( ifstream & );
    94116bool getANL( ifstream & );
    95 int fail( ifstream & is );
     117void ends( ifstream & );
     118int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     119
     120bool fail( ifstream & is );
    96121int eof( ifstream & is );
    97 void open( ifstream & is, const char name[], const char mode[] );
     122void open( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r"
    98123void open( ifstream & is, const char name[] );
    99124void close( ifstream & is );
    100125ifstream & read( ifstream & is, char * data, size_t size );
    101126ifstream & ungetc( ifstream & is, char c );
    102 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     127
     128void acquire( ifstream & is );
     129void release( ifstream & is );
     130
     131struct isacquire {
     132        ifstream & is;
     133};
     134void ?{}( isacquire & acq, ifstream & is );
     135void ^?{}( isacquire & acq );
    103136
    104137void ?{}( ifstream & is );
    105 void ?{}( ifstream & is, const char name[], const char mode[] );
     138void ?{}( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r"
    106139void ?{}( ifstream & is, const char name[] );
    107140void ^?{}( ifstream & is );
     
    113146
    114147
    115 DATA_EXCEPTION(Open_Failure)(
     148EHM_EXCEPTION(Open_Failure)(
    116149        union {
    117150                ofstream * ostream;
     
    122155);
    123156
    124 void ?{}( Open_Failure & this, ofstream & ostream );
    125 void ?{}( Open_Failure & this, ifstream & istream );
     157void ?{}( Open_Failure & this, ofstream & );
     158void ?{}( Open_Failure & this, ifstream & );
    126159
    127160// Local Variables: //
  • libcfa/src/gmp.hfa

    rfeacef9 r5407cdc  
    1010// Created On       : Tue Apr 19 08:43:43 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb  9 09:56:54 2020
    13 // Update Count     : 31
     12// Last Modified On : Tue Apr 20 20:59:21 2021
     13// Update Count     : 32
    1414//
    1515
     
    263263        forall( ostype & | ostream( ostype ) ) {
    264264                ostype & ?|?( ostype & os, Int mp ) {
    265                         if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     265                        if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    266266                        gmp_printf( "%Zd", mp.mpz );
    267267                        sepOn( os );
  • libcfa/src/heap.cfa

    rfeacef9 r5407cdc  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jan 10 11:20:49 2021
    13 // Update Count     : 1031
     12// Last Modified On : Tue Apr 20 21:20:48 2021
     13// Update Count     : 1033
    1414//
    1515
     
    5252static bool prtFree = false;
    5353
    54 inline bool prtFree() {
     54bool prtFree() {
    5555        return prtFree;
    5656} // prtFree
     
    11281128
    11291129        // Set the alignment for an the allocation and return previous alignment or 0 if no alignment.
    1130         size_t $malloc_alignment_set( void * addr, size_t alignment ) {
     1130        size_t malloc_alignment_set$( void * addr, size_t alignment ) {
    11311131          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
    11321132                size_t ret;
     
    11391139                } // if
    11401140                return ret;
    1141         } // $malloc_alignment_set
     1141        } // malloc_alignment_set$
    11421142
    11431143
     
    11531153
    11541154        // Set allocation is zero filled and return previous zero filled.
    1155         bool $malloc_zero_fill_set( void * addr ) {
     1155        bool malloc_zero_fill_set$( void * addr ) {
    11561156          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    11571157                HeapManager.Storage.Header * header = headerAddr( addr );
     
    11621162                header->kind.real.blockSize |= 2;                               // mark as zero filled
    11631163                return ret;
    1164         } // $malloc_zero_fill_set
     1164        } // malloc_zero_fill_set$
    11651165
    11661166
     
    11761176
    11771177        // Set allocation size and return previous size.
    1178         size_t $malloc_size_set( void * addr, size_t size ) {
     1178        size_t malloc_size_set$( void * addr, size_t size ) {
    11791179          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    11801180                HeapManager.Storage.Header * header = headerAddr( addr );
     
    11851185                header->kind.real.size = size;
    11861186                return ret;
    1187         } // $malloc_size_set
     1187        } // malloc_size_set$
    11881188
    11891189
  • libcfa/src/iostream.cfa

    rfeacef9 r5407cdc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Aug 24 08:31:35 2020
    13 // Update Count     : 1130
     12// Last Modified On : Tue Apr 27 18:01:03 2021
     13// Update Count     : 1330
    1414//
    1515
     
    3636
    3737
    38 forall( ostype & | ostream( ostype ) ) {
     38forall( ostype & | basic_ostream( ostype ) ) {
    3939        ostype & ?|?( ostype & os, bool b ) {
    40                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     40                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    4141                fmt( os, "%s", b ? "true" : "false" );
    4242                return os;
     
    4848        ostype & ?|?( ostype & os, char c ) {
    4949                fmt( os, "%c", c );
    50                 if ( c == '\n' ) $setNL( os, true );
     50                if ( c == '\n' ) setNL$( os, true );
    5151                return sepOff( os );
    5252        } // ?|?
     
    5656
    5757        ostype & ?|?( ostype & os, signed char sc ) {
    58                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     58                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    5959                fmt( os, "%hhd", sc );
    6060                return os;
     
    6565
    6666        ostype & ?|?( ostype & os, unsigned char usc ) {
    67                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     67                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    6868                fmt( os, "%hhu", usc );
    6969                return os;
     
    7474
    7575        ostype & ?|?( ostype & os, short int si ) {
    76                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     76                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    7777                fmt( os, "%hd", si );
    7878                return os;
     
    8383
    8484        ostype & ?|?( ostype & os, unsigned short int usi ) {
    85                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     85                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    8686                fmt( os, "%hu", usi );
    8787                return os;
     
    9292
    9393        ostype & ?|?( ostype & os, int i ) {
    94                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     94                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    9595                fmt( os, "%d", i );
    9696                return os;
     
    101101
    102102        ostype & ?|?( ostype & os, unsigned int ui ) {
    103                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     103                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    104104                fmt( os, "%u", ui );
    105105                return os;
     
    110110
    111111        ostype & ?|?( ostype & os, long int li ) {
    112                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     112                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    113113                fmt( os, "%ld", li );
    114114                return os;
     
    119119
    120120        ostype & ?|?( ostype & os, unsigned long int uli ) {
    121                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     121                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    122122                fmt( os, "%lu", uli );
    123123                return os;
     
    128128
    129129        ostype & ?|?( ostype & os, long long int lli ) {
    130                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     130                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    131131                fmt( os, "%lld", lli );
    132132                return os;
     
    137137
    138138        ostype & ?|?( ostype & os, unsigned long long int ulli ) {
    139                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     139                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    140140                fmt( os, "%llu", ulli );
    141141                return os;
     
    145145        } // ?|?
    146146
    147 #if defined( __SIZEOF_INT128__ )
     147        #if defined( __SIZEOF_INT128__ )
    148148        //      UINT64_MAX 18_446_744_073_709_551_615_ULL
    149149        #define P10_UINT64 10_000_000_000_000_000_000_ULL       // 19 zeroes
    150150
    151151        static inline void base10_128( ostype & os, unsigned int128 val ) {
    152 #if defined(__GNUC__) && __GNUC_PREREQ(7,0)                             // gcc version >= 7
     152                #if defined(__GNUC__) && __GNUC_PREREQ(7,0)             // gcc version >= 7
    153153                if ( val > P10_UINT64 ) {
    154 #else
     154                #else
    155155                if ( (uint64_t)(val >> 64) != 0 || (uint64_t)val > P10_UINT64 ) { // patch gcc 5 & 6 -O3 bug
    156 #endif // __GNUC_PREREQ(7,0)
     156                #endif // __GNUC_PREREQ(7,0)
    157157                        base10_128( os, val / P10_UINT64 );                     // recursive
    158158                        fmt( os, "%.19lu", (uint64_t)(val % P10_UINT64) );
     
    171171
    172172        ostype & ?|?( ostype & os, int128 llli ) {
    173                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     173                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    174174                base10_128( os, llli );
    175175                return os;
     
    180180
    181181        ostype & ?|?( ostype & os, unsigned int128 ullli ) {
    182                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     182                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    183183                base10_128( os, ullli );
    184184                return os;
     
    187187                (ostype &)(os | ullli); ends( os );
    188188        } // ?|?
    189 #endif // __SIZEOF_INT128__
     189        #endif // __SIZEOF_INT128__
    190190
    191191        #define PrintWithDP( os, format, val, ... ) \
     
    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 */ \
     
    204204
    205205        ostype & ?|?( ostype & os, float f ) {
    206                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     206                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    207207                PrintWithDP( os, "%g", f );
    208208                return os;
     
    213213
    214214        ostype & ?|?( ostype & os, double d ) {
    215                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     215                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    216216                PrintWithDP( os, "%.*lg", d, DBL_DIG );
    217217                return os;
     
    222222
    223223        ostype & ?|?( ostype & os, long double ld ) {
    224                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     224                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    225225                PrintWithDP( os, "%.*Lg", ld, LDBL_DIG );
    226226                return os;
     
    231231
    232232        ostype & ?|?( ostype & os, float _Complex fc ) {
    233                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     233                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    234234//              os | crealf( fc ) | nonl;
    235235                PrintWithDP( os, "%g", crealf( fc ) );
     
    243243
    244244        ostype & ?|?( ostype & os, double _Complex dc ) {
    245                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     245                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    246246//              os | creal( dc ) | nonl;
    247247                PrintWithDP( os, "%.*lg", creal( dc ), DBL_DIG );
     
    255255
    256256        ostype & ?|?( ostype & os, long double _Complex ldc ) {
    257                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     257                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    258258//              os | creall( ldc ) || nonl;
    259259                PrintWithDP( os, "%.*Lg", creall( ldc ), LDBL_DIG );
     
    266266        } // ?|?
    267267
    268         ostype & ?|?( ostype & os, const char str[] ) {
     268        ostype & ?|?( ostype & os, const char s[] ) {
    269269                enum { Open = 1, Close, OpenClose };
    270270                static const unsigned char mask[256] @= {
     
    282282                }; // mask
    283283
    284           if ( str[0] == '\0' ) { sepOff( os ); return os; } // null string => no separator
     284          if ( s[0] == '\0' ) { sepOff( os ); return os; } // null string => no separator
    285285
    286286                // first character IS NOT spacing or closing punctuation => add left separator
    287                 unsigned char ch = str[0];                                              // must make unsigned
    288                 if ( $sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
    289                         fmt( os, "%s", $sepGetCur( os ) );
     287                unsigned char ch = s[0];                                                // must make unsigned
     288                if ( sepPrt$( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
     289                        fmt( os, "%s", sepGetCur$( os ) );
    290290                } // if
    291291
    292292                // if string starts line, must reset to determine open state because separator is off
    293                 $sepReset( os );                                                                // reset separator
     293                sepReset$( os );                                                                // reset separator
    294294
    295295                // last character IS spacing or opening punctuation => turn off separator for next item
    296                 size_t len = strlen( str );
    297                 ch = str[len - 1];                                                              // must make unsigned
    298                 if ( $sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
     296                int len = strlen( s );
     297                ch = s[len - 1];                                                                // must make unsigned
     298                fmt( os, "%s", s );                                                             // fmt resets seperator, but reset it again
     299                if ( sepPrt$( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
    299300                        sepOn( os );
    300301                } else {
    301302                        sepOff( os );
    302303                } // if
    303                 if ( ch == '\n' ) $setNL( os, true );                   // check *AFTER* $sepPrt call above as it resets NL flag
    304                 return write( os, str, len );
    305         } // ?|?
    306 
    307         void ?|?( ostype & os, const char str[] ) {
    308                 (ostype &)(os | str); ends( os );
    309         } // ?|?
    310 
    311 //      ostype & ?|?( ostype & os, const char16_t * str ) {
    312 //              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    313 //              fmt( os, "%ls", str );
     304                if ( ch == '\n' ) setNL$( os, true );                   // check *AFTER* sepPrt$ call above as it resets NL flag
     305                return os;
     306//              return write( os, s, len );
     307        } // ?|?
     308        void ?|?( ostype & os, const char s[] ) {
     309                (ostype &)(os | s); ends( os );
     310        } // ?|?
     311
     312//      ostype & ?|?( ostype & os, const char16_t * s ) {
     313//              if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     314//              fmt( os, "%ls", s );
    314315//              return os;
    315316//      } // ?|?
    316317
    317318// #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
    318 //      ostype & ?|?( ostype & os, const char32_t * str ) {
    319 //              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    320 //              fmt( os, "%ls", str );
     319//      ostype & ?|?( ostype & os, const char32_t * s ) {
     320//              if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     321//              fmt( os, "%ls", s );
    321322//              return os;
    322323//      } // ?|?
    323324// #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )
    324325
    325 //      ostype & ?|?( ostype & os, const wchar_t * str ) {
    326 //              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    327 //              fmt( os, "%ls", str );
     326//      ostype & ?|?( ostype & os, const wchar_t * s ) {
     327//              if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     328//              fmt( os, "%ls", s );
    328329//              return os;
    329330//      } // ?|?
    330331
    331332        ostype & ?|?( ostype & os, const void * p ) {
    332                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     333                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    333334                fmt( os, "%p", p );
    334335                return os;
     
    340341        // manipulators
    341342        ostype & ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
    342                 (ostype &)(manip( os ));
    343                 return os;
     343                return manip( os );
    344344        } // ?|?
    345345        void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
    346                 (ostype &)(manip( os ));
    347                 if ( $getPrt( os ) ) ends( os );                                // something printed ?
    348                 $setPrt( os, false );                                                   // turn off
     346                manip( os );
     347                if ( getPrt$( os ) ) ends( os );                                // something printed ?
     348                setPrt$( os, false );                                                   // turn off
    349349        } // ?|?
    350350
     
    359359        ostype & nl( ostype & os ) {
    360360                (ostype &)(os | '\n');
    361                 $setPrt( os, false );                                                   // turn off
    362                 $setNL( os, true );
    363                 flush( os );
     361                setPrt$( os, false );                                                   // turn off
     362                setNL$( os, true );
    364363                return sepOff( os );                                                    // prepare for next line
    365364        } // nl
    366365
    367366        ostype & nonl( ostype & os ) {
    368                 $setPrt( os, false );                                                   // turn off
     367                setPrt$( os, false );                                                   // turn off
    369368                return os;
    370369        } // nonl
     
    399398                return os;
    400399        } // nlOff
     400} // distribution
     401
     402forall( ostype & | ostream( ostype ) ) {
     403        ostype & acquire( ostype & os ) {
     404                acquire( os );                                                                  // call void returning
     405                return os;
     406        } // acquire
    401407} // distribution
    402408
     
    405411        ostype & ?|?( ostype & os, T arg, Params rest ) {
    406412                (ostype &)(os | arg);                                                   // print first argument
    407                 $sepSetCur( os, sepGetTuple( os ) );                    // switch to tuple separator
     413                sepSetCur$( os, sepGetTuple( os ) );                    // switch to tuple separator
    408414                (ostype &)(os | rest);                                                  // print remaining arguments
    409                 $sepSetCur( os, sepGet( os ) );                                 // switch to regular separator
     415                sepSetCur$( os, sepGet( os ) );                                 // switch to regular separator
    410416                return os;
    411417        } // ?|?
     
    413419                // (ostype &)(?|?( os, arg, rest )); ends( os );
    414420                (ostype &)(os | arg);                                                   // print first argument
    415                 $sepSetCur( os, sepGetTuple( os ) );                    // switch to tuple separator
     421                sepSetCur$( os, sepGetTuple( os ) );                    // switch to tuple separator
    416422                (ostype &)(os | rest);                                                  // print remaining arguments
    417                 $sepSetCur( os, sepGet( os ) );                                 // switch to regular separator
     423                sepSetCur$( os, sepGet( os ) );                                 // switch to regular separator
    418424                ends( os );
    419425        } // ?|?
     
    442448// Default prefix for non-decimal prints is 0b, 0, 0x.
    443449#define IntegralFMTImpl( T, IFMTNP, IFMTP ) \
    444 forall( ostype & | ostream( ostype ) ) { \
     450forall( ostype & | basic_ostream( ostype ) ) { \
    445451        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    446                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     452                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \
    447453\
    448454                if ( f.base == 'b' || f.base == 'B' ) {                 /* bespoke binary format */ \
     
    517523                return os; \
    518524        } /* ?|? */ \
    519         void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
    520 } // distribution
    521 
    522 IntegralFMTImpl( signed char, "%    *hh ", "%    *.*hh " )
    523 IntegralFMTImpl( unsigned char, "%    *hh ", "%    *.*hh " )
    524 IntegralFMTImpl( signed short int, "%    *h ", "%    *.*h " )
    525 IntegralFMTImpl( unsigned short int, "%    *h ", "%    *.*h " )
    526 IntegralFMTImpl( signed int, "%    * ", "%    *.* " )
    527 IntegralFMTImpl( unsigned int, "%    * ", "%    *.* " )
    528 IntegralFMTImpl( signed long int, "%    *l ", "%    *.*l " )
    529 IntegralFMTImpl( unsigned long int, "%    *l ", "%    *.*l " )
    530 IntegralFMTImpl( signed long long int, "%    *ll ", "%    *.*ll " )
    531 IntegralFMTImpl( unsigned long long int, "%    *ll ", "%    *.*ll " )
    532 
    533 #if 0
     525        void ?|?( ostype & os, _Ostream_Manip(T) f ) { \
     526                (ostype &)(os | f); ends( os ); \
     527        } /* ?|? */ \
     528} // distribution
     529
     530IntegralFMTImpl( signed char, "     *hh ", "     *.*hh " )
     531IntegralFMTImpl( unsigned char, "     *hh ", "     *.*hh " )
     532IntegralFMTImpl( signed short int, "     *h ", "     *.*h " )
     533IntegralFMTImpl( unsigned short int, "     *h ", "     *.*h " )
     534IntegralFMTImpl( signed int, "     * ", "     *.* " )
     535IntegralFMTImpl( unsigned int, "     * ", "     *.* " )
     536IntegralFMTImpl( signed long int, "     *l ", "     *.*l " )
     537IntegralFMTImpl( unsigned long int, "     *l ", "     *.*l " )
     538IntegralFMTImpl( signed long long int, "     *ll ", "     *.*ll " )
     539IntegralFMTImpl( unsigned long long int, "     *ll ", "     *.*ll " )
     540
     541
    534542#if defined( __SIZEOF_INT128__ )
    535543// Default prefix for non-decimal prints is 0b, 0, 0x.
    536 #define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \
    537 forall( ostype & | ostream( ostype ) ) \
    538 static void base10_128( ostype & os, _Ostream_Manip(T) f ) { \
    539         if ( f.val > UINT64_MAX ) { \
    540                 unsigned long long int lsig = f.val % P10_UINT64; \
    541                 f.val /= P10_UINT64; /* msig */ \
    542                 base10_128( os, f ); /* recursion */ \
    543                 _Ostream_Manip(unsigned long long int) fmt @= { lsig, 0, 19, 'u', { .all : 0 } }; \
    544                 fmt.flags.nobsdp = true; \
    545                 /* printf( "fmt1 %c %lld %d\n", fmt.base, fmt.val, fmt.all ); */ \
    546                 sepOff( os ); \
    547                 (ostype &)(os | fmt); \
    548         } else { \
    549                 /* printf( "fmt2 %c %lld %d\n", f.base, (unsigned long long int)f.val, f.all ); */ \
    550                 _Ostream_Manip(SIGNED long long int) fmt @= { (SIGNED long long int)f.val, f.wd, f.pc, f.base, { .all : f.all } }; \
    551                 (ostype &)(os | fmt); \
    552         } /* if */ \
    553 } /* base10_128 */ \
    554 forall( ostype & | ostream( ostype ) ) { \
    555         ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    556                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
    557 \
    558                 if ( f.base == 'b' | f.base == 'B' | f.base == 'o' | f.base == 'x' | f.base == 'X' ) { \
    559                         unsigned long long int msig = (unsigned long long int)(f.val >> 64); \
    560                         unsigned long long int lsig = (unsigned long long int)(f.val); \
    561                         _Ostream_Manip(SIGNED long long int) fmt @= { msig, f.wd, f.pc, f.base, { .all : f.all } }; \
    562                         _Ostream_Manip(unsigned long long int) fmt2 @= { lsig, 0, 0, f.base, { .all : 0 } }; \
    563                         if ( msig == 0 ) { \
    564                                 fmt.val = lsig; \
    565                                 (ostype &)(os | fmt); \
    566                         } else { \
    567                                 fmt2.flags.pad0 = fmt2.flags.nobsdp = true;     \
    568                                 if ( f.base == 'b' | f.base == 'B' ) { \
    569                                         if ( fmt.flags.pc && fmt.pc > 64 ) fmt.pc -= 64; else { fmt.flags.pc = false; fmt.pc = 0; } \
    570                                         if ( fmt.flags.left ) { \
    571                                                 fmt.flags.left = false; \
    572                                                 fmt.wd = 0; \
    573                                                 /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
    574                                                 fmt2.flags.left = true; \
    575                                                 int msigd = high1( msig ); \
    576                                                 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
    577                                                 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0b base specifier */ \
    578                                                 if ( (int)fmt2.wd < 64 ) fmt2.wd = 64; /* cast deals with negative value */ \
    579                                                 fmt2.flags.pc = true; fmt2.pc = 64; \
    580                                         } else { \
    581                                                 if ( fmt.wd > 64 ) fmt.wd -= 64; \
    582                                                 else fmt.wd = 1; \
    583                                                 /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
    584                                                 fmt2.wd = 64; \
    585                                         } /* if */ \
    586                                         /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
    587                                         (ostype &)(os | fmt | "" | fmt2); \
    588                                 } else if ( f.base == 'o' ) { \
    589                                         if ( fmt.flags.pc && fmt.pc > 22 ) fmt.pc -= 22; else { fmt.flags.pc = false; fmt.pc = 0; } \
    590                                         fmt.val = (unsigned long long int)fmt.val >> 2; \
    591                                         fmt2.val = ((msig & 0x3) << 1) + ((lsig & 0x8000000000000000U) != 0); \
    592                                         if ( fmt.flags.left ) { \
    593                                                 fmt.flags.left = false; \
    594                                                 fmt.wd = 0; \
    595                                                 /* 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 ); */ \
    596                                                 (ostype &)(os | fmt | "" | fmt2); \
    597                                                 sepOff( os ); \
    598                                                 fmt2.flags.left = true; \
    599                                                 int msigd = ceiling_div( high1( fmt.val ), 3 ); \
    600                                                 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
    601                                                 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 1; /* compensate for 0 base specifier */ \
    602                                                 if ( (int)fmt2.wd < 21 ) fmt2.wd = 21; /* cast deals with negative value */ \
    603                                                 fmt2.flags.pc = true; fmt2.pc = 21; \
    604                                         } else { \
    605                                                 if ( fmt.wd > 22 ) fmt.wd -= 22; \
    606                                                 else fmt.wd = 1; \
    607                                                 /* 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 ); */ \
    608                                                 (ostype &)(os | fmt | "" | fmt2); \
    609                                                 sepOff( os ); \
    610                                                 fmt2.wd = 21; \
    611                                         } /* if */ \
    612                                         fmt2.val = lsig & 0x7fffffffffffffffU; \
    613                                         /* printf( "\nC %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
    614                                         (ostype &)(os | fmt2); \
    615                                 } else { /* f.base == 'x'  | f.base == 'X' */ \
    616                                         if ( fmt.flags.pc && fmt.pc > 16 ) fmt.pc -= 16; else { fmt.flags.pc = false; fmt.pc = 0; } \
    617                                         if ( fmt.flags.left ) { \
    618                                                 fmt.flags.left = false; \
    619                                                 fmt.wd = 0; \
    620                                                 /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
    621                                                 fmt2.flags.left = true; \
    622                                                 int msigd = high1( msig ); \
    623                                                 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
    624                                                 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0x base specifier */ \
    625                                                 if ( (int)fmt2.wd < 16 ) fmt2.wd = 16; /* cast deals with negative value */ \
    626                                                 fmt2.flags.pc = true; fmt2.pc = 16; \
    627                                         } else { \
    628                                                 if ( fmt.wd > 16 ) fmt.wd -= 16; \
    629                                                 else fmt.wd = 1; \
    630                                                 /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
    631                                                 fmt2.wd = 16; \
    632                                         } /* if */ \
    633                                         /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
    634                                         (ostype &)(os | fmt | "" | fmt2); \
    635                                 } /* if */ \
    636                         } /* if */ \
    637                 } else { \
    638                         if ( CODE == 'd' ) { \
    639                                 if ( f.val < 0 )  { fmt( os, "-" ); sepOff( os ); f.val = -f.val; f.flags.sign = false; } \
    640                         } /* if */ \
    641                         base10_128( os, f ); \
    642                 } /* if */ \
    643                 return os; \
    644         } /* ?|? */ \
    645         void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
    646 } // distribution
    647 
    648 IntegralFMTImpl128( int128, signed, 'd', "%    *ll ", "%    *.*ll " )
    649 IntegralFMTImpl128( unsigned int128, unsigned, 'u', "%    *ll ", "%    *.*ll " )
    650 #endif // __SIZEOF_INT128__
    651 #endif // 0
    652 
    653 #if 1
    654 #if defined( __SIZEOF_INT128__ )
    655 // Default prefix for non-decimal prints is 0b, 0, 0x.
    656 forall( ostype & | ostream( ostype ) )
     544forall( ostype & | basic_ostream( ostype ) )
    657545static inline void base_128( ostype & os, unsigned int128 val, unsigned int128 power, _Ostream_Manip(uint64_t) & f, unsigned int maxdig, unsigned int bits, unsigned int cnt = 0 ) {
    658546        int wd = 1;                                                                                     // f.wd is never 0 because 0 implies left-pad
     
    719607
    720608#define IntegralFMTImpl128( T ) \
    721 forall( ostype & | ostream( ostype ) ) { \
     609forall( ostype & | basic_ostream( ostype ) ) { \
    722610        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    723611                _Ostream_Manip(uint64_t) fmt; \
     
    741629IntegralFMTImpl128( unsigned int128 )
    742630#endif // __SIZEOF_INT128__
    743 #endif // 0
    744631
    745632// *********************************** floating point ***********************************
    746633
    747 #define PrintWithDP2( os, format, val, ... ) \
     634static const char *suffixes[] = {
     635        "y", "z", "a", "f", "p", "n", "u", "m", "",
     636        "K", "M", "G", "T", "P", "E", "Z", "Y"
     637};
     638#define SUFFIXES_START (-24) /* Smallest power for which there is a suffix defined. */
     639#define SUFFIXES_END (SUFFIXES_START + (int)((sizeof(suffixes) / sizeof(char *) - 1) * 3))
     640
     641#define PrintWithDP2( os, format, ... ) \
    748642        { \
    749                 enum { size = 48 }; \
    750                 char buf[size]; \
    751                 int bufbeg = 0, i, len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
    752                 if ( isfinite( val ) && (f.base != 'g' || f.pc != 0) ) { /* if number, print decimal point */ \
    753                         for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */ \
    754                         if ( i == len && ! f.flags.nobsdp ) { \
    755                                 if ( ! f.flags.left ) { \
    756                                         buf[i] = '.'; buf[i + 1] = '\0'; \
    757                                         if ( buf[0] == ' ' ) bufbeg = 1;        /* decimal point within width */ \
    758                                 } else { \
    759                                         for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \
    760                                         buf[i] = '.'; \
    761                                         if ( i == len ) buf[i + 1] = '\0'; \
     643                if ( ! f.flags.eng ) { \
     644                        len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
     645                        if ( isfinite( f.val ) && ( f.pc != 0 || ! f.flags.nobsdp ) ) { /* if number, print decimal point when no fraction or exponent */ \
     646                                for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */ \
     647                                if ( i == len ) { \
     648                                        if ( ! f.flags.left ) { \
     649                                                buf[i] = '.'; buf[i + 1] = '\0'; \
     650                                                if ( buf[0] == ' ' ) bufbeg = 1; /* decimal point within width */ \
     651                                        } else { \
     652                                                for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \
     653                                                buf[i] = '.'; \
     654                                                if ( i == len ) buf[i + 1] = '\0'; \
     655                                        } /* if */ \
    762656                                } /* if */ \
    763657                        } /* if */ \
     658                } else { \
     659                        int exp10, len2; \
     660                        eng( f.val, f.pc, exp10 );                                      /* changes arguments */ \
     661                        if ( ! f.flags.left && f.wd > 1 ) { \
     662                                /* Exponent size (number of digits, 'e', optional minus sign) */ \
     663                                f.wd -= lrint( floor( log10( abs( exp10 ) ) ) ) + 1 + 1 + (exp10 < 0 ? 1 : 0); \
     664                                if ( f.wd < 1 ) f.wd = 1; \
     665                        } /* if */ \
     666                        len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
     667                        if ( f.flags.left ) { \
     668                                for ( len -= 1; len > 0 && buf[len] == ' '; len -= 1 ); \
     669                                len += 1; \
     670                        } /* if */ \
     671                        if ( ! f.flags.nobsdp || (exp10 < SUFFIXES_START) || (exp10 > SUFFIXES_END) ) { \
     672                                len2 = snprintf( &buf[len], size - len, "e%d", exp10 ); \
     673                        } else { \
     674                                len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \
     675                        } /* if */ \
     676                        if ( f.flags.left && len + len2 < f.wd ) buf[len + len2] = ' '; \
    764677                } /* if */ \
    765678                fmt( os, "%s", &buf[bufbeg] ); \
     
    767680
    768681#define FloatingPointFMTImpl( T, DFMTNP, DFMTP ) \
    769 forall( ostype & | ostream( ostype ) ) { \
     682forall( ostype & | basic_ostream( ostype ) ) { \
     683        static void eng( T &value, int & pc, int & exp10 ) { \
     684                exp10 = lrint( floor( log10( abs( value ) ) ) ); /* round to desired precision */ \
     685                if ( exp10 < 0 ) exp10 -= 2; \
     686                exp10 = floor( exp10, 3 ); \
     687                value *= pow( 10.0, -exp10 ); \
     688                if ( pc <= 3 ) pc = 3; \
     689        } /* eng */ \
     690\
    770691        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    771                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
    772                 char fmtstr[sizeof(DFMTP)];                                             /* sizeof includes '\0' */ \
     692                enum { size = 48 }; \
     693                char buf[size]; \
     694                int bufbeg = 0, i, len; \
     695\
     696                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \
     697                char fmtstr[sizeof(DFMTP) + 8];                                 /* sizeof includes '\0' */ \
    773698                if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
    774699                else memcpy( &fmtstr, DFMTP, sizeof(DFMTP) ); \
     
    784709                        fmtstr[sizeof(DFMTNP)-2] = f.base;                      /* sizeof includes '\0' */ \
    785710                        /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star]); */ \
    786                         PrintWithDP2( os, &fmtstr[star], f.val, f.wd ) \
     711                        PrintWithDP2( os, &fmtstr[star], f.wd, f.val ) \
    787712                } else {                                                                                /* precision */ \
    788713                        fmtstr[sizeof(DFMTP)-2] = f.base;                       /* sizeof includes '\0' */ \
    789714                        /* printf( "%g %d %d %s\n", f.val, f.wd, f.pc, &fmtstr[star] ); */ \
    790                         PrintWithDP2( os, &fmtstr[star], f.val, f.wd, f.pc ) \
     715                        PrintWithDP2( os, &fmtstr[star], f.wd, f.pc, f.val ) \
    791716                } /* if */ \
    792717                return os; \
     
    796721} // distribution
    797722
    798 FloatingPointFMTImpl( double, "%    * ", "%    *.* " )
    799 FloatingPointFMTImpl( long double, "%    *L ", "%    *.*L " )
     723FloatingPointFMTImpl( double, "     * ", "     *.* " )
     724FloatingPointFMTImpl( long double, "     *L ", "     *.*L " )
    800725
    801726// *********************************** character ***********************************
    802727
    803 forall( ostype & | ostream( ostype ) ) {
     728forall( ostype & | basic_ostream( ostype ) ) {
    804729        ostype & ?|?( ostype & os, _Ostream_Manip(char) f ) {
    805730                if ( f.base != 'c' ) {                                                  // bespoke binary/octal/hex format
     
    812737                } // if
    813738
    814                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     739                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    815740
    816741                #define CFMTNP "% * "
     
    834759// *********************************** C string ***********************************
    835760
    836 forall( ostype & | ostream( ostype ) ) {
     761forall( ostype & | basic_ostream( ostype ) ) {
    837762        ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f ) {
    838763                if ( ! f.val ) return os;                                               // null pointer ?
     
    850775                } // if
    851776
    852                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     777                if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    853778
    854779                #define SFMTNP "% * "
     
    882807
    883808
    884 forall( istype & | istream( istype ) ) {
     809forall( istype & | basic_istream( istype ) ) {
    885810        istype & ?|?( istype & is, bool & b ) {
    886811                char val[6];
     
    894819                return is;
    895820        } // ?|?
     821        void ?|?( istype & is, bool & b ) {
     822                (istype &)(is | b); ends( is );
     823        } // ?|?
    896824
    897825        istype & ?|?( istype & is, char & c ) {
     
    905833                return is;
    906834        } // ?|?
     835        void ?|?( istype & is, char & c ) {
     836                (istype &)(is | c); ends( is );
     837        } // ?|?
    907838
    908839        istype & ?|?( istype & is, signed char & sc ) {
     
    910841                return is;
    911842        } // ?|?
     843        void ?|?( istype & is, signed char & sc ) {
     844                (istype &)(is | sc); ends( is );
     845        } // ?|?
    912846
    913847        istype & ?|?( istype & is, unsigned char & usc ) {
     
    915849                return is;
    916850        } // ?|?
     851        void ?|?( istype & is, unsigned char & usc ) {
     852                (istype &)(is | usc); ends( is );
     853        } // ?|?
    917854
    918855        istype & ?|?( istype & is, short int & si ) {
     
    920857                return is;
    921858        } // ?|?
     859        void ?|?( istype & is, short int & si ) {
     860                (istype &)(is | si); ends( is );
     861        } // ?|?
    922862
    923863        istype & ?|?( istype & is, unsigned short int & usi ) {
     
    925865                return is;
    926866        } // ?|?
     867        void ?|?( istype & is, unsigned short int & usi ) {
     868                (istype &)(is | usi); ends( is );
     869        } // ?|?
    927870
    928871        istype & ?|?( istype & is, int & i ) {
     
    930873                return is;
    931874        } // ?|?
     875        void ?|?( istype & is, int & i ) {
     876                (istype &)(is | i); ends( is );
     877        } // ?|?
    932878
    933879        istype & ?|?( istype & is, unsigned int & ui ) {
     
    935881                return is;
    936882        } // ?|?
     883        void ?|?( istype & is, unsigned int & ui ) {
     884                (istype &)(is | ui); ends( is );
     885        } // ?|?
    937886
    938887        istype & ?|?( istype & is, long int & li ) {
     
    940889                return is;
    941890        } // ?|?
     891        void ?|?( istype & is, long int & li ) {
     892                (istype &)(is | li); ends( is );
     893        } // ?|?
    942894
    943895        istype & ?|?( istype & is, unsigned long int & ulli ) {
     
    945897                return is;
    946898        } // ?|?
     899        void ?|?( istype & is, unsigned long int & ulli ) {
     900                (istype &)(is | ulli); ends( is );
     901        } // ?|?
    947902
    948903        istype & ?|?( istype & is, long long int & lli ) {
     
    950905                return is;
    951906        } // ?|?
     907        void ?|?( istype & is, long long int & lli ) {
     908                (istype &)(is | lli); ends( is );
     909        } // ?|?
    952910
    953911        istype & ?|?( istype & is, unsigned long long int & ulli ) {
     
    955913                return is;
    956914        } // ?|?
    957 
    958 #if defined( __SIZEOF_INT128__ )
    959         istype & ?|?( istype & is, int128 & i128 ) {
    960                 return (istype &)(is | (unsigned int128 &)i128);
    961         } // ?|?
    962 
    963         istype & ?|?( istype & is, unsigned int128 & ui128 ) {
     915        void & ?|?( istype & is, unsigned long long int & ulli ) {
     916                (istype &)(is | ulli); ends( is );
     917        } // ?|?
     918
     919        #if defined( __SIZEOF_INT128__ )
     920        istype & ?|?( istype & is, int128 & llli ) {
     921                return (istype &)(is | (unsigned int128 &)llli);
     922        } // ?|?
     923        void ?|?( istype & is, int128 & llli ) {
     924                (istype &)(is | llli); ends( is );
     925        } // ?|?
     926
     927        istype & ?|?( istype & is, unsigned int128 & ullli ) {
    964928                char s[40];
    965929                bool sign = false;
     
    968932                // If the input is too large, the value returned is undefined. If there is no input, no value is returned
    969933                if ( fmt( is, "%39[0-9]%*[0-9]", s ) == 1 ) {   // take first 39 characters, ignore remaining
    970                         ui128 = 0;
     934                        ullli = 0;
    971935                        for ( unsigned int i = 0; s[i] != '\0'; i += 1 ) {
    972                                 ui128 = ui128 * 10 + s[i] - '0';
     936                                ullli = ullli * 10 + s[i] - '0';
    973937                        } // for
    974                         if ( sign ) ui128 = -ui128;
     938                        if ( sign ) ullli = -ullli;
    975939                } else if ( sign ) ungetc( is, '-' );                   // return minus when no digits
    976940                return is;
    977941        } // ?|?
    978 #endif // __SIZEOF_INT128__
     942        void ?|?( istype & is, unsigned int128 & ullli ) {
     943                (istype &)(is | ullli); ends( is );
     944        } // ?|?
     945        #endif // __SIZEOF_INT128__
    979946
    980947        istype & ?|?( istype & is, float & f ) {
     
    982949                return is;
    983950        } // ?|?
     951        void ?|?( istype & is, float & f ) {
     952                (istype &)(is | f); ends( is );
     953        } // ?|?
    984954
    985955        istype & ?|?( istype & is, double & d ) {
     
    987957                return is;
    988958        } // ?|?
     959        void ?|?( istype & is, double & d ) {
     960                (istype &)(is | d); ends( is );
     961        } // ?|?
    989962
    990963        istype & ?|?( istype & is, long double & ld ) {
     
    992965                return is;
    993966        } // ?|?
    994 
     967        void ?|?( istype & is, long double & ld ) {
     968                (istype &)(is | ld); ends( is );
     969        } // ?|?
    995970
    996971        istype & ?|?( istype & is, float _Complex & fc ) {
     
    1000975                return is;
    1001976        } // ?|?
     977        void ?|?( istype & is, float _Complex & fc ) {
     978                (istype &)(is | fc); ends( is );
     979        } // ?|?
    1002980
    1003981        istype & ?|?( istype & is, double _Complex & dc ) {
     
    1007985                return is;
    1008986        } // ?|?
     987        void ?|?( istype & is, double _Complex & dc ) {
     988                (istype &)(is | dc); ends( is );
     989        } // ?|?
    1009990
    1010991        istype & ?|?( istype & is, long double _Complex & ldc ) {
     
    1014995                return is;
    1015996        } // ?|?
     997        void ?|?( istype & is, long double _Complex & ldc ) {
     998                (istype &)(is | ldc); ends( is );
     999        } // ?|?
    10161000
    10171001        // istype & ?|?( istype & is, const char fmt[] ) {
     
    10201004        // } // ?|?
    10211005
    1022         istype & ?|?( istype & is, char * s ) {
     1006        istype & ?|?( istype & is, char s[] ) {
    10231007                fmt( is, "%s", s );
    10241008                return is;
     1009        } // ?|?
     1010        void ?|?( istype & is, char s[] ) {
     1011                (istype &)(is | s); ends( is );
    10251012        } // ?|?
    10261013
     
    10291016                return manip( is );
    10301017        } // ?|?
     1018        void ?|?( istype & is, istype & (* manip)( istype & ) ) {
     1019                manip( is ); ends( is );
     1020        } // ?|?
    10311021
    10321022        istype & nl( istype & is ) {
     
    10461036} // distribution
    10471037
     1038forall( istype & | istream( istype ) ) {
     1039        istype & acquire( istype & is ) {
     1040                acquire( is );                                                                  // call void returning
     1041                return is;
     1042        } // acquire
     1043} // distribution
     1044
    10481045// *********************************** manipulators ***********************************
    10491046
    1050 forall( istype & | istream( istype ) )
    1051 istype & ?|?( istype & is, _Istream_Cstr f ) {
    1052         // skip xxx
    1053         if ( ! f.s ) {
    1054                 // printf( "skip %s %d\n", f.scanset, f.wd );
    1055                 if ( f.wd == -1 ) fmt( is, f.scanset, "" );             // no input arguments
    1056                 else for ( f.wd ) fmt( is, "%*c" );
    1057                 return is;
    1058         } // if
    1059         size_t len = 0;
    1060         if ( f.scanset ) len = strlen( f.scanset );
    1061         char fmtstr[len + 16];
    1062         int start = 1;
    1063         fmtstr[0] = '%';
    1064         if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; }
    1065         if ( f.wd != -1 ) { start += sprintf( &fmtstr[start], "%d", f.wd ); }
    1066         // cstr %s, %*s, %ws, %*ws
    1067         if ( ! f.scanset ) {
    1068                 fmtstr[start] = 's'; fmtstr[start + 1] = '\0';
    1069                 // printf( "cstr %s\n", fmtstr );
     1047forall( istype & | basic_istream( istype ) ) {
     1048        istype & ?|?( istype & is, _Istream_Cstr f ) {
     1049                // skip xxx
     1050                if ( ! f.s ) {
     1051                        // printf( "skip %s %d\n", f.scanset, f.wd );
     1052                        if ( f.wd == -1 ) fmt( is, f.scanset, "" );             // no input arguments
     1053                        else for ( f.wd ) fmt( is, "%*c" );
     1054                        return is;
     1055                } // if
     1056                size_t len = 0;
     1057                if ( f.scanset ) len = strlen( f.scanset );
     1058                char fmtstr[len + 16];
     1059                int start = 1;
     1060                fmtstr[0] = '%';
     1061                if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; }
     1062                if ( f.wd != -1 ) { start += sprintf( &fmtstr[start], "%d", f.wd ); }
     1063                // cstr %s, %*s, %ws, %*ws
     1064                if ( ! f.scanset ) {
     1065                        fmtstr[start] = 's'; fmtstr[start + 1] = '\0';
     1066                        // printf( "cstr %s\n", fmtstr );
     1067                        fmt( is, fmtstr, f.s );
     1068                        return is;
     1069                } // if
     1070                // incl %[xxx],  %*[xxx],  %w[xxx],  %*w[xxx]
     1071                // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx]
     1072                fmtstr[start] = '['; start += 1;
     1073                if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; }
     1074                strcpy( &fmtstr[start], f.scanset );                            // copy includes '\0'
     1075                len += start;
     1076                fmtstr[len] = ']'; fmtstr[len + 1] = '\0';
     1077                // printf( "incl/excl %s\n", fmtstr );
    10701078                fmt( is, fmtstr, f.s );
    10711079                return is;
    1072         } // if
    1073         // incl %[xxx],  %*[xxx],  %w[xxx],  %*w[xxx]
    1074         // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx]
    1075         fmtstr[start] = '['; start += 1;
    1076         if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; }
    1077         strcpy( &fmtstr[start], f.scanset );                            // copy includes '\0'
    1078         len += start;
    1079         fmtstr[len] = ']'; fmtstr[len + 1] = '\0';
    1080         // printf( "incl/excl %s\n", fmtstr );
    1081         fmt( is, fmtstr, f.s );
    1082         return is;
    1083 } // ?|?
    1084 
    1085 forall( istype & | istream( istype ) )
    1086 istype & ?|?( istype & is, _Istream_Char f ) {
    1087         fmt( is, "%*c" );                                                                       // argument variable unused
    1088         return is;
    1089 } // ?|?
     1080        } // ?|?
     1081        void ?|?( istype & is, _Istream_Cstr f ) {
     1082                (istype &)(is | f); ends( is );
     1083        } // ?|?
     1084
     1085        istype & ?|?( istype & is, _Istream_Char f ) {
     1086                fmt( is, "%*c" );                                                                       // argument variable unused
     1087                return is;
     1088        } // ?|?
     1089        void ?|?( istype & is, _Istream_Char f ) {
     1090                (istype &)(is | f); ends( is );
     1091        } // ?|?
     1092} // distribution
    10901093
    10911094#define InputFMTImpl( T, CODE ) \
    1092 forall( istype & | istream( istype ) ) \
    1093 istype & ?|?( istype & is, _Istream_Manip(T) f ) { \
    1094         enum { size = 16 }; \
    1095         char fmtstr[size]; \
    1096         if ( f.wd == -1 ) { \
    1097                 snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \
    1098         } else { \
    1099                 snprintf( fmtstr, size, "%%%s%d%s", f.ignore ? "*" : "", f.wd, CODE ); \
    1100         } /* if */ \
    1101         /* printf( "%d %s %p\n", f.wd, fmtstr, &f.val ); */ \
    1102         fmt( is, fmtstr, &f.val ); \
    1103         return is; \
    1104 } // ?|?
     1095forall( istype & | basic_istream( istype ) ) { \
     1096        istype & ?|?( istype & is, _Istream_Manip(T) f ) { \
     1097                enum { size = 16 }; \
     1098                char fmtstr[size]; \
     1099                if ( f.wd == -1 ) { \
     1100                        snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \
     1101                } else { \
     1102                        snprintf( fmtstr, size, "%%%s%d%s", f.ignore ? "*" : "", f.wd, CODE ); \
     1103                } /* if */ \
     1104                /* printf( "%d %s %p\n", f.wd, fmtstr, &f.val ); */ \
     1105                fmt( is, fmtstr, &f.val ); \
     1106                return is; \
     1107        } /* ?|? */ \
     1108        void ?|?( istype & is, _Istream_Manip(T) f ) { \
     1109                (istype &)(is | f); ends( is ); \
     1110        } /* ?|? */ \
     1111} // distribution
    11051112
    11061113InputFMTImpl( signed char, "hhi" )
     
    11191126InputFMTImpl( long double, "Lf" )
    11201127
    1121 forall( istype & | istream( istype ) )
    1122 istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) {
    1123         float re, im;
    1124         _Istream_Manip(float) fmtuc @= { re, fc.wd, fc.ignore };
    1125         is | fmtuc;
    1126         &fmtuc.val = &im;
    1127         is | fmtuc;
    1128         if ( ! fc.ignore ) fc.val = re + im * _Complex_I;       // re/im are uninitialized for ignore
    1129         return is;
    1130 } // ?|?
    1131 
    1132 forall( istype & | istream( istype ) )
    1133 istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
    1134         double re, im;
    1135         _Istream_Manip(double) fmtuc @= { re, dc.wd, dc.ignore };
    1136         is | fmtuc;
    1137         &fmtuc.val = &im;
    1138         is | fmtuc;
    1139         if ( ! dc.ignore ) dc.val = re + im * _Complex_I;       // re/im are uninitialized for ignore
    1140         return is;
    1141 } // ?|?
    1142 
    1143 forall( istype & | istream( istype ) )
    1144 istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
    1145         long double re, im;
    1146         _Istream_Manip(long double) fmtuc @= { re, ldc.wd, ldc.ignore };
    1147         is | fmtuc;
    1148         &fmtuc.val = &im;
    1149         is | fmtuc;
    1150         if ( ! ldc.ignore ) ldc.val = re + im * _Complex_I;     // re/im are uninitialized for ignore
    1151         return is;
    1152 } // ?|?
     1128forall( istype & | basic_istream( istype ) ) {
     1129        istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) {
     1130                float re, im;
     1131                _Istream_Manip(float) fmtuc @= { re, fc.wd, fc.ignore };
     1132                is | fmtuc;
     1133                &fmtuc.val = &im;
     1134                is | fmtuc;
     1135                if ( ! fc.ignore ) fc.val = re + im * _Complex_I; // re/im are uninitialized for ignore
     1136                return is;
     1137        } // ?|?
     1138        void ?|?( istype & is, _Istream_Manip(float _Complex) fc ) {
     1139                (istype &)(is | fc); ends( is );
     1140        } // ?|?
     1141
     1142        istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
     1143                double re, im;
     1144                _Istream_Manip(double) fmtuc @= { re, dc.wd, dc.ignore };
     1145                is | fmtuc;
     1146                &fmtuc.val = &im;
     1147                is | fmtuc;
     1148                if ( ! dc.ignore ) dc.val = re + im * _Complex_I; // re/im are uninitialized for ignore
     1149                return is;
     1150        } // ?|?
     1151        void ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
     1152                (istype &)(is | dc); ends( is );
     1153        } // ?|?
     1154
     1155        istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
     1156                long double re, im;
     1157                _Istream_Manip(long double) fmtuc @= { re, ldc.wd, ldc.ignore };
     1158                is | fmtuc;
     1159                &fmtuc.val = &im;
     1160                is | fmtuc;
     1161                if ( ! ldc.ignore ) ldc.val = re + im * _Complex_I;     // re/im are uninitialized for ignore
     1162                return is;
     1163        } // ?|?
     1164        void ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
     1165                (istype &)(is | ldc); ends( is );
     1166        } // ?|?
     1167} // distribution
    11531168
    11541169// Local Variables: //
  • libcfa/src/iostream.hfa

    rfeacef9 r5407cdc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Aug 11 22:16:14 2020
    13 // Update Count     : 350
     12// Last Modified On : Tue Apr 27 17:59:21 2021
     13// Update Count     : 398
    1414//
    1515
     
    2222
    2323
    24 trait ostream( ostype & ) {
     24trait basic_ostream( ostype & ) {
    2525        // private
    26         bool $sepPrt( ostype & );                                                       // get separator state (on/off)
    27         void $sepReset( ostype & );                                                     // set separator state to default state
    28         void $sepReset( ostype &, bool );                                       // set separator and default state
    29         const char * $sepGetCur( ostype & );                            // get current separator string
    30         void $sepSetCur( ostype &, const char [] );                     // set current separator string
    31         bool $getNL( ostype & );                                                        // check newline
    32         void $setNL( ostype &, bool );                                          // saw newline
    33         bool $getANL( ostype & );                                                       // get auto newline (on/off)
    34         bool $getPrt( ostype & );                                                       // get fmt called in output cascade
    35         void $setPrt( ostype &, bool );                                         // set fmt called in output cascade
     26        bool sepPrt$( ostype & );                                                       // get separator state (on/off)
     27        void sepReset$( ostype & );                                                     // set separator state to default state
     28        void sepReset$( ostype &, bool );                                       // set separator and default state
     29        const char * sepGetCur$( ostype & );                            // get current separator string
     30        void sepSetCur$( ostype &, const char [] );                     // set current separator string
     31        bool getNL$( ostype & );                                                        // check newline
     32        void setNL$( ostype &, bool );                                          // saw newline
     33        bool getANL$( ostype & );                                                       // get auto newline (on/off)
     34        bool getPrt$( ostype & );                                                       // get fmt called in output cascade
     35        void setPrt$( ostype &, bool );                                         // set fmt called in output cascade
    3636        // public
    3737        void sepOn( ostype & );                                                         // turn separator state on
     
    4747        void sepSetTuple( ostype &, const char [] );            // set tuple separator to string (15 character maximum)
    4848
    49         void ends( ostype & os );                                                       // end of output statement
    50         int fail( ostype & );
     49        void ends( ostype & );                                                          // end of output statement
     50        int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
     51}; // basic_ostream
     52       
     53trait ostream( ostype & | basic_ostream( ostype ) ) {
    5154        int flush( ostype & );
    52         void open( ostype & os, const char name[], const char mode[] );
    53         void close( ostype & os );
     55        bool fail( ostype & );                                                          // operation failed?
     56        void open( ostype &, const char name[], const char mode[] );
     57        void close( ostype & );
    5458        ostype & write( ostype &, const char [], size_t );
    55         int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
     59        void acquire( ostype & );                                                       // concurrent access
    5660}; // ostream
    5761
     
    6670// implement writable for intrinsic types
    6771
    68 forall( ostype & | ostream( ostype ) ) {
     72forall( ostype & | basic_ostream( ostype ) ) {
    6973        ostype & ?|?( ostype &, bool );
    7074        void ?|?( ostype &, bool );
     
    9397        ostype & ?|?( ostype &, unsigned long long int );
    9498        void ?|?( ostype &, unsigned long long int );
    95 #if defined( __SIZEOF_INT128__ )
     99        #if defined( __SIZEOF_INT128__ )
    96100        ostype & ?|?( ostype &, int128 );
    97101        void ?|?( ostype &, int128 );
    98102        ostype & ?|?( ostype &, unsigned int128 );
    99103        void ?|?( ostype &, unsigned int128 );
    100 #endif // __SIZEOF_INT128__
     104        #endif // __SIZEOF_INT128__
    101105
    102106        ostype & ?|?( ostype &, float );
     
    117121        void ?|?( ostype &, const char [] );
    118122        // ostype & ?|?( ostype &, const char16_t * );
    119 #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
     123        #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
    120124        // ostype & ?|?( ostype &, const char32_t * );
    121 #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )
     125        #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )
    122126        // ostype & ?|?( ostype &, const wchar_t * );
    123127        ostype & ?|?( ostype &, const void * );
     
    139143} // distribution
    140144
     145forall( ostype & | ostream( ostype ) ) {
     146        ostype & acquire( ostype & );
     147} // distribution
     148
    141149// tuples
    142150forall( ostype &, T, Params... | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) {
     
    156164struct _Ostream_Manip {
    157165        T val;                                                                                          // polymorphic base-type
    158         unsigned int wd, pc;                                                            // width, precision
     166        int wd, pc;                                                                                     // width, precision: signed for computations
    159167        char base;                                                                                      // numeric base / floating-point style
    160168        union {
    161169                unsigned char all;
    162170                struct {
     171                        unsigned char eng:1;                                            // engineering notation
    163172                        unsigned char neg:1;                                            // val is negative
    164173                        unsigned char pc:1;                                                     // precision specified
     
    183192        _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'x', { .all : 0 } }; } \
    184193        _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, CODE, { .all : 0 } }; } \
    185         _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \
     194        _Ostream_Manip(T) wd( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \
    186195        _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
    187         _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; } \
     196        _Ostream_Manip(T) & wd( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
    188197        _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
    189198        _Ostream_Manip(T) & upcase( _Ostream_Manip(T) & fmt ) { if ( fmt.base == 'x' || fmt.base == 'b' ) fmt.base -= 32; /* upper case */ return fmt; } \
     
    193202        _Ostream_Manip(T) & sign( _Ostream_Manip(T) & fmt ) { fmt.flags.sign = true; return fmt; } \
    194203} /* distribution */ \
    195 forall( ostype & | ostream( ostype ) ) { \
     204forall( ostype & | basic_ostream( ostype ) ) { \
    196205        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
    197206        void ?|?( ostype & os, _Ostream_Manip(T) f ); \
     
    220229        _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'a', { .all : 0 } }; } \
    221230        _Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'e', { .all : 0 } }; } \
    222         _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .all : 0 } }; } \
    223         _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
    224         _Ostream_Manip(T) ws( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
    225         _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
    226         _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; } \
     231        _Ostream_Manip(T) eng( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.eng : true } }; } \
     232        _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'g', { .all : 0 } }; } \
     233        _Ostream_Manip(T) wd( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
     234        _Ostream_Manip(T) ws( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
     235        _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; return fmt; } \
     236        _Ostream_Manip(T) & wd( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
     237        _Ostream_Manip(T) & ws( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
    227238        _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
    228239        _Ostream_Manip(T) upcase( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'G', { .all : 0 } }; } \
     
    233244        _Ostream_Manip(T) nodp( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
    234245        _Ostream_Manip(T) & nodp( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
     246        _Ostream_Manip(T) unit( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
     247        _Ostream_Manip(T) & unit( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
    235248} /* distribution */ \
    236 forall( ostype & | ostream( ostype ) ) { \
     249forall( ostype & | basic_ostream( ostype ) ) { \
    237250        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
    238251        void ?|?( ostype & os, _Ostream_Manip(T) f ); \
     
    254267        _Ostream_Manip(char) & nobase( _Ostream_Manip(char) & fmt ) { fmt.flags.nobsdp = true; return fmt; }
    255268} // distribution
    256 forall( ostype & | ostream( ostype ) ) {
     269forall( ostype & | basic_ostream( ostype ) ) {
    257270        ostype & ?|?( ostype & os, _Ostream_Manip(char) f );
    258271        void ?|?( ostype & os, _Ostream_Manip(char) f );
     
    266279        _Ostream_Manip(const char *) hex( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }
    267280        _Ostream_Manip(const char *) wd( unsigned int w, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }
    268         _Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }
     281        _Ostream_Manip(const char *) wd( unsigned int w, unsigned int pc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }
    269282        _Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; }
    270         _Ostream_Manip(const char *) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
     283        _Ostream_Manip(const char *) & wd( unsigned int w, unsigned int pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
    271284        _Ostream_Manip(const char *) & left( _Ostream_Manip(const char *) & fmt ) { fmt.flags.left = true; return fmt; }
    272285        _Ostream_Manip(const char *) & nobase( _Ostream_Manip(const char *) & fmt ) { fmt.flags.nobsdp = true; return fmt; }
    273286} // distribution
    274 forall( ostype & | ostream( ostype ) ) {
     287forall( ostype & | basic_ostream( ostype ) ) {
    275288        ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f );
    276289        void ?|?( ostype & os, _Ostream_Manip(const char *) f );
     
    281294
    282295
    283 trait istream( istype & ) {
     296trait basic_istream( istype & ) {
     297        bool getANL( istype & );                                                        // get scan newline (on/off)
    284298        void nlOn( istype & );                                                          // read newline
    285299        void nlOff( istype & );                                                         // scan newline
    286         bool getANL( istype & );                                                        // get scan newline (on/off)
    287         int fail( istype & );
     300
     301        void ends( istype & os );                                                       // end of output statement
     302        int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     303        istype & ungetc( istype &, char );
    288304        int eof( istype & );
     305}; // basic_istream
     306
     307trait istream( istype & | basic_istream( istype ) ) {
     308        bool fail( istype & );
    289309        void open( istype & is, const char name[] );
    290310        void close( istype & is );
    291311        istype & read( istype &, char *, size_t );
    292         istype & ungetc( istype &, char );
    293         int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     312        void acquire( istype & );                                                       // concurrent access
    294313}; // istream
    295314
     
    298317}; // readable
    299318
    300 forall( istype & | istream( istype ) ) {
     319forall( istype & | basic_istream( istype ) ) {
    301320        istype & ?|?( istype &, bool & );
     321        void ?|?( istype &, bool & );
    302322
    303323        istype & ?|?( istype &, char & );
     324        void ?|?( istype &, char & );
    304325        istype & ?|?( istype &, signed char & );
     326        void ?|?( istype &, signed char & );
    305327        istype & ?|?( istype &, unsigned char & );
     328        void ?|?( istype &, unsigned char & );
    306329
    307330        istype & ?|?( istype &, short int & );
     331        void ?|?( istype &, short int & );
    308332        istype & ?|?( istype &, unsigned short int & );
     333        void ?|?( istype &, unsigned short int & );
    309334        istype & ?|?( istype &, int & );
     335        void ?|?( istype &, int & );
    310336        istype & ?|?( istype &, unsigned int & );
     337        void ?|?( istype &, unsigned int & );
    311338        istype & ?|?( istype &, long int & );
     339        void ?|?( istype &, long int & );
    312340        istype & ?|?( istype &, unsigned long int & );
     341        void ?|?( istype &, unsigned long int & );
    313342        istype & ?|?( istype &, long long int & );
     343        void ?|?( istype &, long long int & );
    314344        istype & ?|?( istype &, unsigned long long int & );
    315 #if defined( __SIZEOF_INT128__ )
     345        void ?|?( istype &, unsigned long long int & );
     346        #if defined( __SIZEOF_INT128__ )
    316347        istype & ?|?( istype &, int128 & );
     348        void ?|?( istype &, int128 & );
    317349        istype & ?|?( istype &, unsigned int128 & );
    318 #endif // __SIZEOF_INT128__
     350        void ?|?( istype &, unsigned int128 & );
     351        #endif // __SIZEOF_INT128__
    319352
    320353        istype & ?|?( istype &, float & );
     354        void ?|?( istype &, float & );
    321355        istype & ?|?( istype &, double & );
     356        void ?|?( istype &, double & );
    322357        istype & ?|?( istype &, long double & );
     358        void ?|?( istype &, long double & );
    323359
    324360        istype & ?|?( istype &, float _Complex & );
     361        void ?|?( istype &, float _Complex & );
    325362        istype & ?|?( istype &, double _Complex & );
     363        void ?|?( istype &, double _Complex & );
    326364        istype & ?|?( istype &, long double _Complex & );
     365        void ?|?( istype &, long double _Complex & );
    327366
    328367//      istype & ?|?( istype &, const char [] );
    329         istype & ?|?( istype &, char * );
     368        istype & ?|?( istype &, char [] );
     369        void ?|?( istype &, char [] );
    330370
    331371        // manipulators
    332372        istype & ?|?( istype &, istype & (*)( istype & ) );
     373        void ?|?( istype &, istype & (*)( istype & ) );
    333374        istype & nl( istype & is );
    334375        istype & nlOn( istype & );
    335376        istype & nlOff( istype & );
     377} // distribution
     378
     379forall( istype & | istream( istype ) ) {
     380        istype & acquire( istype & );
    336381} // distribution
    337382
     
    352397
    353398static inline {
     399        _Istream_Cstr skip( const char scanset[] ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
    354400        _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; }
    355         _Istream_Cstr skip( const char scanset[] ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
    356401        _Istream_Cstr incl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
    357402        _Istream_Cstr & incl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
     
    363408        _Istream_Cstr & wdi( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
    364409} // distribution
    365 forall( istype & | istream( istype ) ) istype & ?|?( istype & is, _Istream_Cstr f );
     410forall( istype & | basic_istream( istype ) ) {
     411        istype & ?|?( istype & is, _Istream_Cstr f );
     412        void ?|?( istype & is, _Istream_Cstr f );
     413}
    366414
    367415struct _Istream_Char {
     
    373421        _Istream_Char & ignore( _Istream_Char & fmt ) { fmt.ignore = true; return fmt; }
    374422} // distribution
    375 forall( istype & | istream( istype ) ) istype & ?|?( istype & is, _Istream_Char f );
     423forall( istype & | basic_istream( istype ) ) {
     424        istype & ?|?( istype & is, _Istream_Char f );
     425        void ?|?( istype & is, _Istream_Char f );
     426}
    376427
    377428forall( T & | sized( T ) )
     
    389440        _Istream_Manip(T) & wdi( unsigned int w, _Istream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
    390441} /* distribution */ \
    391 forall( istype & | istream( istype ) ) { \
     442forall( istype & | basic_istream( istype ) ) { \
    392443        istype & ?|?( istype & is, _Istream_Manip(T) f ); \
     444        void ?|?( istype & is, _Istream_Manip(T) f ); \
    393445} // ?|?
    394446
  • libcfa/src/math.hfa

    rfeacef9 r5407cdc  
    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/startup.cfa

    rfeacef9 r5407cdc  
    3939
    4040    void disable_interrupts() __attribute__(( weak )) {}
    41     void enable_interrupts_noPoll() __attribute__(( weak )) {}
     41    void enable_interrupts() __attribute__(( weak )) {}
    4242} // extern "C"
    4343
  • libcfa/src/stdlib.hfa

    rfeacef9 r5407cdc  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jan 21 22:02:13 2021
    13 // Update Count     : 574
     12// Last Modified On : Tue Apr 20 21:20:03 2021
     13// Update Count     : 575
    1414//
    1515
     
    4444
    4545// Macro because of returns
    46 #define $ARRAY_ALLOC( allocation, alignment, dim ) \
     46#define ARRAY_ALLOC$( allocation, alignment, dim ) \
    4747        if ( _Alignof(T) <= libAlign() ) return (T *)(void *)allocation( dim, (size_t)sizeof(T) ); /* C allocation */ \
    4848        else return (T *)alignment( _Alignof(T), dim, sizeof(T) )
     
    5757
    5858        T * aalloc( size_t dim ) {
    59                 $ARRAY_ALLOC( aalloc, amemalign, dim );
     59                ARRAY_ALLOC$( aalloc, amemalign, dim );
    6060        } // aalloc
    6161
    6262        T * calloc( size_t dim ) {
    63                 $ARRAY_ALLOC( calloc, cmemalign, dim );
     63                ARRAY_ALLOC$( calloc, cmemalign, dim );
    6464        } // calloc
    6565
     
    119119                S_fill(T) ?`fill( T    a[], size_t nmemb )      { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; }
    120120
    121         3. Replace the $alloc_internal function which is outside ttype forall-block with following function:
    122                 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) {
     121        3. Replace the alloc_internal$ function which is outside ttype forall-block with following function:
     122                T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) {
    123123                        T * ptr = NULL;
    124124                        size_t size = sizeof(T);
     
    145145
    146146                        return ptr;
    147                 } // $alloc_internal
     147                } // alloc_internal$
    148148*/
    149149
     
    175175        S_realloc(T)    ?`realloc ( T * a )                             { return (S_realloc(T)){a}; }
    176176
    177         T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {
     177        T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {
    178178                T * ptr = NULL;
    179179                size_t size = sizeof(T);
     
    206206
    207207                return ptr;
    208         } // $alloc_internal
    209 
    210         forall( TT... | { T * $alloc_internal( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {
    211 
    212                 T * $alloc_internal( void *       , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) {
    213                 return $alloc_internal( Resize, (T*)0p, Align, Dim, Fill, rest);
    214                 }
    215 
    216                 T * $alloc_internal( void * Resize, T *        , size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest) {
    217                 return $alloc_internal( (void*)0p, Realloc, Align, Dim, Fill, rest);
    218                 }
    219 
    220                 T * $alloc_internal( void * Resize, T * Realloc, size_t      , size_t Dim, S_fill(T) Fill, T_align Align, TT rest) {
    221                 return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest);
    222                 }
    223 
    224                 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T)     , S_fill(T) Fill, TT rest) {
    225                 return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest);
     208        } // alloc_internal$
     209
     210        forall( TT... | { T * alloc_internal$( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {
     211
     212                T * alloc_internal$( void *       , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) {
     213                return alloc_internal$( Resize, (T*)0p, Align, Dim, Fill, rest);
     214                }
     215
     216                T * alloc_internal$( void * Resize, T *        , size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest) {
     217                return alloc_internal$( (void*)0p, Realloc, Align, Dim, Fill, rest);
     218                }
     219
     220                T * alloc_internal$( void * Resize, T * Realloc, size_t      , size_t Dim, S_fill(T) Fill, T_align Align, TT rest) {
     221                return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest);
     222                }
     223
     224                T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T)     , S_fill(T) Fill, TT rest) {
     225                return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest);
    226226                }
    227227
    228228            T * alloc( TT all ) {
    229                 return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all);
     229                return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all);
    230230            }
    231231
    232232            T * alloc( size_t dim, TT all ) {
    233                 return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all);
     233                return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all);
    234234            }
    235235
  • libcfa/src/time.hfa

    rfeacef9 r5407cdc  
    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 21 06:32:31 2021
     13// Update Count     : 667
    1414//
    1515
     
    2828
    2929static inline {
     30        void ?{}( Duration & dur, timeval t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
     31        void ?{}( Duration & dur, timespec t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
     32
    3033        Duration ?=?( Duration & dur, __attribute__((unused)) zero_t ) { return dur{ 0 }; }
     34        Duration ?=?( Duration & dur, timeval t ) with( dur ) {
     35                tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL);
     36                return dur;
     37        } // ?=?
     38        Duration ?=?( Duration & dur, timespec t ) with( dur ) {
     39                tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
     40                return dur;
     41        } // ?=?
    3142
    3243        Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tn }; }
     
    4960        Duration ?%?( Duration lhs, Duration rhs ) { return (Duration)@{ lhs.tn % rhs.tn }; }
    5061        Duration ?%=?( Duration & lhs, Duration rhs ) { lhs = lhs % rhs; return lhs; }
     62
     63        bool ?==?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn == 0; }
     64        bool ?!=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn != 0; }
     65        bool ?<? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn <  0; }
     66        bool ?<=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn <= 0; }
     67        bool ?>? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >  0; }
     68        bool ?>=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >= 0; }
    5169
    5270        bool ?==?( Duration lhs, Duration rhs ) { return lhs.tn == rhs.tn; }
     
    5674        bool ?>? ( Duration lhs, Duration rhs ) { return lhs.tn >  rhs.tn; }
    5775        bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tn >= rhs.tn; }
    58 
    59         bool ?==?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn == 0; }
    60         bool ?!=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn != 0; }
    61         bool ?<? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn <  0; }
    62         bool ?<=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn <= 0; }
    63         bool ?>? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >  0; }
    64         bool ?>=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >= 0; }
    6576
    6677        Duration abs( Duration rhs ) { return rhs.tn >= 0 ? rhs : -rhs; }
     
    152163void ?{}( Time & time, int year, int month = 1, int day = 1, int hour = 0, int min = 0, int sec = 0, int64_t nsec = 0 );
    153164static inline {
     165        void ?{}( Time & time, timeval t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
     166        void ?{}( Time & time, timespec t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
     167
    154168        Time ?=?( Time & time, __attribute__((unused)) zero_t ) { return time{ 0 }; }
    155 
    156         void ?{}( Time & time, timeval t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
    157169        Time ?=?( Time & time, timeval t ) with( time ) {
    158170                tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL);
    159171                return time;
    160172        } // ?=?
    161 
    162         void ?{}( Time & time, timespec t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
    163173        Time ?=?( Time & time, timespec t ) with( time ) {
    164174                tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
  • libcfa/src/virtual.c

    rfeacef9 r5407cdc  
    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/Convert.cpp

    rfeacef9 r5407cdc  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 09 15::37::05 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Nov 12 10:07:00 2020
    13 // Update Count     : 34
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Mar 12 18:43:51 2021
     13// Update Count     : 36
    1414//
    1515
     
    327327        const ast::AsmDecl * visit( const ast::AsmDecl * node ) override final {
    328328                auto decl = new AsmDecl( get<AsmStmt>().accept1( node->stmt ) );
     329                declPostamble( decl, node );
     330                return nullptr;
     331        }
     332
     333        const ast::DirectiveDecl * visit( const ast::DirectiveDecl * node ) override final {
     334                auto decl = new DirectiveDecl( get<DirectiveStmt>().accept1( node->stmt ) );
    329335                declPostamble( decl, node );
    330336                return nullptr;
     
    17691775        }
    17701776
     1777        virtual void visit( const DirectiveDecl * old ) override final {
     1778                auto decl = new ast::DirectiveDecl{
     1779                        old->location,
     1780                        GET_ACCEPT_1(stmt, DirectiveStmt)
     1781                };
     1782                decl->extension  = old->extension;
     1783                decl->uniqueId   = old->uniqueId;
     1784                decl->storage    = { old->storageClasses.val };
     1785
     1786                this->node = decl;
     1787        }
     1788
    17711789        virtual void visit( const StaticAssertDecl * old ) override final {
    17721790                auto decl = new ast::StaticAssertDecl{
  • src/AST/Decl.hpp

    rfeacef9 r5407cdc  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 11 20:48:38 2021
    13 // Update Count     : 30
     12// Last Modified On : Fri Mar 12 18:25:05 2021
     13// Update Count     : 32
    1414//
    1515
     
    365365};
    366366
     367/// C-preprocessor directive `#...`
     368class DirectiveDecl : public Decl {
     369public:
     370        ptr<DirectiveStmt> stmt;
     371
     372        DirectiveDecl( const CodeLocation & loc, DirectiveStmt * stmt )
     373        : Decl( loc, "", {}, {} ), stmt(stmt) {}
     374
     375        const DirectiveDecl * accept( Visitor & v ) const override { return v.visit( this ); }
     376private:
     377        DirectiveDecl * clone() const override { return new DirectiveDecl( *this ); }
     378        MUTATE_FRIEND
     379};
     380
    367381class StaticAssertDecl : public Decl {
    368382public:
  • src/AST/Expr.cpp

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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/AST/Fwd.hpp

    rfeacef9 r5407cdc  
    99// Author           : Andrew Beach
    1010// Created On       : Wed May  8 16:05:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Jul 23 14:15:00 2020
    13 // Update Count     : 2
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Mar 12 18:37:39 2021
     13// Update Count     : 4
    1414//
    1515
     
    3535class TypedefDecl;
    3636class AsmDecl;
     37class DirectiveDecl;
    3738class StaticAssertDecl;
    3839
  • src/AST/Node.cpp

    rfeacef9 r5407cdc  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 16 14:16:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jun  5 10:21:00 2020
    13 // Update Count     : 1
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Mar 12 18:25:06 2021
     13// Update Count     : 2
    1414//
    1515
     
    130130template class ast::ptr_base< ast::AsmDecl, ast::Node::ref_type::weak >;
    131131template class ast::ptr_base< ast::AsmDecl, ast::Node::ref_type::strong >;
     132template class ast::ptr_base< ast::DirectiveDecl, ast::Node::ref_type::weak >;
     133template class ast::ptr_base< ast::DirectiveDecl, ast::Node::ref_type::strong >;
    132134template class ast::ptr_base< ast::StaticAssertDecl, ast::Node::ref_type::weak >;
    133135template class ast::ptr_base< ast::StaticAssertDecl, ast::Node::ref_type::strong >;
  • src/AST/Pass.hpp

    rfeacef9 r5407cdc  
    139139        const ast::Decl *             visit( const ast::TypedefDecl          * ) override final;
    140140        const ast::AsmDecl *          visit( const ast::AsmDecl              * ) override final;
     141        const ast::DirectiveDecl *    visit( const ast::DirectiveDecl        * ) override final;
    141142        const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) override final;
    142143        const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) override final;
  • src/AST/Pass.impl.hpp

    rfeacef9 r5407cdc  
    646646
    647647//--------------------------------------------------------------------------
     648// DirectiveDecl
     649template< typename core_t >
     650const ast::DirectiveDecl * ast::Pass< core_t >::visit( const ast::DirectiveDecl * node ) {
     651        VISIT_START( node );
     652
     653        VISIT(
     654                maybe_accept( node, &DirectiveDecl::stmt );
     655        )
     656
     657        VISIT_END( DirectiveDecl, node );
     658}
     659
     660//--------------------------------------------------------------------------
    648661// StaticAssertDecl
    649662template< typename core_t >
  • src/AST/Print.cpp

    rfeacef9 r5407cdc  
    387387
    388388        virtual const ast::AsmDecl * visit( const ast::AsmDecl * node ) override final {
     389                safe_print( node->stmt );
     390                return node;
     391        }
     392
     393        virtual const ast::DirectiveDecl * visit( const ast::DirectiveDecl * node ) override final {
    389394                safe_print( node->stmt );
    390395                return node;
  • src/AST/Type.cpp

    rfeacef9 r5407cdc  
    105105}
    106106
     107// --- BaseInstType
     108
    107109std::vector<readonly<Decl>> BaseInstType::lookup( const std::string& name ) const {
    108110        assertf( aggr(), "Must have aggregate to perform lookup" );
     
    119121template<typename decl_t>
    120122SueInstType<decl_t>::SueInstType(
    121         const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
    122 : BaseInstType( b->name, q, move(as) ), base( b ) {}
     123        const base_type * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
     124: BaseInstType( b->name, q, std::move(as) ), base( b ) {}
    123125
    124126template<typename decl_t>
     
    142144        const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
    143145: BaseInstType( b->name, q, move(as) ), base( b ) {}
     146
     147// --- TypeInstType
    144148
    145149void TypeInstType::set_base( const TypeDecl * b ) {
  • src/AST/Visitor.hpp

    rfeacef9 r5407cdc  
    99// Author           : Andrew Beach
    1010// Created On       : Thr May 9 15:28:00 2019
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr May 9 15:33:00 2019
    13 // Update Count     : 0
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Mar 12 18:25:07 2021
     13// Update Count     : 1
    1414//
    1515
     
    3131    virtual const ast::Decl *             visit( const ast::TypedefDecl          * ) = 0;
    3232    virtual const ast::AsmDecl *          visit( const ast::AsmDecl              * ) = 0;
     33    virtual const ast::DirectiveDecl *    visit( const ast::DirectiveDecl        * ) = 0;
    3334    virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) = 0;
    3435    virtual const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) = 0;
  • src/CodeGen/CodeGenerator.cc

    rfeacef9 r5407cdc  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 08:32:48 2020
    13 // Update Count     : 532
     12// Last Modified On : Fri Mar 12 19:00:42 2021
     13// Update Count     : 536
    1414//
    1515#include "CodeGenerator.h"
     
    935935                if ( asmStmt->get_instruction() ) asmStmt->get_instruction()->accept( *visitor );
    936936                output << " )";
     937        }
     938
     939        void CodeGenerator::postvisit( DirectiveDecl * directiveDecl ) {
     940                output << endl << directiveDecl->get_stmt()->directive; // endl prevents spaces before directive
    937941        }
    938942
  • src/CodeGen/CodeGenerator.h

    rfeacef9 r5407cdc  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:58:31 2020
    13 // Update Count     : 62
     12// Last Modified On : Fri Mar 12 18:35:38 2021
     13// Update Count     : 63
    1414//
    1515
     
    105105                void postvisit( DirectiveStmt * );
    106106                void postvisit( AsmDecl * );                                    // special: statement in declaration context
     107                void postvisit( DirectiveDecl * );                              // special: statement in declaration context
    107108                void postvisit( IfStmt * );
    108109                void postvisit( SwitchStmt * );
  • src/Common/CodeLocationTools.cpp

    rfeacef9 r5407cdc  
    99// Author           : Andrew Beach
    1010// Created On       : Fri Dec  4 15:42:00 2020
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Dec  9  9:42:00 2020
    13 // Update Count     : 1
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Mar 12 18:35:37 2021
     13// Update Count     : 2
    1414//
    1515
     
    102102    macro(TypedefDecl, Decl) \
    103103    macro(AsmDecl, AsmDecl) \
     104    macro(DirectiveDecl, DirectiveDecl) \
    104105    macro(StaticAssertDecl, StaticAssertDecl) \
    105106    macro(CompoundStmt, CompoundStmt) \
  • src/Common/PassVisitor.h

    rfeacef9 r5407cdc  
    7777        virtual void visit( AsmDecl * asmDecl ) override final;
    7878        virtual void visit( const AsmDecl * asmDecl ) override final;
     79        virtual void visit( DirectiveDecl * directiveDecl ) override final;
     80        virtual void visit( const DirectiveDecl * directiveDecl ) override final;
    7981        virtual void visit( StaticAssertDecl * assertDecl ) override final;
    8082        virtual void visit( const StaticAssertDecl * assertDecl ) override final;
     
    261263        virtual Declaration * mutate( TypedefDecl * typeDecl ) override final;
    262264        virtual AsmDecl * mutate( AsmDecl * asmDecl ) override final;
     265        virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) override final;
    263266        virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) override final;
    264267
  • src/Common/PassVisitor.impl.h

    rfeacef9 r5407cdc  
    973973
    974974//--------------------------------------------------------------------------
     975// DirectiveDecl
     976template< typename pass_type >
     977void PassVisitor< pass_type >::visit( DirectiveDecl * node ) {
     978        VISIT_START( node );
     979
     980        maybeAccept_impl( node->stmt, *this );
     981
     982        VISIT_END( node );
     983}
     984
     985template< typename pass_type >
     986void PassVisitor< pass_type >::visit( const DirectiveDecl * node ) {
     987        VISIT_START( node );
     988
     989        maybeAccept_impl( node->stmt, *this );
     990
     991        VISIT_END( node );
     992}
     993
     994template< typename pass_type >
     995DirectiveDecl * PassVisitor< pass_type >::mutate( DirectiveDecl * node ) {
     996        MUTATE_START( node );
     997
     998        maybeMutate_impl( node->stmt, *this );
     999
     1000        MUTATE_END( DirectiveDecl, node );
     1001}
     1002
     1003//--------------------------------------------------------------------------
    9751004// StaticAssertDecl
    9761005template< typename pass_type >
  • src/Concurrency/Keywords.cc

    rfeacef9 r5407cdc  
    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        };
     
    393400                        except_decl = decl;
    394401                }
     402                else if ( !typeid_decl && typeid_name == decl->name && decl->body ) {
     403                        typeid_decl = decl;
     404                }
    395405                else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
    396406                        vtable_decl = decl;
     
    404414                if ( type_decl && isDestructorFor( decl, type_decl ) )
    405415                        dtor_decl = decl;
    406                 else if ( vtable_name.empty() )
    407                         ;
    408                 else if( !decl->has_body() )
     416                else if ( vtable_name.empty() || !decl->has_body() )
    409417                        ;
    410418                else if ( auto param = isMainFor( decl, cast_target ) ) {
     
    418426                        std::list< Expression * > poly_args = { new TypeExpr( struct_type->clone() ) };
    419427                        ObjectDecl * vtable_object = Virtual::makeVtableInstance(
     428                                "_default_vtable_object_declaration",
    420429                                vtable_decl->makeInst( poly_args ), struct_type, nullptr );
    421430                        declsToAddAfter.push_back( vtable_object );
     431                        declsToAddAfter.push_back(
     432                                new ObjectDecl(
     433                                        Virtual::concurrentDefaultVTableName(),
     434                                        Type::Const,
     435                                        LinkageSpec::Cforall,
     436                                        /* bitfieldWidth */ nullptr,
     437                                        new ReferenceType( Type::Const, vtable_object->type->clone() ),
     438                                        new SingleInit( new VariableExpr( vtable_object ) )
     439                                )
     440                        );
    422441                        declsToAddAfter.push_back( Virtual::makeGetExceptionFunction(
    423442                                vtable_object, except_decl->makeInst( std::move( poly_args ) )
     
    448467                if( !dtor_decl ) SemanticError( decl, context_error );
    449468
    450                 addVtableForward( decl );
     469                if ( !exception_name.empty() ) {
     470                        if( !typeid_decl ) SemanticError( decl, context_error );
     471                        if( !vtable_decl ) SemanticError( decl, context_error );
     472
     473                        addTypeId( decl );
     474                        addVtableForward( decl );
     475                }
    451476                FunctionDecl * func = forwardDeclare( decl );
    452477                ObjectDecl * field = addField( decl );
     
    454479        }
    455480
     481        void ConcurrentSueKeyword::addTypeId( StructDecl * decl ) {
     482                assert( typeid_decl );
     483                StructInstType typeid_type( Type::Const, typeid_decl );
     484                typeid_type.parameters.push_back( new TypeExpr(
     485                        new StructInstType( noQualifiers, decl )
     486                        ) );
     487                declsToAddBefore.push_back( Virtual::makeTypeIdInstance( &typeid_type ) );
     488        }
     489
    456490        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                 }
     491                assert( vtable_decl );
     492                std::list< Expression * > poly_args = {
     493                        new TypeExpr( new StructInstType( noQualifiers, decl ) ),
     494                };
     495                declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
     496                        vtable_decl->makeInst( poly_args ),
     497                        except_decl->makeInst( poly_args )
     498                ) );
     499                ObjectDecl * vtable_object = Virtual::makeVtableForward(
     500                        "_default_vtable_object_declaration",
     501                        vtable_decl->makeInst( move( poly_args ) ) );
     502                declsToAddBefore.push_back( vtable_object );
     503                declsToAddBefore.push_back(
     504                        new ObjectDecl(
     505                                Virtual::concurrentDefaultVTableName(),
     506                                Type::Const,
     507                                LinkageSpec::Cforall,
     508                                /* bitfieldWidth */ nullptr,
     509                                new ReferenceType( Type::Const, vtable_object->type->clone() ),
     510                                /* init */ nullptr
     511                        )
     512                );
    471513        }
    472514
  • src/Parser/DeclarationNode.cc

    rfeacef9 r5407cdc  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 11 20:58:07 2021
    13 // Update Count     : 1137
     12// Last Modified On : Tue Mar 23 08:44:08 2021
     13// Update Count     : 1149
    1414//
    1515
     
    167167}
    168168
    169 DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {
    170         DeclarationNode * newnode = new DeclarationNode;
    171         newnode->name = name;
    172         newnode->type = new TypeData( TypeData::Function );
    173         newnode->type->function.params = param;
    174         newnode->type->function.body = body;
    175 
    176         if ( ret ) {
    177                 newnode->type->base = ret->type;
    178                 ret->type = nullptr;
    179                 delete ret;
    180         } // if
    181 
    182         return newnode;
    183 } // DeclarationNode::newFunction
    184 
    185 
    186169DeclarationNode * DeclarationNode::newStorageClass( Type::StorageClasses sc ) {
    187170        DeclarationNode * newnode = new DeclarationNode;
     
    237220        return newnode;
    238221} // DeclarationNode::newForall
    239 
    240 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) {
    241         DeclarationNode * newnode = new DeclarationNode;
    242         newnode->type = new TypeData( TypeData::SymbolicInst );
    243         newnode->type->symbolic.name = name;
    244         newnode->type->symbolic.isTypedef = true;
    245         newnode->type->symbolic.params = nullptr;
    246         return newnode;
    247 } // DeclarationNode::newFromTypedef
    248222
    249223DeclarationNode * DeclarationNode::newFromGlobalScope() {
     
    289263} // DeclarationNode::newEnum
    290264
     265DeclarationNode * DeclarationNode::newName( const string * name ) {
     266        DeclarationNode * newnode = new DeclarationNode;
     267        assert( ! newnode->name );
     268        newnode->name = name;
     269        return newnode;
     270} // DeclarationNode::newName
     271
    291272DeclarationNode * DeclarationNode::newEnumConstant( const string * name, ExpressionNode * constant ) {
    292         DeclarationNode * newnode = new DeclarationNode;
    293         newnode->name = name;
     273        DeclarationNode * newnode = newName( name );
    294274        newnode->enumeratorValue.reset( constant );
    295275        return newnode;
    296276} // DeclarationNode::newEnumConstant
    297277
    298 DeclarationNode * DeclarationNode::newName( const string * name ) {
    299         DeclarationNode * newnode = new DeclarationNode;
    300         newnode->name = name;
    301         return newnode;
    302 } // DeclarationNode::newName
     278DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) {
     279        DeclarationNode * newnode = new DeclarationNode;
     280        newnode->type = new TypeData( TypeData::SymbolicInst );
     281        newnode->type->symbolic.name = name;
     282        newnode->type->symbolic.isTypedef = true;
     283        newnode->type->symbolic.params = nullptr;
     284        return newnode;
     285} // DeclarationNode::newFromTypedef
    303286
    304287DeclarationNode * DeclarationNode::newFromTypeGen( const string * name, ExpressionNode * params ) {
     
    312295
    313296DeclarationNode * DeclarationNode::newTypeParam( TypeDecl::Kind tc, const string * name ) {
    314         DeclarationNode * newnode = new DeclarationNode;
     297        DeclarationNode * newnode = newName( name );
    315298        newnode->type = nullptr;
    316         assert( ! newnode->name );
    317 //      newnode->variable.name = name;
    318         newnode->name = name;
    319299        newnode->variable.tyClass = tc;
    320300        newnode->variable.assertions = nullptr;
     
    343323
    344324DeclarationNode * DeclarationNode::newTypeDecl( const string * name, DeclarationNode * typeParams ) {
    345         DeclarationNode * newnode = new DeclarationNode;
    346         newnode->name = name;
     325        DeclarationNode * newnode = newName( name );
    347326        newnode->type = new TypeData( TypeData::Symbolic );
    348327        newnode->type->symbolic.isTypedef = false;
     
    417396} // DeclarationNode::newBuiltinType
    418397
     398DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {
     399        DeclarationNode * newnode = newName( name );
     400        newnode->type = new TypeData( TypeData::Function );
     401        newnode->type->function.params = param;
     402        newnode->type->function.body = body;
     403
     404        if ( ret ) {
     405                newnode->type->base = ret->type;
     406                ret->type = nullptr;
     407                delete ret;
     408        } // if
     409
     410        return newnode;
     411} // DeclarationNode::newFunction
     412
    419413DeclarationNode * DeclarationNode::newAttribute( const string * name, ExpressionNode * expr ) {
    420414        DeclarationNode * newnode = new DeclarationNode;
     
    424418        newnode->attributes.push_back( new Attribute( *name, exprs ) );
    425419        delete name;
     420        return newnode;
     421}
     422
     423DeclarationNode * DeclarationNode::newDirectiveStmt( StatementNode * stmt ) {
     424        DeclarationNode * newnode = new DeclarationNode;
     425        newnode->directiveStmt = stmt;
    426426        return newnode;
    427427}
     
    879879}
    880880
    881 DeclarationNode * DeclarationNode::cloneType( string * newName ) {
    882         DeclarationNode * newnode = new DeclarationNode;
     881DeclarationNode * DeclarationNode::cloneType( string * name ) {
     882        DeclarationNode * newnode = newName( name );
    883883        newnode->type = maybeClone( type );
    884884        newnode->copySpecifiers( this );
    885         assert( newName );
    886         newnode->name = newName;
    887885        return newnode;
    888886}
     
    10721070                return new AsmDecl( strict_dynamic_cast<AsmStmt *>( asmStmt->build() ) );
    10731071        } // if
     1072        if ( directiveStmt ) {
     1073                return new DirectiveDecl( strict_dynamic_cast<DirectiveStmt *>( directiveStmt->build() ) );
     1074        } // if
    10741075
    10751076        if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
  • src/Parser/ParseNode.h

    rfeacef9 r5407cdc  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Jan  3 18:23:01 2021
    13 // Update Count     : 896
     12// Last Modified On : Fri Mar 12 15:19:04 2021
     13// Update Count     : 897
    1414//
    1515
     
    249249        static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false );
    250250        static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes
     251        static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement
    251252        static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement
    252253        static DeclarationNode * newStaticAssert( ExpressionNode * condition, Expression * message );
     
    345346        std::string error;
    346347        StatementNode * asmStmt = nullptr;
     348        StatementNode * directiveStmt = nullptr;
    347349
    348350        static UniqueName anonymous;
  • src/Parser/TypeData.h

    rfeacef9 r5407cdc  
    77// TypeData.h --
    88//
    9 // Author           : Rodolfo G. Esteves
     9// Author           : Peter A. Buhr
    1010// Created On       : Sat May 16 15:18:36 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:42:35 2019
    13 // Update Count     : 199
     12// Last Modified On : Sat Mar 27 09:05:35 2021
     13// Update Count     : 200
    1414//
    1515
    1616#pragma once
    1717
    18 #include <iosfwd>                // for ostream
    19 #include <list>                  // for list
    20 #include <string>                // for string
     18#include <iosfwd>                                                                               // for ostream
     19#include <list>                                                                                 // for list
     20#include <string>                                                                               // for string
    2121
    22 #include "ParseNode.h"           // for DeclarationNode, DeclarationNode::Ag...
    23 #include "SynTree/LinkageSpec.h" // for Spec
    24 #include "SynTree/Type.h"        // for Type, ReferenceToType (ptr only)
    25 #include "SynTree/SynTree.h"     // for Visitor Nodes
     22#include "ParseNode.h"                                                                  // for DeclarationNode, DeclarationNode::Ag...
     23#include "SynTree/LinkageSpec.h"                                                // for Spec
     24#include "SynTree/Type.h"                                                               // for Type, ReferenceToType (ptr only)
     25#include "SynTree/SynTree.h"                                                    // for Visitor Nodes
    2626
    2727struct TypeData {
     
    3333                const std::string * name = nullptr;
    3434                DeclarationNode * params = nullptr;
    35                 ExpressionNode * actuals = nullptr;                                             // holds actual parameters later applied to AggInst
     35                ExpressionNode * actuals = nullptr;                             // holds actual parameters later applied to AggInst
    3636                DeclarationNode * fields = nullptr;
    3737                bool body;
     
    6262
    6363        struct Function_t {
    64                 mutable DeclarationNode * params = nullptr;                             // mutables modified in buildKRFunction
    65                 mutable DeclarationNode * idList = nullptr;                             // old-style
     64                mutable DeclarationNode * params = nullptr;             // mutables modified in buildKRFunction
     65                mutable DeclarationNode * idList = nullptr;             // old-style
    6666                mutable DeclarationNode * oldDeclList = nullptr;
    6767                StatementNode * body = nullptr;
    68                 ExpressionNode * withExprs = nullptr;                                           // expressions from function's with_clause
     68                ExpressionNode * withExprs = nullptr;                   // expressions from function's with_clause
    6969        };
    7070
  • src/Parser/TypedefTable.cc

    rfeacef9 r5407cdc  
    1010// Created On       : Sat May 16 15:20:13 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 15 08:06:36 2020
    13 // Update Count     : 259
     12// Last Modified On : Mon Mar 15 20:56:47 2021
     13// Update Count     : 260
    1414//
    1515
     
    8989        debugPrint( cerr << "Adding enclosing at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl );
    9090        auto ret = kindTable.insertAt( scope, identifier, kind );
    91         if ( ! ret.second ) ret.first->second = kind;   // exists => update
     91        if ( ! ret.second ) ret.first->second = kind;           // exists => update
    9292} // TypedefTable::addToEnclosingScope
    9393
  • src/Parser/lex.ll

    rfeacef9 r5407cdc  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Tue Oct  6 18:15:41 2020
    13  * Update Count     : 743
     12 * Last Modified On : Thu Apr  1 13:22:31 2021
     13 * Update Count     : 754
    1414 */
    1515
     
    221221break                   { KEYWORD_RETURN(BREAK); }
    222222case                    { KEYWORD_RETURN(CASE); }
    223 catch                   { KEYWORD_RETURN(CATCH); }                              // CFA
    224 catchResume             { KEYWORD_RETURN(CATCHRESUME); }                // CFA
     223catch                   { QKEYWORD_RETURN(CATCH); }                             // CFA
     224catchResume             { QKEYWORD_RETURN(CATCHRESUME); }               // CFA
    225225char                    { KEYWORD_RETURN(CHAR); }
    226226choose                  { KEYWORD_RETURN(CHOOSE); }                             // CFA
     
    247247fallthrough             { KEYWORD_RETURN(FALLTHROUGH); }                // CFA
    248248fallthru                { KEYWORD_RETURN(FALLTHRU); }                   // CFA
    249 finally                 { KEYWORD_RETURN(FINALLY); }                    // CFA
     249finally                 { QKEYWORD_RETURN(FINALLY); }                   // CFA
     250fixup                   { QKEYWORD_RETURN(FIXUP); }                             // CFA
    250251float                   { KEYWORD_RETURN(FLOAT); }
    251252__float80               { KEYWORD_RETURN(uuFLOAT80); }                  // GCC
     
    287288or                              { QKEYWORD_RETURN(WOR); }                               // CFA
    288289otype                   { KEYWORD_RETURN(OTYPE); }                              // CFA
     290recover                 { QKEYWORD_RETURN(RECOVER); }                   // CFA
    289291register                { KEYWORD_RETURN(REGISTER); }
     292report                  { KEYWORD_RETURN(THROWRESUME); }                // CFA
    290293restrict                { KEYWORD_RETURN(RESTRICT); }                   // C99
    291294__restrict              { KEYWORD_RETURN(RESTRICT); }                   // GCC
     
    315318__typeof                { KEYWORD_RETURN(TYPEOF); }                             // GCC
    316319__typeof__              { KEYWORD_RETURN(TYPEOF); }                             // GCC
     320typeid                  { KEYWORD_RETURN(TYPEID); }                             // GCC
    317321union                   { KEYWORD_RETURN(UNION); }
    318322__uint128_t             { KEYWORD_RETURN(UINT128); }                    // GCC
     
    324328__volatile              { KEYWORD_RETURN(VOLATILE); }                   // GCC
    325329__volatile__    { KEYWORD_RETURN(VOLATILE); }                   // GCC
    326 waitfor                 { KEYWORD_RETURN(WAITFOR); }
    327 when                    { KEYWORD_RETURN(WHEN); }
     330vtable                  { KEYWORD_RETURN(VTABLE); }                             // CFA
     331waitfor                 { KEYWORD_RETURN(WAITFOR); }                    // CFA
     332when                    { KEYWORD_RETURN(WHEN); }                               // CFA
    328333while                   { KEYWORD_RETURN(WHILE); }
    329334with                    { KEYWORD_RETURN(WITH); }                               // CFA
  • src/Parser/parser.yy

    rfeacef9 r5407cdc  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb  3 18:30:12 2021
    13 // Update Count     : 4700
     12// Last Modified On : Mon Apr 26 18:41:54 2021
     13// Update Count     : 4990
    1414//
    1515
     
    3232//
    3333// 1. designation with and without '=' (use ':' instead)
    34 // 2. attributes not allowed in parenthesis of declarator
     34
    3535//
    3636// All of the syntactic extensions for GCC C are marked with the comment "GCC". The second extensions are for Cforall
     
    211211} // forCtrl
    212212
    213 bool forall = false, yyy = false;                                               // aggregate have one or more forall qualifiers ?
     213bool forall = false;                                                                    // aggregate have one or more forall qualifiers ?
    214214
    215215// https://www.gnu.org/software/bison/manual/bison.html#Location-Type
     
    264264%token RESTRICT                                                                                 // C99
    265265%token ATOMIC                                                                                   // C11
    266 %token FORALL MUTEX VIRTUAL COERCE                                              // CFA
     266%token FORALL MUTEX VIRTUAL VTABLE COERCE                               // CFA
    267267%token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED
    268268%token BOOL COMPLEX IMAGINARY                                                   // C99
     
    270270%token uFLOAT16 uFLOAT32 uFLOAT32X uFLOAT64 uFLOAT64X uFLOAT128 // GCC
    271271%token ZERO_T ONE_T                                                                             // CFA
    272 %token VALIST                                                                                   // GCC
    273 %token AUTO_TYPE                                                                                // GCC
    274 %token TYPEOF BASETYPEOF LABEL                                                  // GCC
     272%token SIZEOF TYPEOF VALIST AUTO_TYPE                                   // GCC
     273%token OFFSETOF BASETYPEOF TYPEID                                               // CFA
    275274%token ENUM STRUCT UNION
    276275%token EXCEPTION                                                                                // CFA
    277276%token GENERATOR COROUTINE MONITOR THREAD                               // CFA
    278277%token OTYPE FTYPE DTYPE TTYPE TRAIT                                    // CFA
    279 %token SIZEOF OFFSETOF
    280278// %token RESUME                                                                                        // CFA
     279%token LABEL                                                                                    // GCC
    281280%token SUSPEND                                                                                  // CFA
    282281%token ATTRIBUTE EXTENSION                                                              // GCC
    283282%token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN
    284 %token CHOOSE DISABLE ENABLE FALLTHRU FALLTHROUGH TRY CATCH CATCHRESUME FINALLY 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
    285285%token ASM                                                                                              // C99, extension ISO/IEC 9899:1999 Section J.5.10(1)
    286286%token ALIGNAS ALIGNOF GENERIC STATICASSERT                             // C11
    287287
    288288// names and constants: lexer differentiates between identifier and typedef names
    289 %token<tok> IDENTIFIER                  QUOTED_IDENTIFIER               TYPEDEFname                             TYPEGENname
    290 %token<tok> TIMEOUT                             WOR
    291 %token<tok> INTEGERconstant             CHARACTERconstant               STRINGliteral
     289%token<tok> IDENTIFIER          QUOTED_IDENTIFIER       TYPEDEFname             TYPEGENname
     290%token<tok> TIMEOUT                     WOR                                     CATCH                   RECOVER                 CATCHRESUME             FIXUP           FINALLY         // CFA
     291%token<tok> INTEGERconstant     CHARACTERconstant       STRINGliteral
    292292%token<tok> DIRECTIVE
    293293// Floating point constant is broken into three kinds of tokens because of the ambiguity with tuple indexing and
     
    321321%type<en> constant
    322322%type<en> tuple                                                 tuple_expression_list
    323 %type<op> ptrref_operator                               unary_operator                          assignment_operator
     323%type<op> ptrref_operator                               unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
    324324%type<en> primary_expression                    postfix_expression                      unary_expression
    325325%type<en> cast_expression_list                  cast_expression                         exponential_expression          multiplicative_expression       additive_expression
     
    373373
    374374%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
     375%type<decl> vtable vtable_opt default_opt
    375376
    376377%type<decl> trait_declaration trait_declaration_list trait_declaring_list trait_specifier
     
    428429
    429430%type<decl> type_declaration_specifier type_type_specifier type_name typegen_name
    430 %type<decl> typedef typedef_declaration typedef_expression
     431%type<decl> typedef_name typedef_declaration typedef_expression
    431432
    432433%type<decl> variable_type_redeclarator type_ptr type_array type_function
     
    440441
    441442%type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
    442 %type<decl> type_specifier type_specifier_nobody enum_specifier_nobody
     443%type<decl> type_specifier type_specifier_nobody
    443444
    444445%type<decl> variable_declarator variable_ptr variable_array variable_function
    445446%type<decl> variable_abstract_declarator variable_abstract_ptr variable_abstract_array variable_abstract_function
    446447
    447 %type<decl> attribute_list_opt attribute_list attribute_opt attribute attribute_name_list attribute_name
     448%type<decl> attribute_list_opt attribute_list attribute attribute_name_list attribute_name
    448449
    449450// initializers
     
    462463// Order of these lines matters (low-to-high precedence). THEN is left associative over WOR/TIMEOUT/ELSE, WOR is left
    463464// associative over TIMEOUT/ELSE, and TIMEOUT is left associative over ELSE.
    464 %precedence THEN        // rule precedence for IF/WAITFOR statement
    465 %precedence WOR         // token precedence for start of WOR in WAITFOR statement
    466 %precedence TIMEOUT     // token precedence for start of TIMEOUT in WAITFOR statement
    467 %precedence ELSE        // token precedence for start of else clause in IF/WAITFOR statement
     465%precedence THEN                // rule precedence for IF/WAITFOR statement
     466%precedence WOR                 // token precedence for start of WOR in WAITFOR statement
     467%precedence TIMEOUT             // token precedence for start of TIMEOUT in WAITFOR statement
     468%precedence CATCH               // token precedence for start of TIMEOUT in WAITFOR statement
     469%precedence RECOVER             // token precedence for start of TIMEOUT in WAITFOR statement
     470%precedence CATCHRESUME // token precedence for start of TIMEOUT in WAITFOR statement
     471%precedence FIXUP               // token precedence for start of TIMEOUT in WAITFOR statement
     472%precedence FINALLY             // token precedence for start of TIMEOUT in WAITFOR statement
     473%precedence ELSE                // token precedence for start of else clause in IF/WAITFOR statement
     474
    468475
    469476// Handle shift/reduce conflict for generic type by shifting the '(' token. For example, this string is ambiguous:
     
    544551        TIMEOUT
    545552        | WOR
     553        | CATCH
     554        | RECOVER
     555        | CATCHRESUME
     556        | FIXUP
     557        | FINALLY
    546558        ;
    547559
     
    774786        | OFFSETOF '(' type_no_function ',' identifier ')'
    775787                { $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) ); }
     788        | TYPEID '(' type_no_function ')'
     789                {
     790                        SemanticError( yylloc, "typeid name is currently unimplemented." ); $$ = nullptr;
     791                        // $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) );
     792                }
    776793        ;
    777794
     
    795812                { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
    796813        | '(' aggregate_control '&' ')' cast_expression         // CFA
     814                { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
     815        | '(' aggregate_control '*' ')' cast_expression         // CFA
    797816                { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
    798817        | '(' VIRTUAL ')' cast_expression                                       // CFA
     
    939958
    940959assignment_operator:
     960        simple_assignment_operator
     961        | compound_assignment_operator
     962        ;
     963
     964simple_assignment_operator:
    941965        '='                                                                                     { $$ = OperKinds::Assign; }
    942         | ATassign                                                                      { $$ = OperKinds::AtAssn; }
    943         | EXPassign                                                                     { $$ = OperKinds::ExpAssn; }
     966        | ATassign                                                                      { $$ = OperKinds::AtAssn; } // CFA
     967        ;
     968
     969compound_assignment_operator:
     970        EXPassign                                                                       { $$ = OperKinds::ExpAssn; }
    944971        | MULTassign                                                            { $$ = OperKinds::MulAssn; }
    945972        | DIVassign                                                                     { $$ = OperKinds::DivAssn; }
     
    10191046                { $$ = new StatementNode( build_compound( (StatementNode *)0 ) ); }
    10201047        | '{' push
    1021           local_label_declaration_opt                                           // GCC, local labels
     1048          local_label_declaration_opt                                           // GCC, local labels appear at start of block
    10221049          statement_decl_list                                                           // C99, intermix declarations and statements
    10231050          pop '}'
     
    12171244        | comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA
    12181245                { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, $7 ); }
     1246
     1247        | comma_expression ';' TYPEDEFname                                      // CFA, array type
     1248                {
     1249                        SemanticError( yylloc, "Array interator is currently unimplemented." ); $$ = nullptr;
     1250                        $$ = forCtrl( new ExpressionNode( build_varref( $3 ) ), $1, nullptr, OperKinds::Range, nullptr, nullptr );
     1251                }
    12191252
    12201253                // There is a S/R conflicit if ~ and -~ are factored out.
     
    13661399
    13671400exception_statement:
    1368         TRY compound_statement handler_clause
     1401        TRY compound_statement handler_clause                                   %prec THEN
    13691402                { $$ = new StatementNode( build_try( $2, $3, 0 ) ); }
    13701403        | TRY compound_statement finally_clause
     
    13891422handler_key:
    13901423        CATCH                                                                           { $$ = CatchStmt::Terminate; }
     1424        | RECOVER                                                                       { $$ = CatchStmt::Terminate; }
    13911425        | CATCHRESUME                                                           { $$ = CatchStmt::Resume; }
     1426        | FIXUP                                                                         { $$ = CatchStmt::Resume; }
    13921427        ;
    13931428
     
    17411776        ;
    17421777
    1743 enum_specifier_nobody:                                                                  // type specifier - {...}
    1744                 // Preclude SUE declarations in restricted scopes (see type_specifier_nobody)
    1745         basic_type_specifier
    1746         | sue_type_specifier_nobody
    1747         ;
    1748 
    17491778type_qualifier_list_opt:                                                                // GCC, used in asm_statement
    17501779        // empty
     
    17661795type_qualifier:
    17671796        type_qualifier_name
    1768         | attribute
     1797        | attribute                                                                                     // trick handles most atrribute locations
    17691798        ;
    17701799
     
    18741903        | AUTO_TYPE
    18751904                { $$ = DeclarationNode::newBuiltinType( DeclarationNode::AutoType ); }
     1905        | vtable
     1906        ;
     1907
     1908vtable_opt:
     1909        // empty
     1910                { $$ = nullptr; }
     1911        | vtable;
     1912        ;
     1913
     1914vtable:
     1915        VTABLE '(' type_list ')' default_opt
     1916                { SemanticError( yylloc, "vtable is currently unimplemented." ); $$ = nullptr; }
     1917        ;
     1918
     1919default_opt:
     1920        // empty
     1921                { $$ = nullptr; }
     1922        | DEFAULT
     1923                { SemanticError( yylloc, "vtable default is currently unimplemented." ); $$ = nullptr; }
    18761924        ;
    18771925
     
    20252073          '{' field_declaration_list_opt '}' type_parameters_opt
    20262074                { $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); }
    2027         | aggregate_key attribute_list_opt type_name
    2028                 {
    2029                         // for type_name can be a qualified type name S.T, in which case only the last name in the chain needs a typedef (other names in the chain should already have one)
    2030                         typedefTable.makeTypedef( *$3->type->leafName(), forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
     2075        | aggregate_key attribute_list_opt TYPEDEFname          // unqualified type name
     2076                {
     2077                        typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
    20312078                        forall = false;                                                         // reset
    20322079                }
    20332080          '{' field_declaration_list_opt '}' type_parameters_opt
    2034                 { $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, $8, $6, true )->addQualifiers( $2 ); }
     2081                {
     2082                        DeclarationNode::newFromTypedef( $3 );
     2083                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     2084                }
     2085        | aggregate_key attribute_list_opt TYPEGENname          // unqualified type name
     2086                {
     2087                        typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
     2088                        forall = false;                                                         // reset
     2089                }
     2090          '{' field_declaration_list_opt '}' type_parameters_opt
     2091                {
     2092                        DeclarationNode::newFromTypeGen( $3, nullptr );
     2093                        $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
     2094                }
    20352095        | aggregate_type_nobody
    20362096        ;
     
    20692129
    20702130aggregate_data:
    2071         STRUCT
    2072                 { yyy = true; $$ = AggregateDecl::Struct; }
     2131        STRUCT vtable_opt
     2132                { $$ = AggregateDecl::Struct; }
    20732133        | UNION
    2074                 { yyy = true; $$ = AggregateDecl::Union; }
     2134                { $$ = AggregateDecl::Union; }
    20752135        | EXCEPTION                                                                                     // CFA
    2076                 // { yyy = true; $$ = AggregateDecl::Exception; }
    2077                 { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2136                { $$ = AggregateDecl::Exception; }
     2137          //            { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20782138        ;
    20792139
    20802140aggregate_control:                                                                              // CFA
    20812141        MONITOR
    2082                 { yyy = true; $$ = AggregateDecl::Monitor; }
     2142                { $$ = AggregateDecl::Monitor; }
    20832143        | MUTEX STRUCT
    2084                 { yyy = true; $$ = AggregateDecl::Monitor; }
     2144                { $$ = AggregateDecl::Monitor; }
    20852145        | GENERATOR
    2086                 { yyy = true; $$ = AggregateDecl::Generator; }
     2146                { $$ = AggregateDecl::Generator; }
    20872147        | MUTEX GENERATOR
    20882148                { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20892149        | COROUTINE
    2090                 { yyy = true; $$ = AggregateDecl::Coroutine; }
     2150                { $$ = AggregateDecl::Coroutine; }
    20912151        | MUTEX COROUTINE
    20922152                { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    20932153        | THREAD
    2094                 { yyy = true; $$ = AggregateDecl::Thread; }
     2154                { $$ = AggregateDecl::Thread; }
    20952155        | MUTEX THREAD
    20962156                { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     
    21882248        ;
    21892249
    2190 // Cannot use attribute_list_opt because of ambiguity with enum_specifier_nobody, which already parses attribute.
    2191 // Hence, only a single attribute is allowed after the "ENUM".
    21922250enum_type:                                                                                              // enum
    2193         ENUM attribute_opt '{' enumerator_list comma_opt '}'
     2251        ENUM attribute_list_opt '{' enumerator_list comma_opt '}'
    21942252                { $$ = DeclarationNode::newEnum( nullptr, $4, true )->addQualifiers( $2 ); }
    2195         | ENUM attribute_opt identifier
     2253        | ENUM attribute_list_opt identifier
    21962254                { typedefTable.makeTypedef( *$3 ); }
    21972255          '{' enumerator_list comma_opt '}'
    21982256                { $$ = DeclarationNode::newEnum( $3, $6, true )->addQualifiers( $2 ); }
    2199         | ENUM attribute_opt typedef                                            // enum cannot be generic
     2257        | ENUM attribute_list_opt typedef_name                          // unqualified type name
    22002258          '{' enumerator_list comma_opt '}'
    22012259                { $$ = DeclarationNode::newEnum( $3->name, $5, true )->addQualifiers( $2 ); }
    2202         | ENUM enum_specifier_nobody '{' enumerator_list comma_opt '}'
    2203                 // { $$ = DeclarationNode::newEnum( nullptr, $4, true ); }
    2204                 { SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; }
    2205         | ENUM enum_specifier_nobody declarator '{' enumerator_list comma_opt '}'
    2206                 // {
    2207                 //      typedefTable.makeTypedef( *$3->name );
    2208                 //      $$ = DeclarationNode::newEnum( nullptr, $5, true );
    2209                 // }
    2210                 { SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; }
     2260        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
     2261                {
     2262                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
     2263                        SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr;
     2264                }
     2265        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
     2266                {
     2267                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
     2268                        typedefTable.makeTypedef( *$6 );
     2269                }
     2270          '{' enumerator_list comma_opt '}'
     2271                {
     2272                        SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr;
     2273                }
     2274        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}'
     2275                {
     2276                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
     2277                        typedefTable.makeTypedef( *$6->name );
     2278                        SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr;
     2279                }
    22112280        | enum_type_nobody
    22122281        ;
    22132282
    22142283enum_type_nobody:                                                                               // enum - {...}
    2215         ENUM attribute_opt identifier
    2216                 {
    2217                         typedefTable.makeTypedef( *$3 );
    2218                         $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 );
    2219                 }
    2220         | ENUM attribute_opt type_name                                          // enum cannot be generic
    2221                 {
    2222                         typedefTable.makeTypedef( *$3->type->symbolic.name );
    2223                         $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 );
    2224                 }
     2284        ENUM attribute_list_opt identifier
     2285                { typedefTable.makeTypedef( *$3 ); $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 ); }
     2286        | ENUM attribute_list_opt type_name                                     // qualified type name
     2287                { typedefTable.makeTypedef( *$3->type->symbolic.name ); $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 ); }
    22252288        ;
    22262289
     
    22282291        identifier_or_type_name enumerator_value_opt
    22292292                { $$ = DeclarationNode::newEnumConstant( $1, $2 ); }
     2293        | INLINE type_name
     2294                { $$ = DeclarationNode::newEnumConstant( new string("inline"), nullptr ); }
    22302295        | enumerator_list ',' identifier_or_type_name enumerator_value_opt
    22312296                { $$ = $1->appendList( DeclarationNode::newEnumConstant( $3, $4 ) ); }
     2297        | enumerator_list ',' INLINE type_name enumerator_value_opt
     2298                { $$ = $1->appendList( DeclarationNode::newEnumConstant( new string("inline"), nullptr ) ); }
    22322299        ;
    22332300
     
    22372304        // | '=' constant_expression
    22382305        //      { $$ = $2; }
    2239         | '=' initializer
     2306        | simple_assignment_operator initializer
    22402307                { $$ = $2->get_expression(); }                                  // FIX ME: enum only deals with constant_expression
    22412308        ;
     
    23652432        // empty
    23662433                { $$ = nullptr; }
    2367         | '=' initializer
    2368                 { $$ = $2; }
    2369         | '=' VOID
    2370                 { $$ = new InitializerNode( true ); }
    2371         | ATassign initializer
    2372                 { $$ = $2->set_maybeConstructed( false ); }
     2434        | simple_assignment_operator initializer        { $$ = $1 == OperKinds::Assign ? $2 : $2->set_maybeConstructed( false ); }
     2435        | '=' VOID                                                                      { $$ = new InitializerNode( true ); }
    23732436        ;
    23742437
     
    26262689
    26272690external_definition:
    2628         declaration
     2691        DIRECTIVE
     2692                { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( $1 ) ) ); }
     2693        | declaration
    26292694        | external_function_definition
    26302695        | EXTENSION external_definition                                         // GCC, multiple __extension__ allowed, meaning unknown
     
    26342699                }
    26352700        | ASM '(' string_literal ')' ';'                                        // GCC, global assembler statement
    2636                 {
    2637                         $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) );
    2638                 }
     2701                { $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) ); }
    26392702        | EXTERN STRINGliteral                                                          // C++-style linkage specifier
    26402703                {
     
    27822845        ;
    27832846
    2784 attribute_opt:
    2785         // empty
    2786                 { $$ = nullptr; }
    2787         | attribute
    2788         ;
    2789 
    27902847attribute:                                                                                              // GCC
    27912848        ATTRIBUTE '(' '(' attribute_name_list ')' ')'
     
    28492906// declaring an array of functions versus a pointer to an array of functions.
    28502907
     2908paren_identifier:
     2909        identifier
     2910                { $$ = DeclarationNode::newName( $1 ); }
     2911        | '(' paren_identifier ')'                                                      // redundant parenthesis
     2912                { $$ = $2; }
     2913        ;
     2914
    28512915variable_declarator:
    28522916        paren_identifier attribute_list_opt
     
    28592923        ;
    28602924
    2861 paren_identifier:
    2862         identifier
    2863                 { $$ = DeclarationNode::newName( $1 ); }
    2864         | '(' paren_identifier ')'                                                      // redundant parenthesis
    2865                 { $$ = $2; }
    2866         ;
    2867 
    28682925variable_ptr:
    28692926        ptrref_operator variable_declarator
     
    28712928        | ptrref_operator type_qualifier_list variable_declarator
    28722929                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    2873         | '(' variable_ptr ')' attribute_list_opt
    2874                 { $$ = $2->addQualifiers( $4 ); }                               // redundant parenthesis
     2930        | '(' variable_ptr ')' attribute_list_opt                       // redundant parenthesis
     2931                { $$ = $2->addQualifiers( $4 ); }
     2932        | '(' attribute_list variable_ptr ')' attribute_list_opt // redundant parenthesis
     2933                { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
    28752934        ;
    28762935
     
    28802939        | '(' variable_ptr ')' array_dimension
    28812940                { $$ = $2->addArray( $4 ); }
    2882         | '(' variable_array ')' multi_array_dimension          // redundant parenthesis
     2941        | '(' attribute_list variable_ptr ')' array_dimension
     2942                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
     2943        | '(' variable_array ')' multi_array_dimension          // redundant parenthesis
    28832944                { $$ = $2->addArray( $4 ); }
     2945        | '(' attribute_list variable_array ')' multi_array_dimension // redundant parenthesis
     2946                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    28842947        | '(' variable_array ')'                                                        // redundant parenthesis
    28852948                { $$ = $2; }
     2949        | '(' attribute_list variable_array ')'                         // redundant parenthesis
     2950                { $$ = $3->addQualifiers( $2 ); }
    28862951        ;
    28872952
     
    28892954        '(' variable_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    28902955                { $$ = $2->addParamList( $6 ); }
     2956        | '(' attribute_list variable_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     2957                { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    28912958        | '(' variable_function ')'                                                     // redundant parenthesis
    28922959                { $$ = $2; }
     2960        | '(' attribute_list variable_function ')'                      // redundant parenthesis
     2961                { $$ = $3->addQualifiers( $2 ); }
    28932962        ;
    28942963
     
    29102979        | '(' function_ptr ')' '(' push parameter_type_list_opt pop ')'
    29112980                { $$ = $2->addParamList( $6 ); }
     2981        | '(' attribute_list function_ptr ')' '(' push parameter_type_list_opt pop ')'
     2982                { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    29122983        | '(' function_no_ptr ')'                                                       // redundant parenthesis
    29132984                { $$ = $2; }
     2985        | '(' attribute_list function_no_ptr ')'                        // redundant parenthesis
     2986                { $$ = $3->addQualifiers( $2 ); }
    29142987        ;
    29152988
     
    29192992        | ptrref_operator type_qualifier_list function_declarator
    29202993                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    2921         | '(' function_ptr ')'
    2922                 { $$ = $2; }
     2994        | '(' function_ptr ')' attribute_list_opt
     2995                { $$ = $2->addQualifiers( $4 ); }
     2996        | '(' attribute_list function_ptr ')' attribute_list_opt
     2997                { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
    29232998        ;
    29242999
     
    29263001        '(' function_ptr ')' array_dimension
    29273002                { $$ = $2->addArray( $4 ); }
     3003        | '(' attribute_list function_ptr ')' array_dimension
     3004                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    29283005        | '(' function_array ')' multi_array_dimension          // redundant parenthesis
    29293006                { $$ = $2->addArray( $4 ); }
     3007        | '(' attribute_list function_array ')' multi_array_dimension // redundant parenthesis
     3008                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    29303009        | '(' function_array ')'                                                        // redundant parenthesis
    29313010                { $$ = $2; }
     3011        | '(' attribute_list function_array ')'                         // redundant parenthesis
     3012                { $$ = $3->addQualifiers( $2 ); }
    29323013        ;
    29333014
     
    29503031        | '(' KR_function_ptr ')' '(' push parameter_type_list_opt pop ')'
    29513032                { $$ = $2->addParamList( $6 ); }
     3033        | '(' attribute_list KR_function_ptr ')' '(' push parameter_type_list_opt pop ')'
     3034                { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    29523035        | '(' KR_function_no_ptr ')'                                            // redundant parenthesis
    29533036                { $$ = $2; }
     3037        | '(' attribute_list KR_function_no_ptr ')'                     // redundant parenthesis
     3038                { $$ = $3->addQualifiers( $2 ); }
    29543039        ;
    29553040
     
    29613046        | '(' KR_function_ptr ')'
    29623047                { $$ = $2; }
     3048        | '(' attribute_list KR_function_ptr ')'
     3049                { $$ = $3->addQualifiers( $2 ); }
    29633050        ;
    29643051
     
    29663053        '(' KR_function_ptr ')' array_dimension
    29673054                { $$ = $2->addArray( $4 ); }
     3055        | '(' attribute_list KR_function_ptr ')' array_dimension
     3056                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    29683057        | '(' KR_function_array ')' multi_array_dimension       // redundant parenthesis
    29693058                { $$ = $2->addArray( $4 ); }
     3059        | '(' attribute_list KR_function_array ')' multi_array_dimension // redundant parenthesis
     3060                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    29703061        | '(' KR_function_array ')'                                                     // redundant parenthesis
    29713062                { $$ = $2; }
     3063        | '(' attribute_list KR_function_array ')'                      // redundant parenthesis
     3064                { $$ = $3->addQualifiers( $2 ); }
    29723065        ;
    29733066
     
    29813074// The pattern precludes declaring an array of functions versus a pointer to an array of functions, and returning arrays
    29823075// and functions versus pointers to arrays and functions.
     3076
     3077paren_type:
     3078        typedef_name
     3079                {
     3080                        // hide type name in enclosing scope by variable name
     3081                        typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "ID" );
     3082                }
     3083        | '(' paren_type ')'
     3084                { $$ = $2; }
     3085        ;
    29833086
    29843087variable_type_redeclarator:
     
    29923095        ;
    29933096
    2994 paren_type:
    2995         typedef
    2996                 // hide type name in enclosing scope by variable name
    2997                 {
    2998                         // if ( ! typedefTable.existsCurr( *$1->name ) ) {
    2999                                 typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "ID" );
    3000                         // } else {
    3001                         //      SemanticError( yylloc, string("'") + *$1->name + "' redeclared as different kind of symbol." ); $$ = nullptr;
    3002                         // } // if
    3003                 }
    3004         | '(' paren_type ')'
    3005                 { $$ = $2; }
    3006         ;
    3007 
    30083097type_ptr:
    30093098        ptrref_operator variable_type_redeclarator
     
    30113100        | ptrref_operator type_qualifier_list variable_type_redeclarator
    30123101                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3013         | '(' type_ptr ')' attribute_list_opt
    3014                 { $$ = $2->addQualifiers( $4 ); }                               // redundant parenthesis
     3102        | '(' type_ptr ')' attribute_list_opt                           // redundant parenthesis
     3103                { $$ = $2->addQualifiers( $4 ); }
     3104        | '(' attribute_list type_ptr ')' attribute_list_opt // redundant parenthesis
     3105                { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
    30153106        ;
    30163107
     
    30203111        | '(' type_ptr ')' array_dimension
    30213112                { $$ = $2->addArray( $4 ); }
     3113        | '(' attribute_list type_ptr ')' array_dimension
     3114                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    30223115        | '(' type_array ')' multi_array_dimension                      // redundant parenthesis
    30233116                { $$ = $2->addArray( $4 ); }
     3117        | '(' attribute_list type_array ')' multi_array_dimension // redundant parenthesis
     3118                { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    30243119        | '(' type_array ')'                                                            // redundant parenthesis
    30253120                { $$ = $2; }
     3121        | '(' attribute_list type_array ')'                                     // redundant parenthesis
     3122                { $$ = $3->addQualifiers( $2 ); }
    30263123        ;
    30273124
     
    30313128        | '(' type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    30323129                { $$ = $2->addParamList( $6 ); }
     3130        | '(' attribute_list type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     3131                { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    30333132        | '(' type_function ')'                                                         // redundant parenthesis
    30343133                { $$ = $2; }
     3134        | '(' attribute_list type_function ')'                          // redundant parenthesis
     3135                { $$ = $3->addQualifiers( $2 ); }
    30353136        ;
    30363137
     
    30573158        | ptrref_operator type_qualifier_list identifier_parameter_declarator
    30583159                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3059         | '(' identifier_parameter_ptr ')' attribute_list_opt
     3160        | '(' identifier_parameter_ptr ')' attribute_list_opt // redundant parenthesis
    30603161                { $$ = $2->addQualifiers( $4 ); }
    30613162        ;
     
    30913192
    30923193type_parameter_redeclarator:
    3093         typedef attribute_list_opt
     3194        typedef_name attribute_list_opt
    30943195                { $$ = $1->addQualifiers( $2 ); }
    3095         | '&' MUTEX typedef attribute_list_opt
     3196        | '&' MUTEX typedef_name attribute_list_opt
    30963197                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    30973198        | type_parameter_ptr
     
    31023203        ;
    31033204
    3104 typedef:
     3205typedef_name:
    31053206        TYPEDEFname
    31063207                { $$ = DeclarationNode::newName( $1 ); }
     
    31143215        | ptrref_operator type_qualifier_list type_parameter_redeclarator
    31153216                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3116         | '(' type_parameter_ptr ')' attribute_list_opt
     3217        | '(' type_parameter_ptr ')' attribute_list_opt         // redundant parenthesis
    31173218                { $$ = $2->addQualifiers( $4 ); }
    31183219        ;
    31193220
    31203221type_parameter_array:
    3121         typedef array_parameter_dimension
     3222        typedef_name array_parameter_dimension
    31223223                { $$ = $1->addArray( $2 ); }
    31233224        | '(' type_parameter_ptr ')' array_parameter_dimension
     
    31263227
    31273228type_parameter_function:
    3128         typedef '(' push parameter_type_list_opt pop ')'        // empty parameter list OBSOLESCENT (see 3)
     3229        typedef_name '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    31293230                { $$ = $1->addParamList( $4 ); }
    31303231        | '(' type_parameter_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     
    32553356        | ptrref_operator type_qualifier_list abstract_parameter_declarator
    32563357                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3257         | '(' abstract_parameter_ptr ')' attribute_list_opt
     3358        | '(' abstract_parameter_ptr ')' attribute_list_opt     // redundant parenthesis
    32583359                { $$ = $2->addQualifiers( $4 ); }
    32593360        ;
     
    33343435        | ptrref_operator type_qualifier_list variable_abstract_declarator
    33353436                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3336         | '(' variable_abstract_ptr ')' attribute_list_opt
     3437        | '(' variable_abstract_ptr ')' attribute_list_opt      // redundant parenthesis
    33373438                { $$ = $2->addQualifiers( $4 ); }
    33383439        ;
  • src/ResolvExpr/CurrentObject.cc

    rfeacef9 r5407cdc  
    925925                if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) {
    926926                        if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) {
     927                                assert( sit->base );
    927928                                return new StructIterator{ loc, sit };
    928929                        } else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) {
     930                                assert( uit->base );
    929931                                return new UnionIterator{ loc, uit };
    930932                        } else {
  • src/SynTree/Constant.cc

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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/SynTree/Declaration.cc

    rfeacef9 r5407cdc  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 16:39:56 2019
    13 // Update Count     : 36
     12// Last Modified On : Fri Mar 12 18:35:39 2021
     13// Update Count     : 37
    1414//
    1515
     
    6666
    6767
     68DirectiveDecl::DirectiveDecl( DirectiveStmt *stmt ) : Declaration( "", Type::StorageClasses(), LinkageSpec::C ), stmt( stmt ) {
     69}
     70
     71DirectiveDecl::DirectiveDecl( const DirectiveDecl &other ) : Declaration( other ), stmt( maybeClone( other.stmt ) ) {
     72}
     73
     74DirectiveDecl::~DirectiveDecl() {
     75        delete stmt;
     76}
     77
     78void DirectiveDecl::print( std::ostream &os, Indenter indent ) const {
     79        stmt->print( os, indent );
     80}
     81
     82void DirectiveDecl::printShort( std::ostream &os, Indenter indent ) const {
     83        stmt->print( os, indent );
     84}
     85
     86
    6887StaticAssertDecl::StaticAssertDecl( Expression * condition, ConstantExpr * message ) : Declaration( "", Type::StorageClasses(), LinkageSpec::C ), condition( condition ), message( message )  {
    6988}
  • src/SynTree/Declaration.h

    rfeacef9 r5407cdc  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 11 20:48:39 2021
    13 // Update Count     : 158
     12// Last Modified On : Fri Mar 12 18:35:36 2021
     13// Update Count     : 159
    1414//
    1515
     
    400400};
    401401
     402class DirectiveDecl : public Declaration {
     403  public:
     404        DirectiveStmt * stmt;
     405
     406        DirectiveDecl( DirectiveStmt * stmt );
     407        DirectiveDecl( const DirectiveDecl & other );
     408        virtual ~DirectiveDecl();
     409
     410        DirectiveStmt * get_stmt() { return stmt; }
     411        void set_stmt( DirectiveStmt * newValue ) { stmt = newValue; }
     412
     413        virtual DirectiveDecl * clone() const override { return new DirectiveDecl( *this ); }
     414        virtual void accept( Visitor & v ) override { v.visit( this ); }
     415        virtual void accept( Visitor & v ) const override { v.visit( this ); }
     416        virtual DirectiveDecl * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     417        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     418        virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;
     419};
     420
    402421class StaticAssertDecl : public Declaration {
    403422public:
  • src/SynTree/Mutator.h

    rfeacef9 r5407cdc  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 25 22:37:46 2019
    13 // Update Count     : 17
     12// Last Modified On : Fri Mar 12 18:35:36 2021
     13// Update Count     : 18
    1414//
    1515#pragma once
     
    3434        virtual Declaration * mutate( TypedefDecl * typeDecl ) = 0;
    3535        virtual AsmDecl * mutate( AsmDecl * asmDecl ) = 0;
     36        virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) = 0;
    3637        virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) = 0;
    3738
  • src/SynTree/SynTree.h

    rfeacef9 r5407cdc  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 25 22:37:45 2019
    13 // Update Count     : 12
     12// Last Modified On : Fri Mar 12 18:56:44 2021
     13// Update Count     : 13
    1414//
    1515
     
    3636class TypedefDecl;
    3737class AsmDecl;
     38class DirectiveDecl;
    3839class StaticAssertDecl;
    3940
  • src/SynTree/Visitor.h

    rfeacef9 r5407cdc  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 25 22:21:49 2019
    13 // Update Count     : 14
     12// Last Modified On : Fri Mar 12 18:35:35 2021
     13// Update Count     : 15
    1414//
    1515
     
    4545        virtual void visit( AsmDecl * node ) { visit( const_cast<const AsmDecl *>(node) ); }
    4646        virtual void visit( const AsmDecl * asmDecl ) = 0;
     47        virtual void visit( DirectiveDecl * node ) { visit( const_cast<const DirectiveDecl *>(node) ); }
     48        virtual void visit( const DirectiveDecl * directiveDecl ) = 0;
    4749        virtual void visit( StaticAssertDecl * node ) { visit( const_cast<const StaticAssertDecl *>(node) ); }
    4850        virtual void visit( const StaticAssertDecl * assertDecl ) = 0;
  • src/Virtual/ExpandCasts.cc

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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 : Wed Apr 21 15:36:00 2021
     13// Update Count     : 2
    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";
    2638}
    2739
     40std::string baseTypeName( std::string const & vtable_type_name ) {
     41        return vtable_type_name.substr(0, vtable_type_name.size() - 7);
     42}
     43
    2844std::string instanceName( std::string const & name ) {
    2945        return std::string("_") + name + "_instance";
     
    3248std::string vtableInstanceName( std::string const & name ) {
    3349        return instanceName( vtableTypeName( name ) );
     50}
     51
     52std::string concurrentDefaultVTableName() {
     53        return "_default_vtable";
    3454}
    3555
     
    4161
    4262static ObjectDecl * makeVtableDeclaration(
     63                std::string const & name,
    4364                StructInstType * type, Initializer * init ) {
    44         std::string const & name = instanceName( type->name );
    4565        Type::StorageClasses storage = noStorageClasses;
    4666        if ( nullptr == init ) {
     
    5777}
    5878
    59 ObjectDecl * makeVtableForward( StructInstType * type ) {
     79ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {
    6080        assert( type );
    61         return makeVtableDeclaration( type, nullptr );
     81        return makeVtableDeclaration( name, type, nullptr );
    6282}
    6383
    6484ObjectDecl * makeVtableInstance(
    65                 StructInstType * vtableType, Type * objectType, Initializer * init ) {
     85                std::string const & name, StructInstType * vtableType,
     86                Type * objectType, Initializer * init ) {
    6687        assert( vtableType );
    6788        assert( objectType );
     
    81102                                inits.push_back(
    82103                                                new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );
     104                        } else if ( std::string( "__cfavir_typeid" ) == field->name ) {
     105                                std::string const & baseType = baseTypeName( vtableType->name );
     106                                std::string const & typeId = typeIdName( baseType );
     107                                inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );
    83108                        } else if ( std::string( "size" ) == field->name ) {
    84109                                inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );
     
    95120                assert(false);
    96121        }
    97         return makeVtableDeclaration( vtableType, init );
     122        return makeVtableDeclaration( name, vtableType, init );
    98123}
    99124
     
    147172}
    148173
    149 }
     174Attribute * linkonce( const std::string & subsection ) {
     175        const std::string section = ".gnu.linkonce." + subsection;
     176        return new Attribute( "section", {
     177                new ConstantExpr( Constant::from_string( section ) ),
     178        } );
     179}
     180
     181ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
     182        assert( typeIdType );
     183        StructInstType * type = typeIdType->clone();
     184        type->tq.is_const = true;
     185        std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );
     186        return new ObjectDecl(
     187                typeid_name,
     188                noStorageClasses,
     189                LinkageSpec::Cforall,
     190                /* bitfieldWidth */ nullptr,
     191                type,
     192                new ListInit( { new SingleInit(
     193                        new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )
     194                        ) } ),
     195                { linkonce( typeid_name ) },
     196                noFuncSpecifiers
     197        );
     198}
     199
     200}
  • src/Virtual/Tables.h

    rfeacef9 r5407cdc  
    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 : Wed Apr 21 10:30:00 2021
     13// Update Count     : 2
    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 );
    2628std::string vtableInstanceName( std::string const & type_name );
     29std::string concurrentDefaultVTableName();
    2730bool isVTableInstanceName( std::string const & name );
    2831
    29 ObjectDecl * makeVtableForward( StructInstType * vtableType );
     32ObjectDecl * makeVtableForward(
     33        std::string const & name, StructInstType * vtableType );
    3034/* Create a forward declaration of a vtable of the given type.
    3135 * vtableType node is consumed.
    3236 */
    3337
    34 ObjectDecl * makeVtableInstance( StructInstType * vtableType, Type * objectType,
     38ObjectDecl * makeVtableInstance(
     39        std::string const & name,
     40        StructInstType * vtableType, Type * objectType,
    3541        Initializer * init = nullptr );
    3642/* Create an initialized definition of a vtable.
     
    5056 */
    5157
     58ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
     59/* Build an instance of the type-id from the type of the type-id.
     60 * TODO: Should take the parent type. Currently locked to the exception_t.
     61 */
     62
    5263}
  • src/main.cc

    rfeacef9 r5407cdc  
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Feb  8 21:10:16 2021
    13 // Update Count     : 642
     12// Last Modified On : Sat Mar  6 15:49:00 2021
     13// Update Count     : 656
    1414//
    1515
     
    101101static string PreludeDirector = "";
    102102
    103 static void parse_cmdline( int argc, char *argv[] );
     103static void parse_cmdline( int argc, char * argv[] );
    104104static void parse( FILE * input, LinkageSpec::Spec linkage, bool shouldExit = false );
    105105static void dump( list< Declaration * > & translationUnit, ostream & out = cout );
     106static void dump( ast::TranslationUnit && transUnit, ostream & out = cout );
    106107
    107108static void backtrace( int start ) {                                    // skip first N stack frames
     
    158159#define SIGPARMS int sig __attribute__(( unused )), siginfo_t * sfp __attribute__(( unused )), ucontext_t * cxt __attribute__(( unused ))
    159160
    160 static void Signal( int sig, void (*handler)(SIGPARMS), int flags ) {
     161static void Signal( int sig, void (* handler)(SIGPARMS), int flags ) {
    161162        struct sigaction act;
    162163
     
    165166
    166167        if ( sigaction( sig, &act, nullptr ) == -1 ) {
    167             cerr << "*CFA runtime error* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl;
     168            cerr << "*cfa-cpp compilation error* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl;
    168169            _exit( EXIT_FAILURE );
    169170        } // if
     
    349350                        PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    350351                        if ( exprp ) {
    351                                 translationUnit = convert( move( transUnit ) );
    352                                 dump( translationUnit );
     352                                dump( move( transUnit ) );
    353353                                return EXIT_SUCCESS;
    354354                        } // if
     
    421421                        delete output;
    422422                } // if
    423         } catch ( SemanticErrorException &e ) {
     423        } catch ( SemanticErrorException & e ) {
    424424                if ( errorp ) {
    425425                        cerr << "---AST at error:---" << endl;
     
    432432                } // if
    433433                return EXIT_FAILURE;
    434         } catch ( UnimplementedError &e ) {
     434        } catch ( UnimplementedError & e ) {
    435435                cout << "Sorry, " << e.get_what() << " is not currently implemented" << endl;
    436436                if ( output != &cout ) {
     
    438438                } // if
    439439                return EXIT_FAILURE;
    440         } catch ( CompilerError &e ) {
     440        } catch ( CompilerError & e ) {
    441441                cerr << "Compiler Error: " << e.get_what() << endl;
    442442                cerr << "(please report bugs to [REDACTED])" << endl;
     
    445445                } // if
    446446                return EXIT_FAILURE;
     447        } catch ( std::bad_alloc & ) {
     448                cerr << "*cfa-cpp compilation error* std::bad_alloc" << endl;
     449                backtrace( 1 );
     450                abort();
    447451        } catch ( ... ) {
    448452                exception_ptr eptr = current_exception();
     
    451455                                rethrow_exception(eptr);
    452456                        } else {
    453                                 cerr << "Exception Uncaught and Unknown" << endl;
    454                         } // if
    455                 } catch(const exception& e) {
    456                         cerr << "Uncaught Exception \"" << e.what() << "\"\n";
     457                                cerr << "*cfa-cpp compilation error* exception uncaught and unknown" << endl;
     458                        } // if
     459                } catch( const exception & e ) {
     460                        cerr << "*cfa-cpp compilation error* uncaught exception \"" << e.what() << "\"\n";
    457461                } // try
    458462                return EXIT_FAILURE;
     
    544548enum { printoptsSize = sizeof( printopts ) / sizeof( printopts[0] ) };
    545549
    546 static void usage( char *argv[] ) {
     550static void usage( char * argv[] ) {
    547551    cout << "Usage: " << argv[0] << " [options] [input-file (default stdin)] [output-file (default stdout)], where options are:" << endl;
    548552        int i = 0, j = 1;                                                                       // j skips starting colon
     
    732736} // dump
    733737
     738static void dump( ast::TranslationUnit && transUnit, ostream & out ) {
     739        std::list< Declaration * > translationUnit = convert( move( transUnit ) );
     740        dump( translationUnit, out );
     741}
     742
    734743// Local Variables: //
    735744// tab-width: 4 //
  • tests/.expect/KRfunctions.nast.arm64.txt

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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/attributes.nast.arm64.txt

    rfeacef9 r5407cdc  
    66
    77}
    8 struct __attribute__ ((unused)) __anonymous0 {
     8struct __anonymous0 {
    99};
    1010static inline void _X12_constructorFv_S12__anonymous0_autogen___1(struct __anonymous0 *_X4_dstS12__anonymous0_1);
     
    2626    return _X4_retS12__anonymous0_1;
    2727}
     28__attribute__ ((unused)) struct __anonymous0 _X5DummyS12__anonymous0_1;
    2829struct __attribute__ ((unused)) Agn1;
    2930struct __attribute__ ((unused)) Agn2 {
     
    103104    __attribute__ ((used,unused,unused)) signed int _X2f7i_1;
    104105    __attribute__ ((used,used,unused)) signed int _X2f8i_1;
    105     __attribute__ ((unused,unused)) signed int *_X2f9Pi_1;
     106    __attribute__ ((unused)) signed int *_X2f9Pi_1;
     107    __attribute__ ((unused,used)) signed int *_X3f10Pi_1;
     108    __attribute__ ((unused,unused)) signed int *_X3f11Pi_1;
     109    __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1;
     110    __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1;
     111    __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1;
    106112};
    107113static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1);
     
    117123static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1);
    118124static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1);
    119 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1);
     125static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1);
     126static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1);
     127static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1);
     128static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1);
     129static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1);
     130static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1);
    120131static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    121132    {
     
    155166    }
    156167
     168    {
     169        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     170    }
     171
     172    {
     173        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     174    }
     175
     176    {
     177        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     178    }
     179
     180    {
     181        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     182    }
     183
     184    {
     185        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     186    }
     187
    157188}
    158189static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){
     
    193224    }
    194225
     226    {
     227        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);
     228    }
     229
     230    {
     231        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);
     232    }
     233
     234    {
     235        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);
     236    }
     237
     238    {
     239        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);
     240    }
     241
     242    {
     243        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);
     244    }
     245
    195246}
    196247static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
     248    {
     249        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);
     250    }
     251
     252    {
     253        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);
     254    }
     255
     256    {
     257        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);
     258    }
     259
     260    {
     261        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);
     262    }
     263
     264    {
     265        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);
     266    }
     267
    197268    {
    198269        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */);
     
    271342
    272343    {
     344        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));
     345    }
     346
     347    {
     348        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));
     349    }
     350
     351    {
     352        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));
     353    }
     354
     355    {
     356        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));
     357    }
     358
     359    {
     360        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));
     361    }
     362
     363    {
    273364        ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1)));
    274365    }
     
    313404    }
    314405
     406    {
     407        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     408    }
     409
     410    {
     411        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     412    }
     413
     414    {
     415        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     416    }
     417
     418    {
     419        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     420    }
     421
     422    {
     423        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     424    }
     425
    315426}
    316427static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){
     
    351462    }
    352463
     464    {
     465        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     466    }
     467
     468    {
     469        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     470    }
     471
     472    {
     473        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     474    }
     475
     476    {
     477        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     478    }
     479
     480    {
     481        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     482    }
     483
    353484}
    354485static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){
     
    389520    }
    390521
     522    {
     523        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     524    }
     525
     526    {
     527        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     528    }
     529
     530    {
     531        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     532    }
     533
     534    {
     535        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     536    }
     537
     538    {
     539        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     540    }
     541
    391542}
    392543static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){
     
    427578    }
    428579
     580    {
     581        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     582    }
     583
     584    {
     585        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     586    }
     587
     588    {
     589        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     590    }
     591
     592    {
     593        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     594    }
     595
     596    {
     597        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     598    }
     599
    429600}
    430601static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){
     
    465636    }
    466637
     638    {
     639        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     640    }
     641
     642    {
     643        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     644    }
     645
     646    {
     647        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     648    }
     649
     650    {
     651        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     652    }
     653
     654    {
     655        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     656    }
     657
    467658}
    468659static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){
     
    503694    }
    504695
     696    {
     697        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     698    }
     699
     700    {
     701        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     702    }
     703
     704    {
     705        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     706    }
     707
     708    {
     709        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     710    }
     711
     712    {
     713        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     714    }
     715
    505716}
    506717static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){
     
    541752    }
    542753
     754    {
     755        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     756    }
     757
     758    {
     759        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     760    }
     761
     762    {
     763        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     764    }
     765
     766    {
     767        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     768    }
     769
     770    {
     771        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     772    }
     773
    543774}
    544775static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){
     
    579810    }
    580811
    581 }
    582 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){
     812    {
     813        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     814    }
     815
     816    {
     817        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     818    }
     819
     820    {
     821        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     822    }
     823
     824    {
     825        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     826    }
     827
     828    {
     829        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     830    }
     831
     832}
     833static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){
    583834    {
    584835        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     
    615866    {
    616867        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     868    }
     869
     870    {
     871        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     872    }
     873
     874    {
     875        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     876    }
     877
     878    {
     879        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     880    }
     881
     882    {
     883        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     884    }
     885
     886    {
     887        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     888    }
     889
     890}
     891static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){
     892    {
     893        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     894    }
     895
     896    {
     897        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     898    }
     899
     900    {
     901        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     902    }
     903
     904    {
     905        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     906    }
     907
     908    {
     909        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     910    }
     911
     912    {
     913        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     914    }
     915
     916    {
     917        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     918    }
     919
     920    {
     921        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     922    }
     923
     924    {
     925        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     926    }
     927
     928    {
     929        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     930    }
     931
     932    {
     933        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     934    }
     935
     936    {
     937        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     938    }
     939
     940    {
     941        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     942    }
     943
     944    {
     945        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     946    }
     947
     948}
     949static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){
     950    {
     951        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     952    }
     953
     954    {
     955        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     956    }
     957
     958    {
     959        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     960    }
     961
     962    {
     963        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     964    }
     965
     966    {
     967        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     968    }
     969
     970    {
     971        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     972    }
     973
     974    {
     975        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     976    }
     977
     978    {
     979        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     980    }
     981
     982    {
     983        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     984    }
     985
     986    {
     987        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     988    }
     989
     990    {
     991        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     992    }
     993
     994    {
     995        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     996    }
     997
     998    {
     999        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     1000    }
     1001
     1002    {
     1003        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1004    }
     1005
     1006}
     1007static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){
     1008    {
     1009        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1010    }
     1011
     1012    {
     1013        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1014    }
     1015
     1016    {
     1017        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1018    }
     1019
     1020    {
     1021        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1022    }
     1023
     1024    {
     1025        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1026    }
     1027
     1028    {
     1029        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1030    }
     1031
     1032    {
     1033        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1034    }
     1035
     1036    {
     1037        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1038    }
     1039
     1040    {
     1041        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1042    }
     1043
     1044    {
     1045        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1046    }
     1047
     1048    {
     1049        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1050    }
     1051
     1052    {
     1053        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1054    }
     1055
     1056    {
     1057        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     1058    }
     1059
     1060    {
     1061        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1062    }
     1063
     1064}
     1065static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){
     1066    {
     1067        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1068    }
     1069
     1070    {
     1071        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1072    }
     1073
     1074    {
     1075        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1076    }
     1077
     1078    {
     1079        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1080    }
     1081
     1082    {
     1083        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1084    }
     1085
     1086    {
     1087        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1088    }
     1089
     1090    {
     1091        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1092    }
     1093
     1094    {
     1095        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1096    }
     1097
     1098    {
     1099        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1100    }
     1101
     1102    {
     1103        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1104    }
     1105
     1106    {
     1107        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1108    }
     1109
     1110    {
     1111        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1112    }
     1113
     1114    {
     1115        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
     1116    }
     1117
     1118    {
     1119        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1120    }
     1121
     1122}
     1123static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){
     1124    {
     1125        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1126    }
     1127
     1128    {
     1129        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1130    }
     1131
     1132    {
     1133        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1134    }
     1135
     1136    {
     1137        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1138    }
     1139
     1140    {
     1141        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1142    }
     1143
     1144    {
     1145        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1146    }
     1147
     1148    {
     1149        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1150    }
     1151
     1152    {
     1153        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1154    }
     1155
     1156    {
     1157        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1158    }
     1159
     1160    {
     1161        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1162    }
     1163
     1164    {
     1165        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1166    }
     1167
     1168    {
     1169        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1170    }
     1171
     1172    {
     1173        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
     1174    }
     1175
     1176    {
     1177        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);
    6171178    }
    6181179
     
    6271188__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    6281189__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
     1190__attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();
     1191__attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();
    6291192__attribute__ ((unused,used)) signed int _X2f1Fi___1();
    6301193__attribute__ ((unused)) signed int _X2f1Fi___1(){
     
    6361199}
    6371200__attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[];
    638 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{
    639     __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[];
    640 }
    641 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0);
    642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){
    643     __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0);
     1201__attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[];
     1202__attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{
     1203    __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[];
     1204}
     1205__attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{
     1206    __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[];
     1207}
     1208__attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0);
     1209__attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){
     1210    __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0);
     1211}
     1212__attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){
     1213    __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0);
     1214}
     1215__attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){
     1216    __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0);
    6441217}
    6451218signed int _X3vtrFi___1(){
     
    6491222    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)];
    6501223    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)];
    651     __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
     1224    __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)];
     1225    __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2();
    6521226    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
    6531227}
     
    6711245signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    6721246signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    673 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned long int )5)]));
     1247signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int __param_0[((unsigned long int )5)]));
    6741248signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    6751249signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    676 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int (*__param_0)(signed int __param_0)));
     1250signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object3)(signed int (*__param_0)(signed int __param_0)));
    6771251signed int _X2adFi___1(){
    6781252    __attribute__ ((unused)) signed int _X10_retval_adi_1;
     
    7761350
    7771351}
    778 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4);
    779 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6);
    780 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8);
    781 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)());
    782 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0));
    783 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)());
    784 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0));
     1352signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5);
     1353signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7);
     1354signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9);
     1355signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)());
     1356signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));
     1357signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());
     1358signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
    7851359struct Vad {
    7861360    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.nast.x64.txt

    rfeacef9 r5407cdc  
    104104    __attribute__ ((used,unused,unused)) signed int _X2f7i_1;
    105105    __attribute__ ((used,used,unused)) signed int _X2f8i_1;
    106     __attribute__ ((unused,unused)) signed int *_X2f9Pi_1;
     106    __attribute__ ((unused)) signed int *_X2f9Pi_1;
     107    __attribute__ ((unused,used)) signed int *_X3f10Pi_1;
     108    __attribute__ ((unused,unused)) signed int *_X3f11Pi_1;
     109    __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1;
     110    __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1;
     111    __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1;
    107112};
    108113static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1);
     
    118123static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1);
    119124static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1);
    120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1);
     125static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1);
     126static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1);
     127static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1);
     128static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1);
     129static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1);
     130static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1);
    121131static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    122132    {
     
    156166    }
    157167
     168    {
     169        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     170    }
     171
     172    {
     173        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     174    }
     175
     176    {
     177        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     178    }
     179
     180    {
     181        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     182    }
     183
     184    {
     185        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     186    }
     187
    158188}
    159189static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){
     
    194224    }
    195225
     226    {
     227        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);
     228    }
     229
     230    {
     231        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);
     232    }
     233
     234    {
     235        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);
     236    }
     237
     238    {
     239        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);
     240    }
     241
     242    {
     243        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);
     244    }
     245
    196246}
    197247static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
     248    {
     249        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);
     250    }
     251
     252    {
     253        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);
     254    }
     255
     256    {
     257        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);
     258    }
     259
     260    {
     261        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);
     262    }
     263
     264    {
     265        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);
     266    }
     267
    198268    {
    199269        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */);
     
    272342
    273343    {
     344        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));
     345    }
     346
     347    {
     348        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));
     349    }
     350
     351    {
     352        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));
     353    }
     354
     355    {
     356        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));
     357    }
     358
     359    {
     360        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));
     361    }
     362
     363    {
    274364        ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1)));
    275365    }
     
    314404    }
    315405
     406    {
     407        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     408    }
     409
     410    {
     411        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     412    }
     413
     414    {
     415        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     416    }
     417
     418    {
     419        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     420    }
     421
     422    {
     423        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     424    }
     425
    316426}
    317427static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){
     
    352462    }
    353463
     464    {
     465        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     466    }
     467
     468    {
     469        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     470    }
     471
     472    {
     473        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     474    }
     475
     476    {
     477        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     478    }
     479
     480    {
     481        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     482    }
     483
    354484}
    355485static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){
     
    390520    }
    391521
     522    {
     523        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     524    }
     525
     526    {
     527        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     528    }
     529
     530    {
     531        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     532    }
     533
     534    {
     535        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     536    }
     537
     538    {
     539        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     540    }
     541
    392542}
    393543static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){
     
    428578    }
    429579
     580    {
     581        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     582    }
     583
     584    {
     585        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     586    }
     587
     588    {
     589        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     590    }
     591
     592    {
     593        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     594    }
     595
     596    {
     597        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     598    }
     599
    430600}
    431601static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){
     
    466636    }
    467637
     638    {
     639        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     640    }
     641
     642    {
     643        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     644    }
     645
     646    {
     647        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     648    }
     649
     650    {
     651        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     652    }
     653
     654    {
     655        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     656    }
     657
    468658}
    469659static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){
     
    504694    }
    505695
     696    {
     697        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     698    }
     699
     700    {
     701        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     702    }
     703
     704    {
     705        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     706    }
     707
     708    {
     709        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     710    }
     711
     712    {
     713        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     714    }
     715
    506716}
    507717static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){
     
    542752    }
    543753
     754    {
     755        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     756    }
     757
     758    {
     759        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     760    }
     761
     762    {
     763        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     764    }
     765
     766    {
     767        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     768    }
     769
     770    {
     771        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     772    }
     773
    544774}
    545775static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){
     
    580810    }
    581811
    582 }
    583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){
     812    {
     813        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     814    }
     815
     816    {
     817        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     818    }
     819
     820    {
     821        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     822    }
     823
     824    {
     825        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     826    }
     827
     828    {
     829        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     830    }
     831
     832}
     833static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){
    584834    {
    585835        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     
    616866    {
    617867        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     868    }
     869
     870    {
     871        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     872    }
     873
     874    {
     875        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     876    }
     877
     878    {
     879        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     880    }
     881
     882    {
     883        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     884    }
     885
     886    {
     887        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     888    }
     889
     890}
     891static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){
     892    {
     893        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     894    }
     895
     896    {
     897        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     898    }
     899
     900    {
     901        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     902    }
     903
     904    {
     905        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     906    }
     907
     908    {
     909        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     910    }
     911
     912    {
     913        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     914    }
     915
     916    {
     917        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     918    }
     919
     920    {
     921        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     922    }
     923
     924    {
     925        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     926    }
     927
     928    {
     929        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     930    }
     931
     932    {
     933        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     934    }
     935
     936    {
     937        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     938    }
     939
     940    {
     941        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     942    }
     943
     944    {
     945        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     946    }
     947
     948}
     949static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){
     950    {
     951        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     952    }
     953
     954    {
     955        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     956    }
     957
     958    {
     959        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     960    }
     961
     962    {
     963        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     964    }
     965
     966    {
     967        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     968    }
     969
     970    {
     971        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     972    }
     973
     974    {
     975        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     976    }
     977
     978    {
     979        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     980    }
     981
     982    {
     983        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     984    }
     985
     986    {
     987        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     988    }
     989
     990    {
     991        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     992    }
     993
     994    {
     995        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     996    }
     997
     998    {
     999        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     1000    }
     1001
     1002    {
     1003        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1004    }
     1005
     1006}
     1007static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){
     1008    {
     1009        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1010    }
     1011
     1012    {
     1013        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1014    }
     1015
     1016    {
     1017        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1018    }
     1019
     1020    {
     1021        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1022    }
     1023
     1024    {
     1025        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1026    }
     1027
     1028    {
     1029        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1030    }
     1031
     1032    {
     1033        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1034    }
     1035
     1036    {
     1037        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1038    }
     1039
     1040    {
     1041        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1042    }
     1043
     1044    {
     1045        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1046    }
     1047
     1048    {
     1049        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1050    }
     1051
     1052    {
     1053        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1054    }
     1055
     1056    {
     1057        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     1058    }
     1059
     1060    {
     1061        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1062    }
     1063
     1064}
     1065static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){
     1066    {
     1067        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1068    }
     1069
     1070    {
     1071        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1072    }
     1073
     1074    {
     1075        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1076    }
     1077
     1078    {
     1079        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1080    }
     1081
     1082    {
     1083        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1084    }
     1085
     1086    {
     1087        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1088    }
     1089
     1090    {
     1091        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1092    }
     1093
     1094    {
     1095        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1096    }
     1097
     1098    {
     1099        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1100    }
     1101
     1102    {
     1103        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1104    }
     1105
     1106    {
     1107        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1108    }
     1109
     1110    {
     1111        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1112    }
     1113
     1114    {
     1115        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
     1116    }
     1117
     1118    {
     1119        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1120    }
     1121
     1122}
     1123static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){
     1124    {
     1125        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1126    }
     1127
     1128    {
     1129        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1130    }
     1131
     1132    {
     1133        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1134    }
     1135
     1136    {
     1137        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1138    }
     1139
     1140    {
     1141        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1142    }
     1143
     1144    {
     1145        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1146    }
     1147
     1148    {
     1149        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1150    }
     1151
     1152    {
     1153        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1154    }
     1155
     1156    {
     1157        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1158    }
     1159
     1160    {
     1161        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1162    }
     1163
     1164    {
     1165        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1166    }
     1167
     1168    {
     1169        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1170    }
     1171
     1172    {
     1173        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
     1174    }
     1175
     1176    {
     1177        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);
    6181178    }
    6191179
     
    6281188__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    6291189__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
     1190__attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();
     1191__attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();
    6301192__attribute__ ((unused,used)) signed int _X2f1Fi___1();
    6311193__attribute__ ((unused)) signed int _X2f1Fi___1(){
     
    6371199}
    6381200__attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[];
    639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{
    640     __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[];
    641 }
    642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0);
    643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){
    644     __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0);
     1201__attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[];
     1202__attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{
     1203    __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[];
     1204}
     1205__attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{
     1206    __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[];
     1207}
     1208__attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0);
     1209__attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){
     1210    __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0);
     1211}
     1212__attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){
     1213    __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0);
     1214}
     1215__attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){
     1216    __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0);
    6451217}
    6461218signed int _X3vtrFi___1(){
     
    6501222    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)];
    6511223    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)];
    652     __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
     1224    __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)];
     1225    __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2();
    6531226    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
    6541227}
     
    6721245signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    6731246signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned long int )5)]));
     1247signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int __param_0[((unsigned long int )5)]));
    6751248signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    6761249signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int (*__param_0)(signed int __param_0)));
     1250signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object3)(signed int (*__param_0)(signed int __param_0)));
    6781251signed int _X2adFi___1(){
    6791252    __attribute__ ((unused)) signed int _X10_retval_adi_1;
     
    7771350
    7781351}
    779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4);
    780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6);
    781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8);
    782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)());
    783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0));
    784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)());
    785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0));
     1352signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5);
     1353signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7);
     1354signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9);
     1355signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)());
     1356signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));
     1357signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());
     1358signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
    7861359struct Vad {
    7871360    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.nast.x86.txt

    rfeacef9 r5407cdc  
    104104    __attribute__ ((used,unused,unused)) signed int _X2f7i_1;
    105105    __attribute__ ((used,used,unused)) signed int _X2f8i_1;
    106     __attribute__ ((unused,unused)) signed int *_X2f9Pi_1;
     106    __attribute__ ((unused)) signed int *_X2f9Pi_1;
     107    __attribute__ ((unused,used)) signed int *_X3f10Pi_1;
     108    __attribute__ ((unused,unused)) signed int *_X3f11Pi_1;
     109    __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1;
     110    __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1;
     111    __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1;
    107112};
    108113static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1);
     
    118123static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1);
    119124static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1);
    120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1);
     125static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1);
     126static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1);
     127static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1);
     128static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1);
     129static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1);
     130static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1);
    121131static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    122132    {
     
    156166    }
    157167
     168    {
     169        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     170    }
     171
     172    {
     173        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     174    }
     175
     176    {
     177        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     178    }
     179
     180    {
     181        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     182    }
     183
     184    {
     185        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     186    }
     187
    158188}
    159189static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){
     
    194224    }
    195225
     226    {
     227        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);
     228    }
     229
     230    {
     231        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);
     232    }
     233
     234    {
     235        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);
     236    }
     237
     238    {
     239        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);
     240    }
     241
     242    {
     243        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);
     244    }
     245
    196246}
    197247static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
     248    {
     249        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);
     250    }
     251
     252    {
     253        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);
     254    }
     255
     256    {
     257        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);
     258    }
     259
     260    {
     261        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);
     262    }
     263
     264    {
     265        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);
     266    }
     267
    198268    {
    199269        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */);
     
    272342
    273343    {
     344        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));
     345    }
     346
     347    {
     348        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));
     349    }
     350
     351    {
     352        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));
     353    }
     354
     355    {
     356        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));
     357    }
     358
     359    {
     360        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));
     361    }
     362
     363    {
    274364        ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1)));
    275365    }
     
    314404    }
    315405
     406    {
     407        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     408    }
     409
     410    {
     411        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     412    }
     413
     414    {
     415        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     416    }
     417
     418    {
     419        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     420    }
     421
     422    {
     423        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     424    }
     425
    316426}
    317427static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){
     
    352462    }
    353463
     464    {
     465        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     466    }
     467
     468    {
     469        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     470    }
     471
     472    {
     473        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     474    }
     475
     476    {
     477        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     478    }
     479
     480    {
     481        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     482    }
     483
    354484}
    355485static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){
     
    390520    }
    391521
     522    {
     523        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     524    }
     525
     526    {
     527        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     528    }
     529
     530    {
     531        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     532    }
     533
     534    {
     535        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     536    }
     537
     538    {
     539        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     540    }
     541
    392542}
    393543static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){
     
    428578    }
    429579
     580    {
     581        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     582    }
     583
     584    {
     585        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     586    }
     587
     588    {
     589        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     590    }
     591
     592    {
     593        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     594    }
     595
     596    {
     597        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     598    }
     599
    430600}
    431601static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){
     
    466636    }
    467637
     638    {
     639        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     640    }
     641
     642    {
     643        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     644    }
     645
     646    {
     647        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     648    }
     649
     650    {
     651        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     652    }
     653
     654    {
     655        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     656    }
     657
    468658}
    469659static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){
     
    504694    }
    505695
     696    {
     697        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     698    }
     699
     700    {
     701        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     702    }
     703
     704    {
     705        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     706    }
     707
     708    {
     709        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     710    }
     711
     712    {
     713        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     714    }
     715
    506716}
    507717static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){
     
    542752    }
    543753
     754    {
     755        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     756    }
     757
     758    {
     759        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     760    }
     761
     762    {
     763        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     764    }
     765
     766    {
     767        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     768    }
     769
     770    {
     771        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     772    }
     773
    544774}
    545775static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){
     
    580810    }
    581811
    582 }
    583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){
     812    {
     813        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     814    }
     815
     816    {
     817        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     818    }
     819
     820    {
     821        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     822    }
     823
     824    {
     825        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     826    }
     827
     828    {
     829        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     830    }
     831
     832}
     833static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){
    584834    {
    585835        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     
    616866    {
    617867        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     868    }
     869
     870    {
     871        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     872    }
     873
     874    {
     875        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     876    }
     877
     878    {
     879        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     880    }
     881
     882    {
     883        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     884    }
     885
     886    {
     887        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     888    }
     889
     890}
     891static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){
     892    {
     893        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     894    }
     895
     896    {
     897        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     898    }
     899
     900    {
     901        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     902    }
     903
     904    {
     905        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     906    }
     907
     908    {
     909        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     910    }
     911
     912    {
     913        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     914    }
     915
     916    {
     917        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     918    }
     919
     920    {
     921        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     922    }
     923
     924    {
     925        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     926    }
     927
     928    {
     929        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     930    }
     931
     932    {
     933        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     934    }
     935
     936    {
     937        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     938    }
     939
     940    {
     941        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     942    }
     943
     944    {
     945        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     946    }
     947
     948}
     949static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){
     950    {
     951        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     952    }
     953
     954    {
     955        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     956    }
     957
     958    {
     959        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     960    }
     961
     962    {
     963        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     964    }
     965
     966    {
     967        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     968    }
     969
     970    {
     971        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     972    }
     973
     974    {
     975        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     976    }
     977
     978    {
     979        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     980    }
     981
     982    {
     983        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     984    }
     985
     986    {
     987        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     988    }
     989
     990    {
     991        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     992    }
     993
     994    {
     995        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     996    }
     997
     998    {
     999        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     1000    }
     1001
     1002    {
     1003        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1004    }
     1005
     1006}
     1007static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){
     1008    {
     1009        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1010    }
     1011
     1012    {
     1013        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1014    }
     1015
     1016    {
     1017        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1018    }
     1019
     1020    {
     1021        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1022    }
     1023
     1024    {
     1025        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1026    }
     1027
     1028    {
     1029        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1030    }
     1031
     1032    {
     1033        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1034    }
     1035
     1036    {
     1037        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1038    }
     1039
     1040    {
     1041        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1042    }
     1043
     1044    {
     1045        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1046    }
     1047
     1048    {
     1049        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1050    }
     1051
     1052    {
     1053        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1054    }
     1055
     1056    {
     1057        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     1058    }
     1059
     1060    {
     1061        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1062    }
     1063
     1064}
     1065static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){
     1066    {
     1067        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1068    }
     1069
     1070    {
     1071        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1072    }
     1073
     1074    {
     1075        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1076    }
     1077
     1078    {
     1079        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1080    }
     1081
     1082    {
     1083        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1084    }
     1085
     1086    {
     1087        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1088    }
     1089
     1090    {
     1091        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1092    }
     1093
     1094    {
     1095        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1096    }
     1097
     1098    {
     1099        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1100    }
     1101
     1102    {
     1103        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1104    }
     1105
     1106    {
     1107        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1108    }
     1109
     1110    {
     1111        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1112    }
     1113
     1114    {
     1115        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
     1116    }
     1117
     1118    {
     1119        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1120    }
     1121
     1122}
     1123static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){
     1124    {
     1125        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1126    }
     1127
     1128    {
     1129        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1130    }
     1131
     1132    {
     1133        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1134    }
     1135
     1136    {
     1137        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1138    }
     1139
     1140    {
     1141        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1142    }
     1143
     1144    {
     1145        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1146    }
     1147
     1148    {
     1149        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1150    }
     1151
     1152    {
     1153        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1154    }
     1155
     1156    {
     1157        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1158    }
     1159
     1160    {
     1161        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1162    }
     1163
     1164    {
     1165        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1166    }
     1167
     1168    {
     1169        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1170    }
     1171
     1172    {
     1173        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
     1174    }
     1175
     1176    {
     1177        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);
    6181178    }
    6191179
     
    6281188__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    6291189__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
     1190__attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();
     1191__attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();
    6301192__attribute__ ((unused,used)) signed int _X2f1Fi___1();
    6311193__attribute__ ((unused)) signed int _X2f1Fi___1(){
     
    6371199}
    6381200__attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[];
    639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{
    640     __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[];
    641 }
    642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0);
    643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){
    644     __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0);
     1201__attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[];
     1202__attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{
     1203    __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[];
     1204}
     1205__attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{
     1206    __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[];
     1207}
     1208__attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0);
     1209__attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){
     1210    __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0);
     1211}
     1212__attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){
     1213    __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0);
     1214}
     1215__attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){
     1216    __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0);
    6451217}
    6461218signed int _X3vtrFi___1(){
     
    6501222    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned int )5)];
    6511223    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned int )5)];
    652     __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
     1224    __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned int )5)];
     1225    __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2();
    6531226    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
    6541227}
     
    6721245signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    6731246signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned int )5)]));
     1247signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int __param_0[((unsigned int )5)]));
    6751248signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    6761249signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int (*__param_0)(signed int __param_0)));
     1250signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object3)(signed int (*__param_0)(signed int __param_0)));
    6781251signed int _X2adFi___1(){
    6791252    __attribute__ ((unused)) signed int _X10_retval_adi_1;
     
    7771350
    7781351}
    779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4);
    780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6);
    781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8);
    782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)());
    783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0));
    784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)());
    785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0));
     1352signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5);
     1353signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7);
     1354signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9);
     1355signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)());
     1356signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));
     1357signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());
     1358signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
    7861359struct Vad {
    7871360    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.oast.x64.txt

    rfeacef9 r5407cdc  
    104104    __attribute__ ((used,unused,unused)) signed int _X2f7i_1;
    105105    __attribute__ ((used,used,unused)) signed int _X2f8i_1;
    106     __attribute__ ((unused,unused)) signed int *_X2f9Pi_1;
     106    __attribute__ ((unused)) signed int *_X2f9Pi_1;
     107    __attribute__ ((unused,used)) signed int *_X3f10Pi_1;
     108    __attribute__ ((unused,unused)) signed int *_X3f11Pi_1;
     109    __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1;
     110    __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1;
     111    __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1;
    107112};
    108113static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1);
     
    118123static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1);
    119124static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1);
    120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1);
     125static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1);
     126static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1);
     127static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1);
     128static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1);
     129static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1);
     130static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1);
    121131static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    122132    {
     
    156166    }
    157167
     168    {
     169        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     170    }
     171
     172    {
     173        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     174    }
     175
     176    {
     177        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     178    }
     179
     180    {
     181        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     182    }
     183
     184    {
     185        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     186    }
     187
    158188}
    159189static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){
     
    194224    }
    195225
     226    {
     227        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);
     228    }
     229
     230    {
     231        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);
     232    }
     233
     234    {
     235        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);
     236    }
     237
     238    {
     239        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);
     240    }
     241
     242    {
     243        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);
     244    }
     245
    196246}
    197247static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
     248    {
     249        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);
     250    }
     251
     252    {
     253        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);
     254    }
     255
     256    {
     257        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);
     258    }
     259
     260    {
     261        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);
     262    }
     263
     264    {
     265        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);
     266    }
     267
    198268    {
    199269        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */);
     
    272342
    273343    {
     344        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));
     345    }
     346
     347    {
     348        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));
     349    }
     350
     351    {
     352        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));
     353    }
     354
     355    {
     356        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));
     357    }
     358
     359    {
     360        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));
     361    }
     362
     363    {
    274364        ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1)));
    275365    }
     
    314404    }
    315405
     406    {
     407        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     408    }
     409
     410    {
     411        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     412    }
     413
     414    {
     415        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     416    }
     417
     418    {
     419        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     420    }
     421
     422    {
     423        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     424    }
     425
    316426}
    317427static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){
     
    352462    }
    353463
     464    {
     465        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     466    }
     467
     468    {
     469        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     470    }
     471
     472    {
     473        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     474    }
     475
     476    {
     477        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     478    }
     479
     480    {
     481        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     482    }
     483
    354484}
    355485static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){
     
    390520    }
    391521
     522    {
     523        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     524    }
     525
     526    {
     527        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     528    }
     529
     530    {
     531        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     532    }
     533
     534    {
     535        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     536    }
     537
     538    {
     539        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     540    }
     541
    392542}
    393543static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){
     
    428578    }
    429579
     580    {
     581        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     582    }
     583
     584    {
     585        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     586    }
     587
     588    {
     589        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     590    }
     591
     592    {
     593        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     594    }
     595
     596    {
     597        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     598    }
     599
    430600}
    431601static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){
     
    466636    }
    467637
     638    {
     639        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     640    }
     641
     642    {
     643        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     644    }
     645
     646    {
     647        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     648    }
     649
     650    {
     651        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     652    }
     653
     654    {
     655        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     656    }
     657
    468658}
    469659static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){
     
    504694    }
    505695
     696    {
     697        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     698    }
     699
     700    {
     701        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     702    }
     703
     704    {
     705        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     706    }
     707
     708    {
     709        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     710    }
     711
     712    {
     713        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     714    }
     715
    506716}
    507717static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){
     
    542752    }
    543753
     754    {
     755        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     756    }
     757
     758    {
     759        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     760    }
     761
     762    {
     763        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     764    }
     765
     766    {
     767        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     768    }
     769
     770    {
     771        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     772    }
     773
    544774}
    545775static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){
     
    580810    }
    581811
    582 }
    583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){
     812    {
     813        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     814    }
     815
     816    {
     817        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     818    }
     819
     820    {
     821        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     822    }
     823
     824    {
     825        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     826    }
     827
     828    {
     829        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     830    }
     831
     832}
     833static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){
    584834    {
    585835        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     
    616866    {
    617867        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     868    }
     869
     870    {
     871        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     872    }
     873
     874    {
     875        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     876    }
     877
     878    {
     879        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     880    }
     881
     882    {
     883        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     884    }
     885
     886    {
     887        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     888    }
     889
     890}
     891static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){
     892    {
     893        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     894    }
     895
     896    {
     897        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     898    }
     899
     900    {
     901        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     902    }
     903
     904    {
     905        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     906    }
     907
     908    {
     909        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     910    }
     911
     912    {
     913        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     914    }
     915
     916    {
     917        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     918    }
     919
     920    {
     921        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     922    }
     923
     924    {
     925        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     926    }
     927
     928    {
     929        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     930    }
     931
     932    {
     933        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     934    }
     935
     936    {
     937        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     938    }
     939
     940    {
     941        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     942    }
     943
     944    {
     945        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     946    }
     947
     948}
     949static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){
     950    {
     951        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     952    }
     953
     954    {
     955        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     956    }
     957
     958    {
     959        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     960    }
     961
     962    {
     963        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     964    }
     965
     966    {
     967        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     968    }
     969
     970    {
     971        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     972    }
     973
     974    {
     975        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     976    }
     977
     978    {
     979        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     980    }
     981
     982    {
     983        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     984    }
     985
     986    {
     987        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     988    }
     989
     990    {
     991        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     992    }
     993
     994    {
     995        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     996    }
     997
     998    {
     999        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     1000    }
     1001
     1002    {
     1003        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1004    }
     1005
     1006}
     1007static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){
     1008    {
     1009        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1010    }
     1011
     1012    {
     1013        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1014    }
     1015
     1016    {
     1017        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1018    }
     1019
     1020    {
     1021        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1022    }
     1023
     1024    {
     1025        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1026    }
     1027
     1028    {
     1029        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1030    }
     1031
     1032    {
     1033        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1034    }
     1035
     1036    {
     1037        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1038    }
     1039
     1040    {
     1041        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1042    }
     1043
     1044    {
     1045        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1046    }
     1047
     1048    {
     1049        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1050    }
     1051
     1052    {
     1053        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1054    }
     1055
     1056    {
     1057        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     1058    }
     1059
     1060    {
     1061        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1062    }
     1063
     1064}
     1065static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){
     1066    {
     1067        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1068    }
     1069
     1070    {
     1071        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1072    }
     1073
     1074    {
     1075        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1076    }
     1077
     1078    {
     1079        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1080    }
     1081
     1082    {
     1083        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1084    }
     1085
     1086    {
     1087        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1088    }
     1089
     1090    {
     1091        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1092    }
     1093
     1094    {
     1095        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1096    }
     1097
     1098    {
     1099        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1100    }
     1101
     1102    {
     1103        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1104    }
     1105
     1106    {
     1107        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1108    }
     1109
     1110    {
     1111        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1112    }
     1113
     1114    {
     1115        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
     1116    }
     1117
     1118    {
     1119        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1120    }
     1121
     1122}
     1123static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){
     1124    {
     1125        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1126    }
     1127
     1128    {
     1129        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1130    }
     1131
     1132    {
     1133        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1134    }
     1135
     1136    {
     1137        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1138    }
     1139
     1140    {
     1141        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1142    }
     1143
     1144    {
     1145        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1146    }
     1147
     1148    {
     1149        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1150    }
     1151
     1152    {
     1153        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1154    }
     1155
     1156    {
     1157        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1158    }
     1159
     1160    {
     1161        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1162    }
     1163
     1164    {
     1165        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1166    }
     1167
     1168    {
     1169        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1170    }
     1171
     1172    {
     1173        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
     1174    }
     1175
     1176    {
     1177        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);
    6181178    }
    6191179
     
    6281188__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    6291189__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
     1190__attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();
     1191__attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();
    6301192__attribute__ ((unused,used)) signed int _X2f1Fi___1();
    6311193__attribute__ ((unused)) signed int _X2f1Fi___1(){
     
    6371199}
    6381200__attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[];
    639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{
    640     __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[];
    641 }
    642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1);
    643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){
    644     __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3);
     1201__attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[];
     1202__attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{
     1203    __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[];
     1204}
     1205__attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{
     1206    __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[];
     1207}
     1208__attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __anonymous_object2);
     1209__attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object3){
     1210    __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __anonymous_object4);
     1211}
     1212__attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object5){
     1213    __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __anonymous_object6);
     1214}
     1215__attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object7){
     1216    __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __anonymous_object8);
    6451217}
    6461218signed int _X3vtrFi___1(){
     
    6501222    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)];
    6511223    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)];
    652     __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
     1224    __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)];
     1225    __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2();
    6531226    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
    6541227}
     
    6721245signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    6731246signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object4)(__attribute__ ((unused,unused)) signed int __anonymous_object5[((unsigned long int )5)]));
     1247signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object9)(__attribute__ ((unused,unused)) signed int __anonymous_object10[((unsigned long int )5)]));
    6751248signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    6761249signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object6)(__attribute__ ((unused)) signed int (*__anonymous_object7)(__attribute__ ((unused,unused)) signed int __anonymous_object8)));
     1250signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object11)(__attribute__ ((unused)) signed int (*__anonymous_object12)(__attribute__ ((unused,unused)) signed int __anonymous_object13)));
    6781251signed int _X2adFi___1(){
    6791252    __attribute__ ((unused)) signed int _X10_retval_adi_1;
     
    7771350
    7781351}
    779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object9, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object10);
    780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object11, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object12);
    781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object13, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object14);
    782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)());
    783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __anonymous_object18), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object19)(__attribute__ ((unused)) signed int __anonymous_object20));
    784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)());
    785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object23)(__attribute__ ((unused)) signed int __anonymous_object24), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object25)(__attribute__ ((unused)) signed int __anonymous_object26));
     1352signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object14, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object15);
     1353signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object16, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object17);
     1354signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object18, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object19);
     1355signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object20)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)());
     1356signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)(__attribute__ ((unused)) signed int __anonymous_object23), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object24)(__attribute__ ((unused)) signed int __anonymous_object25));
     1357signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object26)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object27)());
     1358signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object28)(__attribute__ ((unused)) signed int __anonymous_object29), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object30)(__attribute__ ((unused)) signed int __anonymous_object31));
    7861359struct Vad {
    7871360    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.oast.x86.txt

    rfeacef9 r5407cdc  
    104104    __attribute__ ((used,unused,unused)) signed int _X2f7i_1;
    105105    __attribute__ ((used,used,unused)) signed int _X2f8i_1;
    106     __attribute__ ((unused,unused)) signed int *_X2f9Pi_1;
     106    __attribute__ ((unused)) signed int *_X2f9Pi_1;
     107    __attribute__ ((unused,used)) signed int *_X3f10Pi_1;
     108    __attribute__ ((unused,unused)) signed int *_X3f11Pi_1;
     109    __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1;
     110    __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1;
     111    __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1;
    107112};
    108113static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1);
     
    118123static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1);
    119124static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1);
    120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1);
     125static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1);
     126static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1);
     127static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1);
     128static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1);
     129static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1);
     130static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1);
    121131static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    122132    {
     
    156166    }
    157167
     168    {
     169        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     170    }
     171
     172    {
     173        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     174    }
     175
     176    {
     177        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     178    }
     179
     180    {
     181        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     182    }
     183
     184    {
     185        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     186    }
     187
    158188}
    159189static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){
     
    194224    }
    195225
     226    {
     227        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);
     228    }
     229
     230    {
     231        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);
     232    }
     233
     234    {
     235        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);
     236    }
     237
     238    {
     239        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);
     240    }
     241
     242    {
     243        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);
     244    }
     245
    196246}
    197247static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
     248    {
     249        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);
     250    }
     251
     252    {
     253        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);
     254    }
     255
     256    {
     257        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);
     258    }
     259
     260    {
     261        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);
     262    }
     263
     264    {
     265        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);
     266    }
     267
    198268    {
    199269        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */);
     
    272342
    273343    {
     344        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));
     345    }
     346
     347    {
     348        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));
     349    }
     350
     351    {
     352        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));
     353    }
     354
     355    {
     356        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));
     357    }
     358
     359    {
     360        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));
     361    }
     362
     363    {
    274364        ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1)));
    275365    }
     
    314404    }
    315405
     406    {
     407        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     408    }
     409
     410    {
     411        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     412    }
     413
     414    {
     415        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     416    }
     417
     418    {
     419        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     420    }
     421
     422    {
     423        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     424    }
     425
    316426}
    317427static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){
     
    352462    }
    353463
     464    {
     465        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     466    }
     467
     468    {
     469        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     470    }
     471
     472    {
     473        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     474    }
     475
     476    {
     477        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     478    }
     479
     480    {
     481        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     482    }
     483
    354484}
    355485static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){
     
    390520    }
    391521
     522    {
     523        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     524    }
     525
     526    {
     527        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     528    }
     529
     530    {
     531        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     532    }
     533
     534    {
     535        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     536    }
     537
     538    {
     539        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     540    }
     541
    392542}
    393543static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){
     
    428578    }
    429579
     580    {
     581        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     582    }
     583
     584    {
     585        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     586    }
     587
     588    {
     589        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     590    }
     591
     592    {
     593        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     594    }
     595
     596    {
     597        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     598    }
     599
    430600}
    431601static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){
     
    466636    }
    467637
     638    {
     639        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     640    }
     641
     642    {
     643        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     644    }
     645
     646    {
     647        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     648    }
     649
     650    {
     651        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     652    }
     653
     654    {
     655        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     656    }
     657
    468658}
    469659static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){
     
    504694    }
    505695
     696    {
     697        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     698    }
     699
     700    {
     701        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     702    }
     703
     704    {
     705        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     706    }
     707
     708    {
     709        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     710    }
     711
     712    {
     713        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     714    }
     715
    506716}
    507717static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){
     
    542752    }
    543753
     754    {
     755        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     756    }
     757
     758    {
     759        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     760    }
     761
     762    {
     763        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     764    }
     765
     766    {
     767        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     768    }
     769
     770    {
     771        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     772    }
     773
    544774}
    545775static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){
     
    580810    }
    581811
    582 }
    583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){
     812    {
     813        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     814    }
     815
     816    {
     817        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     818    }
     819
     820    {
     821        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     822    }
     823
     824    {
     825        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     826    }
     827
     828    {
     829        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     830    }
     831
     832}
     833static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){
    584834    {
    585835        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     
    616866    {
    617867        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     868    }
     869
     870    {
     871        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
     872    }
     873
     874    {
     875        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     876    }
     877
     878    {
     879        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     880    }
     881
     882    {
     883        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     884    }
     885
     886    {
     887        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     888    }
     889
     890}
     891static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){
     892    {
     893        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     894    }
     895
     896    {
     897        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     898    }
     899
     900    {
     901        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     902    }
     903
     904    {
     905        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     906    }
     907
     908    {
     909        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     910    }
     911
     912    {
     913        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     914    }
     915
     916    {
     917        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     918    }
     919
     920    {
     921        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     922    }
     923
     924    {
     925        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     926    }
     927
     928    {
     929        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     930    }
     931
     932    {
     933        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
     934    }
     935
     936    {
     937        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     938    }
     939
     940    {
     941        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     942    }
     943
     944    {
     945        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     946    }
     947
     948}
     949static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){
     950    {
     951        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     952    }
     953
     954    {
     955        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     956    }
     957
     958    {
     959        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     960    }
     961
     962    {
     963        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     964    }
     965
     966    {
     967        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     968    }
     969
     970    {
     971        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     972    }
     973
     974    {
     975        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     976    }
     977
     978    {
     979        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     980    }
     981
     982    {
     983        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     984    }
     985
     986    {
     987        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     988    }
     989
     990    {
     991        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     992    }
     993
     994    {
     995        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
     996    }
     997
     998    {
     999        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     1000    }
     1001
     1002    {
     1003        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1004    }
     1005
     1006}
     1007static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){
     1008    {
     1009        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1010    }
     1011
     1012    {
     1013        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1014    }
     1015
     1016    {
     1017        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1018    }
     1019
     1020    {
     1021        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1022    }
     1023
     1024    {
     1025        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1026    }
     1027
     1028    {
     1029        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1030    }
     1031
     1032    {
     1033        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1034    }
     1035
     1036    {
     1037        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1038    }
     1039
     1040    {
     1041        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1042    }
     1043
     1044    {
     1045        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1046    }
     1047
     1048    {
     1049        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1050    }
     1051
     1052    {
     1053        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1054    }
     1055
     1056    {
     1057        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
     1058    }
     1059
     1060    {
     1061        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1062    }
     1063
     1064}
     1065static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){
     1066    {
     1067        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1068    }
     1069
     1070    {
     1071        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1072    }
     1073
     1074    {
     1075        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1076    }
     1077
     1078    {
     1079        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1080    }
     1081
     1082    {
     1083        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1084    }
     1085
     1086    {
     1087        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1088    }
     1089
     1090    {
     1091        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1092    }
     1093
     1094    {
     1095        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1096    }
     1097
     1098    {
     1099        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1100    }
     1101
     1102    {
     1103        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1104    }
     1105
     1106    {
     1107        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1108    }
     1109
     1110    {
     1111        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1112    }
     1113
     1114    {
     1115        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
     1116    }
     1117
     1118    {
     1119        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
     1120    }
     1121
     1122}
     1123static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){
     1124    {
     1125        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     1126    }
     1127
     1128    {
     1129        ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
     1130    }
     1131
     1132    {
     1133        ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
     1134    }
     1135
     1136    {
     1137        ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
     1138    }
     1139
     1140    {
     1141        ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
     1142    }
     1143
     1144    {
     1145        ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
     1146    }
     1147
     1148    {
     1149        ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
     1150    }
     1151
     1152    {
     1153        ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
     1154    }
     1155
     1156    {
     1157        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
     1158    }
     1159
     1160    {
     1161        ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
     1162    }
     1163
     1164    {
     1165        ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
     1166    }
     1167
     1168    {
     1169        ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
     1170    }
     1171
     1172    {
     1173        ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
     1174    }
     1175
     1176    {
     1177        ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);
    6181178    }
    6191179
     
    6281188__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    6291189__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
     1190__attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();
     1191__attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();
    6301192__attribute__ ((unused,used)) signed int _X2f1Fi___1();
    6311193__attribute__ ((unused)) signed int _X2f1Fi___1(){
     
    6371199}
    6381200__attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[];
    639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{
    640     __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[];
    641 }
    642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1);
    643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){
    644     __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3);
     1201__attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[];
     1202__attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{
     1203    __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[];
     1204}
     1205__attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{
     1206    __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[];
     1207}
     1208__attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __anonymous_object2);
     1209__attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object3){
     1210    __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __anonymous_object4);
     1211}
     1212__attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object5){
     1213    __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __anonymous_object6);
     1214}
     1215__attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object7){
     1216    __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __anonymous_object8);
    6451217}
    6461218signed int _X3vtrFi___1(){
     
    6501222    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned int )5)];
    6511223    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned int )5)];
    652     __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
     1224    __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned int )5)];
     1225    __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2();
    6531226    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
    6541227}
     
    6721245signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    6731246signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object4)(__attribute__ ((unused,unused)) signed int __anonymous_object5[((unsigned int )5)]));
     1247signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object9)(__attribute__ ((unused,unused)) signed int __anonymous_object10[((unsigned int )5)]));
    6751248signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    6761249signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object6)(__attribute__ ((unused)) signed int (*__anonymous_object7)(__attribute__ ((unused,unused)) signed int __anonymous_object8)));
     1250signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object11)(__attribute__ ((unused)) signed int (*__anonymous_object12)(__attribute__ ((unused,unused)) signed int __anonymous_object13)));
    6781251signed int _X2adFi___1(){
    6791252    __attribute__ ((unused)) signed int _X10_retval_adi_1;
     
    7771350
    7781351}
    779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object9, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object10);
    780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object11, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object12);
    781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object13, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object14);
    782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)());
    783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __anonymous_object18), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object19)(__attribute__ ((unused)) signed int __anonymous_object20));
    784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)());
    785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object23)(__attribute__ ((unused)) signed int __anonymous_object24), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object25)(__attribute__ ((unused)) signed int __anonymous_object26));
     1352signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object14, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object15);
     1353signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object16, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object17);
     1354signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object18, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object19);
     1355signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object20)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)());
     1356signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)(__attribute__ ((unused)) signed int __anonymous_object23), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object24)(__attribute__ ((unused)) signed int __anonymous_object25));
     1357signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object26)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object27)());
     1358signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object28)(__attribute__ ((unused)) signed int __anonymous_object29), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object30)(__attribute__ ((unused)) signed int __anonymous_object31));
    7861359struct Vad {
    7871360    __attribute__ ((unused)) signed int :4;
  • tests/.expect/declarationSpecifier.arm64.txt

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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/Makefile.am

    rfeacef9 r5407cdc  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Fri Oct  9 23:13:07 2020
    14 ## Update Count     : 86
     13## Last Modified On : Tue Mar  2 21:39:01 2021
     14## Update Count     : 90
    1515###############################################################################
    1616
     
    2626archiveerrors=
    2727
    28 DEBUG_FLAGS=-debug -O0
     28DEBUG_FLAGS=-debug -g -O0
    2929
    3030quick_test=avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes
     
    4444        -Wall \
    4545        -Wno-unused-function \
    46         -quiet @CFA_FLAGS@ \
    47         -DIN_DIR="${abs_srcdir}/.in/"
     46        -Wno-psabi \
     47        -quiet @CFA_FLAGS@
    4848
    4949AM_CFAFLAGS = -XCFA --deterministic-out
     
    7575        pybin/tools.py \
    7676        long_tests.hfa \
    77         .in/io.data \
     77        io/.in/io.data \
     78        io/.in/many_read.data \
    7879        avltree/avl.h \
    7980        avltree/avl-private.h \
    8081        concurrent/clib.c \
     82        concurrent/clib_tls.c \
    8183        exceptions/with-threads.hfa \
    8284        exceptions/except-io.hfa
     
    142144# don't use distcc to do the linking because distcc doesn't do linking
    143145% : %.cfa $(CFACCBIN)
    144         $(CFACOMPILETEST) -c -o $(abspath ${@}).o
     146        $(CFACOMPILETEST) -c -o $(abspath ${@}).o -DIN_DIR="$(abspath $(dir ${<}))/.in/"
    145147        $(CFACCLINK) ${@}.o -o $(abspath ${@})
    146148        rm $(abspath ${@}).o
     
    170172
    171173SYNTAX_ONLY_CODE = expression typedefRedef variableDeclarator switch numericConstants identFuncDeclarator forall \
    172         init1 limits nested-types stdincludes cast labelledExit array builtins/sync warnings/self-assignment
     174        init1 limits nested-types stdincludes cast labelledExit array quasiKeyword include/includes builtins/sync warnings/self-assignment
    173175$(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN)
    174176        $(CFACOMPILE_SYNTAX)
  • tests/attributes.cfa

    rfeacef9 r5407cdc  
    1010// Created On       : Mon Feb  6 16:07:02 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jan 25 21:26:41 2021
    13 // Update Count     : 20
     12// Last Modified On : Mon Mar 15 13:53:31 2021
     13// Update Count     : 38
    1414//
    1515
     
    4242    __attribute__(( unused )) int f5 __attribute__(( unused ));
    4343    __attribute__(( used )) int f6 __attribute__(( packed )), f7 __attribute__(( unused )) __attribute__(( unused )), __attribute__(( used )) f8 __attribute__(( unused ));
    44     int ( ( * (f9) __attribute__(( unused )) ) __attribute__(( unused )) );
     44    int * f9 __attribute__(( unused ));
     45    __attribute__(( used )) int __attribute__(( unused )) * f10;
     46    int ( ( * f11 __attribute__(( unused )) ) __attribute__(( unused )) );
     47    int ( ( __attribute__(( unused )) * f12  __attribute__(( unused )) ) __attribute__(( unused )) );
     48    int ( ( __attribute__(( unused )) * (f13)  __attribute__(( unused )) ) __attribute__(( unused )) );
     49    int ( ( ( __attribute__(( unused )) * (f14) )  __attribute__(( unused )) ) __attribute__(( unused )) );
    4550};
    4651
     
    5560const __attribute__(( used )) int __attribute__(( used )) vd5[5] __attribute__(( used )), __attribute__(( unused )) ((vd6)[5]) __attribute__(( used ));
    5661const __attribute__(( used )) int __attribute__(( used )) (* __attribute__(( used )) vd7)() __attribute__(( used )), __attribute__(( unused )) ((* __attribute__(( used )) vd8)()) __attribute__(( used ));
    57 
     62const __attribute__(( used )) int __attribute__(( used )) ( __attribute__(( used )) * vd9)() __attribute__(( used )), __attribute__(( unused )) (( __attribute__(( used )) * vd10)()) __attribute__(( used ));
    5863
    5964// function_declarator
     
    6368__attribute__(( unused )) int * __attribute__(( unused )) * const __attribute__(( unused )) f2() {}
    6469__attribute__(( unused )) int (* __attribute__(( unused )) f3(int))[] __attribute__(( used ));
    65 __attribute__(( unused )) int (* __attribute__(( unused )) f3(int p))[] {}
    66 __attribute__(( unused )) int (* __attribute__(( unused )) f4())(int) __attribute__(( used ));
    67 __attribute__(( unused )) int (* __attribute__(( unused )) f4())(int) {}
     70__attribute__(( unused )) int ( __attribute__(( unused )) * __attribute__(( unused )) f4(int))[] __attribute__(( used ));
     71__attribute__(( unused )) int (* __attribute__(( unused )) f5(int p))[] {}
     72__attribute__(( unused )) int ( __attribute__(( unused )) * (f6)(int p))[] {}
     73__attribute__(( unused )) int (* __attribute__(( unused )) f7())(int) __attribute__(( used ));
     74__attribute__(( unused )) int (* __attribute__(( unused )) f8())(int) {}
     75__attribute__(( unused )) int ( __attribute__(( unused )) * f9())(int) {}
     76__attribute__(( unused )) int ( __attribute__(( unused )) * (f10)())(int) {}
    6877
    6978
     
    7685    __attribute__(( unused )) int __attribute__(( unused )) t3[5] __attribute__(( unused ));
    7786    __attribute__(( unused )) int __attribute__(( unused )) (* (* __attribute__(( unused )) t4[5]) __attribute__(( unused )) ) __attribute__(( unused ));
    78     __attribute__(( unused )) int __attribute__(( unused )) t5() __attribute__(( unused ));
     87    __attribute__(( unused )) int __attribute__(( unused )) ( __attribute__(( unused )) * ( __attribute__(( unused )) * t5[5]) __attribute__(( unused )) ) __attribute__(( unused ));
     88    __attribute__(( unused )) int __attribute__(( unused )) t6() __attribute__(( unused ));
    7989    __attribute__(( unused )) int __attribute__(( unused )) * __attribute__(( unused )) ((t6))() __attribute__(( unused ));
    8090}
  • tests/concurrent/clib.c

    rfeacef9 r5407cdc  
    1 #include <clib/cfathread.h>
    2 
    31#include <stdio.h>
    42#include <stdlib.h>
     3#include <clib/cfathread.h>
     4#include <bits/defs.hfa>
     5
     6extern "C" {
     7void _exit(int status);
     8}
    59
    610thread_local struct drand48_data buffer = { 0 };
     
    1519cfathread_t volatile blocked[blocked_size];
    1620
    17 void Worker( cfathread_t this ) {
     21void * Worker( void * ) {
    1822        for(int i = 0; i < 1000; i++) {
    1923                int idx = myrand() % blocked_size;
     
    2226                        cfathread_unpark( thrd );
    2327                } else {
    24                         cfathread_t thrd = __atomic_exchange_n(&blocked[idx], this, __ATOMIC_SEQ_CST);
     28                        cfathread_t thrd = __atomic_exchange_n(&blocked[idx], cfathread_self(), __ATOMIC_SEQ_CST);
    2529                        cfathread_unpark( thrd );
    2630                        cfathread_park();
     
    2832        }
    2933        printf("Done\n");
     34        return NULL;
    3035}
    3136
    3237volatile bool stop;
    33 void Unparker( cfathread_t this ) {
     38void * Unparker( void * ) {
    3439        while(!stop) {
    3540                int idx = myrand() % blocked_size;
     
    4247        }
    4348        printf("Done Unparker\n");
     49        return NULL;
    4450}
    4551
     
    5157        }
    5258
    53         cfathread_setproccnt( 4 );
    54         cfathread_t u = cfathread_create( Unparker );
     59        cfathread_cluster_t cl = cfathread_cluster_self();
     60
     61        cfathread_cluster_add_worker( cl, NULL, NULL, NULL );
     62        cfathread_cluster_add_worker( cl, NULL, NULL, NULL );
     63        cfathread_cluster_add_worker( cl, NULL, NULL, NULL );
     64
     65        cfathread_attr_t attr;
     66        cfathread_attr_init(&attr);
     67        cfathread_attr_setcluster(&attr, cl);
     68
     69        cfathread_t u;
     70        cfathread_create( &u, &attr, Unparker, NULL );
    5571        {
    5672                cfathread_t t[20];
    5773                for(int i = 0; i < 20; i++) {
    58                         t[i] = cfathread_create( Worker );
     74                        cfathread_create( &t[i], &attr, Worker, NULL );
    5975                }
    6076                for(int i = 0; i < 20; i++) {
    61                         cfathread_join( t[i] );
     77                        cfathread_join( t[i], NULL );
    6278                }
    6379        }
    6480        stop = true;
    65         cfathread_join(u);
    66         cfathread_setproccnt( 1 );
     81        cfathread_join(u, NULL);
     82        cfathread_attr_destroy(&attr);
     83        fflush(stdout);
     84        _exit(0);
    6785}
  • tests/concurrent/coroutineYield.cfa

    rfeacef9 r5407cdc  
    3838
    3939
     40Coroutine c;
    4041int main(int argc, char* argv[]) {
    41         Coroutine c;
    4242        for(int i = 0; TEST(i < N); i++) {
    4343                #if !defined(TEST_FOREVER)
  • tests/concurrent/futures/multi.cfa

    rfeacef9 r5407cdc  
    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/errors/.expect/completeType.nast.arm64.txt

    rfeacef9 r5407cdc  
    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

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

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

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

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

    rfeacef9 r5407cdc  
    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}
  • tests/exceptions/cancel/thread.cfa

    rfeacef9 r5407cdc  
    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}
  • tests/exceptions/conditional.cfa

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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

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

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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/linking/exception-nothreads.cfa

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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/linking/weakso_nothd.cfa

    rfeacef9 r5407cdc  
    66//
    77// weakso_nothd.cfa --
    8 // test whether or not usind a weakso locks pulls in threads
     8// test whether or not using a weakso locks pulls in threads
    99//
    1010// Author           : Thierry Delisle
  • tests/meta/.expect/archVast.nast.arm64.txt

    rfeacef9 r5407cdc  
    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/time.cfa

    rfeacef9 r5407cdc  
    1010// Created On       : Tue Mar 27 17:24:56 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jun 18 18:14:49 2020
    13 // Update Count     : 37
     12// Last Modified On : Fri Apr 16 14:59:53 2021
     13// Update Count     : 38
    1414//
    1515
     
    5353        //       | "Newfoundland" | getTime( Newfoundland )
    5454        //       | "local" | getTime()
    55         //       | "local nsec" | getTimeNsec()
     55        //       | "local nsec" | timeHiRes()
    5656        //       | "PST" | PST();                                                               // getTime short form
    5757        // sout | nl;
  • tests/unified_locking/.expect/locks.txt

    rfeacef9 r5407cdc  
    1111Start Test 6: owner lock and condition variable 3 wait/notify all
    1212Done Test 6
    13 Start Test 7: multi acquisiton lock and condition variable multiple acquire and wait/notify
     13Start Test 7: fast lock and condition variable single wait/notify
    1414Done Test 7
    15 Start Test 8: owner lock and condition variable multiple acquire and wait/notify
     15Start Test 8: fast lock and condition variable 3 wait/notify all
    1616Done Test 8
    17 Start Test 9: no lock condition variable wait/notify
     17Start Test 9: multi acquisiton lock and condition variable multiple acquire and wait/notify
    1818Done Test 9
    19 Start Test 10: locked condition variable wait/notify with front()
     19Start Test 10: owner lock and condition variable multiple acquire and wait/notify
    2020Done Test 10
     21Start Test 11: no lock condition variable wait/notify
     22Done Test 11
     23Start Test 12: locked condition variable wait/notify with front()
     24Done Test 12
  • tests/unified_locking/locks.cfa

    rfeacef9 r5407cdc  
    1515condition_variable( owner_lock ) c_o;
    1616
     17fast_lock f;
     18condition_variable( fast_lock ) c_f;
     19
    1720thread T_C_M_WS1 {};
    1821
     
    6871                }
    6972                unlock(s);
     73        }
     74}
     75
     76thread T_C_F_WS1 {};
     77
     78void main( T_C_F_WS1 & this ) {
     79        for (unsigned int i = 0; i < num_times; i++) {
     80                lock(f);
     81                if(empty(c_f) && i != num_times - 1) {
     82                        wait(c_f,f);
     83                }else{
     84                        notify_one(c_f);
     85                }
     86                unlock(f);
     87        }
     88}
     89
     90thread T_C_F_WB1 {};
     91
     92void main( T_C_F_WB1 & this ) {
     93        for (unsigned int i = 0; i < num_times; i++) {
     94                lock(f);
     95                if(counter(c_f) == 3 || i == num_times - 1) {
     96                        notify_all(c_f);
     97                }else{
     98                        wait(c_f,f);
     99                }
     100                unlock(f);
    70101        }
    71102}
     
    255286        printf("Done Test 6\n");
    256287
    257         printf("Start Test 7: multi acquisiton lock and condition variable multiple acquire and wait/notify\n");
     288        printf("Start Test 7: fast lock and condition variable single wait/notify\n");
     289        {
     290                T_C_F_WS1 t1[2];
     291        }
     292        printf("Done Test 7\n");
     293
     294        printf("Start Test 8: fast lock and condition variable 3 wait/notify all\n");
     295        {
     296                T_C_F_WB1 t1[4];
     297        }
     298        printf("Done Test 8\n");
     299
     300        printf("Start Test 9: multi acquisiton lock and condition variable multiple acquire and wait/notify\n");
    258301        {
    259302                T_C_M_WS2 t1[2];
    260303        }
    261         printf("Done Test 7\n");
    262 
    263         printf("Start Test 8: owner lock and condition variable multiple acquire and wait/notify\n");
     304        printf("Done Test 9\n");
     305
     306        printf("Start Test 10: owner lock and condition variable multiple acquire and wait/notify\n");
    264307        {
    265308                T_C_O_WS2 t1[2];
    266309        }
    267         printf("Done Test 8\n");
    268 
    269         printf("Start Test 9: no lock condition variable wait/notify\n");
     310        printf("Done Test 10\n");
     311
     312        printf("Start Test 11: no lock condition variable wait/notify\n");
    270313        {
    271314                T_C_NLW t1;
    272315                T_C_NLS t2;
    273316        }
    274         printf("Done Test 9\n");
    275 
    276         printf("Start Test 10: locked condition variable wait/notify with front()\n");
     317        printf("Done Test 11\n");
     318
     319        printf("Start Test 12: locked condition variable wait/notify with front()\n");
    277320        {
    278321                T_C_S_WNF t1[2];
    279322        }
    280         printf("Done Test 10\n");
     323        printf("Done Test 12\n");
    281324
    282325        // removed to limit test duration. Full test is in long run tests
  • tests/vector_math/.expect/vec4_float.txt

    rfeacef9 r5407cdc  
    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

    rfeacef9 r5407cdc  
    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.