Changeset 7770cc8
- Timestamp:
- Nov 24, 2021, 9:47:56 PM (7 months ago)
- Branches:
- enum, master
- Children:
- 5235d49
- Parents:
- 94647b0 (diff), 3cc1111 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 21 added
- 1 deleted
- 86 edited
Legend:
- Unmodified
- Added
- Removed
-
benchmark/Makefile.am
r94647b0 r7770cc8 613 613 614 614 RDQBENCHES = \ 615 rdq-churn-cfa \ 615 616 rdq-cycle-cfa \ 616 617 rdq-cycle-tokio \ -
benchmark/io/http/filecache.cfa
r94647b0 r7770cc8 185 185 sout | "Filled cache from path \"" | path | "\" with" | fcount | "files"; 186 186 if( conflicts > 0 ) { 187 sout | "Found" | conflicts | "conflicts (s eed: " | options.file_cache.hash_seed | ")";187 sout | "Found" | conflicts | "conflicts (size: " | file_cache.size | ", seed: " | options.file_cache.hash_seed | ")"; 188 188 #if defined(REJECT_CONFLICTS) 189 189 abort("Conflicts found in the cache"); -
benchmark/io/http/http_ring.cpp
r94647b0 r7770cc8 118 118 // Get a fix reply based on the return code 119 119 const char * http_msgs[] = { 120 "HTTP/1.1 200 OK\r\nServer: Htt oForall\r\nContent-Type: text/plain\r\nContent-Length: 15\r\nConnection: keep-alive\r\n\r\nHello, World!\r\n",121 "HTTP/1.1 400 Bad Request\r\nServer: Htt oForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",122 "HTTP/1.1 404 Not Found\r\nServer: Htt oForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",123 "HTTP/1.1 405 Method Not \r\nServer: Htt oForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",124 "HTTP/1.1 408 Request Timeout\r\nServer: Htt oForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",125 "HTTP/1.1 413 Payload Too Large\r\nServer: Htt oForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",126 "HTTP/1.1 414 URI Too Long\r\nServer: Htt oForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n",120 "HTTP/1.1 200 OK\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 15\r\nConnection: keep-alive\r\n\r\nHello, World!\r\n", 121 "HTTP/1.1 400 Bad Request\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n", 122 "HTTP/1.1 404 Not Found\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n", 123 "HTTP/1.1 405 Method Not \r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n", 124 "HTTP/1.1 408 Request Timeout\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n", 125 "HTTP/1.1 413 Payload Too Large\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n", 126 "HTTP/1.1 414 URI Too Long\r\nServer: HttpForall\r\nContent-Type: text/plain\r\nContent-Length: 0 \r\n\r\n", 127 127 }; 128 128 static_assert( KNOWN_CODES == (sizeof(http_msgs) / sizeof(http_msgs[0])) ); -
benchmark/io/http/main.cfa
r94647b0 r7770cc8 150 150 if(errno == EADDRINUSE) { 151 151 if(waited == 0) { 152 if(!options.interactive) abort | "Port already in use in non-interactive mode. Aborting"; 152 153 sout | "Waiting for port"; 153 154 } else { … … 190 191 init_protocol(); 191 192 { 192 Worker workers[options.clopts.nworkers];193 Worker * workers = anew(options.clopts.nworkers); 193 194 for(i; options.clopts.nworkers) { 194 195 // if( options.file_cache.fixed_fds ) { … … 212 213 } 213 214 sout | nl; 215 if(!options.interactive) park(); 214 216 { 215 217 char buffer[128]; … … 249 251 250 252 sout | "Stopping connection threads..." | nonl; flush( sout ); 253 adelete(workers); 251 254 } 252 255 sout | "done"; -
benchmark/io/http/options.cfa
r94647b0 r7770cc8 21 21 false, // log 22 22 false, // stats 23 true, // interactive 24 0, // redirect 25 0, // redirect 23 26 24 27 { // file_cache … … 52 55 // bool sqkpoll = false; 53 56 // bool iokpoll = false; 54 unsigned nentries = 16;57 unsigned nentries = 0; 55 58 bool isolate = false; 56 59 … … 62 65 {'\0', "isolate", "Create one cluster per processor", isolate, parse_settrue}, 63 66 {'\0', "log", "Enable logs", options.log, parse_settrue}, 67 {'\0', "sout", "Redirect standard out to file", options.reopen_stdout}, 68 {'\0', "serr", "Redirect standard error to file", options.reopen_stderr}, 64 69 {'\0', "stats", "Enable statistics", options.stats, parse_settrue}, 70 {'\0', "shell", "Disable interactive mode", options.interactive, parse_setfalse}, 65 71 {'\0', "accept-backlog", "Maximum number of pending accepts", options.socket.backlog}, 66 72 {'\0', "request_len", "Maximum number of bytes in the http request, requests with more data will be answered with Http Code 414", options.socket.buflen}, … … 79 85 parse_args( argc, argv, opt, opt_cnt, "[OPTIONS]... [PATH]\ncforall http server", left ); 80 86 81 if( !is_pow2(nentries) ) {87 if( nentries != 0 && !is_pow2(nentries) ) { 82 88 unsigned v = nentries; 83 89 v--; … … 131 137 132 138 options.file_cache.path = path; 139 140 if( options.reopen_stdout && options.reopen_stderr && 0 == strcmp(options.reopen_stdout, options.reopen_stderr) ) { 141 serr | "Redirect sout and serr to the same file is not supported"; 142 exit(EXIT_FAILURE); 143 } 144 145 if( options.reopen_stdout ) { 146 sout | "redirecting sout to '" | options.reopen_stdout | "'"; 147 FILE * ret = freopen( options.reopen_stdout, "w", stdout); 148 if( ret == 0p ) { 149 serr | "Failed to redirect sout to '" | options.reopen_stdout | "'"; 150 exit(EXIT_FAILURE); 151 } 152 } 153 154 if( options.reopen_stderr ) { 155 sout | "redirecting serr to '" | options.reopen_stderr | "'"; 156 FILE * ret = freopen( options.reopen_stderr, "w", stderr); 157 if( ret == 0p ) { 158 serr | "Failed to redirect serr to '" | options.reopen_stderr | "'"; 159 exit(EXIT_FAILURE); 160 } 161 } 133 162 } -
benchmark/io/http/options.hfa
r94647b0 r7770cc8 10 10 bool log; 11 11 bool stats; 12 bool interactive; 13 const char * reopen_stdout; 14 const char * reopen_stderr; 12 15 13 16 struct { -
benchmark/io/http/protocol.cfa
r94647b0 r7770cc8 11 11 #include <fstream.hfa> 12 12 #include <iofwd.hfa> 13 #include <io/types.hfa> 14 #include <mutex_stmt.hfa> 13 15 14 16 #include <assert.h> … … 26 28 #define PLAINTEXT_MEMCPY 27 29 #define PLAINTEXT_NOCOPY 30 #define LINKED_IO 28 31 29 32 struct https_msg_str { … … 53 56 } 54 57 55 static inline int answer( int fd, const char * it, int len ) {58 static inline int answer( int fd, const char * it, int len ) { 56 59 while(len > 0) { 57 60 // Call write 58 61 int ret = cfa_send(fd, it, len, 0, CFA_IO_LAZY); 59 62 if( ret < 0 ) { 60 if( errno == ECONNRESET || errno == EPIPE ) return -ECONNRESET;63 if( errno == ECONNRESET || errno == EPIPE ) { close(fd); return -ECONNRESET; } 61 64 if( errno == EAGAIN || errno == EWOULDBLOCK) return -EAGAIN; 62 65 … … 77 80 } 78 81 79 int answer_header( int fd, size_t size ) { 80 char buffer[512]; 81 char * it = buffer; 82 static int fill_header(char * it, size_t size) { 82 83 memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len); 83 84 it += http_msgs[OK200]->len; 84 85 int len = http_msgs[OK200]->len; 85 86 len += snprintf(it, 512 - len, "%d \n\n", size); 87 return len; 88 } 89 90 static int answer_header( int fd, size_t size ) { 91 char buffer[512]; 92 int len = fill_header(buffer, size); 86 93 return answer( fd, buffer, len ); 87 94 } … … 135 142 } 136 143 137 138 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len) { 139 char * it = buffer; 140 size_t count = len - 1; 141 int rlen = 0; 142 READ: 143 for() { 144 int ret = cfa_recv(fd, (void*)it, count, 0, CFA_IO_LAZY); 145 // int ret = read(fd, (void*)it, count); 146 if(ret == 0 ) return [OK200, true, 0, 0]; 147 if(ret < 0 ) { 148 if( errno == EAGAIN || errno == EWOULDBLOCK) continue READ; 149 if( errno == ECONNRESET ) return [E408, true, 0, 0]; 150 if( errno == EPIPE ) return [E408, true, 0, 0]; 151 abort( "read error: (%d) %s\n", (int)errno, strerror(errno) ); 152 } 153 it[ret + 1] = '\0'; 154 rlen += ret; 155 156 if( strstr( it, "\r\n\r\n" ) ) break; 157 158 it += ret; 159 count -= ret; 160 161 if( count < 1 ) return [E414, false, 0, 0]; 162 } 163 164 if( options.log ) { 165 write(sout, buffer, rlen); 166 sout | nl; 167 } 168 169 it = buffer; 170 int ret = memcmp(it, "GET /", 5); 171 if( ret != 0 ) return [E400, false, 0, 0]; 172 it += 5; 173 174 char * end = strstr( it, " " ); 175 return [OK200, false, it, end - it]; 176 } 177 178 int sendfile( int pipe[2], int fd, int ans_fd, size_t count ) { 144 static int sendfile( int pipe[2], int fd, int ans_fd, size_t count ) { 179 145 unsigned sflags = SPLICE_F_MOVE; // | SPLICE_F_MORE; 180 146 off_t offset = 0; … … 207 173 } 208 174 175 static void zero_sqe(struct io_uring_sqe * sqe) { 176 sqe->flags = 0; 177 sqe->ioprio = 0; 178 sqe->fd = 0; 179 sqe->off = 0; 180 sqe->addr = 0; 181 sqe->len = 0; 182 sqe->fsync_flags = 0; 183 sqe->__pad2[0] = 0; 184 sqe->__pad2[1] = 0; 185 sqe->__pad2[2] = 0; 186 sqe->fd = 0; 187 sqe->off = 0; 188 sqe->addr = 0; 189 sqe->len = 0; 190 } 191 192 enum FSM_STATE { 193 Initial, 194 Retry, 195 Error, 196 Done, 197 }; 198 199 struct FSM_Result { 200 FSM_STATE state; 201 int error; 202 }; 203 204 static inline void ?{}(FSM_Result & this) { this.state = Initial; this.error = 0; } 205 static inline bool is_error(FSM_Result & this) { return Error == this.state; } 206 static inline bool is_done(FSM_Result & this) { return Done == this.state; } 207 208 static inline int error(FSM_Result & this, int error) { 209 this.error = error; 210 this.state = Error; 211 return error; 212 } 213 214 static inline int done(FSM_Result & this) { 215 this.state = Done; 216 return 0; 217 } 218 219 static inline int retry(FSM_Result & this) { 220 this.state = Retry; 221 return 0; 222 } 223 224 static inline int need(FSM_Result & this) { 225 switch(this.state) { 226 case Initial: 227 case Retry: 228 return 1; 229 case Error: 230 if(this.error == 0) mutex(serr) serr | "State marked error but code is 0"; 231 case Done: 232 return 0; 233 } 234 } 235 236 // Generator that handles sending the header 237 generator header_g { 238 io_future_t f; 239 const char * next; 240 int fd; size_t len; 241 FSM_Result res; 242 }; 243 244 static inline void ?{}(header_g & this, int fd, const char * it, size_t len ) { 245 this.next = it; 246 this.fd = fd; 247 this.len = len; 248 } 249 250 static inline void fill(header_g & this, struct io_uring_sqe * sqe) { 251 zero_sqe(sqe); 252 sqe->opcode = IORING_OP_SEND; 253 sqe->user_data = (uintptr_t)&this.f; 254 sqe->flags = IOSQE_IO_LINK; 255 sqe->fd = this.fd; 256 sqe->addr = (uintptr_t)this.next; 257 sqe->len = this.len; 258 } 259 260 static inline int error(header_g & this, int error) { 261 int ret = close(this.fd); 262 if( ret != 0 ) { 263 mutex(serr) serr | "Failed to close fd" | errno; 264 } 265 return error(this.res, error); 266 } 267 268 static inline int wait_and_process(header_g & this) { 269 wait(this.f); 270 271 // Did something crazy happen? 272 if(this.f.result > this.len) { 273 mutex(serr) serr | "HEADER sent too much!"; 274 return error(this, -ERANGE); 275 } 276 277 // Something failed? 278 if(this.f.result < 0) { 279 int error = -this.f.result; 280 if( error == ECONNRESET ) return error(this, -ECONNRESET); 281 if( error == EPIPE ) return error(this, -EPIPE); 282 if( error == ECANCELED ) { 283 mutex(serr) serr | "HEADER was cancelled, WTF!"; 284 return error(this, -ECONNRESET); 285 } 286 if( error == EAGAIN || error == EWOULDBLOCK) { 287 mutex(serr) serr | "HEADER got eagain, WTF!"; 288 return error(this, -ECONNRESET); 289 } 290 } 291 292 // Done? 293 if(this.f.result == this.len) { 294 return done(this.res); 295 } 296 297 // It must be a Short read 298 this.len -= this.f.result; 299 this.next += this.f.result; 300 reset(this.f); 301 return retry(this.res); 302 } 303 304 // Generator that handles splicing in a file 305 struct splice_in_t { 306 io_future_t f; 307 int fd; int pipe; size_t len; off_t off; 308 FSM_Result res; 309 }; 310 311 static inline void ?{}(splice_in_t & this, int fd, int pipe, size_t len) { 312 this.fd = fd; 313 this.pipe = pipe; 314 this.len = len; 315 this.off = 0; 316 } 317 318 static inline void fill(splice_in_t & this, struct io_uring_sqe * sqe) { 319 zero_sqe(sqe); 320 sqe->opcode = IORING_OP_SPLICE; 321 sqe->user_data = (uintptr_t)&this.f; 322 sqe->flags = 0; 323 sqe->splice_fd_in = this.fd; 324 sqe->splice_off_in = this.off; 325 sqe->fd = this.pipe; 326 sqe->off = (__u64)-1; 327 sqe->len = this.len; 328 sqe->splice_flags = SPLICE_F_MOVE; 329 } 330 331 static inline int wait_and_process(splice_in_t & this) { 332 wait(this.f); 333 334 // Something failed? 335 if(this.f.result < 0) { 336 int error = -this.f.result; 337 if( error == ECONNRESET ) return error(this.res, -ECONNRESET); 338 if( error == EPIPE ) return error(this.res, -EPIPE); 339 if( error == ECANCELED ) { 340 mutex(serr) serr | "SPLICE IN was cancelled, WTF!"; 341 return error(this.res, -ECONNRESET); 342 } 343 if( error == EAGAIN || error == EWOULDBLOCK) { 344 mutex(serr) serr | "SPLICE IN got eagain, WTF!"; 345 return error(this.res, -ECONNRESET); 346 } 347 } 348 349 // Did something crazy happen? 350 if(this.f.result > this.len) { 351 mutex(serr) serr | "SPLICE IN spliced too much!"; 352 return error(this.res, -ERANGE); 353 } 354 355 // Done? 356 if(this.f.result == this.len) { 357 return done(this.res); 358 } 359 360 // It must be a Short read 361 this.len -= this.f.result; 362 this.off += this.f.result; 363 reset(this.f); 364 return retry(this.res); 365 } 366 367 generator splice_out_g { 368 io_future_t f; 369 int pipe; int fd; size_t len; 370 FSM_Result res; 371 }; 372 373 static inline void ?{}(splice_out_g & this, int pipe, int fd, size_t len) { 374 this.pipe = pipe; 375 this.fd = fd; 376 this.len = len; 377 } 378 379 static inline void fill(splice_out_g & this, struct io_uring_sqe * sqe) { 380 zero_sqe(sqe); 381 sqe->opcode = IORING_OP_SPLICE; 382 sqe->user_data = (uintptr_t)&this.f; 383 sqe->flags = 0; 384 sqe->splice_fd_in = this.pipe; 385 sqe->splice_off_in = (__u64)-1; 386 sqe->fd = this.fd; 387 sqe->off = (__u64)-1; 388 sqe->len = this.len; 389 sqe->splice_flags = SPLICE_F_MOVE; 390 } 391 392 static inline int error(splice_out_g & this, int error) { 393 int ret = close(this.fd); 394 if( ret != 0 ) { 395 mutex(serr) serr | "Failed to close fd" | errno; 396 } 397 return error(this.res, error); 398 } 399 400 static inline void wait_and_process(splice_out_g & this) { 401 wait(this.f); 402 403 // Something failed? 404 if(this.f.result < 0) { 405 int error = -this.f.result; 406 if( error == ECONNRESET ) return error(this, -ECONNRESET); 407 if( error == EPIPE ) return error(this, -EPIPE); 408 if( error == ECANCELED ) { 409 this.f.result = 0; 410 goto SHORT_WRITE; 411 } 412 if( error == EAGAIN || error == EWOULDBLOCK) { 413 mutex(serr) serr | "SPLICE OUT got eagain, WTF!"; 414 return error(this, -ECONNRESET); 415 } 416 } 417 418 // Did something crazy happen? 419 if(this.f.result > this.len) { 420 mutex(serr) serr | "SPLICE OUT spliced too much!" | this.f.result | ">" | this.len; 421 return error(this.res, -ERANGE); 422 } 423 424 // Done? 425 if(this.f.result == this.len) { 426 return done(this.res); 427 } 428 429 SHORT_WRITE: 430 // It must be a Short Write 431 this.len -= this.f.result; 432 reset(this.f); 433 return retry(this.res); 434 } 435 436 int answer_sendfile( int pipe[2], int fd, int ans_fd, size_t fsize ) { 437 #if defined(LINKED_IO) 438 char buffer[512]; 439 int len = fill_header(buffer, fsize); 440 header_g header = { fd, buffer, len }; 441 splice_in_t splice_in = { ans_fd, pipe[1], fsize }; 442 splice_out_g splice_out = { pipe[0], fd, fsize }; 443 444 RETRY_LOOP: for() { 445 int have = need(header.res) + need(splice_in.res) + 1; 446 int idx = 0; 447 struct io_uring_sqe * sqes[3]; 448 __u32 idxs[3]; 449 struct $io_context * ctx = cfa_io_allocate(sqes, idxs, have); 450 451 if(need(splice_in.res)) { fill(splice_in, sqes[idx++]); } 452 if(need( header.res)) { fill(header , sqes[idx++]); } 453 fill(splice_out, sqes[idx]); 454 455 // Submit everything 456 asm volatile("": : :"memory"); 457 cfa_io_submit( ctx, idxs, have, false ); 458 459 // wait for the results 460 // Always wait for splice-in to complete as 461 // we may need to kill the connection if it fails 462 // If it already completed, this is a no-op 463 wait_and_process(splice_in); 464 465 if(is_error(splice_in.res)) { 466 mutex(serr) serr | "SPLICE IN failed with" | splice_in.res.error; 467 close(fd); 468 } 469 470 // Process the other 2 471 wait_and_process(header); 472 wait_and_process(splice_out); 473 474 if(is_done(splice_out.res)) { 475 break RETRY_LOOP; 476 } 477 478 // We need to wait for the completion if 479 // - both completed 480 // - the header failed 481 // - 482 483 if( is_error(header.res) 484 || is_error(splice_in.res) 485 || is_error(splice_out.res)) { 486 return -ECONNRESET; 487 } 488 } 489 490 return len + fsize; 491 #else 492 int ret = answer_header(fd, fsize); 493 if( ret < 0 ) { close(fd); return ret; } 494 return sendfile(pipe, fd, ans_fd, fsize); 495 #endif 496 } 497 498 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len) { 499 char * it = buffer; 500 size_t count = len - 1; 501 int rlen = 0; 502 READ: 503 for() { 504 int ret = cfa_recv(fd, (void*)it, count, 0, CFA_IO_LAZY); 505 // int ret = read(fd, (void*)it, count); 506 if(ret == 0 ) return [OK200, true, 0, 0]; 507 if(ret < 0 ) { 508 if( errno == EAGAIN || errno == EWOULDBLOCK) continue READ; 509 if( errno == ECONNRESET ) { close(fd); return [E408, true, 0, 0]; } 510 if( errno == EPIPE ) { close(fd); return [E408, true, 0, 0]; } 511 abort( "read error: (%d) %s\n", (int)errno, strerror(errno) ); 512 } 513 it[ret + 1] = '\0'; 514 rlen += ret; 515 516 if( strstr( it, "\r\n\r\n" ) ) break; 517 518 it += ret; 519 count -= ret; 520 521 if( count < 1 ) return [E414, false, 0, 0]; 522 } 523 524 if( options.log ) { 525 write(sout, buffer, rlen); 526 sout | nl; 527 } 528 529 it = buffer; 530 int ret = memcmp(it, "GET /", 5); 531 if( ret != 0 ) return [E400, false, 0, 0]; 532 it += 5; 533 534 char * end = strstr( it, " " ); 535 return [OK200, false, it, end - it]; 536 } 537 209 538 //============================================================================================= 210 539 … … 214 543 215 544 const char * original_http_msgs[] = { 216 "HTTP/1.1 200 OK\nServer: Htt oForall\nDate: %s \nContent-Type: text/plain\nContent-Length: ",217 "HTTP/1.1 200 OK\ nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 15\n\nHello, World!\n\n",218 "HTTP/1.1 400 Bad Request\nServer: Htt oForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",219 "HTTP/1.1 404 Not Found\nServer: Htt oForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",220 "HTTP/1.1 405 Method Not Allowed\nServer: Htt oForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",221 "HTTP/1.1 408 Request Timeout\nServer: Htt oForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",222 "HTTP/1.1 413 Payload Too Large\nServer: Htt oForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",223 "HTTP/1.1 414 URI Too Long\nServer: Htt oForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",545 "HTTP/1.1 200 OK\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: ", 546 "HTTP/1.1 200 OK\r\nServer: HttpForall\r\nConnection: keep-alive\r\nContent-Length: 15\r\nContent-Type: text/html\r\nDate: %s \r\n\r\nHello, World!\r\n", 547 "HTTP/1.1 400 Bad Request\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 548 "HTTP/1.1 404 Not Found\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 549 "HTTP/1.1 405 Method Not Allowed\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 550 "HTTP/1.1 408 Request Timeout\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 551 "HTTP/1.1 413 Payload Too Large\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 552 "HTTP/1.1 414 URI Too Long\nServer: HttpForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 224 553 }; 225 554 … … 251 580 Time now = timeHiRes(); 252 581 strftime( buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now ); 253 sout | "Updated date to '" | buff | "'";582 // if( options.log ) sout | "Updated date to '" | buff | "'"; 254 583 255 584 for(i; KNOWN_CODES) { … … 264 593 this.idx = (this.idx + 1) % 2; 265 594 266 sout | "Date thread sleeping";595 // if( options.log ) sout | "Date thread sleeping"; 267 596 268 597 sleep(1`s); -
benchmark/io/http/protocol.hfa
r94647b0 r7770cc8 16 16 17 17 int answer_error( int fd, HttpCode code ); 18 int answer_header( int fd, size_t size );19 18 int answer_plaintext( int fd ); 20 19 int answer_empty( int fd ); 20 int answer_sendfile( int pipe[2], int fd, int ans_fd, size_t count ); 21 21 22 22 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len); 23 24 int sendfile( int pipe[2], int fd, int ans_fd, size_t count ); -
benchmark/io/http/worker.cfa
r94647b0 r7770cc8 18 18 void ?{}( Worker & this ) { 19 19 size_t cli = rand() % options.clopts.cltr_cnt; 20 ((thread&)this){ "Server Worker Thread", *options.clopts.instance[cli], 512000 };20 ((thread&)this){ "Server Worker Thread", *options.clopts.instance[cli], 64000 }; 21 21 options.clopts.thrd_cnt[cli]++; 22 22 this.pipe[0] = -1; … … 122 122 } 123 123 124 // Send the header125 int ret = answer_header(fd, count);126 if( ret == -ECONNRESET ) break REQUEST;127 128 124 // Send the desired file 129 ret =sendfile( this.pipe, fd, ans_fd, count);125 int ret = answer_sendfile( this.pipe, fd, ans_fd, count); 130 126 if( ret == -ECONNRESET ) break REQUEST; 131 127 … … 134 130 135 131 if( options.log ) sout | "=== Connection closed ==="; 136 close(fd);137 132 continue CONNECTION; 138 133 } -
doc/theses/mubeen_zulfiqar_MMath/allocator.tex
r94647b0 r7770cc8 24 24 \end{itemize} 25 25 26 The new features added to uHeapLmmm (incl. @malloc _size@ routine)26 The new features added to uHeapLmmm (incl. @malloc\_size@ routine) 27 27 \CFA alloc interface with examples. 28 28 29 \begin{itemize} 29 30 \item … … 117 118 We added a few more features and routines to the allocator's C interface that can make the allocator more usable to the programmers. THese features will programmer more control on the dynamic memory allocation. 118 119 119 \subsubsection void * aalloc( size _t dim, size_t elemSize )120 \subsubsection void * aalloc( size\_t dim, size\_t elemSize ) 120 121 aalloc is an extension of malloc. It allows programmer to allocate a dynamic array of objects without calculating the total size of array explicitly. The only alternate of this routine in the other allocators is calloc but calloc also fills the dynamic memory with 0 which makes it slower for a programmer who only wants to dynamically allocate an array of objects without filling it with 0. 121 122 \paragraph{Usage} 122 123 aalloc takes two parameters. 124 123 125 \begin{itemize} 124 126 \item … … 129 131 It returns address of dynamic object allocatoed on heap that can contain dim number of objects of the size elemSize. On failure, it returns NULL pointer. 130 132 131 \subsubsection void * resize( void * oaddr, size _t size )133 \subsubsection void * resize( void * oaddr, size\_t size ) 132 134 resize is an extension of relloc. It allows programmer to reuse a cuurently allocated dynamic object with a new size requirement. Its alternate in the other allocators is realloc but relloc also copy the data in old object to the new object which makes it slower for the programmer who only wants to reuse an old dynamic object for a new size requirement but does not want to preserve the data in the old object to the new object. 133 135 \paragraph{Usage} 134 136 resize takes two parameters. 137 135 138 \begin{itemize} 136 139 \item … … 141 144 It returns an object that is of the size given but it does not preserve the data in the old object. On failure, it returns NULL pointer. 142 145 143 \subsubsection void * resize( void * oaddr, size _t nalign, size_t size )146 \subsubsection void * resize( void * oaddr, size\_t nalign, size\_t size ) 144 147 This resize is an extension of the above resize (FIX ME: cite above resize). In addition to resizing the size of of an old object, it can also realign the old object to a new alignment requirement. 145 148 \paragraph{Usage} 146 149 This resize takes three parameters. It takes an additional parameter of nalign as compared to the above resize (FIX ME: cite above resize). 150 147 151 \begin{itemize} 148 152 \item … … 155 159 It returns an object with the size and alignment given in the parameters. On failure, it returns a NULL pointer. 156 160 157 \subsubsection void * amemalign( size _t alignment, size_t dim, size_t elemSize )161 \subsubsection void * amemalign( size\_t alignment, size\_t dim, size\_t elemSize ) 158 162 amemalign is a hybrid of memalign and aalloc. It allows programmer to allocate an aligned dynamic array of objects without calculating the total size of the array explicitly. It frees the programmer from calculating the total size of the array. 159 163 \paragraph{Usage} 160 164 amemalign takes three parameters. 165 161 166 \begin{itemize} 162 167 \item … … 169 174 It returns a dynamic array of objects that has the capacity to contain dim number of objects of the size of elemSize. The returned dynamic array is aligned to the given alignment. On failure, it returns NULL pointer. 170 175 171 \subsubsection void * cmemalign( size _t alignment, size_t dim, size_t elemSize )176 \subsubsection void * cmemalign( size\_t alignment, size\_t dim, size\_t elemSize ) 172 177 cmemalign is a hybrid of amemalign and calloc. It allows programmer to allocate an aligned dynamic array of objects that is 0 filled. The current way to do this in other allocators is to allocate an aligned object with memalign and then fill it with 0 explicitly. This routine provides both features of aligning and 0 filling, implicitly. 173 178 \paragraph{Usage} 174 179 cmemalign takes three parameters. 180 175 181 \begin{itemize} 176 182 \item … … 183 189 It returns a dynamic array of objects that has the capacity to contain dim number of objects of the size of elemSize. The returned dynamic array is aligned to the given alignment and is 0 filled. On failure, it returns NULL pointer. 184 190 185 \subsubsection size_t malloc_alignment( void * addr ) 186 malloc_alignment returns the alignment of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required alignment. 187 \paragraph{Usage} 188 malloc_alignment takes one parameters. 191 \subsubsection size\_t malloc\_alignment( void * addr ) 192 malloc\_alignment returns the alignment of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required alignment. 193 \paragraph{Usage} 194 malloc\_alignment takes one parameters. 195 189 196 \begin{itemize} 190 197 \item 191 198 addr: the address of the currently allocated dynamic object. 192 199 \end{itemize} 193 malloc_alignment returns the alignment of the given dynamic object. On failure, it return the value of default alignment of the uHeapLmmm allocator. 194 195 \subsubsection bool malloc_zero_fill( void * addr ) 196 malloc_zero_fill returns whether a currently allocated dynamic object was initially zero filled at the time of allocation. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verifying the zero filled property of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was zero filled at the time of allocation. 197 \paragraph{Usage} 198 malloc_zero_fill takes one parameters. 200 malloc\_alignment returns the alignment of the given dynamic object. On failure, it return the value of default alignment of the uHeapLmmm allocator. 201 202 \subsubsection bool malloc\_zero\_fill( void * addr ) 203 malloc\_zero\_fill returns whether a currently allocated dynamic object was initially zero filled at the time of allocation. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verifying the zero filled property of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was zero filled at the time of allocation. 204 \paragraph{Usage} 205 malloc\_zero\_fill takes one parameters. 206 199 207 \begin{itemize} 200 208 \item 201 209 addr: the address of the currently allocated dynamic object. 202 210 \end{itemize} 203 malloc_zero_fill returns true if the dynamic object was initially zero filled and return false otherwise. On failure, it returns false. 204 205 \subsubsection size_t malloc_size( void * addr ) 206 malloc_size returns the allocation size of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required size. Its current alternate in the other allocators is malloc_usable_size. But, malloc_size is different from malloc_usable_size as malloc_usabe_size returns the total data capacity of dynamic object including the extra space at the end of the dynamic object. On the other hand, malloc_size returns the size that was given to the allocator at the allocation of the dynamic object. This size is updated when an object is realloced, resized, or passed through a similar allocator routine. 207 \paragraph{Usage} 208 malloc_size takes one parameters. 211 malloc\_zero\_fill returns true if the dynamic object was initially zero filled and return false otherwise. On failure, it returns false. 212 213 \subsubsection size\_t malloc\_size( void * addr ) 214 malloc\_size returns the allocation size of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required size. Its current alternate in the other allocators is malloc\_usable\_size. But, malloc\_size is different from malloc\_usable\_size as malloc\_usabe\_size returns the total data capacity of dynamic object including the extra space at the end of the dynamic object. On the other hand, malloc\_size returns the size that was given to the allocator at the allocation of the dynamic object. This size is updated when an object is realloced, resized, or passed through a similar allocator routine. 215 \paragraph{Usage} 216 malloc\_size takes one parameters. 217 209 218 \begin{itemize} 210 219 \item 211 220 addr: the address of the currently allocated dynamic object. 212 221 \end{itemize} 213 malloc _size returns the allocation size of the given dynamic object. On failure, it return zero.214 215 \subsubsection void * realloc( void * oaddr, size _t nalign, size_t size )222 malloc\_size returns the allocation size of the given dynamic object. On failure, it return zero. 223 224 \subsubsection void * realloc( void * oaddr, size\_t nalign, size\_t size ) 216 225 This realloc is an extension of the default realloc (FIX ME: cite default realloc). In addition to reallocating an old object and preserving the data in old object, it can also realign the old object to a new alignment requirement. 217 226 \paragraph{Usage} 218 227 This realloc takes three parameters. It takes an additional parameter of nalign as compared to the default realloc. 228 219 229 \begin{itemize} 220 230 \item … … 237 247 It returns a dynamic object of the size of type T. On failure, it return NULL pointer. 238 248 239 \subsubsection T * aalloc( size _t dim )249 \subsubsection T * aalloc( size\_t dim ) 240 250 This aalloc is a simplified polymorphic form of above aalloc (FIX ME: cite aalloc). It takes one parameter as compared to the above aalloc that takes two parameters. 241 251 \paragraph{Usage} 242 252 aalloc takes one parameters. 253 243 254 \begin{itemize} 244 255 \item … … 247 258 It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. On failure, it return NULL pointer. 248 259 249 \subsubsection T * calloc( size _t dim )260 \subsubsection T * calloc( size\_t dim ) 250 261 This calloc is a simplified polymorphic form of defualt calloc (FIX ME: cite calloc). It takes one parameter as compared to the default calloc that takes two parameters. 251 262 \paragraph{Usage} 252 263 This calloc takes one parameter. 264 253 265 \begin{itemize} 254 266 \item … … 257 269 It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. On failure, it return NULL pointer. 258 270 259 \subsubsection T * resize( T * ptr, size _t size )271 \subsubsection T * resize( T * ptr, size\_t size ) 260 272 This resize is a simplified polymorphic form of above resize (FIX ME: cite resize with alignment). It takes two parameters as compared to the above resize that takes three parameters. It frees the programmer from explicitly mentioning the alignment of the allocation as CFA provides gives allocator the liberty to get the alignment of the returned type. 261 273 \paragraph{Usage} 262 274 This resize takes two parameters. 275 263 276 \begin{itemize} 264 277 \item … … 269 282 It returns a dynamic object of the size given in paramters. The returned object is aligned to the alignemtn of type T. On failure, it return NULL pointer. 270 283 271 \subsubsection T * realloc( T * ptr, size _t size )284 \subsubsection T * realloc( T * ptr, size\_t size ) 272 285 This realloc is a simplified polymorphic form of defualt realloc (FIX ME: cite realloc with align). It takes two parameters as compared to the above realloc that takes three parameters. It frees the programmer from explicitly mentioning the alignment of the allocation as CFA provides gives allocator the liberty to get the alignment of the returned type. 273 286 \paragraph{Usage} 274 287 This realloc takes two parameters. 288 275 289 \begin{itemize} 276 290 \item … … 281 295 It returns a dynamic object of the size given in paramters that preserves the data in the given object. The returned object is aligned to the alignemtn of type T. On failure, it return NULL pointer. 282 296 283 \subsubsection T * memalign( size _t align )297 \subsubsection T * memalign( size\_t align ) 284 298 This memalign is a simplified polymorphic form of defualt memalign (FIX ME: cite memalign). It takes one parameters as compared to the default memalign that takes two parameters. 285 299 \paragraph{Usage} 286 300 memalign takes one parameters. 301 287 302 \begin{itemize} 288 303 \item … … 291 306 It returns a dynamic object of the size of type T that is aligned to given parameter align. On failure, it return NULL pointer. 292 307 293 \subsubsection T * amemalign( size _t align, size_t dim )308 \subsubsection T * amemalign( size\_t align, size\_t dim ) 294 309 This amemalign is a simplified polymorphic form of above amemalign (FIX ME: cite amemalign). It takes two parameter as compared to the above amemalign that takes three parameters. 295 310 \paragraph{Usage} 296 311 amemalign takes two parameters. 312 297 313 \begin{itemize} 298 314 \item … … 303 319 It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. The returned object is aligned to the given parameter align. On failure, it return NULL pointer. 304 320 305 \subsubsection T * cmemalign( size _t align, size_t dim )321 \subsubsection T * cmemalign( size\_t align, size\_t dim ) 306 322 This cmemalign is a simplified polymorphic form of above cmemalign (FIX ME: cite cmemalign). It takes two parameter as compared to the above cmemalign that takes three parameters. 307 323 \paragraph{Usage} 308 324 cmemalign takes two parameters. 325 309 326 \begin{itemize} 310 327 \item … … 315 332 It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. The returned object is aligned to the given parameter align and is zero filled. On failure, it return NULL pointer. 316 333 317 \subsubsection T * aligned_alloc( size_t align ) 318 This aligned_alloc is a simplified polymorphic form of defualt aligned_alloc (FIX ME: cite aligned_alloc). It takes one parameter as compared to the default aligned_alloc that takes two parameters. 319 \paragraph{Usage} 320 This aligned_alloc takes one parameter. 334 \subsubsection T * aligned\_alloc( size\_t align ) 335 This aligned\_alloc is a simplified polymorphic form of defualt aligned\_alloc (FIX ME: cite aligned\_alloc). It takes one parameter as compared to the default aligned\_alloc that takes two parameters. 336 \paragraph{Usage} 337 This aligned\_alloc takes one parameter. 338 321 339 \begin{itemize} 322 340 \item … … 325 343 It returns a dynamic object of the size of type T that is aligned to the given parameter. On failure, it return NULL pointer. 326 344 327 \subsubsection int posix_memalign( T ** ptr, size_t align ) 328 This posix_memalign is a simplified polymorphic form of defualt posix_memalign (FIX ME: cite posix_memalign). It takes two parameters as compared to the default posix_memalign that takes three parameters. 329 \paragraph{Usage} 330 This posix_memalign takes two parameter. 345 \subsubsection int posix\_memalign( T ** ptr, size\_t align ) 346 This posix\_memalign is a simplified polymorphic form of defualt posix\_memalign (FIX ME: cite posix\_memalign). It takes two parameters as compared to the default posix\_memalign that takes three parameters. 347 \paragraph{Usage} 348 This posix\_memalign takes two parameter. 349 331 350 \begin{itemize} 332 351 \item … … 335 354 align: required alignment of the dynamic object. 336 355 \end{itemize} 356 337 357 It stores address of the dynamic object of the size of type T in given parameter ptr. This object is aligned to the given parameter. On failure, it return NULL pointer. 338 358 … … 349 369 It returns a dynamic object of the size that is calcutaed by rouding the size of type T. The returned object is also aligned to the page size. On failure, it return NULL pointer. 350 370 351 \subsection {Alloc Interface}371 \subsection Alloc Interface 352 372 In addition to improve allocator interface both for CFA and our standalone allocator uHeapLmmm in C. We also added a new alloc interface in CFA that increases usability of dynamic memory allocation. 353 373 This interface helps programmers in three major ways. 374 354 375 \begin{itemize} 355 376 \item … … 371 392 This is the only parameter in the alloc routine that has a fixed-position and it is also the only parameter that does not use a backtick function. It has to be passed at the first position to alloc call in-case of an array allocation of objects of type T. 372 393 It represents the required number of members in the array allocation as in CFA's aalloc (FIX ME: cite aalloc). 373 This parameter should be of type size _t.394 This parameter should be of type size\_t. 374 395 375 396 Example: int a = alloc( 5 ) … … 377 398 378 399 \paragraph{Align} 379 This parameter is position-free and uses a backtick routine align (`align). The parameter passed with `align should be of type size _t. If the alignment parameter is not a power of two or is less than the default alignment of the allocator (that can be found out using routine libAlign in CFA) then the passed alignment parameter will be rejected and the default alignment will be used.400 This parameter is position-free and uses a backtick routine align (`align). The parameter passed with `align should be of type size\_t. If the alignment parameter is not a power of two or is less than the default alignment of the allocator (that can be found out using routine libAlign in CFA) then the passed alignment parameter will be rejected and the default alignment will be used. 380 401 381 402 Example: int b = alloc( 5 , 64`align ) … … 385 406 This parameter is position-free and uses a backtick routine fill (`fill). In case of realloc, only the extra space after copying the data in the old object will be filled with given parameter. 386 407 Three types of parameters can be passed using `fill. 408 387 409 \begin{itemize} 388 410 \item -
doc/theses/mubeen_zulfiqar_MMath/background.tex
r94647b0 r7770cc8 23 23 ==================== 24 24 25 \cite{Wasik08} 25 \section{Background} 26 27 % FIXME: cite wasik 28 \cite{wasik.thesis} 29 30 \subsection{Memory Allocation} 31 With dynamic allocation being an important feature of C, there are many standalone memory allocators that have been designed for different purposes. For this thesis, we chose 7 of the most popular and widely used memory allocators. 32 33 \paragraph{dlmalloc} 34 dlmalloc (FIX ME: cite allocator) is a thread-safe allocator that is single threaded and single heap. dlmalloc maintains free-lists of different sizes to store freed dynamic memory. (FIX ME: cite wasik) 35 36 \paragraph{hoard} 37 Hoard (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and using a heap layer framework. It has per-thred heaps that have thread-local free-lists, and a gloabl shared heap. (FIX ME: cite wasik) 38 39 \paragraph{jemalloc} 40 jemalloc (FIX ME: cite allocator) is a thread-safe allocator that uses multiple arenas. Each thread is assigned an arena. Each arena has chunks that contain contagious memory regions of same size. An arena has multiple chunks that contain regions of multiple sizes. 41 42 \paragraph{ptmalloc} 43 ptmalloc (FIX ME: cite allocator) is a modification of dlmalloc. It is a thread-safe multi-threaded memory allocator that uses multiple heaps. ptmalloc heap has similar design to dlmalloc's heap. 44 45 \paragraph{rpmalloc} 46 rpmalloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses per-thread heap. Each heap has multiple size-classes and each size-calss contains memory regions of the relevant size. 47 48 \paragraph{tbb malloc} 49 tbb malloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses private heap for each thread. Each private-heap has multiple bins of different sizes. Each bin contains free regions of the same size. 50 51 \paragraph{tc malloc} 52 tcmalloc (FIX ME: cite allocator) is a thread-safe allocator. It uses per-thread cache to store free objects that prevents contention on shared resources in multi-threaded application. A central free-list is used to refill per-thread cache when it gets empty. 53 54 \subsection{Benchmarks} 55 There are multiple benchmarks that are built individually and evaluate different aspects of a memory allocator. But, there is not standard set of benchamrks that can be used to evaluate multiple aspects of memory allocators. 56 57 \paragraph{threadtest} 58 (FIX ME: cite benchmark and hoard) Each thread repeatedly allocates and then deallocates 100,000 objects. Runtime of the benchmark evaluates its efficiency. 59 60 \paragraph{shbench} 61 (FIX ME: cite benchmark and hoard) Each thread allocates and randomly frees a number of random-sized objects. It is a stress test that also uses runtime to determine efficiency of the allocator. 62 63 \paragraph{larson} 64 (FIX ME: cite benchmark and hoard) Larson simulates a server environment. Multiple threads are created where each thread allocator and free a number of objects within a size range. Some objects are passed from threads to the child threads to free. It caluculates memory operations per second as an indicator of memory allocator's performance. -
doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex
r94647b0 r7770cc8 149 149 *** FIX ME: Insert a figure of above benchmark with description 150 150 151 \paragr pah{Relevant Knobs}151 \paragraph{Relevant Knobs} 152 152 *** FIX ME: Insert Relevant Knobs 153 153 -
doc/theses/mubeen_zulfiqar_MMath/intro.tex
r94647b0 r7770cc8 47 47 \begin{itemize} 48 48 \item 49 aligned _alloc49 aligned\_alloc 50 50 \item 51 malloc _usable_size51 malloc\_usable\_size 52 52 \item 53 53 memalign 54 54 \item 55 posix _memalign55 posix\_memalign 56 56 \item 57 57 pvalloc … … 61 61 62 62 With the rise of concurrent applications, memory allocators should be able to fulfill dynamic memory requests from multiple threads in parallel without causing contention on shared resources. There needs to be a set of a standard benchmarks that can be used to evaluate an allocator's performance in different scenerios. 63 64 \section{Background}65 66 \subsection{Memory Allocation}67 With dynamic allocation being an important feature of C, there are many standalone memory allocators that have been designed for different purposes. For this thesis, we chose 7 of the most popular and widely used memory allocators.68 69 \paragraph{dlmalloc}70 dlmalloc (FIX ME: cite allocator) is a thread-safe allocator that is single threaded and single heap. dlmalloc maintains free-lists of different sizes to store freed dynamic memory. (FIX ME: cite wasik)71 72 \paragraph{hoard}73 Hoard (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and using a heap layer framework. It has per-thred heaps that have thread-local free-lists, and a gloabl shared heap. (FIX ME: cite wasik)74 75 \paragraph{jemalloc}76 jemalloc (FIX ME: cite allocator) is a thread-safe allocator that uses multiple arenas. Each thread is assigned an arena. Each arena has chunks that contain contagious memory regions of same size. An arena has multiple chunks that contain regions of multiple sizes.77 78 \paragraph{ptmalloc}79 ptmalloc (FIX ME: cite allocator) is a modification of dlmalloc. It is a thread-safe multi-threaded memory allocator that uses multiple heaps. ptmalloc heap has similar design to dlmalloc's heap.80 81 \paragraph{rpmalloc}82 rpmalloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses per-thread heap. Each heap has multiple size-classes and each size-calss contains memory regions of the relevant size.83 84 \paragraph{tbb malloc}85 tbb malloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses private heap for each thread. Each private-heap has multiple bins of different sizes. Each bin contains free regions of the same size.86 87 \paragraph{tc malloc}88 tcmalloc (FIX ME: cite allocator) is a thread-safe allocator. It uses per-thread cache to store free objects that prevents contention on shared resources in multi-threaded application. A central free-list is used to refill per-thread cache when it gets empty.89 90 \subsection{Benchmarks}91 There are multiple benchmarks that are built individually and evaluate different aspects of a memory allocator. But, there is not standard set of benchamrks that can be used to evaluate multiple aspects of memory allocators.92 93 \paragraph{threadtest}94 (FIX ME: cite benchmark and hoard) Each thread repeatedly allocates and then deallocates 100,000 objects. Runtime of the benchmark evaluates its efficiency.95 96 \paragraph{shbench}97 (FIX ME: cite benchmark and hoard) Each thread allocates and randomly frees a number of random-sized objects. It is a stress test that also uses runtime to determine efficiency of the allocator.98 99 \paragraph{larson}100 (FIX ME: cite benchmark and hoard) Larson simulates a server environment. Multiple threads are created where each thread allocator and free a number of objects within a size range. Some objects are passed from threads to the child threads to free. It caluculates memory operations per second as an indicator of memory allocator's performance.101 63 102 64 \section{Research Objectives} -
doc/theses/mubeen_zulfiqar_MMath/performance.tex
r94647b0 r7770cc8 44 44 tc & & \\ 45 45 \end{tabularx} 46 (FIX ME: complete table) 46 47 %(FIX ME: complete table) 47 48 48 49 \section{Experiment Environment} -
doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.bib
r94647b0 r7770cc8 27 27 address = "Reading, Massachusetts" 28 28 } 29 30 @article{wasik.thesis, 31 author = "Ayelet Wasik", 32 title = "Features of A Multi-Threaded Memory Alloator", 33 publisher = "University of Waterloo", 34 year = "2008" 35 } -
doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.tex
r94647b0 r7770cc8 84 84 \usepackage{graphicx} 85 85 \usepackage{comment} % Removes large sections of the document. 86 \usepackage{tabularx} 86 87 87 88 % Hyperlinks make it very easy to navigate an electronic document. … … 191 192 % Tip: Putting each sentence on a new line is a way to simplify later editing. 192 193 %---------------------------------------------------------------------- 194 \begin{sloppypar} 195 193 196 \input{intro} 194 197 \input{background} … … 197 200 \input{performance} 198 201 \input{conclusion} 202 203 \end{sloppypar} 199 204 200 205 %---------------------------------------------------------------------- -
doc/theses/thierry_delisle_PhD/.gitignore
r94647b0 r7770cc8 13 13 comp_II/presentation.pdf 14 14 15 seminars/build/ 16 seminars/img/*.fig.bak 17 seminars/*.pdf 18 15 19 thesis/build/ 16 20 thesis/fig/*.fig.bak -
doc/theses/thierry_delisle_PhD/thesis/Makefile
r94647b0 r7770cc8 20 20 practice \ 21 21 io \ 22 eval_micro \ 23 eval_macro \ 22 24 }} 23 25 … … 35 37 pivot_ring \ 36 38 system \ 39 cycle \ 37 40 } 38 41 -
doc/theses/thierry_delisle_PhD/thesis/thesis.tex
r94647b0 r7770cc8 1 1 %====================================================================== 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, 5 5 % University of Waterloo, 200 University Ave. W., Waterloo, Ontario, Canada 6 6 % FOR ASSISTANCE, please send mail to request@uwaterloo.ca … … 15 15 % Some important notes on using this template and making it your own... 16 16 17 % The University of Waterloo has required electronic thesis submission since October 2006. 17 % The University of Waterloo has required electronic thesis submission since October 2006. 18 18 % See the uWaterloo thesis regulations at 19 19 % https://uwaterloo.ca/graduate-studies/thesis. 20 20 % This thesis template is geared towards generating a PDF version optimized for viewing on an electronic display, including hyperlinks within the PDF. 21 21 22 % DON'T FORGET TO ADD YOUR OWN NAME AND TITLE in the "hyperref" package configuration below. 22 % DON'T FORGET TO ADD YOUR OWN NAME AND TITLE in the "hyperref" package configuration below. 23 23 % THIS INFORMATION GETS EMBEDDED IN THE PDF FINAL PDF DOCUMENT. 24 24 % You can view the information if you view properties of the PDF document. 25 25 26 % Many faculties/departments also require one or more printed copies. 27 % This template attempts to satisfy both types of output. 26 % Many faculties/departments also require one or more printed copies. 27 % This template attempts to satisfy both types of output. 28 28 % See additional notes below. 29 29 % It is based on the standard "book" document class which provides all necessary sectioning structures and allows multi-part theses. … … 32 32 33 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 34 35 35 % E.g. to process a thesis called "mythesis.tex" based on this template, run: 36 36 37 37 % pdflatex mythesis -- first pass of the pdflatex processor 38 38 % bibtex mythesis -- generates bibliography from .bib data file(s) 39 % makeindex -- should be run only if an index is used 39 % makeindex -- should be run only if an index is used 40 40 % pdflatex mythesis -- fixes numbering in cross-references, bibliographic references, glossaries, index, etc. 41 41 % pdflatex mythesis -- it takes a couple of passes to completely process all cross-references 42 42 43 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. 44 % Then click the PDFLaTeX button two more times. 45 45 % If you have an index as well,you'll need to run MakeIndex from the Tools menu as well, before running pdflatex 46 46 % the last two times. … … 51 51 % Tip: Photographs should be cropped and compressed so as not to be too large. 52 52 53 % To create a PDF output that is optimized for double-sided printing: 53 % To create a PDF output that is optimized for double-sided printing: 54 54 % 1) comment-out the \documentclass statement in the preamble below, and un-comment the second \documentclass line. 55 55 % 2) change the value assigned below to the boolean variable "PrintVersion" from " false" to "true". … … 67 67 % If you have to, it's easier to make changes to nomenclature once here than in a million places throughout your thesis! 68 68 \newcommand{\package}[1]{\textbf{#1}} % package names in bold text 69 \newcommand{\cmmd}[1]{\textbackslash\texttt{#1}} % command name in tt font 69 \newcommand{\cmmd}[1]{\textbackslash\texttt{#1}} % command name in tt font 70 70 \newcommand{\href}[1]{#1} % does nothing, but defines the command so the print-optimized version will ignore \href tags (redefined by hyperref pkg). 71 71 %\newcommand{\texorpdfstring}[2]{#1} % does nothing, but defines the command … … 235 235 \part{Evaluation} 236 236 \label{Evaluation} 237 \chapter{Theoretical and Existance Proofs}238 \ chapter{Micro-Benchmarks}239 \ chapter{Larger-Scale applications}237 % \chapter{Theoretical and Existance Proofs} 238 \input{text/eval_micro.tex} 239 \input{text/eval_macro.tex} 240 240 \part{Conclusion \& Annexes} 241 241 -
doc/user/user.tex
r94647b0 r7770cc8 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Mon May 31 09:03:34202114 %% Update Count : 50 7113 %% Last Modified On : Sun Oct 10 12:45:00 2021 14 %% Update Count : 5095 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 4444 4444 \CFA provides a fine-grained solution where a \Index{recursive lock} is acquired and released indirectly via a manipulator ©acquire© or instantiating an \Index{RAII} type specific for the kind of stream: ©osacquire©\index{ostream@©ostream©!osacquire@©osacquire©} for output streams and ©isacquire©\index{isacquire@©isacquire©}\index{istream@©istream©!isacquire@©isacquire©} for input streams. 4445 4445 4446 The common usage is manipulator ©acquire©\index{ostream@©ostream©!acquire@©acquire©} to lock a stream during a single cascaded I/O expression, with the manipulator appearing as the first item in a cascade list, \eg:4447 \begin{cfa} 4448 $\emph{thread\(_1\)}$ : sout | ®acquire® | "abc " | "def "; // manipulator4449 $\emph{thread\(_2\)}$ : sout | ®acquire®| "uvw " | "xyz ";4446 The common usage is the short form of the mutex statement\index{ostream@©ostream©!mutex@©mutex©} to lock a stream during a single cascaded I/O expression, \eg: 4447 \begin{cfa} 4448 $\emph{thread\(_1\)}$ : ®mutex()® sout | "abc " | "def "; 4449 $\emph{thread\(_2\)}$ : ®mutex()® sout | "uvw " | "xyz "; 4450 4450 \end{cfa} 4451 4451 Now, the order of the thread execution is still non-deterministic, but the output is constrained to two possible lines in either order. … … 4466 4466 In summary, the stream lock is acquired by the ©acquire© manipulator and implicitly released at the end of the cascaded I/O expression ensuring all operations in the expression occur atomically. 4467 4467 4468 To lock a stream across multiple I/O operations, an object of type ©osacquire© or ©isacquire© is declared to implicitly acquire/release the stream lock providing mutual exclusion for the object's duration, \eg: 4469 \begin{cfa} 4470 { // acquire sout for block duration 4471 ®osacquire® acq = { sout }; $\C{// named stream locker}$ 4468 To lock a stream across multiple I/O operations, he long form of the mutex statement is used, \eg: 4469 \begin{cfa} 4470 ®mutex( sout )® { 4472 4471 sout | 1; 4473 sout | ®acquire® | 2 | 3; $\C{// unnecessary, but ok to acquire and release again}$4472 ®mutex() sout® | 2 | 3; $\C{// unnecessary, but ok because of recursive lock}$ 4474 4473 sout | 4; 4475 } // implicitly release the lock when "acq" is deallocated4476 \end{cfa} 4477 Note, the unnecessary © acquire© manipulatorworks because the recursive stream-lock can be acquired/released multiple times by the owner thread.4474 } // implicitly release sout lock 4475 \end{cfa} 4476 Note, the unnecessary ©mutex© in the middle of the mutex statement, works because the recursive stream-lock can be acquired/released multiple times by the owner thread. 4478 4477 Hence, calls to functions that also acquire a stream lock for their output do not result in \Index{deadlock}. 4479 4478 4480 4479 The previous values written by threads 1 and 2 can be read in concurrently: 4481 4480 \begin{cfa} 4482 { // acquire sin lock for block duration 4483 ®isacquire acq = { sin };® $\C{// named stream locker}$ 4481 ®mutex( sin )® { 4484 4482 int x, y, z, w; 4485 4483 sin | x; 4486 sin | ®acquire® | y | z; $\C{// unnecessary, but ok to acquire and release again}$4484 ®mutex() sin® | y | z; $\C{// unnecessary, but ok because of recursive lock}$ 4487 4485 sin | w; 4488 } // implicitly release the lock when "acq" is deallocated4486 } // implicitly release sin lock 4489 4487 \end{cfa} 4490 4488 Again, the order of the reading threads is non-deterministic. … … 4493 4491 \Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg: 4494 4492 \begin{cfa} 4495 sout | ®acquire® | "data:" | rtn( mon ); $\C{// mutex call on monitor}$4493 ®mutex() sout® | "data:" | rtn( mon ); $\C{// mutex call on monitor}$ 4496 4494 \end{cfa} 4497 4495 If the thread executing the I/O expression blocks in the monitor with the ©sout© lock, other threads writing to ©sout© also block until the thread holding the lock is unblocked and releases it. … … 4500 4498 \begin{cfa} 4501 4499 int ®data® = rtn( mon ); 4502 sout | acquire| "data:" | ®data®;4500 mutex() sout | "data:" | ®data®; 4503 4501 \end{cfa} 4504 4502 … … 4506 4504 \section{String Stream} 4507 4505 4508 All the stream formatting capabilities are available to format text to/from a C string rather than to a stream file. 4509 \VRef[Figure]{f:StringStreamProcessing} shows writing (output) and reading (input) from a C string. 4506 The stream types ©ostrstream© and ©istrstream© provide all the stream formatting capabilities to/from a C string rather than a stream file. 4507 \VRef[Figure]{f:StringStreamProcessing} shows writing (output) to and reading (input) from a C string. 4508 The only string stream operations different from a file stream are: 4509 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt] 4510 \item 4511 constructors to create a stream that writes to a write buffer (©ostrstream©) of ©size©, or reads from a read buffer (©istrstream©) containing a C string terminated with ©'\0'©. 4512 \begin{cfa} 4513 void ?{}( ostrstream &, char buf[], size_t size ); 4514 void ?{}( istrstream & is, char buf[] ); 4515 \end{cfa} 4516 \item 4517 \Indexc{write} (©ostrstream© only) writes all the buffered characters to the specified stream (©stdout© default). 4518 \begin{cfa} 4519 ostrstream & write( ostrstream & os, FILE * stream = stdout ); 4520 \end{cfa} 4521 There is no ©read© for ©istrstream©. 4522 \end{itemize} 4523 4510 4524 \begin{figure} 4511 4525 \begin{cfa} … … 4520 4534 double x = 12345678.9, y = 98765.4321e-11; 4521 4535 4522 osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) ; $\C{// same lines of output}$4523 write( osstr ); 4524 printf( "%s", buf ); 4525 sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) ;4526 4527 char buf2[] = "12 14 15 3.5 7e4 "; $\C{// input buffer}$4536 osstr | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc"; 4537 write( osstr ); $\C{// write string to stdout}$ 4538 printf( "%s", buf ); $\C{// same lines of output}$ 4539 sout | i | hex(j) | wd(10, k) | sci(x) | unit(eng(y)) | "abc"; 4540 4541 char buf2[] = "12 14 15 3.5 7e4 abc"; $\C{// input buffer}$ 4528 4542 ®istrstream isstr = { buf2 };® 4529 isstr | i | j | k | x | y; 4530 sout | i | j | k | x | y; 4531 } 4543 char s[10]; 4544 isstr | i | j | k | x | y | s; 4545 sout | i | j | k | x | y | s; 4546 } 4547 4548 3 0x5 7 1.234568e+07 987.654n abc 4549 3 0x5 7 1.234568e+07 987.654n abc 4550 3 0x5 7 1.234568e+07 987.654n abc 4551 12 14 15 3.5 70000. abc 4532 4552 \end{cfa} 4533 4553 \caption{String Stream Processing} 4534 4554 \label{f:StringStreamProcessing} 4535 4555 \end{figure} 4536 4537 \VRef[Figure]{f:StringStreamFunctions} shows the string stream operations.4538 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]4539 \item4540 \Indexc{write} (©ostrstream© only) writes all the buffered characters to the specified stream (©stdout© default).4541 \end{itemize}4542 The constructor functions:4543 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]4544 \item4545 create a bound stream to a write buffer (©ostrstream©) of ©size© or a read buffer (©istrstream©) containing a C string terminated with ©'\0'©.4546 \end{itemize}4547 4548 \begin{figure}4549 \begin{cfa}4550 // *********************************** ostrstream ***********************************4551 4552 ostrstream & write( ostrstream & os, FILE * stream = stdout );4553 4554 void ?{}( ostrstream &, char buf[], size_t size );4555 4556 // *********************************** istrstream ***********************************4557 4558 void ?{}( istrstream & is, char buf[] );4559 \end{cfa}4560 \caption{String Stream Functions}4561 \label{f:StringStreamFunctions}4562 \end{figure}4563 4564 4556 4565 4557 \begin{comment} -
libcfa/prelude/bootloader.cf
r94647b0 r7770cc8 3 3 char ** cfa_args_argv; 4 4 char ** cfa_args_envp; 5 int cfa_main_returned = 0;5 __attribute__((weak)) extern int cfa_main_returned; 6 6 7 7 int main(int argc, char* argv[], char* envp[]) { … … 10 10 cfa_args_envp = envp; 11 11 int ret = invoke_main(argc, argv, envp); 12 cfa_main_returned = 1;12 if(&cfa_main_returned) cfa_main_returned = 1; 13 13 return ret; 14 14 } -
libcfa/src/concurrency/io.cfa
r94647b0 r7770cc8 133 133 } 134 134 135 void __cfa_io_flush( processor * proc) {135 bool __cfa_io_flush( processor * proc, bool wait ) { 136 136 /* paranoid */ verify( ! __preemption_enabled() ); 137 137 /* paranoid */ verify( proc ); … … 141 141 $io_context & ctx = *proc->io.ctx; 142 142 143 // for(i; 2) {144 // unsigned idx = proc->rdq.id + i;145 // cltr->ready_queue.lanes.tscs[idx].tv = -1ull;146 // }147 148 143 __ioarbiter_flush( ctx ); 149 144 150 145 __STATS__( true, io.calls.flush++; ) 151 int ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, 0, 0, (sigset_t *)0p, _NSIG / 8);146 int ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, wait ? 1 : 0, 0, (sigset_t *)0p, _NSIG / 8); 152 147 if( ret < 0 ) { 153 148 switch((int)errno) { … … 157 152 // Update statistics 158 153 __STATS__( false, io.calls.errors.busy ++; ) 159 // for(i; 2) { 160 // unsigned idx = proc->rdq.id + i; 161 // cltr->ready_queue.lanes.tscs[idx].tv = rdtscl(); 162 // } 163 return; 154 return false; 164 155 default: 165 156 abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) ); … … 182 173 183 174 ctx.proc->io.pending = false; 184 185 175 ready_schedule_lock(); 186 __cfa_io_drain( proc );176 bool ret = __cfa_io_drain( proc ); 187 177 ready_schedule_unlock(); 188 // for(i; 2) { 189 // unsigned idx = proc->rdq.id + i; 190 // cltr->ready_queue.lanes.tscs[idx].tv = rdtscl(); 191 // } 178 return ret; 192 179 } 193 180 … … 293 280 } 294 281 295 296 282 //============================================================================================= 297 283 // submission … … 311 297 // Make the sqes visible to the submitter 312 298 __atomic_store_n(sq.kring.tail, tail + have, __ATOMIC_RELEASE); 313 sq.to_submit ++;299 sq.to_submit += have; 314 300 315 301 ctx->proc->io.pending = true; 316 302 ctx->proc->io.dirty = true; 317 303 if(sq.to_submit > 30 || !lazy) { 318 __cfa_io_flush( ctx->proc );304 __cfa_io_flush( ctx->proc, false ); 319 305 } 320 306 } … … 515 501 } 516 502 } 503 504 #if defined(IO_URING_IDLE) 505 bool __kernel_read(processor * proc, io_future_t & future, char buf[], int fd) { 506 $io_context * ctx = proc->io.ctx; 507 /* paranoid */ verify( ! __preemption_enabled() ); 508 /* paranoid */ verify( proc == __cfaabi_tls.this_processor ); 509 /* paranoid */ verify( ctx ); 510 511 __u32 idx; 512 struct io_uring_sqe * sqe; 513 514 // We can proceed to the fast path 515 if( !__alloc(ctx, &idx, 1) ) return false; 516 517 // Allocation was successful 518 __fill( &sqe, 1, &idx, ctx ); 519 520 sqe->opcode = IORING_OP_READ; 521 sqe->user_data = (uintptr_t)&future; 522 sqe->flags = 0; 523 sqe->ioprio = 0; 524 sqe->fd = 0; 525 sqe->off = 0; 526 sqe->fsync_flags = 0; 527 sqe->__pad2[0] = 0; 528 sqe->__pad2[1] = 0; 529 sqe->__pad2[2] = 0; 530 sqe->addr = (uintptr_t)buf; 531 sqe->len = sizeof(uint64_t); 532 533 asm volatile("": : :"memory"); 534 535 /* paranoid */ verify( sqe->user_data == (uintptr_t)&future ); 536 __submit( ctx, &idx, 1, true ); 537 538 /* paranoid */ verify( proc == __cfaabi_tls.this_processor ); 539 /* paranoid */ verify( ! __preemption_enabled() ); 540 } 541 #endif 517 542 #endif -
libcfa/src/concurrency/io/setup.cfa
r94647b0 r7770cc8 32 32 33 33 void __cfa_io_start( processor * proc ) {} 34 void __cfa_io_flush( processor * proc) {}34 bool __cfa_io_flush( processor * proc, bool ) {} 35 35 void __cfa_io_stop ( processor * proc ) {} 36 36 … … 111 111 this.ext_sq.empty = true; 112 112 (this.ext_sq.queue){}; 113 __io_uring_setup( this, cl.io.params, proc->idle );113 __io_uring_setup( this, cl.io.params, proc->idle_fd ); 114 114 __cfadbg_print_safe(io_core, "Kernel I/O : Created ring for io_context %u (%p)\n", this.fd, &this); 115 115 } … … 220 220 cq.cqes = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes); 221 221 222 // Step 4 : eventfd 223 // io_uring_register is so f*cking slow on some machine that it 224 // will never succeed if preemption isn't hard blocked 225 __cfadbg_print_safe(io_core, "Kernel I/O : registering %d for completion with ring %d\n", procfd, fd); 226 227 __disable_interrupts_hard(); 228 229 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1); 230 if (ret < 0) { 231 abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno)); 232 } 233 234 __enable_interrupts_hard(); 235 236 __cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd); 222 #if !defined(IO_URING_IDLE) 223 // Step 4 : eventfd 224 // io_uring_register is so f*cking slow on some machine that it 225 // will never succeed if preemption isn't hard blocked 226 __cfadbg_print_safe(io_core, "Kernel I/O : registering %d for completion with ring %d\n", procfd, fd); 227 228 __disable_interrupts_hard(); 229 230 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1); 231 if (ret < 0) { 232 abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno)); 233 } 234 235 __enable_interrupts_hard(); 236 237 __cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd); 238 #endif 237 239 238 240 // some paranoid checks -
libcfa/src/concurrency/io/types.hfa
r94647b0 r7770cc8 185 185 186 186 // Wait for the future to be fulfilled 187 bool wait ( io_future_t & this ) {188 return wait(this.self);189 }187 bool wait ( io_future_t & this ) { return wait (this.self); } 188 void reset ( io_future_t & this ) { return reset (this.self); } 189 bool available( io_future_t & this ) { return available(this.self); } 190 190 } -
libcfa/src/concurrency/kernel.cfa
r94647b0 r7770cc8 34 34 #include "strstream.hfa" 35 35 #include "device/cpu.hfa" 36 #include "io/types.hfa" 36 37 37 38 //Private includes … … 124 125 static void __wake_one(cluster * cltr); 125 126 126 static void mark_idle (__cluster_proc_list & idles, processor & proc); 127 static void idle_sleep(processor * proc, io_future_t & future, char buf[]); 128 static bool mark_idle (__cluster_proc_list & idles, processor & proc); 127 129 static void mark_awake(__cluster_proc_list & idles, processor & proc); 128 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list idles );129 130 130 131 extern void __cfa_io_start( processor * ); 131 132 extern bool __cfa_io_drain( processor * ); 132 extern void __cfa_io_flush( processor *);133 extern bool __cfa_io_flush( processor *, bool wait ); 133 134 extern void __cfa_io_stop ( processor * ); 134 135 static inline bool __maybe_io_drain( processor * ); 136 137 #if defined(IO_URING_IDLE) && defined(CFA_HAVE_LINUX_IO_URING_H) 138 extern bool __kernel_read(processor * proc, io_future_t & future, char buf[], int fd); 139 #endif 135 140 136 141 extern void __disable_interrupts_hard(); … … 148 153 /* paranoid */ verify( __preemption_enabled() ); 149 154 } 155 150 156 151 157 //============================================================================================= … … 163 169 verify(this); 164 170 171 io_future_t future; // used for idle sleep when io_uring is present 172 future.self.ptr = 1p; // mark it as already fulfilled so we know if there is a pending request or not 173 char buf[sizeof(uint64_t)]; 174 165 175 __cfa_io_start( this ); 166 176 … … 196 206 197 207 if( !readyThread ) { 198 __cfa_io_flush( this ); 208 __cfa_io_flush( this, false ); 209 199 210 readyThread = __next_thread_slow( this->cltr ); 200 211 } … … 210 221 211 222 // Push self to idle stack 212 mark_idle(this->cltr->procs, * this);223 if(!mark_idle(this->cltr->procs, * this)) continue MAIN_LOOP; 213 224 214 225 // Confirm the ready-queue is empty … … 226 237 } 227 238 228 #if !defined(__CFA_NO_STATISTICS__) 229 if(this->print_halts) { 230 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); 239 idle_sleep( this, future, buf ); 240 241 // We were woken up, remove self from idle 242 mark_awake(this->cltr->procs, * this); 243 244 // DON'T just proceed, start looking again 245 continue MAIN_LOOP; 246 } 247 248 /* paranoid */ verify( readyThread ); 249 250 // Reset io dirty bit 251 this->io.dirty = false; 252 253 // We found a thread run it 254 __run_thread(this, readyThread); 255 256 // Are we done? 257 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 258 259 if(this->io.pending && !this->io.dirty) { 260 __cfa_io_flush( this, false ); 261 } 262 263 #else 264 #warning new kernel loop 265 SEARCH: { 266 /* paranoid */ verify( ! __preemption_enabled() ); 267 268 // First, lock the scheduler since we are searching for a thread 269 ready_schedule_lock(); 270 271 // Try to get the next thread 272 readyThread = pop_fast( this->cltr ); 273 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 274 275 // If we can't find a thread, might as well flush any outstanding I/O 276 if(this->io.pending) { __cfa_io_flush( this, false ); } 277 278 // Spin a little on I/O, just in case 279 for(5) { 280 __maybe_io_drain( this ); 281 readyThread = pop_fast( this->cltr ); 282 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 283 } 284 285 // no luck, try stealing a few times 286 for(5) { 287 if( __maybe_io_drain( this ) ) { 288 readyThread = pop_fast( this->cltr ); 289 } else { 290 readyThread = pop_slow( this->cltr ); 231 291 } 232 #endif 233 234 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 292 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 293 } 294 295 // still no luck, search for a thread 296 readyThread = pop_search( this->cltr ); 297 if(readyThread) { ready_schedule_unlock(); break SEARCH; } 298 299 // Don't block if we are done 300 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) { 301 ready_schedule_unlock(); 302 break MAIN_LOOP; 303 } 304 305 __STATS( __tls_stats()->ready.sleep.halts++; ) 306 307 // Push self to idle stack 308 ready_schedule_unlock(); 309 if(!mark_idle(this->cltr->procs, * this)) goto SEARCH; 310 ready_schedule_lock(); 311 312 // Confirm the ready-queue is empty 313 __maybe_io_drain( this ); 314 readyThread = pop_search( this->cltr ); 315 ready_schedule_unlock(); 316 317 if( readyThread ) { 318 // A thread was found, cancel the halt 319 mark_awake(this->cltr->procs, * this); 320 321 __STATS( __tls_stats()->ready.sleep.cancels++; ) 322 323 // continue the main loop 324 break SEARCH; 325 } 326 327 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); ) 328 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd); 235 329 236 330 { 237 331 eventfd_t val; 238 ssize_t ret = read( this->idle , &val, sizeof(val) );332 ssize_t ret = read( this->idle_fd, &val, sizeof(val) ); 239 333 if(ret < 0) { 240 334 switch((int)errno) { … … 252 346 } 253 347 254 #if !defined(__CFA_NO_STATISTICS__) 255 if(this->print_halts) { 256 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); 257 } 258 #endif 348 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); ) 259 349 260 350 // We were woken up, remove self from idle … … 265 355 } 266 356 267 /* paranoid */ verify( readyThread );268 269 // Reset io dirty bit270 this->io.dirty = false;271 272 // We found a thread run it273 __run_thread(this, readyThread);274 275 // Are we done?276 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;277 278 if(this->io.pending && !this->io.dirty) {279 __cfa_io_flush( this );280 }281 282 #else283 #warning new kernel loop284 SEARCH: {285 /* paranoid */ verify( ! __preemption_enabled() );286 287 // First, lock the scheduler since we are searching for a thread288 ready_schedule_lock();289 290 // Try to get the next thread291 readyThread = pop_fast( this->cltr );292 if(readyThread) { ready_schedule_unlock(); break SEARCH; }293 294 // If we can't find a thread, might as well flush any outstanding I/O295 if(this->io.pending) { __cfa_io_flush( this ); }296 297 // Spin a little on I/O, just in case298 for(5) {299 __maybe_io_drain( this );300 readyThread = pop_fast( this->cltr );301 if(readyThread) { ready_schedule_unlock(); break SEARCH; }302 }303 304 // no luck, try stealing a few times305 for(5) {306 if( __maybe_io_drain( this ) ) {307 readyThread = pop_fast( this->cltr );308 } else {309 readyThread = pop_slow( this->cltr );310 }311 if(readyThread) { ready_schedule_unlock(); break SEARCH; }312 }313 314 // still no luck, search for a thread315 readyThread = pop_search( this->cltr );316 if(readyThread) { ready_schedule_unlock(); break SEARCH; }317 318 // Don't block if we are done319 if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;320 321 __STATS( __tls_stats()->ready.sleep.halts++; )322 323 // Push self to idle stack324 ready_schedule_unlock();325 mark_idle(this->cltr->procs, * this);326 ready_schedule_lock();327 328 // Confirm the ready-queue is empty329 __maybe_io_drain( this );330 readyThread = pop_search( this->cltr );331 ready_schedule_unlock();332 333 if( readyThread ) {334 // A thread was found, cancel the halt335 mark_awake(this->cltr->procs, * this);336 337 __STATS( __tls_stats()->ready.sleep.cancels++; )338 339 // continue the main loop340 break SEARCH;341 }342 343 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )344 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);345 346 {347 eventfd_t val;348 ssize_t ret = read( this->idle, &val, sizeof(val) );349 if(ret < 0) {350 switch((int)errno) {351 case EAGAIN:352 #if EAGAIN != EWOULDBLOCK353 case EWOULDBLOCK:354 #endif355 case EINTR:356 // No need to do anything special here, just assume it's a legitimate wake-up357 break;358 default:359 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) );360 }361 }362 }363 364 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); )365 366 // We were woken up, remove self from idle367 mark_awake(this->cltr->procs, * this);368 369 // DON'T just proceed, start looking again370 continue MAIN_LOOP;371 }372 373 357 RUN_THREAD: 374 358 /* paranoid */ verify( ! __preemption_enabled() ); … … 385 369 386 370 if(this->io.pending && !this->io.dirty) { 387 __cfa_io_flush( this );371 __cfa_io_flush( this, false ); 388 372 } 389 373 … … 758 742 759 743 // Check if there is a sleeping processor 760 processor * p; 761 unsigned idle; 762 unsigned total; 763 [idle, total, p] = query_idles(this->procs); 744 int fd = __atomic_load_n(&this->procs.fd, __ATOMIC_SEQ_CST); 764 745 765 746 // If no one is sleeping, we are done 766 if( idle== 0 ) return;747 if( fd == 0 ) return; 767 748 768 749 // We found a processor, wake it up 769 750 eventfd_t val; 770 751 val = 1; 771 eventfd_write( p->idle, val );752 eventfd_write( fd, val ); 772 753 773 754 #if !defined(__CFA_NO_STATISTICS__) … … 794 775 eventfd_t val; 795 776 val = 1; 796 eventfd_write( this->idle , val );777 eventfd_write( this->idle_fd, val ); 797 778 __enable_interrupts_checked(); 798 779 } 799 780 800 static void mark_idle(__cluster_proc_list & this, processor & proc) { 801 /* paranoid */ verify( ! __preemption_enabled() ); 802 lock( this ); 781 static void idle_sleep(processor * this, io_future_t & future, char buf[]) { 782 #if !defined(IO_URING_IDLE) || !defined(CFA_HAVE_LINUX_IO_URING_H) 783 #if !defined(__CFA_NO_STATISTICS__) 784 if(this->print_halts) { 785 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); 786 } 787 #endif 788 789 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle_fd); 790 791 { 792 eventfd_t val; 793 ssize_t ret = read( this->idle_fd, &val, sizeof(val) ); 794 if(ret < 0) { 795 switch((int)errno) { 796 case EAGAIN: 797 #if EAGAIN != EWOULDBLOCK 798 case EWOULDBLOCK: 799 #endif 800 case EINTR: 801 // No need to do anything special here, just assume it's a legitimate wake-up 802 break; 803 default: 804 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 805 } 806 } 807 } 808 809 #if !defined(__CFA_NO_STATISTICS__) 810 if(this->print_halts) { 811 __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); 812 } 813 #endif 814 #else 815 #if !defined(CFA_HAVE_IORING_OP_READ) 816 #error this is only implemented if the read is present 817 #endif 818 // Do we already have a pending read 819 if(available(future)) { 820 // There is no pending read, we need to add one 821 reset(future); 822 823 __kernel_read(this, future, buf, this->idle_fd ); 824 } 825 826 __cfa_io_flush( this, true ); 827 #endif 828 } 829 830 static bool mark_idle(__cluster_proc_list & this, processor & proc) { 831 /* paranoid */ verify( ! __preemption_enabled() ); 832 if(!try_lock( this )) return false; 803 833 this.idle++; 804 834 /* paranoid */ verify( this.idle <= this.total ); 805 835 remove(proc); 806 836 insert_first(this.idles, proc); 837 838 __atomic_store_n(&this.fd, proc.idle_fd, __ATOMIC_SEQ_CST); 807 839 unlock( this ); 808 840 /* paranoid */ verify( ! __preemption_enabled() ); 841 842 return true; 809 843 } 810 844 … … 816 850 remove(proc); 817 851 insert_last(this.actives, proc); 852 853 { 854 int fd = 0; 855 if(!this.idles`isEmpty) fd = this.idles`first.idle_fd; 856 __atomic_store_n(&this.fd, fd, __ATOMIC_SEQ_CST); 857 } 858 818 859 unlock( this ); 819 /* paranoid */ verify( ! __preemption_enabled() );820 }821 822 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list this ) {823 /* paranoid */ verify( ! __preemption_enabled() );824 /* paranoid */ verify( ready_schedule_islocked() );825 826 for() {827 uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);828 if( 1 == (l % 2) ) { Pause(); continue; }829 unsigned idle = this.idle;830 unsigned total = this.total;831 processor * proc = &this.idles`first;832 // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it833 asm volatile("": : :"memory");834 if(l != __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST)) { Pause(); continue; }835 return [idle, total, proc];836 }837 838 /* paranoid */ verify( ready_schedule_islocked() );839 860 /* paranoid */ verify( ! __preemption_enabled() ); 840 861 } … … 898 919 if(head == tail) return false; 899 920 #if OLD_MAIN 900 ready_schedule_lock();901 ret = __cfa_io_drain( proc );902 ready_schedule_unlock();921 ready_schedule_lock(); 922 ret = __cfa_io_drain( proc ); 923 ready_schedule_unlock(); 903 924 #else 904 925 ret = __cfa_io_drain( proc ); 905 #endif926 #endif 906 927 #endif 907 928 return ret; … … 939 960 /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count); 940 961 /* paranoid */ verify( it->local_data->this_stats ); 962 // __print_stats( it->local_data->this_stats, cltr->print_stats, "Processor", it->name, (void*)it ); 941 963 __tally_stats( cltr->stats, it->local_data->this_stats ); 942 964 it = &(*it)`next; … … 948 970 // this doesn't solve all problems but does solve many 949 971 // so it's probably good enough 972 disable_interrupts(); 950 973 uint_fast32_t last_size = ready_mutate_lock(); 951 974 … … 955 978 // Unlock the RWlock 956 979 ready_mutate_unlock( last_size ); 980 enable_interrupts(); 957 981 } 958 982 -
libcfa/src/concurrency/kernel.hfa
r94647b0 r7770cc8 100 100 101 101 // Idle lock (kernel semaphore) 102 int idle ;102 int idle_fd; 103 103 104 104 // Termination synchronisation (user semaphore) … … 195 195 struct __cluster_proc_list { 196 196 // Spin lock protecting the queue 197 volatile uint64_t lock; 197 __spinlock_t lock; 198 199 // FD to use to wake a processor 200 volatile int fd; 198 201 199 202 // Total number of processors -
libcfa/src/concurrency/kernel/startup.cfa
r94647b0 r7770cc8 100 100 // Other Forward Declarations 101 101 extern void __wake_proc(processor *); 102 extern int cfa_main_returned; // from interpose.cfa 102 103 103 104 //----------------------------------------------------------------------------- … … 268 269 269 270 static void __kernel_shutdown(void) { 271 if(!cfa_main_returned) return; 270 272 /* paranoid */ verify( __preemption_enabled() ); 271 273 disable_interrupts(); … … 525 527 this.local_data = 0p; 526 528 527 this.idle = eventfd(0, 0);528 if (idle < 0) {529 this.idle_fd = eventfd(0, 0); 530 if (idle_fd < 0) { 529 531 abort("KERNEL ERROR: PROCESSOR EVENTFD - %s\n", strerror(errno)); 530 532 } … … 540 542 // Not a ctor, it just preps the destruction but should not destroy members 541 543 static void deinit(processor & this) { 542 close(this.idle );544 close(this.idle_fd); 543 545 } 544 546 … … 582 584 // Cluster 583 585 static void ?{}(__cluster_proc_list & this) { 584 this. lock= 0;586 this.fd = 0; 585 587 this.idle = 0; 586 588 this.total = 0; -
libcfa/src/concurrency/kernel_private.hfa
r94647b0 r7770cc8 39 39 } 40 40 41 // #define IO_URING_IDLE 42 41 43 //----------------------------------------------------------------------------- 42 44 // Scheduler … … 149 151 __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE); 150 152 } 151 152 153 154 155 153 156 154 //----------------------------------------------------------------------- … … 268 266 ready_schedule_lock(); 269 267 270 // Simple counting lock, acquired, acquired by incrementing the counter 271 // to an odd number 272 for() { 273 uint64_t l = this.lock; 274 if( 275 (0 == (l % 2)) 276 && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) 277 ) return; 278 Pause(); 279 } 280 281 /* paranoid */ verify( ! __preemption_enabled() ); 268 lock( this.lock __cfaabi_dbg_ctx2 ); 269 270 /* paranoid */ verify( ! __preemption_enabled() ); 271 } 272 273 static inline bool try_lock(__cluster_proc_list & this) { 274 /* paranoid */ verify( ! __preemption_enabled() ); 275 276 // Start by locking the global RWlock so that we know no-one is 277 // adding/removing processors while we mess with the idle lock 278 ready_schedule_lock(); 279 280 if(try_lock( this.lock __cfaabi_dbg_ctx2 )) { 281 // success 282 /* paranoid */ verify( ! __preemption_enabled() ); 283 return true; 284 } 285 286 // failed to lock 287 ready_schedule_unlock(); 288 289 /* paranoid */ verify( ! __preemption_enabled() ); 290 return false; 282 291 } 283 292 … … 285 294 /* paranoid */ verify( ! __preemption_enabled() ); 286 295 287 /* paranoid */ verify( 1 == (this.lock % 2) ); 288 // Simple couting lock, release by incrementing to an even number 289 __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST ); 296 unlock(this.lock); 290 297 291 298 // Release the global lock, which we acquired when locking -
libcfa/src/concurrency/monitor.hfa
r94647b0 r7770cc8 65 65 free( th ); 66 66 } 67 68 static inline forall( T & | sized(T) | { void ^?{}( T & mutex ); } ) 69 void adelete( T arr[] ) { 70 if ( arr ) { // ignore null 71 size_t dim = malloc_size( arr ) / sizeof( T ); 72 for ( int i = dim - 1; i >= 0; i -= 1 ) { // reverse allocation order, must be unsigned 73 ^(arr[i]){}; // run destructor 74 } // for 75 free( arr ); 76 } // if 77 } // adelete 67 78 68 79 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/mutex_stmt.hfa
r94647b0 r7770cc8 1 1 #include "bits/algorithm.hfa" 2 #include <assert.h> 3 #include "invoke.h" 4 #include "stdlib.hfa" 5 #include <stdio.h> 2 #include "bits/defs.hfa" 6 3 7 4 //----------------------------------------------------------------------------- -
libcfa/src/device/cpu.cfa
r94647b0 r7770cc8 144 144 // Count number of cpus in the system 145 145 static int count_cpus(void) { 146 const char * fpath = "/sys/devices/system/cpu/ present";146 const char * fpath = "/sys/devices/system/cpu/online"; 147 147 int fd = open(fpath, 0, O_RDONLY); 148 148 /* paranoid */ verifyf(fd >= 0, "Could not open file %s", fpath); -
libcfa/src/fstream.cfa
r94647b0 r7770cc8 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Sep 21 21:51:38202113 // Update Count : 46012 // Last Modified On : Sun Oct 10 11:23:05 2021 13 // Update Count : 512 14 14 // 15 15 … … 28 28 #define IO_MSG "I/O error: " 29 29 30 void ?{}( ofstream & os, void * file ) with(os) { 30 // private 31 void ?{}( ofstream & os, void * file ) with( os ) { 31 32 file$ = file; 32 33 sepDefault$ = true; … … 35 36 prt$ = false; 36 37 sawNL$ = false; 37 acquired$ = false;38 38 sepSetCur$( os, sepGet( os ) ); 39 39 sepSet( os, " " ); … … 41 41 } // ?{} 42 42 43 // private 44 bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; } 45 void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; } 46 void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; } 47 const char * sepGetCur$( ofstream & os ) { return os.sepCur$; } 48 void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; } 49 bool getNL$( ofstream & os ) { return os.sawNL$; } 50 void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; } 51 bool getANL$( ofstream & os ) { return os.nlOnOff$; } 52 bool getPrt$( ofstream & os ) { return os.prt$; } 53 void setPrt$( ofstream & os, bool state ) { os.prt$ = state; } 43 inline bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; } 44 inline void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; } 45 inline void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; } 46 inline const char * sepGetCur$( ofstream & os ) { return os.sepCur$; } 47 inline void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; } 48 inline bool getNL$( ofstream & os ) { return os.sawNL$; } 49 inline void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; } 50 inline bool getANL$( ofstream & os ) { return os.nlOnOff$; } 51 inline bool getPrt$( ofstream & os ) { return os.prt$; } 52 inline void setPrt$( ofstream & os, bool state ) { os.prt$ = state; } 53 54 inline void lock( ofstream & os ) with( os ) { lock( os.lock$ ); } 55 inline void unlock( ofstream & os ) { unlock( os.lock$ ); } 54 56 55 57 // public 56 58 void ?{}( ofstream & os ) { os.file$ = 0p; } 57 58 void ?{}( ofstream & os, const char name[], const char mode[] ) { 59 open( os, name, mode ); 60 } // ?{} 61 62 void ?{}( ofstream & os, const char name[] ) { 63 open( os, name, "w" ); 64 } // ?{} 65 66 void ^?{}( ofstream & os ) { 67 close( os ); 68 } // ^?{} 59 void ?{}( ofstream & os, const char name[], const char mode[] ) { open( os, name, mode ); } 60 void ?{}( ofstream & os, const char name[] ) { open( os, name, "w" ); } 61 void ^?{}( ofstream & os ) { close( os ); } 69 62 70 63 void sepOn( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); } … … 107 100 if ( &os == &exit ) exit( EXIT_FAILURE ); 108 101 if ( &os == &abort ) abort(); 109 if ( os.acquired$ ) { os.acquired$ = false; release( os ); }110 102 } // ends 111 103 112 bool fail( ofstream & os ) { 113 return os.file$ == 0 || ferror( (FILE *)(os.file$) ); 114 } // fail 115 116 void clear( ofstream & os ) { 117 clearerr( (FILE *)(os.file$) ); 118 } // clear 119 120 int flush( ofstream & os ) { 121 return fflush( (FILE *)(os.file$) ); 122 } // flush 104 bool fail( ofstream & os ) { return os.file$ == 0 || ferror( (FILE *)(os.file$) ); } 105 void clear( ofstream & os ) { clearerr( (FILE *)(os.file$) ); } 106 int flush( ofstream & os ) { return fflush( (FILE *)(os.file$) ); } 123 107 124 108 void open( ofstream & os, const char name[], const char mode[] ) { 125 FILE * file = fopen( name, mode ); 109 FILE * file; 110 for ( cnt; 10 ) { 111 errno = 0; 112 file = fopen( name, mode ); 113 if ( file != 0p || errno != EINTR ) break; // timer interrupt ? 114 if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" ); 115 } // for 126 116 if ( file == 0p ) { 127 117 throw (Open_Failure){ os }; … … 131 121 } // open 132 122 133 void open( ofstream & os, const char name[] ) { 134 open( os, name, "w" ); 135 } // open 136 137 void close( ofstream & os ) with(os) { 123 void open( ofstream & os, const char name[] ) { open( os, name, "w" ); } 124 125 void close( ofstream & os ) with( os ) { 138 126 if ( (FILE *)(file$) == 0p ) return; 139 127 if ( (FILE *)(file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return; 140 128 141 if ( fclose( (FILE *)(file$) ) == EOF ) { 129 int ret; 130 for ( cnt; 10 ) { 131 errno = 0; 132 ret = fclose( (FILE *)(file$) ); 133 if ( ret != EOF || errno != EINTR ) break; // timer interrupt ? 134 if ( cnt == 9 ) abort( "ofstream open EINTR spinning exceeded" ); 135 } // for 136 if ( ret == EOF ) { 142 137 throw (Close_Failure){ os }; 143 138 // abort | IO_MSG "close output" | nl | strerror( errno ); 144 139 } // if 145 file$ = 0p; 140 file$ = 0p; // safety after close 146 141 } // close 147 142 … … 162 157 va_list args; 163 158 va_start( args, format ); 164 int len = vfprintf( (FILE *)(os.file$), format, args ); 159 160 int len; 161 for ( cnt; 10 ) { 162 errno = 0; 163 len = vfprintf( (FILE *)(os.file$), format, args ); 164 if ( len != EOF || errno != EINTR ) break; // timer interrupt ? 165 if ( cnt == 9 ) abort( "ofstream fmt EINTR spinning exceeded" ); 166 } // for 165 167 if ( len == EOF ) { 166 168 if ( ferror( (FILE *)(os.file$) ) ) { … … 175 177 } // fmt 176 178 177 inline void acquire( ofstream & os ) with(os) {178 lock( lock$ ); // may increase recursive lock179 if ( ! acquired$ ) acquired$ = true; // not locked ?180 else unlock( lock$ ); // unwind recursive lock at start181 } // acquire182 183 inline void release( ofstream & os ) {184 unlock( os.lock$ );185 } // release186 187 void ?{}( osacquire & acq, ofstream & os ) { lock( os.lock$ ); &acq.os = &os; }188 void ^?{}( osacquire & acq ) { release( acq.os ); }189 190 179 static ofstream soutFile = { (FILE *)stdout }; 191 180 ofstream & sout = soutFile, & stdout = soutFile; … … 205 194 flush( os ); 206 195 return os; 207 // (ofstream &)(os | '\n');208 // setPrt$( os, false ); // turn off209 // setNL$( os, true );210 // flush( os );211 // return sepOff( os ); // prepare for next line212 196 } // nl 213 197 … … 217 201 218 202 // private 219 void ?{}( ifstream & is, void * file ) with( is) {203 void ?{}( ifstream & is, void * file ) with( is ) { 220 204 file$ = file; 221 205 nlOnOff$ = false; 222 acquired$ = false; 223 } // ?{} 206 } // ?{} 207 208 bool getANL$( ifstream & os ) { return os.nlOnOff$; } 209 210 inline void lock( ifstream & os ) with( os ) { lock( os.lock$ ); } 211 inline void unlock( ifstream & os ) { unlock( os.lock$ ); } 224 212 225 213 // public 226 214 void ?{}( ifstream & is ) { is.file$ = 0p; } 227 228 void ?{}( ifstream & is, const char name[], const char mode[] ) { 229 open( is, name, mode ); 230 } // ?{} 231 232 void ?{}( ifstream & is, const char name[] ) { 233 open( is, name, "r" ); 234 } // ?{} 235 236 void ^?{}( ifstream & is ) { 237 close( is ); 238 } // ^?{} 215 void ?{}( ifstream & is, const char name[], const char mode[] ) { open( is, name, mode ); } 216 void ?{}( ifstream & is, const char name[] ) { open( is, name, "r" ); } 217 void ^?{}( ifstream & is ) { close( is ); } 218 219 bool fail( ifstream & is ) { return is.file$ == 0p || ferror( (FILE *)(is.file$) ); } 220 void clear( ifstream & is ) { clearerr( (FILE *)(is.file$) ); } 239 221 240 222 void nlOn( ifstream & os ) { os.nlOnOff$ = true; } 241 223 void nlOff( ifstream & os ) { os.nlOnOff$ = false; } 242 bool getANL( ifstream & os ) { return os.nlOnOff$; } 243 244 bool fail( ifstream & is ) { 245 return is.file$ == 0p || ferror( (FILE *)(is.file$) ); 246 } // fail 247 248 void clear( ifstream & is ) { 249 clearerr( (FILE *)(is.file$) ); 250 } // clear 251 252 void ends( ifstream & is ) { 253 if ( is.acquired$ ) { is.acquired$ = false; release( is ); } 254 } // ends 255 256 bool eof( ifstream & is ) { 257 return feof( (FILE *)(is.file$) ); 258 } // eof 224 225 void ends( ifstream & is ) {} 226 227 bool eof( ifstream & is ) { return feof( (FILE *)(is.file$) ) != 0; } 259 228 260 229 void open( ifstream & is, const char name[], const char mode[] ) { 261 FILE * file = fopen( name, mode ); 230 FILE * file; 231 for ( cnt; 10 ) { 232 errno = 0; 233 file = fopen( name, mode ); 234 if ( file != 0p || errno != EINTR ) break; // timer interrupt ? 235 if ( cnt == 9 ) abort( "ifstream open EINTR spinning exceeded" ); 236 } // for 262 237 if ( file == 0p ) { 263 238 throw (Open_Failure){ is }; … … 267 242 } // open 268 243 269 void open( ifstream & is, const char name[] ) { 270 open( is, name, "r" ); 271 } // open 272 273 void close( ifstream & is ) with(is) { 244 void open( ifstream & is, const char name[] ) { open( is, name, "r" ); } 245 246 void close( ifstream & is ) with( is ) { 274 247 if ( (FILE *)(file$) == 0p ) return; 275 248 if ( (FILE *)(file$) == (FILE *)stdin ) return; 276 249 277 if ( fclose( (FILE *)(file$) ) == EOF ) { 250 int ret; 251 for ( cnt; 10 ) { 252 errno = 0; 253 ret = fclose( (FILE *)(file$) ); 254 if ( ret != EOF || errno != EINTR ) break; // timer interrupt ? 255 if ( cnt == 9 ) abort( "ifstream close EINTR spinning exceeded" ); 256 } // for 257 if ( ret == EOF ) { 278 258 throw (Close_Failure){ is }; 279 259 // abort | IO_MSG "close input" | nl | strerror( errno ); 280 260 } // if 281 file$ = 0p; 261 file$ = 0p; // safety after close 282 262 } // close 283 263 … … 308 288 int fmt( ifstream & is, const char format[], ... ) { 309 289 va_list args; 310 311 290 va_start( args, format ); 312 int len = vfscanf( (FILE *)(is.file$), format, args ); 291 292 int len; 293 for () { // no check for EINTR limit waiting for keyboard input 294 errno = 0; 295 len = vfscanf( (FILE *)(is.file$), format, args ); 296 if ( len != EOF || errno != EINTR ) break; // timer interrupt ? 297 } // for 313 298 if ( len == EOF ) { 314 299 if ( ferror( (FILE *)(is.file$) ) ) { … … 319 304 return len; 320 305 } // fmt 321 322 inline void acquire( ifstream & is ) with(is) {323 lock( lock$ ); // may increase recursive lock324 if ( ! acquired$ ) acquired$ = true; // not locked ?325 else unlock( lock$ ); // unwind recursive lock at start326 } // acquire327 328 inline void release( ifstream & is ) {329 unlock( is.lock$ );330 } // release331 332 void ?{}( isacquire & acq, ifstream & is ) { lock( is.lock$ ); &acq.is = &is; }333 void ^?{}( isacquire & acq ) { release( acq.is ); }334 306 335 307 static ifstream sinFile = { (FILE *)stdin }; -
libcfa/src/fstream.hfa
r94647b0 r7770cc8 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jul 28 07:35:50202113 // Update Count : 2 3412 // Last Modified On : Sun Oct 10 09:37:32 2021 13 // Update Count : 243 14 14 // 15 15 … … 36 36 char tupleSeparator$[ofstream_sepSize]; 37 37 multiple_acquisition_lock lock$; 38 bool acquired$;39 38 }; // ofstream 40 39 … … 52 51 bool getPrt$( ofstream & ); 53 52 void setPrt$( ofstream &, bool ); 53 54 void lock( ofstream & ); 55 void unlock( ofstream & ); 54 56 55 57 // public … … 75 77 void open( ofstream &, const char name[] ); 76 78 void close( ofstream & ); 79 77 80 ofstream & write( ofstream &, const char data[], size_t size ); 78 79 void acquire( ofstream & );80 void release( ofstream & );81 82 void lock( ofstream & );83 void unlock( ofstream & );84 85 struct osacquire {86 ofstream & os;87 };88 void ?{}( osacquire & acq, ofstream & );89 void ^?{}( osacquire & acq );90 81 91 82 void ?{}( ofstream & ); … … 110 101 bool nlOnOff$; 111 102 multiple_acquisition_lock lock$; 112 bool acquired$;113 103 }; // ifstream 114 104 115 105 // Satisfies istream 116 106 107 // private 108 bool getANL$( ifstream & ); 109 110 void lock( ifstream & ); 111 void unlock( ifstream & ); 112 117 113 // public 118 114 void nlOn( ifstream & ); 119 115 void nlOff( ifstream & ); 120 bool getANL( ifstream & );121 116 void ends( ifstream & ); 122 117 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); … … 128 123 void open( ifstream & is, const char name[] ); 129 124 void close( ifstream & is ); 125 130 126 ifstream & read( ifstream & is, char data[], size_t size ); 131 127 ifstream & ungetc( ifstream & is, char c ); 132 133 void acquire( ifstream & is );134 void release( ifstream & is );135 136 struct isacquire {137 ifstream & is;138 };139 void ?{}( isacquire & acq, ifstream & is );140 void ^?{}( isacquire & acq );141 128 142 129 void ?{}( ifstream & is ); -
libcfa/src/heap.cfa
r94647b0 r7770cc8 102 102 } // prtUnfreed 103 103 104 extern int cfa_main_returned; // from bootloader.cf104 extern int cfa_main_returned; // from interpose.cfa 105 105 extern "C" { 106 106 void heapAppStart() { // called by __cfaabi_appready_startup -
libcfa/src/interpose.cfa
r94647b0 r7770cc8 94 94 } __cabi_libc; 95 95 96 int cfa_main_returned; 97 96 98 extern "C" { 97 99 void __cfaabi_interpose_startup( void ) { 98 100 const char *version = 0p; 101 cfa_main_returned = 0; 99 102 100 103 preload_libgcc(); -
libcfa/src/iostream.cfa
r94647b0 r7770cc8 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S at May 15 09:39:21202113 // Update Count : 134 212 // Last Modified On : Sun Oct 10 09:28:17 2021 13 // Update Count : 1345 14 14 // 15 15 … … 398 398 return os; 399 399 } // nlOff 400 } // distribution401 402 forall( ostype & | ostream( ostype ) ) {403 ostype & acquire( ostype & os ) {404 acquire( os ); // call void returning405 return os;406 } // acquire407 400 } // distribution 408 401 … … 829 822 fmt( is, "%c", &temp ); // must pass pointer through varg to fmt 830 823 // do not overwrite parameter with newline unless appropriate 831 if ( temp != '\n' || getANL ( is ) ) { c = temp; break; }824 if ( temp != '\n' || getANL$( is ) ) { c = temp; break; } 832 825 if ( eof( is ) ) break; 833 826 } // for … … 1035 1028 return is; 1036 1029 } // nlOff 1037 } // distribution1038 1039 forall( istype & | istream( istype ) ) {1040 istype & acquire( istype & is ) {1041 acquire( is ); // call void returning1042 return is;1043 } // acquire1044 1030 } // distribution 1045 1031 -
libcfa/src/iostream.hfa
r94647b0 r7770cc8 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 28 20:37:56202113 // Update Count : 40 112 // Last Modified On : Sun Oct 10 10:02:07 2021 13 // Update Count : 407 14 14 // 15 15 … … 58 58 void close( ostype & ); 59 59 ostype & write( ostype &, const char [], size_t ); 60 void acquire( ostype & ); // concurrent access61 60 }; // ostream 62 61 … … 142 141 ostype & nlOn( ostype & ); 143 142 ostype & nlOff( ostype & ); 144 } // distribution145 146 forall( ostype & | ostream( ostype ) ) {147 ostype & acquire( ostype & );148 143 } // distribution 149 144 … … 296 291 297 292 trait basic_istream( istype & ) { 298 bool getANL( istype & ); // get scan newline (on/off) 293 // private 294 bool getANL$( istype & ); // get scan newline (on/off) 295 // public 299 296 void nlOn( istype & ); // read newline 300 297 void nlOff( istype & ); // scan newline 301 302 298 void ends( istype & os ); // end of output statement 303 299 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); … … 312 308 void close( istype & is ); 313 309 istype & read( istype &, char [], size_t ); 314 void acquire( istype & ); // concurrent access315 310 }; // istream 316 311 … … 379 374 } // distribution 380 375 381 forall( istype & | istream( istype ) ) {382 istype & acquire( istype & );383 } // distribution384 385 376 // *********************************** manipulators *********************************** 386 377 -
libcfa/src/strstream.cfa
r94647b0 r7770cc8 10 10 // Created On : Thu Apr 22 22:24:35 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 27 20:59:53202113 // Update Count : 7812 // Last Modified On : Sun Oct 10 16:13:20 2021 13 // Update Count : 101 14 14 // 15 15 16 16 #include "strstream.hfa" 17 #include "fstream.hfa" // abort 17 18 18 19 #include <stdio.h> // vsnprintf … … 30 31 31 32 // private 32 bool sepPrt$( ostrstream & os ) { setNL$( os, false ); return os.sepOnOff$; }33 void sepReset$( ostrstream & os ) { os.sepOnOff$ = os.sepDefault$; }34 void sepReset$( ostrstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }35 const char * sepGetCur$( ostrstream & os ) { return os.sepCur$; }36 void sepSetCur$( ostrstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }37 bool getNL$( ostrstream & os ) { return os.sawNL$; }38 void setNL$( ostrstream & os, bool state ) { os.sawNL$ = state; }39 bool getANL$( ostrstream & os ) { return os.nlOnOff$; }40 bool getPrt$( ostrstream & os ) { return os.prt$; }41 void setPrt$( ostrstream & os, bool state ) { os.prt$ = state; }33 inline bool sepPrt$( ostrstream & os ) { setNL$( os, false ); return os.sepOnOff$; } 34 inline void sepReset$( ostrstream & os ) { os.sepOnOff$ = os.sepDefault$; } 35 inline void sepReset$( ostrstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; } 36 inline const char * sepGetCur$( ostrstream & os ) { return os.sepCur$; } 37 inline void sepSetCur$( ostrstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; } 38 inline bool getNL$( ostrstream & os ) { return os.sawNL$; } 39 inline void setNL$( ostrstream & os, bool state ) { os.sawNL$ = state; } 40 inline bool getANL$( ostrstream & os ) { return os.nlOnOff$; } 41 inline bool getPrt$( ostrstream & os ) { return os.prt$; } 42 inline void setPrt$( ostrstream & os, bool state ) { os.prt$ = state; } 42 43 43 44 // public … … 128 129 // *********************************** istrstream *********************************** 129 130 131 // private 132 bool getANL$( istrstream & is ) { return is.nlOnOff$; } 130 133 131 134 // public … … 136 139 } // ?{} 137 140 138 bool getANL( istrstream & is ) { return is.nlOnOff$; }139 141 void nlOn( istrstream & is ) { is.nlOnOff$ = true; } 140 142 void nlOff( istrstream & is ) { is.nlOnOff$ = false; } 141 143 142 void ends( istrstream & is ) { 143 } // ends 144 void ends( istrstream & is ) {} 145 bool eof( istrstream & is ) { return false; } 144 146 145 int eof( istrstream & is ) { 146 return 0; 147 } // eof 147 int fmt( istrstream & is, const char format[], ... ) with(is) { 148 va_list args; 149 va_start( args, format ); 150 // THIS DOES NOT WORK BECAUSE VSSCANF RETURNS NUMBER OF VALUES READ VERSUS BUFFER POSITION SCANNED. 151 int len = vsscanf( buf$ + cursor$, format, args ); 152 va_end( args ); 153 if ( len == EOF ) { 154 abort | IO_MSG "invalid read"; 155 } // if 156 // SKULLDUGGERY: This hack skips over characters read by vsscanf by moving to the next whitespace but it does not 157 // handle C reads with wdi manipulators that leave the cursor at a non-whitespace character. 158 for ( ; buf$[cursor$] != ' ' && buf$[cursor$] != '\t' && buf$[cursor$] != '\0'; cursor$ += 1 ) { 159 //printf( "X \'%c\'\n", buf$[cursor$] ); 160 } // for 161 if ( buf$[cursor$] != '\0' ) cursor$ += 1; // advance to whitespace 162 return len; 163 } // fmt 148 164 149 165 istrstream &ungetc( istrstream & is, char c ) { … … 154 170 } // ungetc 155 171 156 int fmt( istrstream & is, const char format[], ... ) {157 va_list args;158 va_start( args, format );159 // This does not work because vsscanf does not return buffer position.160 int len = vsscanf( is.buf$ + is.cursor$, format, args );161 va_end( args );162 if ( len == EOF ) {163 int j;164 printf( "X %d%n\n", len, &j );165 } // if166 is.cursor$ += len;167 return len;168 } // fmt169 170 172 // Local Variables: // 171 173 // tab-width: 4 // -
libcfa/src/strstream.hfa
r94647b0 r7770cc8 10 10 // Created On : Thu Apr 22 22:20:59 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 27 20:58:50202113 // Update Count : 4 112 // Last Modified On : Sun Oct 10 10:14:22 2021 13 // Update Count : 47 14 14 // 15 15 … … 85 85 // Satisfies basic_istream 86 86 87 // private 88 bool getANL$( istrstream & ); 89 87 90 // public 88 bool getANL( istrstream & );89 91 void nlOn( istrstream & ); 90 92 void nlOff( istrstream & ); 91 93 void ends( istrstream & ); 94 92 95 int fmt( istrstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 93 istrstream & ungetc( istrstream & is, char c);94 int eof( istrstream & is);96 istrstream & ungetc( istrstream &, char ); 97 bool eof( istrstream & ); 95 98 96 void ?{}( istrstream & is, char buf[] );99 void ?{}( istrstream &, char buf[] ); 97 100 98 101 // Local Variables: // -
src/AST/Convert.cpp
r94647b0 r7770cc8 1041 1041 1042 1042 const ast::Expr * visit( const ast::StmtExpr * node ) override final { 1043 auto stmts = node->stmts;1044 // disable sharing between multiple StmtExprs explicitly.1045 // this should no longer be true.1046 1047 1043 auto rslt = new StmtExpr( 1048 get<CompoundStmt>().accept1( stmts)1044 get<CompoundStmt>().accept1(node->stmts) 1049 1045 ); 1050 1046 1051 1047 rslt->returnDecls = get<ObjectDecl>().acceptL(node->returnDecls); 1052 1048 rslt->dtors = get<Expression>().acceptL(node->dtors); 1053 if (node->resultExpr) { 1054 // this MUST be found by children visit 1055 rslt->resultExpr = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(node->resultExpr)); 1056 } 1049 1050 // is this even used after convert? 1051 //if (tmp->resultExpr) { 1052 // // this MUST be found by children visit 1053 // rslt->resultExpr = strict_dynamic_cast<ExprStmt *>(readonlyCache.at(tmp->resultExpr)); 1054 //} 1057 1055 1058 1056 auto expr = visitBaseExpr( node, rslt ); … … 1446 1444 1447 1445 std::list< Declaration * > convert( const ast::TranslationUnit && translationUnit ) { 1446 // Copy values from the global store to the local static variables. 1447 ast::sizeType = translationUnit.global.sizeType; 1448 ast::dereferenceOperator = translationUnit.global.dereference; 1449 ast::dtorStruct = translationUnit.global.dtorStruct; 1450 ast::dtorStructDestroy = translationUnit.global.dtorDestroy; 1451 1448 1452 ConverterNewToOld c; 1449 1453 std::list< Declaration * > decls; -
src/AST/Copy.hpp
r94647b0 r7770cc8 10 10 // Created On : Wed Jul 10 16:13:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Jun 19 16:43:00 202013 // Update Count : 112 // Last Modified On : Thr Nov 11 9:22:00 2021 13 // Update Count : 2 14 14 // 15 15 16 16 #pragma once 17 17 18 #include "Decl.hpp" 19 #include "Expr.hpp" 20 #include "Pass.hpp" 21 #include "Stmt.hpp" 22 #include "Type.hpp" 23 #include <unordered_set> 24 #include <unordered_map> 18 #include "Node.hpp" 19 #include <cassert> 25 20 26 21 namespace ast { … … 43 38 */ 44 39 45 class DeepCopyCore { 46 std::unordered_map< const Node *, const Node * > nodeCache; 47 std::unordered_set< readonly<Node> * > readonlyCache; 48 49 template<typename node_t> 50 void readonlyInsert( const readonly<node_t> * ptrptr ) { 51 readonlyCache.insert( (readonly<Node> *) ptrptr ); 52 } 53 54 public: 55 template<typename node_t> 56 const node_t * previsit( const node_t * node ) { 57 const node_t * copy = shallowCopy( node ); 58 nodeCache.insert( std::make_pair( node, copy ) ); 59 return copy; 60 } 61 62 void postvisit( const AggregateDecl * node ) { 63 readonlyInsert( &node->parent ); 64 } 65 66 void postvisit( const StructInstType * node ) { 67 readonlyInsert( &node->base ); 68 } 69 70 void postvisit( const UnionInstType * node ) { 71 readonlyInsert( &node->base ); 72 } 73 74 void postvisit( const EnumInstType * node ) { 75 readonlyInsert( &node->base ); 76 } 77 78 void postvisit( const TraitInstType * node ) { 79 readonlyInsert( &node->base ); 80 } 81 82 void postvisit( const TypeInstType * node ) { 83 readonlyInsert( &node->base ); 84 } 85 86 void postvisit( const ImplicitCtorDtorStmt * node ) { 87 readonlyInsert( (const readonly<Stmt> *) &node->callStmt ); 88 } 89 90 void postvisit( const MemberExpr * node ) { 91 readonlyInsert( &node->member ); 92 } 93 94 void postvisit( const VariableExpr * node ) { 95 readonlyInsert( &node->var ); 96 } 97 98 void postvisit( const OffsetofExpr * node ) { 99 readonlyInsert( &node->member ); 100 } 101 102 void postvisit( const DeletedExpr * node ) { 103 readonlyInsert( &node->deleteStmt ); 104 } 105 106 void readonlyUpdates() { 107 for ( readonly<Node> * ptr : readonlyCache ) { 108 auto it = nodeCache.find( ptr->get() ); 109 if ( nodeCache.end() != it ) { 110 *ptr = it->second; 111 } 112 } 113 } 114 }; 115 40 // Implementations: 116 41 template<typename node_t> 117 42 node_t * shallowCopy( const node_t * localRoot ) { … … 121 46 template<typename node_t> 122 47 node_t * deepCopy( const node_t * localRoot ) { 123 Pass< DeepCopyCore > dc; 124 node_t const * newRoot = localRoot->accept( dc ); 125 dc.core.readonlyUpdates(); 126 return const_cast< node_t * >( newRoot ); 48 return strict_dynamic_cast<node_t *>( deepCopy<Node>( localRoot ) ); 127 49 } 50 51 template<> 52 Node * deepCopy<Node>( const Node * localRoot ); 128 53 129 54 } -
src/AST/Decl.hpp
r94647b0 r7770cc8 131 131 // declared type, derived from parameter declarations 132 132 ptr<FunctionType> type; 133 /// Null for the forward declaration of a function. 133 134 ptr<CompoundStmt> stmts; 134 135 std::vector< ptr<Expr> > withExprs; … … 269 270 : AggregateDecl( loc, name, std::move(attrs), linkage ), kind( kind ) {} 270 271 271 bool is_coroutine() { return kind == Coroutine; }272 bool is_generator() { return kind == Generator; }273 bool is_monitor () { return kind == Monitor ; }274 bool is_thread () { return kind == Thread ; }272 bool is_coroutine() const { return kind == Coroutine; } 273 bool is_generator() const { return kind == Generator; } 274 bool is_monitor () const { return kind == Monitor ; } 275 bool is_thread () const { return kind == Thread ; } 275 276 276 277 const Decl * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Init.hpp
r94647b0 r7770cc8 98 98 const_iterator begin() const { return initializers.begin(); } 99 99 const_iterator end() const { return initializers.end(); } 100 size_t size() const { return initializers.size(); } 100 101 101 102 const Init * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Pass.hpp
r94647b0 r7770cc8 109 109 static auto read( node_type const * node, Args&&... args ) { 110 110 Pass<core_t> visitor( std::forward<Args>( args )... ); 111 node_typeconst * temp = node->accept( visitor );111 auto const * temp = node->accept( visitor ); 112 112 assert( temp == node ); 113 113 return visitor.get_result(); … … 124 124 static auto read( node_type const * node ) { 125 125 Pass<core_t> visitor; 126 node_typeconst * temp = node->accept( visitor );126 auto const * temp = node->accept( visitor ); 127 127 assert( temp == node ); 128 128 return visitor.get_result(); … … 348 348 349 349 /// When this node is finished being visited, restore the value of a variable 350 /// You may assign to the return value to set the new value in the same statement. 350 351 template< typename T > 351 voidGuardValue( T& val ) {352 T& GuardValue( T& val ) { 352 353 at_cleanup( [ val ]( void * newVal ) { 353 354 * static_cast< T * >( newVal ) = val; 354 355 }, static_cast< void * >( & val ) ); 356 return val; 355 357 } 356 358 … … 394 396 }; 395 397 398 /// Used to get a pointer to the wrapping TranslationUnit. 399 struct WithConstTranslationUnit { 400 const TranslationUnit * translationUnit = nullptr; 401 402 const TranslationUnit & transUnit() const { 403 assertf( translationUnit, "WithConstTranslationUnit not set-up." ); 404 return *translationUnit; 405 } 406 }; 407 396 408 } 397 409 -
src/AST/Pass.impl.hpp
r94647b0 r7770cc8 420 420 template< typename core_t > 421 421 inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) { 422 return ast::accept_all( unit.decls, visitor ); 422 if ( auto ptr = __pass::translation_unit::get_cptr( visitor.core, 0 ) ) { 423 ValueGuard<const TranslationUnit *> guard( *ptr ); 424 *ptr = &unit; 425 return ast::accept_all( unit.decls, visitor ); 426 } else { 427 return ast::accept_all( unit.decls, visitor ); 428 } 423 429 } 424 430 -
src/AST/Pass.proto.hpp
r94647b0 r7770cc8 426 426 } // namespace forall 427 427 428 // For passes that need access to the global context. Sreaches `translationUnit` 429 namespace translation_unit { 430 template<typename core_t> 431 static inline auto get_cptr( core_t & core, int ) 432 -> decltype( &core.translationUnit ) { 433 return &core.translationUnit; 434 } 435 436 template<typename core_t> 437 static inline const TranslationUnit ** get_cptr( core_t &, long ) { 438 return nullptr; 439 } 440 } 441 428 442 template<typename core_t> 429 443 static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) { -
src/AST/Stmt.hpp
r94647b0 r7770cc8 175 175 class CaseStmt final : public Stmt { 176 176 public: 177 /// Null for the default label. 177 178 ptr<Expr> cond; 178 179 std::vector<ptr<Stmt>> stmts; -
src/AST/TranslationUnit.hpp
r94647b0 r7770cc8 26 26 std::list< ptr< Decl > > decls; 27 27 28 struct Global s{28 struct Global { 29 29 std::map< UniqueId, Decl * > idMap; 30 30 31 const Type *sizeType;31 ptr<Type> sizeType; 32 32 const FunctionDecl * dereference; 33 33 const StructDecl * dtorStruct; -
src/AST/module.mk
r94647b0 r7770cc8 24 24 AST/Convert.cpp \ 25 25 AST/Convert.hpp \ 26 AST/Copy.cpp \ 26 27 AST/Copy.hpp \ 27 28 AST/CVQualifiers.hpp \ -
src/AST/porting.md
r94647b0 r7770cc8 98 98 * `Initializer` => `ast::Init` 99 99 * `Statement` => `ast::Stmt` 100 * `ReferenceToType` => `ast::BaseInstType` 100 101 * any field names should follow a similar renaming 101 102 * because they don't really belong to `Type` (and for consistency with `Linkage::Spec`): -
src/CodeGen/FixMain.cc
r94647b0 r7770cc8 22 22 #include <string> // for operator<< 23 23 24 #include "AST/Decl.hpp" 25 #include "AST/Type.hpp" 26 #include "Common/PassVisitor.h" 24 27 #include "Common/SemanticError.h" // for SemanticError 25 28 #include "CodeGen/GenType.h" // for GenType … … 29 32 30 33 namespace CodeGen { 34 35 namespace { 36 37 struct FindMainCore { 38 FunctionDecl * main_signature = nullptr; 39 40 void previsit( FunctionDecl * decl ) { 41 if ( FixMain::isMain( decl ) ) { 42 if ( main_signature ) { 43 SemanticError( decl, "Multiple definition of main routine\n" ); 44 } 45 main_signature = decl; 46 } 47 } 48 }; 49 50 } 51 31 52 bool FixMain::replace_main = false; 32 std::unique_ptr<FunctionDecl> FixMain::main_signature = nullptr;33 53 34 54 template<typename container> … … 37 57 } 38 58 39 void FixMain::registerMain(FunctionDecl* functionDecl) 40 { 41 if(main_signature) { 42 SemanticError(functionDecl, "Multiple definition of main routine\n"); 43 } 44 main_signature.reset( functionDecl->clone() ); 45 } 59 void FixMain::fix( std::list< Declaration * > & translationUnit, 60 std::ostream &os, const char* bootloader_filename ) { 61 PassVisitor< FindMainCore > main_finder; 62 acceptAll( translationUnit, main_finder ); 63 FunctionDecl * main_signature = main_finder.pass.main_signature; 46 64 47 void FixMain::fix(std::ostream &os, const char* bootloader_filename) {48 65 if( main_signature ) { 49 66 os << "static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return "; 50 main_signature->mangleName = SymTab::Mangler::mangle(main_signature .get());67 main_signature->mangleName = SymTab::Mangler::mangle(main_signature); 51 68 52 69 os << main_signature->get_scopedMangleName() << "("; … … 65 82 } 66 83 } 84 85 namespace { 86 87 ObjectDecl * signedIntObj() { 88 return new ObjectDecl( 89 "", Type::StorageClasses(), LinkageSpec::Cforall, 0, 90 new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ); 91 } 92 93 ObjectDecl * charStarObj() { 94 return new ObjectDecl( 95 "", Type::StorageClasses(), LinkageSpec::Cforall, 0, 96 new PointerType( Type::Qualifiers(), 97 new PointerType( Type::Qualifiers(), 98 new BasicType( Type::Qualifiers(), BasicType::Char ) ) ), 99 nullptr ); 100 } 101 102 std::string create_mangled_main_function_name( FunctionType * function_type ) { 103 std::unique_ptr<FunctionDecl> decl( new FunctionDecl( 104 "main", Type::StorageClasses(), LinkageSpec::Cforall, 105 function_type, nullptr ) ); 106 return SymTab::Mangler::mangle( decl.get() ); 107 } 108 109 std::string mangled_0_argument_main() { 110 FunctionType* main_type = new FunctionType( Type::Qualifiers(), true ); 111 main_type->get_returnVals().push_back( signedIntObj() ); 112 return create_mangled_main_function_name( main_type ); 113 } 114 115 std::string mangled_2_argument_main() { 116 FunctionType* main_type = new FunctionType( Type::Qualifiers(), false ); 117 main_type->get_returnVals().push_back( signedIntObj() ); 118 main_type->get_parameters().push_back( signedIntObj() ); 119 main_type->get_parameters().push_back( charStarObj() ); 120 return create_mangled_main_function_name( main_type ); 121 } 122 123 bool is_main( const std::string & mangled_name ) { 124 // This breaks if you move it out of the function. 125 static const std::string mangled_mains[] = { 126 mangled_0_argument_main(), 127 mangled_2_argument_main(), 128 //mangled_3_argument_main(), 129 }; 130 131 for ( auto main_name : mangled_mains ) { 132 if ( main_name == mangled_name ) return true; 133 } 134 return false; 135 } 136 137 } // namespace 138 139 bool FixMain::isMain( FunctionDecl * decl ) { 140 if ( std::string("main") != decl->name ) { 141 return false; 142 } 143 return is_main( SymTab::Mangler::mangle( decl, true, true ) ); 144 } 145 146 bool FixMain::isMain( const ast::FunctionDecl * decl ) { 147 if ( std::string("main") != decl->name ) { 148 return false; 149 } 150 return is_main( Mangle::mangle( decl, Mangle::Type ) ); 151 } 152 67 153 }; -
src/CodeGen/FixMain.h
r94647b0 r7770cc8 9 9 // Author : Thierry Delisle 10 10 // Created On : Thr Jan 12 14:11:09 2017 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sun Feb 16 03:24:32 202013 // Update Count : 511 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Oct 29 16:20:00 2021 13 // Update Count : 8 14 14 // 15 15 … … 18 18 #include <iosfwd> 19 19 #include <memory> 20 #include <list> 20 21 21 22 #include "SynTree/LinkageSpec.h" 22 23 24 class Declaration; 23 25 class FunctionDecl; 26 namespace ast { 27 class FunctionDecl; 28 } 24 29 25 30 namespace CodeGen { 26 class FixMain {27 public :28 static inline LinkageSpec::Spec mainLinkage() {29 return replace_main ? LinkageSpec::Cforall : LinkageSpec::C;30 }31 32 static inline void setReplaceMain(bool val) {33 replace_main = val;34 }35 31 36 static void registerMain(FunctionDecl* val); 32 class FixMain { 33 public : 34 static inline LinkageSpec::Spec mainLinkage() { 35 return replace_main ? LinkageSpec::Cforall : LinkageSpec::C; 36 } 37 37 38 static void fix(std::ostream &os, const char* bootloader_filename); 38 static inline void setReplaceMain(bool val) { 39 replace_main = val; 40 } 39 41 40 private: 41 static bool replace_main; 42 static std::unique_ptr<FunctionDecl> main_signature; 43 }; 42 static bool isMain(FunctionDecl* decl); 43 static bool isMain(const ast::FunctionDecl * decl); 44 45 static void fix( std::list< Declaration * > & decls, 46 std::ostream &os, const char* bootloader_filename ); 47 48 private: 49 static bool replace_main; 50 }; 51 44 52 } // namespace CodeGen -
src/CodeGen/FixNames.cc
r94647b0 r7770cc8 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Dec 13 23:39:14 201913 // Update Count : 2 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Oct 29 15:49:00 2021 13 // Update Count : 23 14 14 // 15 15 … … 19 19 #include <string> // for string, operator!=, operator== 20 20 21 #include "AST/Chain.hpp" 22 #include "AST/Expr.hpp" 23 #include "AST/Pass.hpp" 21 24 #include "Common/PassVisitor.h" 22 25 #include "Common/SemanticError.h" // for SemanticError … … 46 49 }; 47 50 48 std::string mangle_main() {49 FunctionType* main_type;50 std::unique_ptr<FunctionDecl> mainDecl { new FunctionDecl( "main", Type::StorageClasses(), LinkageSpec::Cforall,51 main_type = new FunctionType( Type::Qualifiers(), true ), nullptr )52 };53 main_type->get_returnVals().push_back(54 new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr )55 );56 57 auto && name = SymTab::Mangler::mangle( mainDecl.get() );58 // std::cerr << name << std::endl;59 return std::move(name);60 }61 std::string mangle_main_args() {62 FunctionType* main_type;63 std::unique_ptr<FunctionDecl> mainDecl { new FunctionDecl( "main", Type::StorageClasses(), LinkageSpec::Cforall,64 main_type = new FunctionType( Type::Qualifiers(), false ), nullptr )65 };66 main_type->get_returnVals().push_back(67 new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr )68 );69 70 main_type->get_parameters().push_back(71 new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr )72 );73 74 main_type->get_parameters().push_back(75 new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, 0,76 new PointerType( Type::Qualifiers(), new PointerType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::Char ) ) ),77 nullptr )78 );79 80 auto&& name = SymTab::Mangler::mangle( mainDecl.get() );81 // std::cerr << name << std::endl;82 return std::move(name);83 }84 85 bool is_main(const std::string& name) {86 static std::string mains[] = {87 mangle_main(),88 mangle_main_args()89 };90 91 for(const auto& m : mains) {92 if( name == m ) return true;93 }94 return false;95 }96 97 51 void fixNames( std::list< Declaration* > & translationUnit ) { 98 52 PassVisitor<FixNames> fixer; … … 118 72 fixDWT( functionDecl ); 119 73 120 if (is_main( SymTab::Mangler::mangle(functionDecl, true, true) )) {74 if ( FixMain::isMain( functionDecl ) ) { 121 75 int nargs = functionDecl->get_functionType()->get_parameters().size(); 122 76 if( !(nargs == 0 || nargs == 2 || nargs == 3) ) { … … 124 78 } 125 79 functionDecl->get_statements()->get_kids().push_back( new ReturnStmt( new ConstantExpr( Constant::from_int( 0 ) ) ) ); 126 CodeGen::FixMain::registerMain( functionDecl );127 80 } 128 81 } … … 132 85 GuardAction( [this](){ scopeLevel--; } ); 133 86 } 87 88 /// Does work with the main function and scopeLevels. 89 class FixNames_new : public ast::WithGuards { 90 int scopeLevel = 1; 91 92 bool shouldSetScopeLevel( const ast::DeclWithType * dwt ) { 93 return !dwt->name.empty() && dwt->linkage.is_mangled 94 && dwt->scopeLevel != scopeLevel; 95 } 96 public: 97 const ast::ObjectDecl *postvisit( const ast::ObjectDecl *objectDecl ) { 98 if ( shouldSetScopeLevel( objectDecl ) ) { 99 return ast::mutate_field( objectDecl, &ast::ObjectDecl::scopeLevel, scopeLevel ); 100 } 101 return objectDecl; 102 } 103 104 const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) { 105 // This store is used to ensure a maximum of one call to mutate. 106 ast::FunctionDecl * mutDecl = nullptr; 107 108 if ( shouldSetScopeLevel( functionDecl ) ) { 109 mutDecl = ast::mutate( functionDecl ); 110 mutDecl->scopeLevel = scopeLevel; 111 } 112 113 if ( FixMain::isMain( functionDecl ) ) { 114 if ( !mutDecl ) { mutDecl = ast::mutate( functionDecl ); } 115 116 int nargs = mutDecl->params.size(); 117 if ( 0 != nargs && 2 != nargs && 3 != nargs ) { 118 SemanticError( functionDecl, "Main expected to have 0, 2 or 3 arguments\n" ); 119 } 120 ast::chain_mutate( mutDecl->stmts )->kids.push_back( 121 new ast::ReturnStmt( 122 mutDecl->location, 123 ast::ConstantExpr::from_int( mutDecl->location, 0 ) 124 ) 125 ); 126 } 127 return mutDecl ? mutDecl : functionDecl; 128 } 129 130 void previsit( const ast::CompoundStmt * ) { 131 GuardValue( scopeLevel ) += 1; 132 } 133 }; 134 135 void fixNames( ast::TranslationUnit & translationUnit ) { 136 ast::Pass<FixNames_new>::run( translationUnit ); 137 } 138 134 139 } // namespace CodeGen 135 140 -
src/CodeGen/FixNames.h
r94647b0 r7770cc8 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Jul 21 22:17:33 201713 // Update Count : 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 26 13:47:00 2021 13 // Update Count : 4 14 14 // 15 15 … … 19 19 20 20 class Declaration; 21 namespace ast { 22 struct TranslationUnit; 23 } 21 24 22 25 namespace CodeGen { 23 26 /// mangles object and function names 24 27 void fixNames( std::list< Declaration* > & translationUnit ); 28 void fixNames( ast::TranslationUnit & translationUnit ); 25 29 } // namespace CodeGen 26 30 -
src/CodeTools/DeclStats.cc
r94647b0 r7770cc8 156 156 /// number of counting bins for linkages 157 157 static const unsigned n_named_specs = 8; 158 /// map from total number of specs to bins 159 static const unsigned ind_for_linkage[16]; 158 /// Mapping function from linkage to bin. 159 static unsigned linkage_index( LinkageSpec::Spec spec ) { 160 switch ( spec ) { 161 case LinkageSpec::Intrinsic: return 0; 162 case LinkageSpec::C: return 1; 163 case LinkageSpec::Cforall: return 2; 164 case LinkageSpec::AutoGen: return 3; 165 case LinkageSpec::Compiler: return 4; 166 case LinkageSpec::BuiltinCFA: return 5; 167 case LinkageSpec::BuiltinC: return 6; 168 default: return 7; 169 } 170 } 160 171 161 172 Stats for_linkage[n_named_specs]; ///< Stores separate stats per linkage … … 366 377 const std::string& mangleName = decl->get_mangleName().empty() ? decl->name : decl->get_mangleName(); 367 378 if ( seen_names.insert( mangleName ).second ) { 368 Stats& stats = for_linkage[ ind_for_linkage[ decl->linkage ]];379 Stats& stats = for_linkage[ linkage_index( decl->linkage ) ]; 369 380 370 381 ++stats.n_decls; … … 527 538 }; 528 539 529 const unsigned DeclStats::ind_for_linkage[]530 = { 7, 7, 2, 1, 7, 7, 7, 3, 4, 7, 6, 5, 7, 7, 7, 0 };531 532 540 void printDeclStats( std::list< Declaration * > &translationUnit ) { 533 541 PassVisitor<DeclStats> stats; -
src/Common/module.mk
r94647b0 r7770cc8 22 22 Common/CompilerError.h \ 23 23 Common/Debug.h \ 24 Common/DeclStats.hpp \ 25 Common/DeclStats.cpp \ 24 26 Common/ErrorObjects.h \ 25 27 Common/Eval.cc \ … … 33 35 Common/PassVisitor.proto.h \ 34 36 Common/PersistentMap.h \ 37 Common/ResolvProtoDump.hpp \ 38 Common/ResolvProtoDump.cpp \ 35 39 Common/ScopedMap.h \ 36 40 Common/SemanticError.cc \ -
src/Concurrency/Keywords.cc
r94647b0 r7770cc8 979 979 // If this is the destructor for a monitor it must be mutex 980 980 if(isDtor) { 981 // This reflects MutexKeyword::validate, except does not produce an error. 981 982 Type* ty = decl->get_functionType()->get_parameters().front()->get_type(); 982 983 -
src/ControlStruct/ExceptTranslate.cc
r94647b0 r7770cc8 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Except Visitor.cc --7 // ExceptTranslate.cc -- Conversion of exception control flow structures. 8 8 // 9 9 // Author : Andrew Beach -
src/ControlStruct/ExceptTranslate.h
r94647b0 r7770cc8 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // ExceptTranslate.h -- 7 // ExceptTranslate.h -- Conversion of exception control flow structures. 8 8 // 9 9 // Author : Andrew Beach 10 10 // Created On : Tus Jun 06 10:13:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tus May 19 11:47:00 202013 // Update Count : 512 // Last Modified On : Mon Nov 8 11:43:00 2020 13 // Update Count : 6 14 14 // 15 15 … … 19 19 20 20 class Declaration; 21 namespace ast { 22 class TranslationUnit; 23 } 21 24 22 25 namespace ControlStruct { 23 26 void translateThrows( std::list< Declaration *> & translationUnit ); 27 void translateThrows( ast::TranslationUnit & transUnit ); 24 28 /* Replaces all throw & throwResume statements with function calls. 25 29 * These still need to be resolved, so call this before the reslover. -
src/ControlStruct/LabelGenerator.cc
r94647b0 r7770cc8 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Mar 11 22:23:20 201913 // Update Count : 1 511 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 8 10:18:00 2021 13 // Update Count : 17 14 14 // 15 15 … … 19 19 20 20 #include "LabelGenerator.h" 21 22 #include "AST/Attribute.hpp" 23 #include "AST/Label.hpp" 24 #include "AST/Stmt.hpp" 21 25 #include "SynTree/Attribute.h" // for Attribute 22 26 #include "SynTree/Label.h" // for Label, operator<< … … 24 28 25 29 namespace ControlStruct { 26 LabelGenerator * LabelGenerator::labelGenerator = 0; 30 31 int LabelGenerator::current = 0; 32 LabelGenerator * LabelGenerator::labelGenerator = nullptr; 27 33 28 34 LabelGenerator * LabelGenerator::getGenerator() { … … 43 49 return l; 44 50 } 51 52 ast::Label LabelGenerator::newLabel( 53 const std::string & suffix, const ast::Stmt * stmt ) { 54 assert( stmt ); 55 56 std::ostringstream os; 57 os << "__L" << current++ << "__" << suffix; 58 if ( stmt && !stmt->labels.empty() ) { 59 os << "_" << stmt->labels.front() << "__"; 60 } 61 ast::Label ret_label( stmt->location, os.str() ); 62 ret_label.attributes.push_back( new ast::Attribute( "unused" ) ); 63 return ret_label; 64 } 65 45 66 } // namespace ControlStruct 46 67 -
src/ControlStruct/LabelGenerator.h
r94647b0 r7770cc8 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:20:14 201713 // Update Count : 611 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Nov 8 10:16:00 2021 13 // Update Count : 8 14 14 // 15 15 … … 21 21 22 22 class Statement; 23 namespace ast { 24 class Stmt; 25 class Label; 26 } 23 27 24 28 namespace ControlStruct { 25 class LabelGenerator { 26 public: 27 static LabelGenerator *getGenerator(); 28 Label newLabel(std::string suffix, Statement * stmt = nullptr); 29 void reset() { current = 0; } 30 void rewind() { current--; } 31 protected: 32 LabelGenerator(): current(0) {} 33 private: 34 int current; 35 static LabelGenerator *labelGenerator; 36 }; 29 30 class LabelGenerator { 31 static int current; 32 static LabelGenerator *labelGenerator; 33 protected: 34 LabelGenerator() {} 35 public: 36 static LabelGenerator *getGenerator(); 37 static Label newLabel(std::string suffix, Statement * stmt = nullptr); 38 static ast::Label newLabel( const std::string&, const ast::Stmt * ); 39 static void reset() { current = 0; } 40 static void rewind() { current--; } 41 }; 42 37 43 } // namespace ControlStruct 38 44 -
src/ControlStruct/module.mk
r94647b0 r7770cc8 18 18 ControlStruct/ExceptDecl.cc \ 19 19 ControlStruct/ExceptDecl.h \ 20 ControlStruct/FixLabels.cpp \ 21 ControlStruct/FixLabels.hpp \ 20 22 ControlStruct/ForExprMutator.cc \ 21 23 ControlStruct/ForExprMutator.h \ … … 26 28 ControlStruct/MLEMutator.cc \ 27 29 ControlStruct/MLEMutator.h \ 30 ControlStruct/MultiLevelExit.cpp \ 31 ControlStruct/MultiLevelExit.hpp \ 28 32 ControlStruct/Mutate.cc \ 29 33 ControlStruct/Mutate.h 30 34 31 SRC += $(SRC_CONTROLSTRUCT) ControlStruct/ExceptTranslate.cc ControlStruct/ExceptTranslate.h 35 SRC += $(SRC_CONTROLSTRUCT) \ 36 ControlStruct/ExceptTranslateNew.cpp \ 37 ControlStruct/ExceptTranslate.cc \ 38 ControlStruct/ExceptTranslate.h 39 32 40 SRCDEMANGLE += $(SRC_CONTROLSTRUCT) 33 41 -
src/InitTweak/FixInitNew.cpp
r94647b0 r7770cc8 591 591 // need to add __Destructor for _tmp_cp variables as well 592 592 593 assertf( ast::dtorStruct && ast::dtorStruct->members.size() == 2, "Destructor generation requires __Destructor definition." ); 593 assertf( ast::dtorStruct, "Destructor generation requires __Destructor definition." ); 594 assertf( ast::dtorStruct->members.size() == 2, "__Destructor definition does not have expected fields." ); 594 595 assertf( ast::dtorStructDestroy, "Destructor generation requires __destroy_Destructor." ); 595 596 … … 1216 1217 1217 1218 static UniqueName memberDtorNamer = { "__memberDtor" }; 1218 assertf( Validate::dtorStruct, "builtin __Destructor not found." );1219 assertf( Validate::dtorStructDestroy, "builtin __destroy_Destructor not found." );1219 assertf( ast::dtorStruct, "builtin __Destructor not found." ); 1220 assertf( ast::dtorStructDestroy, "builtin __destroy_Destructor not found." ); 1220 1221 1221 1222 ast::Expr * thisExpr = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, thisParam ) ), new ast::PointerType( new ast::VoidType(), ast::CV::Qualifiers() ) ); -
src/InitTweak/GenInit.cc
r94647b0 r7770cc8 9 9 // Author : Rob Schluntz 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Dec 13 23:15:10 201913 // Update Count : 18 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Oct 25 13:53:00 2021 13 // Update Count : 186 14 14 // 15 15 #include "GenInit.h" … … 24 24 #include "AST/Decl.hpp" 25 25 #include "AST/Init.hpp" 26 #include "AST/Pass.hpp" 26 27 #include "AST/Node.hpp" 27 28 #include "AST/Stmt.hpp" … … 294 295 } 295 296 297 namespace { 298 299 # warning Remove the _New suffix after the conversion is complete. 300 struct HoistArrayDimension_NoResolve_New final : 301 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting, 302 public ast::WithGuards, public ast::WithConstTranslationUnit, 303 public ast::WithVisitorRef<HoistArrayDimension_NoResolve_New> { 304 void previsit( const ast::ObjectDecl * decl ); 305 const ast::DeclWithType * postvisit( const ast::ObjectDecl * decl ); 306 // Do not look for objects inside there declarations (and type). 307 void previsit( const ast::AggregateDecl * ) { visit_children = false; } 308 void previsit( const ast::NamedTypeDecl * ) { visit_children = false; } 309 void previsit( const ast::FunctionType * ) { visit_children = false; } 310 311 const ast::Type * hoist( const ast::Type * type ); 312 313 ast::Storage::Classes storageClasses; 314 }; 315 316 void HoistArrayDimension_NoResolve_New::previsit( 317 const ast::ObjectDecl * decl ) { 318 GuardValue( storageClasses ) = decl->storage; 319 } 320 321 const ast::DeclWithType * HoistArrayDimension_NoResolve_New::postvisit( 322 const ast::ObjectDecl * objectDecl ) { 323 return mutate_field( objectDecl, &ast::ObjectDecl::type, 324 hoist( objectDecl->type ) ); 325 } 326 327 const ast::Type * HoistArrayDimension_NoResolve_New::hoist( 328 const ast::Type * type ) { 329 static UniqueName dimensionName( "_array_dim" ); 330 331 if ( !isInFunction() || storageClasses.is_static ) { 332 return type; 333 } 334 335 if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) { 336 if ( nullptr == arrayType->dimension ) { 337 return type; 338 } 339 340 if ( !Tuples::maybeImpure( arrayType->dimension ) ) { 341 return type; 342 } 343 344 ast::ptr<ast::Type> dimType = transUnit().global.sizeType; 345 assert( dimType ); 346 add_qualifiers( dimType, ast::CV::Qualifiers( ast::CV::Const ) ); 347 348 ast::ObjectDecl * arrayDimension = new ast::ObjectDecl( 349 arrayType->dimension->location, 350 dimensionName.newName(), 351 dimType, 352 new ast::SingleInit( 353 arrayType->dimension->location, 354 arrayType->dimension 355 ) 356 ); 357 358 ast::ArrayType * mutType = ast::mutate( arrayType ); 359 mutType->dimension = new ast::VariableExpr( 360 arrayDimension->location, arrayDimension ); 361 declsToAddBefore.push_back( arrayDimension ); 362 363 mutType->base = hoist( mutType->base ); 364 return mutType; 365 } 366 return type; 367 } 368 369 struct ReturnFixer_New final : 370 public ast::WithStmtsToAdd<>, ast::WithGuards { 371 void previsit( const ast::FunctionDecl * decl ); 372 const ast::ReturnStmt * previsit( const ast::ReturnStmt * stmt ); 373 private: 374 const ast::FunctionDecl * funcDecl = nullptr; 375 }; 376 377 void ReturnFixer_New::previsit( const ast::FunctionDecl * decl ) { 378 GuardValue( funcDecl ) = decl; 379 } 380 381 const ast::ReturnStmt * ReturnFixer_New::previsit( 382 const ast::ReturnStmt * stmt ) { 383 auto & returns = funcDecl->returns; 384 assert( returns.size() < 2 ); 385 // Hands off if the function returns a reference. 386 // Don't allocate a temporary if the address is returned. 387 if ( stmt->expr && 1 == returns.size() ) { 388 ast::ptr<ast::DeclWithType> retDecl = returns.front(); 389 if ( isConstructable( retDecl->get_type() ) ) { 390 // Explicitly construct the return value using the return 391 // expression and the retVal object. 392 assertf( "" != retDecl->name, 393 "Function %s has unnamed return value.\n", 394 funcDecl->name.c_str() ); 395 396 auto retVal = retDecl.strict_as<ast::ObjectDecl>(); 397 if ( auto varExpr = stmt->expr.as<ast::VariableExpr>() ) { 398 // Check if the return statement is already set up. 399 if ( varExpr->var == retVal ) return stmt; 400 } 401 ast::ptr<ast::Stmt> ctorStmt = genCtorDtor( 402 retVal->location, "?{}", retVal, stmt->expr ); 403 assertf( ctorStmt, 404 "ReturnFixer: genCtorDtor returned nllptr: %s / %s", 405 toString( retVal ).c_str(), 406 toString( stmt->expr ).c_str() ); 407 stmtsToAddBefore.push_back( ctorStmt ); 408 409 // Return the retVal object. 410 ast::ReturnStmt * mutStmt = ast::mutate( stmt ); 411 mutStmt->expr = new ast::VariableExpr( 412 stmt->location, retDecl ); 413 return mutStmt; 414 } 415 } 416 return stmt; 417 } 418 419 } // namespace 420 421 void genInit( ast::TranslationUnit & transUnit ) { 422 ast::Pass<HoistArrayDimension_NoResolve_New>::run( transUnit ); 423 ast::Pass<ReturnFixer_New>::run( transUnit ); 424 } 425 296 426 void CtorDtor::generateCtorDtor( std::list< Declaration * > & translationUnit ) { 297 427 PassVisitor<CtorDtor> ctordtor; -
src/InitTweak/GenInit.h
r94647b0 r7770cc8 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sat Jul 22 09:31:19 201713 // Update Count : 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Oct 22 16:08:00 2021 13 // Update Count : 6 14 14 // 15 15 … … 27 27 /// Adds return value temporaries and wraps Initializers in ConstructorInit nodes 28 28 void genInit( std::list< Declaration * > & translationUnit ); 29 void genInit( ast::TranslationUnit & translationUnit ); 29 30 30 31 /// Converts return statements into copy constructor calls on the hidden return variable -
src/InitTweak/InitTweak.cc
r94647b0 r7770cc8 9 9 // Author : Rob Schluntz 10 10 // Created On : Fri May 13 11:26:36 2016 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Wed Jun 16 20:57:22202113 // Update Count : 1 811 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Nov 19 19:22:00 2021 13 // Update Count : 19 14 14 // 15 15 … … 540 540 } 541 541 542 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ) { 543 assertf( ftype, "getTypeofThis: nullptr ftype" ); 544 const std::vector<ast::ptr<ast::Type>> & params = ftype->params; 545 assertf( !params.empty(), "getTypeofThis: ftype with 0 parameters: %s", 546 toString( ftype ).c_str() ); 547 const ast::ReferenceType * refType = 548 params.front().strict_as<ast::ReferenceType>(); 549 return refType->base; 550 } 551 542 552 ObjectDecl * getParamThis( FunctionType * ftype ) { 543 553 assertf( ftype, "getParamThis: nullptr ftype" ); -
src/InitTweak/InitTweak.h
r94647b0 r7770cc8 10 10 // Created On : Fri May 13 11:26:36 2016 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Jul 19 14:18:00 201913 // Update Count : 612 // Last Modified On : Fri Nov 19 14:18:00 2021 13 // Update Count : 7 14 14 // 15 15 … … 35 35 /// returns the base type of the first parameter to a constructor/destructor/assignment function 36 36 Type * getTypeofThis( FunctionType * ftype ); 37 const ast::Type * getTypeofThis( const ast::FunctionType * ftype ); 37 38 38 39 /// returns the first parameter of a constructor/destructor/assignment function -
src/Parser/parser.yy
r94647b0 r7770cc8 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Sep 11 08:20:44202113 // Update Count : 5 04012 // Last Modified On : Fri Oct 15 09:20:17 2021 13 // Update Count : 5163 14 14 // 15 15 … … 31 31 // from ANSI90 to ANSI11 C are marked with the comment "C99/C11". 32 32 33 // This grammar also has two levels of extensions. The first extensions cover most of the GCC C extensions All of the33 // This grammar also has two levels of extensions. The first extensions cover most of the GCC C extensions. All of the 34 34 // syntactic extensions for GCC C are marked with the comment "GCC". The second extensions are for Cforall (CFA), which 35 35 // fixes several of C's outstanding problems and extends C with many modern language concepts. All of the syntactic … … 69 69 // 2. String encodings are transformed into canonical form (one encoding at start) so the encoding can be found 70 70 // without searching the string, e.g.: "abc" L"def" L"ghi" => L"abc" "def" "ghi". Multiple encodings must match, 71 // i.e., u"a" U"b" L"c" is disallowed.71 // e.g., u"a" U"b" L"c" is disallowed. 72 72 73 73 if ( from[0] != '"' ) { // encoding ? … … 310 310 %token ATassign // @= 311 311 312 %type<tok> identifier 313 %type<tok> identifier_or_type_name attr_name 312 %type<tok> identifier identifier_at identifier_or_type_name attr_name 314 313 %type<tok> quasi_keyword 315 314 %type<constant> string_literal … … 327 326 %type<en> conditional_expression constant_expression assignment_expression assignment_expression_opt 328 327 %type<en> comma_expression comma_expression_opt 329 %type<en> argument_expression_list_opt argument_expression default_initializer_opt328 %type<en> argument_expression_list_opt argument_expression_list argument_expression default_initializer_opt 330 329 %type<ifctl> if_control_expression 331 330 %type<fctl> for_control_expression for_control_expression_list … … 559 558 IDENTIFIER 560 559 | quasi_keyword 560 ; 561 562 identifier_at: 563 identifier 561 564 | '@' // CFA 562 565 { Token tok = { new string( DeclarationNode::anonymous.newName() ), yylval.tok.loc }; $$ = tok; } … … 693 696 // empty 694 697 { $$ = nullptr; } 695 | argument_expression 698 | argument_expression_list 699 ; 700 701 argument_expression_list: 702 argument_expression 696 703 | argument_expression_list_opt ',' argument_expression 697 704 { $$ = (ExpressionNode *)($1->set_last( $3 )); } … … 731 738 | FLOATINGconstant fraction_constants_opt 732 739 { $$ = new ExpressionNode( build_field_name_fraction_constants( build_field_name_FLOATINGconstant( *$1 ), $2 ) ); } 733 | identifier fraction_constants_opt740 | identifier_at fraction_constants_opt // CFA, allow anonymous fields 734 741 { 735 742 $$ = new ExpressionNode( build_field_name_fraction_constants( build_varref( $1 ), $2 ) ); … … 1084 1091 comma_expression_opt ';' 1085 1092 { $$ = new StatementNode( build_expr( $1 ) ); } 1093 | MUTEX '(' ')' comma_expression ';' 1094 { $$ = new StatementNode( build_mutex( nullptr, new StatementNode( build_expr( $4 ) ) ) ); } 1095 // { SemanticError( yylloc, "Mutex expression is currently unimplemented." ); $$ = nullptr; } 1086 1096 ; 1087 1097 … … 1182 1192 1183 1193 iteration_statement: 1184 WHILE '(' push if_control_expression ')' statement pop 1185 { $$ = new StatementNode( build_while( $4, maybe_build_compound( $6 ) ) ); } 1186 | WHILE '(' ')' statement // CFA => while ( 1 ) 1194 WHILE '(' ')' statement // CFA => while ( 1 ) 1187 1195 { $$ = new StatementNode( build_while( new IfCtrl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); } 1188 | DO statement WHILE '(' comma_expression ')' ';' 1189 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); } 1196 | WHILE '(' if_control_expression ')' statement %prec THEN 1197 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); } 1198 | WHILE '(' if_control_expression ')' statement ELSE statement // CFA 1199 { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; } 1190 1200 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) 1191 1201 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); } 1192 | FOR '(' push for_control_expression_list ')' statement pop 1193 { $$ = new StatementNode( build_for( $4, maybe_build_compound( $6 ) ) ); } 1202 | DO statement WHILE '(' comma_expression ')' ';' %prec THEN 1203 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); } 1204 | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA 1205 { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; } 1194 1206 | FOR '(' ')' statement // CFA => for ( ;; ) 1195 1207 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); } 1208 | FOR '(' for_control_expression_list ')' statement %prec THEN 1209 { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); } 1210 | FOR '(' for_control_expression_list ')' statement ELSE statement // CFA 1211 { SemanticError( yylloc, "Loop default block is currently unimplemented." ); $$ = nullptr; } 1196 1212 ; 1197 1213 … … 1339 1355 with_statement: 1340 1356 WITH '(' tuple_expression_list ')' statement 1341 { 1342 $$ = new StatementNode( build_with( $3, $5 ) ); 1343 } 1357 { $$ = new StatementNode( build_with( $3, $5 ) ); } 1344 1358 ; 1345 1359 1346 1360 // If MUTEX becomes a general qualifier, there are shift/reduce conflicts, so change syntax to "with mutex". 1347 1361 mutex_statement: 1348 MUTEX '(' argument_expression_list _opt')' statement1362 MUTEX '(' argument_expression_list ')' statement 1349 1363 { $$ = new StatementNode( build_mutex( $3, $5 ) ); } 1350 1364 ; … … 2475 2489 designation: 2476 2490 designator_list ':' // C99, CFA uses ":" instead of "=" 2477 | identifier ':' // GCC, field name2491 | identifier_at ':' // GCC, field name 2478 2492 { $$ = new ExpressionNode( build_varref( $1 ) ); } 2479 2493 ; … … 2487 2501 2488 2502 designator: 2489 '.' identifier 2503 '.' identifier_at // C99, field name 2490 2504 { $$ = new ExpressionNode( build_varref( $2 ) ); } 2491 2505 | '[' push assignment_expression pop ']' // C99, single array element … … 2919 2933 2920 2934 paren_identifier: 2921 identifier 2935 identifier_at 2922 2936 { $$ = DeclarationNode::newName( $1 ); } 2923 2937 | '(' paren_identifier ')' // redundant parenthesis -
src/ResolvExpr/module.mk
r94647b0 r7770cc8 61 61 ResolvExpr/WidenMode.h 62 62 63 SRC += $(SRC_RESOLVEXPR) \ 64 ResolvExpr/AlternativePrinter.cc \ 65 ResolvExpr/AlternativePrinter.h \ 66 ResolvExpr/CandidatePrinter.cpp \ 67 ResolvExpr/CandidatePrinter.hpp 63 68 64 SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc ResolvExpr/AlternativePrinter.h65 69 SRCDEMANGLE += $(SRC_RESOLVEXPR) -
src/SymTab/Validate.cc
r94647b0 r7770cc8 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:50:04 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Dec 13 23:43:34 201913 // Update Count : 36 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Nov 12 11:00:00 2021 13 // Update Count : 364 14 14 // 15 15 … … 334 334 }; 335 335 336 void validate ( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug) {336 void validate_A( std::list< Declaration * > & translationUnit ) { 337 337 PassVisitor<EnumAndPointerDecay_old> epc; 338 PassVisitor<LinkReferenceToTypes_old> lrt( nullptr );339 PassVisitor<ResolveEnumInitializers> rei( nullptr );340 PassVisitor<ForallPointerDecay_old> fpd;341 PassVisitor<CompoundLiteral> compoundliteral;342 PassVisitor<ValidateGenericParameters> genericParams;343 PassVisitor<LabelAddressFixer> labelAddrFixer;344 338 PassVisitor<HoistTypeDecls> hoistDecls; 345 PassVisitor<FixQualifiedTypes> fixQual;346 347 339 { 348 340 Stats::Heap::newPass("validate-A"); … … 354 346 acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling 355 347 } 348 } 349 350 void validate_B( std::list< Declaration * > & translationUnit ) { 351 PassVisitor<LinkReferenceToTypes_old> lrt( nullptr ); 352 PassVisitor<FixQualifiedTypes> fixQual; 356 353 { 357 354 Stats::Heap::newPass("validate-B"); … … 362 359 EliminateTypedef::eliminateTypedef( translationUnit ); 363 360 } 361 } 362 363 void validate_C( std::list< Declaration * > & translationUnit ) { 364 PassVisitor<ValidateGenericParameters> genericParams; 365 PassVisitor<ResolveEnumInitializers> rei( nullptr ); 364 366 { 365 367 Stats::Heap::newPass("validate-C"); … … 381 383 }); 382 384 } 385 } 386 387 void validate_D( std::list< Declaration * > & translationUnit ) { 388 PassVisitor<ForallPointerDecay_old> fpd; 383 389 { 384 390 Stats::Heap::newPass("validate-D"); … … 397 403 }); 398 404 } 405 } 406 407 void validate_E( std::list< Declaration * > & translationUnit ) { 408 PassVisitor<CompoundLiteral> compoundliteral; 399 409 { 400 410 Stats::Heap::newPass("validate-E"); … … 415 425 } 416 426 } 427 } 428 429 void validate_F( std::list< Declaration * > & translationUnit ) { 430 PassVisitor<LabelAddressFixer> labelAddrFixer; 417 431 { 418 432 Stats::Heap::newPass("validate-F"); … … 437 451 } 438 452 } 453 } 454 455 void validate( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug ) { 456 validate_A( translationUnit ); 457 validate_B( translationUnit ); 458 validate_C( translationUnit ); 459 validate_D( translationUnit ); 460 validate_E( translationUnit ); 461 validate_F( translationUnit ); 439 462 } 440 463 -
src/SymTab/Validate.h
r94647b0 r7770cc8 35 35 void validateType( Type *type, const Indexer *indexer ); 36 36 37 // Sub-passes of validate. 38 void validate_A( std::list< Declaration * > &translationUnit ); 39 void validate_B( std::list< Declaration * > &translationUnit ); 40 void validate_C( std::list< Declaration * > &translationUnit ); 41 void validate_D( std::list< Declaration * > &translationUnit ); 42 void validate_E( std::list< Declaration * > &translationUnit ); 43 void validate_F( std::list< Declaration * > &translationUnit ); 44 37 45 const ast::Type * validateType( 38 46 const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ); -
src/Tuples/TupleExpansionNew.cpp
r94647b0 r7770cc8 21 21 void previsit( const ast::UntypedMemberExpr * ) { visit_children = false; } 22 22 const ast::Expr * postvisit( const ast::UntypedMemberExpr * memberExpr ); 23 }; 24 struct UniqueExprExpander final : public ast::WithDeclsToAdd<> { 25 const ast::Expr * postvisit( const ast::UniqueExpr * unqExpr ); 26 std::map< int, ast::ptr<ast::Expr> > decls; // not vector, because order added may not be increasing order 23 27 }; 24 28 } // namespace … … 66 70 } 67 71 } // namespace 72 73 void expandUniqueExpr( ast::TranslationUnit & translationUnit ) { 74 ast::Pass< UniqueExprExpander >::run( translationUnit ); 75 } 76 77 namespace { 78 const ast::Expr * UniqueExprExpander::postvisit( const ast::UniqueExpr * unqExpr ) { 79 const CodeLocation loc = unqExpr->location; 80 const int id = unqExpr->id; 81 82 // on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID, 83 // and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable. 84 if ( ! decls.count( id ) ) { 85 ast::ptr< ast::Expr > assignUnq; 86 const ast::VariableExpr * var = unqExpr->var; 87 if ( unqExpr->object ) { 88 // an object was generated to represent this unique expression -- it should be added to the list of declarations now 89 declsToAddBefore.push_back( unqExpr->object.as< ast::Decl >() ); 90 // deep copy required due to unresolved issues with UniqueExpr 91 assignUnq = ast::UntypedExpr::createAssign( loc, var, unqExpr->expr ); 92 } else { 93 const auto commaExpr = unqExpr->expr.strict_as< ast::CommaExpr >(); 94 assignUnq = commaExpr->arg1; 95 } 96 auto finished = new ast::ObjectDecl( loc, toString( "_unq", id, "_finished_" ), new ast::BasicType( ast::BasicType::Kind::Bool ), 97 new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) ), {}, ast::Linkage::Cforall ); 98 declsToAddBefore.push_back( finished ); 99 // (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N)) 100 // This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code. 101 auto assignFinished = ast::UntypedExpr::createAssign( loc, new ast::VariableExpr( loc, finished ), 102 ast::ConstantExpr::from_int( loc, 1 ) ); 103 auto condExpr = new ast::ConditionalExpr( loc, new ast::VariableExpr( loc, finished ), var, 104 new ast::CommaExpr( loc, new ast::CommaExpr( loc, assignUnq, assignFinished ), var ) ); 105 condExpr->result = var->result; 106 condExpr->env = unqExpr->env; 107 decls[id] = condExpr; 108 } 109 //delete unqExpr; 110 return ast::deepCopy(decls[id].get()); 111 } 112 } // namespace 68 113 } // namespace Tuples -
src/Tuples/Tuples.h
r94647b0 r7770cc8 46 46 /// replaces UniqueExprs with a temporary variable and one call 47 47 void expandUniqueExpr( std::list< Declaration * > & translationUnit ); 48 void expandUniqueExpr( ast::TranslationUnit & translationUnit ); 48 49 49 50 /// returns VoidType if any of the expressions have Voidtype, otherwise TupleType of the Expression result types -
src/Validate/FindSpecialDecls.h
r94647b0 r7770cc8 9 9 // Author : Rob Schluntz 10 10 // Created On : Thu Aug 30 09:49:02 2018 11 // Last Modified By : Rob Schluntz12 // Last Modified On : Thu Aug 30 09:51:12 201813 // Update Count : 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Nov 10 15:16:00 2021 13 // Update Count : 3 14 14 // 15 15 … … 22 22 class StructDecl; 23 23 class Type; 24 25 namespace ast { 26 class TranslationUnit; 27 } 24 28 25 29 namespace Validate { … … 38 42 /// find and remember some of the special declarations that are useful for generating code, so that they do not have to be discovered multiple times. 39 43 void findSpecialDecls( std::list< Declaration * > & translationUnit ); 44 45 /// find and remember some of the special declarations that are useful for 46 /// generating code, so that they do not have to be discovered multiple times. 47 void findGlobalDecls( ast::TranslationUnit & translationUnit ); 48 40 49 } // namespace Validate 41 50 -
src/Validate/module.mk
r94647b0 r7770cc8 15 15 ############################################################################### 16 16 17 SRC += Validate/HandleAttributes.cc Validate/HandleAttributes.h Validate/FindSpecialDecls.cc Validate/FindSpecialDecls.h 18 SRCDEMANGLE += Validate/HandleAttributes.cc Validate/HandleAttributes.h Validate/FindSpecialDecls.cc Validate/FindSpecialDecls.h 17 SRC_VALIDATE = \ 18 Validate/HandleAttributes.cc \ 19 Validate/HandleAttributes.h \ 20 Validate/InitializerLength.cpp \ 21 Validate/InitializerLength.hpp \ 22 Validate/LabelAddressFixer.cpp \ 23 Validate/LabelAddressFixer.hpp \ 24 Validate/FindSpecialDeclsNew.cpp \ 25 Validate/FindSpecialDecls.cc \ 26 Validate/FindSpecialDecls.h 27 28 SRC += $(SRC_VALIDATE) 29 SRCDEMANGLE += $(SRC_VALIDATE) -
src/main.cc
r94647b0 r7770cc8 9 9 // Author : Peter Buhr and Rob Schluntz 10 10 // Created On : Fri May 15 23:12:02 2015 11 // Last Modified By : Henry Xue12 // Last Modified On : Mon Aug 23 15:42:08202113 // Update Count : 65 011 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Nov 12 11:06:00 2021 13 // Update Count : 658 14 14 // 15 15 … … 43 43 #include "Common/CodeLocationTools.hpp" // for forceFillCodeLocations 44 44 #include "Common/CompilerError.h" // for CompilerError 45 #include "Common/DeclStats.hpp" // for printDeclStats 46 #include "Common/ResolvProtoDump.hpp" // for dumpAsResolverProto 45 47 #include "Common/Stats.h" 46 48 #include "Common/PassVisitor.h" … … 51 53 #include "ControlStruct/ExceptDecl.h" // for translateExcept 52 54 #include "ControlStruct/ExceptTranslate.h" // for translateEHM 55 #include "ControlStruct/FixLabels.hpp" // for fixLabels 53 56 #include "ControlStruct/Mutate.h" // for mutate 54 57 #include "GenPoly/Box.h" // for box … … 62 65 #include "Parser/TypedefTable.h" // for TypedefTable 63 66 #include "ResolvExpr/AlternativePrinter.h" // for AlternativePrinter 67 #include "ResolvExpr/CandidatePrinter.hpp" // for printCandidates 64 68 #include "ResolvExpr/Resolver.h" // for resolve 65 69 #include "SymTab/Validate.h" // for validate … … 68 72 #include "SynTree/Visitor.h" // for acceptAll 69 73 #include "Tuples/Tuples.h" // for expandMemberTuples, expan... 74 #include "Validate/FindSpecialDecls.h" // for findGlobalDecls 75 #include "Validate/InitializerLength.hpp" // for setLengthFromInitializer 76 #include "Validate/LabelAddressFixer.hpp" // for fixLabelAddresses 70 77 #include "Virtual/ExpandCasts.h" // for expandCasts 71 78 … … 314 321 315 322 // add the assignment statement after the initialization of a type parameter 316 PASS( "Validate", SymTab::validate( translationUnit, symtabp ) ); 317 if ( symtabp ) { 318 deleteAll( translationUnit ); 319 return EXIT_SUCCESS; 320 } // if 321 322 if ( expraltp ) { 323 PassVisitor<ResolvExpr::AlternativePrinter> printer( cout ); 324 acceptAll( translationUnit, printer ); 325 return EXIT_SUCCESS; 326 } // if 327 328 if ( validp ) { 329 dump( translationUnit ); 330 return EXIT_SUCCESS; 331 } // if 332 333 PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) ); 334 PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) ); 335 PASS( "Fix Names", CodeGen::fixNames( translationUnit ) ); 336 PASS( "Gen Init", InitTweak::genInit( translationUnit ) ); 337 338 if ( libcfap ) { 339 // generate the bodies of cfa library functions 340 LibCfa::makeLibCfa( translationUnit ); 341 } // if 342 343 if ( declstatsp ) { 344 CodeTools::printDeclStats( translationUnit ); 345 deleteAll( translationUnit ); 346 return EXIT_SUCCESS; 347 } // if 348 349 if ( bresolvep ) { 350 dump( translationUnit ); 351 return EXIT_SUCCESS; 352 } // if 323 PASS( "Validate-A", SymTab::validate_A( translationUnit ) ); 324 PASS( "Validate-B", SymTab::validate_B( translationUnit ) ); 325 PASS( "Validate-C", SymTab::validate_C( translationUnit ) ); 326 PASS( "Validate-D", SymTab::validate_D( translationUnit ) ); 327 PASS( "Validate-E", SymTab::validate_E( translationUnit ) ); 353 328 354 329 CodeTools::fillLocations( translationUnit ); 355 356 if ( resolvprotop ) {357 CodeTools::dumpAsResolvProto( translationUnit );358 return EXIT_SUCCESS;359 } // if360 330 361 331 if( useNewAST ) { … … 366 336 auto transUnit = convert( move( translationUnit ) ); 367 337 338 forceFillCodeLocations( transUnit ); 339 340 PASS( "Set Length From Initializer", Validate::setLengthFromInitializer( transUnit ) ); 341 PASS( "Find Global Decls", Validate::findGlobalDecls( transUnit ) ); 342 PASS( "Fix Label Address", Validate::fixLabelAddresses( transUnit ) ); 343 344 if ( symtabp ) { 345 return EXIT_SUCCESS; 346 } // if 347 348 if ( expraltp ) { 349 ResolvExpr::printCandidates( transUnit ); 350 return EXIT_SUCCESS; 351 } // if 352 353 if ( validp ) { 354 dump( move( transUnit ) ); 355 return EXIT_SUCCESS; 356 } // if 357 358 PASS( "Translate Throws", ControlStruct::translateThrows( transUnit ) ); 359 PASS( "Fix Labels", ControlStruct::fixLabels( transUnit ) ); 360 PASS( "Fix Names", CodeGen::fixNames( transUnit ) ); 361 PASS( "Gen Init", InitTweak::genInit( transUnit ) ); 368 362 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) ); 369 363 364 if ( libcfap ) { 365 // Generate the bodies of cfa library functions. 366 LibCfa::makeLibCfa( transUnit ); 367 } // if 368 369 if ( declstatsp ) { 370 printDeclStats( transUnit ); 371 return EXIT_SUCCESS; 372 } // if 373 374 if ( bresolvep ) { 375 dump( move( transUnit ) ); 376 return EXIT_SUCCESS; 377 } // if 378 379 if ( resolvprotop ) { 380 dumpAsResolverProto( transUnit ); 381 return EXIT_SUCCESS; 382 } // if 383 370 384 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 371 385 if ( exprp ) { … … 377 391 378 392 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary())); 393 394 // fix ObjectDecl - replaces ConstructorInit nodes 395 if ( ctorinitp ) { 396 dump( move( transUnit ) ); 397 return EXIT_SUCCESS; 398 } // if 399 400 // Currently not working due to unresolved issues with UniqueExpr 401 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( transUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused 379 402 translationUnit = convert( move( transUnit ) ); 380 403 } else { 404 PASS( "Validate-F", SymTab::validate_F( translationUnit ) ); 405 406 if ( symtabp ) { 407 deleteAll( translationUnit ); 408 return EXIT_SUCCESS; 409 } // if 410 411 if ( expraltp ) { 412 PassVisitor<ResolvExpr::AlternativePrinter> printer( cout ); 413 acceptAll( translationUnit, printer ); 414 return EXIT_SUCCESS; 415 } // if 416 417 if ( validp ) { 418 dump( translationUnit ); 419 return EXIT_SUCCESS; 420 } // if 421 422 PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) ); 423 PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) ); 424 PASS( "Fix Names", CodeGen::fixNames( translationUnit ) ); 425 PASS( "Gen Init", InitTweak::genInit( translationUnit ) ); 381 426 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( translationUnit ) ); 427 428 if ( libcfap ) { 429 // Generate the bodies of cfa library functions. 430 LibCfa::makeLibCfa( translationUnit ); 431 } // if 432 433 if ( declstatsp ) { 434 CodeTools::printDeclStats( translationUnit ); 435 deleteAll( translationUnit ); 436 return EXIT_SUCCESS; 437 } // if 438 439 if ( bresolvep ) { 440 dump( translationUnit ); 441 return EXIT_SUCCESS; 442 } // if 443 444 CodeTools::fillLocations( translationUnit ); 445 446 if ( resolvprotop ) { 447 CodeTools::dumpAsResolvProto( translationUnit ); 448 return EXIT_SUCCESS; 449 } // if 382 450 383 451 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); … … 388 456 389 457 PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) ); 458 459 // fix ObjectDecl - replaces ConstructorInit nodes 460 if ( ctorinitp ) { 461 dump ( translationUnit ); 462 return EXIT_SUCCESS; 463 } // if 464 465 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused 390 466 } 391 392 // fix ObjectDecl - replaces ConstructorInit nodes393 if ( ctorinitp ) {394 dump ( translationUnit );395 return EXIT_SUCCESS;396 } // if397 398 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused399 467 400 468 PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) ); … … 443 511 PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) ); 444 512 445 CodeGen::FixMain::fix( *output, (PreludeDirector + "/bootloader.c").c_str() ); 513 CodeGen::FixMain::fix( translationUnit, *output, 514 (PreludeDirector + "/bootloader.c").c_str() ); 446 515 if ( output != &cout ) { 447 516 delete output; -
tests/.expect/declarationSpecifier.x64.txt
r94647b0 r7770cc8 1132 1132 char **_X13cfa_args_argvPPc_1; 1133 1133 char **_X13cfa_args_envpPPc_1; 1134 signed int _X17cfa_main_returnedi_1 = ((signed int )0);1134 __attribute__ ((weak)) extern signed int _X17cfa_main_returnedi_1; 1135 1135 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){ 1136 1136 __attribute__ ((unused)) signed int _X12_retval_maini_1; … … 1149 1149 signed int _tmp_cp_ret6; 1150 1150 signed int _X3reti_2 = (((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6); 1151 { 1152 ((void)(_X17cfa_main_returnedi_1=((signed int )1))); 1151 if ( ((&_X17cfa_main_returnedi_1)!=((signed int *)0)) ) { 1152 { 1153 ((void)(_X17cfa_main_returnedi_1=((signed int )1))); 1154 } 1155 1153 1156 } 1154 1157 -
tests/.expect/declarationSpecifier.x86.txt
r94647b0 r7770cc8 1132 1132 char **_X13cfa_args_argvPPc_1; 1133 1133 char **_X13cfa_args_envpPPc_1; 1134 signed int _X17cfa_main_returnedi_1 = ((signed int )0);1134 __attribute__ ((weak)) extern signed int _X17cfa_main_returnedi_1; 1135 1135 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){