Changes in / [3b402339:144fa5c]


Ignore:
Files:
3 deleted
11 edited

Legend:

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

    r3b402339 r144fa5c  
    99#include <liburing.h>
    1010
    11 // #define NOBATCHING
    12 // #define USE_ASYNC
    13 
    14 // Options passed to each threads
     11typedef enum {
     12        EVENT_END,
     13        EVENT_ACCEPT,
     14        EVENT_REQUEST,
     15        EVENT_ANSWER
     16} event_t;
     17
     18struct __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
    1538struct __attribute__((aligned(128))) options_t {
    16         // Data passed to accept
    1739        struct {
    1840                int sockfd;
     
    2244        } acpt;
    2345
    24         // Termination notification
    2546        int endfd;
    26 
    27         // The ring to use for io
    2847        struct io_uring * ring;
     48
     49        struct {
     50                size_t subs = 0;
     51                size_t cnts = 0;
     52        } result;
    2953};
    3054
    3155//=========================================================
    32 // General statistics
    33 struct __attribute__((aligned(128))) stats_block_t {
    34         struct {
    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;
    63 };
    64 
    65 // Each thread gets its own block of stats
    66 // and there is a global block for tallying at the end
    67 thread_local stats_block_t stats;
    68 stats_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
    73 const size_t array_max = 25000;
    74 class 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
    77 volatile int max_fd = 0;
    78 
    79 //=========================================================
    80 // Some small wrappers for ring operations used outside the connection state machine
    81 // get sqe + error handling
    8256static struct io_uring_sqe * get_sqe(struct io_uring * ring) {
    8357        struct io_uring_sqe * sqe = io_uring_get_sqe(ring);
     
    8963}
    9064
    91 // read of the event fd is not done by a connection
    92 // use nullptr as the user data
     65static void submit(struct io_uring * ) {
     66        // io_uring_submit(ring);
     67}
     68
     69//=========================================================
    9370static void ring_end(struct io_uring * ring, int fd, char * buffer, size_t len) {
    9471        struct io_uring_sqe * sqe = get_sqe(ring);
    9572        io_uring_prep_read(sqe, fd, buffer, len, 0);
    96         io_uring_sqe_set_data(sqe, nullptr);
    97         io_uring_submit(ring);
     73        io_uring_sqe_set_data(sqe, request_t::create(EVENT_END));
     74        submit(ring);
     75}
     76
     77static 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
     86static 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;
    9896}
    9997
    10098//=========================================================
    101 // All answers are fixed and determined by the return code
    10299enum HttpCode {
    103100        OK200 = 0,
     
    111108};
    112109
    113 // Get a fix reply based on the return code
    114110const char * http_msgs[] = {
    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",
     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",
    122118};
    123 static_assert( KNOWN_CODES == (sizeof(http_msgs) / sizeof(http_msgs[0])) );
    124 
    125 // Pre-compute the length of these replys
    126 const 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]),
     119
     120static_assert( KNOWN_CODES == (sizeof(http_msgs ) / sizeof(http_msgs [0])));
     121
     122const int http_codes[] = {
     123        200,
     124        400,
     125        404,
     126        405,
     127        408,
     128        413,
     129        414,
    134130};
    135 static_assert( KNOWN_CODES == (sizeof(http_lens) / sizeof(http_lens[0])) );
     131
     132static_assert( KNOWN_CODES == (sizeof(http_codes) / sizeof(http_codes[0])));
     133
     134int code_val(HttpCode code) {
     135        return http_codes[code];
     136}
     137
     138static 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
     154static 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}
    136197
    137198//=========================================================
    138 // Finate state machine responsible for handling each connection
    139 class __attribute__((aligned(128))) connection {
    140 private:
    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 
    166 private:
    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);
     199static 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
     210static 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);
    245218                                return;
    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         }
    395 public:
    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 };
     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
     261static 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}
    420289
    421290//=========================================================
    422 // Main loop of the WebServer
    423 // Effectively uses one thread_local copy of everything per kernel thread
     291extern "C" {
     292extern int __io_uring_flush_sq(struct io_uring *ring);
     293}
     294
    424295void * proc_loop(void * arg) {
    425         // Get the thread local argument
     296        size_t count = 0;
    426297        struct options_t & opt = *(struct options_t *)arg;
     298
    427299        struct io_uring * ring = opt.ring;
    428300
    429         // Track the shutdown using a event_fd
    430301        char endfd_buf[8];
    431302        ring_end(ring, opt.endfd, endfd_buf, 8);
    432303
    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
     304        ring_accept(ring, opt.acpt.sockfd, opt.acpt.addr, opt.acpt.addrlen, opt.acpt.flags);
     305
     306        bool done = false;
    441307        while(!done) {
    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) );
     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) );
    448322                        exit(EXIT_FAILURE);
    449323                }
    450324
    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) {
     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:
    462330                                done = true;
    463331                                break;
    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;
     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;
    503349}
    504350
    505351//=========================================================
    506 #include <bit> // for ispow2
    507 
     352struct __attribute__((aligned(128))) aligned_ring {
     353        struct io_uring storage;
     354};
     355
     356#include <bit>
     357
     358#include <pthread.h>
    508359extern "C" {
    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
     360        #include <signal.h>
     361        #include <sys/eventfd.h>
     362        #include <sys/socket.h>
     363        #include <netinet/in.h>
    514364}
    515365
    516366int 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
    523367        signal(SIGPIPE, SIG_IGN);
    524368
    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
    532 
    533         //===================
    534         // Arguments Parsing
     369        unsigned nthreads = 1;
     370        unsigned port = 8800;
     371        unsigned entries = 256;
     372        unsigned backlog = 10;
     373        bool attach = false;
     374
     375        //===================
     376        // Arguments
    535377        int c;
    536         while ((c = getopt (argc, argv, "t:p:e:b:aS")) != -1) {
     378        while ((c = getopt (argc, argv, "t:p:e:b:a")) != -1) {
    537379                switch (c)
    538380                {
     
    552394                        attach = true;
    553395                        break;
    554                 case 'S':
    555                         sqpoll = true;
    556                         break;
    557396                case '?':
    558397                default:
    559                         std::cerr << "Usage: -t <threads> -p <port> -e <entries> -b <backlog> -aS" << std::endl;
     398                        std::cerr << "Usage: -t <threads> -p <port> -e <entries> -b <backlog> -a" << std::endl;
    560399                        return EXIT_FAILURE;
    561400                }
     
    577416        //===================
    578417        // End FD
    579         // Create a single event fd to notify the kernel threads when the server shutsdown
    580418        int efd = eventfd(0, EFD_SEMAPHORE);
    581419        if (efd < 0) {
     
    586424        //===================
    587425        // Open Socket
    588         // Listen on specified port
    589426        std::cout << getpid() << " : Listening on port " << port << std::endl;
    590427        int server_fd = socket(AF_INET, SOCK_STREAM, 0);
     
    602439        address.sin_port = htons( port );
    603440
    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
    606441        int waited = 0;
    607442        while(true) {
     
    609444                if(ret < 0) {
    610445                        if(errno == EADDRINUSE) {
    611                                 // Port is in used let's retry later
    612446                                if(waited == 0) {
    613447                                        std::cerr << "Waiting for port" << std::endl;
    614448                                } else {
    615                                         // To be cure, print how long we have been waiting
    616449                                        std::cerr << "\r" << waited;
    617450                                        std::cerr.flush();
    618451                                }
    619452                                waited ++;
    620                                 usleep( 1000000 ); // Wait and retry
     453                                usleep( 1000000 );
    621454                                continue;
    622455                        }
    623                         // Some other error occured, this is a real error
    624456                        std::cerr << "bind error: (" << errno << ") " << strerror(errno) << std::endl;
    625457                        exit(EXIT_FAILURE);
     
    642474        std::cout << std::endl;
    643475
    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         };
    651476        aligned_ring thrd_rings[nthreads];
    652477        pthread_t    thrd_hdls[nthreads];
    653478        options_t    thrd_opts[nthreads];
    654         bool no_drops  = true;
    655         bool fast_poll = true;
    656         bool nfix_sqpl = true;
    657479        for(unsigned i = 0; i < nthreads; i++) {
    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;
     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;
    667487                        p.wq_fd = thrd_rings[0].storage.ring_fd;
    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
     488                        io_uring_queue_init_params(entries, &thrd_rings[i].storage, &p);
     489                }
     490
    679491                thrd_opts[i].acpt.sockfd  = server_fd;
    680492                thrd_opts[i].acpt.addr    = (struct sockaddr *)&address;
     
    691503        }
    692504
    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;
    697 
    698505        //===================
    699506        // Server Started
     
    703510                int ret;
    704511                do {
    705                         // Wait for a Ctrl-D to close the server
    706512                        ret = read(STDIN_FILENO, buffer, 128);
    707513                        if(ret < 0) {
     
    720526
    721527        //===================
    722         // Use eventfd_write to tell the threads we are closing
    723528        (std::cout << "Sending Shutdown to Threads... ").flush();
    724529        ret = eventfd_write(efd, nthreads);
     
    730535
    731536        //===================
    732         // Join all the threads and close the rings
    733537        (std::cout << "Stopping Threads Done... ").flush();
     538        size_t total = 0;
     539        size_t count = 0;
    734540        for(unsigned i = 0; i < nthreads; i++) {
    735541                void * retval;
     
    739545                        exit(EXIT_FAILURE);
    740546                }
     547                // total += (size_t)retval;
     548                total += thrd_opts[i].result.subs;
     549                count += thrd_opts[i].result.cnts;
    741550
    742551                io_uring_queue_exit(thrd_opts[i].ring);
    743552        }
    744553        std::cout << "done" << std::endl;
    745 
    746         //===================
    747         // Close the sockets
     554        std::cout << "Submit average: " << total << "/" << count << "(" << (((double)total) / count) << ")" << std::endl;
     555
     556        //===================
    748557        (std::cout << "Closing Socket... ").flush();
    749558        ret = shutdown( server_fd, SHUT_RD );
     
    758567                exit(EXIT_FAILURE);
    759568        }
    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;
    771 }
    772 
    773 // compile-command: "g++ http_ring.cpp -std=c++2a -pthread -luring -O3" //
     569        std::cout << "done" << std::endl;
     570}
  • doc/theses/andrew_beach_MMath/existing.tex

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

    r3b402339 r144fa5c  
    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

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

    r3b402339 r144fa5c  
    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
    74 of the Examining Committee is by majority vote.
    75   \bigskip
    76 
    77   \noindent
    78 \begin{tabbing}
    79 Internal-External Member: \=  \kill % using longest text to define tab length
    80 External Examiner: \>  Bruce Bruce \\
     73The 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}
     78Internal-External Member: \=  \kill % using longest text to define tab length
     79External Examiner: \>  Bruce Bruce \\
    8180\> Professor, Dept. of Philosophy of Zoology, University of Wallamaloo \\
    82 \end{tabbing}
    83   \bigskip
    84 
     81\end{tabbing} 
     82  \bigskip
     83 
    8584  \noindent
    8685\begin{tabbing}
     
    9291\end{tabbing}
    9392  \bigskip
    94 
     93 
    9594  \noindent
    9695  \begin{tabbing}
     
    10099\end{tabbing}
    101100  \bigskip
    102 
     101 
    103102  \noindent
    104103\begin{tabbing}
     
    108107\end{tabbing}
    109108  \bigskip
    110 
     109 
    111110  \noindent
    112111\begin{tabbing}
     
    124123  % December 13th, 2006.  It is designed for an electronic thesis.
    125124  \noindent
    126 I hereby declare that I am the sole author of this thesis. This is a true copy
    127 of the thesis, including any required final revisions, as accepted by my
    128 examiners.
    129 
    130   \bigskip
    131 
     125I 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 
    132129  \noindent
    133130I understand that my thesis may be made electronically available to the public.
  • doc/theses/andrew_beach_MMath/thesis.tex

    r3b402339 r144fa5c  
    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

    r3b402339 r144fa5c  
    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
    50 % Roman numerals starting with `ii'.
     49% The rest of the front pages should contain no headers and be numbered using Roman numerals starting with `ii'
    5150\pagestyle{plain}
    5251\setcounter{page}{2}
    5352
    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.
     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.
    5855
    59 \begin{comment}
     56\begin{comment} 
    6057% E X A M I N I N G   C O M M I T T E E (Required for Ph.D. theses only)
    6158% Remove or comment out the lines below to remove this page
    6259\begin{center}\textbf{Examining Committee Membership}\end{center}
    6360  \noindent
    64 The following served on the Examining Committee for this thesis.
    65 The decision of the Examining Committee is by majority vote.
     61The following served on the Examining Committee for this thesis. The decision of the Examining Committee is by majority vote.
    6662  \bigskip
    67 
     63 
    6864  \noindent
    6965\begin{tabbing}
    7066Internal-External Member: \=  \kill % using longest text to define tab length
    71 External Examiner: \>  Bruce Bruce \\
     67External Examiner: \>  Bruce Bruce \\ 
    7268\> Professor, Dept. of Philosophy of Zoology, University of Wallamaloo \\
    73 \end{tabbing}
     69\end{tabbing} 
    7470  \bigskip
    75 
     71 
    7672  \noindent
    7773\begin{tabbing}
     
    8379\end{tabbing}
    8480  \bigskip
    85 
     81 
    8682  \noindent
    8783  \begin{tabbing}
     
    9187\end{tabbing}
    9288  \bigskip
    93 
     89 
    9490  \noindent
    9591\begin{tabbing}
     
    9995\end{tabbing}
    10096  \bigskip
    101 
     97 
    10298  \noindent
    10399\begin{tabbing}
     
    115111  % December 13th, 2006.  It is designed for an electronic thesis.
    116112 \begin{center}\textbf{Author's Declaration}\end{center}
    117 
     113 
    118114 \noindent
    119 I hereby declare that I am the sole author of this thesis. This is a true copy
    120 of the thesis, including any required final revisions, as accepted by my
    121 examiners.
     115I 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.
    122116
    123117  \bigskip
    124 
     118 
    125119  \noindent
    126120I understand that my thesis may be made electronically available to the public.
  • doc/theses/andrew_beach_MMath/uw-ethesis.tex

    r3b402339 r144fa5c  
    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
    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.
     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.
    1614%======================================================================
    1715% Some important notes on using this template and making it your own...
    1816
    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.
     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.
    3128% See additional notes below.
    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 
     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 
    4335% E.g. to process a thesis called "mythesis.tex" based on this template, run:
    4436
    4537% pdflatex mythesis     -- first pass of the pdflatex processor
    4638% bibtex mythesis       -- generates bibliography from .bib data file(s)
    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.
     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.
    6651% Tip: Photographs should be cropped and compressed so as not to be too large.
    6752
    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 % ======================================================================
     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%======================================================================
    7558%   D O C U M E N T   P R E A M B L E
    76 % Specify the document class, default style attributes, page dimensions, etc.
     59% Specify the document class, default style attributes, and page dimensions, etc.
    7760% For hyperlinked PDF, suitable for viewing on a computer, use this:
    7861\documentclass[letterpaper,12pt,titlepage,oneside,final]{book}
    7962
    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:
     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:
    8364%\documentclass[letterpaper,12pt,titlepage,openright,twoside,final]{book}
    8465
    8566% Some LaTeX commands I define for my own nomenclature.
    86 % If you have to, it's easier to make changes to nomenclature once here than
    87 % in a million places throughout your thesis!
     67% If you have to, it's easier to make changes to nomenclature once here than in a million places throughout your thesis!
    8868\newcommand{\package}[1]{\textbf{#1}} % package names in bold text
    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).
     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).
    9271%\newcommand{\texorpdfstring}[2]{#1} % does nothing, but defines the command
    9372% Anything defined here may be redefined by packages added below...
     
    9776\newboolean{PrintVersion}
    9877\setboolean{PrintVersion}{false}
    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.
     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.
    10179
    10280%\usepackage{nomencl} % For a nomenclature (optional; available from ctan.org)
    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}
     81\usepackage{amsmath,amssymb,amstext} % Lots of math symbols and environments
     82\usepackage[pdftex]{graphicx} % For including graphics N.B. pdftex graphics driver
    10783
    10884% Hyperlinks make it very easy to navigate an electronic 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.
     85% In addition, this is where you should specify the thesis title and author as they appear in the properties of the PDF document.
    11186% Use the "hyperref" package
    11287% N.B. HYPERREF MUST BE THE LAST PACKAGE LOADED; ADD ADDITIONAL PKGS ABOVE
    11388\usepackage[pdftex,pagebackref=true]{hyperref} % with basic options
    11489%\usepackage[pdftex,pagebackref=true]{hyperref}
    115 % N.B. pagebackref=true provides links back from the References to the body
    116 % text. This can cause trouble for printing.
     90                % N.B. pagebackref=true provides links back from the References to the body text. This can cause trouble for printing.
    11791\hypersetup{
    11892    plainpages=false,       % needed if Roman numbers in frontpages
     
    12296    pdffitwindow=false,     % window fit to page when opened
    12397    pdfstartview={FitH},    % fits the width of the page to the window
    124 %    pdftitle={uWaterloo\ LaTeX\ Thesis\ Template}, % title: CHANGE THIS TEXT!
     98%    pdftitle={uWaterloo\ LaTeX\ Thesis\ Template},    % title: CHANGE THIS TEXT!
    12599%    pdfauthor={Author},    % author: CHANGE THIS TEXT! and uncomment this line
    126100%    pdfsubject={Subject},  % subject: CHANGE THIS TEXT! and uncomment this line
    127 %    pdfkeywords={keyword1} {key2} {key3}, % optional list of keywords
     101%    pdfkeywords={keyword1} {key2} {key3}, % list of keywords, and uncomment this line if desired
    128102    pdfnewwindow=true,      % links in new window
    129103    colorlinks=true,        % false: boxed links; true: colored links
     
    133107    urlcolor=cyan           % color of external links
    134108}
    135 % for improved print quality, change some hyperref options
    136 \ifthenelse{\boolean{PrintVersion}}{
     109\ifthenelse{\boolean{PrintVersion}}{   % for improved print quality, change some hyperref options
    137110\hypersetup{    % override some previously defined hyperref options
    138111%    colorlinks,%
     
    143116}{} % end of ifthenelse (no else)
    144117
    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.
     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.
    151122
    152123% Setting up the page margins...
    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:
     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:
    162129\setlength{\marginparwidth}{0pt} % width of margin notes
    163130% N.B. If margin notes are used, you must adjust \textwidth, \marginparwidth
    164131% and \marginparsep so that the space left between the margin notes and page
    165132% edge is less than 15 mm (0.6 in.)
    166 % width of space between body text and margin notes
    167 \setlength{\marginparsep}{0pt}
    168 % Adds 1/8 in. to binding side of all
     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
    169135% even-numbered pages when the "twoside" printing option is selected
    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}
     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
    176138\raggedbottom
    177139
    178 % The following statement specifies the amount of space between paragraphs.
    179 % Other reasonable specifications are \bigskipamount and \smallskipamount.
     140% The following statement specifies the amount of space between paragraphs. Other reasonable specifications are \bigskipamount and \smallskipamount.
    180141\setlength{\parskip}{\medskipamount}
    181142
    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.
     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.
    185145\renewcommand{\baselinestretch}{1} % this is the default line space setting
    186146
    187147% By default, each chapter will start on a recto (right-hand side) 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.
     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.
    193151\let\origdoublepage\cleardoublepage
    194152\newcommand{\clearemptydoublepage}{%
     
    196154\let\cleardoublepage\clearemptydoublepage
    197155
    198 % Define Glossary terms (This is properly done here, in the preamble and
    199 % could also be \input{} from a separate file...)
     156% Define Glossary terms (This is properly done here, in the preamble and could also be \input{} from a separate file...)
    200157\input{glossaries}
    201158\makeglossaries
     
    212169%   L O G I C A L    D O C U M E N T
    213170% The logical document contains the main content of your thesis.
    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.
     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.
    217172%======================================================================
    218173\begin{document}
     
    221176% FRONT MATERIAL
    222177% title page,declaration, borrowers' page, abstract, acknowledgements,
    223 % dedication, table of contents, list of tables, list of figures,
    224 % nomenclature, etc.
    225 %----------------------------------------------------------------------
    226 \input{uw-ethesis-frontpgs}
     178% dedication, table of contents, list of tables, list of figures, nomenclature, etc.
     179%----------------------------------------------------------------------
     180\input{uw-ethesis-frontpgs}
    227181
    228182%----------------------------------------------------------------------
    229183% MAIN BODY
    230184% We suggest using a separate file for each chapter of your thesis.
    231 % Start each chapter file with the \chapter command. Only use \documentclass,
    232 % \begin{document} and \end{document} commands in this master document.
     185% Start each chapter file with the \chapter command.
     186% Only use \documentclass or \begin{document} and \end{document} commands in this master document.
    233187% Tip: Putting each sentence on a new line is a way to simplify later editing.
    234188%----------------------------------------------------------------------
     
    246200% Bibliography
    247201
    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.
     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.
    251204\bibliographystyle{plain}
    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:
     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:
    263211\renewcommand*{\bibname}{References}
    264212
     
    267215
    268216\bibliography{uw-ethesis,pl}
    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).
     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).
    276222% \nocite{*}
    277223%----------------------------------------------------------------------
     
    281227% The \appendix statement indicates the beginning of the appendices.
    282228\appendix
    283 % Add an un-numbered title page before the appendices and a line in the Table
    284 % of Contents
     229% Add an un-numbered title page before the appendices and a line in the Table of Contents
    285230% \chapter*{APPENDICES}
    286231% \addcontentsline{toc}{chapter}{APPENDICES}
    287 % Appendices are just more chapters, with different labeling (letters instead
    288 % of numbers).
     232% Appendices are just more chapters, with different labeling (letters instead of numbers).
    289233% \input{appendix-matlab_plots.tex}
    290234
    291 % GLOSSARIES (Lists of definitions, abbreviations, symbols, etc.
    292 % provided by the glossaries-extra package)
     235% GLOSSARIES (Lists of definitions, abbreviations, symbols, etc. provided by the glossaries-extra package)
    293236% -----------------------------
    294237\printglossaries
  • libcfa/src/memory.cfa

    r3b402339 r144fa5c  
    1010// Created On       : Tue Jun  2 16:48:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Feb  1 16:10:00 2021
    13 // Update Count     : 1
     12// Last Modified On : Tue Jun  3 12:30:00 2020
     13// Update Count     : 0
    1414//
    1515
     
    5656}
    5757
    58 forall(T & | sized(T))
     58forall(T & | sized(T) | { void ^?{}(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);
    6263        internal_copy(this, that);
    6364}
     
    6566forall(T & | sized(T), Args... | { void ?{}(T&, Args); })
    6667void ?{}(counter_ptr(T) & this, Args args) {
    67         this.data = malloc();
    68         this.data->counter = 1;
    69         (this.data->object){args};
     68        this.data = (counter_data(T)*)new(args);
    7069}
    7170
     
    127126forall(T & | sized(T), Args... | { void ?{}(T &, Args); })
    128127void ?{}(unique_ptr(T) & this, Args args) {
    129         this.data = malloc();
    130         (*this.data){args};
     128        this.data = (T *)new(args);
    131129}
    132130
  • libcfa/src/memory.hfa

    r3b402339 r144fa5c  
    1010// Created On       : Tue Jun  2 16:48:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jan 29 15:52:00 2021
    13 // Update Count     : 1
     12// Last Modified On : Tue Jun  3 12:29:00 2020
     13// Update Count     : 0
    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)) {
     20        struct counter_data {
     21                unsigned int counter;
     22                T object;
     23        };
    2424
    25 forall(T & | sized(T), Args... | { void ?{}(T &, Args); })
    26 void ?{}(counter_data(T) & this, Args args);
     25        forall(Args... | { void ?{}(T &, Args); })
     26        void ?{}(counter_data(T) & this, Args args);
    2727
    28 forall(T & | sized(T) | { void ^?{}(T &); })
    29 void ^?{}(counter_data(T) & this);
     28        forall( | { void ^?{}(T &); })
     29        void ^?{}(counter_data(T) & this);
     30}
    3031
    3132// This is one of many pointers keeping this alive.
    32 forall(T & | sized(T))
    33 struct counter_ptr {
    34         counter_data(T) * data;
    35 };
     33forall(T & | sized(T)) {
     34        struct counter_ptr {
     35                counter_data(T) * data;
     36        };
    3637
    37 forall(T & | sized(T))
    38 void ?{}(counter_ptr(T) & this);
    39 forall(T & | sized(T))
    40 void ?{}(counter_ptr(T) & this, zero_t);
    41 forall(T & | sized(T))
    42 void ?{}(counter_ptr(T) & this, counter_ptr(T) that);
    43 forall(T & | sized(T), Args... | { void ?{}(T&, Args); })
    44 void ?{}(counter_ptr(T) & this, Args args);
     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);
    4544
    46 forall(T & | sized(T) | { void ^?{}(T &); })
    47 void ^?{}(counter_ptr(T) & this);
     45        forall( | { void ^?{}(T &); })
     46        void ^?{}(counter_ptr(T) & this);
    4847
    49 forall(T & | sized(T))
    50 T & *?(counter_ptr(T) & this);
     48        T & *?(counter_ptr(T) & this);
    5149
    52 forall(T & | sized(T) | { void ^?{}(T &); })
    53 void ?=?(counter_ptr(T) & this, counter_ptr(T) that);
    54 forall(T & | sized(T) | { void ^?{}(T &); })
    55 void ?=?(counter_ptr(T) & this, zero_t);
     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);
    5654
    57 forall(T & | sized(T))
    58 int ?==?(counter_ptr(T) const & this, counter_ptr(T) const & that);
    59 forall(T & | sized(T))
    60 int ?!=?(counter_ptr(T) const & this, counter_ptr(T) const & that);
    61 forall(T & | sized(T))
    62 int ?==?(counter_ptr(T) const & this, zero_t);
    63 forall(T & | sized(T))
    64 int ?!=?(counter_ptr(T) const & this, zero_t);
     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}
    6560
    6661// This is the only pointer that keeps this alive.
    67 forall(T &)
    68 struct unique_ptr {
    69         T * data;
    70 };
     62forall(T &) {
     63        struct unique_ptr {
     64                T * data;
     65        };
    7166
    72 forall(T &)
    73 void ?{}(unique_ptr(T) & this);
    74 forall(T &)
    75 void ?{}(unique_ptr(T) & this, zero_t);
    76 forall(T &)
    77 void ?{}(unique_ptr(T) & this, unique_ptr(T) that) = void;
    78 forall(T & | sized(T), Args... | { void ?{}(T &, Args); })
    79 void ?{}(unique_ptr(T) & this, Args args);
     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);
    8072
    81 forall(T & | { void ^?{}(T &); })
    82 void ^?{}(unique_ptr(T) & this);
     73        forall( | { void ^?{}(T &); })
     74        void ^?{}(unique_ptr(T) & this);
    8375
    84 forall(T & )
    85 T & *?(unique_ptr(T) & this);
     76        T & *?(unique_ptr(T) & this);
    8677
    87 forall(T &)
    88 void ?=?(unique_ptr(T) & this, unique_ptr(T) that) = void;
    89 forall(T & | { void ^?{}(T &); })
    90 void ?=?(unique_ptr(T) & this, zero_t);
     78        void ?=?(unique_ptr(T) & this, unique_ptr(T) that) = void;
     79        forall( | { void ^?{}(T &); })
     80        void ?=?(unique_ptr(T) & this, zero_t);
    9181
    92 forall(T & | { void ^?{}(T &); })
    93 void move(unique_ptr(T) & this, unique_ptr(T) & that);
     82        forall( | { void ^?{}(T &); })
     83        void move(unique_ptr(T) & this, unique_ptr(T) & that);
    9484
    95 forall(T &)
    96 int ?==?(unique_ptr(T) const & this, unique_ptr(T) const & that);
    97 forall(T &)
    98 int ?!=?(unique_ptr(T) const & this, unique_ptr(T) const & that);
    99 forall(T &)
    100 int ?==?(unique_ptr(T) const & this, zero_t);
    101 forall(T &)
    102 int ?!=?(unique_ptr(T) const & this, zero_t);
     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}
  • tests/smart-pointers.cfa

    r3b402339 r144fa5c  
    22
    33#include <memory.hfa>
    4 #include <assert.h>
     4#include <stdlib.hfa>
    55
    66void counter_test(void) {
     
    5353}
    5454
    55 void 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 
    6755int main(int argc, char * argv[]) {
    6856        counter_test();
    6957        unique_test();
    7058        pointer_equality();
    71 
    72         printf("done\n");
    7359}
Note: See TracChangeset for help on using the changeset viewer.