Changes in / [144fa5c:3b402339]


Ignore:
Files:
3 added
11 edited

Legend:

Unmodified
Added
Removed
  • benchmark/io/http/http_ring.cpp

    r144fa5c r3b402339  
    99#include <liburing.h>
    1010
    11 typedef enum {
    12         EVENT_END,
    13         EVENT_ACCEPT,
    14         EVENT_REQUEST,
    15         EVENT_ANSWER
    16 } event_t;
    17 
    18 struct __attribute__((aligned(128))) request_t {
    19         event_t type;
    20         int fd;
    21         size_t length;
    22         char * buff;
    23         char data[0];
    24 
    25         static struct request_t * create(event_t type, size_t extra) {
    26                 auto ret = (struct request_t *)malloc(sizeof(struct request_t) + extra);
    27                 ret->type = type;
    28                 ret->length = extra;
    29                 ret->buff = ret->data;
    30                 return ret;
    31         }
    32 
    33         static struct request_t * create(event_t type) {
    34                 return create(type, 0);
    35         }
    36 };
    37 
     11// #define NOBATCHING
     12// #define USE_ASYNC
     13
     14// Options passed to each threads
    3815struct __attribute__((aligned(128))) options_t {
     16        // Data passed to accept
    3917        struct {
    4018                int sockfd;
     
    4422        } acpt;
    4523
     24        // Termination notification
    4625        int endfd;
     26
     27        // The ring to use for io
    4728        struct io_uring * ring;
    48 
     29};
     30
     31//=========================================================
     32// General statistics
     33struct __attribute__((aligned(128))) stats_block_t {
    4934        struct {
    50                 size_t subs = 0;
    51                 size_t cnts = 0;
    52         } result;
     35                volatile size_t conns = 0;
     36                volatile size_t reads = 0;
     37                volatile size_t writes = 0;
     38                volatile size_t full_writes = 0;
     39        } completions;
     40
     41        struct {
     42                volatile size_t conns = 0;
     43                struct {
     44                        volatile size_t pipes = 0;
     45                        volatile size_t reset = 0;
     46                        volatile size_t other = 0;
     47                } requests;
     48
     49                struct {
     50                        volatile size_t pipes = 0;
     51                        volatile size_t reset = 0;
     52                        volatile size_t other = 0;
     53                } answers;
     54        } errors;
     55
     56        struct {
     57                volatile size_t current = 0;
     58                volatile size_t max = 0;
     59                volatile size_t used = 0;
     60        } conns;
     61
     62        volatile size_t recycle_errors = 0;
    5363};
    5464
     65// Each thread gets its own block of stats
     66// and there is a global block for tallying at the end
     67thread_local stats_block_t stats;
     68stats_block_t global_stats;
     69
     70// Get an array of current connections
     71// This is just for debugging, to make sure
     72// no two state-machines get the same fd
     73const size_t array_max = 25000;
     74class connection * volatile conns[array_max] = { 0 };
     75
     76// Max fd we've seen, keep track so it's convenient to adjust the array size after
     77volatile int max_fd = 0;
     78
    5579//=========================================================
     80// Some small wrappers for ring operations used outside the connection state machine
     81// get sqe + error handling
    5682static struct io_uring_sqe * get_sqe(struct io_uring * ring) {
    5783        struct io_uring_sqe * sqe = io_uring_get_sqe(ring);
     
    6389}
    6490
    65 static void submit(struct io_uring * ) {
    66         // io_uring_submit(ring);
    67 }
    68 
    69 //=========================================================
     91// read of the event fd is not done by a connection
     92// use nullptr as the user data
    7093static void ring_end(struct io_uring * ring, int fd, char * buffer, size_t len) {
    7194        struct io_uring_sqe * sqe = get_sqe(ring);
    7295        io_uring_prep_read(sqe, fd, buffer, len, 0);
    73         io_uring_sqe_set_data(sqe, request_t::create(EVENT_END));
    74         submit(ring);
     96        io_uring_sqe_set_data(sqe, nullptr);
     97        io_uring_submit(ring);
    7598}
    7699
    77 static void ring_accept(struct io_uring * ring, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
    78         auto req = request_t::create(EVENT_ACCEPT);
    79         struct io_uring_sqe * sqe = get_sqe(ring);
    80         io_uring_prep_accept(sqe, sockfd, addr, addrlen, flags);
    81         io_uring_sqe_set_data(sqe, req);
    82         submit(ring);
    83         // std::cout << "Submitted accept: " << req << std::endl;
    84 }
    85 
    86 static void ring_request(struct io_uring * ring, int fd) {
    87         size_t size = 1024;
    88         auto req = request_t::create(EVENT_REQUEST, size);
    89         req->fd = fd;
    90 
    91         struct io_uring_sqe * sqe = get_sqe(ring);
    92         io_uring_prep_read(sqe, fd, req->buff, size, 0);
    93         io_uring_sqe_set_data(sqe, req);
    94         submit(ring);
    95         // std::cout << "Submitted request: " << req << " (" << (void*)req->buffer << ")"<<std::endl;
    96 }
    97 
    98100//=========================================================
     101// All answers are fixed and determined by the return code
    99102enum HttpCode {
    100103        OK200 = 0,
     
    108111};
    109112
     113// Get a fix reply based on the return code
    110114const char * http_msgs[] = {
    111         "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: %zu \n\n%s",
    112         "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    113         "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    114         "HTTP/1.1 405 Method Not Allowed\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    115         "HTTP/1.1 408 Request Timeout\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    116         "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    117         "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     115        "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",
     116        "HTTP/1.1 400 Bad Request\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     117        "HTTP/1.1 404 Not Found\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     118        "HTTP/1.1 405 Method Not \r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     119        "HTTP/1.1 408 Request Timeout\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     120        "HTTP/1.1 413 Payload Too Large\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
     121        "HTTP/1.1 414 URI Too Long\r\nServer: HttoForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",
    118122};
    119 
    120 static_assert( KNOWN_CODES == (sizeof(http_msgs ) / sizeof(http_msgs [0])));
    121 
    122 const int http_codes[] = {
    123         200,
    124         400,
    125         404,
    126         405,
    127         408,
    128         413,
    129         414,
     123static_assert( KNOWN_CODES == (sizeof(http_msgs) / sizeof(http_msgs[0])) );
     124
     125// Pre-compute the length of these replys
     126const size_t http_lens[] = {
     127        strlen(http_msgs[0]),
     128        strlen(http_msgs[1]),
     129        strlen(http_msgs[2]),
     130        strlen(http_msgs[3]),
     131        strlen(http_msgs[4]),
     132        strlen(http_msgs[5]),
     133        strlen(http_msgs[6]),
    130134};
    131 
    132 static_assert( KNOWN_CODES == (sizeof(http_codes) / sizeof(http_codes[0])));
    133 
    134 int code_val(HttpCode code) {
    135         return http_codes[code];
    136 }
    137 
    138 static void ring_answer(struct io_uring * ring, int fd, HttpCode code) {
    139         size_t size = 256;
    140         auto req = request_t::create(EVENT_ANSWER, size);
    141         req->fd = fd;
    142 
    143         const char * fmt = http_msgs[code];
    144         const char * date = "";
    145         size = snprintf(req->buff, size, fmt, date, size);
    146 
    147         struct io_uring_sqe * sqe = get_sqe(ring);
    148         io_uring_prep_write(sqe, fd, req->buff, size, 0);
    149         io_uring_sqe_set_data(sqe, req);
    150         submit(ring);
    151         // std::cout << "Submitted good answer: " << req << " (" << (void*)req->buffer << ")"<<std::endl;
    152 }
    153 
    154 static void ring_answer(struct io_uring * ring, int fd, const std::string &) {
    155         // size_t size = 256;
    156         // auto req = request_t::create(EVENT_ANSWER, size);
    157         // req->fd = fd;
    158 
    159         // const char * fmt = http_msgs[OK200];
    160         // const char * date = "";
    161         // size_t len = snprintf(req->buffer, size, fmt, date, ans.size(), ans.c_str());
    162         // req->length = len;
    163 
    164         // struct io_uring_sqe * sqe = get_sqe(ring);
    165         // io_uring_prep_write(sqe, fd, req->buffer, len, 0);
    166         // io_uring_sqe_set_data(sqe, req);
    167         // submit(ring);
    168         // std::cout << "Submitted good answer: " << req << " (" << (void*)req->buffer << ")"<<std::endl;
    169 
    170 
    171         static const char* RESPONSE = "HTTP/1.1 200 OK\r\n" \
    172                                                 "Content-Length: 15\r\n" \
    173                                                 "Content-Type: text/html\r\n" \
    174                                                 "Connection: keep-alive\r\n" \
    175                                                 "Server: testserver\r\n" \
    176                                                 "\r\n" \
    177                                                 "Hello, World!\r\n";
    178 
    179         static const size_t RLEN = strlen(RESPONSE);
    180 
    181         size_t size = 256;
    182         auto req = request_t::create(EVENT_ANSWER, size);
    183         req->fd = fd;
    184         req->buff = (char*)RESPONSE;
    185         req->length = RLEN;
    186 
    187         // const char * fmt = http_msgs[OK200];
    188         // const char * date = "";
    189         // size_t len = snprintf(req->buffer, size, fmt, date, ans.size(), ans.c_str());
    190         // req->length = len;
    191 
    192         struct io_uring_sqe * sqe = get_sqe(ring);
    193         io_uring_prep_write(sqe, fd, RESPONSE, RLEN, 0);
    194         io_uring_sqe_set_data(sqe, req);
    195         submit(ring);
    196 }
     135static_assert( KNOWN_CODES == (sizeof(http_lens) / sizeof(http_lens[0])) );
    197136
    198137//=========================================================
    199 static void handle_new_conn(struct io_uring * ring, int fd) {
    200         if( fd < 0 ) {
    201                 int err = -fd;
    202                 if( err == ECONNABORTED ) return;
    203                 std::cerr << "accept error: (" << errno << ") " << strerror(errno) << std::endl;
    204                 exit(EXIT_FAILURE);
    205         }
    206 
    207         ring_request(ring, fd);
    208 }
    209 
    210 static void handle_request(struct io_uring * ring, struct request_t * in, int res) {
    211         if( res < 0 ) {
    212                 int err = -res;
    213                 switch(err) {
    214                         case EPIPE:
    215                         case ECONNRESET:
    216                                 close(in->fd);
    217                                 free(in);
     138// Finate state machine responsible for handling each connection
     139class __attribute__((aligned(128))) connection {
     140private:
     141        // The state of the machine
     142        enum {
     143                ACCEPTING,  // Accept sent waiting for connection
     144                REQUESTING, // Waiting for new request
     145                ANSWERING,  // Either request received submitting answer or short answer sent, need to submit rest
     146        } state;
     147
     148        // The file descriptor of the connection
     149        int fd;
     150
     151        // request data
     152        static const size_t buffer_size = 1024; // Size of the read buffer
     153        const char * buffer;                      // Buffer into which requests are read
     154
     155        // send data
     156        size_t to_send;         // Data left to send
     157        const char * iterator;  // Pointer to rest of the message to send
     158
     159        // stats
     160        // how many requests/answers were complete, that is, a valid cqe was obtained
     161        struct {
     162                size_t requests = 0;
     163                size_t answers = 0;
     164        } stats;
     165
     166private:
     167        connection()
     168                : state(ACCEPTING)
     169                , fd(0)
     170                , buffer( new char[buffer_size])
     171                , iterator(nullptr)
     172        {}
     173
     174        ~connection() {
     175                delete [] buffer;
     176                ::stats.conns.current--;
     177        }
     178
     179        // Close the current connection
     180        void close(int err) {
     181                // std::cout << "(" << this->stats.requests << "," << this->stats.answers << ", e" << err << ") ";
     182                conns[fd] = nullptr;
     183
     184                if(fd != 0) {
     185                        ::close(fd);
     186                }
     187                delete this;
     188        }
     189
     190        //--------------------------------------------------
     191        // Wrappers for submit so we can tweak it more easily
     192        static void submit(struct io_uring * ring, struct io_uring_sqe * sqe, connection * conn) {
     193                (void)ring;
     194                #ifdef USE_ASYNC
     195                        io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
     196                #endif
     197                io_uring_sqe_set_data(sqe, conn);
     198                #ifdef NOBATCHING
     199                        io_uring_submit(ring);
     200                #endif
     201        }
     202
     203        void submit(struct io_uring * ring, struct io_uring_sqe * sqe) {
     204                submit(ring, sqe, this);
     205        }
     206
     207        //--------------------------------------------------
     208        // get a new request from the client
     209        void request(struct io_uring * ring) {
     210                state = REQUESTING;
     211                struct io_uring_sqe * sqe = get_sqe(ring);
     212                io_uring_prep_recv(sqe, fd, (void*)buffer, buffer_size, 0);
     213                submit(ring, sqe);
     214        }
     215
     216        //--------------------------------------------------
     217        // Send a new answer based on a return code
     218        void answer(struct io_uring * ring, HttpCode code) {
     219                iterator = http_msgs[code];
     220                to_send  = http_lens[code];
     221                if(to_send != 124) {
     222                        std::cerr << "Answer has weird size: " << to_send << " (" << (int)code << ")" << std::endl;
     223                }
     224                answer(ring);
     225        }
     226
     227        // send a new answer to the client
     228        // Reused for incomplete writes
     229        void answer(struct io_uring * ring) {
     230                state = ANSWERING;
     231                struct io_uring_sqe * sqe = get_sqe(ring);
     232                io_uring_prep_send(sqe, fd, iterator, to_send, 0);
     233                submit(ring, sqe);
     234        }
     235
     236        //--------------------------------------------------
     237        // Handle a new connection, results for getting an cqe while in the ACCEPTING state
     238        void newconn(struct io_uring * ring, int ret) {
     239                // Check errors
     240                if( ret < 0 ) {
     241                        int err = -ret;
     242                        if( err == ECONNABORTED ) {
     243                                ::stats.errors.conns++;
     244                                this->close(err);
    218245                                return;
    219                         default:
    220                                 std::cerr << "request error: (" << err << ") " << strerror(err) << std::endl;
    221                                 exit(EXIT_FAILURE);
    222                 }
    223         }
    224 
    225         if(res == 0) {
    226                 close(in->fd);
    227                 free(in);
    228                 return;
    229         }
    230 
    231         const char * it = in->buff;
    232         if( !strstr( it, "\r\n\r\n" ) ) {
    233                 std::cout << "Incomplete request" << std::endl;
    234                 close(in->fd);
    235                 free(in);
    236                 return;
    237         }
    238 
    239         it = in->buff;
    240         const std::string reply = "Hello, World!\n";
    241         int ret = memcmp(it, "GET ", 4);
    242         if( ret != 0 ) {
    243                 ring_answer(ring, in->fd, E400);
    244                 goto NEXT;
    245         }
    246 
    247         it += 4;
    248         ret = memcmp(it, "/plaintext", 10);
    249         if( ret != 0 ) {
    250                 ring_answer(ring, in->fd, E404);
    251                 goto NEXT;
    252         }
    253 
    254         ring_answer(ring, in->fd, reply);
    255 
    256         NEXT:
    257                 ring_request(ring, in->fd);
    258                 return;
    259 }
    260 
    261 static void handle_answer(struct io_uring * ring, struct request_t * in, int res) {
    262         if( res < 0 ) {
    263                 int err = -res;
    264                 switch(err) {
    265                         case EPIPE:
    266                         case ECONNRESET:
    267                                 close(in->fd);
    268                                 free(in);
    269                                 return;
    270                         default:
    271                                 std::cerr << "answer error: (" << err << ") " << strerror(err) << std::endl;
    272                                 exit(EXIT_FAILURE);
    273                 }
    274         }
    275 
    276         if( res >= in->length ) {
    277                 free(in);
    278                 return;
    279         }
    280 
    281         struct io_uring_sqe * sqe = get_sqe(ring);
    282         io_uring_prep_write(sqe, in->fd, in->buff + res, in->length - res, 0);
    283         io_uring_sqe_set_data(sqe, in);
    284         submit(ring);
    285         // std::cout << "Re-Submitted request: " << in << " (" << (void*)in->buffer << ")"<<std::endl;
    286 
    287         ring_request(ring, in->fd);
    288 }
     246                        }
     247                        std::cerr << "accept error: (" << errno << ") " << strerror(errno) << std::endl;
     248                        exit(EXIT_FAILURE);
     249                }
     250
     251                // Count the connections
     252                ::stats.completions.conns++;
     253                ::stats.conns.current++;
     254                if(::stats.conns.current > ::stats.conns.max) {
     255                        ::stats.conns.max = ::stats.conns.current;
     256                }
     257
     258                // Read on the data
     259                fd = ret;
     260                request(ring);
     261
     262                // check the max fd so we know if we exceeded the array
     263                for(;;) {
     264                        int expected = max_fd;
     265                        if(expected >= fd) return;
     266                        if( __atomic_compare_exchange_n(&max_fd, &expected, fd, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) return;
     267                }
     268
     269                // check if we have enough space to fit inside the array
     270                if(fd >= array_max) {
     271                        std::cerr << "accept error: fd " << fd << " is too high" << std::endl;
     272                        return;
     273                }
     274
     275                // Put our connection into the global array
     276                // No one else should be using it so if they are that's a bug
     277                auto exist = __atomic_exchange_n( &conns[fd], this, __ATOMIC_SEQ_CST);
     278                if( exist ) {
     279                        size_t first = __atomic_fetch_add(&global_stats.recycle_errors, 1, __ATOMIC_SEQ_CST);
     280                        if( first == 0 ) {
     281                                std::cerr << "First: accept has existing connection " << std::endl;
     282                        }
     283                }
     284        }
     285
     286        // Handle a new request, results for getting an cqe while in the REQUESTING state
     287        void newrequest(struct io_uring * ring, int res) {
     288                // Check errors
     289                if( res < 0 ) {
     290                        int err = -res;
     291                        switch(err) {
     292                                case EPIPE:
     293                                        ::stats.errors.requests.pipes++;
     294                                        break;
     295                                        // Don't fall through the get better stats
     296                                case ECONNRESET:
     297                                        ::stats.errors.requests.reset++;
     298                                        break;
     299                                default:
     300                                        ::stats.errors.requests.other++;
     301                                        std::cerr << "request error: (" << err << ") " << strerror(err) << std::endl;
     302                                        exit(EXIT_FAILURE);
     303                        }
     304
     305                        // Connection failed, close it
     306                        this->close(err);
     307                        return;
     308                }
     309
     310                // Update stats
     311                ::stats.completions.reads++;
     312
     313                // Is this an EOF
     314                if(res == 0) {
     315                        // Yes, close the connection
     316                        this->close(0);
     317                        return;
     318                }
     319
     320                // Find the end of the request header
     321                const char * it = buffer;
     322                if( !strstr( it, "\r\n\r\n" ) ) {
     323                        // This state machine doesn't support incomplete reads
     324                        // Print them to output so it's clear there is an issue
     325                        std::cout << "Incomplete request" << std::endl;
     326                        this->close(EBADR);
     327                        return;
     328                }
     329
     330                // Find the method to use
     331                it = buffer;
     332                int ret = memcmp(it, "GET ", 4);
     333                if( ret != 0 ) {
     334                        // We only support get, answer with an error
     335                        answer(ring, E400);
     336                        return;
     337                }
     338
     339                // Find the target
     340                it += 4;
     341                ret = memcmp(it, "/plaintext", 10);
     342                if( ret != 0 ) {
     343                        // We only support /plaintext, answer with an error
     344                        answer(ring, E404);
     345                        return;
     346                }
     347
     348                // Correct request, answer with the payload
     349                this->stats.requests++;
     350                answer(ring, OK200);
     351        }
     352
     353        // Handle a partial or full answer sent, results for getting an cqe while in the ANSWERING state
     354        void writedone(struct io_uring * ring, int res) {
     355                // Check errors
     356                if( res < 0 ) {
     357                        int err = -res;
     358                        switch(err) {
     359                                case EPIPE:
     360                                        ::stats.errors.answers.pipes++;
     361                                        break;
     362                                        // Don't fall through the get better stats
     363                                case ECONNRESET:
     364                                        ::stats.errors.answers.reset++;
     365                                        break;
     366                                default:
     367                                        ::stats.errors.answers.other++;
     368                                        std::cerr << "answer error: (" << err << ") " << strerror(err) << std::endl;
     369                                        exit(EXIT_FAILURE);
     370                        }
     371
     372                        this->close(err);
     373                        return;
     374                }
     375
     376                // Update stats
     377                ::stats.completions.writes++;
     378                if(res == 124) ::stats.completions.full_writes++;
     379
     380                // Is this write completed
     381                if( res == to_send ) {
     382                        // Yes, more stats
     383                        this->stats.answers++;
     384                        if(this->stats.answers == 1) ::stats.conns.used++;
     385                        // Then read a new request
     386                        request(ring);
     387                        return;
     388                }
     389
     390                // Not a completed read, push the rest
     391                to_send -= res;
     392                iterator += res;
     393                answer(ring);
     394        }
     395public:
     396        // Submit a call to accept and create a new connection object
     397        static void accept(struct io_uring * ring, const struct options_t & opt) {
     398                struct io_uring_sqe * sqe = get_sqe(ring);
     399                io_uring_prep_accept(sqe, opt.acpt.sockfd, opt.acpt.addr, opt.acpt.addrlen, opt.acpt.flags);
     400                submit(ring, sqe, new connection());
     401                // std::cout << "Submitted accept: " << req << std::endl;
     402        }
     403
     404        // Handle a new cqe
     405        void handle(struct io_uring * ring, int res, const struct options_t & opt) {
     406                switch(state) {
     407                case ACCEPTING:
     408                        connection::accept(ring, opt);
     409                        newconn(ring, res);
     410                        break;
     411                case REQUESTING:
     412                        newrequest(ring, res);
     413                        break;
     414                case ANSWERING:
     415                        writedone(ring, res);
     416                        break;
     417                }
     418        }
     419};
    289420
    290421//=========================================================
    291 extern "C" {
    292 extern int __io_uring_flush_sq(struct io_uring *ring);
    293 }
    294 
     422// Main loop of the WebServer
     423// Effectively uses one thread_local copy of everything per kernel thread
    295424void * proc_loop(void * arg) {
    296         size_t count = 0;
     425        // Get the thread local argument
    297426        struct options_t & opt = *(struct options_t *)arg;
    298 
    299427        struct io_uring * ring = opt.ring;
    300428
     429        // Track the shutdown using a event_fd
    301430        char endfd_buf[8];
    302431        ring_end(ring, opt.endfd, endfd_buf, 8);
    303432
    304         ring_accept(ring, opt.acpt.sockfd, opt.acpt.addr, opt.acpt.addrlen, opt.acpt.flags);
    305 
    306         bool done = false;
     433        // Accept our first connection
     434        // May not take effect until io_uring_submit_and_wait
     435        connection::accept(ring, opt);
     436
     437        int reset = 1;       // Counter to print stats once in a while
     438        bool done = false;   // Are we done
     439        size_t sqes = 0;     // Number of sqes we submitted
     440        size_t call = 0;     // Number of submits we made
    307441        while(!done) {
    308                 struct io_uring_cqe *cqe;
    309                 int ret;
    310                 while(-EAGAIN == (ret = io_uring_wait_cqe_nr(ring, &cqe, 0))) {
    311                         ret = io_uring_submit_and_wait(ring, 1);
    312                         if (ret < 0) {
    313                                 fprintf( stderr, "io_uring get error: (%d) %s\n", (int)-ret, strerror(-ret) );
    314                                 exit(EXIT_FAILURE);
    315                         }
    316                         opt.result.subs += ret;
    317                         opt.result.cnts++;
    318                 }
    319 
    320                 if (ret < 0 && -EAGAIN != ret) {
    321                         fprintf( stderr, "io_uring peek error: (%d) %s\n", (int)-ret, strerror(-ret) );
     442                // Submit all the answers we have and wait for responses
     443                int ret = io_uring_submit_and_wait(ring, 1);
     444
     445                // check errors
     446                if (ret < 0) {
     447                        fprintf( stderr, "io_uring S&W error: (%d) %s\n", (int)-ret, strerror(-ret) );
    322448                        exit(EXIT_FAILURE);
    323449                }
    324450
    325                 auto req = (struct request_t *)cqe->user_data;
    326                 // std::cout << req << " completed with " << cqe->res << std::endl;
    327 
    328                 switch(req->type) {
    329                         case EVENT_END:
     451                // Check how good we are at batching sqes
     452                sqes += ret;
     453                call++;
     454
     455                struct io_uring_cqe *cqe;
     456                unsigned head;
     457                unsigned count = 0;
     458
     459                // go through all cqes
     460                io_uring_for_each_cqe(ring, head, cqe) {
     461                        if (0 == cqe->user_data) {
    330462                                done = true;
    331463                                break;
    332                         case EVENT_ACCEPT:
    333                                 handle_new_conn(ring, cqe->res);
    334                                 free(req);
    335                                 ring_accept(ring, opt.acpt.sockfd, opt.acpt.addr, opt.acpt.addrlen, opt.acpt.flags);
    336                                 break;
    337                         case EVENT_REQUEST:
    338                                 handle_request(ring, req, cqe->res);
    339                                 break;
    340                         case EVENT_ANSWER:
    341                                 handle_answer(ring, req, cqe->res);
    342                                 break;
    343                 }
    344 
    345                 io_uring_cqe_seen(ring, cqe);
    346         }
    347 
    348         return (void*)count;
     464                        }
     465
     466                        auto req = (class connection *)cqe->user_data;
     467                        req->handle( ring, cqe->res, opt );
     468
     469                        // Every now and then, print some stats
     470                        reset--;
     471                        if(reset == 0) {
     472                                std::cout << "Submit average: " << sqes << "/" << call << "(" << (((double)sqes) / call) << ")" << std::endl;
     473                                // Reset to some random number of completions
     474                                // use the ring_fd in the number of threads don't all print at once
     475                                reset = 100000 + (100000 * (ring->ring_fd % 5));
     476                        }
     477
     478                        // Keep track of how many cqes we have seen
     479                        count++;
     480                }
     481
     482                // Mark the cqes as seen
     483                io_uring_cq_advance(ring, count);
     484        }
     485
     486        // Tally all the thread local statistics
     487        __atomic_fetch_add( &global_stats.completions.conns, ::stats.completions.conns, __ATOMIC_SEQ_CST );
     488        __atomic_fetch_add( &global_stats.completions.reads, ::stats.completions.reads, __ATOMIC_SEQ_CST );
     489        __atomic_fetch_add( &global_stats.completions.writes, ::stats.completions.writes, __ATOMIC_SEQ_CST );
     490        __atomic_fetch_add( &global_stats.completions.full_writes, ::stats.completions.full_writes, __ATOMIC_SEQ_CST );
     491        __atomic_fetch_add( &global_stats.errors.conns, ::stats.errors.conns, __ATOMIC_SEQ_CST );
     492        __atomic_fetch_add( &global_stats.errors.requests.pipes, ::stats.errors.requests.pipes, __ATOMIC_SEQ_CST );
     493        __atomic_fetch_add( &global_stats.errors.requests.reset, ::stats.errors.requests.reset, __ATOMIC_SEQ_CST );
     494        __atomic_fetch_add( &global_stats.errors.requests.other, ::stats.errors.requests.other, __ATOMIC_SEQ_CST );
     495        __atomic_fetch_add( &global_stats.errors.answers.pipes, ::stats.errors.answers.pipes, __ATOMIC_SEQ_CST );
     496        __atomic_fetch_add( &global_stats.errors.answers.reset, ::stats.errors.answers.reset, __ATOMIC_SEQ_CST );
     497        __atomic_fetch_add( &global_stats.errors.answers.other, ::stats.errors.answers.other, __ATOMIC_SEQ_CST );
     498        __atomic_fetch_add( &global_stats.conns.current, ::stats.conns.current, __ATOMIC_SEQ_CST );
     499        __atomic_fetch_add( &global_stats.conns.max, ::stats.conns.max, __ATOMIC_SEQ_CST );
     500        __atomic_fetch_add( &global_stats.conns.used, ::stats.conns.used, __ATOMIC_SEQ_CST );
     501
     502        return nullptr;
    349503}
    350504
    351505//=========================================================
    352 struct __attribute__((aligned(128))) aligned_ring {
    353         struct io_uring storage;
    354 };
    355 
    356 #include <bit>
    357 
    358 #include <pthread.h>
     506#include <bit> // for ispow2
     507
    359508extern "C" {
    360         #include <signal.h>
    361         #include <sys/eventfd.h>
    362         #include <sys/socket.h>
    363         #include <netinet/in.h>
     509        #include <pthread.h>      // for pthreads
     510        #include <signal.h>       // for signal(SIGPIPE, SIG_IGN);
     511        #include <sys/eventfd.h>  // use for termination
     512        #include <sys/socket.h>   // for sockets in general
     513        #include <netinet/in.h>   // for sockaddr_in, AF_INET
    364514}
    365515
    366516int main(int argc, char * argv[]) {
     517        // Initialize the array of connection-fd associations
     518        for(int i = 0; i < array_max; i++) {
     519                conns[i] = nullptr;
     520        }
     521
     522        // Make sure we ignore all sigpipes
    367523        signal(SIGPIPE, SIG_IGN);
    368524
    369         unsigned nthreads = 1;
    370         unsigned port = 8800;
    371         unsigned entries = 256;
    372         unsigned backlog = 10;
    373         bool attach = false;
     525        // Default command line arguments
     526        unsigned nthreads = 1;      // number of kernel threads
     527        unsigned port = 8800;       // which port to listen on
     528        unsigned entries = 256;     // number of entries per ring/kernel thread
     529        unsigned backlog = 262144;  // backlog argument to listen
     530        bool attach = false;        // Whether or not to attach all the rings
     531        bool sqpoll = false;        // Whether or not to use SQ Polling
    374532
    375533        //===================
    376         // Arguments
     534        // Arguments Parsing
    377535        int c;
    378         while ((c = getopt (argc, argv, "t:p:e:b:a")) != -1) {
     536        while ((c = getopt (argc, argv, "t:p:e:b:aS")) != -1) {
    379537                switch (c)
    380538                {
     
    394552                        attach = true;
    395553                        break;
     554                case 'S':
     555                        sqpoll = true;
     556                        break;
    396557                case '?':
    397558                default:
    398                         std::cerr << "Usage: -t <threads> -p <port> -e <entries> -b <backlog> -a" << std::endl;
     559                        std::cerr << "Usage: -t <threads> -p <port> -e <entries> -b <backlog> -aS" << std::endl;
    399560                        return EXIT_FAILURE;
    400561                }
     
    416577        //===================
    417578        // End FD
     579        // Create a single event fd to notify the kernel threads when the server shutsdown
    418580        int efd = eventfd(0, EFD_SEMAPHORE);
    419581        if (efd < 0) {
     
    424586        //===================
    425587        // Open Socket
     588        // Listen on specified port
    426589        std::cout << getpid() << " : Listening on port " << port << std::endl;
    427590        int server_fd = socket(AF_INET, SOCK_STREAM, 0);
     
    439602        address.sin_port = htons( port );
    440603
     604        // In case the port is already in use, don't just return an error
     605        // Linux is very slow at reclaiming port so just retry regularly
    441606        int waited = 0;
    442607        while(true) {
     
    444609                if(ret < 0) {
    445610                        if(errno == EADDRINUSE) {
     611                                // Port is in used let's retry later
    446612                                if(waited == 0) {
    447613                                        std::cerr << "Waiting for port" << std::endl;
    448614                                } else {
     615                                        // To be cure, print how long we have been waiting
    449616                                        std::cerr << "\r" << waited;
    450617                                        std::cerr.flush();
    451618                                }
    452619                                waited ++;
    453                                 usleep( 1000000 );
     620                                usleep( 1000000 ); // Wait and retry
    454621                                continue;
    455622                        }
     623                        // Some other error occured, this is a real error
    456624                        std::cerr << "bind error: (" << errno << ") " << strerror(errno) << std::endl;
    457625                        exit(EXIT_FAILURE);
     
    474642        std::cout << std::endl;
    475643
     644        // Create the desired number of kernel-threads and for each
     645        // create a ring. Create the rings in the main so we can attach them
     646        // Since the rings are all in a dense VLA, aligned them so we don't get false sharing
     647        // it's unlikely but better safe than sorry
     648        struct __attribute__((aligned(128))) aligned_ring {
     649                struct io_uring storage;
     650        };
    476651        aligned_ring thrd_rings[nthreads];
    477652        pthread_t    thrd_hdls[nthreads];
    478653        options_t    thrd_opts[nthreads];
     654        bool no_drops  = true;
     655        bool fast_poll = true;
     656        bool nfix_sqpl = true;
    479657        for(unsigned i = 0; i < nthreads; i++) {
    480                 if(!attach || i == 0) {
    481                         io_uring_queue_init(entries, &thrd_rings[i].storage, 0);
    482                 }
    483                 else {
    484                         struct io_uring_params p;
    485                         memset(&p, 0, sizeof(p));
    486                         p.flags = IORING_SETUP_ATTACH_WQ;
     658                struct io_uring_params p = { };
     659
     660                if(sqpoll) { // If sqpoll is on, add the flag
     661                        p.flags |= IORING_SETUP_SQPOLL;
     662                        p.sq_thread_idle = 100;
     663                }
     664
     665                if (attach && i != 0) { // If attach is on, add the flag, except for the first ring
     666                        p.flags |= IORING_SETUP_ATTACH_WQ;
    487667                        p.wq_fd = thrd_rings[0].storage.ring_fd;
    488                         io_uring_queue_init_params(entries, &thrd_rings[i].storage, &p);
    489                 }
    490 
     668                }
     669
     670                // Create the ring
     671                io_uring_queue_init_params(entries, &thrd_rings[i].storage, &p);
     672
     673                // Check if some of the note-worthy features are there
     674                if(0 == (p.features & IORING_FEAT_NODROP         )) { no_drops  = false; }
     675                if(0 == (p.features & IORING_FEAT_FAST_POLL      )) { fast_poll = false; }
     676                if(0 == (p.features & IORING_FEAT_SQPOLL_NONFIXED)) { nfix_sqpl = false; }
     677
     678                // Write the socket options we want to the options we pass to the threads
    491679                thrd_opts[i].acpt.sockfd  = server_fd;
    492680                thrd_opts[i].acpt.addr    = (struct sockaddr *)&address;
     
    502690                }
    503691        }
     692
     693        // Tell the user if the features are present
     694        if( no_drops ) std::cout << "No Drop Present" << std::endl;
     695        if( fast_poll) std::cout << "Fast Poll Present" << std::endl;
     696        if(!nfix_sqpl) std::cout << "Non-Fixed SQ Poll not Present" << std::endl;
    504697
    505698        //===================
     
    510703                int ret;
    511704                do {
     705                        // Wait for a Ctrl-D to close the server
    512706                        ret = read(STDIN_FILENO, buffer, 128);
    513707                        if(ret < 0) {
     
    526720
    527721        //===================
     722        // Use eventfd_write to tell the threads we are closing
    528723        (std::cout << "Sending Shutdown to Threads... ").flush();
    529724        ret = eventfd_write(efd, nthreads);
     
    535730
    536731        //===================
     732        // Join all the threads and close the rings
    537733        (std::cout << "Stopping Threads Done... ").flush();
    538         size_t total = 0;
    539         size_t count = 0;
    540734        for(unsigned i = 0; i < nthreads; i++) {
    541735                void * retval;
     
    545739                        exit(EXIT_FAILURE);
    546740                }
    547                 // total += (size_t)retval;
    548                 total += thrd_opts[i].result.subs;
    549                 count += thrd_opts[i].result.cnts;
    550741
    551742                io_uring_queue_exit(thrd_opts[i].ring);
    552743        }
    553744        std::cout << "done" << std::endl;
    554         std::cout << "Submit average: " << total << "/" << count << "(" << (((double)total) / count) << ")" << std::endl;
    555745
    556746        //===================
     747        // Close the sockets
    557748        (std::cout << "Closing Socket... ").flush();
    558749        ret = shutdown( server_fd, SHUT_RD );
     
    567758                exit(EXIT_FAILURE);
    568759        }
    569         std::cout << "done" << std::endl;
     760        std::cout << "done" << std::endl << std::endl;
     761
     762        // Print stats and exit
     763        std::cout << "Errors: " << global_stats.errors.conns << "c, (" << global_stats.errors.requests.pipes << "p, " << global_stats.errors.requests.reset << "r, " << global_stats.errors.requests.other << "o" << ")r, (" << global_stats.errors.answers.pipes << "p, " << global_stats.errors.answers.reset << "r, " << global_stats.errors.answers.other << "o" << ")a" << std::endl;
     764        std::cout << "Completions: " << global_stats.completions.conns << "c, " << global_stats.completions.reads << "r, " << global_stats.completions.writes << "w" << std::endl;
     765        std::cout << "Full Writes: " << global_stats.completions.full_writes << std::endl;
     766        std::cout << "Max FD: " << max_fd << std::endl;
     767        std::cout << "Successful connections: " << global_stats.conns.used << std::endl;
     768        std::cout << "Max concurrent connections: " << global_stats.conns.max << std::endl;
     769        std::cout << "Accepts on non-zeros: " << global_stats.recycle_errors << std::endl;
     770        std::cout << "Leaked conn objects: " << global_stats.conns.current << std::endl;
    570771}
     772
     773// compile-command: "g++ http_ring.cpp -std=c++2a -pthread -luring -O3" //
  • doc/theses/andrew_beach_MMath/existing.tex

    r144fa5c r3b402339  
    1212obvious to the reader.
    1313
    14 \section{\texorpdfstring{Overloading and \lstinline|extern|}{Overloading and extern}}
     14\section{\texorpdfstring{Overloading and \lstinline|extern|}
     15         {Overloading and extern}}
    1516\CFA has extensive overloading, allowing multiple definitions of the same name
    1617to be defined.~\cite{Moss18}
  • doc/theses/andrew_beach_MMath/features.tex

    r144fa5c r3b402339  
    77Virtual types and casts are not required for a basic exception-system but are
    88useful for advanced exception features. However, \CFA is not object-oriented so
    9 there is no obvious concept of virtuals.  Hence, to create advanced exception
     9there is no obvious concept of virtuals. Hence, to create advanced exception
    1010features for this work, I needed to designed and implemented a virtual-like
    1111system for \CFA.
     
    3030\end{center}
    3131The hierarchy provides the ability to handle an exception at different degrees
    32 of specificity (left to right).  Hence, it is possible to catch a more general
     32of specificity (left to right). Hence, it is possible to catch a more general
    3333exception-type in higher-level code where the implementation details are
    3434unknown, which reduces tight coupling to the lower-level implementation.
     
    7878
    7979Exceptions are defined by the trait system; there are a series of traits, and
    80 if a type satisfies them, then it can be used as an exception.  The following
     80if a type satisfies them, then it can be used as an exception. The following
    8181is the base trait all exceptions need to match.
    8282\begin{cfa}
     
    9292\PAB{I do not understand this paragraph.}
    9393One odd thing about @get_exception_vtable@ is that it should always be a
    94 constant function, returning the same value regardless of its argument.  A
     94constant function, returning the same value regardless of its argument. A
    9595pointer or reference to the virtual table instance could be used instead,
    9696however using a function has some ease of implementation advantages and allows
    9797for easier disambiguation because the virtual type name (or the address of an
    9898instance that is in scope) can be used instead of the mangled virtual table
    99 name.  Also note the use of the word ``promise'' in the trait
     99name. Also note the use of the word ``promise'' in the trait
    100100description. Currently, \CFA cannot check to see if either @exceptT@ or
    101101@virtualT@ match the layout requirements. This is considered part of
     
    126126
    127127Finally there are three convenience macros for referring to the these traits:
    128 @IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@ and @IS_RESUMPTION_EXCEPTION@.  Each
     128@IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@ and @IS_RESUMPTION_EXCEPTION@. Each
    129129takes the virtual type's name, and for polymorphic types only, the
    130130parenthesized list of polymorphic arguments. These macros do the name mangling
     
    212212expression has a type with a @void defaultResumptionHandler(T &)@ (default
    213213handler) defined, where the handler is found at the call site by the type
    214 system.  At runtime, a representation of the exception type and an instance of
     214system. At runtime, a representation of the exception type and an instance of
    215215the exception type is \emph{not} copied because the stack is maintained during
    216216the handler search.
     
    306306exception matches, @CONDITION@ is executed. The condition expression may
    307307reference all names in scope at the beginning of the try block and @NAME@
    308 introduced in the handler clause.  If the condition is true, then the handler
     308introduced in the handler clause. If the condition is true, then the handler
    309309matches. Otherwise, the exception search continues at the next appropriate kind
    310310of handler clause in the try block.
     
    359359the end of the block. This requirement ensures always continues as if the
    360360finally clause is not present, \ie finally is for cleanup not changing control
    361 flow.  Because of this requirement, local control flow out of the finally block
    362 is forbidden.  The compiler precludes any @break@, @continue@, @fallthru@ or
     361flow. Because of this requirement, local control flow out of the finally block
     362is forbidden. The compiler precludes any @break@, @continue@, @fallthru@ or
    363363@return@ that causes control to leave the finally block. Other ways to leave
    364364the finally block, such as a long jump or termination are much harder to check,
     
    371371
    372372There is no special statement for starting a cancellation; instead the standard
    373 library function @cancel_stack@ is called passing an exception.  Unlike a
     373library function @cancel_stack@ is called passing an exception. Unlike a
    374374raise, this exception is not used in matching only to pass information about
    375375the cause of the cancellation.
     
    379379\item[Main Stack:]
    380380The main stack is the one used by the program main at the start of execution,
    381 and is the only stack in a sequential program.  Hence, when cancellation is
     381and is the only stack in a sequential program. Hence, when cancellation is
    382382forwarded to the main stack, there is no other forwarding stack, so after the
    383383stack is unwound, there is a program-level abort.
     
    385385\item[Thread Stack:]
    386386A thread stack is created for a @thread@ object or object that satisfies the
    387 @is_thread@ trait.  A thread only has two points of communication that must
     387@is_thread@ trait. A thread only has two points of communication that must
    388388happen: start and join. As the thread must be running to perform a
    389389cancellation, it must occur after start and before join, so join is a
    390 cancellation point.  After the stack is unwound, the thread halts and waits for
     390cancellation point. After the stack is unwound, the thread halts and waits for
    391391another thread to join with it. The joining thread, checks for a cancellation,
    392392and if present, resumes exception @ThreadCancelled@.
     
    408408
    409409\item[Coroutine Stack:] A coroutine stack is created for a @coroutine@ object
    410 or object that satisfies the @is_coroutine@ trait.  A coroutine only knows of
    411 two other coroutines, its starter and its last resumer.  The last resumer has
    412 the tightest coupling to the coroutine it activated.  Hence, cancellation of
     410or object that satisfies the @is_coroutine@ trait. A coroutine only knows of
     411two other coroutines, its starter and its last resumer. The last resumer has
     412the tightest coupling to the coroutine it activated. Hence, cancellation of
    413413the active coroutine is forwarded to the last resumer after the stack is
    414414unwound, as the last resumer has the most precise knowledge about the current
  • doc/theses/andrew_beach_MMath/implement.tex

    r144fa5c r3b402339  
    278278@_URC_END_OF_STACK@.
    279279
    280 Second, when a handler is matched, raise exception continues onto the cleanup phase.
     280Second, when a handler is matched, raise exception continues onto the cleanup
     281phase.
    281282Once again, it calls the personality functions of each stack frame from newest
    282283to oldest. This pass stops at the stack frame containing the matching handler.
  • doc/theses/andrew_beach_MMath/thesis-frontpgs.tex

    r144fa5c r3b402339  
    3636
    3737        A thesis \\
    38         presented to the University of Waterloo \\ 
     38        presented to the University of Waterloo \\
    3939        in fulfillment of the \\
    4040        thesis requirement for the degree of \\
     
    6464\cleardoublepage
    6565
    66  
     66
    6767%----------------------------------------------------------------------
    6868% EXAMINING COMMITTEE (Required for Ph.D. theses only)
     
    7171\begin{center}\textbf{Examining Committee Membership}\end{center}
    7272  \noindent
    73 The following served on the Examining Committee for this thesis. The decision of the Examining Committee is by majority vote.
    74   \bigskip
    75  
    76   \noindent
    77 \begin{tabbing}
    78 Internal-External Member: \=  \kill % using longest text to define tab length
    79 External Examiner: \>  Bruce Bruce \\
     73The following served on the Examining Committee for this thesis. The decision
     74of the Examining Committee is by majority vote.
     75  \bigskip
     76
     77  \noindent
     78\begin{tabbing}
     79Internal-External Member: \=  \kill % using longest text to define tab length
     80External Examiner: \>  Bruce Bruce \\
    8081\> Professor, Dept. of Philosophy of Zoology, University of Wallamaloo \\
    81 \end{tabbing} 
    82   \bigskip
    83  
     82\end{tabbing}
     83  \bigskip
     84
    8485  \noindent
    8586\begin{tabbing}
     
    9192\end{tabbing}
    9293  \bigskip
    93  
     94
    9495  \noindent
    9596  \begin{tabbing}
     
    99100\end{tabbing}
    100101  \bigskip
    101  
     102
    102103  \noindent
    103104\begin{tabbing}
     
    107108\end{tabbing}
    108109  \bigskip
    109  
     110
    110111  \noindent
    111112\begin{tabbing}
     
    123124  % December 13th, 2006.  It is designed for an electronic thesis.
    124125  \noindent
    125 I hereby declare that I am the sole author of this thesis. This is a true copy of the thesis, including any required final revisions, as accepted by my examiners.
    126 
    127   \bigskip
    128  
     126I hereby declare that I am the sole author of this thesis. This is a true copy
     127of the thesis, including any required final revisions, as accepted by my
     128examiners.
     129
     130  \bigskip
     131
    129132  \noindent
    130133I understand that my thesis may be made electronically available to the public.
  • doc/theses/andrew_beach_MMath/thesis.tex

    r144fa5c r3b402339  
    4545% FRONT MATERIAL
    4646%----------------------------------------------------------------------
    47 \input{thesis-frontpgs} 
     47\input{thesis-frontpgs}
    4848
    4949%----------------------------------------------------------------------
     
    6565A \gls{computer} could compute $\pi$ all day long. In fact, subsets of digits
    6666of $\pi$'s decimal approximation would make a good source for psuedo-random
    67 vectors, \gls{rvec} . 
     67vectors, \gls{rvec} .
    6868
    6969%----------------------------------------------------------------------
     
    9696
    9797\begin{itemize}
    98 \item A well-prepared PDF should be 
     98\item A well-prepared PDF should be
    9999  \begin{enumerate}
    100100    \item Of reasonable size, {\it i.e.} photos cropped and compressed.
    101     \item Scalable, to allow enlargment of text and drawings. 
    102   \end{enumerate} 
     101    \item Scalable, to allow enlargment of text and drawings.
     102  \end{enumerate}
    103103\item Photos must be bit maps, and so are not scaleable by definition. TIFF and
    104104BMP are uncompressed formats, while JPEG is compressed. Most photos can be
    105105compressed without losing their illustrative value.
    106 \item Drawings that you make should be scalable vector graphics, \emph{not} 
     106\item Drawings that you make should be scalable vector graphics, \emph{not}
    107107bit maps. Some scalable vector file formats are: EPS, SVG, PNG, WMF. These can
    108 all be converted into PNG or PDF, that pdflatex recognizes. Your drawing 
    109 package probably can export to one of these formats directly. Otherwise, a 
    110 common procedure is to print-to-file through a Postscript printer driver to 
    111 create a PS file, then convert that to EPS (encapsulated PS, which has a 
    112 bounding box to describe its exact size rather than a whole page). 
     108all be converted into PNG or PDF, that pdflatex recognizes. Your drawing
     109package probably can export to one of these formats directly. Otherwise, a
     110common procedure is to print-to-file through a Postscript printer driver to
     111create a PS file, then convert that to EPS (encapsulated PS, which has a
     112bounding box to describe its exact size rather than a whole page).
    113113Programs such as GSView (a Ghostscript GUI) can create both EPS and PDF from
    114114PS files. Appendix~\ref{AppendixA} shows how to generate properly sized Matlab
    115115plots and save them as PDF.
    116116\item It's important to crop your photos and draw your figures to the size that
    117 you want to appear in your thesis. Scaling photos with the 
    118 includegraphics command will cause loss of resolution. And scaling down 
     117you want to appear in your thesis. Scaling photos with the
     118includegraphics command will cause loss of resolution. And scaling down
    119119drawings may cause any text annotations to become too small.
    120120\end{itemize}
    121  
     121
    122122For more information on \LaTeX\, see the uWaterloo Skills for the
    123 Academic Workplace \href{https://uwaterloo.ca/information-systems-technology/services/electronic-thesis-preparation-and-submission-support/ethesis-guide/creating-pdf-version-your-thesis/creating-pdf-files-using-latex/latex-ethesis-and-large-documents}{course notes}. 
     123Academic Workplace \href{https://uwaterloo.ca/information-systems-technology/services/electronic-thesis-preparation-and-submission-support/ethesis-guide/creating-pdf-version-your-thesis/creating-pdf-files-using-latex/latex-ethesis-and-large-documents}{course notes}.
    124124\footnote{
    125125Note that while it is possible to include hyperlinks to external documents,
    126 it is not wise to do so, since anything you can't control may change over time. 
    127 It \emph{would} be appropriate and necessary to provide external links to 
    128 additional resources for a multimedia ``enhanced'' thesis. 
    129 But also note that if the \package{hyperref} package is not included, 
    130 as for the print-optimized option in this thesis template, any \cmmd{href} 
     126it is not wise to do so, since anything you can't control may change over time.
     127It \emph{would} be appropriate and necessary to provide external links to
     128additional resources for a multimedia ``enhanced'' thesis.
     129But also note that if the \package{hyperref} package is not included,
     130as for the print-optimized option in this thesis template, any \cmmd{href}
    131131commands in your logical document are no longer defined.
    132132A work-around employed by this thesis template is to define a dummy
    133 \cmmd{href} command (which does nothing) in the preamble of the document, 
    134 before the \package{hyperref} package is included. 
     133\cmmd{href} command (which does nothing) in the preamble of the document,
     134before the \package{hyperref} package is included.
    135135The dummy definition is then redifined by the
    136136\package{hyperref} package when it is included.
     
    138138
    139139The classic book by Leslie Lamport \cite{lamport.book}, author of \LaTeX , is
    140 worth a look too, and the many available add-on packages are described by 
     140worth a look too, and the many available add-on packages are described by
    141141Goossens \textit{et al} \cite{goossens.book}.
    142142
     
    180180Export Setup button in the figure Property Editor.
    181181
    182 \section{From the Command Line} 
     182\section{From the Command Line}
    183183All figure properties can also be manipulated from the command line. Here's an
    184 example: 
     184example:
    185185\begin{verbatim}
    186186x=[0:0.1:pi];
  • doc/theses/andrew_beach_MMath/uw-ethesis-frontpgs.tex

    r144fa5c r3b402339  
    3030        \normalsize
    3131        A thesis \\
    32         presented to the University of Waterloo \\ 
     32        presented to the University of Waterloo \\
    3333        in fulfillment of the \\
    3434        thesis requirement for the degree of \\
     
    4747\end{titlepage}
    4848
    49 % The rest of the front pages should contain no headers and be numbered using Roman numerals starting with `ii'
     49% The rest of the front pages should contain no headers and be numbered using
     50% Roman numerals starting with `ii'.
    5051\pagestyle{plain}
    5152\setcounter{page}{2}
    5253
    53 \cleardoublepage % Ends the current page and causes all figures and tables that have so far appeared in the input to be printed.
    54 % In a two-sided printing style, it also makes the next page a right-hand (odd-numbered) page, producing a blank page if necessary.
     54\cleardoublepage % Ends the current page and causes all figures and tables
     55% that have so far appeared in the input to be printed. In a two-sided
     56% printing style, it also makes the next page a right-hand (odd-numbered)
     57% page, producing a blank page if necessary.
    5558
    56 \begin{comment} 
     59\begin{comment}
    5760% E X A M I N I N G   C O M M I T T E E (Required for Ph.D. theses only)
    5861% Remove or comment out the lines below to remove this page
    5962\begin{center}\textbf{Examining Committee Membership}\end{center}
    6063  \noindent
    61 The following served on the Examining Committee for this thesis. The decision of the Examining Committee is by majority vote.
     64The following served on the Examining Committee for this thesis.
     65The decision of the Examining Committee is by majority vote.
    6266  \bigskip
    63  
     67
    6468  \noindent
    6569\begin{tabbing}
    6670Internal-External Member: \=  \kill % using longest text to define tab length
    67 External Examiner: \>  Bruce Bruce \\ 
     71External Examiner: \>  Bruce Bruce \\
    6872\> Professor, Dept. of Philosophy of Zoology, University of Wallamaloo \\
    69 \end{tabbing} 
     73\end{tabbing}
    7074  \bigskip
    71  
     75
    7276  \noindent
    7377\begin{tabbing}
     
    7983\end{tabbing}
    8084  \bigskip
    81  
     85
    8286  \noindent
    8387  \begin{tabbing}
     
    8791\end{tabbing}
    8892  \bigskip
    89  
     93
    9094  \noindent
    9195\begin{tabbing}
     
    9599\end{tabbing}
    96100  \bigskip
    97  
     101
    98102  \noindent
    99103\begin{tabbing}
     
    111115  % December 13th, 2006.  It is designed for an electronic thesis.
    112116 \begin{center}\textbf{Author's Declaration}\end{center}
    113  
     117
    114118 \noindent
    115 I hereby declare that I am the sole author of this thesis. This is a true copy of the thesis, including any required final revisions, as accepted by my examiners.
     119I hereby declare that I am the sole author of this thesis. This is a true copy
     120of the thesis, including any required final revisions, as accepted by my
     121examiners.
    116122
    117123  \bigskip
    118  
     124
    119125  \noindent
    120126I understand that my thesis may be made electronically available to the public.
  • doc/theses/andrew_beach_MMath/uw-ethesis.tex

    r144fa5c r3b402339  
    11%======================================================================
    2 % University of Waterloo Thesis Template for LaTeX 
    3 % Last Updated November, 2020 
    4 % by Stephen Carr, IST Client Services, 
     2% University of Waterloo Thesis Template for LaTeX
     3% Last Updated November, 2020
     4% by Stephen Carr, IST Client Services,
    55% University of Waterloo, 200 University Ave. W., Waterloo, Ontario, Canada
    66% FOR ASSISTANCE, please send mail to request@uwaterloo.ca
    77
    88% DISCLAIMER
    9 % To the best of our knowledge, this template satisfies the current uWaterloo thesis requirements.
    10 % However, it is your responsibility to assure that you have met all requirements of the University and your particular department.
    11 
    12 % Many thanks for the feedback from many graduates who assisted the development of this template.
    13 % Also note that there are explanatory comments and tips throughout this template.
     9% To the best of our knowledge, this template satisfies the current uWaterloo
     10% thesis requirements. However, it is your responsibility to assure that you
     11% have met all requirements of the University and your particular department.
     12
     13% Many thanks for the feedback from many graduates who assisted the
     14% development of this template. Also note that there are explanatory comments
     15% and tips throughout this template.
    1416%======================================================================
    1517% Some important notes on using this template and making it your own...
    1618
    17 % The University of Waterloo has required electronic thesis submission since October 2006.
    18 % See the uWaterloo thesis regulations at
    19 % https://uwaterloo.ca/graduate-studies/thesis.
    20 % This thesis template is geared towards generating a PDF version optimized for viewing on an electronic display, including hyperlinks within the PDF.
    21 
    22 % DON'T FORGET TO ADD YOUR OWN NAME AND TITLE in the "hyperref" package configuration below.
    23 % THIS INFORMATION GETS EMBEDDED IN THE PDF FINAL PDF DOCUMENT.
    24 % You can view the information if you view properties of the PDF document.
    25 
    26 % Many faculties/departments also require one or more printed copies.
    27 % This template attempts to satisfy both types of output.
     19% The University of Waterloo has required electronic thesis submission since
     20% October 2006. See the uWaterloo thesis regulations at:
     21%   https://uwaterloo.ca/graduate-studies/thesis.
     22% This thesis template is geared towards generating a PDF version optimized
     23% for viewing on an electronic display, including hyperlinks within the PDF.
     24
     25% DON'T FORGET TO ADD YOUR OWN NAME AND TITLE in the "hyperref" package
     26% configuration below. THIS INFORMATION GETS EMBEDDED IN THE FINAL PDF
     27% DOCUMENT. You can view the information if you view properties of the PDF.
     28
     29% Many faculties/departments also require one or more printed copies.
     30% This template attempts to satisfy both types of output.
    2831% See additional notes below.
    29 % It is based on the standard "book" document class which provides all necessary sectioning structures and allows multi-part theses.
    30 
    31 % If you are using this template in Overleaf (cloud-based collaboration service), then it is automatically processed and previewed for you as you edit.
    32 
    33 % For people who prefer to install their own LaTeX distributions on their own computers, and process the source files manually, the following notes provide the sequence of tasks:
    34  
     32% It is based on the standard "book" document class which provides all
     33% necessary sectioning structures and allows multi-part theses.
     34
     35% If you are using this template in Overleaf (cloud-based collaboration
     36% service), then it is automatically processed and previewed for you as you
     37% edit.
     38
     39% For people who prefer to install their own LaTeX distributions on their own
     40% computers, and process the source files manually, the following notes
     41% provide the sequence of tasks:
     42
    3543% E.g. to process a thesis called "mythesis.tex" based on this template, run:
    3644
    3745% pdflatex mythesis     -- first pass of the pdflatex processor
    3846% bibtex mythesis       -- generates bibliography from .bib data file(s)
    39 % makeindex         -- should be run only if an index is used
    40 % pdflatex mythesis     -- fixes numbering in cross-references, bibliographic references, glossaries, index, etc.
    41 % pdflatex mythesis     -- it takes a couple of passes to completely process all cross-references
    42 
    43 % If you use the recommended LaTeX editor, Texmaker, you would open the mythesis.tex file, then click the PDFLaTeX button. Then run BibTeX (under the Tools menu).
    44 % Then click the PDFLaTeX button two more times.
    45 % If you have an index as well,you'll need to run MakeIndex from the Tools menu as well, before running pdflatex
    46 % the last two times.
    47 
    48 % N.B. The "pdftex" program allows graphics in the following formats to be included with the "\includegraphics" command: PNG, PDF, JPEG, TIFF
    49 % Tip: Generate your figures and photos in the size you want them to appear in your thesis, rather than scaling them with \includegraphics options.
    50 % Tip: Any drawings you do should be in scalable vector graphic formats: SVG, PNG, WMF, EPS and then converted to PNG or PDF, so they are scalable in the final PDF as well.
     47% makeindex         -- should be run only if an index is used
     48% pdflatex mythesis     -- fixes numbering in cross-references, bibliographic
     49%                      references, glossaries, index, etc.
     50% pdflatex mythesis     -- it takes a couple of passes to completely process all
     51%                      cross-references
     52
     53% If you use the recommended LaTeX editor, Texmaker, you would open the
     54% mythesis.tex file, then click the PDFLaTeX button. Then run BibTeX (under
     55% the Tools menu). Then click the PDFLaTeX button two more times.
     56% If you have an index as well, you'll need to run MakeIndex from the Tools
     57% menu as well, before running pdflatex the last two times.
     58
     59% N.B. The "pdftex" program allows graphics in the following formats to be
     60% included with the "\includegraphics" command: PNG, PDF, JPEG, TIFF
     61% Tip: Generate your figures and photos in the size you want them to appear
     62% in your thesis, rather than scaling them with \includegraphics options.
     63% Tip: Any drawings you do should be in scalable vector graphic formats: SVG,
     64% PNG, WMF, EPS and then converted to PNG or PDF, so they are scalable in the
     65% final PDF as well.
    5166% Tip: Photographs should be cropped and compressed so as not to be too large.
    5267
    53 % To create a PDF output that is optimized for double-sided printing:
    54 % 1) comment-out the \documentclass statement in the preamble below, and un-comment the second \documentclass line.
    55 % 2) change the value assigned below to the boolean variable "PrintVersion" from " false" to "true".
    56 
    57 %======================================================================
     68% To create a PDF output that is optimized for double-sided printing:
     69% 1) comment-out the \documentclass statement in the preamble below, and
     70%    un-comment the second \documentclass line.
     71% 2) change the value assigned below to the boolean variable "PrintVersion"
     72%    from " false" to "true".
     73
     74% ======================================================================
    5875%   D O C U M E N T   P R E A M B L E
    59 % Specify the document class, default style attributes, and page dimensions, etc.
     76% Specify the document class, default style attributes, page dimensions, etc.
    6077% For hyperlinked PDF, suitable for viewing on a computer, use this:
    6178\documentclass[letterpaper,12pt,titlepage,oneside,final]{book}
    6279
    63 % For PDF, suitable for double-sided printing, change the PrintVersion variable below to "true" and use this \documentclass line instead of the one above:
     80% For PDF, suitable for double-sided printing, change the PrintVersion
     81% variable below to "true" and use this \documentclass line instead of the
     82% one above:
    6483%\documentclass[letterpaper,12pt,titlepage,openright,twoside,final]{book}
    6584
    6685% Some LaTeX commands I define for my own nomenclature.
    67 % If you have to, it's easier to make changes to nomenclature once here than in a million places throughout your thesis!
     86% If you have to, it's easier to make changes to nomenclature once here than
     87% in a million places throughout your thesis!
    6888\newcommand{\package}[1]{\textbf{#1}} % package names in bold text
    69 \newcommand{\cmmd}[1]{\textbackslash\texttt{#1}} % command name in tt font
    70 \newcommand{\href}[1]{#1} % does nothing, but defines the command so the print-optimized version will ignore \href tags (redefined by hyperref pkg).
     89\newcommand{\cmmd}[1]{\textbackslash\texttt{#1}} % command name in tt font
     90\newcommand{\href}[1]{#1} % does nothing, but defines the command so the
     91% print-optimized version will ignore \href tags (redefined by hyperref pkg).
    7192%\newcommand{\texorpdfstring}[2]{#1} % does nothing, but defines the command
    7293% Anything defined here may be redefined by packages added below...
     
    7697\newboolean{PrintVersion}
    7798\setboolean{PrintVersion}{false}
    78 % CHANGE THIS VALUE TO "true" as necessary, to improve printed results for hard copies by overriding some options of the hyperref package, called below.
     99% CHANGE THIS VALUE TO "true" as necessary, to improve printed results for
     100% hard copies by overriding some options of the hyperref package, called below.
    79101
    80102%\usepackage{nomencl} % For a nomenclature (optional; available from ctan.org)
    81 \usepackage{amsmath,amssymb,amstext} % Lots of math symbols and environments
    82 \usepackage[pdftex]{graphicx} % For including graphics N.B. pdftex graphics driver
     103% Lots of math symbols and environments
     104\usepackage{amsmath,amssymb,amstext}
     105% For including graphics N.B. pdftex graphics driver
     106\usepackage[pdftex]{graphicx}
    83107
    84108% Hyperlinks make it very easy to navigate an electronic document.
    85 % In addition, this is where you should specify the thesis title and author as they appear in the properties of the PDF document.
     109% In addition, this is where you should specify the thesis title and author as
     110% they appear in the properties of the PDF document.
    86111% Use the "hyperref" package
    87112% N.B. HYPERREF MUST BE THE LAST PACKAGE LOADED; ADD ADDITIONAL PKGS ABOVE
    88113\usepackage[pdftex,pagebackref=true]{hyperref} % with basic options
    89114%\usepackage[pdftex,pagebackref=true]{hyperref}
    90                 % N.B. pagebackref=true provides links back from the References to the body text. This can cause trouble for printing.
     115% N.B. pagebackref=true provides links back from the References to the body
     116% text. This can cause trouble for printing.
    91117\hypersetup{
    92118    plainpages=false,       % needed if Roman numbers in frontpages
     
    96122    pdffitwindow=false,     % window fit to page when opened
    97123    pdfstartview={FitH},    % fits the width of the page to the window
    98 %    pdftitle={uWaterloo\ LaTeX\ Thesis\ Template},    % title: CHANGE THIS TEXT!
     124%    pdftitle={uWaterloo\ LaTeX\ Thesis\ Template}, % title: CHANGE THIS TEXT!
    99125%    pdfauthor={Author},    % author: CHANGE THIS TEXT! and uncomment this line
    100126%    pdfsubject={Subject},  % subject: CHANGE THIS TEXT! and uncomment this line
    101 %    pdfkeywords={keyword1} {key2} {key3}, % list of keywords, and uncomment this line if desired
     127%    pdfkeywords={keyword1} {key2} {key3}, % optional list of keywords
    102128    pdfnewwindow=true,      % links in new window
    103129    colorlinks=true,        % false: boxed links; true: colored links
     
    107133    urlcolor=cyan           % color of external links
    108134}
    109 \ifthenelse{\boolean{PrintVersion}}{   % for improved print quality, change some hyperref options
     135% for improved print quality, change some hyperref options
     136\ifthenelse{\boolean{PrintVersion}}{
    110137\hypersetup{    % override some previously defined hyperref options
    111138%    colorlinks,%
     
    116143}{} % end of ifthenelse (no else)
    117144
    118 \usepackage[automake,toc,abbreviations]{glossaries-extra} % Exception to the rule of hyperref being the last add-on package
    119 % If glossaries-extra is not in your LaTeX distribution, get it from CTAN (http://ctan.org/pkg/glossaries-extra),
    120 % although it's supposed to be in both the TeX Live and MikTeX distributions. There are also documentation and
    121 % installation instructions there.
     145% Exception to the rule of hyperref being the last add-on package
     146\usepackage[automake,toc,abbreviations]{glossaries-extra}
     147% If glossaries-extra is not in your LaTeX distribution, get it from CTAN
     148% (http://ctan.org/pkg/glossaries-extra), although it's supposed to be in
     149% both the TeX Live and MikTeX distributions. There are also documentation
     150% and installation instructions there.
    122151
    123152% Setting up the page margins...
    124 \setlength{\textheight}{9in}\setlength{\topmargin}{-0.45in}\setlength{\headsep}{0.25in}
    125 % uWaterloo thesis requirements specify a minimum of 1 inch (72pt) margin at the
    126 % top, bottom, and outside page edges and a 1.125 in. (81pt) gutter margin (on binding side).
    127 % While this is not an issue for electronic viewing, a PDF may be printed, and so we have the same page layout for both printed and electronic versions, we leave the gutter margin in.
    128 % Set margins to minimum permitted by uWaterloo thesis regulations:
     153\setlength{\textheight}{9in}
     154\setlength{\topmargin}{-0.45in}
     155\setlength{\headsep}{0.25in}
     156% uWaterloo thesis requirements specify a minimum of 1 inch (72pt) margin at
     157% the top, bottom, and outside page edges and a 1.125 in. (81pt) gutter margin
     158% (on binding side). While this is not an issue for electronic viewing, a PDF
     159% may be printed, and so we have the same page layout for both printed and
     160% electronic versions, we leave the gutter margin in. Set margins to minimum
     161% permitted by uWaterloo thesis regulations:
    129162\setlength{\marginparwidth}{0pt} % width of margin notes
    130163% N.B. If margin notes are used, you must adjust \textwidth, \marginparwidth
    131164% and \marginparsep so that the space left between the margin notes and page
    132165% edge is less than 15 mm (0.6 in.)
    133 \setlength{\marginparsep}{0pt} % width of space between body text and margin notes
    134 \setlength{\evensidemargin}{0.125in} % Adds 1/8 in. to binding side of all
     166% width of space between body text and margin notes
     167\setlength{\marginparsep}{0pt}
     168% Adds 1/8 in. to binding side of all
    135169% even-numbered pages when the "twoside" printing option is selected
    136 \setlength{\oddsidemargin}{0.125in} % Adds 1/8 in. to the left of all pages when "oneside" printing is selected, and to the left of all odd-numbered pages when "twoside" printing is selected
    137 \setlength{\textwidth}{6.375in} % assuming US letter paper (8.5 in. x 11 in.) and side margins as above
     170\setlength{\evensidemargin}{0.125in}
     171% Adds 1/8 in. to the left of all pages when "oneside" printing is selected,
     172% and to the left of all odd-numbered pages when "twoside" printing is selected
     173\setlength{\oddsidemargin}{0.125in}
     174% assuming US letter paper (8.5 in. x 11 in.) and side margins as above
     175\setlength{\textwidth}{6.375in}
    138176\raggedbottom
    139177
    140 % The following statement specifies the amount of space between paragraphs. Other reasonable specifications are \bigskipamount and \smallskipamount.
     178% The following statement specifies the amount of space between paragraphs.
     179% Other reasonable specifications are \bigskipamount and \smallskipamount.
    141180\setlength{\parskip}{\medskipamount}
    142181
    143 % The following statement controls the line spacing. 
    144 % The default spacing corresponds to good typographic conventions and only slight changes (e.g., perhaps "1.2"), if any, should be made.
     182% The following statement controls the line spacing.
     183% The default spacing corresponds to good typographic conventions and only
     184% slight changes (e.g., perhaps "1.2"), if any, should be made.
    145185\renewcommand{\baselinestretch}{1} % this is the default line space setting
    146186
    147187% By default, each chapter will start on a recto (right-hand side) page.
    148 % We also force each section of the front pages to start on a recto page by inserting \cleardoublepage commands.
    149 % In many cases, this will require that the verso (left-hand) page be blank, and while it should be counted, a page number should not be printed.
    150 % The following statements ensure a page number is not printed on an otherwise blank verso page.
     188% We also force each section of the front pages to start on a recto page by
     189% inserting \cleardoublepage commands. In many cases, this will require that
     190% the verso (left-hand) page be blank, and while it should be counted, a page
     191% number should not be printed. The following statements ensure a page number
     192% is not printed on an otherwise blank verso page.
    151193\let\origdoublepage\cleardoublepage
    152194\newcommand{\clearemptydoublepage}{%
     
    154196\let\cleardoublepage\clearemptydoublepage
    155197
    156 % Define Glossary terms (This is properly done here, in the preamble and could also be \input{} from a separate file...)
     198% Define Glossary terms (This is properly done here, in the preamble and
     199% could also be \input{} from a separate file...)
    157200\input{glossaries}
    158201\makeglossaries
     
    169212%   L O G I C A L    D O C U M E N T
    170213% The logical document contains the main content of your thesis.
    171 % Being a large document, it is a good idea to divide your thesis into several files, each one containing one chapter or other significant chunk of content, so you can easily shuffle things around later if desired.
     214% Being a large document, it is a good idea to divide your thesis into several
     215% files, each one containing one chapter or other significant chunk of content,
     216% so you can easily shuffle things around later if desired.
    172217%======================================================================
    173218\begin{document}
     
    176221% FRONT MATERIAL
    177222% title page,declaration, borrowers' page, abstract, acknowledgements,
    178 % dedication, table of contents, list of tables, list of figures, nomenclature, etc.
    179 %----------------------------------------------------------------------
    180 \input{uw-ethesis-frontpgs}
     223% dedication, table of contents, list of tables, list of figures,
     224% nomenclature, etc.
     225%----------------------------------------------------------------------
     226\input{uw-ethesis-frontpgs}
    181227
    182228%----------------------------------------------------------------------
    183229% MAIN BODY
    184230% We suggest using a separate file for each chapter of your thesis.
    185 % Start each chapter file with the \chapter command.
    186 % Only use \documentclass or \begin{document} and \end{document} commands in this master document.
     231% Start each chapter file with the \chapter command. Only use \documentclass,
     232% \begin{document} and \end{document} commands in this master document.
    187233% Tip: Putting each sentence on a new line is a way to simplify later editing.
    188234%----------------------------------------------------------------------
     
    200246% Bibliography
    201247
    202 % The following statement selects the style to use for references. 
    203 % It controls the sort order of the entries in the bibliography and also the formatting for the in-text labels.
     248% The following statement selects the style to use for references.
     249% It controls the sort order of the entries in the bibliography and also the
     250% formatting for the in-text labels.
    204251\bibliographystyle{plain}
    205 % This specifies the location of the file containing the bibliographic information. 
    206 % It assumes you're using BibTeX to manage your references (if not, why not?).
    207 \cleardoublepage % This is needed if the "book" document class is used, to place the anchor in the correct page, because the bibliography will start on its own page.
    208 % Use \clearpage instead if the document class uses the "oneside" argument
    209 \phantomsection  % With hyperref package, enables hyperlinking from the table of contents to bibliography             
    210 % The following statement causes the title "References" to be used for the bibliography section:
     252% This specifies the location of the file containing the bibliographic
     253% information. It assumes you're using BibTeX to manage your references (if
     254% not, why not?).
     255\cleardoublepage % This is needed if the "book" document class is used, to
     256% place the anchor in the correct page, because the bibliography will start
     257% on its own page.
     258% Use \clearpage instead if the document class uses the "oneside" argument.
     259\phantomsection  % With hyperref package, enables hyperlinking from the table
     260% of contents to bibliography.
     261% The following statement causes the title "References" to be used for the
     262% bibliography section:
    211263\renewcommand*{\bibname}{References}
    212264
     
    215267
    216268\bibliography{uw-ethesis,pl}
    217 % Tip: You can create multiple .bib files to organize your references.
    218 % Just list them all in the \bibliogaphy command, separated by commas (no spaces).
    219 
    220 % The following statement causes the specified references to be added to the bibliography even if they were not cited in the text.
    221 % The asterisk is a wildcard that causes all entries in the bibliographic database to be included (optional).
     269% Tip: You can create multiple .bib files to organize your references. Just
     270% list them all in the \bibliogaphy command, separated by commas (no spaces).
     271
     272% The following statement causes the specified references to be added to the
     273% bibliography even if they were not cited in the text. The asterisk is a
     274% wildcard that causes all entries in the bibliographic database to be
     275% included (optional).
    222276% \nocite{*}
    223277%----------------------------------------------------------------------
     
    227281% The \appendix statement indicates the beginning of the appendices.
    228282\appendix
    229 % Add an un-numbered title page before the appendices and a line in the Table of Contents
     283% Add an un-numbered title page before the appendices and a line in the Table
     284% of Contents
    230285% \chapter*{APPENDICES}
    231286% \addcontentsline{toc}{chapter}{APPENDICES}
    232 % Appendices are just more chapters, with different labeling (letters instead of numbers).
     287% Appendices are just more chapters, with different labeling (letters instead
     288% of numbers).
    233289% \input{appendix-matlab_plots.tex}
    234290
    235 % GLOSSARIES (Lists of definitions, abbreviations, symbols, etc. provided by the glossaries-extra package)
     291% GLOSSARIES (Lists of definitions, abbreviations, symbols, etc.
     292% provided by the glossaries-extra package)
    236293% -----------------------------
    237294\printglossaries
  • libcfa/src/memory.cfa

    r144fa5c r3b402339  
    1010// Created On       : Tue Jun  2 16:48:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Jun  3 12:30:00 2020
    13 // Update Count     : 0
     12// Last Modified On : Mon Feb  1 16:10:00 2021
     13// Update Count     : 1
    1414//
    1515
     
    5656}
    5757
    58 forall(T & | sized(T) | { void ^?{}(T &); })
     58forall(T & | sized(T))
    5959void ?{}(counter_ptr(T) & this, counter_ptr(T) that) {
    6060        // `that` is a copy but it should have neither a constructor
    6161        // nor destructor run on it so it shouldn't need adjustment.
    62         internal_decrement(this);
    6362        internal_copy(this, that);
    6463}
     
    6665forall(T & | sized(T), Args... | { void ?{}(T&, Args); })
    6766void ?{}(counter_ptr(T) & this, Args args) {
    68         this.data = (counter_data(T)*)new(args);
     67        this.data = malloc();
     68        this.data->counter = 1;
     69        (this.data->object){args};
    6970}
    7071
     
    126127forall(T & | sized(T), Args... | { void ?{}(T &, Args); })
    127128void ?{}(unique_ptr(T) & this, Args args) {
    128         this.data = (T *)new(args);
     129        this.data = malloc();
     130        (*this.data){args};
    129131}
    130132
  • libcfa/src/memory.hfa

    r144fa5c r3b402339  
    1010// Created On       : Tue Jun  2 16:48:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Jun  3 12:29:00 2020
    13 // Update Count     : 0
     12// Last Modified On : Fri Jan 29 15:52:00 2021
     13// Update Count     : 1
    1414//
    1515
     
    1717
    1818// Internal data object.
    19 forall(T & | sized(T)) {
    20         struct counter_data {
    21                 unsigned int counter;
    22                 T object;
    23         };
     19forall(T & | sized(T))
     20struct counter_data {
     21        unsigned int counter;
     22        T object;
     23};
    2424
    25         forall(Args... | { void ?{}(T &, Args); })
    26         void ?{}(counter_data(T) & this, Args args);
     25forall(T & | sized(T), Args... | { void ?{}(T &, Args); })
     26void ?{}(counter_data(T) & this, Args args);
    2727
    28         forall( | { void ^?{}(T &); })
    29         void ^?{}(counter_data(T) & this);
    30 }
     28forall(T & | sized(T) | { void ^?{}(T &); })
     29void ^?{}(counter_data(T) & this);
    3130
    3231// This is one of many pointers keeping this alive.
    33 forall(T & | sized(T)) {
    34         struct counter_ptr {
    35                 counter_data(T) * data;
    36         };
     32forall(T & | sized(T))
     33struct counter_ptr {
     34        counter_data(T) * data;
     35};
    3736
    38         void ?{}(counter_ptr(T) & this);
    39         void ?{}(counter_ptr(T) & this, zero_t);
    40         forall( | { void ^?{}(T &); })
    41         void ?{}(counter_ptr(T) & this, counter_ptr(T) that);
    42         forall(Args... | { void ?{}(T&, Args); })
    43         void ?{}(counter_ptr(T) & this, Args args);
     37forall(T & | sized(T))
     38void ?{}(counter_ptr(T) & this);
     39forall(T & | sized(T))
     40void ?{}(counter_ptr(T) & this, zero_t);
     41forall(T & | sized(T))
     42void ?{}(counter_ptr(T) & this, counter_ptr(T) that);
     43forall(T & | sized(T), Args... | { void ?{}(T&, Args); })
     44void ?{}(counter_ptr(T) & this, Args args);
    4445
    45         forall( | { void ^?{}(T &); })
    46         void ^?{}(counter_ptr(T) & this);
     46forall(T & | sized(T) | { void ^?{}(T &); })
     47void ^?{}(counter_ptr(T) & this);
    4748
    48         T & *?(counter_ptr(T) & this);
     49forall(T & | sized(T))
     50T & *?(counter_ptr(T) & this);
    4951
    50         forall( | { void ^?{}(T &); })
    51         void ?=?(counter_ptr(T) & this, counter_ptr(T) that);
    52         forall( | { void ^?{}(T &); })
    53         void ?=?(counter_ptr(T) & this, zero_t);
     52forall(T & | sized(T) | { void ^?{}(T &); })
     53void ?=?(counter_ptr(T) & this, counter_ptr(T) that);
     54forall(T & | sized(T) | { void ^?{}(T &); })
     55void ?=?(counter_ptr(T) & this, zero_t);
    5456
    55         int ?==?(counter_ptr(T) const & this, counter_ptr(T) const & that);
    56         int ?!=?(counter_ptr(T) const & this, counter_ptr(T) const & that);
    57         int ?==?(counter_ptr(T) const & this, zero_t);
    58         int ?!=?(counter_ptr(T) const & this, zero_t);
    59 }
     57forall(T & | sized(T))
     58int ?==?(counter_ptr(T) const & this, counter_ptr(T) const & that);
     59forall(T & | sized(T))
     60int ?!=?(counter_ptr(T) const & this, counter_ptr(T) const & that);
     61forall(T & | sized(T))
     62int ?==?(counter_ptr(T) const & this, zero_t);
     63forall(T & | sized(T))
     64int ?!=?(counter_ptr(T) const & this, zero_t);
    6065
    6166// This is the only pointer that keeps this alive.
    62 forall(T &) {
    63         struct unique_ptr {
    64                 T * data;
    65         };
     67forall(T &)
     68struct unique_ptr {
     69        T * data;
     70};
    6671
    67         void ?{}(unique_ptr(T) & this);
    68         void ?{}(unique_ptr(T) & this, zero_t);
    69         void ?{}(unique_ptr(T) & this, unique_ptr(T) that) = void;
    70         forall( | sized(T), Args... | { void ?{}(T &, Args); })
    71         void ?{}(unique_ptr(T) & this, Args args);
     72forall(T &)
     73void ?{}(unique_ptr(T) & this);
     74forall(T &)
     75void ?{}(unique_ptr(T) & this, zero_t);
     76forall(T &)
     77void ?{}(unique_ptr(T) & this, unique_ptr(T) that) = void;
     78forall(T & | sized(T), Args... | { void ?{}(T &, Args); })
     79void ?{}(unique_ptr(T) & this, Args args);
    7280
    73         forall( | { void ^?{}(T &); })
    74         void ^?{}(unique_ptr(T) & this);
     81forall(T & | { void ^?{}(T &); })
     82void ^?{}(unique_ptr(T) & this);
    7583
    76         T & *?(unique_ptr(T) & this);
     84forall(T & )
     85T & *?(unique_ptr(T) & this);
    7786
    78         void ?=?(unique_ptr(T) & this, unique_ptr(T) that) = void;
    79         forall( | { void ^?{}(T &); })
    80         void ?=?(unique_ptr(T) & this, zero_t);
     87forall(T &)
     88void ?=?(unique_ptr(T) & this, unique_ptr(T) that) = void;
     89forall(T & | { void ^?{}(T &); })
     90void ?=?(unique_ptr(T) & this, zero_t);
    8191
    82         forall( | { void ^?{}(T &); })
    83         void move(unique_ptr(T) & this, unique_ptr(T) & that);
     92forall(T & | { void ^?{}(T &); })
     93void move(unique_ptr(T) & this, unique_ptr(T) & that);
    8494
    85         int ?==?(unique_ptr(T) const & this, unique_ptr(T) const & that);
    86         int ?!=?(unique_ptr(T) const & this, unique_ptr(T) const & that);
    87         int ?==?(unique_ptr(T) const & this, zero_t);
    88         int ?!=?(unique_ptr(T) const & this, zero_t);
    89 }
     95forall(T &)
     96int ?==?(unique_ptr(T) const & this, unique_ptr(T) const & that);
     97forall(T &)
     98int ?!=?(unique_ptr(T) const & this, unique_ptr(T) const & that);
     99forall(T &)
     100int ?==?(unique_ptr(T) const & this, zero_t);
     101forall(T &)
     102int ?!=?(unique_ptr(T) const & this, zero_t);
  • tests/smart-pointers.cfa

    r144fa5c r3b402339  
    22
    33#include <memory.hfa>
    4 #include <stdlib.hfa>
     4#include <assert.h>
    55
    66void counter_test(void) {
     
    5353}
    5454
     55void declare_test(void) {
     56        counter_ptr(int) ptr_i0 = 3;
     57        counter_ptr(char) ptr_c0 = 'a';
     58        counter_ptr(float) ptr_f0 = 3.5f;
     59        counter_ptr(double) ptr_d0 = 3.5;
     60
     61        unique_ptr(int) ptr_i1 = 3;
     62        unique_ptr(char) ptr_c1 = 'a';
     63        unique_ptr(float) ptr_f1 = 3.5f;
     64        unique_ptr(double) ptr_d1 = 3.5;
     65}
     66
    5567int main(int argc, char * argv[]) {
    5668        counter_test();
    5769        unique_test();
    5870        pointer_equality();
     71
     72        printf("done\n");
    5973}
Note: See TracChangeset for help on using the changeset viewer.