Changeset cc287800


Ignore:
Timestamp:
Nov 8, 2021, 5:28:21 PM (23 months ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, ast-experimental, enum, forall-pointer-decay, master, pthread-emulation, qualifiedEnum
Children:
36a05d7
Parents:
949339b (diff), 5ee153d (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:
9 added
1 deleted
64 edited

Legend:

Unmodified
Added
Removed
  • benchmark/io/http/filecache.cfa

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    190190                        init_protocol();
    191191                        {
    192                                 Worker workers[options.clopts.nworkers];
     192                                Worker * workers = anew(options.clopts.nworkers);
    193193                                for(i; options.clopts.nworkers) {
    194194                                        // if( options.file_cache.fixed_fds ) {
     
    212212                                }
    213213                                sout | nl;
     214                                if(!options.interactive) park();
    214215                                {
    215216                                        char buffer[128];
     
    249250
    250251                                sout | "Stopping connection threads..." | nonl; flush( sout );
     252                                adelete(workers);
    251253                        }
    252254                        sout | "done";
  • benchmark/io/http/options.cfa

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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        // Did something crazy happen?
     335        if(this.f.result > this.len) {
     336                mutex(serr) serr | "SPLICE IN spliced too much!";
     337                return error(this.res, -ERANGE);
     338        }
     339
     340        // Something failed?
     341        if(this.f.result < 0) {
     342                int error = -this.f.result;
     343                if( error == ECONNRESET ) return error(this.res, -ECONNRESET);
     344                if( error == EPIPE ) return error(this.res, -EPIPE);
     345                if( error == ECANCELED ) {
     346                        mutex(serr) serr | "SPLICE IN was cancelled, WTF!";
     347                        return error(this.res, -ECONNRESET);
     348                }
     349                if( error == EAGAIN || error == EWOULDBLOCK) {
     350                        mutex(serr) serr | "SPLICE IN got eagain, WTF!";
     351                        return error(this.res, -ECONNRESET);
     352                }
     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        // Did something crazy happen?
     404        if(this.f.result > this.len) {
     405                mutex(serr) serr | "SPLICE OUT spliced too much!";
     406                return error(this.res, -ERANGE);
     407        }
     408
     409        // Something failed?
     410        if(this.f.result < 0) {
     411                int error = -this.f.result;
     412                if( error == ECONNRESET ) return error(this, -ECONNRESET);
     413                if( error == EPIPE ) return error(this, -EPIPE);
     414                if( error == ECANCELED ) {
     415                        this.f.result = 0;
     416                        goto SHORT_WRITE;
     417                }
     418                if( error == EAGAIN || error == EWOULDBLOCK) {
     419                        mutex(serr) serr | "SPLICE OUT got eagain, WTF!";
     420                        return error(this, -ECONNRESET);
     421                }
     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\nDate\r\nConnection: keep-alive\r\nContent-Length: 15\r\nContent-Type: text/html: %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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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/user/user.tex

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    183183                ctx.proc->io.pending = false;
    184184
    185                 ready_schedule_lock();
    186185                __cfa_io_drain( proc );
    187                 ready_schedule_unlock();
    188186                // for(i; 2) {
    189187                //      unsigned idx = proc->rdq.id + i;
     
    311309                // Make the sqes visible to the submitter
    312310                __atomic_store_n(sq.kring.tail, tail + have, __ATOMIC_RELEASE);
    313                 sq.to_submit++;
     311                sq.to_submit += have;
    314312
    315313                ctx->proc->io.pending = true;
    316314                ctx->proc->io.dirty   = true;
    317315                if(sq.to_submit > 30 || !lazy) {
     316                        ready_schedule_lock();
    318317                        __cfa_io_flush( ctx->proc );
     318                        ready_schedule_unlock();
    319319                }
    320320        }
  • libcfa/src/concurrency/io/types.hfa

    r949339b rcc287800  
    188188                return wait(this.self);
    189189        }
     190
     191        void reset( io_future_t & this ) {
     192                return reset(this.self);
     193        }
    190194}
  • libcfa/src/concurrency/kernel.cfa

    r949339b rcc287800  
    196196
    197197                        if( !readyThread ) {
     198                                ready_schedule_lock();
    198199                                __cfa_io_flush( this );
     200                                ready_schedule_unlock();
     201
    199202                                readyThread = __next_thread_slow( this->cltr );
    200203                        }
     
    277280
    278281                        if(this->io.pending && !this->io.dirty) {
     282                                ready_schedule_lock();
    279283                                __cfa_io_flush( this );
     284                                ready_schedule_unlock();
    280285                        }
    281286
     
    317322
    318323                                // Don't block if we are done
    319                                 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     324                                if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) {
     325                                        ready_schedule_unlock();
     326                                        break MAIN_LOOP;
     327                                }
    320328
    321329                                __STATS( __tls_stats()->ready.sleep.halts++; )
     
    939947                        /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
    940948                        /* paranoid */ verify( it->local_data->this_stats );
     949                        // __print_stats( it->local_data->this_stats, cltr->print_stats, "Processor", it->name, (void*)it );
    941950                        __tally_stats( cltr->stats, it->local_data->this_stats );
    942951                        it = &(*it)`next;
     
    948957                // this doesn't solve all problems but does solve many
    949958                // so it's probably good enough
     959                disable_interrupts();
    950960                uint_fast32_t last_size = ready_mutate_lock();
    951961
     
    955965                // Unlock the RWlock
    956966                ready_mutate_unlock( last_size );
     967                enable_interrupts();
    957968        }
    958969
  • libcfa/src/concurrency/kernel/startup.cfa

    r949339b rcc287800  
    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();
  • libcfa/src/concurrency/monitor.hfa

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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/Decl.hpp

    r949339b rcc287800  
    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;
  • src/AST/Pass.hpp

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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/porting.md

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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/ControlStruct/ExceptTranslate.cc

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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/GenInit.cc

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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/Parser/parser.yy

    r949339b rcc287800  
    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/main.cc

    r949339b rcc287800  
    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 : Mon Nov  8 11:42:00 2021
     13// Update Count     : 656
    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
     
    331334                } // if
    332335
    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
    353 
    354336                CodeTools::fillLocations( translationUnit );
    355 
    356                 if ( resolvprotop ) {
    357                         CodeTools::dumpAsResolvProto( translationUnit );
    358                         return EXIT_SUCCESS;
    359                 } // if
    360337
    361338                if( useNewAST ) {
     
    366343                        auto transUnit = convert( move( translationUnit ) );
    367344
     345                        forceFillCodeLocations( transUnit );
     346
     347                        PASS( "Translate Throws", ControlStruct::translateThrows( transUnit ) );
     348                        PASS( "Fix Labels", ControlStruct::fixLabels( transUnit ) );
     349                        PASS( "Fix Names", CodeGen::fixNames( transUnit ) );
     350                        PASS( "Gen Init", InitTweak::genInit( transUnit ) );
    368351                        PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) );
    369                        
     352
     353                        if ( libcfap ) {
     354                                // Generate the bodies of cfa library functions.
     355                                LibCfa::makeLibCfa( transUnit );
     356                        } // if
     357
     358                        if ( declstatsp ) {
     359                                printDeclStats( transUnit );
     360                                return EXIT_SUCCESS;
     361                        } // if
     362
     363                        if ( bresolvep ) {
     364                                dump( move( transUnit ) );
     365                                return EXIT_SUCCESS;
     366                        } // if
     367
     368                        if ( resolvprotop ) {
     369                                dumpAsResolverProto( transUnit );
     370                                return EXIT_SUCCESS;
     371                        } // if
     372
    370373                        PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    371374                        if ( exprp ) {
     
    377380
    378381                        PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
     382
    379383                        translationUnit = convert( move( transUnit ) );
    380384                } else {
     385                        PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) );
     386                        PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
     387                        PASS( "Fix Names", CodeGen::fixNames( translationUnit ) );
     388                        PASS( "Gen Init", InitTweak::genInit( translationUnit ) );
    381389                        PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( translationUnit ) );
     390
     391                        if ( libcfap ) {
     392                                // Generate the bodies of cfa library functions.
     393                                LibCfa::makeLibCfa( translationUnit );
     394                        } // if
     395
     396                        if ( declstatsp ) {
     397                                CodeTools::printDeclStats( translationUnit );
     398                                deleteAll( translationUnit );
     399                                return EXIT_SUCCESS;
     400                        } // if
     401
     402                        if ( bresolvep ) {
     403                                dump( translationUnit );
     404                                return EXIT_SUCCESS;
     405                        } // if
     406
     407                        CodeTools::fillLocations( translationUnit );
     408
     409                        if ( resolvprotop ) {
     410                                CodeTools::dumpAsResolvProto( translationUnit );
     411                                return EXIT_SUCCESS;
     412                        } // if
    382413
    383414                        PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
     
    443474                PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
    444475
    445                 CodeGen::FixMain::fix( *output, (PreludeDirector + "/bootloader.c").c_str() );
     476                CodeGen::FixMain::fix( translationUnit, *output,
     477                                (PreludeDirector + "/bootloader.c").c_str() );
    446478                if ( output != &cout ) {
    447479                        delete output;
  • tests/.expect/declarationSpecifier.x64.txt

    r949339b rcc287800  
    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

    r949339b rcc287800  
    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/gccExtensions.x64.txt

    r949339b rcc287800  
    324324char **_X13cfa_args_argvPPc_1;
    325325char **_X13cfa_args_envpPPc_1;
    326 signed int _X17cfa_main_returnedi_1 = ((signed int )0);
     326__attribute__ ((weak)) extern signed int _X17cfa_main_returnedi_1;
    327327signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    328328    __attribute__ ((unused)) signed int _X12_retval_maini_1;
     
    341341    signed int _tmp_cp_ret6;
    342342    signed int _X3reti_2 = (((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6);
    343     {
    344         ((void)(_X17cfa_main_returnedi_1=((signed int )1)));
     343    if ( ((&_X17cfa_main_returnedi_1)!=((signed int *)0)) ) {
     344        {
     345            ((void)(_X17cfa_main_returnedi_1=((signed int )1)));
     346        }
     347
    345348    }
    346349
  • tests/.expect/gccExtensions.x86.txt

    r949339b rcc287800  
    302302char **_X13cfa_args_argvPPc_1;
    303303char **_X13cfa_args_envpPPc_1;
    304 signed int _X17cfa_main_returnedi_1 = ((signed int )0);
     304__attribute__ ((weak)) extern signed int _X17cfa_main_returnedi_1;
    305305signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    306306    __attribute__ ((unused)) signed int _X12_retval_maini_1;
     
    319319    signed int _tmp_cp_ret6;
    320320    signed int _X3reti_2 = (((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6);
    321     {
    322         ((void)(_X17cfa_main_returnedi_1=((signed int )1)));
     321    if ( ((&_X17cfa_main_returnedi_1)!=((signed int *)0)) ) {
     322        {
     323            ((void)(_X17cfa_main_returnedi_1=((signed int )1)));
     324        }
     325
    323326    }
    324327
  • tests/concurrent/semaphore.cfa

    r949339b rcc287800  
    22#include <locks.hfa>
    33#include <thread.hfa>
     4#include <mutex_stmt.hfa>
    45
    56enum { num_blockers = 17, num_unblockers = 13 };
     
    2829                thrash();
    2930                P(ben);
    30                 if(((thread&)this).seqable.next != 0p) sout | acquire |"Link not invalidated";
     31                if(((thread&)this).seqable.next != 0p) mutex(sout) sout | "Link not invalidated";
    3132                thrash();
    3233        }
  • tests/concurrent/sleep.cfa

    r949339b rcc287800  
    11#include <fstream.hfa>
    22#include <thread.hfa>
     3#include <mutex_stmt.hfa>
    34#include <time.hfa>
    45
     
    2930
    3031int main() {
    31         sout | acquire | "start";
     32        mutex( sout ) sout | "start";
    3233        {
    3334                slow_sleeper slow;
     
    3637                yield();
    3738        }
    38         sout | acquire | "done";
     39        mutex( sout ) sout | "done";
    3940}
    4041
  • tests/io/io-acquire.cfa

    r949339b rcc287800  
    1010// Created On       : Mon Mar  1 18:40:09 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 11:49:34 2021
    13 // Update Count     : 18
     12// Last Modified On : Wed Oct  6 18:04:58 2021
     13// Update Count     : 72
    1414//
    1515
    1616#include <fstream.hfa>
    1717#include <thread.hfa>
     18#include <mutex_stmt.hfa>
    1819
    1920thread T {};
     
    2122        // output from parallel threads should not be scrambled
    2223
    23         for ( 100 ) {                                                                           // local protection
    24                 sout | acquire | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
     24        for ( 100 ) {                                                                           // expression protection
     25                mutex(sout) sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
    2526        }
    26         {                                                                                                       // global protection (RAII)
    27                 osacquire acq = { sout };
     27        mutex( sout ) {                                                                         // statement protection
    2828                for ( 100 ) {
    2929                        sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
     
    3131        }
    3232        {                                                                                                       // duplicate protection demonstrating recursive lock
    33                 osacquire acq = { sout };
    34                 for ( 100 ) {
    35                         osacquire acq = { sout };
    36                         sout | acquire | 1 | 2 | 3 | 4 | 5 | acquire | 6 | 7 | 8 | 9;
    37                         sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
     33                ofstream & h1( ofstream & os ) {                                // helper
     34                        mutex( os ) return os | 1 | 2 | 3 | 4;          // unnecessary mutex
     35                }
     36                ofstream & h2( ofstream & os ) {                                // helper
     37                        mutex( os ) return os | 6 | 7 | 8 | 9;          // unnecessary mutex
     38                }
     39                mutex( sout ) {                                                                 // unnecessary mutex
     40                        for ( 100 ) {
     41                                mutex( sout ) {
     42                                        sout | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
     43                                        sout | h1 | 5 | h2;                                     // refactored code
     44                                }
     45                        }
    3846                }
    3947        }
     
    4250
    4351        int a, b, c, d, e, f, g, h, i;
    44         for ( 100 ) {                                                                           // local protection
    45                 sin | acquire | a | b | c | d | e | f | g | h | i;
     52        for ( 100 ) {                                                                           // expression protection
     53                mutex(sin) sin | a | b | c | d | e | f | g | h | i;
    4654        }
    47         {                                                                                                       // global protection (RAII)
    48                 isacquire acq = { sin };
     55        mutex( sin ) {                                                                          // statement protection
    4956                for ( 100 ) {
    5057                        sin  | a | b | c | d | e | f | g | h | i;
     
    5259        }
    5360        {                                                                                                       // duplicate protection demonstrating recursive lock
    54                 isacquire acq = { sin };
    55                 for ( 100 ) {
    56                         isacquire acq = { sin };
    57                         sin | acquire | a | b | c | d | e | acquire | f | g | h | i;
    58                         sin | a | b | c | d | e | f | g | h | i;
     61                ifstream & h1( ifstream & is ) {                                // helper
     62                        mutex( is ) return is | a | b | c | d;          // unnecessary mutex
     63                }
     64                ifstream & h2( ifstream & is ) {                                // helper
     65                        mutex( is ) return is | f | g | h | i;          // unnecessary mutex
     66                }
     67                mutex( sin ) {                                                                  // unnecessary mutex
     68                        for ( 5 ) {
     69                                mutex( sin ) {
     70                                        sin  | a | b | c | d | e | f | g | h | i;
     71                                        sin  | h1 | e | h2;                                     // refactored code
     72                                }
     73                        }
    5974                }
    6075        }
  • tests/linking/io-acquire.cfa

    r949339b rcc287800  
    1717#include <fstream.hfa>
    1818#include <stdlib.hfa>
     19#include <mutex_stmt.hfa>
    1920
    2021int main() {
    2122        int i;
    2223        if(threading_enabled()) {
    23                 stdout | acquire | "YES";
     24                mutex( stdout ) stdout | "YES";
    2425                stdin | i;
    2526        } else {
    26                 stdout | acquire | "NO";
     27                mutex( stdout ) stdout | "NO";
    2728                stdin | i;
    2829        }
  • tests/pybin/test_run.py

    r949339b rcc287800  
    6565        def toString( cls, retcode, duration ):
    6666                if settings.generating :
    67                         if   retcode == TestResult.SUCCESS:     text = "Done   "
    68                         elif retcode == TestResult.TIMEOUT:     text = "TIMEOUT"
    69                         else :                                          text = "ERROR code %d" % retcode
     67                        if   retcode == TestResult.SUCCESS:     key = 'pass'; text = "Done   "
     68                        elif retcode == TestResult.TIMEOUT:     key = 'time'; text = "TIMEOUT"
     69                        else :  key = 'fail';   text = "ERROR code %d" % retcode
    7070                else :
    71                         if   retcode == TestResult.SUCCESS:     text = "PASSED "
    72                         elif retcode == TestResult.TIMEOUT:     text = "TIMEOUT"
    73                         else :                                          text = "FAILED with code %d" % retcode
     71                        if   retcode == TestResult.SUCCESS:     key = 'pass'; text = "PASSED "
     72                        elif retcode == TestResult.TIMEOUT:     key = 'time'; text = "TIMEOUT"
     73                        else :  key = 'fail';   text = "FAILED with code %d" % retcode
    7474
    7575                text += "    C%s - R%s" % (fmtDur(duration[0]), fmtDur(duration[1]))
    76                 return text
     76                return key, text
  • tests/test.py

    r949339b rcc287800  
    257257
    258258                # update output based on current action
    259                 result_txt = TestResult.toString( retcode, duration )
     259                result_key, result_txt = TestResult.toString( retcode, duration )
    260260
    261261                #print result with error if needed
     
    265265                        text = text + '\n' + error
    266266
    267                 return retcode == TestResult.SUCCESS, text
     267                return retcode == TestResult.SUCCESS, result_key, text
    268268        except KeyboardInterrupt:
    269                 return False, ""
     269                return False, 'keybrd', ""
    270270        # except Exception as ex:
    271271        #       print("Unexpected error in worker thread running {}: {}".format(t.target(), ex), file=sys.stderr)
     
    283283
    284284        failed = False
     285        rescnts = {     'pass': 0, 'fail': 0, 'time': 0, 'keybrd': 0 }
     286        other = 0
    285287
    286288        # for each test to run
     
    294296                )
    295297
    296                 for i, (succ, txt) in enumerate(timed(results, timeout = settings.timeout.total), 1) :
     298                for i, (succ, code, txt) in enumerate(timed(results, timeout = settings.timeout.total), 1) :
     299                        if code in rescnts.keys():
     300                                rescnts[code] += 1
     301                        else:
     302                                other += 1
     303
    297304                        if not succ :
    298305                                failed = True
     
    319326        # clean the workspace
    320327        make('clean', output_file=subprocess.DEVNULL, error=subprocess.DEVNULL)
     328
     329        print("{} passes, {} failures, {} timeouts, {} cancelled, {} other".format(rescnts['pass'], rescnts['fail'], rescnts['time'], rescnts['keybrd'], other))
    321330
    322331        return failed
     
    443452                        failed = run_tests(local_tests, options.jobs)
    444453                        if failed:
    445                                 result = 1
    446454                                if not settings.continue_:
    447455                                        break
Note: See TracChangeset for help on using the changeset viewer.