source: benchmark/io/http/protocol.cfa

Last change on this file was 17c6edeb, checked in by Thierry Delisle <tdelisle@…>, 6 weeks ago

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

  • Property mode set to 100644
File size: 19.1 KB
Line 
1#include "protocol.hfa"
2
3#define _GNU_SOURCE
4extern "C" {
5        #include <fcntl.h>
6}
7
8#define xstr(s) str(s)
9#define str(s) #s
10
11#include <fstream.hfa>
12#include <iofwd.hfa>
13#include <io/types.hfa>
14#include <mutex_stmt.hfa>
15
16#include <assert.h>
17// #include <stdio.h> // Don't use stdio.h, too slow to compile
18extern "C" {
19      int snprintf ( char * s, size_t n, const char * format, ... );
20        ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
21        // #include <linux/io_uring.h>
22}
23#include <string.h>
24#include <errno.h>
25
26#include "options.hfa"
27#include "worker.hfa"
28
29#define PLAINTEXT_1WRITE
30#define PLAINTEXT_MEMCPY
31#define PLAINTEXT_NOCOPY
32// #define LINKED_IO
33#define TRUE_SENDFILE
34
35static inline __s32 wait_res( io_future_t & this ) {
36        wait( this );
37        if( this.result < 0 ) {{
38                errno = -this.result;
39                return -1;
40        }}
41        return this.result;
42}
43
44struct https_msg_str {
45        char msg[512];
46        size_t len;
47};
48
49const https_msg_str * volatile http_msgs[KNOWN_CODES] = { 0 };
50
51_Static_assert( KNOWN_CODES == (sizeof(http_msgs ) / sizeof(http_msgs [0])));
52
53const int http_codes[KNOWN_CODES] = {
54        200,
55        200,
56        400,
57        404,
58        405,
59        408,
60        413,
61        414,
62};
63
64_Static_assert( KNOWN_CODES == (sizeof(http_codes) / sizeof(http_codes[0])));
65
66int code_val(HttpCode code) {
67        return http_codes[code];
68}
69
70static inline int answer( int fd, const char * it, int len ) {
71        while(len > 0) {
72                // Call write
73                int ret = cfa_send(fd, it, len, 0, CFA_IO_LAZY);
74                if( ret < 0 ) {
75                        if( errno == ECONNRESET || errno == EPIPE || errno == EBADF ) {
76                                ret = close(fd);
77                                if( ret != 0 ) abort( "close in 'answer' error: (%d) %s\n", (int)errno, strerror(errno) );
78                                return -ECONNRESET;
79                        }
80
81                        abort( "'answer error' error: (%d) %s\n", (int)errno, strerror(errno) );
82                }
83
84                // update it/len
85                it  += ret;
86                len -= ret;
87        }
88        return 0;
89}
90
91// int answer_error( int fd, HttpCode code ) {
92//      /* paranoid */ assert( code < KNOWN_CODES && code != OK200 );
93//      int idx = (int)code;
94//      return answer( fd, http_msgs[idx]->msg, http_msgs[idx]->len );
95// }
96
97static int fill_header(char * it, size_t size) {
98        memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
99        it += http_msgs[OK200]->len;
100        int len = http_msgs[OK200]->len;
101        len += snprintf(it, 512 - len, "%d \n\n", size);
102        return len;
103}
104
105static int answer_header( int fd, size_t size ) {
106        char buffer[512];
107        int len = fill_header(buffer, size);
108        return answer( fd, buffer, len );
109}
110
111// #if defined(PLAINTEXT_NOCOPY)
112// int answer_plaintext( int fd ) {
113//      return answer(fd, http_msgs[OK200_PlainText]->msg, http_msgs[OK200_PlainText]->len); // +1 cause snprintf doesn't count nullterminator
114// }
115// #elif defined(PLAINTEXT_MEMCPY)
116// #define TEXTSIZE 15
117// int answer_plaintext( int fd ) {
118//      char text[] = "Hello, World!\n\n";
119//      char ts[] = xstr(TEXTSIZE) " \n\n";
120//      _Static_assert(sizeof(text) - 1 == TEXTSIZE);
121//      char buffer[512 + TEXTSIZE];
122//      char * it = buffer;
123//      memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
124//      it += http_msgs[OK200]->len;
125//      int len = http_msgs[OK200]->len;
126//      memcpy(it, ts, sizeof(ts) - 1);
127//      it += sizeof(ts) - 1;
128//      len += sizeof(ts) - 1;
129//      memcpy(it, text, TEXTSIZE);
130//      return answer(fd, buffer, len + TEXTSIZE);
131// }
132// #elif defined(PLAINTEXT_1WRITE)
133// int answer_plaintext( int fd ) {
134//      char text[] = "Hello, World!\n\n";
135//      char buffer[512 + sizeof(text)];
136//      char * it = buffer;
137//      memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
138//      it += http_msgs[OK200]->len;
139//      int len = http_msgs[OK200]->len;
140//      int r = snprintf(it, 512 - len, "%d \n\n", sizeof(text));
141//      it += r;
142//      len += r;
143//      memcpy(it, text, sizeof(text));
144//      return answer(fd, buffer, len + sizeof(text));
145// }
146// #else
147// int answer_plaintext( int fd ) {
148//      char text[] = "Hello, World!\n\n";
149//      int ret = answer_header(fd, sizeof(text));
150//      if( ret < 0 ) return ret;
151//      return answer(fd, text, sizeof(text));
152// }
153// #endif
154
155// int answer_empty( int fd ) {
156//      return answer_header(fd, 0);
157// }
158
159static int sendfile( int pipe[2], int fd, int ans_fd, size_t count, sendfile_stats_t & stats ) {
160        int zipf_idx = -1;
161        STATS: for(i; zipf_cnts) {
162                if(count <= zipf_sizes[i]) {
163                        zipf_idx = i;
164                        break STATS;
165                }
166        }
167        if(zipf_idx < 0) mutex(serr) serr | "SENDFILE" | count | " greated than biggest zipf file";
168
169        #if defined(TRUE_SENDFILE)
170                off_t offset = 0;
171                ssize_t ret;
172                int flags = fcntl(fd, F_GETFL);
173                if(flags < 0) abort("getfl in 'true sendfile' error: (%d) %s\n", (int)errno, strerror(errno) );
174                ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
175                if(ret < 0) abort("setfl in 'true sendfile' error: (%d) %s\n", (int)errno, strerror(errno) );
176
177                while(count) {
178                        ret = sendfile(fd, ans_fd, &offset, count);
179                        if( ret <= 0 ) {
180                                if( errno == EAGAIN || errno == EWOULDBLOCK ) {
181                                        stats.eagain++;
182                                        yield();
183                                        continue;
184                                }
185                                if( errno == ECONNRESET || errno == EPIPE ) {
186                                        ret = close(fd);
187                                        if( ret != 0 ) abort( "close in 'true sendfile' error: (%d) %s\n", (int)errno, strerror(errno) );
188                                        return -ECONNRESET;
189                                }
190                                abort( "sendfile error: %d (%d) %s\n", ret, (int)errno, strerror(errno) );
191                        }
192                        count -= ret;
193                        stats.splcin++;
194                        if(count > 0) stats.avgrd[zipf_idx].calls++;
195                        stats.avgrd[zipf_idx].bytes += ret;
196                }
197
198                ret = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
199                if(ret < 0) abort("resetfl in 'true sendfile' error: (%d) %s\n", (int)errno, strerror(errno) );
200        #else
201                #error not implemented
202                // unsigned sflags = SPLICE_F_MOVE; // | SPLICE_F_MORE;
203                // off_t offset = 0;
204                // ssize_t ret;
205                // SPLICE1: while(count > 0) {
206                //      stats.tries++;
207                //      // ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, sflags, CFA_IO_LAZY);
208                //      ret = splice(ans_fd, &offset, pipe[1], 0p, count, sflags);
209                //      if( ret <= 0 ) {
210                //              if( errno == ECONNRESET || errno == EPIPE ) {
211                //                      ret = close(fd);
212                //                      if( ret != 0 ) abort( "close in 'sendfile splice in' error: (%d) %s\n", (int)errno, strerror(errno) );
213                //                      return -ECONNRESET;
214                //              }
215                //              abort( "splice [0] error: %d (%d) %s\n", ret, (int)errno, strerror(errno) );
216                //      }
217                //      count -= ret;
218                //      stats.splcin++;
219                //      if(count > 0) stats.avgrd[zipf_idx].calls++;
220                //      stats.avgrd[zipf_idx].bytes += ret;
221
222                //      size_t in_pipe = ret;
223                //      SPLICE2: while(in_pipe > 0) {
224                //              ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, sflags, CFA_IO_LAZY);
225                //              // ret = splice(pipe[0], 0p, fd, 0p, in_pipe, sflags);
226                //              if( ret <= 0 ) {
227                //                      if( errno == ECONNRESET || errno == EPIPE ) {
228                //                              ret = close(fd);
229                //                              if( ret != 0 ) abort( "close in 'sendfile splice out' error: (%d) %s\n", (int)errno, strerror(errno) );
230                //                              return -ECONNRESET;
231                //                      }
232                //                      abort( "splice [1] error: %d (%d) %s\n", ret, (int)errno, strerror(errno) );
233                //              }
234                //              stats.splcot++;
235                //              in_pipe -= ret;
236                //      }
237
238                // }
239        #endif
240
241        return count;
242}
243
244// enum FSM_STATE {
245//      Initial,
246//      Retry,
247//      Error,
248//      Done,
249// };
250
251// struct FSM_Result {
252//      FSM_STATE state;
253//      int error;
254// };
255
256// static inline void ?{}(FSM_Result & this) { this.state = Initial; this.error = 0; }
257// static inline bool is_error(FSM_Result & this) { return Error == this.state; }
258// static inline bool is_done(FSM_Result & this) { return Done == this.state; }
259
260// static inline int error(FSM_Result & this, int error) {
261//      this.error = error;
262//      this.state = Error;
263//      return error;
264// }
265
266// static inline int done(FSM_Result & this) {
267//      this.state = Done;
268//      return 0;
269// }
270
271// static inline int retry(FSM_Result & this) {
272//      this.state = Retry;
273//      return 0;
274// }
275
276// static inline int need(FSM_Result & this) {
277//      switch(this.state) {
278//              case Initial:
279//              case Retry:
280//                      return 1;
281//              case Error:
282//                      if(this.error == 0) mutex(serr) serr | "State marked error but code is 0";
283//              case Done:
284//                      return 0;
285//      }
286// }
287
288// // Generator that handles sending the header
289// generator header_g {
290//      io_future_t f;
291//      const char * next;
292//      int fd; size_t len;
293//      FSM_Result res;
294// };
295
296// static inline void ?{}(header_g & this, int fd, const char * it, size_t len ) {
297//      this.next = it;
298//      this.fd = fd;
299//      this.len = len;
300// }
301
302// static inline void fill(header_g & this, struct io_uring_sqe * sqe) {
303//      zero_sqe(sqe);
304//      sqe->opcode = IORING_OP_SEND;
305//      sqe->user_data = (uintptr_t)&this.f;
306//      sqe->flags = IOSQE_IO_LINK;
307//      sqe->fd = this.fd;
308//      sqe->addr = (uintptr_t)this.next;
309//      sqe->len = this.len;
310// }
311
312// static inline int error(header_g & this, int error) {
313//      int ret = close(this.fd);
314//      if( ret != 0 ) {
315//              mutex(serr) serr | "Failed to close fd" | errno;
316//      }
317//      return error(this.res, error);
318// }
319
320// static inline int wait_and_process(header_g & this, sendfile_stats_t & stats) {
321//      wait(this.f);
322
323//      // Did something crazy happen?
324//      if(this.f.result > this.len) {
325//              mutex(serr) serr | "HEADER sent too much!";
326//              return error(this, -ERANGE);
327//      }
328
329//      // Something failed?
330//      if(this.f.result < 0) {
331//              int error = -this.f.result;
332//              if( error == ECONNRESET ) return error(this, -ECONNRESET);
333//              if( error == EPIPE ) return error(this, -EPIPE);
334//              if( error == ECANCELED ) {
335//                      mutex(serr) serr | "HEADER was cancelled, WTF!";
336//                      return error(this, -ECONNRESET);
337//              }
338//              if( error == EAGAIN || error == EWOULDBLOCK) {
339//                      mutex(serr) serr | "HEADER got eagain, WTF!";
340//                      return error(this, -ECONNRESET);
341//              }
342//      }
343
344//      // Done?
345//      if(this.f.result == this.len) {
346//              return done(this.res);
347//      }
348
349//      stats.header++;
350
351//      // It must be a Short read
352//      this.len  -= this.f.result;
353//      this.next += this.f.result;
354//      reset(this.f);
355//      return retry(this.res);
356// }
357
358// // Generator that handles splicing in a file
359// struct splice_in_t {
360//      io_future_t f;
361//      int fd; int pipe; size_t len; off_t off;
362//      short zipf_idx;
363//      FSM_Result res;
364// };
365
366// static inline void ?{}(splice_in_t & this, int fd, int pipe, size_t len) {
367//      this.fd = fd;
368//      this.pipe = pipe;
369//      this.len = len;
370//      this.off = 0;
371//      this.zipf_idx = -1;
372//      STATS: for(i; zipf_cnts) {
373//              if(len <= zipf_sizes[i]) {
374//                      this.zipf_idx = i;
375//                      break STATS;
376//              }
377//      }
378//      if(this.zipf_idx < 0) mutex(serr) serr | "SPLICE IN" | len | " greated than biggest zipf file";
379// }
380
381// static inline void fill(splice_in_t & this, struct io_uring_sqe * sqe) {
382//      zero_sqe(sqe);
383//      sqe->opcode = IORING_OP_SPLICE;
384//      sqe->user_data = (uintptr_t)&this.f;
385//      sqe->flags = 0;
386//      sqe->splice_fd_in = this.fd;
387//      sqe->splice_off_in = this.off;
388//      sqe->fd = this.pipe;
389//      sqe->off = (__u64)-1;
390//      sqe->len = this.len;
391//      sqe->splice_flags = SPLICE_F_MOVE;
392// }
393
394// static inline int wait_and_process(splice_in_t & this, sendfile_stats_t & stats ) {
395//      wait(this.f);
396
397//      // Something failed?
398//      if(this.f.result < 0) {
399//              int error = -this.f.result;
400//              if( error == ECONNRESET ) return error(this.res, -ECONNRESET);
401//              if( error == EPIPE ) return error(this.res, -EPIPE);
402//              if( error == ECANCELED ) {
403//                      mutex(serr) serr | "SPLICE IN was cancelled, WTF!";
404//                      return error(this.res, -ECONNRESET);
405//              }
406//              if( error == EAGAIN || error == EWOULDBLOCK) {
407//                      mutex(serr) serr | "SPLICE IN got eagain, WTF!";
408//                      return error(this.res, -ECONNRESET);
409//              }
410//              mutex(serr) serr | "SPLICE IN got" | error | ", WTF!";
411//              return error(this.res, -ECONNRESET);
412//      }
413
414//      // Did something crazy happen?
415//      if(this.f.result > this.len) {
416//              mutex(serr) serr | "SPLICE IN spliced too much!";
417//              return error(this.res, -ERANGE);
418//      }
419
420//      // Done?
421//      if(this.f.result == this.len) {
422//              return done(this.res);
423//      }
424
425//      stats.splcin++;
426//      stats.avgrd[this.zipf_idx].calls++;
427//      stats.avgrd[this.zipf_idx].bytes += this.f.result;
428
429//      // It must be a Short read
430//      this.len -= this.f.result;
431//      this.off += this.f.result;
432//      reset(this.f);
433//      return retry(this.res);
434// }
435
436// generator splice_out_g {
437//      io_future_t f;
438//      int pipe; int fd; size_t len;
439//      FSM_Result res;
440// };
441
442// static inline void ?{}(splice_out_g & this, int pipe, int fd, size_t len) {
443//      this.pipe = pipe;
444//      this.fd = fd;
445//      this.len = len;
446// }
447
448// static inline void fill(splice_out_g & this, struct io_uring_sqe * sqe) {
449//      zero_sqe(sqe);
450//      sqe->opcode = IORING_OP_SPLICE;
451//      sqe->user_data = (uintptr_t)&this.f;
452//      sqe->flags = 0;
453//      sqe->splice_fd_in = this.pipe;
454//      sqe->splice_off_in = (__u64)-1;
455//      sqe->fd = this.fd;
456//      sqe->off = (__u64)-1;
457//      sqe->len = this.len;
458//      sqe->splice_flags = SPLICE_F_MOVE;
459// }
460
461// static inline int error(splice_out_g & this, int error) {
462//      int ret = close(this.fd);
463//      if( ret != 0 ) {
464//              mutex(serr) serr | "Failed to close fd" | errno;
465//      }
466//      return error(this.res, error);
467// }
468
469// static inline void wait_and_process(splice_out_g & this, sendfile_stats_t & stats ) {
470//      wait(this.f);
471
472//      // Something failed?
473//      if(this.f.result < 0) {
474//              int error = -this.f.result;
475//              if( error == ECONNRESET ) return error(this, -ECONNRESET);
476//              if( error == EPIPE ) return error(this, -EPIPE);
477//              if( error == ECANCELED ) {
478//                      this.f.result = 0;
479//                      goto SHORT_WRITE;
480//              }
481//              if( error == EAGAIN || error == EWOULDBLOCK) {
482//                      mutex(serr) serr | "SPLICE OUT got eagain, WTF!";
483//                      return error(this, -ECONNRESET);
484//              }
485//              mutex(serr) serr | "SPLICE OUT got" | error | ", WTF!";
486//              return error(this, -ECONNRESET);
487//      }
488
489//      // Did something crazy happen?
490//      if(this.f.result > this.len) {
491//              mutex(serr) serr | "SPLICE OUT spliced too much!" | this.f.result | ">" | this.len;
492//              return error(this.res, -ERANGE);
493//      }
494
495//      // Done?
496//      if(this.f.result == this.len) {
497//              return done(this.res);
498//      }
499
500// SHORT_WRITE:
501//      stats.splcot++;
502
503//      // It must be a Short Write
504//      this.len -= this.f.result;
505//      reset(this.f);
506//      return retry(this.res);
507// }
508
509int answer_sendfile( int pipe[2], int fd, int ans_fd, size_t fsize, sendfile_stats_t & stats ) {
510        stats.calls++;
511        #if defined(LINKED_IO)
512                // char buffer[512];
513                // int len = fill_header(buffer, fsize);
514                // header_g header = { fd, buffer, len };
515                // splice_in_t splice_in = { ans_fd, pipe[1], fsize };
516                // splice_out_g splice_out = { pipe[0], fd, fsize };
517
518                // RETRY_LOOP: for() {
519                //      stats.tries++;
520                //      int have = need(header.res) + need(splice_in.res) + 1;
521                //      int idx = 0;
522                //      struct io_uring_sqe * sqes[3];
523                //      __u32 idxs[3];
524                //      struct io_context$ * ctx = cfa_io_allocate(sqes, idxs, have);
525
526                //      if(need(splice_in.res)) { fill(splice_in, sqes[idx++]); }
527                //      if(need(   header.res)) { fill(header   , sqes[idx++]); }
528                //      fill(splice_out, sqes[idx]);
529
530                //      // Submit everything
531                //      asm volatile("": : :"memory");
532                //      cfa_io_submit( ctx, idxs, have, false );
533
534                //      // wait for the results
535                //      // Always wait for splice-in to complete as
536                //      // we may need to kill the connection if it fails
537                //      // If it already completed, this is a no-op
538                //      wait_and_process(splice_in, stats);
539
540                //      if(is_error(splice_in.res)) {
541                //              if(splice_in.res.error == -EPIPE) return -ECONNRESET;
542                //              mutex(serr) serr | "SPLICE IN failed with" | splice_in.res.error;
543                //              int ret = close(fd);
544                //              if( ret != 0 ) abort( "close in 'answer sendfile' error: (%d) %s\n", (int)errno, strerror(errno) );
545                //      }
546
547                //      // Process the other 2
548                //      wait_and_process(header, stats);
549                //      wait_and_process(splice_out, stats);
550
551                //      if(is_done(splice_out.res)) {
552                //              break RETRY_LOOP;
553                //      }
554
555                //      // We need to wait for the completion if
556                //      // - both completed
557                //      // - the header failed
558                //      // -
559
560                //      if(  is_error(header.res)
561                //        || is_error(splice_in.res)
562                //        || is_error(splice_out.res)) {
563                //              return -ECONNRESET;
564                //      }
565                // }
566
567                // return len + fsize;
568        #else
569                int ret = answer_header(fd, fsize);
570                if( ret < 0 ) { return ret; }
571                return sendfile(pipe, fd, ans_fd, fsize, stats);
572        #endif
573}
574
575[HttpCode code, bool closed, * const char file, size_t len] http_read(volatile int & fd, []char buffer, size_t len, io_future_t * f) {
576        char * it = buffer;
577        size_t count = len - 1;
578        int rlen = 0;
579        READ:
580        for() {
581                int ret;
582                if( f ) {
583                        ret = wait_res(*f);
584                        reset(*f);
585                        f = 0p;
586                } else {
587                        ret = cfa_recv(fd, (void*)it, count, 0, CFA_IO_LAZY);
588                }
589                // int ret = read(fd, (void*)it, count);
590                if(ret == 0 ) {
591                        ret = close(fd);
592                        if( ret != 0 ) abort( "close in 'http read good' error: (%d) %s\n", (int)errno, strerror(errno) );
593                        return [OK200, true, 0, 0];
594                }
595                if(ret < 0 ) {
596                        if( errno == ECONNRESET || errno == EPIPE ) {
597                                ret = close(fd);
598                                if( ret != 0 ) abort( "close in 'http read bad' error: (%d) %s\n", (int)errno, strerror(errno) );
599                                return [E408, true, 0, 0];
600                        }
601                        abort( "read error: (%d) %s\n", (int)errno, strerror(errno) );
602                }
603                it[ret + 1] = '\0';
604                rlen += ret;
605
606                if( strstr( it, "\r\n\r\n" ) ) break;
607
608                it += ret;
609                count -= ret;
610
611                if( count < 1 ) return [E414, false, 0, 0];
612        }
613
614        if( options.log ) {
615                write(sout, buffer, rlen);
616                sout | nl;
617        }
618
619        it = buffer;
620        int ret = memcmp(it, "GET /", 5);
621        if( ret != 0 ) return [E400, false, 0, 0];
622        it += 5;
623
624        char * end = strstr( it, " " );
625        return [OK200, false, it, end - it];
626}
627
628//=============================================================================================
629
630#include <clock.hfa>
631#include <time.hfa>
632#include <thread.hfa>
633
634const char * original_http_msgs[] = {
635        "HTTP/1.1 200 OK\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: ",
636        "HTTP/1.1 200 OK\r\nServer: HttpForall\r\nConnection: keep-alive\r\nContent-Length: 15\r\nContent-Type: text/html\r\nDate: %s \r\n\r\nHello, World!\r\n",
637        "HTTP/1.1 400 Bad Request\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
638        "HTTP/1.1 404 Not Found\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
639        "HTTP/1.1 405 Method Not Allowed\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
640        "HTTP/1.1 408 Request Timeout\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
641        "HTTP/1.1 413 Payload Too Large\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
642        "HTTP/1.1 414 URI Too Long\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
643};
644
645struct date_buffer {
646        https_msg_str strs[KNOWN_CODES];
647};
648
649thread DateFormater {
650        int idx;
651        date_buffer buffers[2];
652};
653
654void ?{}( DateFormater & this ) {
655        ((thread&)this){ "Server Date Thread" };
656        this.idx = 0;
657        memset( &this.buffers[0], 0, sizeof(this.buffers[0]) );
658        memset( &this.buffers[1], 0, sizeof(this.buffers[1]) );
659}
660
661void main(DateFormater & this) {
662        LOOP: for() {
663                waitfor( ^?{} : this) {
664                        break LOOP;
665                }
666                or else {}
667
668
669                char buff[100];
670                Time now = timeHiRes();
671                strftime( buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now );
672                // if( options.log ) sout | "Updated date to '" | buff | "'";
673
674                for(i; KNOWN_CODES) {
675                        size_t len = snprintf( this.buffers[this.idx].strs[i].msg, 512, original_http_msgs[i], buff );
676                        this.buffers[this.idx].strs[i].len = len;
677                }
678
679                for(i; KNOWN_CODES) {
680                        https_msg_str * next = &this.buffers[this.idx].strs[i];
681                        __atomic_exchange_n((https_msg_str * volatile *)&http_msgs[i], next, __ATOMIC_SEQ_CST);
682                }
683                this.idx = (this.idx + 1) % 2;
684
685                // if( options.log ) sout | "Date thread sleeping";
686
687                sleep(1`s);
688        }
689}
690
691//=============================================================================================
692DateFormater * the_date_formatter;
693
694void init_protocol(void) {
695        the_date_formatter = alloc();
696        (*the_date_formatter){};
697}
698
699void deinit_protocol(void) {
700        ^(*the_date_formatter){};
701        free( the_date_formatter );
702}
Note: See TracBrowser for help on using the repository browser.