Changeset 7770cc8


Ignore:
Timestamp:
Nov 24, 2021, 9:47:56 PM (7 months ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
enum, master
Children:
5235d49
Parents:
94647b0 (diff), 3cc1111 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Files:
21 added
1 deleted
86 edited

Legend:

Unmodified
Added
Removed
  • benchmark/Makefile.am

    r94647b0 r7770cc8  
    613613
    614614RDQBENCHES = \
     615        rdq-churn-cfa \
    615616        rdq-cycle-cfa \
    616617        rdq-cycle-tokio \
  • benchmark/io/http/filecache.cfa

    r94647b0 r7770cc8  
    185185        sout | "Filled cache from path \"" | path | "\" with" | fcount | "files";
    186186        if( conflicts > 0 ) {
    187                 sout | "Found" | conflicts | "conflicts (seed: " | options.file_cache.hash_seed | ")";
     187                sout | "Found" | conflicts | "conflicts (size: " | file_cache.size | ", seed: " | options.file_cache.hash_seed | ")";
    188188                #if defined(REJECT_CONFLICTS)
    189189                        abort("Conflicts found in the cache");
  • benchmark/io/http/http_ring.cpp

    r94647b0 r7770cc8  
    118118// Get a fix reply based on the return code
    119119const char * http_msgs[] = {
    120         "HTTP/1.1 200 OK\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 15\r\nConnection: keep-alive\r\n\r\nHello, World!\r\n",
    121         "HTTP/1.1 400 Bad Request\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
    122         "HTTP/1.1 404 Not Found\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
    123         "HTTP/1.1 405 Method Not \r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
    124         "HTTP/1.1 408 Request Timeout\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
    125         "HTTP/1.1 413 Payload Too Large\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
    126         "HTTP/1.1 414 URI Too Long\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     120        "HTTP/1.1 200 OK\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 15\r\nConnection: keep-alive\r\n\r\nHello, World!\r\n",
     121        "HTTP/1.1 400 Bad Request\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     122        "HTTP/1.1 404 Not Found\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     123        "HTTP/1.1 405 Method Not \r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     124        "HTTP/1.1 408 Request Timeout\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     125        "HTTP/1.1 413 Payload Too Large\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     126        "HTTP/1.1 414 URI Too Long\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
    127127};
    128128static_assert( KNOWN_CODES == (sizeof(http_msgs) / sizeof(http_msgs[0])) );
  • benchmark/io/http/main.cfa

    r94647b0 r7770cc8  
    150150                        if(errno == EADDRINUSE) {
    151151                                if(waited == 0) {
     152                                        if(!options.interactive) abort | "Port already in use in non-interactive mode. Aborting";
    152153                                        sout | "Waiting for port";
    153154                                } else {
     
    190191                        init_protocol();
    191192                        {
    192                                 Worker workers[options.clopts.nworkers];
     193                                Worker * workers = anew(options.clopts.nworkers);
    193194                                for(i; options.clopts.nworkers) {
    194195                                        // if( options.file_cache.fixed_fds ) {
     
    212213                                }
    213214                                sout | nl;
     215                                if(!options.interactive) park();
    214216                                {
    215217                                        char buffer[128];
     
    249251
    250252                                sout | "Stopping connection threads..." | nonl; flush( sout );
     253                                adelete(workers);
    251254                        }
    252255                        sout | "done";
  • benchmark/io/http/options.cfa

    r94647b0 r7770cc8  
    2121        false, // log
    2222        false, // stats
     23        true, // interactive
     24        0, // redirect
     25        0, // redirect
    2326
    2427        { // file_cache
     
    5255        // bool sqkpoll = false;
    5356        // bool iokpoll = false;
    54         unsigned nentries = 16;
     57        unsigned nentries = 0;
    5558        bool isolate = false;
    5659
     
    6265                {'\0', "isolate",        "Create one cluster per processor", isolate, parse_settrue},
    6366                {'\0', "log",            "Enable logs", options.log, parse_settrue},
     67                {'\0', "sout",           "Redirect standard out to file", options.reopen_stdout},
     68                {'\0', "serr",           "Redirect standard error to file", options.reopen_stderr},
    6469                {'\0', "stats",          "Enable statistics", options.stats, parse_settrue},
     70                {'\0', "shell",          "Disable interactive mode", options.interactive, parse_setfalse},
    6571                {'\0', "accept-backlog", "Maximum number of pending accepts", options.socket.backlog},
    6672                {'\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},
     
    7985        parse_args( argc, argv, opt, opt_cnt, "[OPTIONS]... [PATH]\ncforall http server", left );
    8086
    81         if( !is_pow2(nentries) ) {
     87        if( nentries != 0 && !is_pow2(nentries) ) {
    8288                unsigned v = nentries;
    8389                v--;
     
    131137
    132138        options.file_cache.path = path;
     139
     140        if( options.reopen_stdout && options.reopen_stderr && 0 == strcmp(options.reopen_stdout, options.reopen_stderr) ) {
     141                serr | "Redirect sout and serr to the same file is not supported";
     142                exit(EXIT_FAILURE);
     143        }
     144
     145        if( options.reopen_stdout ) {
     146                sout | "redirecting sout to '" | options.reopen_stdout | "'";
     147                FILE  * ret = freopen( options.reopen_stdout, "w", stdout);
     148                if( ret == 0p ) {
     149                        serr | "Failed to redirect sout to '" | options.reopen_stdout | "'";
     150                        exit(EXIT_FAILURE);
     151                }
     152        }
     153
     154        if( options.reopen_stderr ) {
     155                sout | "redirecting serr to '" | options.reopen_stderr | "'";
     156                FILE  * ret = freopen( options.reopen_stderr, "w", stderr);
     157                if( ret == 0p ) {
     158                        serr | "Failed to redirect serr to '" | options.reopen_stderr | "'";
     159                        exit(EXIT_FAILURE);
     160                }
     161        }
    133162}
  • benchmark/io/http/options.hfa

    r94647b0 r7770cc8  
    1010        bool log;
    1111        bool stats;
     12        bool interactive;
     13        const char * reopen_stdout;
     14        const char * reopen_stderr;
    1215
    1316        struct {
  • benchmark/io/http/protocol.cfa

    r94647b0 r7770cc8  
    1111#include <fstream.hfa>
    1212#include <iofwd.hfa>
     13#include <io/types.hfa>
     14#include <mutex_stmt.hfa>
    1315
    1416#include <assert.h>
     
    2628#define PLAINTEXT_MEMCPY
    2729#define PLAINTEXT_NOCOPY
     30#define LINKED_IO
    2831
    2932struct https_msg_str {
     
    5356}
    5457
    55 static inline int answer( int fd, const char * it, int len) {
     58static inline int answer( int fd, const char * it, int len ) {
    5659        while(len > 0) {
    5760                // Call write
    5861                int ret = cfa_send(fd, it, len, 0, CFA_IO_LAZY);
    5962                if( ret < 0 ) {
    60                         if( errno == ECONNRESET || errno == EPIPE ) return -ECONNRESET;
     63                        if( errno == ECONNRESET || errno == EPIPE ) { close(fd); return -ECONNRESET; }
    6164                        if( errno == EAGAIN || errno == EWOULDBLOCK) return -EAGAIN;
    6265
     
    7780}
    7881
    79 int answer_header( int fd, size_t size ) {
    80         char buffer[512];
    81         char * it = buffer;
     82static int fill_header(char * it, size_t size) {
    8283        memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
    8384        it += http_msgs[OK200]->len;
    8485        int len = http_msgs[OK200]->len;
    8586        len += snprintf(it, 512 - len, "%d \n\n", size);
     87        return len;
     88}
     89
     90static int answer_header( int fd, size_t size ) {
     91        char buffer[512];
     92        int len = fill_header(buffer, size);
    8693        return answer( fd, buffer, len );
    8794}
     
    135142}
    136143
    137 
    138 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len) {
    139         char * it = buffer;
    140         size_t count = len - 1;
    141         int rlen = 0;
    142         READ:
    143         for() {
    144                 int ret = cfa_recv(fd, (void*)it, count, 0, CFA_IO_LAZY);
    145                 // int ret = read(fd, (void*)it, count);
    146                 if(ret == 0 ) return [OK200, true, 0, 0];
    147                 if(ret < 0 ) {
    148                         if( errno == EAGAIN || errno == EWOULDBLOCK) continue READ;
    149                         if( errno == ECONNRESET ) return [E408, true, 0, 0];
    150                         if( errno == EPIPE ) return [E408, true, 0, 0];
    151                         abort( "read error: (%d) %s\n", (int)errno, strerror(errno) );
    152                 }
    153                 it[ret + 1] = '\0';
    154                 rlen += ret;
    155 
    156                 if( strstr( it, "\r\n\r\n" ) ) break;
    157 
    158                 it += ret;
    159                 count -= ret;
    160 
    161                 if( count < 1 ) return [E414, false, 0, 0];
    162         }
    163 
    164         if( options.log ) {
    165                 write(sout, buffer, rlen);
    166                 sout | nl;
    167         }
    168 
    169         it = buffer;
    170         int ret = memcmp(it, "GET /", 5);
    171         if( ret != 0 ) return [E400, false, 0, 0];
    172         it += 5;
    173 
    174         char * end = strstr( it, " " );
    175         return [OK200, false, it, end - it];
    176 }
    177 
    178 int sendfile( int pipe[2], int fd, int ans_fd, size_t count ) {
     144static int sendfile( int pipe[2], int fd, int ans_fd, size_t count ) {
    179145        unsigned sflags = SPLICE_F_MOVE; // | SPLICE_F_MORE;
    180146        off_t offset = 0;
     
    207173}
    208174
     175static void zero_sqe(struct io_uring_sqe * sqe) {
     176        sqe->flags = 0;
     177        sqe->ioprio = 0;
     178        sqe->fd = 0;
     179        sqe->off = 0;
     180        sqe->addr = 0;
     181        sqe->len = 0;
     182        sqe->fsync_flags = 0;
     183        sqe->__pad2[0] = 0;
     184        sqe->__pad2[1] = 0;
     185        sqe->__pad2[2] = 0;
     186        sqe->fd = 0;
     187        sqe->off = 0;
     188        sqe->addr = 0;
     189        sqe->len = 0;
     190}
     191
     192enum FSM_STATE {
     193        Initial,
     194        Retry,
     195        Error,
     196        Done,
     197};
     198
     199struct FSM_Result {
     200        FSM_STATE state;
     201        int error;
     202};
     203
     204static inline void ?{}(FSM_Result & this) { this.state = Initial; this.error = 0; }
     205static inline bool is_error(FSM_Result & this) { return Error == this.state; }
     206static inline bool is_done(FSM_Result & this) { return Done == this.state; }
     207
     208static inline int error(FSM_Result & this, int error) {
     209        this.error = error;
     210        this.state = Error;
     211        return error;
     212}
     213
     214static inline int done(FSM_Result & this) {
     215        this.state = Done;
     216        return 0;
     217}
     218
     219static inline int retry(FSM_Result & this) {
     220        this.state = Retry;
     221        return 0;
     222}
     223
     224static inline int need(FSM_Result & this) {
     225        switch(this.state) {
     226                case Initial:
     227                case Retry:
     228                        return 1;
     229                case Error:
     230                        if(this.error == 0) mutex(serr) serr | "State marked error but code is 0";
     231                case Done:
     232                        return 0;
     233        }
     234}
     235
     236// Generator that handles sending the header
     237generator header_g {
     238        io_future_t f;
     239        const char * next;
     240        int fd; size_t len;
     241        FSM_Result res;
     242};
     243
     244static inline void ?{}(header_g & this, int fd, const char * it, size_t len ) {
     245        this.next = it;
     246        this.fd = fd;
     247        this.len = len;
     248}
     249
     250static inline void fill(header_g & this, struct io_uring_sqe * sqe) {
     251        zero_sqe(sqe);
     252        sqe->opcode = IORING_OP_SEND;
     253        sqe->user_data = (uintptr_t)&this.f;
     254        sqe->flags = IOSQE_IO_LINK;
     255        sqe->fd = this.fd;
     256        sqe->addr = (uintptr_t)this.next;
     257        sqe->len = this.len;
     258}
     259
     260static inline int error(header_g & this, int error) {
     261        int ret = close(this.fd);
     262        if( ret != 0 ) {
     263                mutex(serr) serr | "Failed to close fd" | errno;
     264        }
     265        return error(this.res, error);
     266}
     267
     268static inline int wait_and_process(header_g & this) {
     269        wait(this.f);
     270
     271        // Did something crazy happen?
     272        if(this.f.result > this.len) {
     273                mutex(serr) serr | "HEADER sent too much!";
     274                return error(this, -ERANGE);
     275        }
     276
     277        // Something failed?
     278        if(this.f.result < 0) {
     279                int error = -this.f.result;
     280                if( error == ECONNRESET ) return error(this, -ECONNRESET);
     281                if( error == EPIPE ) return error(this, -EPIPE);
     282                if( error == ECANCELED ) {
     283                        mutex(serr) serr | "HEADER was cancelled, WTF!";
     284                        return error(this, -ECONNRESET);
     285                }
     286                if( error == EAGAIN || error == EWOULDBLOCK) {
     287                        mutex(serr) serr | "HEADER got eagain, WTF!";
     288                        return error(this, -ECONNRESET);
     289                }
     290        }
     291
     292        // Done?
     293        if(this.f.result == this.len) {
     294                return done(this.res);
     295        }
     296
     297        // It must be a Short read
     298        this.len  -= this.f.result;
     299        this.next += this.f.result;
     300        reset(this.f);
     301        return retry(this.res);
     302}
     303
     304// Generator that handles splicing in a file
     305struct splice_in_t {
     306        io_future_t f;
     307        int fd; int pipe; size_t len; off_t off;
     308        FSM_Result res;
     309};
     310
     311static inline void ?{}(splice_in_t & this, int fd, int pipe, size_t len) {
     312        this.fd = fd;
     313        this.pipe = pipe;
     314        this.len = len;
     315        this.off = 0;
     316}
     317
     318static inline void fill(splice_in_t & this, struct io_uring_sqe * sqe) {
     319        zero_sqe(sqe);
     320        sqe->opcode = IORING_OP_SPLICE;
     321        sqe->user_data = (uintptr_t)&this.f;
     322        sqe->flags = 0;
     323        sqe->splice_fd_in = this.fd;
     324        sqe->splice_off_in = this.off;
     325        sqe->fd = this.pipe;
     326        sqe->off = (__u64)-1;
     327        sqe->len = this.len;
     328        sqe->splice_flags = SPLICE_F_MOVE;
     329}
     330
     331static inline int wait_and_process(splice_in_t & this) {
     332        wait(this.f);
     333
     334        // Something failed?
     335        if(this.f.result < 0) {
     336                int error = -this.f.result;
     337                if( error == ECONNRESET ) return error(this.res, -ECONNRESET);
     338                if( error == EPIPE ) return error(this.res, -EPIPE);
     339                if( error == ECANCELED ) {
     340                        mutex(serr) serr | "SPLICE IN was cancelled, WTF!";
     341                        return error(this.res, -ECONNRESET);
     342                }
     343                if( error == EAGAIN || error == EWOULDBLOCK) {
     344                        mutex(serr) serr | "SPLICE IN got eagain, WTF!";
     345                        return error(this.res, -ECONNRESET);
     346                }
     347        }
     348
     349        // Did something crazy happen?
     350        if(this.f.result > this.len) {
     351                mutex(serr) serr | "SPLICE IN spliced too much!";
     352                return error(this.res, -ERANGE);
     353        }
     354
     355        // Done?
     356        if(this.f.result == this.len) {
     357                return done(this.res);
     358        }
     359
     360        // It must be a Short read
     361        this.len -= this.f.result;
     362        this.off += this.f.result;
     363        reset(this.f);
     364        return retry(this.res);
     365}
     366
     367generator splice_out_g {
     368        io_future_t f;
     369        int pipe; int fd; size_t len;
     370        FSM_Result res;
     371};
     372
     373static inline void ?{}(splice_out_g & this, int pipe, int fd, size_t len) {
     374        this.pipe = pipe;
     375        this.fd = fd;
     376        this.len = len;
     377}
     378
     379static inline void fill(splice_out_g & this, struct io_uring_sqe * sqe) {
     380        zero_sqe(sqe);
     381        sqe->opcode = IORING_OP_SPLICE;
     382        sqe->user_data = (uintptr_t)&this.f;
     383        sqe->flags = 0;
     384        sqe->splice_fd_in = this.pipe;
     385        sqe->splice_off_in = (__u64)-1;
     386        sqe->fd = this.fd;
     387        sqe->off = (__u64)-1;
     388        sqe->len = this.len;
     389        sqe->splice_flags = SPLICE_F_MOVE;
     390}
     391
     392static inline int error(splice_out_g & this, int error) {
     393        int ret = close(this.fd);
     394        if( ret != 0 ) {
     395                mutex(serr) serr | "Failed to close fd" | errno;
     396        }
     397        return error(this.res, error);
     398}
     399
     400static inline void wait_and_process(splice_out_g & this) {
     401        wait(this.f);
     402
     403        // Something failed?
     404        if(this.f.result < 0) {
     405                int error = -this.f.result;
     406                if( error == ECONNRESET ) return error(this, -ECONNRESET);
     407                if( error == EPIPE ) return error(this, -EPIPE);
     408                if( error == ECANCELED ) {
     409                        this.f.result = 0;
     410                        goto SHORT_WRITE;
     411                }
     412                if( error == EAGAIN || error == EWOULDBLOCK) {
     413                        mutex(serr) serr | "SPLICE OUT got eagain, WTF!";
     414                        return error(this, -ECONNRESET);
     415                }
     416        }
     417
     418        // Did something crazy happen?
     419        if(this.f.result > this.len) {
     420                mutex(serr) serr | "SPLICE OUT spliced too much!" | this.f.result | ">" | this.len;
     421                return error(this.res, -ERANGE);
     422        }
     423
     424        // Done?
     425        if(this.f.result == this.len) {
     426                return done(this.res);
     427        }
     428
     429SHORT_WRITE:
     430        // It must be a Short Write
     431        this.len -= this.f.result;
     432        reset(this.f);
     433        return retry(this.res);
     434}
     435
     436int answer_sendfile( int pipe[2], int fd, int ans_fd, size_t fsize ) {
     437        #if defined(LINKED_IO)
     438                char buffer[512];
     439                int len = fill_header(buffer, fsize);
     440                header_g header = { fd, buffer, len };
     441                splice_in_t splice_in = { ans_fd, pipe[1], fsize };
     442                splice_out_g splice_out = { pipe[0], fd, fsize };
     443
     444                RETRY_LOOP: for() {
     445                        int have = need(header.res) + need(splice_in.res) + 1;
     446                        int idx = 0;
     447                        struct io_uring_sqe * sqes[3];
     448                        __u32 idxs[3];
     449                        struct $io_context * ctx = cfa_io_allocate(sqes, idxs, have);
     450
     451                        if(need(splice_in.res)) { fill(splice_in, sqes[idx++]); }
     452                        if(need(   header.res)) { fill(header   , sqes[idx++]); }
     453                        fill(splice_out, sqes[idx]);
     454
     455                        // Submit everything
     456                        asm volatile("": : :"memory");
     457                        cfa_io_submit( ctx, idxs, have, false );
     458
     459                        // wait for the results
     460                        // Always wait for splice-in to complete as
     461                        // we may need to kill the connection if it fails
     462                        // If it already completed, this is a no-op
     463                        wait_and_process(splice_in);
     464
     465                        if(is_error(splice_in.res)) {
     466                                mutex(serr) serr | "SPLICE IN failed with" | splice_in.res.error;
     467                                close(fd);
     468                        }
     469
     470                        // Process the other 2
     471                        wait_and_process(header);
     472                        wait_and_process(splice_out);
     473
     474                        if(is_done(splice_out.res)) {
     475                                break RETRY_LOOP;
     476                        }
     477
     478                        // We need to wait for the completion if
     479                        // - both completed
     480                        // - the header failed
     481                        // -
     482
     483                        if(  is_error(header.res)
     484                          || is_error(splice_in.res)
     485                          || is_error(splice_out.res)) {
     486                                return -ECONNRESET;
     487                        }
     488                }
     489
     490                return len + fsize;
     491        #else
     492                int ret = answer_header(fd, fsize);
     493                if( ret < 0 ) { close(fd); return ret; }
     494                return sendfile(pipe, fd, ans_fd, fsize);
     495        #endif
     496}
     497
     498[HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len) {
     499        char * it = buffer;
     500        size_t count = len - 1;
     501        int rlen = 0;
     502        READ:
     503        for() {
     504                int ret = cfa_recv(fd, (void*)it, count, 0, CFA_IO_LAZY);
     505                // int ret = read(fd, (void*)it, count);
     506                if(ret == 0 ) return [OK200, true, 0, 0];
     507                if(ret < 0 ) {
     508                        if( errno == EAGAIN || errno == EWOULDBLOCK) continue READ;
     509                        if( errno == ECONNRESET ) { close(fd); return [E408, true, 0, 0]; }
     510                        if( errno == EPIPE ) { close(fd); return [E408, true, 0, 0]; }
     511                        abort( "read error: (%d) %s\n", (int)errno, strerror(errno) );
     512                }
     513                it[ret + 1] = '\0';
     514                rlen += ret;
     515
     516                if( strstr( it, "\r\n\r\n" ) ) break;
     517
     518                it += ret;
     519                count -= ret;
     520
     521                if( count < 1 ) return [E414, false, 0, 0];
     522        }
     523
     524        if( options.log ) {
     525                write(sout, buffer, rlen);
     526                sout | nl;
     527        }
     528
     529        it = buffer;
     530        int ret = memcmp(it, "GET /", 5);
     531        if( ret != 0 ) return [E400, false, 0, 0];
     532        it += 5;
     533
     534        char * end = strstr( it, " " );
     535        return [OK200, false, it, end - it];
     536}
     537
    209538//=============================================================================================
    210539
     
    214543
    215544const 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",
     545        "HTTP/1.1 200 OK\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: ",
     546        "HTTP/1.1 200 OK\r\nServer: HttpForall\r\nConnection: keep-alive\r\nContent-Length: 15\r\nContent-Type: text/html\r\nDate: %s \r\n\r\nHello, World!\r\n",
     547        "HTTP/1.1 400 Bad Request\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     548        "HTTP/1.1 404 Not Found\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     549        "HTTP/1.1 405 Method Not Allowed\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     550        "HTTP/1.1 408 Request Timeout\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     551        "HTTP/1.1 413 Payload Too Large\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     552        "HTTP/1.1 414 URI Too Long\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    224553};
    225554
     
    251580                Time now = timeHiRes();
    252581                strftime( buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now );
    253                 sout | "Updated date to '" | buff | "'";
     582                // if( options.log ) sout | "Updated date to '" | buff | "'";
    254583
    255584                for(i; KNOWN_CODES) {
     
    264593                this.idx = (this.idx + 1) % 2;
    265594
    266                 sout | "Date thread sleeping";
     595                // if( options.log ) sout | "Date thread sleeping";
    267596
    268597                sleep(1`s);
  • benchmark/io/http/protocol.hfa

    r94647b0 r7770cc8  
    1616
    1717int answer_error( int fd, HttpCode code );
    18 int answer_header( int fd, size_t size );
    1918int answer_plaintext( int fd );
    2019int answer_empty( int fd );
     20int answer_sendfile( int pipe[2], int fd, int ans_fd, size_t count );
    2121
    2222[HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len);
    23 
    24 int sendfile( int pipe[2], int fd, int ans_fd, size_t count );
  • benchmark/io/http/worker.cfa

    r94647b0 r7770cc8  
    1818void ?{}( Worker & this ) {
    1919        size_t cli = rand() % options.clopts.cltr_cnt;
    20         ((thread&)this){ "Server Worker Thread", *options.clopts.instance[cli], 512000 };
     20        ((thread&)this){ "Server Worker Thread", *options.clopts.instance[cli], 64000 };
    2121        options.clopts.thrd_cnt[cli]++;
    2222        this.pipe[0] = -1;
     
    122122                        }
    123123
    124                         // Send the header
    125                         int ret = answer_header(fd, count);
    126                         if( ret == -ECONNRESET ) break REQUEST;
    127 
    128124                        // Send the desired file
    129                         ret = sendfile( this.pipe, fd, ans_fd, count);
     125                        int ret = answer_sendfile( this.pipe, fd, ans_fd, count);
    130126                        if( ret == -ECONNRESET ) break REQUEST;
    131127
     
    134130
    135131                if( options.log ) sout | "=== Connection closed ===";
    136                 close(fd);
    137132                continue CONNECTION;
    138133        }
  • doc/theses/mubeen_zulfiqar_MMath/allocator.tex

    r94647b0 r7770cc8  
    2424\end{itemize}
    2525
    26 The new features added to uHeapLmmm (incl. @malloc_size@ routine)
     26The new features added to uHeapLmmm (incl. @malloc\_size@ routine)
    2727\CFA alloc interface with examples.
     28
    2829\begin{itemize}
    2930\item
     
    117118We added a few more features and routines to the allocator's C interface that can make the allocator more usable to the programmers. THese features will programmer more control on the dynamic memory allocation.
    118119
    119 \subsubsection void * aalloc( size_t dim, size_t elemSize )
     120\subsubsection void * aalloc( size\_t dim, size\_t elemSize )
    120121aalloc is an extension of malloc. It allows programmer to allocate a dynamic array of objects without calculating the total size of array explicitly. The only alternate of this routine in the other allocators is calloc but calloc also fills the dynamic memory with 0 which makes it slower for a programmer who only wants to dynamically allocate an array of objects without filling it with 0.
    121122\paragraph{Usage}
    122123aalloc takes two parameters.
     124
    123125\begin{itemize}
    124126\item
     
    129131It returns address of dynamic object allocatoed on heap that can contain dim number of objects of the size elemSize. On failure, it returns NULL pointer.
    130132
    131 \subsubsection void * resize( void * oaddr, size_t size )
     133\subsubsection void * resize( void * oaddr, size\_t size )
    132134resize is an extension of relloc. It allows programmer to reuse a cuurently allocated dynamic object with a new size requirement. Its alternate in the other allocators is realloc but relloc also copy the data in old object to the new object which makes it slower for the programmer who only wants to reuse an old dynamic object for a new size requirement but does not want to preserve the data in the old object to the new object.
    133135\paragraph{Usage}
    134136resize takes two parameters.
     137
    135138\begin{itemize}
    136139\item
     
    141144It returns an object that is of the size given but it does not preserve the data in the old object. On failure, it returns NULL pointer.
    142145
    143 \subsubsection void * resize( void * oaddr, size_t nalign, size_t size )
     146\subsubsection void * resize( void * oaddr, size\_t nalign, size\_t size )
    144147This resize is an extension of the above resize (FIX ME: cite above resize). In addition to resizing the size of of an old object, it can also realign the old object to a new alignment requirement.
    145148\paragraph{Usage}
    146149This resize takes three parameters. It takes an additional parameter of nalign as compared to the above resize (FIX ME: cite above resize).
     150
    147151\begin{itemize}
    148152\item
     
    155159It returns an object with the size and alignment given in the parameters. On failure, it returns a NULL pointer.
    156160
    157 \subsubsection void * amemalign( size_t alignment, size_t dim, size_t elemSize )
     161\subsubsection void * amemalign( size\_t alignment, size\_t dim, size\_t elemSize )
    158162amemalign is a hybrid of memalign and aalloc. It allows programmer to allocate an aligned dynamic array of objects without calculating the total size of the array explicitly. It frees the programmer from calculating the total size of the array.
    159163\paragraph{Usage}
    160164amemalign takes three parameters.
     165
    161166\begin{itemize}
    162167\item
     
    169174It returns a dynamic array of objects that has the capacity to contain dim number of objects of the size of elemSize. The returned dynamic array is aligned to the given alignment. On failure, it returns NULL pointer.
    170175
    171 \subsubsection void * cmemalign( size_t alignment, size_t dim, size_t elemSize )
     176\subsubsection void * cmemalign( size\_t alignment, size\_t dim, size\_t elemSize )
    172177cmemalign is a hybrid of amemalign and calloc. It allows programmer to allocate an aligned dynamic array of objects that is 0 filled. The current way to do this in other allocators is to allocate an aligned object with memalign and then fill it with 0 explicitly. This routine provides both features of aligning and 0 filling, implicitly.
    173178\paragraph{Usage}
    174179cmemalign takes three parameters.
     180
    175181\begin{itemize}
    176182\item
     
    183189It returns a dynamic array of objects that has the capacity to contain dim number of objects of the size of elemSize. The returned dynamic array is aligned to the given alignment and is 0 filled. On failure, it returns NULL pointer.
    184190
    185 \subsubsection size_t malloc_alignment( void * addr )
    186 malloc_alignment returns the alignment of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required alignment.
    187 \paragraph{Usage}
    188 malloc_alignment takes one parameters.
     191\subsubsection size\_t malloc\_alignment( void * addr )
     192malloc\_alignment returns the alignment of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required alignment.
     193\paragraph{Usage}
     194malloc\_alignment takes one parameters.
     195
    189196\begin{itemize}
    190197\item
    191198addr: the address of the currently allocated dynamic object.
    192199\end{itemize}
    193 malloc_alignment returns the alignment of the given dynamic object. On failure, it return the value of default alignment of the uHeapLmmm allocator.
    194 
    195 \subsubsection bool malloc_zero_fill( void * addr )
    196 malloc_zero_fill returns whether a currently allocated dynamic object was initially zero filled at the time of allocation. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verifying the zero filled property of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was zero filled at the time of allocation.
    197 \paragraph{Usage}
    198 malloc_zero_fill takes one parameters.
     200malloc\_alignment returns the alignment of the given dynamic object. On failure, it return the value of default alignment of the uHeapLmmm allocator.
     201
     202\subsubsection bool malloc\_zero\_fill( void * addr )
     203malloc\_zero\_fill returns whether a currently allocated dynamic object was initially zero filled at the time of allocation. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verifying the zero filled property of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was zero filled at the time of allocation.
     204\paragraph{Usage}
     205malloc\_zero\_fill takes one parameters.
     206
    199207\begin{itemize}
    200208\item
    201209addr: the address of the currently allocated dynamic object.
    202210\end{itemize}
    203 malloc_zero_fill returns true if the dynamic object was initially zero filled and return false otherwise. On failure, it returns false.
    204 
    205 \subsubsection size_t malloc_size( void * addr )
    206 malloc_size returns the allocation size of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required size. Its current alternate in the other allocators is malloc_usable_size. But, malloc_size is different from malloc_usable_size as malloc_usabe_size returns the total data capacity of dynamic object including the extra space at the end of the dynamic object. On the other hand, malloc_size returns the size that was given to the allocator at the allocation of the dynamic object. This size is updated when an object is realloced, resized, or passed through a similar allocator routine.
    207 \paragraph{Usage}
    208 malloc_size takes one parameters.
     211malloc\_zero\_fill returns true if the dynamic object was initially zero filled and return false otherwise. On failure, it returns false.
     212
     213\subsubsection size\_t malloc\_size( void * addr )
     214malloc\_size returns the allocation size of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required size. Its current alternate in the other allocators is malloc\_usable\_size. But, malloc\_size is different from malloc\_usable\_size as malloc\_usabe\_size returns the total data capacity of dynamic object including the extra space at the end of the dynamic object. On the other hand, malloc\_size returns the size that was given to the allocator at the allocation of the dynamic object. This size is updated when an object is realloced, resized, or passed through a similar allocator routine.
     215\paragraph{Usage}
     216malloc\_size takes one parameters.
     217
    209218\begin{itemize}
    210219\item
    211220addr: the address of the currently allocated dynamic object.
    212221\end{itemize}
    213 malloc_size returns the allocation size of the given dynamic object. On failure, it return zero.
    214 
    215 \subsubsection void * realloc( void * oaddr, size_t nalign, size_t size )
     222malloc\_size returns the allocation size of the given dynamic object. On failure, it return zero.
     223
     224\subsubsection void * realloc( void * oaddr, size\_t nalign, size\_t size )
    216225This realloc is an extension of the default realloc (FIX ME: cite default realloc). In addition to reallocating an old object and preserving the data in old object, it can also realign the old object to a new alignment requirement.
    217226\paragraph{Usage}
    218227This realloc takes three parameters. It takes an additional parameter of nalign as compared to the default realloc.
     228
    219229\begin{itemize}
    220230\item
     
    237247It returns a dynamic object of the size of type T. On failure, it return NULL pointer.
    238248
    239 \subsubsection T * aalloc( size_t dim )
     249\subsubsection T * aalloc( size\_t dim )
    240250This aalloc is a simplified polymorphic form of above aalloc (FIX ME: cite aalloc). It takes one parameter as compared to the above aalloc that takes two parameters.
    241251\paragraph{Usage}
    242252aalloc takes one parameters.
     253
    243254\begin{itemize}
    244255\item
     
    247258It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. On failure, it return NULL pointer.
    248259
    249 \subsubsection T * calloc( size_t dim )
     260\subsubsection T * calloc( size\_t dim )
    250261This calloc is a simplified polymorphic form of defualt calloc (FIX ME: cite calloc). It takes one parameter as compared to the default calloc that takes two parameters.
    251262\paragraph{Usage}
    252263This calloc takes one parameter.
     264
    253265\begin{itemize}
    254266\item
     
    257269It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. On failure, it return NULL pointer.
    258270
    259 \subsubsection T * resize( T * ptr, size_t size )
     271\subsubsection T * resize( T * ptr, size\_t size )
    260272This resize is a simplified polymorphic form of above resize (FIX ME: cite resize with alignment). It takes two parameters as compared to the above resize that takes three parameters. It frees the programmer from explicitly mentioning the alignment of the allocation as CFA provides gives allocator the liberty to get the alignment of the returned type.
    261273\paragraph{Usage}
    262274This resize takes two parameters.
     275
    263276\begin{itemize}
    264277\item
     
    269282It returns a dynamic object of the size given in paramters. The returned object is aligned to the alignemtn of type T. On failure, it return NULL pointer.
    270283
    271 \subsubsection T * realloc( T * ptr, size_t size )
     284\subsubsection T * realloc( T * ptr, size\_t size )
    272285This realloc is a simplified polymorphic form of defualt realloc (FIX ME: cite realloc with align). It takes two parameters as compared to the above realloc that takes three parameters. It frees the programmer from explicitly mentioning the alignment of the allocation as CFA provides gives allocator the liberty to get the alignment of the returned type.
    273286\paragraph{Usage}
    274287This realloc takes two parameters.
     288
    275289\begin{itemize}
    276290\item
     
    281295It returns a dynamic object of the size given in paramters that preserves the data in the given object. The returned object is aligned to the alignemtn of type T. On failure, it return NULL pointer.
    282296
    283 \subsubsection T * memalign( size_t align )
     297\subsubsection T * memalign( size\_t align )
    284298This memalign is a simplified polymorphic form of defualt memalign (FIX ME: cite memalign). It takes one parameters as compared to the default memalign that takes two parameters.
    285299\paragraph{Usage}
    286300memalign takes one parameters.
     301
    287302\begin{itemize}
    288303\item
     
    291306It returns a dynamic object of the size of type T that is aligned to given parameter align. On failure, it return NULL pointer.
    292307
    293 \subsubsection T * amemalign( size_t align, size_t dim )
     308\subsubsection T * amemalign( size\_t align, size\_t dim )
    294309This amemalign is a simplified polymorphic form of above amemalign (FIX ME: cite amemalign). It takes two parameter as compared to the above amemalign that takes three parameters.
    295310\paragraph{Usage}
    296311amemalign takes two parameters.
     312
    297313\begin{itemize}
    298314\item
     
    303319It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. The returned object is aligned to the given parameter align. On failure, it return NULL pointer.
    304320
    305 \subsubsection T * cmemalign( size_t align, size_t dim  )
     321\subsubsection T * cmemalign( size\_t align, size\_t dim  )
    306322This cmemalign is a simplified polymorphic form of above cmemalign (FIX ME: cite cmemalign). It takes two parameter as compared to the above cmemalign that takes three parameters.
    307323\paragraph{Usage}
    308324cmemalign takes two parameters.
     325
    309326\begin{itemize}
    310327\item
     
    315332It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. The returned object is aligned to the given parameter align and is zero filled. On failure, it return NULL pointer.
    316333
    317 \subsubsection T * aligned_alloc( size_t align )
    318 This aligned_alloc is a simplified polymorphic form of defualt aligned_alloc (FIX ME: cite aligned_alloc). It takes one parameter as compared to the default aligned_alloc that takes two parameters.
    319 \paragraph{Usage}
    320 This aligned_alloc takes one parameter.
     334\subsubsection T * aligned\_alloc( size\_t align )
     335This aligned\_alloc is a simplified polymorphic form of defualt aligned\_alloc (FIX ME: cite aligned\_alloc). It takes one parameter as compared to the default aligned\_alloc that takes two parameters.
     336\paragraph{Usage}
     337This aligned\_alloc takes one parameter.
     338
    321339\begin{itemize}
    322340\item
     
    325343It returns a dynamic object of the size of type T that is aligned to the given parameter. On failure, it return NULL pointer.
    326344
    327 \subsubsection int posix_memalign( T ** ptr, size_t align )
    328 This posix_memalign is a simplified polymorphic form of defualt posix_memalign (FIX ME: cite posix_memalign). It takes two parameters as compared to the default posix_memalign that takes three parameters.
    329 \paragraph{Usage}
    330 This posix_memalign takes two parameter.
     345\subsubsection int posix\_memalign( T ** ptr, size\_t align )
     346This posix\_memalign is a simplified polymorphic form of defualt posix\_memalign (FIX ME: cite posix\_memalign). It takes two parameters as compared to the default posix\_memalign that takes three parameters.
     347\paragraph{Usage}
     348This posix\_memalign takes two parameter.
     349
    331350\begin{itemize}
    332351\item
     
    335354align: required alignment of the dynamic object.
    336355\end{itemize}
     356
    337357It stores address of the dynamic object of the size of type T in given parameter ptr. This object is aligned to the given parameter. On failure, it return NULL pointer.
    338358
     
    349369It returns a dynamic object of the size that is calcutaed by rouding the size of type T. The returned object is also aligned to the page size. On failure, it return NULL pointer.
    350370
    351 \subsection{Alloc Interface}
     371\subsection Alloc Interface
    352372In addition to improve allocator interface both for CFA and our standalone allocator uHeapLmmm in C. We also added a new alloc interface in CFA that increases usability of dynamic memory allocation.
    353373This interface helps programmers in three major ways.
     374
    354375\begin{itemize}
    355376\item
     
    371392This is the only parameter in the alloc routine that has a fixed-position and it is also the only parameter that does not use a backtick function. It has to be passed at the first position to alloc call in-case of an array allocation of objects of type T.
    372393It represents the required number of members in the array allocation as in CFA's aalloc (FIX ME: cite aalloc).
    373 This parameter should be of type size_t.
     394This parameter should be of type size\_t.
    374395
    375396Example: int a = alloc( 5 )
     
    377398
    378399\paragraph{Align}
    379 This parameter is position-free and uses a backtick routine align (`align). The parameter passed with `align should be of type size_t. If the alignment parameter is not a power of two or is less than the default alignment of the allocator (that can be found out using routine libAlign in CFA) then the passed alignment parameter will be rejected and the default alignment will be used.
     400This parameter is position-free and uses a backtick routine align (`align). The parameter passed with `align should be of type size\_t. If the alignment parameter is not a power of two or is less than the default alignment of the allocator (that can be found out using routine libAlign in CFA) then the passed alignment parameter will be rejected and the default alignment will be used.
    380401
    381402Example: int b = alloc( 5 , 64`align )
     
    385406This parameter is position-free and uses a backtick routine fill (`fill). In case of realloc, only the extra space after copying the data in the old object will be filled with given parameter.
    386407Three types of parameters can be passed using `fill.
     408
    387409\begin{itemize}
    388410\item
  • doc/theses/mubeen_zulfiqar_MMath/background.tex

    r94647b0 r7770cc8  
    2323====================
    2424
    25 \cite{Wasik08}
     25\section{Background}
     26
     27% FIXME: cite wasik
     28\cite{wasik.thesis}
     29
     30\subsection{Memory Allocation}
     31With dynamic allocation being an important feature of C, there are many standalone memory allocators that have been designed for different purposes. For this thesis, we chose 7 of the most popular and widely used memory allocators.
     32
     33\paragraph{dlmalloc}
     34dlmalloc (FIX ME: cite allocator) is a thread-safe allocator that is single threaded and single heap. dlmalloc maintains free-lists of different sizes to store freed dynamic memory. (FIX ME: cite wasik)
     35
     36\paragraph{hoard}
     37Hoard (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and using a heap layer framework. It has per-thred heaps that have thread-local free-lists, and a gloabl shared heap. (FIX ME: cite wasik)
     38
     39\paragraph{jemalloc}
     40jemalloc (FIX ME: cite allocator) is a thread-safe allocator that uses multiple arenas. Each thread is assigned an arena. Each arena has chunks that contain contagious memory regions of same size. An arena has multiple chunks that contain regions of multiple sizes.
     41
     42\paragraph{ptmalloc}
     43ptmalloc (FIX ME: cite allocator) is a modification of dlmalloc. It is a thread-safe multi-threaded memory allocator that uses multiple heaps. ptmalloc heap has similar design to dlmalloc's heap.
     44
     45\paragraph{rpmalloc}
     46rpmalloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses per-thread heap. Each heap has multiple size-classes and each size-calss contains memory regions of the relevant size.
     47
     48\paragraph{tbb malloc}
     49tbb malloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses private heap for each thread. Each private-heap has multiple bins of different sizes. Each bin contains free regions of the same size.
     50
     51\paragraph{tc malloc}
     52tcmalloc (FIX ME: cite allocator) is a thread-safe allocator. It uses per-thread cache to store free objects that prevents contention on shared resources in multi-threaded application. A central free-list is used to refill per-thread cache when it gets empty.
     53
     54\subsection{Benchmarks}
     55There are multiple benchmarks that are built individually and evaluate different aspects of a memory allocator. But, there is not standard set of benchamrks that can be used to evaluate multiple aspects of memory allocators.
     56
     57\paragraph{threadtest}
     58(FIX ME: cite benchmark and hoard) Each thread repeatedly allocates and then deallocates 100,000 objects. Runtime of the benchmark evaluates its efficiency.
     59
     60\paragraph{shbench}
     61(FIX ME: cite benchmark and hoard) Each thread allocates and randomly frees a number of random-sized objects. It is a stress test that also uses runtime to determine efficiency of the allocator.
     62
     63\paragraph{larson}
     64(FIX ME: cite benchmark and hoard) Larson simulates a server environment. Multiple threads are created where each thread allocator and free a number of objects within a size range. Some objects are passed from threads to the child threads to free. It caluculates memory operations per second as an indicator of memory allocator's performance.
  • doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex

    r94647b0 r7770cc8  
    149149*** FIX ME: Insert a figure of above benchmark with description
    150150
    151 \paragrpah{Relevant Knobs}
     151\paragraph{Relevant Knobs}
    152152*** FIX ME: Insert Relevant Knobs
    153153
  • doc/theses/mubeen_zulfiqar_MMath/intro.tex

    r94647b0 r7770cc8  
    4747\begin{itemize}
    4848\item
    49 aligned_alloc
     49aligned\_alloc
    5050\item
    51 malloc_usable_size
     51malloc\_usable\_size
    5252\item
    5353memalign
    5454\item
    55 posix_memalign
     55posix\_memalign
    5656\item
    5757pvalloc
     
    6161
    6262With the rise of concurrent applications, memory allocators should be able to fulfill dynamic memory requests from multiple threads in parallel without causing contention on shared resources. There needs to be a set of a standard benchmarks that can be used to evaluate an allocator's performance in different scenerios.
    63 
    64 \section{Background}
    65 
    66 \subsection{Memory Allocation}
    67 With dynamic allocation being an important feature of C, there are many standalone memory allocators that have been designed for different purposes. For this thesis, we chose 7 of the most popular and widely used memory allocators.
    68 
    69 \paragraph{dlmalloc}
    70 dlmalloc (FIX ME: cite allocator) is a thread-safe allocator that is single threaded and single heap. dlmalloc maintains free-lists of different sizes to store freed dynamic memory. (FIX ME: cite wasik)
    71 
    72 \paragraph{hoard}
    73 Hoard (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and using a heap layer framework. It has per-thred heaps that have thread-local free-lists, and a gloabl shared heap. (FIX ME: cite wasik)
    74 
    75 \paragraph{jemalloc}
    76 jemalloc (FIX ME: cite allocator) is a thread-safe allocator that uses multiple arenas. Each thread is assigned an arena. Each arena has chunks that contain contagious memory regions of same size. An arena has multiple chunks that contain regions of multiple sizes.
    77 
    78 \paragraph{ptmalloc}
    79 ptmalloc (FIX ME: cite allocator) is a modification of dlmalloc. It is a thread-safe multi-threaded memory allocator that uses multiple heaps. ptmalloc heap has similar design to dlmalloc's heap.
    80 
    81 \paragraph{rpmalloc}
    82 rpmalloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses per-thread heap. Each heap has multiple size-classes and each size-calss contains memory regions of the relevant size.
    83 
    84 \paragraph{tbb malloc}
    85 tbb malloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses private heap for each thread. Each private-heap has multiple bins of different sizes. Each bin contains free regions of the same size.
    86 
    87 \paragraph{tc malloc}
    88 tcmalloc (FIX ME: cite allocator) is a thread-safe allocator. It uses per-thread cache to store free objects that prevents contention on shared resources in multi-threaded application. A central free-list is used to refill per-thread cache when it gets empty.
    89 
    90 \subsection{Benchmarks}
    91 There are multiple benchmarks that are built individually and evaluate different aspects of a memory allocator. But, there is not standard set of benchamrks that can be used to evaluate multiple aspects of memory allocators.
    92 
    93 \paragraph{threadtest}
    94 (FIX ME: cite benchmark and hoard) Each thread repeatedly allocates and then deallocates 100,000 objects. Runtime of the benchmark evaluates its efficiency.
    95 
    96 \paragraph{shbench}
    97 (FIX ME: cite benchmark and hoard) Each thread allocates and randomly frees a number of random-sized objects. It is a stress test that also uses runtime to determine efficiency of the allocator.
    98 
    99 \paragraph{larson}
    100 (FIX ME: cite benchmark and hoard) Larson simulates a server environment. Multiple threads are created where each thread allocator and free a number of objects within a size range. Some objects are passed from threads to the child threads to free. It caluculates memory operations per second as an indicator of memory allocator's performance.
    10163
    10264\section{Research Objectives}
  • doc/theses/mubeen_zulfiqar_MMath/performance.tex

    r94647b0 r7770cc8  
    4444tc               &             &  \\
    4545\end{tabularx}
    46 (FIX ME: complete table)
     46
     47%(FIX ME: complete table)
    4748
    4849\section{Experiment Environment}
  • doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.bib

    r94647b0 r7770cc8  
    2727        address =       "Reading, Massachusetts"
    2828}
     29
     30@article{wasik.thesis,
     31    author        = "Ayelet Wasik",
     32    title         = "Features of A Multi-Threaded Memory Alloator",
     33    publisher     = "University of Waterloo",
     34    year          = "2008"
     35}
  • doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.tex

    r94647b0 r7770cc8  
    8484\usepackage{graphicx}
    8585\usepackage{comment} % Removes large sections of the document.
     86\usepackage{tabularx}
    8687
    8788% Hyperlinks make it very easy to navigate an electronic document.
     
    191192% Tip: Putting each sentence on a new line is a way to simplify later editing.
    192193%----------------------------------------------------------------------
     194\begin{sloppypar}
     195
    193196\input{intro}
    194197\input{background}
     
    197200\input{performance}
    198201\input{conclusion}
     202
     203\end{sloppypar}
    199204
    200205%----------------------------------------------------------------------
  • doc/theses/thierry_delisle_PhD/.gitignore

    r94647b0 r7770cc8  
    1313comp_II/presentation.pdf
    1414
     15seminars/build/
     16seminars/img/*.fig.bak
     17seminars/*.pdf
     18
    1519thesis/build/
    1620thesis/fig/*.fig.bak
  • doc/theses/thierry_delisle_PhD/thesis/Makefile

    r94647b0 r7770cc8  
    2020        practice \
    2121        io \
     22        eval_micro \
     23        eval_macro \
    2224}}
    2325
     
    3537        pivot_ring \
    3638        system \
     39        cycle \
    3740}
    3841
  • doc/theses/thierry_delisle_PhD/thesis/thesis.tex

    r94647b0 r7770cc8  
    11%======================================================================
    2 % University of Waterloo Thesis Template for LaTeX 
    3 % Last Updated November, 2020 
    4 % by Stephen Carr, IST Client Services, 
     2% University of Waterloo Thesis Template for LaTeX
     3% Last Updated November, 2020
     4% by Stephen Carr, IST Client Services,
    55% University of Waterloo, 200 University Ave. W., Waterloo, Ontario, Canada
    66% FOR ASSISTANCE, please send mail to request@uwaterloo.ca
     
    1515% Some important notes on using this template and making it your own...
    1616
    17 % The University of Waterloo has required electronic thesis submission since October 2006. 
     17% The University of Waterloo has required electronic thesis submission since October 2006.
    1818% See the uWaterloo thesis regulations at
    1919% https://uwaterloo.ca/graduate-studies/thesis.
    2020% This thesis template is geared towards generating a PDF version optimized for viewing on an electronic display, including hyperlinks within the PDF.
    2121
    22 % DON'T FORGET TO ADD YOUR OWN NAME AND TITLE in the "hyperref" package configuration below. 
     22% DON'T FORGET TO ADD YOUR OWN NAME AND TITLE in the "hyperref" package configuration below.
    2323% THIS INFORMATION GETS EMBEDDED IN THE PDF FINAL PDF DOCUMENT.
    2424% You can view the information if you view properties of the PDF document.
    2525
    26 % Many faculties/departments also require one or more printed copies. 
    27 % This template attempts to satisfy both types of output. 
     26% Many faculties/departments also require one or more printed copies.
     27% This template attempts to satisfy both types of output.
    2828% See additional notes below.
    2929% It is based on the standard "book" document class which provides all necessary sectioning structures and allows multi-part theses.
     
    3232
    3333% For people who prefer to install their own LaTeX distributions on their own computers, and process the source files manually, the following notes provide the sequence of tasks:
    34  
     34
    3535% E.g. to process a thesis called "mythesis.tex" based on this template, run:
    3636
    3737% pdflatex mythesis     -- first pass of the pdflatex processor
    3838% bibtex mythesis       -- generates bibliography from .bib data file(s)
    39 % makeindex         -- should be run only if an index is used 
     39% makeindex         -- should be run only if an index is used
    4040% pdflatex mythesis     -- fixes numbering in cross-references, bibliographic references, glossaries, index, etc.
    4141% pdflatex mythesis     -- it takes a couple of passes to completely process all cross-references
    4242
    4343% If you use the recommended LaTeX editor, Texmaker, you would open the mythesis.tex file, then click the PDFLaTeX button. Then run BibTeX (under the Tools menu).
    44 % Then click the PDFLaTeX button two more times. 
     44% Then click the PDFLaTeX button two more times.
    4545% If you have an index as well,you'll need to run MakeIndex from the Tools menu as well, before running pdflatex
    4646% the last two times.
     
    5151% Tip: Photographs should be cropped and compressed so as not to be too large.
    5252
    53 % To create a PDF output that is optimized for double-sided printing: 
     53% To create a PDF output that is optimized for double-sided printing:
    5454% 1) comment-out the \documentclass statement in the preamble below, and un-comment the second \documentclass line.
    5555% 2) change the value assigned below to the boolean variable "PrintVersion" from " false" to "true".
     
    6767% If you have to, it's easier to make changes to nomenclature once here than in a million places throughout your thesis!
    6868\newcommand{\package}[1]{\textbf{#1}} % package names in bold text
    69 \newcommand{\cmmd}[1]{\textbackslash\texttt{#1}} % command name in tt font 
     69\newcommand{\cmmd}[1]{\textbackslash\texttt{#1}} % command name in tt font
    7070\newcommand{\href}[1]{#1} % does nothing, but defines the command so the print-optimized version will ignore \href tags (redefined by hyperref pkg).
    7171%\newcommand{\texorpdfstring}[2]{#1} % does nothing, but defines the command
     
    235235\part{Evaluation}
    236236\label{Evaluation}
    237 \chapter{Theoretical and Existance Proofs}
    238 \chapter{Micro-Benchmarks}
    239 \chapter{Larger-Scale applications}
     237% \chapter{Theoretical and Existance Proofs}
     238\input{text/eval_micro.tex}
     239\input{text/eval_macro.tex}
    240240\part{Conclusion \& Annexes}
    241241
  • doc/user/user.tex

    r94647b0 r7770cc8  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon May 31 09:03:34 2021
    14 %% Update Count     : 5071
     13%% Last Modified On : Sun Oct 10 12:45:00 2021
     14%% Update Count     : 5095
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    44444444\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.
    44454445
    4446 The 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:
    4447 \begin{cfa}
    4448 $\emph{thread\(_1\)}$ : sout | ®acquire® | "abc " | "def ";   // manipulator
    4449 $\emph{thread\(_2\)}$ : sout | ®acquire® | "uvw " | "xyz ";
     4446The common usage is the short form of the mutex statement\index{ostream@©ostream©!mutex@©mutex©} to lock a stream during a single cascaded I/O expression, \eg:
     4447\begin{cfa}
     4448$\emph{thread\(_1\)}$ : ®mutex()® sout | "abc " | "def ";
     4449$\emph{thread\(_2\)}$ : ®mutex()® sout | "uvw " | "xyz ";
    44504450\end{cfa}
    44514451Now, the order of the thread execution is still non-deterministic, but the output is constrained to two possible lines in either order.
     
    44664466In 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.
    44674467
    4468 To 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:
    4469 \begin{cfa}
    4470 {       // acquire sout for block duration
    4471         ®osacquire® acq = { sout };                             $\C{// named stream locker}$
     4468To lock a stream across multiple I/O operations, he long form of the mutex statement is used, \eg:
     4469\begin{cfa}
     4470®mutex( sout )® {
    44724471        sout | 1;
    4473         sout | ®acquire® | 2 | 3;                               $\C{// unnecessary, but ok to acquire and release again}$
     4472        ®mutex() sout® | 2 | 3;                         $\C{// unnecessary, but ok because of recursive lock}$
    44744473        sout | 4;
    4475 }       // implicitly release the lock when "acq" is deallocated
    4476 \end{cfa}
    4477 Note, the unnecessary ©acquire© manipulator works because the recursive stream-lock can be acquired/released multiple times by the owner thread.
     4474} // implicitly release sout lock
     4475\end{cfa}
     4476Note, the unnecessary ©mutex© in the middle of the mutex statement, works because the recursive stream-lock can be acquired/released multiple times by the owner thread.
    44784477Hence, calls to functions that also acquire a stream lock for their output do not result in \Index{deadlock}.
    44794478
    44804479The previous values written by threads 1 and 2 can be read in concurrently:
    44814480\begin{cfa}
    4482 {       // acquire sin lock for block duration
    4483         ®isacquire acq = { sin };®                              $\C{// named stream locker}$
     4481®mutex( sin )® {
    44844482        int x, y, z, w;
    44854483        sin | x;
    4486         sin | ®acquire® | y | z;                                $\C{// unnecessary, but ok to acquire and release again}$
     4484        ®mutex() sin® | y | z;                          $\C{// unnecessary, but ok because of recursive lock}$
    44874485        sin | w;
    4488 }       // implicitly release the lock when "acq" is deallocated
     4486} // implicitly release sin lock
    44894487\end{cfa}
    44904488Again, the order of the reading threads is non-deterministic.
     
    44934491\Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg:
    44944492\begin{cfa}
    4495 sout | ®acquire® | "data:" | rtn( mon );        $\C{// mutex call on monitor}$
     4493®mutex() sout® | "data:" | rtn( mon );  $\C{// mutex call on monitor}$
    44964494\end{cfa}
    44974495If 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.
     
    45004498\begin{cfa}
    45014499int ®data® = rtn( mon );
    4502 sout | acquire | "data:" | ®data®;
     4500mutex() sout | "data:" | ®data®;
    45034501\end{cfa}
    45044502
     
    45064504\section{String Stream}
    45074505
    4508 All the stream formatting capabilities are available to format text to/from a C string rather than to a stream file.
    4509 \VRef[Figure]{f:StringStreamProcessing} shows writing (output) and reading (input) from a C string.
     4506The stream types ©ostrstream© and ©istrstream© provide all the stream formatting capabilities to/from a C string rather than a stream file.
     4507\VRef[Figure]{f:StringStreamProcessing} shows writing (output) to and reading (input) from a C string.
     4508The only string stream operations different from a file stream are:
     4509\begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
     4510\item
     4511constructors to create a stream that writes to a write buffer (©ostrstream©) of ©size©, or reads from a read buffer (©istrstream©) containing a C string terminated with ©'\0'©.
     4512\begin{cfa}
     4513void ?{}( ostrstream &, char buf[], size_t size );
     4514void ?{}( istrstream & is, char buf[] );
     4515\end{cfa}
     4516\item
     4517\Indexc{write} (©ostrstream© only) writes all the buffered characters to the specified stream (©stdout© default).
     4518\begin{cfa}
     4519ostrstream & write( ostrstream & os, FILE * stream = stdout );
     4520\end{cfa}
     4521There is no ©read© for ©istrstream©.
     4522\end{itemize}
     4523
    45104524\begin{figure}
    45114525\begin{cfa}
     
    45204534        double x = 12345678.9, y = 98765.4321e-11;
    45214535
    4522         osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)); $\C{// same lines of output}$
    4523         write( osstr );
    4524         printf( "%s", buf );
    4525         sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y));
    4526 
    4527         char buf2[] = "12 14 15 3.5 7e4"; $\C{// input buffer}$
     4536        osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc";
     4537        write( osstr ); $\C{// write string to stdout}$
     4538        printf( "%s", buf ); $\C{// same lines of output}$
     4539        sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc";
     4540
     4541        char buf2[] = "12 14 15 3.5 7e4 abc"; $\C{// input buffer}$
    45284542        ®istrstream isstr = { buf2 };®
    4529         isstr | i | j | k | x | y;
    4530         sout | i | j | k | x | y;
    4531 }
     4543        char s[10];
     4544        isstr | i | j | k | x | y | s;
     4545        sout  | i | j | k | x | y | s;
     4546}
     4547
     45483 0x5          7 1.234568e+07 987.654n abc
     45493 0x5          7 1.234568e+07 987.654n abc
     45503 0x5          7 1.234568e+07 987.654n abc
     455112 14 15 3.5 70000. abc
    45324552\end{cfa}
    45334553\caption{String Stream Processing}
    45344554\label{f:StringStreamProcessing}
    45354555\end{figure}
    4536 
    4537 \VRef[Figure]{f:StringStreamFunctions} shows the string stream operations.
    4538 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
    4539 \item
    4540 \Indexc{write} (©ostrstream© only) writes all the buffered characters to the specified stream (©stdout© default).
    4541 \end{itemize}
    4542 The constructor functions:
    4543 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
    4544 \item
    4545 create a bound stream to a write buffer (©ostrstream©) of ©size© or a read buffer (©istrstream©) containing a C string terminated with ©'\0'©.
    4546 \end{itemize}
    4547 
    4548 \begin{figure}
    4549 \begin{cfa}
    4550 // *********************************** ostrstream ***********************************
    4551 
    4552 ostrstream & write( ostrstream & os, FILE * stream = stdout );
    4553 
    4554 void ?{}( ostrstream &, char buf[], size_t size );
    4555 
    4556 // *********************************** istrstream ***********************************
    4557 
    4558 void ?{}( istrstream & is, char buf[] );
    4559 \end{cfa}
    4560 \caption{String Stream Functions}
    4561 \label{f:StringStreamFunctions}
    4562 \end{figure}
    4563 
    45644556
    45654557\begin{comment}
  • libcfa/prelude/bootloader.cf

    r94647b0 r7770cc8  
    33char ** cfa_args_argv;
    44char ** cfa_args_envp;
    5 int cfa_main_returned = 0;
     5__attribute__((weak)) extern int cfa_main_returned;
    66
    77int main(int argc, char* argv[], char* envp[]) {
     
    1010        cfa_args_envp = envp;
    1111        int ret = invoke_main(argc, argv, envp);
    12         cfa_main_returned = 1;
     12        if(&cfa_main_returned) cfa_main_returned = 1;
    1313        return ret;
    1414}
  • libcfa/src/concurrency/io.cfa

    r94647b0 r7770cc8  
    133133        }
    134134
    135         void __cfa_io_flush( processor * proc ) {
     135        bool __cfa_io_flush( processor * proc, bool wait ) {
    136136                /* paranoid */ verify( ! __preemption_enabled() );
    137137                /* paranoid */ verify( proc );
     
    141141                $io_context & ctx = *proc->io.ctx;
    142142
    143                 // for(i; 2) {
    144                 //      unsigned idx = proc->rdq.id + i;
    145                 //      cltr->ready_queue.lanes.tscs[idx].tv = -1ull;
    146                 // }
    147 
    148143                __ioarbiter_flush( ctx );
    149144
    150145                __STATS__( true, io.calls.flush++; )
    151                 int ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, 0, 0, (sigset_t *)0p, _NSIG / 8);
     146                int ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, wait ? 1 : 0, 0, (sigset_t *)0p, _NSIG / 8);
    152147                if( ret < 0 ) {
    153148                        switch((int)errno) {
     
    157152                                // Update statistics
    158153                                __STATS__( false, io.calls.errors.busy ++; )
    159                                 // for(i; 2) {
    160                                 //      unsigned idx = proc->rdq.id + i;
    161                                 //      cltr->ready_queue.lanes.tscs[idx].tv = rdtscl();
    162                                 // }
    163                                 return;
     154                                return false;
    164155                        default:
    165156                                abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) );
     
    182173
    183174                ctx.proc->io.pending = false;
    184 
    185175                ready_schedule_lock();
    186                 __cfa_io_drain( proc );
     176                bool ret = __cfa_io_drain( proc );
    187177                ready_schedule_unlock();
    188                 // for(i; 2) {
    189                 //      unsigned idx = proc->rdq.id + i;
    190                 //      cltr->ready_queue.lanes.tscs[idx].tv = rdtscl();
    191                 // }
     178                return ret;
    192179        }
    193180
     
    293280        }
    294281
    295 
    296282        //=============================================================================================
    297283        // submission
     
    311297                // Make the sqes visible to the submitter
    312298                __atomic_store_n(sq.kring.tail, tail + have, __ATOMIC_RELEASE);
    313                 sq.to_submit++;
     299                sq.to_submit += have;
    314300
    315301                ctx->proc->io.pending = true;
    316302                ctx->proc->io.dirty   = true;
    317303                if(sq.to_submit > 30 || !lazy) {
    318                         __cfa_io_flush( ctx->proc );
     304                        __cfa_io_flush( ctx->proc, false );
    319305                }
    320306        }
     
    515501                }
    516502        }
     503
     504        #if defined(IO_URING_IDLE)
     505                bool __kernel_read(processor * proc, io_future_t & future, char buf[], int fd) {
     506                        $io_context * ctx = proc->io.ctx;
     507                        /* paranoid */ verify( ! __preemption_enabled() );
     508                        /* paranoid */ verify( proc == __cfaabi_tls.this_processor );
     509                        /* paranoid */ verify( ctx );
     510
     511                        __u32 idx;
     512                        struct io_uring_sqe * sqe;
     513
     514                        // We can proceed to the fast path
     515                        if( !__alloc(ctx, &idx, 1) ) return false;
     516
     517                        // Allocation was successful
     518                        __fill( &sqe, 1, &idx, ctx );
     519
     520                        sqe->opcode = IORING_OP_READ;
     521                        sqe->user_data = (uintptr_t)&future;
     522                        sqe->flags = 0;
     523                        sqe->ioprio = 0;
     524                        sqe->fd = 0;
     525                        sqe->off = 0;
     526                        sqe->fsync_flags = 0;
     527                        sqe->__pad2[0] = 0;
     528                        sqe->__pad2[1] = 0;
     529                        sqe->__pad2[2] = 0;
     530                        sqe->addr = (uintptr_t)buf;
     531                        sqe->len = sizeof(uint64_t);
     532
     533                        asm volatile("": : :"memory");
     534
     535                        /* paranoid */ verify( sqe->user_data == (uintptr_t)&future );
     536                        __submit( ctx, &idx, 1, true );
     537
     538                        /* paranoid */ verify( proc == __cfaabi_tls.this_processor );
     539                        /* paranoid */ verify( ! __preemption_enabled() );
     540                }
     541        #endif
    517542#endif
  • libcfa/src/concurrency/io/setup.cfa

    r94647b0 r7770cc8  
    3232
    3333        void __cfa_io_start( processor * proc ) {}
    34         void __cfa_io_flush( processor * proc ) {}
     34        bool __cfa_io_flush( processor * proc, bool ) {}
    3535        void __cfa_io_stop ( processor * proc ) {}
    3636
     
    111111                this.ext_sq.empty = true;
    112112                (this.ext_sq.queue){};
    113                 __io_uring_setup( this, cl.io.params, proc->idle );
     113                __io_uring_setup( this, cl.io.params, proc->idle_fd );
    114114                __cfadbg_print_safe(io_core, "Kernel I/O : Created ring for io_context %u (%p)\n", this.fd, &this);
    115115        }
     
    220220                cq.cqes = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes);
    221221
    222                 // Step 4 : eventfd
    223                 // io_uring_register is so f*cking slow on some machine that it
    224                 // 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 
    227                 __disable_interrupts_hard();
    228 
    229                 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1);
    230                 if (ret < 0) {
    231                         abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno));
    232                 }
    233 
    234                 __enable_interrupts_hard();
    235 
    236                 __cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd);
     222                #if !defined(IO_URING_IDLE)
     223                        // Step 4 : eventfd
     224                        // io_uring_register is so f*cking slow on some machine that it
     225                        // will never succeed if preemption isn't hard blocked
     226                        __cfadbg_print_safe(io_core, "Kernel I/O : registering %d for completion with ring %d\n", procfd, fd);
     227
     228                        __disable_interrupts_hard();
     229
     230                        int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1);
     231                        if (ret < 0) {
     232                                abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno));
     233                        }
     234
     235                        __enable_interrupts_hard();
     236
     237                        __cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd);
     238                #endif
    237239
    238240                // some paranoid checks
  • libcfa/src/concurrency/io/types.hfa

    r94647b0 r7770cc8  
    185185
    186186        // Wait for the future to be fulfilled
    187         bool wait( io_future_t & this ) {
    188                 return wait(this.self);
    189         }
     187        bool wait     ( io_future_t & this ) { return wait     (this.self); }
     188        void reset    ( io_future_t & this ) { return reset    (this.self); }
     189        bool available( io_future_t & this ) { return available(this.self); }
    190190}
  • libcfa/src/concurrency/kernel.cfa

    r94647b0 r7770cc8  
    3434#include "strstream.hfa"
    3535#include "device/cpu.hfa"
     36#include "io/types.hfa"
    3637
    3738//Private includes
     
    124125static void __wake_one(cluster * cltr);
    125126
    126 static void mark_idle (__cluster_proc_list & idles, processor & proc);
     127static void idle_sleep(processor * proc, io_future_t & future, char buf[]);
     128static bool mark_idle (__cluster_proc_list & idles, processor & proc);
    127129static void mark_awake(__cluster_proc_list & idles, processor & proc);
    128 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list idles );
    129130
    130131extern void __cfa_io_start( processor * );
    131132extern bool __cfa_io_drain( processor * );
    132 extern void __cfa_io_flush( processor * );
     133extern bool __cfa_io_flush( processor *, bool wait );
    133134extern void __cfa_io_stop ( processor * );
    134135static inline bool __maybe_io_drain( processor * );
     136
     137#if defined(IO_URING_IDLE) && defined(CFA_HAVE_LINUX_IO_URING_H)
     138        extern bool __kernel_read(processor * proc, io_future_t & future, char buf[], int fd);
     139#endif
    135140
    136141extern void __disable_interrupts_hard();
     
    148153        /* paranoid */ verify( __preemption_enabled() );
    149154}
     155
    150156
    151157//=============================================================================================
     
    163169        verify(this);
    164170
     171        io_future_t future; // used for idle sleep when io_uring is present
     172        future.self.ptr = 1p;  // mark it as already fulfilled so we know if there is a pending request or not
     173        char buf[sizeof(uint64_t)];
     174
    165175        __cfa_io_start( this );
    166176
     
    196206
    197207                        if( !readyThread ) {
    198                                 __cfa_io_flush( this );
     208                                __cfa_io_flush( this, false );
     209
    199210                                readyThread = __next_thread_slow( this->cltr );
    200211                        }
     
    210221
    211222                                // Push self to idle stack
    212                                 mark_idle(this->cltr->procs, * this);
     223                                if(!mark_idle(this->cltr->procs, * this)) continue MAIN_LOOP;
    213224
    214225                                // Confirm the ready-queue is empty
     
    226237                                }
    227238
    228                                 #if !defined(__CFA_NO_STATISTICS__)
    229                                         if(this->print_halts) {
    230                                                 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl());
     239                                idle_sleep( this, future, buf );
     240
     241                                // We were woken up, remove self from idle
     242                                mark_awake(this->cltr->procs, * this);
     243
     244                                // DON'T just proceed, start looking again
     245                                continue MAIN_LOOP;
     246                        }
     247
     248                        /* paranoid */ verify( readyThread );
     249
     250                        // Reset io dirty bit
     251                        this->io.dirty = false;
     252
     253                        // We found a thread run it
     254                        __run_thread(this, readyThread);
     255
     256                        // Are we done?
     257                        if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     258
     259                        if(this->io.pending && !this->io.dirty) {
     260                                __cfa_io_flush( this, false );
     261                        }
     262
     263                        #else
     264                                #warning new kernel loop
     265                        SEARCH: {
     266                                /* paranoid */ verify( ! __preemption_enabled() );
     267
     268                                // First, lock the scheduler since we are searching for a thread
     269                                ready_schedule_lock();
     270
     271                                // Try to get the next thread
     272                                readyThread = pop_fast( this->cltr );
     273                                if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     274
     275                                // If we can't find a thread, might as well flush any outstanding I/O
     276                                if(this->io.pending) { __cfa_io_flush( this, false ); }
     277
     278                                // Spin a little on I/O, just in case
     279                                for(5) {
     280                                        __maybe_io_drain( this );
     281                                        readyThread = pop_fast( this->cltr );
     282                                        if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     283                                }
     284
     285                                // no luck, try stealing a few times
     286                                for(5) {
     287                                        if( __maybe_io_drain( this ) ) {
     288                                                readyThread = pop_fast( this->cltr );
     289                                        } else {
     290                                                readyThread = pop_slow( this->cltr );
    231291                                        }
    232                                 #endif
    233 
    234                                 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
     292                                        if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     293                                }
     294
     295                                // still no luck, search for a thread
     296                                readyThread = pop_search( this->cltr );
     297                                if(readyThread) { ready_schedule_unlock(); break SEARCH; }
     298
     299                                // Don't block if we are done
     300                                if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) {
     301                                        ready_schedule_unlock();
     302                                        break MAIN_LOOP;
     303                                }
     304
     305                                __STATS( __tls_stats()->ready.sleep.halts++; )
     306
     307                                // Push self to idle stack
     308                                ready_schedule_unlock();
     309                                if(!mark_idle(this->cltr->procs, * this)) goto SEARCH;
     310                                ready_schedule_lock();
     311
     312                                // Confirm the ready-queue is empty
     313                                __maybe_io_drain( this );
     314                                readyThread = pop_search( this->cltr );
     315                                ready_schedule_unlock();
     316
     317                                if( readyThread ) {
     318                                        // A thread was found, cancel the halt
     319                                        mark_awake(this->cltr->procs, * this);
     320
     321                                        __STATS( __tls_stats()->ready.sleep.cancels++; )
     322
     323                                        // continue the main loop
     324                                        break SEARCH;
     325                                }
     326
     327                                __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )
     328                                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd);
    235329
    236330                                {
    237331                                        eventfd_t val;
    238                                         ssize_t ret = read( this->idle, &val, sizeof(val) );
     332                                        ssize_t ret = read( this->idle_fd, &val, sizeof(val) );
    239333                                        if(ret < 0) {
    240334                                                switch((int)errno) {
     
    252346                                }
    253347
    254                                 #if !defined(__CFA_NO_STATISTICS__)
    255                                         if(this->print_halts) {
    256                                                 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl());
    257                                         }
    258                                 #endif
     348                                        __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); )
    259349
    260350                                // We were woken up, remove self from idle
     
    265355                        }
    266356
    267                         /* paranoid */ verify( readyThread );
    268 
    269                         // Reset io dirty bit
    270                         this->io.dirty = false;
    271 
    272                         // We found a thread run it
    273                         __run_thread(this, readyThread);
    274 
    275                         // Are we done?
    276                         if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    277 
    278                         if(this->io.pending && !this->io.dirty) {
    279                                 __cfa_io_flush( this );
    280                         }
    281 
    282                         #else
    283                                 #warning new kernel loop
    284                         SEARCH: {
    285                                 /* paranoid */ verify( ! __preemption_enabled() );
    286 
    287                                 // First, lock the scheduler since we are searching for a thread
    288                                 ready_schedule_lock();
    289 
    290                                 // Try to get the next thread
    291                                 readyThread = pop_fast( this->cltr );
    292                                 if(readyThread) { ready_schedule_unlock(); break SEARCH; }
    293 
    294                                 // If we can't find a thread, might as well flush any outstanding I/O
    295                                 if(this->io.pending) { __cfa_io_flush( this ); }
    296 
    297                                 // Spin a little on I/O, just in case
    298                                 for(5) {
    299                                         __maybe_io_drain( this );
    300                                         readyThread = pop_fast( this->cltr );
    301                                         if(readyThread) { ready_schedule_unlock(); break SEARCH; }
    302                                 }
    303 
    304                                 // no luck, try stealing a few times
    305                                 for(5) {
    306                                         if( __maybe_io_drain( this ) ) {
    307                                                 readyThread = pop_fast( this->cltr );
    308                                         } else {
    309                                                 readyThread = pop_slow( this->cltr );
    310                                         }
    311                                         if(readyThread) { ready_schedule_unlock(); break SEARCH; }
    312                                 }
    313 
    314                                 // still no luck, search for a thread
    315                                 readyThread = pop_search( this->cltr );
    316                                 if(readyThread) { ready_schedule_unlock(); break SEARCH; }
    317 
    318                                 // Don't block if we are done
    319                                 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    320 
    321                                 __STATS( __tls_stats()->ready.sleep.halts++; )
    322 
    323                                 // Push self to idle stack
    324                                 ready_schedule_unlock();
    325                                 mark_idle(this->cltr->procs, * this);
    326                                 ready_schedule_lock();
    327 
    328                                 // Confirm the ready-queue is empty
    329                                 __maybe_io_drain( this );
    330                                 readyThread = pop_search( this->cltr );
    331                                 ready_schedule_unlock();
    332 
    333                                 if( readyThread ) {
    334                                         // A thread was found, cancel the halt
    335                                         mark_awake(this->cltr->procs, * this);
    336 
    337                                         __STATS( __tls_stats()->ready.sleep.cancels++; )
    338 
    339                                         // continue the main loop
    340                                         break SEARCH;
    341                                 }
    342 
    343                                 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )
    344                                 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
    345 
    346                                 {
    347                                         eventfd_t val;
    348                                         ssize_t ret = read( this->idle, &val, sizeof(val) );
    349                                         if(ret < 0) {
    350                                                 switch((int)errno) {
    351                                                 case EAGAIN:
    352                                                 #if EAGAIN != EWOULDBLOCK
    353                                                         case EWOULDBLOCK:
    354                                                 #endif
    355                                                 case EINTR:
    356                                                         // No need to do anything special here, just assume it's a legitimate wake-up
    357                                                         break;
    358                                                 default:
    359                                                         abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
    360                                                 }
    361                                         }
    362                                 }
    363 
    364                                         __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); )
    365 
    366                                 // We were woken up, remove self from idle
    367                                 mark_awake(this->cltr->procs, * this);
    368 
    369                                 // DON'T just proceed, start looking again
    370                                 continue MAIN_LOOP;
    371                         }
    372 
    373357                RUN_THREAD:
    374358                        /* paranoid */ verify( ! __preemption_enabled() );
     
    385369
    386370                        if(this->io.pending && !this->io.dirty) {
    387                                 __cfa_io_flush( this );
     371                                __cfa_io_flush( this, false );
    388372                        }
    389373
     
    758742
    759743        // Check if there is a sleeping processor
    760         processor * p;
    761         unsigned idle;
    762         unsigned total;
    763         [idle, total, p] = query_idles(this->procs);
     744        int fd = __atomic_load_n(&this->procs.fd, __ATOMIC_SEQ_CST);
    764745
    765746        // If no one is sleeping, we are done
    766         if( idle == 0 ) return;
     747        if( fd == 0 ) return;
    767748
    768749        // We found a processor, wake it up
    769750        eventfd_t val;
    770751        val = 1;
    771         eventfd_write( p->idle, val );
     752        eventfd_write( fd, val );
    772753
    773754        #if !defined(__CFA_NO_STATISTICS__)
     
    794775                eventfd_t val;
    795776                val = 1;
    796                 eventfd_write( this->idle, val );
     777                eventfd_write( this->idle_fd, val );
    797778        __enable_interrupts_checked();
    798779}
    799780
    800 static void mark_idle(__cluster_proc_list & this, processor & proc) {
    801         /* paranoid */ verify( ! __preemption_enabled() );
    802         lock( this );
     781static void idle_sleep(processor * this, io_future_t & future, char buf[]) {
     782        #if !defined(IO_URING_IDLE) || !defined(CFA_HAVE_LINUX_IO_URING_H)
     783                #if !defined(__CFA_NO_STATISTICS__)
     784                        if(this->print_halts) {
     785                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl());
     786                        }
     787                #endif
     788
     789                __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd);
     790
     791                {
     792                        eventfd_t val;
     793                        ssize_t ret = read( this->idle_fd, &val, sizeof(val) );
     794                        if(ret < 0) {
     795                                switch((int)errno) {
     796                                case EAGAIN:
     797                                #if EAGAIN != EWOULDBLOCK
     798                                        case EWOULDBLOCK:
     799                                #endif
     800                                case EINTR:
     801                                        // No need to do anything special here, just assume it's a legitimate wake-up
     802                                        break;
     803                                default:
     804                                        abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );
     805                                }
     806                        }
     807                }
     808
     809                #if !defined(__CFA_NO_STATISTICS__)
     810                        if(this->print_halts) {
     811                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl());
     812                        }
     813                #endif
     814        #else
     815                #if !defined(CFA_HAVE_IORING_OP_READ)
     816                        #error this is only implemented if the read is present
     817                #endif
     818                // Do we already have a pending read
     819                if(available(future)) {
     820                        // There is no pending read, we need to add one
     821                        reset(future);
     822
     823                        __kernel_read(this, future, buf, this->idle_fd );
     824                }
     825
     826                __cfa_io_flush( this, true );
     827        #endif
     828}
     829
     830static bool mark_idle(__cluster_proc_list & this, processor & proc) {
     831        /* paranoid */ verify( ! __preemption_enabled() );
     832        if(!try_lock( this )) return false;
    803833                this.idle++;
    804834                /* paranoid */ verify( this.idle <= this.total );
    805835                remove(proc);
    806836                insert_first(this.idles, proc);
     837
     838                __atomic_store_n(&this.fd, proc.idle_fd, __ATOMIC_SEQ_CST);
    807839        unlock( this );
    808840        /* paranoid */ verify( ! __preemption_enabled() );
     841
     842        return true;
    809843}
    810844
     
    816850                remove(proc);
    817851                insert_last(this.actives, proc);
     852
     853                {
     854                        int fd = 0;
     855                        if(!this.idles`isEmpty) fd = this.idles`first.idle_fd;
     856                        __atomic_store_n(&this.fd, fd, __ATOMIC_SEQ_CST);
     857                }
     858
    818859        unlock( this );
    819         /* paranoid */ verify( ! __preemption_enabled() );
    820 }
    821 
    822 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list this ) {
    823         /* paranoid */ verify( ! __preemption_enabled() );
    824         /* paranoid */ verify( ready_schedule_islocked() );
    825 
    826         for() {
    827                 uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
    828                 if( 1 == (l % 2) ) { Pause(); continue; }
    829                 unsigned idle    = this.idle;
    830                 unsigned total   = this.total;
    831                 processor * proc = &this.idles`first;
    832                 // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it
    833                 asm volatile("": : :"memory");
    834                 if(l != __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST)) { Pause(); continue; }
    835                 return [idle, total, proc];
    836         }
    837 
    838         /* paranoid */ verify( ready_schedule_islocked() );
    839860        /* paranoid */ verify( ! __preemption_enabled() );
    840861}
     
    898919                if(head == tail) return false;
    899920                #if OLD_MAIN
    900                 ready_schedule_lock();
    901                 ret = __cfa_io_drain( proc );
    902                 ready_schedule_unlock();
     921                        ready_schedule_lock();
     922                        ret = __cfa_io_drain( proc );
     923                        ready_schedule_unlock();
    903924                #else
    904925                        ret = __cfa_io_drain( proc );
    905         #endif
     926                #endif
    906927        #endif
    907928        return ret;
     
    939960                        /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
    940961                        /* paranoid */ verify( it->local_data->this_stats );
     962                        // __print_stats( it->local_data->this_stats, cltr->print_stats, "Processor", it->name, (void*)it );
    941963                        __tally_stats( cltr->stats, it->local_data->this_stats );
    942964                        it = &(*it)`next;
     
    948970                // this doesn't solve all problems but does solve many
    949971                // so it's probably good enough
     972                disable_interrupts();
    950973                uint_fast32_t last_size = ready_mutate_lock();
    951974
     
    955978                // Unlock the RWlock
    956979                ready_mutate_unlock( last_size );
     980                enable_interrupts();
    957981        }
    958982
  • libcfa/src/concurrency/kernel.hfa

    r94647b0 r7770cc8  
    100100
    101101        // Idle lock (kernel semaphore)
    102         int idle;
     102        int idle_fd;
    103103
    104104        // Termination synchronisation (user semaphore)
     
    195195struct __cluster_proc_list {
    196196        // Spin lock protecting the queue
    197         volatile uint64_t lock;
     197        __spinlock_t lock;
     198
     199        // FD to use to wake a processor
     200        volatile int fd;
    198201
    199202        // Total number of processors
  • libcfa/src/concurrency/kernel/startup.cfa

    r94647b0 r7770cc8  
    100100// Other Forward Declarations
    101101extern void __wake_proc(processor *);
     102extern int cfa_main_returned;                                                   // from interpose.cfa
    102103
    103104//-----------------------------------------------------------------------------
     
    268269
    269270static void __kernel_shutdown(void) {
     271        if(!cfa_main_returned) return;
    270272        /* paranoid */ verify( __preemption_enabled() );
    271273        disable_interrupts();
     
    525527        this.local_data = 0p;
    526528
    527         this.idle = eventfd(0, 0);
    528         if (idle < 0) {
     529        this.idle_fd = eventfd(0, 0);
     530        if (idle_fd < 0) {
    529531                abort("KERNEL ERROR: PROCESSOR EVENTFD - %s\n", strerror(errno));
    530532        }
     
    540542// Not a ctor, it just preps the destruction but should not destroy members
    541543static void deinit(processor & this) {
    542         close(this.idle);
     544        close(this.idle_fd);
    543545}
    544546
     
    582584// Cluster
    583585static void ?{}(__cluster_proc_list & this) {
    584         this.lock  = 0;
     586        this.fd    = 0;
    585587        this.idle  = 0;
    586588        this.total = 0;
  • libcfa/src/concurrency/kernel_private.hfa

    r94647b0 r7770cc8  
    3939}
    4040
     41// #define IO_URING_IDLE
     42
    4143//-----------------------------------------------------------------------------
    4244// Scheduler
     
    149151        __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE);
    150152}
    151 
    152 
    153 
    154 
    155153
    156154//-----------------------------------------------------------------------
     
    268266        ready_schedule_lock();
    269267
    270         // Simple counting lock, acquired, acquired by incrementing the counter
    271         // to an odd number
    272         for() {
    273                 uint64_t l = this.lock;
    274                 if(
    275                         (0 == (l % 2))
    276                         && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
    277                 ) return;
    278                 Pause();
    279         }
    280 
    281         /* paranoid */ verify( ! __preemption_enabled() );
     268        lock( this.lock __cfaabi_dbg_ctx2 );
     269
     270        /* paranoid */ verify( ! __preemption_enabled() );
     271}
     272
     273static inline bool try_lock(__cluster_proc_list & this) {
     274        /* paranoid */ verify( ! __preemption_enabled() );
     275
     276        // Start by locking the global RWlock so that we know no-one is
     277        // adding/removing processors while we mess with the idle lock
     278        ready_schedule_lock();
     279
     280        if(try_lock( this.lock __cfaabi_dbg_ctx2 )) {
     281                // success
     282                /* paranoid */ verify( ! __preemption_enabled() );
     283                return true;
     284        }
     285
     286        // failed to lock
     287        ready_schedule_unlock();
     288
     289        /* paranoid */ verify( ! __preemption_enabled() );
     290        return false;
    282291}
    283292
     
    285294        /* paranoid */ verify( ! __preemption_enabled() );
    286295
    287         /* paranoid */ verify( 1 == (this.lock % 2) );
    288         // Simple couting lock, release by incrementing to an even number
    289         __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
     296        unlock(this.lock);
    290297
    291298        // Release the global lock, which we acquired when locking
  • libcfa/src/concurrency/monitor.hfa

    r94647b0 r7770cc8  
    6565        free( th );
    6666}
     67
     68static inline forall( T & | sized(T) | { void ^?{}( T & mutex ); } )
     69void adelete( T arr[] ) {
     70        if ( arr ) {                                                                            // ignore null
     71                size_t dim = malloc_size( arr ) / sizeof( T );
     72                for ( int i = dim - 1; i >= 0; i -= 1 ) {               // reverse allocation order, must be unsigned
     73                        ^(arr[i]){};                                                            // run destructor
     74                } // for
     75                free( arr );
     76        } // if
     77} // adelete
    6778
    6879//-----------------------------------------------------------------------------
  • libcfa/src/concurrency/mutex_stmt.hfa

    r94647b0 r7770cc8  
    11#include "bits/algorithm.hfa"
    2 #include <assert.h>
    3 #include "invoke.h"
    4 #include "stdlib.hfa"
    5 #include <stdio.h>
     2#include "bits/defs.hfa"
    63
    74//-----------------------------------------------------------------------------
  • libcfa/src/device/cpu.cfa

    r94647b0 r7770cc8  
    144144// Count number of cpus in the system
    145145static int count_cpus(void) {
    146         const char * fpath = "/sys/devices/system/cpu/present";
     146        const char * fpath = "/sys/devices/system/cpu/online";
    147147        int fd = open(fpath, 0, O_RDONLY);
    148148        /* paranoid */ verifyf(fd >= 0, "Could not open file %s", fpath);
  • libcfa/src/fstream.cfa

    r94647b0 r7770cc8  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Sep 21 21:51:38 2021
    13 // Update Count     : 460
     12// Last Modified On : Sun Oct 10 11:23:05 2021
     13// Update Count     : 512
    1414//
    1515
     
    2828#define IO_MSG "I/O error: "
    2929
    30 void ?{}( ofstream & os, void * file ) with(os) {
     30// private
     31void ?{}( ofstream & os, void * file ) with( os ) {
    3132        file$ = file;
    3233        sepDefault$ = true;
     
    3536        prt$ = false;
    3637        sawNL$ = false;
    37         acquired$ = false;
    3838        sepSetCur$( os, sepGet( os ) );
    3939        sepSet( os, " " );
     
    4141} // ?{}
    4242
    43 // private
    44 bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
    45 void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }
    46 void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
    47 const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }
    48 void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
    49 bool getNL$( ofstream & os ) { return os.sawNL$; }
    50 void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; }
    51 bool getANL$( ofstream & os ) { return os.nlOnOff$; }
    52 bool getPrt$( ofstream & os ) { return os.prt$; }
    53 void setPrt$( ofstream & os, bool state ) { os.prt$ = state; }
     43inline bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
     44inline void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }
     45inline void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
     46inline const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }
     47inline void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
     48inline bool getNL$( ofstream & os ) { return os.sawNL$; }
     49inline void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; }
     50inline bool getANL$( ofstream & os ) { return os.nlOnOff$; }
     51inline bool getPrt$( ofstream & os ) { return os.prt$; }
     52inline void setPrt$( ofstream & os, bool state ) { os.prt$ = state; }
     53
     54inline void lock( ofstream & os ) with( os ) {  lock( os.lock$ ); }
     55inline void unlock( ofstream & os ) { unlock( os.lock$ ); }
    5456
    5557// public
    5658void ?{}( ofstream & os ) { os.file$ = 0p; }
    57 
    58 void ?{}( ofstream & os, const char name[], const char mode[] ) {
    59         open( os, name, mode );
    60 } // ?{}
    61 
    62 void ?{}( ofstream & os, const char name[] ) {
    63         open( os, name, "w" );
    64 } // ?{}
    65 
    66 void ^?{}( ofstream & os ) {
    67         close( os );
    68 } // ^?{}
     59void ?{}( ofstream & os, const char name[], const char mode[] ) { open( os, name, mode ); }
     60void ?{}( ofstream & os, const char name[] ) { open( os, name, "w" ); }
     61void ^?{}( ofstream & os ) { close( os ); }
    6962
    7063void sepOn( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); }
     
    107100        if ( &os == &exit ) exit( EXIT_FAILURE );
    108101        if ( &os == &abort ) abort();
    109         if ( os.acquired$ ) { os.acquired$ = false; release( os ); }
    110102} // ends
    111103
    112 bool fail( ofstream & os ) {
    113         return os.file$ == 0 || ferror( (FILE *)(os.file$) );
    114 } // fail
    115 
    116 void clear( ofstream & os ) {
    117         clearerr( (FILE *)(os.file$) );
    118 } // clear
    119 
    120 int flush( ofstream & os ) {
    121         return fflush( (FILE *)(os.file$) );
    122 } // flush
     104bool fail( ofstream & os ) { return os.file$ == 0 || ferror( (FILE *)(os.file$) ); }
     105void clear( ofstream & os ) { clearerr( (FILE *)(os.file$) ); }
     106int flush( ofstream & os ) { return fflush( (FILE *)(os.file$) ); }
    123107
    124108void open( ofstream & os, const char name[], const char mode[] ) {
    125         FILE * file = fopen( name, mode );
     109        FILE * file;
     110    for ( cnt; 10 ) {
     111                errno = 0;
     112                file = fopen( name, mode );
     113          if ( file != 0p || errno != EINTR ) break;            // timer interrupt ?
     114          if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" );
     115    } // for
    126116        if ( file == 0p ) {
    127117                throw (Open_Failure){ os };
     
    131121} // open
    132122
    133 void open( ofstream & os, const char name[] ) {
    134         open( os, name, "w" );
    135 } // open
    136 
    137 void close( ofstream & os ) with(os) {
     123void open( ofstream & os, const char name[] ) { open( os, name, "w" ); }
     124
     125void close( ofstream & os ) with( os ) {
    138126  if ( (FILE *)(file$) == 0p ) return;
    139127  if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return;
    140128
    141         if ( fclose( (FILE *)(file$) ) == EOF ) {
     129        int ret;
     130    for ( cnt; 10 ) {
     131                errno = 0;
     132                ret = fclose( (FILE *)(file$) );
     133          if ( ret != EOF || errno != EINTR ) break;            // timer interrupt ?
     134          if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" );
     135    } // for
     136        if ( ret == EOF ) {
    142137                throw (Close_Failure){ os };
    143138                // abort | IO_MSG "close output" | nl | strerror( errno );
    144139        } // if
    145         file$ = 0p;
     140        file$ = 0p;                                                                                     // safety after close
    146141} // close
    147142
     
    162157        va_list args;
    163158        va_start( args, format );
    164         int len = vfprintf( (FILE *)(os.file$), format, args );
     159               
     160        int len;
     161    for ( cnt; 10 ) {
     162                errno = 0;
     163                len = vfprintf( (FILE *)(os.file$), format, args );
     164          if ( len != EOF || errno != EINTR ) break;            // timer interrupt ?
     165          if ( cnt == 9 ) abort( "ofstream fmt EINTR spinning exceeded" );
     166    } // for
    165167        if ( len == EOF ) {
    166168                if ( ferror( (FILE *)(os.file$) ) ) {
     
    175177} // fmt
    176178
    177 inline void acquire( ofstream & os ) with(os) {
    178         lock( lock$ );                                                                          // may increase recursive lock
    179         if ( ! acquired$ ) acquired$ = true;                            // not locked ?
    180         else unlock( lock$ );                                                           // unwind recursive lock at start
    181 } // acquire
    182 
    183 inline void release( ofstream & os ) {
    184         unlock( os.lock$ );
    185 } // release
    186 
    187 void ?{}( osacquire & acq, ofstream & os ) { lock( os.lock$ ); &acq.os = &os; }
    188 void ^?{}( osacquire & acq ) { release( acq.os ); }
    189 
    190179static ofstream soutFile = { (FILE *)stdout };
    191180ofstream & sout = soutFile, & stdout = soutFile;
     
    205194        flush( os );
    206195        return os;
    207         // (ofstream &)(os | '\n');
    208         // setPrt$( os, false );                                                        // turn off
    209         // setNL$( os, true );
    210         // flush( os );
    211         // return sepOff( os );                                                 // prepare for next line
    212196} // nl
    213197
     
    217201
    218202// private
    219 void ?{}( ifstream & is, void * file ) with(is) {
     203void ?{}( ifstream & is, void * file ) with( is ) {
    220204        file$ = file;
    221205        nlOnOff$ = false;
    222         acquired$ = false;
    223 } // ?{}
     206} // ?{}
     207
     208bool getANL$( ifstream & os ) { return os.nlOnOff$; }
     209
     210inline void lock( ifstream & os ) with( os ) { lock( os.lock$ ); }
     211inline void unlock( ifstream & os ) { unlock( os.lock$ ); }
    224212
    225213// public
    226214void ?{}( ifstream & is ) { is.file$ = 0p; }
    227 
    228 void ?{}( ifstream & is, const char name[], const char mode[] ) {
    229         open( is, name, mode );
    230 } // ?{}
    231 
    232 void ?{}( ifstream & is, const char name[] ) {
    233         open( is, name, "r" );
    234 } // ?{}
    235 
    236 void ^?{}( ifstream & is ) {
    237         close( is );
    238 } // ^?{}
     215void ?{}( ifstream & is, const char name[], const char mode[] ) { open( is, name, mode ); }
     216void ?{}( ifstream & is, const char name[] ) { open( is, name, "r" ); }
     217void ^?{}( ifstream & is ) { close( is ); }
     218
     219bool fail( ifstream & is ) { return is.file$ == 0p || ferror( (FILE *)(is.file$) ); }
     220void clear( ifstream & is ) { clearerr( (FILE *)(is.file$) ); }
    239221
    240222void nlOn( ifstream & os ) { os.nlOnOff$ = true; }
    241223void nlOff( ifstream & os ) { os.nlOnOff$ = false; }
    242 bool getANL( ifstream & os ) { return os.nlOnOff$; }
    243 
    244 bool fail( ifstream & is ) {
    245         return is.file$ == 0p || ferror( (FILE *)(is.file$) );
    246 } // fail
    247 
    248 void clear( ifstream & is ) {
    249         clearerr( (FILE *)(is.file$) );
    250 } // clear
    251 
    252 void ends( ifstream & is ) {
    253         if ( is.acquired$ ) { is.acquired$ = false; release( is ); }
    254 } // ends
    255 
    256 bool eof( ifstream & is ) {
    257         return feof( (FILE *)(is.file$) );
    258 } // eof
     224
     225void ends( ifstream & is ) {}
     226
     227bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; }
    259228
    260229void open( ifstream & is, const char name[], const char mode[] ) {
    261         FILE * file = fopen( name, mode );
     230        FILE * file;
     231    for ( cnt; 10 ) {
     232                errno = 0;
     233                file = fopen( name, mode );
     234          if ( file != 0p || errno != EINTR ) break;            // timer interrupt ?
     235          if ( cnt == 9 ) abort( "ifstream open EINTR spinning exceeded" );
     236    } // for
    262237        if ( file == 0p ) {
    263238                throw (Open_Failure){ is };
     
    267242} // open
    268243
    269 void open( ifstream & is, const char name[] ) {
    270         open( is, name, "r" );
    271 } // open
    272 
    273 void close( ifstream & is ) with(is) {
     244void open( ifstream & is, const char name[] ) { open( is, name, "r" ); }
     245
     246void close( ifstream & is ) with( is ) {
    274247  if ( (FILE *)(file$) == 0p ) return;
    275248  if ( (FILE *)(file$) == (FILE *)stdin ) return;
    276249
    277         if ( fclose( (FILE *)(file$) ) == EOF ) {
     250        int ret;
     251    for ( cnt; 10 ) {
     252                errno = 0;
     253                ret = fclose( (FILE *)(file$) );
     254          if ( ret != EOF || errno != EINTR ) break;            // timer interrupt ?
     255          if ( cnt == 9 ) abort( "ifstream close EINTR spinning exceeded" );
     256    } // for
     257        if ( ret == EOF ) {
    278258                throw (Close_Failure){ is };
    279259                // abort | IO_MSG "close input" | nl | strerror( errno );
    280260        } // if
    281         file$ = 0p;
     261        file$ = 0p;                                                                                     // safety after close
    282262} // close
    283263
     
    308288int fmt( ifstream & is, const char format[], ... ) {
    309289        va_list args;
    310 
    311290        va_start( args, format );
    312         int len = vfscanf( (FILE *)(is.file$), format, args );
     291
     292        int len;
     293    for () {                                                                                    // no check for EINTR limit waiting for keyboard input
     294                errno = 0;
     295                len = vfscanf( (FILE *)(is.file$), format, args );
     296          if ( len != EOF || errno != EINTR ) break;            // timer interrupt ?
     297    } // for
    313298        if ( len == EOF ) {
    314299                if ( ferror( (FILE *)(is.file$) ) ) {
     
    319304        return len;
    320305} // fmt
    321 
    322 inline void acquire( ifstream & is ) with(is) {
    323         lock( lock$ );                                                                          // may increase recursive lock
    324         if ( ! acquired$ ) acquired$ = true;                            // not locked ?
    325         else unlock( lock$ );                                                           // unwind recursive lock at start
    326 } // acquire
    327 
    328 inline void release( ifstream & is ) {
    329         unlock( is.lock$ );
    330 } // release
    331 
    332 void ?{}( isacquire & acq, ifstream & is ) { lock( is.lock$ ); &acq.is = &is; }
    333 void ^?{}( isacquire & acq ) { release( acq.is ); }
    334306
    335307static ifstream sinFile = { (FILE *)stdin };
  • libcfa/src/fstream.hfa

    r94647b0 r7770cc8  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jul 28 07:35:50 2021
    13 // Update Count     : 234
     12// Last Modified On : Sun Oct 10 09:37:32 2021
     13// Update Count     : 243
    1414//
    1515
     
    3636        char tupleSeparator$[ofstream_sepSize];
    3737        multiple_acquisition_lock lock$;
    38         bool acquired$;
    3938}; // ofstream
    4039
     
    5251bool getPrt$( ofstream & );
    5352void setPrt$( ofstream &, bool );
     53
     54void lock( ofstream & );
     55void unlock( ofstream & );
    5456
    5557// public
     
    7577void open( ofstream &, const char name[] );
    7678void close( ofstream & );
     79
    7780ofstream & write( ofstream &, const char data[], size_t size );
    78 
    79 void acquire( ofstream & );
    80 void release( ofstream & );
    81 
    82 void lock( ofstream & );
    83 void unlock( ofstream & );
    84 
    85 struct osacquire {
    86         ofstream & os;
    87 };
    88 void ?{}( osacquire & acq, ofstream & );
    89 void ^?{}( osacquire & acq );
    9081
    9182void ?{}( ofstream & );
     
    110101        bool nlOnOff$;
    111102        multiple_acquisition_lock lock$;
    112         bool acquired$;
    113103}; // ifstream
    114104
    115105// Satisfies istream
    116106
     107// private
     108bool getANL$( ifstream & );
     109
     110void lock( ifstream & );
     111void unlock( ifstream & );
     112
    117113// public
    118114void nlOn( ifstream & );
    119115void nlOff( ifstream & );
    120 bool getANL( ifstream & );
    121116void ends( ifstream & );
    122117int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     
    128123void open( ifstream & is, const char name[] );
    129124void close( ifstream & is );
     125
    130126ifstream & read( ifstream & is, char data[], size_t size );
    131127ifstream & ungetc( ifstream & is, char c );
    132 
    133 void acquire( ifstream & is );
    134 void release( ifstream & is );
    135 
    136 struct isacquire {
    137         ifstream & is;
    138 };
    139 void ?{}( isacquire & acq, ifstream & is );
    140 void ^?{}( isacquire & acq );
    141128
    142129void ?{}( ifstream & is );
  • libcfa/src/heap.cfa

    r94647b0 r7770cc8  
    102102} // prtUnfreed
    103103
    104 extern int cfa_main_returned;                                                   // from bootloader.cf
     104extern int cfa_main_returned;                                                   // from interpose.cfa
    105105extern "C" {
    106106        void heapAppStart() {                                                           // called by __cfaabi_appready_startup
  • libcfa/src/interpose.cfa

    r94647b0 r7770cc8  
    9494} __cabi_libc;
    9595
     96int cfa_main_returned;
     97
    9698extern "C" {
    9799        void __cfaabi_interpose_startup( void ) {
    98100                const char *version = 0p;
     101                cfa_main_returned = 0;
    99102
    100103                preload_libgcc();
  • libcfa/src/iostream.cfa

    r94647b0 r7770cc8  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 15 09:39:21 2021
    13 // Update Count     : 1342
     12// Last Modified On : Sun Oct 10 09:28:17 2021
     13// Update Count     : 1345
    1414//
    1515
     
    398398                return os;
    399399        } // nlOff
    400 } // distribution
    401 
    402 forall( ostype & | ostream( ostype ) ) {
    403         ostype & acquire( ostype & os ) {
    404                 acquire( os );                                                                  // call void returning
    405                 return os;
    406         } // acquire
    407400} // distribution
    408401
     
    829822                        fmt( is, "%c", &temp );                                         // must pass pointer through varg to fmt
    830823                        // do not overwrite parameter with newline unless appropriate
    831                         if ( temp != '\n' || getANL( is ) ) { c = temp; break; }
     824                        if ( temp != '\n' || getANL$( is ) ) { c = temp; break; }
    832825                        if ( eof( is ) ) break;
    833826                } // for
     
    10351028                return is;
    10361029        } // nlOff
    1037 } // distribution
    1038 
    1039 forall( istype & | istream( istype ) ) {
    1040         istype & acquire( istype & is ) {
    1041                 acquire( is );                                                                  // call void returning
    1042                 return is;
    1043         } // acquire
    10441030} // distribution
    10451031
  • libcfa/src/iostream.hfa

    r94647b0 r7770cc8  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 28 20:37:56 2021
    13 // Update Count     : 401
     12// Last Modified On : Sun Oct 10 10:02:07 2021
     13// Update Count     : 407
    1414//
    1515
     
    5858        void close( ostype & );
    5959        ostype & write( ostype &, const char [], size_t );
    60         void acquire( ostype & );                                                       // concurrent access
    6160}; // ostream
    6261
     
    142141        ostype & nlOn( ostype & );
    143142        ostype & nlOff( ostype & );
    144 } // distribution
    145 
    146 forall( ostype & | ostream( ostype ) ) {
    147         ostype & acquire( ostype & );
    148143} // distribution
    149144
     
    296291
    297292trait basic_istream( istype & ) {
    298         bool getANL( istype & );                                                        // get scan newline (on/off)
     293        // private
     294        bool getANL$( istype & );                                                       // get scan newline (on/off)
     295        // public
    299296        void nlOn( istype & );                                                          // read newline
    300297        void nlOff( istype & );                                                         // scan newline
    301 
    302298        void ends( istype & os );                                                       // end of output statement
    303299        int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
     
    312308        void close( istype & is );
    313309        istype & read( istype &, char [], size_t );
    314         void acquire( istype & );                                                       // concurrent access
    315310}; // istream
    316311
     
    379374} // distribution
    380375
    381 forall( istype & | istream( istype ) ) {
    382         istype & acquire( istype & );
    383 } // distribution
    384 
    385376// *********************************** manipulators ***********************************
    386377
  • libcfa/src/strstream.cfa

    r94647b0 r7770cc8  
    1010// Created On       : Thu Apr 22 22:24:35 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 20:59:53 2021
    13 // Update Count     : 78
     12// Last Modified On : Sun Oct 10 16:13:20 2021
     13// Update Count     : 101
    1414//
    1515
    1616#include "strstream.hfa"
     17#include "fstream.hfa"                                                                  // abort
    1718
    1819#include <stdio.h>                                                                              // vsnprintf
     
    3031
    3132// private
    32 bool sepPrt$( ostrstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
    33 void sepReset$( ostrstream & os ) { os.sepOnOff$ = os.sepDefault$; }
    34 void sepReset$( ostrstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
    35 const char * sepGetCur$( ostrstream & os ) { return os.sepCur$; }
    36 void sepSetCur$( ostrstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
    37 bool getNL$( ostrstream & os ) { return os.sawNL$; }
    38 void setNL$( ostrstream & os, bool state ) { os.sawNL$ = state; }
    39 bool getANL$( ostrstream & os ) { return os.nlOnOff$; }
    40 bool getPrt$( ostrstream & os ) { return os.prt$; }
    41 void setPrt$( ostrstream & os, bool state ) { os.prt$ = state; }
     33inline bool sepPrt$( ostrstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
     34inline void sepReset$( ostrstream & os ) { os.sepOnOff$ = os.sepDefault$; }
     35inline void sepReset$( ostrstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
     36inline const char * sepGetCur$( ostrstream & os ) { return os.sepCur$; }
     37inline void sepSetCur$( ostrstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
     38inline bool getNL$( ostrstream & os ) { return os.sawNL$; }
     39inline void setNL$( ostrstream & os, bool state ) { os.sawNL$ = state; }
     40inline bool getANL$( ostrstream & os ) { return os.nlOnOff$; }
     41inline bool getPrt$( ostrstream & os ) { return os.prt$; }
     42inline void setPrt$( ostrstream & os, bool state ) { os.prt$ = state; }
    4243
    4344// public
     
    128129// *********************************** istrstream ***********************************
    129130
     131// private
     132bool getANL$( istrstream & is ) { return is.nlOnOff$; }
    130133
    131134// public
     
    136139} // ?{}
    137140
    138 bool getANL( istrstream & is ) { return is.nlOnOff$; }
    139141void nlOn( istrstream & is ) { is.nlOnOff$ = true; }
    140142void nlOff( istrstream & is ) { is.nlOnOff$ = false; }
    141143
    142 void ends( istrstream & is ) {
    143 } // ends
     144void ends( istrstream & is ) {}
     145bool eof( istrstream & is ) { return false; }
    144146
    145 int eof( istrstream & is ) {
    146         return 0;
    147 } // eof
     147int fmt( istrstream & is, const char format[], ... ) with(is) {
     148        va_list args;
     149        va_start( args, format );
     150        // THIS DOES NOT WORK BECAUSE VSSCANF RETURNS NUMBER OF VALUES READ VERSUS BUFFER POSITION SCANNED.
     151        int len = vsscanf( buf$ + cursor$, format, args );
     152        va_end( args );
     153        if ( len == EOF ) {
     154                abort | IO_MSG "invalid read";
     155        } // if
     156        // SKULLDUGGERY: This hack skips over characters read by vsscanf by moving to the next whitespace but it does not
     157        // handle C reads with wdi manipulators that leave the cursor at a non-whitespace character.
     158        for ( ; buf$[cursor$] != ' ' && buf$[cursor$] != '\t' && buf$[cursor$] != '\0'; cursor$ += 1 ) {
     159                //printf( "X \'%c\'\n", buf$[cursor$] );
     160        } // for
     161        if ( buf$[cursor$] != '\0' ) cursor$ += 1;      // advance to whitespace
     162        return len;
     163} // fmt
    148164
    149165istrstream &ungetc( istrstream & is, char c ) {
     
    154170} // ungetc
    155171
    156 int fmt( istrstream & is, const char format[], ... ) {
    157         va_list args;
    158         va_start( args, format );
    159         // This does not work because vsscanf does not return buffer position.
    160         int len = vsscanf( is.buf$ + is.cursor$, format, args );
    161         va_end( args );
    162         if ( len == EOF ) {
    163                 int j;
    164                 printf( "X %d%n\n", len, &j );
    165         } // if
    166         is.cursor$ += len;
    167         return len;
    168 } // fmt
    169 
    170172// Local Variables: //
    171173// tab-width: 4 //
  • libcfa/src/strstream.hfa

    r94647b0 r7770cc8  
    1010// Created On       : Thu Apr 22 22:20:59 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 20:58:50 2021
    13 // Update Count     : 41
     12// Last Modified On : Sun Oct 10 10:14:22 2021
     13// Update Count     : 47
    1414//
    1515
     
    8585// Satisfies basic_istream
    8686
     87// private
     88bool getANL$( istrstream & );
     89
    8790// public
    88 bool getANL( istrstream & );
    8991void nlOn( istrstream & );
    9092void nlOff( istrstream & );
    9193void ends( istrstream & );
     94
    9295int fmt( istrstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    93 istrstream & ungetc( istrstream & is, char c );
    94 int eof( istrstream & is );
     96istrstream & ungetc( istrstream &, char );
     97bool eof( istrstream & );
    9598
    96 void ?{}( istrstream & is, char buf[] );
     99void ?{}( istrstream &, char buf[] );
    97100
    98101// Local Variables: //
  • src/AST/Convert.cpp

    r94647b0 r7770cc8  
    10411041
    10421042        const ast::Expr * visit( const ast::StmtExpr * node ) override final {
    1043                 auto stmts = node->stmts;
    1044                 // disable sharing between multiple StmtExprs explicitly.
    1045                 // this should no longer be true.
    1046 
    10471043                auto rslt = new StmtExpr(
    1048                         get<CompoundStmt>().accept1(stmts)
     1044                        get<CompoundStmt>().accept1(node->stmts)
    10491045                );
    10501046
    10511047                rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls);
    10521048                rslt->dtors       = get<Expression>().acceptL(node->dtors);
    1053                 if (node->resultExpr) {
    1054                         // this MUST be found by children visit
    1055                         rslt->resultExpr  = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(node->resultExpr));
    1056                 }
     1049
     1050                // is this even used after convert?
     1051                //if (tmp->resultExpr) {
     1052                //      // this MUST be found by children visit
     1053                //      rslt->resultExpr  = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(tmp->resultExpr));
     1054                //}
    10571055
    10581056                auto expr = visitBaseExpr( node, rslt );
     
    14461444
    14471445std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit ) {
     1446        // Copy values from the global store to the local static variables.
     1447        ast::sizeType = translationUnit.global.sizeType;
     1448        ast::dereferenceOperator = translationUnit.global.dereference;
     1449        ast::dtorStruct = translationUnit.global.dtorStruct;
     1450        ast::dtorStructDestroy = translationUnit.global.dtorDestroy;
     1451
    14481452        ConverterNewToOld c;
    14491453        std::list< Declaration * > decls;
  • src/AST/Copy.hpp

    r94647b0 r7770cc8  
    1010// Created On       : Wed Jul 10 16:13:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jun 19 16:43:00 2020
    13 // Update Count     : 1
     12// Last Modified On : Thr Nov 11  9:22:00 2021
     13// Update Count     : 2
    1414//
    1515
    1616#pragma once
    1717
    18 #include "Decl.hpp"
    19 #include "Expr.hpp"
    20 #include "Pass.hpp"
    21 #include "Stmt.hpp"
    22 #include "Type.hpp"
    23 #include <unordered_set>
    24 #include <unordered_map>
     18#include "Node.hpp"
     19#include <cassert>
    2520
    2621namespace ast {
     
    4338 */
    4439
    45 class DeepCopyCore {
    46         std::unordered_map< const Node *, const Node * > nodeCache;
    47         std::unordered_set< readonly<Node> * > readonlyCache;
    48 
    49         template<typename node_t>
    50         void readonlyInsert( const readonly<node_t> * ptrptr ) {
    51                 readonlyCache.insert( (readonly<Node> *) ptrptr );
    52         }
    53 
    54 public:
    55         template<typename node_t>
    56         const node_t * previsit( const node_t * node ) {
    57                 const node_t * copy = shallowCopy( node );
    58                 nodeCache.insert( std::make_pair( node, copy ) );
    59                 return copy;
    60         }
    61 
    62         void postvisit( const AggregateDecl * node ) {
    63                 readonlyInsert( &node->parent );
    64         }
    65 
    66         void postvisit( const StructInstType * node ) {
    67                 readonlyInsert( &node->base );
    68         }
    69 
    70         void postvisit( const UnionInstType * node ) {
    71                 readonlyInsert( &node->base );
    72         }
    73 
    74         void postvisit( const EnumInstType * node ) {
    75                 readonlyInsert( &node->base );
    76         }
    77 
    78         void postvisit( const TraitInstType * node ) {
    79                 readonlyInsert( &node->base );
    80         }
    81 
    82         void postvisit( const TypeInstType * node ) {
    83                 readonlyInsert( &node->base );
    84         }
    85 
    86         void postvisit( const ImplicitCtorDtorStmt * node ) {
    87                 readonlyInsert( (const readonly<Stmt> *) &node->callStmt );
    88         }
    89 
    90         void postvisit( const MemberExpr * node ) {
    91                 readonlyInsert( &node->member );
    92         }
    93 
    94         void postvisit( const VariableExpr * node ) {
    95                 readonlyInsert( &node->var );
    96         }
    97 
    98         void postvisit( const OffsetofExpr * node ) {
    99                 readonlyInsert( &node->member );
    100         }
    101 
    102         void postvisit( const DeletedExpr * node ) {
    103                 readonlyInsert( &node->deleteStmt );
    104         }
    105 
    106         void readonlyUpdates() {
    107                 for ( readonly<Node> * ptr : readonlyCache ) {
    108                         auto it = nodeCache.find( ptr->get() );
    109                         if ( nodeCache.end() != it ) {
    110                                 *ptr = it->second;
    111                         }
    112                 }
    113         }
    114 };
    115 
     40// Implementations:
    11641template<typename node_t>
    11742node_t * shallowCopy( const node_t * localRoot ) {
     
    12146template<typename node_t>
    12247node_t * deepCopy( const node_t * localRoot ) {
    123         Pass< DeepCopyCore > dc;
    124         node_t const * newRoot = localRoot->accept( dc );
    125         dc.core.readonlyUpdates();
    126         return const_cast< node_t * >( newRoot );
     48        return strict_dynamic_cast<node_t *>( deepCopy<Node>( localRoot ) );
    12749}
     50
     51template<>
     52Node * deepCopy<Node>( const Node * localRoot );
    12853
    12954}
  • src/AST/Decl.hpp

    r94647b0 r7770cc8  
    131131        // declared type, derived from parameter declarations
    132132        ptr<FunctionType> type;
     133        /// Null for the forward declaration of a function.
    133134        ptr<CompoundStmt> stmts;
    134135        std::vector< ptr<Expr> > withExprs;
     
    269270        : AggregateDecl( loc, name, std::move(attrs), linkage ), kind( kind ) {}
    270271
    271         bool is_coroutine() { return kind == Coroutine; }
    272         bool is_generator() { return kind == Generator; }
    273         bool is_monitor  () { return kind == Monitor  ; }
    274         bool is_thread   () { return kind == Thread   ; }
     272        bool is_coroutine() const { return kind == Coroutine; }
     273        bool is_generator() const { return kind == Generator; }
     274        bool is_monitor  () const { return kind == Monitor  ; }
     275        bool is_thread   () const { return kind == Thread   ; }
    275276
    276277        const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Init.hpp

    r94647b0 r7770cc8  
    9898        const_iterator begin() const { return initializers.begin(); }
    9999        const_iterator end() const { return initializers.end(); }
     100        size_t size() const { return initializers.size(); }
    100101
    101102        const Init * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Pass.hpp

    r94647b0 r7770cc8  
    109109        static auto read( node_type const * node, Args&&... args ) {
    110110                Pass<core_t> visitor( std::forward<Args>( args )... );
    111                 node_type const * temp = node->accept( visitor );
     111                auto const * temp = node->accept( visitor );
    112112                assert( temp == node );
    113113                return visitor.get_result();
     
    124124        static auto read( node_type const * node ) {
    125125                Pass<core_t> visitor;
    126                 node_type const * temp = node->accept( visitor );
     126                auto const * temp = node->accept( visitor );
    127127                assert( temp == node );
    128128                return visitor.get_result();
     
    348348
    349349        /// When this node is finished being visited, restore the value of a variable
     350        /// You may assign to the return value to set the new value in the same statement.
    350351        template< typename T >
    351         void GuardValue( T& val ) {
     352        T& GuardValue( T& val ) {
    352353                at_cleanup( [ val ]( void * newVal ) {
    353354                        * static_cast< T * >( newVal ) = val;
    354355                }, static_cast< void * >( & val ) );
     356                return val;
    355357        }
    356358
     
    394396};
    395397
     398/// Used to get a pointer to the wrapping TranslationUnit.
     399struct WithConstTranslationUnit {
     400        const TranslationUnit * translationUnit = nullptr;
     401
     402        const TranslationUnit & transUnit() const {
     403                assertf( translationUnit, "WithConstTranslationUnit not set-up." );
     404                return *translationUnit;
     405        }
     406};
     407
    396408}
    397409
  • src/AST/Pass.impl.hpp

    r94647b0 r7770cc8  
    420420template< typename core_t >
    421421inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
    422         return ast::accept_all( unit.decls, visitor );
     422        if ( auto ptr = __pass::translation_unit::get_cptr( visitor.core, 0 ) ) {
     423                ValueGuard<const TranslationUnit *> guard( *ptr );
     424                *ptr = &unit;
     425                return ast::accept_all( unit.decls, visitor );
     426        } else {
     427                return ast::accept_all( unit.decls, visitor );
     428        }
    423429}
    424430
  • src/AST/Pass.proto.hpp

    r94647b0 r7770cc8  
    426426        } // namespace forall
    427427
     428        // For passes that need access to the global context. Sreaches `translationUnit`
     429        namespace translation_unit {
     430                template<typename core_t>
     431                static inline auto get_cptr( core_t & core, int )
     432                                -> decltype( &core.translationUnit ) {
     433                        return &core.translationUnit;
     434                }
     435
     436                template<typename core_t>
     437                static inline const TranslationUnit ** get_cptr( core_t &, long ) {
     438                        return nullptr;
     439                }
     440        }
     441
    428442        template<typename core_t>
    429443        static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) {
  • src/AST/Stmt.hpp

    r94647b0 r7770cc8  
    175175class CaseStmt final : public Stmt {
    176176public:
     177        /// Null for the default label.
    177178        ptr<Expr> cond;
    178179        std::vector<ptr<Stmt>> stmts;
  • src/AST/TranslationUnit.hpp

    r94647b0 r7770cc8  
    2626        std::list< ptr< Decl > > decls;
    2727
    28         struct Globals {
     28        struct Global {
    2929                std::map< UniqueId, Decl * > idMap;
    3030
    31                 const Type * sizeType;
     31                ptr<Type> sizeType;
    3232                const FunctionDecl * dereference;
    3333                const StructDecl * dtorStruct;
  • src/AST/module.mk

    r94647b0 r7770cc8  
    2424        AST/Convert.cpp \
    2525        AST/Convert.hpp \
     26        AST/Copy.cpp \
    2627        AST/Copy.hpp \
    2728        AST/CVQualifiers.hpp \
  • src/AST/porting.md

    r94647b0 r7770cc8  
    9898        * `Initializer` => `ast::Init`
    9999    * `Statement` => `ast::Stmt`
     100    * `ReferenceToType` => `ast::BaseInstType`
    100101        * any field names should follow a similar renaming
    101102  * because they don't really belong to `Type` (and for consistency with `Linkage::Spec`):
  • src/CodeGen/FixMain.cc

    r94647b0 r7770cc8  
    2222#include <string>                  // for operator<<
    2323
     24#include "AST/Decl.hpp"
     25#include "AST/Type.hpp"
     26#include "Common/PassVisitor.h"
    2427#include "Common/SemanticError.h"  // for SemanticError
    2528#include "CodeGen/GenType.h"       // for GenType
     
    2932
    3033namespace CodeGen {
     34
     35namespace {
     36
     37struct FindMainCore {
     38        FunctionDecl * main_signature = nullptr;
     39
     40        void previsit( FunctionDecl * decl ) {
     41                if ( FixMain::isMain( decl ) ) {
     42                        if ( main_signature ) {
     43                                SemanticError( decl, "Multiple definition of main routine\n" );
     44                        }
     45                        main_signature = decl;
     46                }
     47        }
     48};
     49
     50}
     51
    3152        bool FixMain::replace_main = false;
    32         std::unique_ptr<FunctionDecl> FixMain::main_signature = nullptr;
    3353
    3454        template<typename container>
     
    3757        }
    3858
    39         void FixMain::registerMain(FunctionDecl* functionDecl)
    40         {
    41                 if(main_signature) {
    42                         SemanticError(functionDecl, "Multiple definition of main routine\n");
    43                 }
    44                 main_signature.reset( functionDecl->clone() );
    45         }
     59        void FixMain::fix( std::list< Declaration * > & translationUnit,
     60                        std::ostream &os, const char* bootloader_filename ) {
     61                PassVisitor< FindMainCore > main_finder;
     62                acceptAll( translationUnit, main_finder );
     63                FunctionDecl * main_signature = main_finder.pass.main_signature;
    4664
    47         void FixMain::fix(std::ostream &os, const char* bootloader_filename) {
    4865                if( main_signature ) {
    4966                        os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return ";
    50                         main_signature->mangleName = SymTab::Mangler::mangle(main_signature.get());
     67                        main_signature->mangleName = SymTab::Mangler::mangle(main_signature);
    5168
    5269                        os << main_signature->get_scopedMangleName() << "(";
     
    6582                }
    6683        }
     84
     85namespace {
     86
     87ObjectDecl * signedIntObj() {
     88        return new ObjectDecl(
     89                "", Type::StorageClasses(), LinkageSpec::Cforall, 0,
     90                new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr );
     91}
     92
     93ObjectDecl * charStarObj() {
     94        return new ObjectDecl(
     95                "", Type::StorageClasses(), LinkageSpec::Cforall, 0,
     96                new PointerType( Type::Qualifiers(),
     97                        new PointerType( Type::Qualifiers(),
     98                                new BasicType( Type::Qualifiers(), BasicType::Char ) ) ),
     99                nullptr );
     100}
     101
     102std::string create_mangled_main_function_name( FunctionType * function_type ) {
     103        std::unique_ptr<FunctionDecl> decl( new FunctionDecl(
     104                "main", Type::StorageClasses(), LinkageSpec::Cforall,
     105                function_type, nullptr ) );
     106        return SymTab::Mangler::mangle( decl.get() );
     107}
     108
     109std::string mangled_0_argument_main() {
     110        FunctionType* main_type = new FunctionType( Type::Qualifiers(), true );
     111        main_type->get_returnVals().push_back( signedIntObj() );
     112        return create_mangled_main_function_name( main_type );
     113}
     114
     115std::string mangled_2_argument_main() {
     116        FunctionType* main_type = new FunctionType( Type::Qualifiers(), false );
     117        main_type->get_returnVals().push_back( signedIntObj() );
     118        main_type->get_parameters().push_back( signedIntObj() );
     119        main_type->get_parameters().push_back( charStarObj() );
     120        return create_mangled_main_function_name( main_type );
     121}
     122
     123bool is_main( const std::string & mangled_name ) {
     124        // This breaks if you move it out of the function.
     125        static const std::string mangled_mains[] = {
     126                mangled_0_argument_main(),
     127                mangled_2_argument_main(),
     128                //mangled_3_argument_main(),
     129        };
     130
     131        for ( auto main_name : mangled_mains ) {
     132                if ( main_name == mangled_name ) return true;
     133        }
     134        return false;
     135}
     136
     137} // namespace
     138
     139bool FixMain::isMain( FunctionDecl * decl ) {
     140        if ( std::string("main") != decl->name ) {
     141                return false;
     142        }
     143        return is_main( SymTab::Mangler::mangle( decl, true, true ) );
     144}
     145
     146bool FixMain::isMain( const ast::FunctionDecl * decl ) {
     147        if ( std::string("main") != decl->name ) {
     148                return false;
     149        }
     150        return is_main( Mangle::mangle( decl, Mangle::Type ) );
     151}
     152
    67153};
  • src/CodeGen/FixMain.h

    r94647b0 r7770cc8  
    99// Author           : Thierry Delisle
    1010// Created On       : Thr Jan 12 14:11:09 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Feb 16 03:24:32 2020
    13 // Update Count     : 5
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Oct 29 16:20:00 2021
     13// Update Count     : 8
    1414//
    1515
     
    1818#include <iosfwd>
    1919#include <memory>
     20#include <list>
    2021
    2122#include "SynTree/LinkageSpec.h"
    2223
     24class Declaration;
    2325class FunctionDecl;
     26namespace ast {
     27        class FunctionDecl;
     28}
    2429
    2530namespace CodeGen {
    26         class FixMain {
    27           public :
    28                 static inline LinkageSpec::Spec mainLinkage() {
    29                         return replace_main ? LinkageSpec::Cforall : LinkageSpec::C;
    30                 }
    31                
    32                 static inline void setReplaceMain(bool val) {
    33                         replace_main = val;
    34                 }
    3531
    36                 static void registerMain(FunctionDecl* val);
     32class FixMain {
     33public :
     34        static inline LinkageSpec::Spec mainLinkage() {
     35                return replace_main ? LinkageSpec::Cforall : LinkageSpec::C;
     36        }
    3737
    38                 static void fix(std::ostream &os, const char* bootloader_filename);
     38        static inline void setReplaceMain(bool val) {
     39                replace_main = val;
     40        }
    3941
    40           private:
    41                 static bool replace_main;
    42                 static std::unique_ptr<FunctionDecl> main_signature;
    43         };
     42        static bool isMain(FunctionDecl* decl);
     43        static bool isMain(const ast::FunctionDecl * decl);
     44
     45        static void fix( std::list< Declaration * > & decls,
     46                        std::ostream &os, const char* bootloader_filename );
     47
     48private:
     49        static bool replace_main;
     50};
     51
    4452} // namespace CodeGen
  • src/CodeGen/FixNames.cc

    r94647b0 r7770cc8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:39:14 2019
    13 // Update Count     : 21
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Oct 29 15:49:00 2021
     13// Update Count     : 23
    1414//
    1515
     
    1919#include <string>                  // for string, operator!=, operator==
    2020
     21#include "AST/Chain.hpp"
     22#include "AST/Expr.hpp"
     23#include "AST/Pass.hpp"
    2124#include "Common/PassVisitor.h"
    2225#include "Common/SemanticError.h"  // for SemanticError
     
    4649        };
    4750
    48         std::string mangle_main() {
    49                 FunctionType* main_type;
    50                 std::unique_ptr<FunctionDecl> mainDecl { new FunctionDecl( "main", Type::StorageClasses(), LinkageSpec::Cforall,
    51                                                                                                                                    main_type = new FunctionType( Type::Qualifiers(), true ), nullptr )
    52                                 };
    53                 main_type->get_returnVals().push_back(
    54                         new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr )
    55                 );
    56 
    57                 auto && name = SymTab::Mangler::mangle( mainDecl.get() );
    58                 // std::cerr << name << std::endl;
    59                 return std::move(name);
    60         }
    61         std::string mangle_main_args() {
    62                 FunctionType* main_type;
    63                 std::unique_ptr<FunctionDecl> mainDecl { new FunctionDecl( "main", Type::StorageClasses(), LinkageSpec::Cforall,
    64                                                                                                                                    main_type = new FunctionType( Type::Qualifiers(), false ), nullptr )
    65                                 };
    66                 main_type->get_returnVals().push_back(
    67                         new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr )
    68                 );
    69 
    70                 main_type->get_parameters().push_back(
    71                         new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr )
    72                 );
    73 
    74                 main_type->get_parameters().push_back(
    75                         new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, 0,
    76                         new PointerType( Type::Qualifiers(), new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::Char ) ) ),
    77                         nullptr )
    78                 );
    79 
    80                 auto&& name = SymTab::Mangler::mangle( mainDecl.get() );
    81                 // std::cerr << name << std::endl;
    82                 return std::move(name);
    83         }
    84 
    85         bool is_main(const std::string& name) {
    86                 static std::string mains[] = {
    87                         mangle_main(),
    88                         mangle_main_args()
    89                 };
    90 
    91                 for(const auto& m : mains) {
    92                         if( name == m ) return true;
    93                 }
    94                 return false;
    95         }
    96 
    9751        void fixNames( std::list< Declaration* > & translationUnit ) {
    9852                PassVisitor<FixNames> fixer;
     
    11872                fixDWT( functionDecl );
    11973
    120                 if(is_main( SymTab::Mangler::mangle(functionDecl, true, true) )) {
     74                if ( FixMain::isMain( functionDecl ) ) {
    12175                        int nargs = functionDecl->get_functionType()->get_parameters().size();
    12276                        if( !(nargs == 0 || nargs == 2 || nargs == 3) ) {
     
    12478                        }
    12579                        functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( new ConstantExpr( Constant::from_int( 0 ) ) ) );
    126                         CodeGen::FixMain::registerMain( functionDecl );
    12780                }
    12881        }
     
    13285                GuardAction( [this](){ scopeLevel--; } );
    13386        }
     87
     88/// Does work with the main function and scopeLevels.
     89class FixNames_new : public ast::WithGuards {
     90        int scopeLevel = 1;
     91
     92        bool shouldSetScopeLevel( const ast::DeclWithType * dwt ) {
     93                return !dwt->name.empty() && dwt->linkage.is_mangled
     94                        && dwt->scopeLevel != scopeLevel;
     95        }
     96public:
     97        const ast::ObjectDecl *postvisit( const ast::ObjectDecl *objectDecl ) {
     98                if ( shouldSetScopeLevel( objectDecl ) ) {
     99                        return ast::mutate_field( objectDecl, &ast::ObjectDecl::scopeLevel, scopeLevel );
     100                }
     101                return objectDecl;
     102        }
     103
     104        const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) {
     105                // This store is used to ensure a maximum of one call to mutate.
     106                ast::FunctionDecl * mutDecl = nullptr;
     107
     108                if ( shouldSetScopeLevel( functionDecl ) ) {
     109                        mutDecl = ast::mutate( functionDecl );
     110                        mutDecl->scopeLevel = scopeLevel;
     111                }
     112
     113                if ( FixMain::isMain( functionDecl ) ) {
     114                        if ( !mutDecl ) { mutDecl = ast::mutate( functionDecl ); }
     115
     116                        int nargs = mutDecl->params.size();
     117                        if ( 0 != nargs && 2 != nargs && 3 != nargs ) {
     118                                SemanticError( functionDecl, "Main expected to have 0, 2 or 3 arguments\n" );
     119                        }
     120                        ast::chain_mutate( mutDecl->stmts )->kids.push_back(
     121                                new ast::ReturnStmt(
     122                                        mutDecl->location,
     123                                        ast::ConstantExpr::from_int( mutDecl->location, 0 )
     124                                )
     125                        );
     126                }
     127                return mutDecl ? mutDecl : functionDecl;
     128        }
     129
     130        void previsit( const ast::CompoundStmt * ) {
     131                GuardValue( scopeLevel ) += 1;
     132        }
     133};
     134
     135void fixNames( ast::TranslationUnit & translationUnit ) {
     136        ast::Pass<FixNames_new>::run( translationUnit );
     137}
     138
    134139} // namespace CodeGen
    135140
  • src/CodeGen/FixNames.h

    r94647b0 r7770cc8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 21 22:17:33 2017
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct 26 13:47:00 2021
     13// Update Count     : 4
    1414//
    1515
     
    1919
    2020class Declaration;
     21namespace ast {
     22        struct TranslationUnit;
     23}
    2124
    2225namespace CodeGen {
    2326        /// mangles object and function names
    2427        void fixNames( std::list< Declaration* > & translationUnit );
     28        void fixNames( ast::TranslationUnit & translationUnit );
    2529} // namespace CodeGen
    2630
  • src/CodeTools/DeclStats.cc

    r94647b0 r7770cc8  
    156156                /// number of counting bins for linkages
    157157                static const unsigned n_named_specs = 8;
    158                 /// map from total number of specs to bins
    159                 static const unsigned ind_for_linkage[16];
     158                /// Mapping function from linkage to bin.
     159                static unsigned linkage_index( LinkageSpec::Spec spec ) {
     160                        switch ( spec ) {
     161                        case LinkageSpec::Intrinsic:  return 0;
     162                        case LinkageSpec::C:          return 1;
     163                        case LinkageSpec::Cforall:    return 2;
     164                        case LinkageSpec::AutoGen:    return 3;
     165                        case LinkageSpec::Compiler:   return 4;
     166                        case LinkageSpec::BuiltinCFA: return 5;
     167                        case LinkageSpec::BuiltinC:   return 6;
     168                        default:                      return 7;
     169                        }
     170                }
    160171
    161172                Stats for_linkage[n_named_specs];            ///< Stores separate stats per linkage
     
    366377                        const std::string& mangleName = decl->get_mangleName().empty() ? decl->name : decl->get_mangleName();
    367378                        if ( seen_names.insert( mangleName ).second ) {
    368                                 Stats& stats = for_linkage[ ind_for_linkage[ decl->linkage ] ];
     379                                Stats& stats = for_linkage[ linkage_index( decl->linkage ) ];
    369380
    370381                                ++stats.n_decls;
     
    527538        };
    528539
    529         const unsigned DeclStats::ind_for_linkage[]
    530                 = { 7, 7, 2, 1,   7, 7, 7, 3,   4, 7, 6, 5,   7, 7, 7, 0 };
    531 
    532540        void printDeclStats( std::list< Declaration * > &translationUnit ) {
    533541                PassVisitor<DeclStats> stats;
  • src/Common/module.mk

    r94647b0 r7770cc8  
    2222      Common/CompilerError.h \
    2323      Common/Debug.h \
     24      Common/DeclStats.hpp \
     25      Common/DeclStats.cpp \
    2426      Common/ErrorObjects.h \
    2527      Common/Eval.cc \
     
    3335      Common/PassVisitor.proto.h \
    3436      Common/PersistentMap.h \
     37      Common/ResolvProtoDump.hpp \
     38      Common/ResolvProtoDump.cpp \
    3539      Common/ScopedMap.h \
    3640      Common/SemanticError.cc \
  • src/Concurrency/Keywords.cc

    r94647b0 r7770cc8  
    979979                        // If this is the destructor for a monitor it must be mutex
    980980                        if(isDtor) {
     981                                // This reflects MutexKeyword::validate, except does not produce an error.
    981982                                Type* ty = decl->get_functionType()->get_parameters().front()->get_type();
    982983
  • src/ControlStruct/ExceptTranslate.cc

    r94647b0 r7770cc8  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // ExceptVisitor.cc --
     7// ExceptTranslate.cc -- Conversion of exception control flow structures.
    88//
    99// Author           : Andrew Beach
  • src/ControlStruct/ExceptTranslate.h

    r94647b0 r7770cc8  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // ExceptTranslate.h --
     7// ExceptTranslate.h -- Conversion of exception control flow structures.
    88//
    99// Author           : Andrew Beach
    1010// Created On       : Tus Jun 06 10:13:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tus May 19 11:47:00 2020
    13 // Update Count     : 5
     12// Last Modified On : Mon Nov  8 11:43:00 2020
     13// Update Count     : 6
    1414//
    1515
     
    1919
    2020class Declaration;
     21namespace ast {
     22        class TranslationUnit;
     23}
    2124
    2225namespace ControlStruct {
    2326        void translateThrows( std::list< Declaration *> & translationUnit );
     27        void translateThrows( ast::TranslationUnit & transUnit );
    2428        /* Replaces all throw & throwResume statements with function calls.
    2529         * These still need to be resolved, so call this before the reslover.
  • src/ControlStruct/LabelGenerator.cc

    r94647b0 r7770cc8  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 11 22:23:20 2019
    13 // Update Count     : 15
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  8 10:18:00 2021
     13// Update Count     : 17
    1414//
    1515
     
    1919
    2020#include "LabelGenerator.h"
     21
     22#include "AST/Attribute.hpp"
     23#include "AST/Label.hpp"
     24#include "AST/Stmt.hpp"
    2125#include "SynTree/Attribute.h"  // for Attribute
    2226#include "SynTree/Label.h"      // for Label, operator<<
     
    2428
    2529namespace ControlStruct {
    26         LabelGenerator * LabelGenerator::labelGenerator = 0;
     30
     31int LabelGenerator::current = 0;
     32LabelGenerator * LabelGenerator::labelGenerator = nullptr;
    2733
    2834        LabelGenerator * LabelGenerator::getGenerator() {
     
    4349                return l;
    4450        }
     51
     52ast::Label LabelGenerator::newLabel(
     53                const std::string & suffix, const ast::Stmt * stmt ) {
     54        assert( stmt );
     55
     56        std::ostringstream os;
     57        os << "__L" << current++ << "__" << suffix;
     58        if ( stmt && !stmt->labels.empty() ) {
     59                os << "_" << stmt->labels.front() << "__";
     60        }
     61        ast::Label ret_label( stmt->location, os.str() );
     62        ret_label.attributes.push_back( new ast::Attribute( "unused" ) );
     63        return ret_label;
     64}
     65
    4566} // namespace ControlStruct
    4667
  • src/ControlStruct/LabelGenerator.h

    r94647b0 r7770cc8  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:20:14 2017
    13 // Update Count     : 6
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Nov  8 10:16:00 2021
     13// Update Count     : 8
    1414//
    1515
     
    2121
    2222class Statement;
     23namespace ast {
     24        class Stmt;
     25        class Label;
     26}
    2327
    2428namespace ControlStruct {
    25         class LabelGenerator {
    26           public:
    27                 static LabelGenerator *getGenerator();
    28                 Label newLabel(std::string suffix, Statement * stmt = nullptr);
    29                 void reset() { current = 0; }
    30                 void rewind() { current--; }
    31           protected:
    32                 LabelGenerator(): current(0) {}
    33           private:
    34                 int current;
    35                 static LabelGenerator *labelGenerator;
    36         };
     29
     30class LabelGenerator {
     31        static int current;
     32        static LabelGenerator *labelGenerator;
     33protected:
     34        LabelGenerator() {}
     35public:
     36        static LabelGenerator *getGenerator();
     37        static Label newLabel(std::string suffix, Statement * stmt = nullptr);
     38        static ast::Label newLabel( const std::string&, const ast::Stmt * );
     39        static void reset() { current = 0; }
     40        static void rewind() { current--; }
     41};
     42
    3743} // namespace ControlStruct
    3844
  • src/ControlStruct/module.mk

    r94647b0 r7770cc8  
    1818        ControlStruct/ExceptDecl.cc \
    1919        ControlStruct/ExceptDecl.h \
     20        ControlStruct/FixLabels.cpp \
     21        ControlStruct/FixLabels.hpp \
    2022        ControlStruct/ForExprMutator.cc \
    2123        ControlStruct/ForExprMutator.h \
     
    2628        ControlStruct/MLEMutator.cc \
    2729        ControlStruct/MLEMutator.h \
     30        ControlStruct/MultiLevelExit.cpp \
     31        ControlStruct/MultiLevelExit.hpp \
    2832        ControlStruct/Mutate.cc \
    2933        ControlStruct/Mutate.h
    3034
    31 SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc ControlStruct/ExceptTranslate.h
     35SRC += $(SRC_CONTROLSTRUCT) \
     36        ControlStruct/ExceptTranslateNew.cpp \
     37        ControlStruct/ExceptTranslate.cc \
     38        ControlStruct/ExceptTranslate.h
     39
    3240SRCDEMANGLE += $(SRC_CONTROLSTRUCT)
    3341
  • src/InitTweak/FixInitNew.cpp

    r94647b0 r7770cc8  
    591591                // need to add __Destructor for _tmp_cp variables as well
    592592
    593                 assertf( ast::dtorStruct && ast::dtorStruct->members.size() == 2, "Destructor generation requires __Destructor definition." );
     593                assertf( ast::dtorStruct, "Destructor generation requires __Destructor definition." );
     594                assertf( ast::dtorStruct->members.size() == 2, "__Destructor definition does not have expected fields." );
    594595                assertf( ast::dtorStructDestroy, "Destructor generation requires __destroy_Destructor." );
    595596
     
    12161217
    12171218                                                        static UniqueName memberDtorNamer = { "__memberDtor" };
    1218                                                         assertf( Validate::dtorStruct, "builtin __Destructor not found." );
    1219                                                         assertf( Validate::dtorStructDestroy, "builtin __destroy_Destructor not found." );
     1219                                                        assertf( ast::dtorStruct, "builtin __Destructor not found." );
     1220                                                        assertf( ast::dtorStructDestroy, "builtin __destroy_Destructor not found." );
    12201221
    12211222                                                        ast::Expr * thisExpr = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, thisParam ) ), new ast::PointerType( new ast::VoidType(), ast::CV::Qualifiers() ) );
  • src/InitTweak/GenInit.cc

    r94647b0 r7770cc8  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:15:10 2019
    13 // Update Count     : 184
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Oct 25 13:53:00 2021
     13// Update Count     : 186
    1414//
    1515#include "GenInit.h"
     
    2424#include "AST/Decl.hpp"
    2525#include "AST/Init.hpp"
     26#include "AST/Pass.hpp"
    2627#include "AST/Node.hpp"
    2728#include "AST/Stmt.hpp"
     
    294295        }
    295296
     297namespace {
     298
     299#       warning Remove the _New suffix after the conversion is complete.
     300        struct HoistArrayDimension_NoResolve_New final :
     301                        public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting,
     302                        public ast::WithGuards, public ast::WithConstTranslationUnit,
     303                        public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New> {
     304                void previsit( const ast::ObjectDecl * decl );
     305                const ast::DeclWithType * postvisit( const ast::ObjectDecl * decl );
     306                // Do not look for objects inside there declarations (and type).
     307                void previsit( const ast::AggregateDecl * ) { visit_children = false; }
     308                void previsit( const ast::NamedTypeDecl * ) { visit_children = false; }
     309                void previsit( const ast::FunctionType * ) { visit_children = false; }
     310
     311                const ast::Type * hoist( const ast::Type * type );
     312
     313                ast::Storage::Classes storageClasses;
     314        };
     315
     316        void HoistArrayDimension_NoResolve_New::previsit(
     317                        const ast::ObjectDecl * decl ) {
     318                GuardValue( storageClasses ) = decl->storage;
     319        }
     320
     321        const ast::DeclWithType * HoistArrayDimension_NoResolve_New::postvisit(
     322                        const ast::ObjectDecl * objectDecl ) {
     323                return mutate_field( objectDecl, &ast::ObjectDecl::type,
     324                                hoist( objectDecl->type ) );
     325        }
     326
     327        const ast::Type * HoistArrayDimension_NoResolve_New::hoist(
     328                        const ast::Type * type ) {
     329                static UniqueName dimensionName( "_array_dim" );
     330
     331                if ( !isInFunction() || storageClasses.is_static ) {
     332                        return type;
     333                }
     334
     335                if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
     336                        if ( nullptr == arrayType->dimension ) {
     337                                return type;
     338                        }
     339
     340                        if ( !Tuples::maybeImpure( arrayType->dimension ) ) {
     341                                return type;
     342                        }
     343
     344                        ast::ptr<ast::Type> dimType = transUnit().global.sizeType;
     345                        assert( dimType );
     346                        add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) );
     347
     348                        ast::ObjectDecl * arrayDimension = new ast::ObjectDecl(
     349                                arrayType->dimension->location,
     350                                dimensionName.newName(),
     351                                dimType,
     352                                new ast::SingleInit(
     353                                        arrayType->dimension->location,
     354                                        arrayType->dimension
     355                                )
     356                        );
     357
     358                        ast::ArrayType * mutType = ast::mutate( arrayType );
     359                        mutType->dimension = new ast::VariableExpr(
     360                                        arrayDimension->location, arrayDimension );
     361                        declsToAddBefore.push_back( arrayDimension );
     362
     363                        mutType->base = hoist( mutType->base );
     364                        return mutType;
     365                }
     366                return type;
     367        }
     368
     369        struct ReturnFixer_New final :
     370                        public ast::WithStmtsToAdd<>, ast::WithGuards {
     371                void previsit( const ast::FunctionDecl * decl );
     372                const ast::ReturnStmt * previsit( const ast::ReturnStmt * stmt );
     373        private:
     374                const ast::FunctionDecl * funcDecl = nullptr;
     375        };
     376
     377        void ReturnFixer_New::previsit( const ast::FunctionDecl * decl ) {
     378                GuardValue( funcDecl ) = decl;
     379        }
     380
     381        const ast::ReturnStmt * ReturnFixer_New::previsit(
     382                        const ast::ReturnStmt * stmt ) {
     383                auto & returns = funcDecl->returns;
     384                assert( returns.size() < 2 );
     385                // Hands off if the function returns a reference.
     386                // Don't allocate a temporary if the address is returned.
     387                if ( stmt->expr && 1 == returns.size() ) {
     388                        ast::ptr<ast::DeclWithType> retDecl = returns.front();
     389                        if ( isConstructable( retDecl->get_type() ) ) {
     390                                // Explicitly construct the return value using the return
     391                                // expression and the retVal object.
     392                                assertf( "" != retDecl->name,
     393                                        "Function %s has unnamed return value.\n",
     394                                        funcDecl->name.c_str() );
     395
     396                                auto retVal = retDecl.strict_as<ast::ObjectDecl>();
     397                                if ( auto varExpr = stmt->expr.as<ast::VariableExpr>() ) {
     398                                        // Check if the return statement is already set up.
     399                                        if ( varExpr->var == retVal ) return stmt;
     400                                }
     401                                ast::ptr<ast::Stmt> ctorStmt = genCtorDtor(
     402                                        retVal->location, "?{}", retVal, stmt->expr );
     403                                assertf( ctorStmt,
     404                                        "ReturnFixer: genCtorDtor returned nllptr: %s / %s",
     405                                        toString( retVal ).c_str(),
     406                                        toString( stmt->expr ).c_str() );
     407                                        stmtsToAddBefore.push_back( ctorStmt );
     408
     409                                // Return the retVal object.
     410                                ast::ReturnStmt * mutStmt = ast::mutate( stmt );
     411                                mutStmt->expr = new ast::VariableExpr(
     412                                        stmt->location, retDecl );
     413                                return mutStmt;
     414                        }
     415                }
     416                return stmt;
     417        }
     418
     419} // namespace
     420
     421        void genInit( ast::TranslationUnit & transUnit ) {
     422                ast::Pass<HoistArrayDimension_NoResolve_New>::run( transUnit );
     423                ast::Pass<ReturnFixer_New>::run( transUnit );
     424        }
     425
    296426        void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) {
    297427                PassVisitor<CtorDtor> ctordtor;
  • src/InitTweak/GenInit.h

    r94647b0 r7770cc8  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:31:19 2017
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Oct 22 16:08:00 2021
     13// Update Count     : 6
    1414//
    1515
     
    2727        /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes
    2828        void genInit( std::list< Declaration * > & translationUnit );
     29        void genInit( ast::TranslationUnit & translationUnit );
    2930
    3031        /// Converts return statements into copy constructor calls on the hidden return variable
  • src/InitTweak/InitTweak.cc

    r94647b0 r7770cc8  
    99// Author           : Rob Schluntz
    1010// Created On       : Fri May 13 11:26:36 2016
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jun 16 20:57:22 2021
    13 // Update Count     : 18
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Nov 19 19:22:00 2021
     13// Update Count     : 19
    1414//
    1515
     
    540540        }
    541541
     542        const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) {
     543                assertf( ftype, "getTypeofThis: nullptr ftype" );
     544                const std::vector<ast::ptr<ast::Type>> & params = ftype->params;
     545                assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s",
     546                                toString( ftype ).c_str() );
     547                const ast::ReferenceType * refType =
     548                        params.front().strict_as<ast::ReferenceType>();
     549                return refType->base;
     550        }
     551
    542552        ObjectDecl * getParamThis( FunctionType * ftype ) {
    543553                assertf( ftype, "getParamThis: nullptr ftype" );
  • src/InitTweak/InitTweak.h

    r94647b0 r7770cc8  
    1010// Created On       : Fri May 13 11:26:36 2016
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jul 19 14:18:00 2019
    13 // Update Count     : 6
     12// Last Modified On : Fri Nov 19 14:18:00 2021
     13// Update Count     : 7
    1414//
    1515
     
    3535        /// returns the base type of the first parameter to a constructor/destructor/assignment function
    3636        Type * getTypeofThis( FunctionType * ftype );
     37        const ast::Type * getTypeofThis( const ast::FunctionType * ftype );
    3738
    3839        /// returns the first parameter of a constructor/destructor/assignment function
  • src/Parser/parser.yy

    r94647b0 r7770cc8  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Sep 11 08:20:44 2021
    13 // Update Count     : 5040
     12// Last Modified On : Fri Oct 15 09:20:17 2021
     13// Update Count     : 5163
    1414//
    1515
     
    3131// from ANSI90 to ANSI11 C are marked with the comment "C99/C11".
    3232
    33 // This grammar also has two levels of extensions. The first extensions cover most of the GCC C extensions All of the
     33// This grammar also has two levels of extensions. The first extensions cover most of the GCC C extensions. All of the
    3434// syntactic extensions for GCC C are marked with the comment "GCC". The second extensions are for Cforall (CFA), which
    3535// fixes several of C's outstanding problems and extends C with many modern language concepts. All of the syntactic
     
    6969        // 2. String encodings are transformed into canonical form (one encoding at start) so the encoding can be found
    7070        //    without searching the string, e.g.: "abc" L"def" L"ghi" => L"abc" "def" "ghi". Multiple encodings must match,
    71         //    i.e., u"a" U"b" L"c" is disallowed.
     71        //    e.g., u"a" U"b" L"c" is disallowed.
    7272
    7373        if ( from[0] != '"' ) {                                                         // encoding ?
     
    310310%token ATassign                                                                                 // @=
    311311
    312 %type<tok> identifier
    313 %type<tok> identifier_or_type_name  attr_name
     312%type<tok> identifier                                   identifier_at                           identifier_or_type_name         attr_name
    314313%type<tok> quasi_keyword
    315314%type<constant> string_literal
     
    327326%type<en> conditional_expression                constant_expression                     assignment_expression           assignment_expression_opt
    328327%type<en> comma_expression                              comma_expression_opt
    329 %type<en> argument_expression_list_opt  argument_expression                     default_initializer_opt
     328%type<en> argument_expression_list_opt  argument_expression_list        argument_expression                     default_initializer_opt
    330329%type<ifctl> if_control_expression
    331330%type<fctl> for_control_expression              for_control_expression_list
     
    559558        IDENTIFIER
    560559        | quasi_keyword
     560        ;
     561
     562identifier_at:
     563        identifier
    561564        | '@'                                                                                           // CFA
    562565                { Token tok = { new string( DeclarationNode::anonymous.newName() ), yylval.tok.loc }; $$ = tok; }
     
    693696        // empty
    694697                { $$ = nullptr; }
    695         | argument_expression
     698        | argument_expression_list
     699        ;
     700
     701argument_expression_list:
     702        argument_expression
    696703        | argument_expression_list_opt ',' argument_expression
    697704                { $$ = (ExpressionNode *)($1->set_last( $3 )); }
     
    731738        | FLOATINGconstant fraction_constants_opt
    732739                { $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); }
    733         | identifier fraction_constants_opt
     740        | identifier_at fraction_constants_opt                          // CFA, allow anonymous fields
    734741                {
    735742                        $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) );
     
    10841091        comma_expression_opt ';'
    10851092                { $$ = new StatementNode( build_expr( $1 ) ); }
     1093        | MUTEX '(' ')' comma_expression ';'
     1094                { $$ = new StatementNode( build_mutex( nullptr, new StatementNode( build_expr( $4 ) ) ) ); }
     1095                // { SemanticError( yylloc, "Mutex expression is currently unimplemented." ); $$ = nullptr; }
    10861096        ;
    10871097
     
    11821192
    11831193iteration_statement:
    1184         WHILE '(' push if_control_expression ')' statement pop
    1185                 { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); }
    1186         | WHILE '(' ')' statement                                                       // CFA => while ( 1 )
     1194        WHILE '(' ')' statement                                                         // CFA => while ( 1 )
    11871195                { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
    1188         | DO statement WHILE '(' comma_expression ')' ';'
    1189                 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
     1196        | WHILE '(' if_control_expression ')' statement         %prec THEN
     1197                { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); }
     1198        | WHILE '(' if_control_expression ')' statement ELSE statement // CFA
     1199                { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
    11901200        | DO statement WHILE '(' ')' ';'                                        // CFA => do while( 1 )
    11911201                { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
    1192         | FOR '(' push for_control_expression_list ')' statement pop
    1193                 { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); }
     1202        | DO statement WHILE '(' comma_expression ')' ';'       %prec THEN
     1203                { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); }
     1204        | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA
     1205                { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
    11941206        | FOR '(' ')' statement                                                         // CFA => for ( ;; )
    11951207                { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); }
     1208        | FOR '(' for_control_expression_list ')' statement     %prec THEN
     1209                { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); }
     1210        | FOR '(' for_control_expression_list ')' statement ELSE statement // CFA
     1211                { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; }
    11961212        ;
    11971213
     
    13391355with_statement:
    13401356        WITH '(' tuple_expression_list ')' statement
    1341                 {
    1342                         $$ = new StatementNode( build_with( $3, $5 ) );
    1343                 }
     1357                { $$ = new StatementNode( build_with( $3, $5 ) ); }
    13441358        ;
    13451359
    13461360// If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex".
    13471361mutex_statement:
    1348         MUTEX '(' argument_expression_list_opt ')' statement
     1362        MUTEX '(' argument_expression_list ')' statement
    13491363                { $$ = new StatementNode( build_mutex( $3, $5 ) ); }
    13501364        ;
     
    24752489designation:
    24762490        designator_list ':'                                                                     // C99, CFA uses ":" instead of "="
    2477         | identifier ':'                                                                        // GCC, field name
     2491        | identifier_at ':'                                                                     // GCC, field name
    24782492                { $$ = new ExpressionNode( build_varref( $1 ) ); }
    24792493        ;
     
    24872501
    24882502designator:
    2489         '.' identifier                                                                          // C99, field name
     2503        '.' identifier_at                                                                       // C99, field name
    24902504                { $$ = new ExpressionNode( build_varref( $2 ) ); }
    24912505        | '[' push assignment_expression pop ']'                        // C99, single array element
     
    29192933
    29202934paren_identifier:
    2921         identifier
     2935        identifier_at
    29222936                { $$ = DeclarationNode::newName( $1 ); }
    29232937        | '(' paren_identifier ')'                                                      // redundant parenthesis
  • src/ResolvExpr/module.mk

    r94647b0 r7770cc8  
    6161      ResolvExpr/WidenMode.h
    6262
     63SRC += $(SRC_RESOLVEXPR) \
     64        ResolvExpr/AlternativePrinter.cc \
     65        ResolvExpr/AlternativePrinter.h \
     66        ResolvExpr/CandidatePrinter.cpp \
     67        ResolvExpr/CandidatePrinter.hpp
    6368
    64 SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc ResolvExpr/AlternativePrinter.h
    6569SRCDEMANGLE += $(SRC_RESOLVEXPR)
  • src/SymTab/Validate.cc

    r94647b0 r7770cc8  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:50:04 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 23:43:34 2019
    13 // Update Count     : 363
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Nov 12 11:00:00 2021
     13// Update Count     : 364
    1414//
    1515
     
    334334        };
    335335
    336         void validate( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug ) {
     336        void validate_A( std::list< Declaration * > & translationUnit ) {
    337337                PassVisitor<EnumAndPointerDecay_old> epc;
    338                 PassVisitor<LinkReferenceToTypes_old> lrt( nullptr );
    339                 PassVisitor<ResolveEnumInitializers> rei( nullptr );
    340                 PassVisitor<ForallPointerDecay_old> fpd;
    341                 PassVisitor<CompoundLiteral> compoundliteral;
    342                 PassVisitor<ValidateGenericParameters> genericParams;
    343                 PassVisitor<LabelAddressFixer> labelAddrFixer;
    344338                PassVisitor<HoistTypeDecls> hoistDecls;
    345                 PassVisitor<FixQualifiedTypes> fixQual;
    346 
    347339                {
    348340                        Stats::Heap::newPass("validate-A");
     
    354346                        acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling
    355347                }
     348        }
     349
     350        void validate_B( std::list< Declaration * > & translationUnit ) {
     351                PassVisitor<LinkReferenceToTypes_old> lrt( nullptr );
     352                PassVisitor<FixQualifiedTypes> fixQual;
    356353                {
    357354                        Stats::Heap::newPass("validate-B");
     
    362359                        EliminateTypedef::eliminateTypedef( translationUnit );
    363360                }
     361        }
     362
     363        void validate_C( std::list< Declaration * > & translationUnit ) {
     364                PassVisitor<ValidateGenericParameters> genericParams;
     365                PassVisitor<ResolveEnumInitializers> rei( nullptr );
    364366                {
    365367                        Stats::Heap::newPass("validate-C");
     
    381383                        });
    382384                }
     385        }
     386
     387        void validate_D( std::list< Declaration * > & translationUnit ) {
     388                PassVisitor<ForallPointerDecay_old> fpd;
    383389                {
    384390                        Stats::Heap::newPass("validate-D");
     
    397403                        });
    398404                }
     405        }
     406
     407        void validate_E( std::list< Declaration * > & translationUnit ) {
     408                PassVisitor<CompoundLiteral> compoundliteral;
    399409                {
    400410                        Stats::Heap::newPass("validate-E");
     
    415425                        }
    416426                }
     427        }
     428
     429        void validate_F( std::list< Declaration * > & translationUnit ) {
     430                PassVisitor<LabelAddressFixer> labelAddrFixer;
    417431                {
    418432                        Stats::Heap::newPass("validate-F");
     
    437451                        }
    438452                }
     453        }
     454
     455        void validate( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug ) {
     456                validate_A( translationUnit );
     457                validate_B( translationUnit );
     458                validate_C( translationUnit );
     459                validate_D( translationUnit );
     460                validate_E( translationUnit );
     461                validate_F( translationUnit );
    439462        }
    440463
  • src/SymTab/Validate.h

    r94647b0 r7770cc8  
    3535        void validateType( Type *type, const Indexer *indexer );
    3636
     37        // Sub-passes of validate.
     38        void validate_A( std::list< Declaration * > &translationUnit );
     39        void validate_B( std::list< Declaration * > &translationUnit );
     40        void validate_C( std::list< Declaration * > &translationUnit );
     41        void validate_D( std::list< Declaration * > &translationUnit );
     42        void validate_E( std::list< Declaration * > &translationUnit );
     43        void validate_F( std::list< Declaration * > &translationUnit );
     44
    3745        const ast::Type * validateType(
    3846                const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab );
  • src/Tuples/TupleExpansionNew.cpp

    r94647b0 r7770cc8  
    2121                void previsit( const ast::UntypedMemberExpr * ) { visit_children = false; }
    2222        const ast::Expr * postvisit( const ast::UntypedMemberExpr * memberExpr );
     23        };
     24        struct UniqueExprExpander final : public ast::WithDeclsToAdd<> {
     25                const ast::Expr * postvisit( const ast::UniqueExpr * unqExpr );
     26                std::map< int, ast::ptr<ast::Expr> > decls; // not vector, because order added may not be increasing order
    2327        };
    2428} // namespace
     
    6670        }
    6771} // namespace
     72
     73void expandUniqueExpr( ast::TranslationUnit & translationUnit ) {
     74        ast::Pass< UniqueExprExpander >::run( translationUnit );
     75}
     76
     77namespace {
     78        const ast::Expr * UniqueExprExpander::postvisit( const ast::UniqueExpr * unqExpr ) {
     79                const CodeLocation loc = unqExpr->location;
     80                const int id = unqExpr->id;
     81
     82                // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,
     83                // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.
     84                if ( ! decls.count( id ) ) {
     85                        ast::ptr< ast::Expr > assignUnq;
     86                        const ast::VariableExpr * var = unqExpr->var;
     87                        if ( unqExpr->object ) {
     88                                // an object was generated to represent this unique expression -- it should be added to the list of declarations now
     89                                declsToAddBefore.push_back( unqExpr->object.as< ast::Decl >() );
     90                                // deep copy required due to unresolved issues with UniqueExpr
     91                                assignUnq = ast::UntypedExpr::createAssign( loc, var, unqExpr->expr );
     92                        } else {
     93                                const auto commaExpr = unqExpr->expr.strict_as< ast::CommaExpr >();
     94                                assignUnq = commaExpr->arg1;
     95                        }
     96                        auto finished = new ast::ObjectDecl( loc, toString( "_unq", id, "_finished_" ), new ast::BasicType( ast::BasicType::Kind::Bool ),
     97                                new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) ), {}, ast::Linkage::Cforall );
     98                        declsToAddBefore.push_back( finished );
     99                        // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))
     100                        // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.
     101                        auto assignFinished = ast::UntypedExpr::createAssign( loc, new ast::VariableExpr( loc, finished ),
     102                                ast::ConstantExpr::from_int( loc, 1 ) );
     103                        auto condExpr = new ast::ConditionalExpr( loc, new ast::VariableExpr( loc, finished ), var,
     104                                new ast::CommaExpr( loc, new ast::CommaExpr( loc, assignUnq, assignFinished ), var ) );
     105                        condExpr->result = var->result;
     106                        condExpr->env = unqExpr->env;
     107                        decls[id] = condExpr;
     108                }
     109                //delete unqExpr;
     110                return ast::deepCopy(decls[id].get());
     111        }
     112} // namespace
    68113} // namespace Tuples
  • src/Tuples/Tuples.h

    r94647b0 r7770cc8  
    4646        /// replaces UniqueExprs with a temporary variable and one call
    4747        void expandUniqueExpr( std::list< Declaration * > & translationUnit );
     48        void expandUniqueExpr( ast::TranslationUnit & translationUnit );
    4849
    4950        /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types
  • src/Validate/FindSpecialDecls.h

    r94647b0 r7770cc8  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Aug 30 09:49:02 2018
    11 // Last Modified By : Rob Schluntz
    12 // Last Modified On : Thu Aug 30 09:51:12 2018
    13 // Update Count     : 2
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Nov 10 15:16:00 2021
     13// Update Count     : 3
    1414//
    1515
     
    2222class StructDecl;
    2323class Type;
     24
     25namespace ast {
     26        class TranslationUnit;
     27}
    2428
    2529namespace Validate {
     
    3842        /// find and remember some of the special declarations that are useful for generating code, so that they do not have to be discovered multiple times.
    3943        void findSpecialDecls( std::list< Declaration * > & translationUnit );
     44
     45/// find and remember some of the special declarations that are useful for
     46/// generating code, so that they do not have to be discovered multiple times.
     47void findGlobalDecls( ast::TranslationUnit & translationUnit );
     48
    4049} // namespace Validate
    4150
  • src/Validate/module.mk

    r94647b0 r7770cc8  
    1515###############################################################################
    1616
    17 SRC += Validate/HandleAttributes.cc Validate/HandleAttributes.h Validate/FindSpecialDecls.cc Validate/FindSpecialDecls.h
    18 SRCDEMANGLE += Validate/HandleAttributes.cc Validate/HandleAttributes.h Validate/FindSpecialDecls.cc Validate/FindSpecialDecls.h
     17SRC_VALIDATE = \
     18        Validate/HandleAttributes.cc \
     19        Validate/HandleAttributes.h \
     20        Validate/InitializerLength.cpp \
     21        Validate/InitializerLength.hpp \
     22        Validate/LabelAddressFixer.cpp \
     23        Validate/LabelAddressFixer.hpp \
     24        Validate/FindSpecialDeclsNew.cpp \
     25        Validate/FindSpecialDecls.cc \
     26        Validate/FindSpecialDecls.h
     27
     28SRC += $(SRC_VALIDATE)
     29SRCDEMANGLE += $(SRC_VALIDATE)
  • src/main.cc

    r94647b0 r7770cc8  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Henry Xue
    12 // Last Modified On : Mon Aug 23 15:42:08 2021
    13 // Update Count     : 650
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Nov 12 11:06:00 2021
     13// Update Count     : 658
    1414//
    1515
     
    4343#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    4444#include "Common/CompilerError.h"           // for CompilerError
     45#include "Common/DeclStats.hpp"             // for printDeclStats
     46#include "Common/ResolvProtoDump.hpp"       // for dumpAsResolverProto
    4547#include "Common/Stats.h"
    4648#include "Common/PassVisitor.h"
     
    5153#include "ControlStruct/ExceptDecl.h"       // for translateExcept
    5254#include "ControlStruct/ExceptTranslate.h"  // for translateEHM
     55#include "ControlStruct/FixLabels.hpp"      // for fixLabels
    5356#include "ControlStruct/Mutate.h"           // for mutate
    5457#include "GenPoly/Box.h"                    // for box
     
    6265#include "Parser/TypedefTable.h"            // for TypedefTable
    6366#include "ResolvExpr/AlternativePrinter.h"  // for AlternativePrinter
     67#include "ResolvExpr/CandidatePrinter.hpp"  // for printCandidates
    6468#include "ResolvExpr/Resolver.h"            // for resolve
    6569#include "SymTab/Validate.h"                // for validate
     
    6872#include "SynTree/Visitor.h"                // for acceptAll
    6973#include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
     74#include "Validate/FindSpecialDecls.h"      // for findGlobalDecls
     75#include "Validate/InitializerLength.hpp"   // for setLengthFromInitializer
     76#include "Validate/LabelAddressFixer.hpp"   // for fixLabelAddresses
    7077#include "Virtual/ExpandCasts.h"            // for expandCasts
    7178
     
    314321
    315322                // add the assignment statement after the initialization of a type parameter
    316                 PASS( "Validate", SymTab::validate( translationUnit, symtabp ) );
    317                 if ( symtabp ) {
    318                         deleteAll( translationUnit );
    319                         return EXIT_SUCCESS;
    320                 } // if
    321 
    322                 if ( expraltp ) {
    323                         PassVisitor<ResolvExpr::AlternativePrinter> printer( cout );
    324                         acceptAll( translationUnit, printer );
    325                         return EXIT_SUCCESS;
    326                 } // if
    327 
    328                 if ( validp ) {
    329                         dump( translationUnit );
    330                         return EXIT_SUCCESS;
    331                 } // if
    332 
    333                 PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) );
    334                 PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
    335                 PASS( "Fix Names", CodeGen::fixNames( translationUnit ) );
    336                 PASS( "Gen Init", InitTweak::genInit( translationUnit ) );
    337 
    338                 if ( libcfap ) {
    339                         // generate the bodies of cfa library functions
    340                         LibCfa::makeLibCfa( translationUnit );
    341                 } // if
    342 
    343                 if ( declstatsp ) {
    344                         CodeTools::printDeclStats( translationUnit );
    345                         deleteAll( translationUnit );
    346                         return EXIT_SUCCESS;
    347                 } // if
    348 
    349                 if ( bresolvep ) {
    350                         dump( translationUnit );
    351                         return EXIT_SUCCESS;
    352                 } // if
     323                PASS( "Validate-A", SymTab::validate_A( translationUnit ) );
     324                PASS( "Validate-B", SymTab::validate_B( translationUnit ) );
     325                PASS( "Validate-C", SymTab::validate_C( translationUnit ) );
     326                PASS( "Validate-D", SymTab::validate_D( translationUnit ) );
     327                PASS( "Validate-E", SymTab::validate_E( translationUnit ) );
    353328
    354329                CodeTools::fillLocations( translationUnit );
    355 
    356                 if ( resolvprotop ) {
    357                         CodeTools::dumpAsResolvProto( translationUnit );
    358                         return EXIT_SUCCESS;
    359                 } // if
    360330
    361331                if( useNewAST ) {
     
    366336                        auto transUnit = convert( move( translationUnit ) );
    367337
     338                        forceFillCodeLocations( transUnit );
     339
     340                        PASS( "Set Length From Initializer", Validate::setLengthFromInitializer( transUnit ) );
     341                        PASS( "Find Global Decls", Validate::findGlobalDecls( transUnit ) );
     342                        PASS( "Fix Label Address", Validate::fixLabelAddresses( transUnit ) );
     343
     344                        if ( symtabp ) {
     345                                return EXIT_SUCCESS;
     346                        } // if
     347
     348                        if ( expraltp ) {
     349                                ResolvExpr::printCandidates( transUnit );
     350                                return EXIT_SUCCESS;
     351                        } // if
     352
     353                        if ( validp ) {
     354                                dump( move( transUnit ) );
     355                                return EXIT_SUCCESS;
     356                        } // if
     357
     358                        PASS( "Translate Throws", ControlStruct::translateThrows( transUnit ) );
     359                        PASS( "Fix Labels", ControlStruct::fixLabels( transUnit ) );
     360                        PASS( "Fix Names", CodeGen::fixNames( transUnit ) );
     361                        PASS( "Gen Init", InitTweak::genInit( transUnit ) );
    368362                        PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) );
    369                        
     363
     364                        if ( libcfap ) {
     365                                // Generate the bodies of cfa library functions.
     366                                LibCfa::makeLibCfa( transUnit );
     367                        } // if
     368
     369                        if ( declstatsp ) {
     370                                printDeclStats( transUnit );
     371                                return EXIT_SUCCESS;
     372                        } // if
     373
     374                        if ( bresolvep ) {
     375                                dump( move( transUnit ) );
     376                                return EXIT_SUCCESS;
     377                        } // if
     378
     379                        if ( resolvprotop ) {
     380                                dumpAsResolverProto( transUnit );
     381                                return EXIT_SUCCESS;
     382                        } // if
     383
    370384                        PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    371385                        if ( exprp ) {
     
    377391
    378392                        PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
     393
     394                        // fix ObjectDecl - replaces ConstructorInit nodes
     395                        if ( ctorinitp ) {
     396                                dump( move( transUnit ) );
     397                                return EXIT_SUCCESS;
     398                        } // if
     399
     400                        // Currently not working due to unresolved issues with UniqueExpr
     401                        PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( transUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    379402                        translationUnit = convert( move( transUnit ) );
    380403                } else {
     404                        PASS( "Validate-F", SymTab::validate_F( translationUnit ) );
     405
     406                        if ( symtabp ) {
     407                                deleteAll( translationUnit );
     408                                return EXIT_SUCCESS;
     409                        } // if
     410
     411                        if ( expraltp ) {
     412                                PassVisitor<ResolvExpr::AlternativePrinter> printer( cout );
     413                                acceptAll( translationUnit, printer );
     414                                return EXIT_SUCCESS;
     415                        } // if
     416
     417                        if ( validp ) {
     418                                dump( translationUnit );
     419                                return EXIT_SUCCESS;
     420                        } // if
     421
     422                        PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) );
     423                        PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
     424                        PASS( "Fix Names", CodeGen::fixNames( translationUnit ) );
     425                        PASS( "Gen Init", InitTweak::genInit( translationUnit ) );
    381426                        PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( translationUnit ) );
     427
     428                        if ( libcfap ) {
     429                                // Generate the bodies of cfa library functions.
     430                                LibCfa::makeLibCfa( translationUnit );
     431                        } // if
     432
     433                        if ( declstatsp ) {
     434                                CodeTools::printDeclStats( translationUnit );
     435                                deleteAll( translationUnit );
     436                                return EXIT_SUCCESS;
     437                        } // if
     438
     439                        if ( bresolvep ) {
     440                                dump( translationUnit );
     441                                return EXIT_SUCCESS;
     442                        } // if
     443
     444                        CodeTools::fillLocations( translationUnit );
     445
     446                        if ( resolvprotop ) {
     447                                CodeTools::dumpAsResolvProto( translationUnit );
     448                                return EXIT_SUCCESS;
     449                        } // if
    382450
    383451                        PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
     
    388456
    389457                        PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
     458
     459                        // fix ObjectDecl - replaces ConstructorInit nodes
     460                        if ( ctorinitp ) {
     461                                dump ( translationUnit );
     462                                return EXIT_SUCCESS;
     463                        } // if
     464
     465                        PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    390466                }
    391 
    392                 // fix ObjectDecl - replaces ConstructorInit nodes
    393                 if ( ctorinitp ) {
    394                         dump ( translationUnit );
    395                         return EXIT_SUCCESS;
    396                 } // if
    397 
    398                 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    399467
    400468                PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) );
     
    443511                PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
    444512
    445                 CodeGen::FixMain::fix( *output, (PreludeDirector + "/bootloader.c").c_str() );
     513                CodeGen::FixMain::fix( translationUnit, *output,
     514                                (PreludeDirector + "/bootloader.c").c_str() );
    446515                if ( output != &cout ) {
    447516                        delete output;
  • tests/.expect/declarationSpecifier.x64.txt

    r94647b0 r7770cc8  
    11321132char **_X13cfa_args_argvPPc_1;
    11331133char **_X13cfa_args_envpPPc_1;
    1134 signed int _X17cfa_main_returnedi_1 = ((signed int )0);
     1134__attribute__ ((weak)) extern signed int _X17cfa_main_returnedi_1;
    11351135signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    11361136    __attribute__ ((unused)) signed int _X12_retval_maini_1;
     
    11491149    signed int _tmp_cp_ret6;
    11501150    signed int _X3reti_2 = (((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6);
    1151     {
    1152         ((void)(_X17cfa_main_returnedi_1=((signed int )1)));
     1151    if ( ((&_X17cfa_main_returnedi_1)!=((signed int *)0)) ) {
     1152        {
     1153            ((void)(_X17cfa_main_returnedi_1=((signed int )1)));
     1154        }
     1155
    11531156    }
    11541157
  • tests/.expect/declarationSpecifier.x86.txt

    r94647b0 r7770cc8  
    11321132char **_X13cfa_args_argvPPc_1;
    11331133char **_X13cfa_args_envpPPc_1;
    1134 signed int _X17cfa_main_returnedi_1 = ((signed int )0);
     1134__attribute__ ((weak)) extern signed int _X17cfa_main_returnedi_1;
    11351135signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){