Changes in / [feacef9:5407cdc]
- Files:
-
- 110 added
- 49 deleted
- 183 edited
Legend:
- Unmodified
- Added
- Removed
-
Jenkins/FullBuild
rfeacef9 r5407cdc 18 18 19 19 parallel ( 20 gcc_8_x86_old: { trigger_build( 'gcc-8', 'x86', false ) }, 21 gcc_7_x86_old: { trigger_build( 'gcc-7', 'x86', false ) }, 22 gcc_6_x86_old: { trigger_build( 'gcc-6', 'x86', false ) }, 23 gcc_9_x64_old: { trigger_build( 'gcc-9', 'x64', false ) }, 24 gcc_8_x64_old: { trigger_build( 'gcc-8', 'x64', false ) }, 25 gcc_7_x64_old: { trigger_build( 'gcc-7', 'x64', false ) }, 26 gcc_6_x64_old: { trigger_build( 'gcc-6', 'x64', false ) }, 27 gcc_5_x64_old: { trigger_build( 'gcc-5', 'x64', false ) }, 20 gcc_8_x86_new: { trigger_build( 'gcc-8', 'x86', true ) }, 21 gcc_7_x86_new: { trigger_build( 'gcc-7', 'x86', true ) }, 22 gcc_6_x86_new: { trigger_build( 'gcc-6', 'x86', true ) }, 23 gcc_9_x64_new: { trigger_build( 'gcc-9', 'x64', true ) }, 24 gcc_8_x64_new: { trigger_build( 'gcc-8', 'x64', true ) }, 25 gcc_7_x64_new: { trigger_build( 'gcc-7', 'x64', true ) }, 26 gcc_6_x64_new: { trigger_build( 'gcc-6', 'x64', true ) }, 27 gcc_5_x64_new: { trigger_build( 'gcc-5', 'x64', true ) }, 28 clang_x64_new: { trigger_build( 'clang', 'x64', true ) }, 28 29 clang_x64_old: { trigger_build( 'clang', 'x64', false ) }, 29 clang_x64_new: { trigger_build( 'clang', 'x64', true ) },30 30 ) 31 31 } … … 66 66 67 67 def trigger_build(String cc, String arch, boolean new_ast) { 68 // Randomly delay the builds by a random amount to avoid hitting the SC server to hard 69 sleep(time: 5 * Math.random(), unit:"MINUTES") 70 71 // Run the build 72 // Don't propagate, it doesn't play nice with our email setup 68 73 def result = build job: 'Cforall/master', \ 69 74 parameters: [ \ -
Jenkinsfile
rfeacef9 r5407cdc 148 148 def test() { 149 149 try { 150 // Print potential limits before testing 151 // in case jenkins messes with them 152 sh 'free -h' 153 sh 'ulimit -a' 154 150 155 Tools.BuildStage('Test: short', !Settings.RunAllTests) { 151 156 dir (BuildDir) { -
benchmark/Makefile.am
rfeacef9 r5407cdc 502 502 503 503 compile-io$(EXEEXT): 504 $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/io 1.cfa504 $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/io/io.cfa 505 505 506 506 compile-monitor$(EXEEXT): -
benchmark/basic/ttst_lock.c
rfeacef9 r5407cdc 9 9 #define CALIGN __attribute__(( aligned (CACHE_ALIGN) )) 10 10 #define CACHE_ALIGN 128 11 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 11 #if defined( __i386 ) || defined( __x86_64 ) 12 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 13 #elif defined( __ARM_ARCH ) 14 #define Pause() __asm__ __volatile__ ( "YIELD" : : : ) 15 #else 16 #error unsupported architecture 17 #endif 12 18 13 19 typedef uintptr_t TYPE; // addressable word-size -
benchmark/benchcltr.hfa
rfeacef9 r5407cdc 114 114 for() { 115 115 sleep(100`ms); 116 end = getTimeNsec();116 end = timeHiRes(); 117 117 Duration delta = end - start; 118 118 /*if(is_tty)*/ { … … 126 126 } 127 127 #else 128 uint64_t getTimeNsec() {128 uint64_t timeHiRes() { 129 129 timespec curr; 130 130 clock_gettime( CLOCK_REALTIME, &curr ); … … 140 140 for(;;) { 141 141 usleep(100000); 142 end = getTimeNsec();142 end = timeHiRes(); 143 143 uint64_t delta = end - start; 144 144 /*if(is_tty)*/ { -
benchmark/io/http/http_ring.cpp
rfeacef9 r5407cdc 20 20 socklen_t *addrlen; 21 21 int flags; 22 unsigned cnt; 22 23 } acpt; 23 24 … … 67 68 thread_local stats_block_t stats; 68 69 stats_block_t global_stats; 70 71 thread_local struct __attribute__((aligned(128))) { 72 size_t to_submit = 0; 73 } local; 69 74 70 75 // Get an array of current connections … … 192 197 static void submit(struct io_uring * ring, struct io_uring_sqe * sqe, connection * conn) { 193 198 (void)ring; 199 local.to_submit++; 194 200 #ifdef USE_ASYNC 195 201 io_uring_sqe_set_flags(sqe, IOSQE_ASYNC); … … 406 412 switch(state) { 407 413 case ACCEPTING: 408 connection::accept(ring, opt);414 // connection::accept(ring, opt); 409 415 newconn(ring, res); 410 416 break; … … 420 426 421 427 //========================================================= 428 extern "C" { 429 #include <sys/eventfd.h> // use for termination 430 } 431 422 432 // Main loop of the WebServer 423 433 // Effectively uses one thread_local copy of everything per kernel thread … … 427 437 struct io_uring * ring = opt.ring; 428 438 439 int blockfd = eventfd(0, 0); 440 if (blockfd < 0) { 441 fprintf( stderr, "eventfd create error: (%d) %s\n", (int)errno, strerror(errno) ); 442 exit(EXIT_FAILURE); 443 } 444 445 int ret = io_uring_register_eventfd(ring, blockfd); 446 if (ret < 0) { 447 fprintf( stderr, "io_uring S&W error: (%d) %s\n", (int)-ret, strerror(-ret) ); 448 exit(EXIT_FAILURE); 449 } 450 429 451 // Track the shutdown using a event_fd 430 452 char endfd_buf[8]; … … 433 455 // Accept our first connection 434 456 // May not take effect until io_uring_submit_and_wait 435 connection::accept(ring, opt); 457 for(unsigned i = 0; i < opt.acpt.cnt; i++) { 458 connection::accept(ring, opt); 459 } 436 460 437 461 int reset = 1; // Counter to print stats once in a while … … 441 465 while(!done) { 442 466 // Submit all the answers we have and wait for responses 443 int ret = io_uring_submit_and_wait(ring, 1); 467 int ret = io_uring_submit(ring); 468 local.to_submit = 0; 444 469 445 470 // check errors … … 452 477 sqes += ret; 453 478 call++; 479 480 481 eventfd_t val; 482 ret = eventfd_read(blockfd, &val); 483 484 // check errors 485 if (ret < 0) { 486 fprintf( stderr, "eventfd read error: (%d) %s\n", (int)errno, strerror(errno) ); 487 exit(EXIT_FAILURE); 488 } 454 489 455 490 struct io_uring_cqe *cqe; … … 463 498 break; 464 499 } 500 501 if(local.to_submit > 30) break; 465 502 466 503 auto req = (class connection *)cqe->user_data; … … 509 546 #include <pthread.h> // for pthreads 510 547 #include <signal.h> // for signal(SIGPIPE, SIG_IGN); 511 #include <sys/eventfd.h> // use for termination512 548 #include <sys/socket.h> // for sockets in general 513 549 #include <netinet/in.h> // for sockaddr_in, AF_INET … … 528 564 unsigned entries = 256; // number of entries per ring/kernel thread 529 565 unsigned backlog = 262144; // backlog argument to listen 566 unsigned preaccept = 1; // start by accepting X per threads 530 567 bool attach = false; // Whether or not to attach all the rings 531 568 bool sqpoll = false; // Whether or not to use SQ Polling … … 534 571 // Arguments Parsing 535 572 int c; 536 while ((c = getopt (argc, argv, "t:p:e:b: aS")) != -1) {573 while ((c = getopt (argc, argv, "t:p:e:b:c:aS")) != -1) { 537 574 switch (c) 538 575 { … … 548 585 case 'b': 549 586 backlog = atoi(optarg); 587 break; 588 case 'c': 589 preaccept = atoi(optarg); 550 590 break; 551 591 case 'a': … … 681 721 thrd_opts[i].acpt.addrlen = (socklen_t*)&addrlen; 682 722 thrd_opts[i].acpt.flags = 0; 723 thrd_opts[i].acpt.cnt = preaccept; 683 724 thrd_opts[i].endfd = efd; 684 725 thrd_opts[i].ring = &thrd_rings[i].storage; -
benchmark/io/http/main.cfa
rfeacef9 r5407cdc 29 29 30 30 //============================================================================================= 31 // Globals32 //=============================================================================================33 struct ServerProc {34 processor self;35 };36 37 void ?{}( ServerProc & this ) {38 /* paranoid */ assert( options.clopts.instance != 0p );39 (this.self){ "Benchmark Processor", *options.clopts.instance };40 41 #if !defined(__CFA_NO_STATISTICS__)42 if( options.clopts.procstats ) {43 print_stats_at_exit( this.self, options.clopts.instance->print_stats );44 }45 if( options.clopts.viewhalts ) {46 print_halts( this.self );47 }48 #endif49 }50 51 extern void init_protocol(void);52 extern void deinit_protocol(void);53 54 //=============================================================================================55 31 // Stats Printer 56 32 //=============================================================================================' … … 58 34 thread StatsPrinter {}; 59 35 60 void ?{}( StatsPrinter & this ) { 61 ((thread&)this){ "Stats Printer Thread" }; 62 } 36 void ?{}( StatsPrinter & this, cluster & cl ) { 37 ((thread&)this){ "Stats Printer Thread", cl }; 38 } 39 40 void ^?{}( StatsPrinter & mutex this ) {} 63 41 64 42 void main(StatsPrinter & this) { … … 71 49 sleep(10`s); 72 50 73 print_stats_now( *options.clopts.instance, CFA_STATS_READY_Q | CFA_STATS_IO ); 74 } 75 } 51 print_stats_now( *active_cluster(), CFA_STATS_READY_Q | CFA_STATS_IO ); 52 } 53 } 54 55 //============================================================================================= 56 // Globals 57 //============================================================================================= 58 struct ServerCluster { 59 cluster self; 60 processor * procs; 61 // io_context * ctxs; 62 StatsPrinter * prnt; 63 64 }; 65 66 void ?{}( ServerCluster & this ) { 67 (this.self){ "Server Cluster", options.clopts.params }; 68 69 this.procs = alloc(options.clopts.nprocs); 70 for(i; options.clopts.nprocs) { 71 (this.procs[i]){ "Benchmark Processor", this.self }; 72 73 #if !defined(__CFA_NO_STATISTICS__) 74 if( options.clopts.procstats ) { 75 print_stats_at_exit( *this.procs, this.self.print_stats ); 76 } 77 if( options.clopts.viewhalts ) { 78 print_halts( *this.procs ); 79 } 80 #endif 81 } 82 83 if(options.stats) { 84 this.prnt = alloc(); 85 (*this.prnt){ this.self }; 86 } else { 87 this.prnt = 0p; 88 } 89 90 #if !defined(__CFA_NO_STATISTICS__) 91 print_stats_at_exit( this.self, CFA_STATS_READY_Q | CFA_STATS_IO ); 92 #endif 93 94 options.clopts.instance[options.clopts.cltr_cnt] = &this.self; 95 options.clopts.cltr_cnt++; 96 } 97 98 void ^?{}( ServerCluster & this ) { 99 delete(this.prnt); 100 101 for(i; options.clopts.nprocs) { 102 ^(this.procs[i]){}; 103 } 104 free(this.procs); 105 106 ^(this.self){}; 107 } 108 109 extern void init_protocol(void); 110 extern void deinit_protocol(void); 76 111 77 112 //============================================================================================= … … 137 172 // Run Server Cluster 138 173 { 139 cluster cl = { "Server Cluster", options.clopts.params };140 #if !defined(__CFA_NO_STATISTICS__)141 print_stats_at_exit( cl, CFA_STATS_READY_Q | CFA_STATS_IO );142 #endif143 options.clopts.instance = &cl;144 145 146 174 int pipe_cnt = options.clopts.nworkers * 2; 147 175 int pipe_off; … … 153 181 } 154 182 155 if(options.file_cache.path && options.file_cache.fixed_fds) {156 register_fixed_files(cl, fds, pipe_off);157 }183 // if(options.file_cache.path && options.file_cache.fixed_fds) { 184 // register_fixed_files(cl, fds, pipe_off); 185 // } 158 186 159 187 { 160 ServerProc procs[options.clopts.nprocs]; 161 StatsPrinter printer; 188 ServerCluster cl[options.clopts.nclusters]; 162 189 163 190 init_protocol(); … … 180 207 unpark( workers[i] ); 181 208 } 182 sout | options.clopts.nworkers | "workers started on" | options.clopts.nprocs | "processors"; 209 sout | options.clopts.nworkers | "workers started on" | options.clopts.nprocs | "processors /" | options.clopts.nclusters | "clusters"; 210 for(i; options.clopts.nclusters) { 211 sout | options.clopts.thrd_cnt[i] | nonl; 212 } 213 sout | nl; 183 214 { 184 215 char buffer[128]; 185 while(int ret = cfa_read(0, buffer, 128, 0, -1`s, 0p, 0p); ret != 0) { 216 for() { 217 int ret = cfa_read(0, buffer, 128, 0); 218 if(ret == 0) break; 186 219 if(ret < 0) abort( "main read error: (%d) %s\n", (int)errno, strerror(errno) ); 220 sout | "User wrote '" | "" | nonl; 221 write(sout, buffer, ret - 1); 222 sout | "'"; 187 223 } 188 224 … … 193 229 for(i; options.clopts.nworkers) { 194 230 workers[i].done = true; 195 cancel(workers[i].cancel);196 231 } 197 232 sout | "done"; … … 221 256 sout | "done"; 222 257 223 sout | "Stopping processors ..." | nonl; flush( sout );258 sout | "Stopping processors/clusters..." | nonl; flush( sout ); 224 259 } 225 260 sout | "done"; -
benchmark/io/http/options.cfa
rfeacef9 r5407cdc 13 13 #include <kernel.hfa> 14 14 #include <parseargs.hfa> 15 #include <stdlib.hfa> 15 16 16 17 #include <stdlib.h> … … 19 20 Options options @= { 20 21 false, // log 22 false, // stats 21 23 22 24 { // file_cache … … 36 38 37 39 { // cluster 40 1, // nclusters; 38 41 1, // nprocs; 39 42 1, // nworkers; … … 46 49 47 50 void parse_options( int argc, char * argv[] ) { 48 bool subthrd = false; 49 bool eagrsub = false; 50 bool fixedfd = false; 51 bool sqkpoll = false; 52 bool iokpoll = false; 53 unsigned sublen = 16; 51 // bool fixedfd = false; 52 // bool sqkpoll = false; 53 // bool iokpoll = false; 54 54 unsigned nentries = 16; 55 bool isolate = false; 55 56 56 57 … … 59 60 { 'c', "cpus", "Number of processors to use", options.clopts.nprocs}, 60 61 { 't', "threads", "Number of worker threads to use", options.clopts.nworkers}, 62 {'\0', "isolate", "Create one cluster per processor", isolate, parse_settrue}, 61 63 {'\0', "log", "Enable logs", options.log, parse_settrue}, 64 {'\0', "stats", "Enable statistics", options.stats, parse_settrue}, 62 65 {'\0', "accept-backlog", "Maximum number of pending accepts", options.socket.backlog}, 63 66 {'\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}, … … 65 68 {'\0', "cache-size", "Size of the cache to use, if set to small, will uses closes power of 2", options.file_cache.size }, 66 69 {'\0', "list-files", "List the files in the specified path and exit", options.file_cache.list, parse_settrue }, 67 { 's', "submitthread", "If set, cluster uses polling thread to submit I/O", subthrd, parse_settrue }, 68 { 'e', "eagersubmit", "If set, cluster submits I/O eagerly but still aggregates submits", eagrsub, parse_settrue}, 69 { 'f', "fixed-fds", "If set, files are open eagerly and pre-registered with the cluster", fixedfd, parse_settrue}, 70 { 'k', "kpollsubmit", "If set, cluster uses IORING_SETUP_SQPOLL, implies -f", sqkpoll, parse_settrue }, 71 { 'i', "kpollcomplete", "If set, cluster uses IORING_SETUP_IOPOLL", iokpoll, parse_settrue }, 72 {'\0', "submitlength", "Max number of submitions that can be submitted together", sublen }, 73 {'\0', "numentries", "Number of I/O entries", nentries }, 70 // { 'f', "fixed-fds", "If set, files are open eagerly and pre-registered with the cluster", fixedfd, parse_settrue}, 71 // { 'k', "kpollsubmit", "If set, cluster uses IORING_SETUP_SQPOLL, implies -f", sqkpoll, parse_settrue }, 72 // { 'i', "kpollcomplete", "If set, cluster uses IORING_SETUP_IOPOLL", iokpoll, parse_settrue }, 73 {'e', "numentries", "Number of I/O entries", nentries }, 74 74 75 75 }; … … 91 91 nentries = v; 92 92 } 93 if(isolate) { 94 options.clopts.nclusters = options.clopts.nprocs; 95 options.clopts.nprocs = 1; 96 } 93 97 options.clopts.params.num_entries = nentries; 94 95 options.clopts.params.poller_submits = subthrd; 96 options.clopts.params.eager_submits = eagrsub; 97 98 if( fixedfd ) { 99 options.file_cache.fixed_fds = true; 98 options.clopts.instance = alloc(options.clopts.nclusters); 99 options.clopts.thrd_cnt = alloc(options.clopts.nclusters); 100 options.clopts.cltr_cnt = 0; 101 for(i; options.clopts.nclusters) { 102 options.clopts.thrd_cnt[i] = 0; 100 103 } 101 104 102 if( sqkpoll ) {103 options.clopts.params.poll_submit = true;104 options.file_cache.fixed_fds = true;105 }106 105 107 if( iokpoll ) { 108 options.clopts.params.poll_complete = true; 109 options.file_cache.open_flags |= O_DIRECT; 110 } 106 // if( fixedfd ) { 107 // options.file_cache.fixed_fds = true; 108 // } 111 109 112 options.clopts.params.num_ready = sublen; 110 // if( sqkpoll ) { 111 // options.file_cache.fixed_fds = true; 112 // } 113 114 // if( iokpoll ) { 115 // options.file_cache.open_flags |= O_DIRECT; 116 // } 113 117 114 118 if( left[0] == 0p ) { return; } -
benchmark/io/http/options.hfa
rfeacef9 r5407cdc 9 9 struct Options { 10 10 bool log; 11 bool stats; 11 12 12 13 struct { … … 26 27 27 28 struct { 29 int nclusters; 28 30 int nprocs; 29 31 int nworkers; … … 31 33 bool procstats; 32 34 bool viewhalts; 33 cluster * instance; 35 cluster ** instance; 36 size_t * thrd_cnt; 37 size_t cltr_cnt; 34 38 } clopts; 35 39 }; -
benchmark/io/http/protocol.cfa
rfeacef9 r5407cdc 5 5 #include <fcntl.h> 6 6 } 7 8 #define xstr(s) str(s) 9 #define str(s) #s 7 10 8 11 #include <fstream.hfa> … … 20 23 #include "options.hfa" 21 24 22 const char * volatile date = 0p; 23 24 const char * http_msgs[] = { 25 "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: %zu \n\n", 26 "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 27 "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 28 "HTTP/1.1 405 Method Not Allowed\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 29 "HTTP/1.1 408 Request Timeout\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 30 "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 31 "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 32 }; 25 #define PLAINTEXT_1WRITE 26 #define PLAINTEXT_MEMCPY 27 #define PLAINTEXT_NOCOPY 28 29 struct https_msg_str { 30 char msg[512]; 31 size_t len; 32 }; 33 34 const https_msg_str * volatile http_msgs[KNOWN_CODES] = { 0 }; 33 35 34 36 _Static_assert( KNOWN_CODES == (sizeof(http_msgs ) / sizeof(http_msgs [0]))); 35 37 36 const int http_codes[] = { 38 const int http_codes[KNOWN_CODES] = { 39 200, 37 40 200, 38 41 400, … … 53 56 while(len > 0) { 54 57 // Call write 55 int ret = cfa_write(fd, it, len, 0, -1`s, 0p, 0p); 56 // int ret = write(fd, it, len); 58 int ret = cfa_send(fd, it, len, 0, CFA_IO_LAZY); 57 59 if( ret < 0 ) { 58 60 if( errno == ECONNRESET || errno == EPIPE ) return -ECONNRESET; … … 72 74 /* paranoid */ assert( code < KNOWN_CODES && code != OK200 ); 73 75 int idx = (int)code; 74 return answer( fd, http_msgs[idx] , strlen( http_msgs[idx] ));76 return answer( fd, http_msgs[idx]->msg, http_msgs[idx]->len ); 75 77 } 76 78 77 79 int answer_header( int fd, size_t size ) { 78 const char * fmt = http_msgs[OK200]; 79 int len = 200; 80 char buffer[len]; 81 len = snprintf(buffer, len, fmt, date, size); 80 char buffer[512]; 81 char * it = buffer; 82 memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len); 83 it += http_msgs[OK200]->len; 84 int len = http_msgs[OK200]->len; 85 len += snprintf(it, 512 - len, "%d \n\n", size); 82 86 return answer( fd, buffer, len ); 83 87 } 84 88 85 int answer_plain( int fd, char buffer[], size_t size ) { 86 int ret = answer_header(fd, size); 89 #if defined(PLAINTEXT_NOCOPY) 90 int answer_plaintext( int fd ) { 91 return answer(fd, http_msgs[OK200_PlainText]->msg, http_msgs[OK200_PlainText]->len); // +1 cause snprintf doesn't count nullterminator 92 } 93 #elif defined(PLAINTEXT_MEMCPY) 94 #define TEXTSIZE 15 95 int answer_plaintext( int fd ) { 96 char text[] = "Hello, World!\n\n"; 97 char ts[] = xstr(TEXTSIZE) " \n\n"; 98 _Static_assert(sizeof(text) - 1 == TEXTSIZE); 99 char buffer[512 + TEXTSIZE]; 100 char * it = buffer; 101 memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len); 102 it += http_msgs[OK200]->len; 103 int len = http_msgs[OK200]->len; 104 memcpy(it, ts, sizeof(ts) - 1); 105 it += sizeof(ts) - 1; 106 len += sizeof(ts) - 1; 107 memcpy(it, text, TEXTSIZE); 108 return answer(fd, buffer, len + TEXTSIZE); 109 } 110 #elif defined(PLAINTEXT_1WRITE) 111 int answer_plaintext( int fd ) { 112 char text[] = "Hello, World!\n\n"; 113 char buffer[512 + sizeof(text)]; 114 char * it = buffer; 115 memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len); 116 it += http_msgs[OK200]->len; 117 int len = http_msgs[OK200]->len; 118 int r = snprintf(it, 512 - len, "%d \n\n", sizeof(text)); 119 it += r; 120 len += r; 121 memcpy(it, text, sizeof(text)); 122 return answer(fd, buffer, len + sizeof(text)); 123 } 124 #else 125 int answer_plaintext( int fd ) { 126 char text[] = "Hello, World!\n\n"; 127 int ret = answer_header(fd, sizeof(text)); 87 128 if( ret < 0 ) return ret; 88 return answer(fd, buffer, size); 89 } 129 return answer(fd, text, sizeof(text)); 130 } 131 #endif 90 132 91 133 int answer_empty( int fd ) { … … 94 136 95 137 96 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len , io_cancellation * cancel) {138 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len) { 97 139 char * it = buffer; 98 140 size_t count = len - 1; … … 100 142 READ: 101 143 for() { 102 int ret = cfa_re ad(fd, (void*)it, count, 0, -1`s, cancel, 0p);144 int ret = cfa_recv(fd, (void*)it, count, 0, CFA_IO_LAZY); 103 145 // int ret = read(fd, (void*)it, count); 104 146 if(ret == 0 ) return [OK200, true, 0, 0]; … … 139 181 ssize_t ret; 140 182 SPLICE1: while(count > 0) { 141 ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, sflags, 0, -1`s, 0p, 0p); 142 // ret = splice(ans_fd, &offset, pipe[1], 0p, count, sflags); 183 ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, sflags, CFA_IO_LAZY); 143 184 if( ret < 0 ) { 144 185 if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE1; … … 152 193 size_t in_pipe = ret; 153 194 SPLICE2: while(in_pipe > 0) { 154 ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, sflags, 0, -1`s, 0p, 0p); 155 // ret = splice(pipe[0], 0p, fd, 0p, in_pipe, sflags); 195 ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, sflags, CFA_IO_LAZY); 156 196 if( ret < 0 ) { 157 197 if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE2; … … 173 213 #include <thread.hfa> 174 214 215 const char * original_http_msgs[] = { 216 "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: ", 217 "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 15\n\nHello, World!\n\n", 218 "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 219 "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 220 "HTTP/1.1 405 Method Not Allowed\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 221 "HTTP/1.1 408 Request Timeout\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 222 "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 223 "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n", 224 }; 225 175 226 struct date_buffer { 176 char buff[100];227 https_msg_str strs[KNOWN_CODES]; 177 228 }; 178 229 … … 183 234 184 235 void ?{}( DateFormater & this ) { 185 ((thread&)this){ "Server Date Thread", *options.clopts.instance };236 ((thread&)this){ "Server Date Thread", *options.clopts.instance[0] }; 186 237 this.idx = 0; 187 memset( this.buffers[0].buff, 0, sizeof(this.buffers[0]) );188 memset( this.buffers[1].buff, 0, sizeof(this.buffers[1]) );238 memset( &this.buffers[0], 0, sizeof(this.buffers[0]) ); 239 memset( &this.buffers[1], 0, sizeof(this.buffers[1]) ); 189 240 } 190 241 … … 196 247 or else {} 197 248 198 Time now = getTimeNsec(); 199 200 strftime( this.buffers[this.idx].buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now ); 201 202 char * next = this.buffers[this.idx].buff; 203 __atomic_exchange_n((char * volatile *)&date, next, __ATOMIC_SEQ_CST); 249 250 char buff[100]; 251 Time now = timeHiRes(); 252 strftime( buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now ); 253 sout | "Updated date to '" | buff | "'"; 254 255 for(i; KNOWN_CODES) { 256 size_t len = snprintf( this.buffers[this.idx].strs[i].msg, 512, original_http_msgs[i], buff ); 257 this.buffers[this.idx].strs[i].len = len; 258 } 259 260 for(i; KNOWN_CODES) { 261 https_msg_str * next = &this.buffers[this.idx].strs[i]; 262 __atomic_exchange_n((https_msg_str * volatile *)&http_msgs[i], next, __ATOMIC_SEQ_CST); 263 } 204 264 this.idx = (this.idx + 1) % 2; 265 266 sout | "Date thread sleeping"; 205 267 206 268 sleep(1`s); -
benchmark/io/http/protocol.hfa
rfeacef9 r5407cdc 1 1 #pragma once 2 3 struct io_cancellation;4 2 5 3 enum HttpCode { 6 4 OK200 = 0, 5 OK200_PlainText, 7 6 E400, 8 7 E404, … … 18 17 int answer_error( int fd, HttpCode code ); 19 18 int answer_header( int fd, size_t size ); 20 int answer_plain ( int fd, char buffer [], size_t size);19 int answer_plaintext( int fd ); 21 20 int answer_empty( int fd ); 22 21 23 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len , io_cancellation *);22 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len); 24 23 25 24 int sendfile( int pipe[2], int fd, int ans_fd, size_t count ); -
benchmark/io/http/worker.cfa
rfeacef9 r5407cdc 17 17 //============================================================================================= 18 18 void ?{}( Worker & this ) { 19 ((thread&)this){ "Server Worker Thread", *options.clopts.instance }; 19 size_t cli = rand() % options.clopts.cltr_cnt; 20 ((thread&)this){ "Server Worker Thread", *options.clopts.instance[cli], 512000 }; 21 options.clopts.thrd_cnt[cli]++; 20 22 this.pipe[0] = -1; 21 23 this.pipe[1] = -1; … … 35 37 for() { 36 38 if( options.log ) sout | "=== Accepting connection ==="; 37 int fd = cfa_accept4( this.[sockfd, addr, addrlen, flags], 0, -1`s, &this.cancel, 0p ); 38 // int fd = accept4( this.[sockfd, addr, addrlen, flags] ); 39 int fd = cfa_accept4( this.[sockfd, addr, addrlen, flags], CFA_IO_LAZY ); 39 40 if(fd < 0) { 40 41 if( errno == ECONNABORTED ) break; … … 42 43 abort( "accept error: (%d) %s\n", (int)errno, strerror(errno) ); 43 44 } 45 if(this.done) break; 44 46 45 47 if( options.log ) sout | "=== New connection" | fd | "" | ", waiting for requests ==="; … … 55 57 char buffer[len]; 56 58 if( options.log ) sout | "=== Reading request ==="; 57 [code, closed, file, name_size] = http_read(fd, buffer, len , &this.cancel);59 [code, closed, file, name_size] = http_read(fd, buffer, len); 58 60 59 61 // if we are done, break out of the loop … … 70 72 if( options.log ) sout | "=== Request for /plaintext ==="; 71 73 72 char text[] = "Hello, World!\n"; 73 74 // Send the header 75 int ret = answer_plain(fd, text, sizeof(text)); 74 int ret = answer_plaintext(fd); 76 75 if( ret == -ECONNRESET ) break REQUEST; 77 76 -
benchmark/io/http/worker.hfa
rfeacef9 r5407cdc 17 17 socklen_t * addrlen; 18 18 int flags; 19 io_cancellation cancel;20 19 volatile bool done; 21 20 }; -
benchmark/io/readv-posix.c
rfeacef9 r5407cdc 111 111 printf("Starting\n"); 112 112 bool is_tty = isatty(STDOUT_FILENO); 113 start = getTimeNsec();113 start = timeHiRes(); 114 114 run = true; 115 115 … … 118 118 119 119 run = false; 120 end = getTimeNsec();120 end = timeHiRes(); 121 121 printf("\nDone\n"); 122 122 -
benchmark/io/readv.cfa
rfeacef9 r5407cdc 147 147 printf("Starting\n"); 148 148 bool is_tty = isatty(STDOUT_FILENO); 149 start = getTimeNsec();149 start = timeHiRes(); 150 150 run = true; 151 151 … … 156 156 157 157 run = false; 158 end = getTimeNsec();158 end = timeHiRes(); 159 159 printf("\nDone\n"); 160 160 } -
benchmark/readyQ/cycle.cc
rfeacef9 r5407cdc 89 89 90 90 bool is_tty = isatty(STDOUT_FILENO); 91 start = getTimeNsec();91 start = timeHiRes(); 92 92 93 93 for(int i = 0; i < nthreads; i++) { … … 97 97 98 98 stop = true; 99 end = getTimeNsec();99 end = timeHiRes(); 100 100 printf("\nDone\n"); 101 101 -
benchmark/readyQ/cycle.cfa
rfeacef9 r5407cdc 65 65 66 66 bool is_tty = isatty(STDOUT_FILENO); 67 start = getTimeNsec();67 start = timeHiRes(); 68 68 69 69 for(i; nthreads) { … … 73 73 74 74 stop = true; 75 end = getTimeNsec();75 end = timeHiRes(); 76 76 printf("\nDone\n"); 77 77 -
benchmark/readyQ/cycle.cpp
rfeacef9 r5407cdc 3 3 #include <libfibre/fibre.h> 4 4 5 class __attribute__((aligned(128))) bench_sem {6 Fibre * volatile ptr = nullptr;7 public:8 inline bool wait() {9 static Fibre * const ready = reinterpret_cast<Fibre * const>(1ull);10 for(;;) {11 Fibre * expected = this->ptr;12 if(expected == ready) {13 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {14 return false;15 }16 }17 else {18 /* paranoid */ assert( expected == nullptr );19 if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {20 fibre_park();21 return true;22 }23 }24 25 }26 }27 28 inline bool post() {29 static Fibre * const ready = reinterpret_cast<Fibre * const>(1ull);30 for(;;) {31 Fibre * expected = this->ptr;32 if(expected == ready) return false;33 if(expected == nullptr) {34 if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {35 return false;36 }37 }38 else {39 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {40 fibre_unpark( expected );41 return true;42 }43 }44 }45 }46 };47 5 struct Partner { 48 6 unsigned long long count = 0; … … 93 51 94 52 bool is_tty = isatty(STDOUT_FILENO); 95 start = getTimeNsec();53 start = timeHiRes(); 96 54 97 55 for(int i = 0; i < nthreads; i++) { … … 101 59 102 60 stop = true; 103 end = getTimeNsec();61 end = timeHiRes(); 104 62 printf("\nDone\n"); 105 63 -
benchmark/readyQ/locality.cfa
rfeacef9 r5407cdc 232 232 233 233 bool is_tty = isatty(STDOUT_FILENO); 234 start = getTimeNsec();234 start = timeHiRes(); 235 235 236 236 for(i; nthreads) { … … 240 240 241 241 stop = true; 242 end = getTimeNsec();242 end = timeHiRes(); 243 243 printf("\nDone\n"); 244 244 -
benchmark/readyQ/locality.cpp
rfeacef9 r5407cdc 9 9 uint64_t dmigs = 0; 10 10 uint64_t gmigs = 0; 11 };12 13 class __attribute__((aligned(128))) bench_sem {14 Fibre * volatile ptr = nullptr;15 public:16 inline bool wait() {17 static Fibre * const ready = reinterpret_cast<Fibre * const>(1ull);18 for(;;) {19 Fibre * expected = this->ptr;20 if(expected == ready) {21 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {22 return false;23 }24 }25 else {26 /* paranoid */ assert( expected == nullptr );27 if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {28 fibre_park();29 return true;30 }31 }32 33 }34 }35 36 inline bool post() {37 static Fibre * const ready = reinterpret_cast<Fibre * const>(1ull);38 for(;;) {39 Fibre * expected = this->ptr;40 if(expected == ready) return false;41 if(expected == nullptr) {42 if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {43 return false;44 }45 }46 else {47 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {48 fibre_unpark( expected );49 return true;50 }51 }52 }53 }54 11 }; 55 12 … … 287 244 288 245 bool is_tty = isatty(STDOUT_FILENO); 289 start = getTimeNsec();246 start = timeHiRes(); 290 247 291 248 for(size_t i = 0; i < nthreads; i++) { … … 295 252 296 253 stop = true; 297 end = getTimeNsec();254 end = timeHiRes(); 298 255 printf("\nDone\n"); 299 256 -
benchmark/readyQ/rq_bench.hfa
rfeacef9 r5407cdc 4 4 #include <stdio.h> 5 5 #include <stdlib.hfa> 6 #include <stats.hfa> 6 7 #include <thread.hfa> 7 8 #include <time.hfa> … … 63 64 (*p){ "Benchmark Processor", this.cl }; 64 65 } 66 #if !defined(__CFA_NO_STATISTICS__) 67 print_stats_at_exit( this.cl, CFA_STATS_READY_Q ); 68 #endif 65 69 } 66 70 … … 73 77 for() { 74 78 sleep(100`ms); 75 Time end = getTimeNsec();79 Time end = timeHiRes(); 76 80 Duration delta = end - start; 77 81 if(is_tty) { -
benchmark/readyQ/rq_bench.hpp
rfeacef9 r5407cdc 6 6 #include <time.h> // timespec 7 7 #include <sys/time.h> // timeval 8 9 typedef __uint128_t __lehmer64_state_t; 10 static inline uint64_t __lehmer64( __lehmer64_state_t & state ) { 11 state *= 0xda942042e4dd58b5; 12 return state >> 64; 13 } 8 14 9 15 enum { TIMEGRAN = 1000000000LL }; // nanosecond granularity, except for timeval … … 46 52 } 47 53 48 uint64_t getTimeNsec() {54 uint64_t timeHiRes() { 49 55 timespec curr; 50 56 clock_gettime( CLOCK_REALTIME, &curr ); … … 60 66 for(;;) { 61 67 Sleeper::usleep(100000); 62 uint64_t end = getTimeNsec();68 uint64_t end = timeHiRes(); 63 69 uint64_t delta = end - start; 64 70 if(is_tty) { … … 74 80 } 75 81 } 82 83 class Fibre; 84 int fibre_park(); 85 int fibre_unpark( Fibre * ); 86 Fibre * fibre_self(); 87 88 class __attribute__((aligned(128))) bench_sem { 89 Fibre * volatile ptr = nullptr; 90 public: 91 inline bool wait() { 92 static Fibre * const ready = reinterpret_cast<Fibre *>(1ull); 93 for(;;) { 94 Fibre * expected = this->ptr; 95 if(expected == ready) { 96 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 97 return false; 98 } 99 } 100 else { 101 /* paranoid */ assert( expected == nullptr ); 102 if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 103 fibre_park(); 104 return true; 105 } 106 } 107 108 } 109 } 110 111 inline bool post() { 112 static Fibre * const ready = reinterpret_cast<Fibre *>(1ull); 113 for(;;) { 114 Fibre * expected = this->ptr; 115 if(expected == ready) return false; 116 if(expected == nullptr) { 117 if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 118 return false; 119 } 120 } 121 else { 122 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 123 fibre_unpark( expected ); 124 return true; 125 } 126 } 127 } 128 } 129 }; 76 130 77 131 // ========================================================================================== … … 188 242 this->help = help; 189 243 this->variable = reinterpret_cast<void*>(&variable); 190 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(static_cast<bool (*)(const char *, T & )>(parse)); 244 #pragma GCC diagnostic push 245 #pragma GCC diagnostic ignored "-Wcast-function-type" 246 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(static_cast<bool (*)(const char *, T & )>(parse)); 247 #pragma GCC diagnostic pop 191 248 } 192 249 … … 197 254 this->help = help; 198 255 this->variable = reinterpret_cast<void*>(&variable); 199 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(parse); 256 #pragma GCC diagnostic push 257 #pragma GCC diagnostic ignored "-Wcast-function-type" 258 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(parse); 259 #pragma GCC diagnostic pop 200 260 } 201 261 }; -
benchmark/readyQ/yield.cfa
rfeacef9 r5407cdc 66 66 67 67 bool is_tty = isatty(STDOUT_FILENO); 68 start = getTimeNsec();68 start = timeHiRes(); 69 69 run = true; 70 70 … … 75 75 76 76 run = false; 77 end = getTimeNsec();77 end = timeHiRes(); 78 78 printf("\nDone\n"); 79 79 } -
doc/LaTeXmacros/lstlang.sty
rfeacef9 r5407cdc 8 8 %% Created On : Sat May 13 16:34:42 2017 9 9 %% Last Modified By : Peter A. Buhr 10 %% Last Modified On : Wed Sep 23 22:40:04 202011 %% Update Count : 2 410 %% Last Modified On : Wed Feb 17 09:21:15 2021 11 %% Update Count : 27 12 12 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 13 … … 113 113 morekeywords={ 114 114 _Alignas, _Alignof, __alignof, __alignof__, asm, __asm, __asm__, __attribute, __attribute__, 115 auto, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__,116 coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally, 115 auto, basetypeof, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__, 116 coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally, fixup, 117 117 __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__, 118 118 inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or, 119 otype, restrict, __restrict, __restrict__, __signed, __signed__, _Static_assert, suspend, thread,120 _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,119 otype, restrict, __restrict, __restrict__, recover, report, __signed, __signed__, _Static_assert, suspend, 120 thread, _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__, 121 121 virtual, __volatile, __volatile__, waitfor, when, with, zero_t, 122 122 }, -
doc/bibliography/pl.bib
rfeacef9 r5407cdc 1797 1797 } 1798 1798 1799 @article{Delisle2 0,1799 @article{Delisle21, 1800 1800 keywords = {concurrency, Cforall}, 1801 1801 contributer = {pabuhr@plg}, 1802 1802 author = {Thierry Delisle and Peter A. Buhr}, 1803 1803 title = {Advanced Control-flow and Concurrency in \textsf{C}$\mathbf{\forall}$}, 1804 year = 2020,1805 1804 journal = spe, 1806 pages = {1-38}, 1807 note = {\href{https://doi-org.proxy.lib.uwaterloo.ca/10.1002/spe.2925}{https://\-doi-org.proxy.lib.uwaterloo.ca/\-10.1002/\-spe.2925}}, 1808 note = {}, 1805 month = may, 1806 year = 2021, 1807 volume = 51, 1808 number = 5, 1809 pages = {1005-1042}, 1810 note = {\href{https://onlinelibrary.wiley.com/doi/10.1002/spe.2925}{https://\-onlinelibrary.wiley.com/\-doi/\-10.1002/\-spe.2925}}, 1809 1811 } 1810 1812 … … 3300 3302 month = jan, 3301 3303 address = {Waterloo, Ontario, Canada, N2L 3G1}, 3302 note = {\ textsf{http://uwspace.uwaterloo.ca/\-bitstream/\-10012/\-3501/\-1/\-Thesis.pdf}},3304 note = {\href{http://uwspace.uwaterloo.ca/bitstream/10012/3501/1/Thesis.pdf}{http://\-uwspace.uwaterloo.ca/\-bitstream/\-10012/\-3501/\-1/\-Thesis.pdf}}, 3303 3305 } 3304 3306 -
doc/theses/andrew_beach_MMath/Makefile
rfeacef9 r5407cdc 4 4 BUILD=out 5 5 TEXSRC=$(wildcard *.tex) 6 FIGSRC=$(wildcard *.fig) 6 7 BIBSRC=$(wildcard *.bib) 7 8 STYSRC=$(wildcard *.sty) … … 13 14 BASE= ${DOC:%.pdf=%} 14 15 16 RAWSRC=${TEXSRC} ${BIBSRC} ${STYSRC} ${CLSSRC} 17 FIGTEX=${FIGSRC:%.fig=${BUILD}/%.tex} 18 15 19 ### Special Rules: 16 20 … … 18 22 19 23 ### Commands: 20 LATEX=TEXINPUTS=${TEXLIB} pdflatex -halt-on-error -output-directory=${BUILD}24 LATEX=TEXINPUTS=${TEXLIB} latex -halt-on-error -output-directory=${BUILD} 21 25 BIBTEX=BIBINPUTS=${BIBLIB} bibtex 22 26 GLOSSARY=INDEXSTYLE=${BUILD} makeglossaries-lite … … 26 30 all: ${DOC} 27 31 28 ${BUILD}/${DOC}: ${TEXSRC} ${BIBSRC} ${STYSRC} ${CLSSRC} Makefile | ${BUILD} 32 # The main rule, it does all the tex/latex processing. 33 ${BUILD}/${BASE}.dvi: ${RAWSRC} ${FIGTEX} Makefile | ${BUILD} 29 34 ${LATEX} ${BASE} 30 35 ${BIBTEX} ${BUILD}/${BASE} … … 33 38 ${LATEX} ${BASE} 34 39 35 ${DOC}: ${BUILD}/${DOC} 36 cp $< $@ 40 # Convert xfig output to tex. (Generates \special declarations.) 41 ${FIGTEX}: ${BUILD}/%.tex: %.fig | ${BUILD} 42 fig2dev -L eepic $< > $@ 43 44 # Step through dvi & postscript to handle xfig specials. 45 %.pdf : ${BUILD}/%.dvi 46 dvipdf $^ $@ 37 47 38 48 ${BUILD}: -
doc/theses/andrew_beach_MMath/existing.tex
rfeacef9 r5407cdc 14 14 \section{Overloading and \lstinline{extern}} 15 15 \CFA has extensive overloading, allowing multiple definitions of the same name 16 to be defined .~\cite{Moss18}16 to be defined~\cite{Moss18}. 17 17 \begin{cfa} 18 18 char i; int i; double i; $\C[3.75in]{// variable overload}$ … … 46 46 pointers using the ampersand (@&@) instead of the pointer asterisk (@*@). \CFA 47 47 references may also be mutable or non-mutable. If mutable, a reference variable 48 may be assigned tousing the address-of operator (@&@), which converts the48 may be assigned using the address-of operator (@&@), which converts the 49 49 reference to a pointer. 50 50 \begin{cfa} … … 58 58 \section{Constructors and Destructors} 59 59 60 Both constructors and destructors are operators, which means they are just60 Both constructors and destructors are operators, which means they are 61 61 functions with special operator names rather than type names in \Cpp. The 62 62 special operator names may be used to call the functions explicitly (not … … 64 64 65 65 In general, operator names in \CFA are constructed by bracketing an operator 66 token with @?@, which indicates wherethe arguments. For example, infixed66 token with @?@, which indicates the position of the arguments. For example, infixed 67 67 multiplication is @?*?@ while prefix dereference is @*?@. This syntax make it 68 68 easy to tell the difference between prefix operations (such as @++?@) and … … 89 89 definition, \CFA creates a default and copy constructor, destructor and 90 90 assignment (like \Cpp). It is possible to define constructors/destructors for 91 basic and existing types .91 basic and existing types (unlike \Cpp). 92 92 93 93 \section{Polymorphism} … … 120 120 do_once(value); 121 121 } 122 void do_once( inti) { ... } // provide assertion123 inti;122 void do_once(@int@ i) { ... } // provide assertion 123 @int@ i; 124 124 do_twice(i); // implicitly pass assertion do_once to do_twice 125 125 \end{cfa} … … 172 172 declarations instead of parameters, returns, and local variable declarations. 173 173 \begin{cfa} 174 forall(dtype T)174 forall(dtype @T@) 175 175 struct node { 176 node(T) * next; // generic linked node 177 T * data; 178 } 176 node(@T@) * next; // generic linked node 177 @T@ * data; 178 } 179 node(@int@) inode; 179 180 \end{cfa} 180 181 The generic type @node(T)@ is an example of a polymorphic-type usage. Like \Cpp 181 template susage, a polymorphic-type usage must specify a type parameter.182 template usage, a polymorphic-type usage must specify a type parameter. 182 183 183 184 There are many other polymorphism features in \CFA but these are the ones used 184 185 by the exception system. 185 186 186 \section{Con currency}187 \CFA has a number of concurrency features: @thread@, @monitor@, @mutex@188 parameters, @coroutine@ and @generator@.The two features that interact with189 the exception system are @ thread@ and @coroutine@; they and their supporting187 \section{Control Flow} 188 \CFA has a number of advanced control-flow features: @generator@, @coroutine@, @monitor@, @mutex@ parameters, and @thread@. 189 The two features that interact with 190 the exception system are @coroutine@ and @thread@; they and their supporting 190 191 constructs are described here. 191 192 … … 216 217 CountUp countup; 217 218 \end{cfa} 218 Each coroutine has @main@ function, which takes a reference to a coroutine219 Each coroutine has a @main@ function, which takes a reference to a coroutine 219 220 object and returns @void@. 220 221 \begin{cfa}[numbers=left] … … 230 231 In this function, or functions called by this function (helper functions), the 231 232 @suspend@ statement is used to return execution to the coroutine's caller 232 without terminating the coroutine .233 without terminating the coroutine's function. 233 234 234 235 A coroutine is resumed by calling the @resume@ function, \eg @resume(countup)@. … … 242 243 @resume(countup).next@. 243 244 244 \subsection{Monitor s and Mutex}245 \subsection{Monitor and Mutex Parameter} 245 246 Concurrency does not guarantee ordering; without ordering results are 246 247 non-deterministic. To claw back ordering, \CFA uses monitors and @mutex@ … … 260 261 and only one runs at a time. 261 262 262 \subsection{Thread s}263 \subsection{Thread} 263 264 Functions, generators, and coroutines are sequential so there is only a single 264 265 (but potentially sophisticated) execution path in a program. Threads introduce … … 268 269 monitors and mutex parameters. For threads to work safely with other threads, 269 270 also requires mutual exclusion in the form of a communication rendezvous, which 270 also supports internal synchronization as for mutex objects. For exceptions 271 only t he basic two basic operations are important: threadfork and join.271 also supports internal synchronization as for mutex objects. For exceptions, 272 only two basic thread operations are important: fork and join. 272 273 273 274 Threads are created like coroutines with an associated @main@ function: -
doc/theses/andrew_beach_MMath/features.tex
rfeacef9 r5407cdc 2 2 3 3 This chapter covers the design and user interface of the \CFA 4 exception-handling mechanism. 4 exception-handling mechanism (EHM). % or exception system. 5 6 We will begin with an overview of EHMs in general. It is not a strict 7 definition of all EHMs nor an exaustive list of all possible features. 8 However it does cover the most common structure and features found in them. 9 10 % We should cover what is an exception handling mechanism and what is an 11 % exception before this. Probably in the introduction. Some of this could 12 % move there. 13 \paragraph{Raise / Handle} 14 An exception operation has two main parts: raise and handle. 15 These terms are sometimes also known as throw and catch but this work uses 16 throw/catch as a particular kind of raise/handle. 17 These are the two parts that the user will write themselves and may 18 be the only two pieces of the EHM that have any syntax in the language. 19 20 \subparagraph{Raise} 21 The raise is the starting point for exception handling. It marks the beginning 22 of exception handling by \newterm{raising} an excepion, which passes it to 23 the EHM. 24 25 Some well known examples include the @throw@ statements of \Cpp and Java and 26 the \codePy{raise} statement from Python. In real systems a raise may preform 27 some other work (such as memory management) but for the purposes of this 28 overview that can be ignored. 29 30 \subparagraph{Handle} 31 The purpose of most exception operations is to run some user code to handle 32 that exception. This code is given, with some other information, in a handler. 33 34 A handler has three common features: the previously mentioned user code, a 35 region of code they cover and an exception label/condition that matches 36 certain exceptions. 37 Only raises inside the covered region and raising exceptions that match the 38 label can be handled by a given handler. 39 Different EHMs will have different rules to pick a handler 40 if multipe handlers could be used such as ``best match" or ``first found". 41 42 The @try@ statements of \Cpp, Java and Python are common examples. All three 43 also show another common feature of handlers, they are grouped by the covered 44 region. 45 46 \paragraph{Propagation} 47 After an exception is raised comes what is usually the biggest step for the 48 EHM: finding and setting up the handler. The propogation from raise to 49 handler can be broken up into three different tasks: searching for a handler, 50 matching against the handler and installing the handler. 51 52 \subparagraph{Searching} 53 The EHM begins by searching for handlers that might be used to handle 54 the exception. Searching is usually independent of the exception that was 55 thrown as it looks for handlers that have the raise site in their covered 56 region. 57 This includes handlers in the current function, as well as any in callers 58 on the stack that have the function call in their covered region. 59 60 \subparagraph{Matching} 61 Each handler found has to be matched with the raised exception. The exception 62 label defines a condition that be use used with exception and decides if 63 there is a match or not. 64 65 In languages where the first match is used this step is intertwined with 66 searching, a match check is preformed immediately after the search finds 67 a possible handler. 68 69 \subparagraph{Installing} 70 After a handler is chosen it must be made ready to run. 71 The implementation can vary widely to fit with the rest of the 72 design of the EHM. The installation step might be trivial or it could be 73 the most expensive step in handling an exception. The latter tends to be the 74 case when stack unwinding is involved. 75 76 If a matching handler is not guarantied to be found the EHM will need a 77 different course of action here in the cases where no handler matches. 78 This is only required with unchecked exceptions as checked exceptions 79 (such as in Java) can make than guaranty. 80 This different action can also be installing a handler but it is usually an 81 implicat and much more general one. 82 83 \subparagraph{Hierarchy} 84 A common way to organize exceptions is in a hierarchical structure. 85 This is especially true in object-orientated languages where the 86 exception hierarchy is a natural extension of the object hierarchy. 87 88 Consider the following hierarchy of exceptions: 89 \begin{center} 90 \input{exception-hierarchy} 91 \end{center} 92 93 A handler labelled with any given exception can handle exceptions of that 94 type or any child type of that exception. The root of the exception hierarchy 95 (here \codeC{exception}) acts as a catch-all, leaf types catch single types 96 and the exceptions in the middle can be used to catch different groups of 97 related exceptions. 98 99 This system has some notable advantages, such as multiple levels of grouping, 100 the ability for libraries to add new exception types and the isolation 101 between different sub-hierarchies. 102 This design is used in \CFA even though it is not a object-orientated 103 language using different tools to create the hierarchy. 104 105 % Could I cite the rational for the Python IO exception rework? 106 107 \paragraph{Completion} 108 After the handler has finished the entire exception operation has to complete 109 and continue executing somewhere else. This step is usually simple, 110 both logically and in its implementation, as the installation of the handler 111 is usually set up to do most of the work. 112 113 The EHM can return control to many different places, 114 the most common are after the handler definition and after the raise. 115 116 \paragraph{Communication} 117 For effective exception handling, additional information is usually passed 118 from the raise to the handler. 119 So far only communication of the exceptions' identity has been covered. 120 A common method is putting fields into the exception instance and giving the 121 handler access to them. 5 122 6 123 \section{Virtuals} 7 Virtual types and casts are not part of the exception system nor are they 8 required for an exception system. But an object-oriented style hierarchy is a 9 great way of organizing exceptions so a minimal virtual system has been added 10 to \CFA. 11 12 The pattern of a simple hierarchy was borrowed from object-oriented 13 programming was chosen for several reasons. 14 The first is that it allows new exceptions to be added in user code 15 and in libraries independently of each other. Another is it allows for 16 different levels of exception grouping (all exceptions, all IO exceptions or 17 a particular IO exception). Also it also provides a simple way of passing 18 data back and forth across the throw. 19 20 Virtual types and casts are not required for a basic exception-system but are 21 useful for advanced exception features. However, \CFA is not object-oriented so 22 there is no obvious concept of virtuals. Hence, to create advanced exception 23 features for this work, I needed to design and implement a virtual-like 24 system for \CFA. 25 26 % NOTE: Maybe we should but less of the rational here. 27 Object-oriented languages often organized exceptions into a simple hierarchy, 28 \eg Java. 29 \begin{center} 30 \setlength{\unitlength}{4000sp}% 31 \begin{picture}(1605,612)(2011,-1951) 32 \put(2100,-1411){\vector(1, 0){225}} 33 \put(3450,-1411){\vector(1, 0){225}} 34 \put(3550,-1411){\line(0,-1){225}} 35 \put(3550,-1636){\vector(1, 0){150}} 36 \put(3550,-1636){\line(0,-1){225}} 37 \put(3550,-1861){\vector(1, 0){150}} 38 \put(2025,-1490){\makebox(0,0)[rb]{\LstBasicStyle{exception}}} 39 \put(2400,-1460){\makebox(0,0)[lb]{\LstBasicStyle{arithmetic}}} 40 \put(3750,-1460){\makebox(0,0)[lb]{\LstBasicStyle{underflow}}} 41 \put(3750,-1690){\makebox(0,0)[lb]{\LstBasicStyle{overflow}}} 42 \put(3750,-1920){\makebox(0,0)[lb]{\LstBasicStyle{zerodivide}}} 43 \end{picture}% 44 \end{center} 45 The hierarchy provides the ability to handle an exception at different degrees 46 of specificity (left to right). Hence, it is possible to catch a more general 47 exception-type in higher-level code where the implementation details are 48 unknown, which reduces tight coupling to the lower-level implementation. 49 Otherwise, low-level code changes require higher-level code changes, \eg, 50 changing from raising @underflow@ to @overflow@ at the low level means changing 51 the matching catch at the high level versus catching the general @arithmetic@ 52 exception. In detail, each virtual type may have a parent and can have any 53 number of children. A type's descendants are its children and its children's 54 descendants. A type may not be its own descendant. 55 56 The exception hierarchy allows a handler (@catch@ clause) to match multiple 57 exceptions, \eg a base-type handler catches both base and derived 58 exception-types. 59 \begin{cfa} 60 try { 61 ... 62 } catch(arithmetic &) { 63 ... // handle arithmetic, underflow, overflow, zerodivide 64 } 65 \end{cfa} 66 Most exception mechanisms perform a linear search of the handlers and select 67 the first matching handler, so the order of handers is now important because 68 matching is many to one. 69 70 Each virtual type needs an associated virtual table. A virtual table is a 71 structure with fields for all the virtual members of a type. A virtual type has 72 all the virtual members of its parent and can add more. It may also update the 73 values of the virtual members and often does. 124 Virtual types and casts are not part of \CFA's EHM nor are they required for 125 any EHM. But \CFA uses a hierarchial system of exceptions and this feature 126 is leveraged to create that. 127 128 % Maybe talk about why the virtual system is so minimal. 129 % Created for but not a part of the exception system. 130 131 The virtual system supports multiple ``trees" of types. Each tree is 132 a simple hierarchy with a single root type. Each type in a tree has exactly 133 one parent -- except for the root type which has zero parents -- and any 134 number of children. 135 Any type that belongs to any of these trees is called a virtual type. 136 137 % A type's ancestors are its parent and its parent's ancestors. 138 % The root type has no ancestors. 139 % A type's decendents are its children and its children's decendents. 140 141 Every virtual type also has a list of virtual members. Children inherit 142 their parent's list of virtual members but may add new members to it. 143 It is important to note that these are virtual members, not virtual methods 144 of object-orientated programming, and can be of any type. 145 However, since \CFA has function pointers and they are allowed, virtual 146 members can be used to mimic virtual methods. 147 148 Each virtual type has a unique id. 149 This unique id and all the virtual members are combined 150 into a virtual table type. Each virtual type has a pointer to a virtual table 151 as a hidden field. 152 153 Up until this point the virtual system is similar to ones found in 154 object-orientated languages but this where \CFA diverges. Objects encapsulate a 155 single set of behaviours in each type, universally across the entire program, 156 and indeed all programs that use that type definition. In this sense the 157 types are ``closed" and cannot be altered. 158 159 In \CFA types do not encapsulate any behaviour. Traits are local and 160 types can begin to statify a trait, stop satifying a trait or satify the same 161 trait in a different way at any lexical location in the program. 162 In this sense they are ``open" as they can change at any time. This means it 163 is implossible to pick a single set of functions that repersent the type's 164 implementation across the program. 165 166 \CFA side-steps this issue by not having a single virtual table for each 167 type. A user can define virtual tables which are filled in at their 168 declaration and given a name. Anywhere that name is visible, even if it was 169 defined locally inside a function (although that means it will not have a 170 static lifetime), it can be used. 171 Specifically, a virtual type is ``bound" to a virtual table which 172 sets the virtual members for that object. The virtual members can be accessed 173 through the object. 74 174 75 175 While much of the virtual infrastructure is created, it is currently only used … … 83 183 \Cpp syntax for special casts. Both the type of @EXPRESSION@ and @TYPE@ must be 84 184 a pointer to a virtual type. 85 The cast dynamically checks if the @EXPRESSION@ type is the same or a sub type185 The cast dynamically checks if the @EXPRESSION@ type is the same or a sub-type 86 186 of @TYPE@, and if true, returns a pointer to the 87 187 @EXPRESSION@ object, otherwise it returns @0p@ (null pointer). … … 101 201 \end{cfa} 102 202 The trait is defined over two types, the exception type and the virtual table 103 type. This should be one-to-one ,each exception type has only one virtual203 type. This should be one-to-one: each exception type has only one virtual 104 204 table type and vice versa. The only assertion in the trait is 105 205 @get_exception_vtable@, which takes a pointer of the exception type and 106 206 returns a reference to the virtual table type instance. 107 207 208 % TODO: This section, and all references to get_exception_vtable, are 209 % out-of-data. Perhaps wait until the update is finished before rewriting it. 108 210 The function @get_exception_vtable@ is actually a constant function. 109 Re cardless of the value passed in (including the null pointer) it should211 Regardless of the value passed in (including the null pointer) it should 110 212 return a reference to the virtual table instance for that type. 111 213 The reason it is a function instead of a constant is that it make type … … 119 221 % similar system I know of (except Agda's I guess) so I took it out. 120 222 121 There are two more traits for exceptions @is_termination_exception@ and 122 @is_resumption_exception@. They are defined as follows: 123 223 There are two more traits for exceptions defined as follows: 124 224 \begin{cfa} 125 225 trait is_termination_exception( … … 133 233 }; 134 234 \end{cfa} 135 136 In other words they make sure that a given type and virtual type is an 137 exception and defines one of the two default handlers. These default handlers 138 are used in the main exception handling operations \see{Exception Handling} 139 and their use will be detailed there. 140 141 However all three of these traits can be trickly to use directly. 142 There is a bit of repetition required but 235 Both traits ensure a pair of types are an exception type and its virtual table 236 and defines one of the two default handlers. The default handlers are used 237 as fallbacks and are discussed in detail in \VRef{s:ExceptionHandling}. 238 239 However, all three of these traits can be tricky to use directly. 240 While there is a bit of repetition required, 143 241 the largest issue is that the virtual table type is mangled and not in a user 144 facing way. So the re are three macros that can be used to wrap these traits145 when you need to referto the names:242 facing way. So these three macros are provided to wrap these traits to 243 simplify referring to the names: 146 244 @IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@ and @IS_RESUMPTION_EXCEPTION@. 147 245 148 All t ake one or two arguments. The first argument is the name of the149 exception type. Its unmangled and mangled form are passedto the trait.246 All three take one or two arguments. The first argument is the name of the 247 exception type. The macro passes its unmangled and mangled form to the trait. 150 248 The second (optional) argument is a parenthesized list of polymorphic 151 arguments. This argument should onlywith polymorphic exceptions and the152 list willbe passed to both types.153 In the current set-up the base name and the polymorphic arguments have to154 match so these macros can be used without losing flexability.249 arguments. This argument is only used with polymorphic exceptions and the 250 list is be passed to both types. 251 In the current set-up, the two types always have the same polymorphic 252 arguments so these macros can be used without losing flexibility. 155 253 156 254 For example consider a function that is polymorphic over types that have a … … 162 260 163 261 \section{Exception Handling} 164 \ CFA provides two kinds of exception handling, termination and resumption.165 These twin operations are the core of the exception handling mechanism and 166 are the reason for the features of exceptions.262 \label{s:ExceptionHandling} 263 \CFA provides two kinds of exception handling: termination and resumption. 264 These twin operations are the core of \CFA's exception handling mechanism. 167 265 This section will cover the general patterns shared by the two operations and 168 266 then go on to cover the details each individual operation. 169 267 170 Both operations follow the same set of steps to do their operation. They both 171 start with the user preforming a throw on an exception. 172 Then there is the search for a handler, if one is found than the exception 173 is caught and the handler is run. After that control returns to normal 174 execution. 175 268 Both operations follow the same set of steps. 269 Both start with the user preforming a raise on an exception. 270 Then the exception propogates up the stack. 271 If a handler is found the exception is caught and the handler is run. 272 After that control returns to normal execution. 176 273 If the search fails a default handler is run and then control 177 returns to normal execution immediately. That is where the default handlers 178 @defaultTermiationHandler@ and @defaultResumptionHandler@ are used. 274 returns to normal execution after the raise. 275 276 This general description covers what the two kinds have in common. 277 Differences include how propogation is preformed, where exception continues 278 after an exception is caught and handled and which default handler is run. 179 279 180 280 \subsection{Termination} 181 281 \label{s:Termination} 182 183 Termination handling is more familiar kind and used in most programming 282 Termination handling is the familiar kind and used in most programming 184 283 languages with exception handling. 185 It is dynamic, non-local goto. If a throw is successful then the stack will 186 be unwound and control will (usually) continue in a different function on 187 the call stack. They are commonly used when an error has occured and recovery 188 is impossible in the current function. 284 It is dynamic, non-local goto. If the raised exception is matched and 285 handled the stack is unwound and control will (usually) continue the function 286 on the call stack that defined the handler. 287 Termination is commonly used when an error has occurred and recovery is 288 impossible locally. 189 289 190 290 % (usually) Control can continue in the current function but then a different 191 291 % control flow construct should be used. 192 292 193 A termination throwis started with the @throw@ statement:293 A termination raise is started with the @throw@ statement: 194 294 \begin{cfa} 195 295 throw EXPRESSION; 196 296 \end{cfa} 197 297 The expression must return a reference to a termination exception, where the 198 termination exception is any type that satifies @is_termination_exception@ 199 at the call site. 200 Through \CFA's trait system the functions in the traits are passed into the 201 throw code. A new @defaultTerminationHandler@ can be defined in any scope to 298 termination exception is any type that satisfies the trait 299 @is_termination_exception@ at the call site. 300 Through \CFA's trait system the trait functions are implicity passed into the 301 throw code and the EHM. 302 A new @defaultTerminationHandler@ can be defined in any scope to 202 303 change the throw's behavior (see below). 203 304 204 The throw will copy the provided exception into managed memory. It is the 205 user's responcibility to ensure the original exception is cleaned up if the 206 stack is unwound (allocating it on the stack should be sufficient). 207 208 Then the exception system searches the stack using the copied exception. 209 It starts starts from the throw and proceeds to the base of the stack, 305 The throw will copy the provided exception into managed memory to ensure 306 the exception is not destroyed if the stack is unwound. 307 It is the user's responsibility to ensure the original exception is cleaned 308 up wheither the stack is unwound or not. Allocating it on the stack is 309 usually sufficient. 310 311 Then propogation starts with the search. \CFA uses a ``first match" rule so 312 matching is preformed with the copied exception as the search continues. 313 It starts from the throwing function and proceeds to the base of the stack, 210 314 from callee to caller. 211 315 At each stack frame, a check is made for resumption handlers defined by the … … 214 318 try { 215 319 GUARDED_BLOCK 216 } catch (EXCEPTION_TYPE$\(_1\)$ * NAME$\(_1\)$) {320 } catch (EXCEPTION_TYPE$\(_1\)$ * [NAME$\(_1\)$]) { 217 321 HANDLER_BLOCK$\(_1\)$ 218 } catch (EXCEPTION_TYPE$\(_2\)$ * NAME$\(_2\)$) {322 } catch (EXCEPTION_TYPE$\(_2\)$ * [NAME$\(_2\)$]) { 219 323 HANDLER_BLOCK$\(_2\)$ 220 324 } 221 325 \end{cfa} 222 When viewed on its own a try statement will simply exceute the statements in223 @GUARDED_BLOCK@ and when those are finished the try statement finishes.326 When viewed on its own, a try statement will simply execute the statements 327 in @GUARDED_BLOCK@ and when those are finished the try statement finishes. 224 328 225 329 However, while the guarded statements are being executed, including any 226 functions they invoke, all the handlers following the try block are now 227 or any functions invoked from those 228 statements, throws an exception, and the exception 229 is not handled by a try statement further up the stack, the termination 230 handlers are searched for a matching exception type from top to bottom. 231 232 Exception matching checks the representation of the thrown exception-type is 233 the same or a descendant type of the exception types in the handler clauses. If 234 it is the same of a descendent of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$ is 330 invoked functions, all the handlers in the statement are now on the search 331 path. If a termination exception is thrown and not handled further up the 332 stack they will be matched against the exception. 333 334 Exception matching checks the handler in each catch clause in the order 335 they appear, top to bottom. If the representation of the thrown exception type 336 is the same or a descendant of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$ 337 (if provided) is 235 338 bound to a pointer to the exception and the statements in @HANDLER_BLOCK@$_i$ 236 339 are executed. If control reaches the end of the handler, the exception is 237 340 freed and control continues after the try statement. 238 341 239 If no handler is found during the search then the default handler is run. 342 If no termination handler is found during the search then the default handler 343 (@defaultTerminationHandler@) is run. 240 344 Through \CFA's trait system the best match at the throw sight will be used. 241 345 This function is run and is passed the copied exception. After the default 242 346 handler is run control continues after the throw statement. 243 347 244 There is a global @defaultTerminationHandler@ that cancels the current stack 245 with the copied exception. However it is generic over all exception types so 246 new default handlers can be defined for different exception types and so 247 different exception types can have different default handlers. 348 There is a global @defaultTerminationHandler@ that is polymorphic over all 349 exception types. Since it is so general a more specific handler can be 350 defined and will be used for those types, effectively overriding the handler 351 for particular exception type. 352 The global default termination handler performs a cancellation 353 \see{\VRef{s:Cancellation}} on the current stack with the copied exception. 248 354 249 355 \subsection{Resumption} 250 356 \label{s:Resumption} 251 357 252 Resumption exception handling is a less common formthan termination but is253 just as old~\cite{Goodenough75} and is in some sense simpler.254 It is a dynamic, non-local function call. If the throw is successful a255 closure will be taken from up the stack and executed, after which the throwing 256 function will continue executing.257 These are most often used when an error occur ed and if the error is repaired358 Resumption exception handling is less common than termination but is 359 just as old~\cite{Goodenough75} and is simpler in many ways. 360 It is a dynamic, non-local function call. If the raised exception is 361 matched a closure will be taken from up the stack and executed, 362 after which the raising function will continue executing. 363 These are most often used when an error occurred and if the error is repaired 258 364 then the function can continue. 259 365 … … 262 368 throwResume EXPRESSION; 263 369 \end{cfa} 264 The semantics of the @throwResume@ statement are like the @throw@, but the 265 expression has return a reference a type that satifies the trait 266 @is_resumption_exception@. The assertions from this trait are available to 370 It works much the same way as the termination throw. 371 The expression must return a reference to a resumption exception, 372 where the resumption exception is any type that satisfies the trait 373 @is_resumption_exception@ at the call site. 374 The assertions from this trait are available to 267 375 the exception system while handling the exception. 268 376 269 At runtime, no copies are made. As the stack is not unwound the exception and 377 At run-time, no exception copy is made. 378 As the stack is not unwound the exception and 270 379 any values on the stack will remain in scope while the resumption is handled. 271 380 272 Then the exception system searches the stack using the provided exception. 273 It starts starts from the throw and proceeds to the base of the stack, 274 from callee to caller. 381 The EHM then begins propogation. The search starts from the raise in the 382 resuming function and proceeds to the base of the stack, from callee to caller. 275 383 At each stack frame, a check is made for resumption handlers defined by the 276 384 @catchResume@ clauses of a @try@ statement. … … 278 386 try { 279 387 GUARDED_BLOCK 280 } catchResume (EXCEPTION_TYPE$\(_1\)$ * NAME$\(_1\)$) {388 } catchResume (EXCEPTION_TYPE$\(_1\)$ * [NAME$\(_1\)$]) { 281 389 HANDLER_BLOCK$\(_1\)$ 282 } catchResume (EXCEPTION_TYPE$\(_2\)$ * NAME$\(_2\)$) {390 } catchResume (EXCEPTION_TYPE$\(_2\)$ * [NAME$\(_2\)$]) { 283 391 HANDLER_BLOCK$\(_2\)$ 284 392 } 285 393 \end{cfa} 286 If the handlers are not involved in a search this will simply execute the 287 @GUARDED_BLOCK@ and then continue to the next statement. 288 Its purpose is to add handlers onto the stack. 289 (Note, termination and resumption handlers may be intermixed in a @try@ 290 statement but the kind of throw must be the same as the handler for it to be 291 considered as a possible match.) 292 293 If a search for a resumption handler reaches a try block it will check each 294 @catchResume@ clause, top-to-bottom. 295 At each handler if the thrown exception is or is a child type of 296 @EXCEPTION_TYPE@$_i$ then the a pointer to the exception is bound to 297 @NAME@$_i$ and then @HANDLER_BLOCK@$_i$ is executed. After the block is 298 finished control will return to the @throwResume@ statement. 394 % I wonder if there would be some good central place for this. 395 Note that termination handlers and resumption handlers may be used together 396 in a single try statement, intermixing @catch@ and @catchResume@ freely. 397 Each type of handler will only interact with exceptions from the matching 398 type of raise. 399 When a try statement is executed it simply executes the statements in the 400 @GUARDED_BLOCK@ and then finishes. 401 402 However, while the guarded statements are being executed, including any 403 invoked functions, all the handlers in the statement are now on the search 404 path. If a resumption exception is reported and not handled further up the 405 stack they will be matched against the exception. 406 407 Exception matching checks the handler in each catch clause in the order 408 they appear, top to bottom. If the representation of the thrown exception type 409 is the same or a descendant of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$ 410 (if provided) is bound to a pointer to the exception and the statements in 411 @HANDLER_BLOCK@$_i$ are executed. 412 If control reaches the end of the handler, execution continues after the 413 the raise statement that raised the handled exception. 299 414 300 415 Like termination, if no resumption handler is found, the default handler … … 302 417 call sight according to \CFA's overloading rules. The default handler is 303 418 passed the exception given to the throw. When the default handler finishes 304 execution continues after the throwstatement.419 execution continues after the raise statement. 305 420 306 421 There is a global @defaultResumptionHandler@ is polymorphic over all 307 422 termination exceptions and preforms a termination throw on the exception. 308 The @defaultTerminationHandler@ for that throwis matched at the original309 throwstatement (the resumption @throwResume@) and it can be customized by423 The @defaultTerminationHandler@ for that raise is matched at the original 424 raise statement (the resumption @throwResume@) and it can be customized by 310 425 introducing a new or better match as well. 311 426 312 % \subsubsection? 313 427 \subsubsection{Resumption Marking} 314 428 A key difference between resumption and termination is that resumption does 315 429 not unwind the stack. A side effect that is that when a handler is matched … … 331 445 search and match the handler in the @catchResume@ clause. This will be 332 446 call and placed on the stack on top of the try-block. The second throw then 333 throws and will sea ch the same try block and put call another instance of the447 throws and will search the same try block and put call another instance of the 334 448 same handler leading to an infinite loop. 335 449 … … 337 451 can form with multiple handlers and different exception types. 338 452 339 To prevent all of these cases we mask sections of the stack, or equvilantly 340 the try statements on the stack, so that the resumption seach skips over 341 them and continues with the next unmasked section of the stack. 342 343 A section of the stack is marked when it is searched to see if it contains 344 a handler for an exception and unmarked when that exception has been handled 345 or the search was completed without finding a handler. 346 347 % This might need a diagram. But it is an important part of the justification 348 % of the design of the traversal order. 349 \begin{verbatim} 350 throwResume2 ----------. 351 | | 352 generated from handler | 353 | | 354 handler | 355 | | 356 throwResume1 -----. : 357 | | : 358 try | : search skip 359 | | : 360 catchResume <----' : 361 | | 362 \end{verbatim} 363 364 The rules can be remembered as thinking about what would be searched in 365 termination. So when a throw happens in a handler; a termination handler 366 skips everything from the original throw to the original catch because that 367 part of the stack has been unwound, a resumption handler skips the same 368 section of stack because it has been masked. 369 A throw in a default handler will preform the same search as the original 370 throw because; for termination nothing has been unwound, for resumption 371 the mask will be the same. 372 373 The symmetry with termination is why this pattern was picked. Other patterns, 374 such as marking just the handlers that caught, also work but lack the 375 symmetry whih means there is more to remember. 453 To prevent all of these cases we mark try statements on the stack. 454 A try statement is marked when a match check is preformed with it and an 455 exception. The statement will be unmarked when the handling of that exception 456 is completed or the search completes without finding a handler. 457 While a try statement is marked its handlers are never matched, effectify 458 skipping over it to the next try statement. 459 460 \begin{center} 461 \input{stack-marking} 462 \end{center} 463 464 These rules mirror what happens with termination. 465 When a termination throw happens in a handler the search will not look at 466 any handlers from the original throw to the original catch because that 467 part of the stack has been unwound. 468 A resumption raise in the same situation wants to search the entire stack, 469 but it will not try to match the exception with try statements in the section 470 that would have been unwound as they are marked. 471 472 The symmetry between resumption termination is why this pattern was picked. 473 Other patterns, such as marking just the handlers that caught, also work but 474 lack the symmetry means there are less rules to remember. 376 475 377 476 \section{Conditional Catch} … … 379 478 condition to further control which exceptions they handle: 380 479 \begin{cfa} 381 catch (EXCEPTION_TYPE * NAME; CONDITION)480 catch (EXCEPTION_TYPE * [NAME] ; CONDITION) 382 481 \end{cfa} 383 482 First, the same semantics is used to match the exception type. Second, if the … … 387 486 matches. Otherwise, the exception search continues as if the exception type 388 487 did not match. 389 \begin{cfa} 390 try { 391 f1 = open( ... ); 392 f2 = open( ... ); 488 489 The condition matching allows finer matching by allowing the match to check 490 more kinds of information than just the exception type. 491 \begin{cfa} 492 try { 493 handle1 = open( f1, ... ); 494 handle2 = open( f2, ... ); 495 handle3 = open( f3, ... ); 393 496 ... 394 497 } catch( IOFailure * f ; fd( f ) == f1 ) { 395 // only handle IO failure for f1 396 } 397 \end{cfa} 398 Note, catching @IOFailure@, checking for @f1@ in the handler, and reraising the 399 exception if not @f1@ is different because the reraise does not examine any of 400 remaining handlers in the current try statement. 401 402 \section{Rethrowing} 403 \colour{red}{From Andrew: I recomend we talk about why the language doesn't 404 have rethrows/reraises instead.} 405 406 \label{s:Rethrowing} 498 // Only handle IO failure for f1. 499 } catch( IOFailure * f ; fd( f ) == f3 ) { 500 // Only handle IO failure for f3. 501 } 502 // Can't handle a failure relating to f2 here. 503 \end{cfa} 504 In this example the file that experianced the IO error is used to decide 505 which handler should be run, if any at all. 506 507 \begin{comment} 508 % I know I actually haven't got rid of them yet, but I'm going to try 509 % to write it as if I had and see if that makes sense: 510 \section{Reraising} 511 \label{s:Reraising} 407 512 Within the handler block or functions called from the handler block, it is 408 513 possible to reraise the most recently caught exception with @throw@ or … … 423 528 is part of an unwound stack frame. To prevent this problem, a new default 424 529 handler is generated that does a program-level abort. 530 \end{comment} 531 532 \subsection{Comparison with Reraising} 533 A more popular way to allow handlers to match in more detail is to reraise 534 the exception after it has been caught if it could not be handled here. 535 On the surface these two features seem interchangable. 536 537 If we used @throw;@ to start a termination reraise then these two statements 538 would have the same behaviour: 539 \begin{cfa} 540 try { 541 do_work_may_throw(); 542 } catch(exception_t * exc ; can_handle(exc)) { 543 handle(exc); 544 } 545 \end{cfa} 546 547 \begin{cfa} 548 try { 549 do_work_may_throw(); 550 } catch(exception_t * exc) { 551 if (can_handle(exc)) { 552 handle(exc); 553 } else { 554 throw; 555 } 556 } 557 \end{cfa} 558 If there are further handlers after this handler only the first version will 559 check them. If multiple handlers on a single try block could handle the same 560 exception the translations get more complex but they are equivilantly 561 powerful. 562 563 Until stack unwinding comes into the picture. In termination handling, a 564 conditional catch happens before the stack is unwound, but a reraise happens 565 afterwards. Normally this might only cause you to loose some debug 566 information you could get from a stack trace (and that can be side stepped 567 entirely by collecting information during the unwind). But for \CFA there is 568 another issue, if the exception isn't handled the default handler should be 569 run at the site of the original raise. 570 571 There are two problems with this: the site of the original raise doesn't 572 exist anymore and the default handler might not exist anymore. The site will 573 always be removed as part of the unwinding, often with the entirety of the 574 function it was in. The default handler could be a stack allocated nested 575 function removed during the unwind. 576 577 This means actually trying to pretend the catch didn't happening, continuing 578 the original raise instead of starting a new one, is infeasible. 579 That is the expected behaviour for most languages and we can't replicate 580 that behaviour. 425 581 426 582 \section{Finally Clauses} 583 \label{s:FinallyClauses} 427 584 Finally clauses are used to preform unconditional clean-up when leaving a 428 scope . They are placed at the end of a try statement:585 scope and are placed at the end of a try statement after any handler clauses: 429 586 \begin{cfa} 430 587 try { … … 442 599 443 600 Execution of the finally block should always finish, meaning control runs off 444 the end of the block. This requirement ensures always continues as if the 445 finally clause is not present, \ie finally is for cleanup not changing control 446 flow. Because of this requirement, local control flow out of the finally block 601 the end of the block. This requirement ensures control always continues as if 602 the finally clause is not present, \ie finally is for cleanup not changing 603 control flow. 604 Because of this requirement, local control flow out of the finally block 447 605 is forbidden. The compiler precludes any @break@, @continue@, @fallthru@ or 448 606 @return@ that causes control to leave the finally block. Other ways to leave 449 607 the finally block, such as a long jump or termination are much harder to check, 450 and at best requiring additional run-time overhead, and so are mearly608 and at best requiring additional run-time overhead, and so are only 451 609 discouraged. 452 610 453 Not all languages with exceptionshave finally clauses. Notably \Cpp does611 Not all languages with unwinding have finally clauses. Notably \Cpp does 454 612 without it as descructors serve a similar role. Although destructors and 455 613 finally clauses can be used in many of the same areas they have their own 456 614 use cases like top-level functions and lambda functions with closures. 457 615 Destructors take a bit more work to set up but are much easier to reuse while 458 finally clauses are good for once offs and can include local information. 616 finally clauses are good for one-off uses and 617 can easily include local information. 459 618 460 619 \section{Cancellation} 620 \label{s:Cancellation} 461 621 Cancellation is a stack-level abort, which can be thought of as as an 462 uncatchable termination. It unwinds the entire ty of thecurrent stack, and if622 uncatchable termination. It unwinds the entire current stack, and if 463 623 possible forwards the cancellation exception to a different stack. 464 624 … … 466 626 There is no special statement for starting a cancellation; instead the standard 467 627 library function @cancel_stack@ is called passing an exception. Unlike a 468 throw, this exception is not used in matching only to pass information about628 raise, this exception is not used in matching only to pass information about 469 629 the cause of the cancellation. 470 (This also means matching cannot fail so there is no default handler either.)471 472 After @cancel_stack@ is called the exception is copied into the exception473 handling mechanism's memory. Then the entirety ofthe current stack is630 (This also means matching cannot fail so there is no default handler.) 631 632 After @cancel_stack@ is called the exception is copied into the EHM's memory 633 and the current stack is 474 634 unwound. After that it depends one which stack is being cancelled. 475 635 \begin{description} 476 636 \item[Main Stack:] 477 637 The main stack is the one used by the program main at the start of execution, 478 and is the only stack in a sequential program. Even in a concurrent program 479 the main stack is only dependent on the environment that started the program. 480 Hence, when the main stack is cancelled there is nowhere else in the program 481 to notify. After the stack is unwound, there is a program-level abort. 638 and is the only stack in a sequential program. 639 After the main stack is unwound there is a program-level abort. 640 641 There are two reasons for this. The first is that it obviously had to do this 642 in a sequential program as there is nothing else to notify and the simplicity 643 of keeping the same behaviour in sequential and concurrent programs is good. 644 Also, even in concurrent programs there is no stack that an innate connection 645 to, so it would have be explicitly managed. 482 646 483 647 \item[Thread Stack:] 484 A thread stack is created for a @thread@ object or object that satisfies the 485 @is_thread@ trait. A thread only has two points of communication that must 486 happen: start and join. As the thread must be running to perform a 487 cancellation, it must occur after start and before join, so join is used 488 for communication here. 489 After the stack is unwound, the thread halts and waits for 490 another thread to join with it. The joining thread checks for a cancellation, 491 and if present, resumes exception @ThreadCancelled@. 492 493 There is a subtle difference between the explicit join (@join@ function) and 494 implicit join (from a destructor call). The explicit join takes the default 495 handler (@defaultResumptionHandler@) from its calling context, which is used if 496 the exception is not caught. The implicit join does a program abort instead. 497 498 This semantics is for safety. If an unwind is triggered while another unwind 499 is underway only one of them can proceed as they both want to ``consume'' the 500 stack. Letting both try to proceed leads to very undefined behaviour. 501 Both termination and cancellation involve unwinding and, since the default 502 @defaultResumptionHandler@ preforms a termination that could more easily 503 happen in an implicate join inside a destructor. So there is an error message 504 and an abort instead. 505 \todo{Perhaps have a more general disucssion of unwind collisions before 506 this point.} 507 508 The recommended way to avoid the abort is to handle the intial resumption 509 from the implicate join. If required you may put an explicate join inside a 510 finally clause to disable the check and use the local 511 @defaultResumptionHandler@ instead. 512 513 \item[Coroutine Stack:] A coroutine stack is created for a @coroutine@ object 514 or object that satisfies the @is_coroutine@ trait. A coroutine only knows of 515 two other coroutines, its starter and its last resumer. Of the two the last 516 resumer has the tightest coupling to the coroutine it activated and the most 517 up-to-date information. 518 519 Hence, cancellation of the active coroutine is forwarded to the last resumer 520 after the stack is unwound. When the resumer restarts, it resumes exception 521 @CoroutineCancelled@, which is polymorphic over the coroutine type and has a 522 pointer to the cancelled coroutine. 523 524 The resume function also has an assertion that the @defaultResumptionHandler@ 525 for the exception. So it will use the default handler like a regular throw. 648 A thread stack is created for a \CFA @thread@ object or object that satisfies 649 the @is_thread@ trait. 650 After a thread stack is unwound there exception is stored until another 651 thread attempts to join with it. Then the exception @ThreadCancelled@, 652 which stores a reference to the thread and to the exception passed to the 653 cancellation, is reported from the join. 654 There is one difference between an explicit join (with the @join@ function) 655 and an implicit join (from a destructor call). The explicit join takes the 656 default handler (@defaultResumptionHandler@) from its calling context while 657 the implicit join provides its own which does a program abort if the 658 @ThreadCancelled@ exception cannot be handled. 659 660 Communication is done at join because a thread only has to have to points of 661 communication with other threads: start and join. 662 Since a thread must be running to perform a cancellation (and cannot be 663 cancelled from another stack), the cancellation must be after start and 664 before the join. So join is the one that we will use. 665 666 % TODO: Find somewhere to discuss unwind collisions. 667 The difference between the explicit and implicit join is for safety and 668 debugging. It helps prevent unwinding collisions by avoiding throwing from 669 a destructor and prevents cascading the error across multiple threads if 670 the user is not equipped to deal with it. 671 Also you can always add an explicit join if that is the desired behaviour. 672 673 \item[Coroutine Stack:] 674 A coroutine stack is created for a @coroutine@ object or object that 675 satisfies the @is_coroutine@ trait. 676 After a coroutine stack is unwound control returns to the resume function 677 that most recently resumed it. The resume statement reports a 678 @CoroutineCancelled@ exception, which contains a references to the cancelled 679 coroutine and the exception used to cancel it. 680 The resume function also takes the @defaultResumptionHandler@ from the 681 caller's context and passes it to the internal report. 682 683 A coroutine knows of two other coroutines, its starter and its last resumer. 684 The starter has a much more distant connection while the last resumer just 685 (in terms of coroutine state) called resume on this coroutine, so the message 686 is passed to the latter. 526 687 \end{description} -
doc/theses/andrew_beach_MMath/future.tex
rfeacef9 r5407cdc 83 83 patterns to find the handler. 84 84 85 \section{Checked Exceptions} 86 Checked exceptions make exceptions part of a function's type by adding the 87 exception signature. An exception signature must declare all checked 88 exceptions that could propogate from the function (either because they were 89 raised inside the function or came from a sub-function). This improves safety 90 by making sure every checked exception is either handled or consciously 91 passed on. 92 93 However checked exceptions were never seriously considered for this project 94 for two reasons. The first is due to time constraints, even copying an 95 existing checked exception system would be pushing the remaining time and 96 trying to address the second problem would take even longer. The second 97 problem is that checked exceptions have some real usability trade-offs in 98 exchange for the increased safety. 99 100 These trade-offs are most problematic when trying to pass exceptions through 101 higher-order functions from the functions the user passed into the 102 higher-order function. There are no well known solutions to this problem 103 that were statifactory for \CFA (which carries some of C's flexability 104 over safety design) so one would have to be researched and developed. 105 106 Follow-up work might add checked exceptions to \CFA, possibly using 107 polymorphic exception signatures, a form of tunneling\cite{Zhang19} or 108 checked and unchecked raises. 109 85 110 \section{Zero-Cost Try} 86 111 \CFA does not have zero-cost try-statements because the compiler generates C -
doc/theses/andrew_beach_MMath/implement.tex
rfeacef9 r5407cdc 13 13 library. 14 14 15 \subsection{Virtual Type} 16 Virtual types only have one change to their structure, the addition of a 17 pointer to the virtual table. This is always the first field so that 18 if it is cast to a supertype the field's location is still known. 19 20 This field is set as part of all new generated constructors. 21 \todo{They only come as part exceptions and don't work.} 22 After the object is created the field is constant. 23 24 However it can be read from, internally it is just a regular field called 25 @virtual_table@. Dereferencing it gives the virtual table and access to the 26 type's virtual members. 27 15 28 \subsection{Virtual Table} 29 Every time a virtual type is defined the new virtual table type must also be 30 defined. 31 32 The unique instance is important because the address of the virtual table 33 instance is used as the identifier for the virtual type. So a pointer to the 34 virtual table and the ID for the virtual type are interchangable. 35 \todo{Unique instances might be going so we will have to talk about the new 36 system instead.} 37 38 The first step in putting it all together is to create the virtual table type. 39 The virtual table type is just a structure and can be described in terms of 40 its fields. The first field is always the parent type ID (or a pointer to 41 the parent virtual table) or 0 (the null pointer). 42 Next are other fields on the parent virtual table are repeated. 43 Finally are the fields used to store any new virtual members of the new 44 The virtual type 45 16 46 The virtual system is accessed through a private constant field inserted at the 17 47 beginning of every virtual type, called the virtual-table pointer. This field 18 48 points at a type's virtual table and is assigned during the object's 19 construction. 49 construction. The address of a virtual table acts as the unique identifier for 20 50 the virtual type, and the first field of a virtual table is a pointer to the 21 parent virtual-table or @0p@. 51 parent virtual-table or @0p@. The remaining fields are duplicated from the 22 52 parent tables in this type's inheritance chain, followed by any fields this type 23 introduces. Parent fields are duplicated so they can be changed ( \CC24 \lstinline[language=c++]|override|), so that references to the dispatched type53 introduces. Parent fields are duplicated so they can be changed (all virtual 54 members are overridable), so that references to the dispatched type 25 55 are replaced with the current virtual type. 26 \PAB{Can you create a simple diagram of the layout?}27 56 % These are always taken by pointer or reference. 57 58 % Simple ascii diragram: 59 \begin{verbatim} 60 parent_pointer \ 61 parent_field0 | 62 ... | Same layout as parent. 63 parent_fieldN / 64 child_field0 65 ... 66 child_fieldN 67 \end{verbatim} 68 \todo{Refine the diagram} 28 69 29 70 % For each virtual type, a virtual table is constructed. This is both a new type … … 34 75 A virtual table is created when the virtual type is created. The name of the 35 76 type is created by mangling the name of the base type. The name of the instance 36 is also generated by name mangling. 77 is also generated by name mangling. The fields are initialized automatically. 37 78 The parent field is initialized by getting the type of the parent field and 38 79 using that to calculate the mangled name of the parent's virtual table type. … … 67 108 \begin{sloppypar} 68 109 Coroutines and threads need instances of @CoroutineCancelled@ and 69 @ThreadCancelled@ respectively to use all of their functionality. 110 @ThreadCancelled@ respectively to use all of their functionality. When a new 70 111 data type is declared with @coroutine@ or @thread@ the forward declaration for 71 112 the instance is created as well. The definition of the virtual table is created … … 80 121 The function is 81 122 \begin{cfa} 82 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent, 123 void * __cfa__virtual_cast( 124 struct __cfa__parent_vtable const * parent, 83 125 struct __cfa__parent_vtable const * const * child ); 84 }85 126 \end{cfa} 86 and it is implemented in the standard library. It takes a pointer to the target 87 type's virtual table and the object pointer being cast. The function performs a 88 linear search starting at the object's virtual-table and walking through the 89 the parent pointers, checking to if it or any of its ancestors are the same as 90 the target-type virtual table-pointer. 91 92 For the generated code, a forward declaration of the virtual works as follows. 93 There is a forward declaration of @__cfa__virtual_cast@ in every \CFA file so 94 it can just be used. The object argument is the expression being cast so that 95 is just placed in the argument list. 96 97 To build the target type parameter, the compiler creates a mapping from 98 concrete type-name -- so for polymorphic types the parameters are filled in -- 99 to virtual table address. Every virtual table declaration is added to the this 100 table; repeats are ignored unless they have conflicting definitions. Note, 101 these declarations do not have to be in scope, but they should usually be 102 introduced as part of the type definition. 103 104 \PAB{I do not understood all of \VRef{s:VirtualSystem}. I think you need to 105 write more to make it clear.} 106 127 and it is implemented in the standard library. The structure reperents the 128 head of a vtable which is the pointer to the parent virtual table. The 129 @parent@ points directly at the parent type virtual table while the @child@ 130 points at the object of the (possibe) child type. 131 132 In terms of the virtual cast expression, @parent@ comes from looking up the 133 type being cast to and @child@ is the result of the expression being cast. 134 Because the complier outputs C code, some type C type casts are also used. 135 The last bit of glue is an map that saves every virtual type the compiler 136 sees. This is used to check the type used in a virtual cast is a virtual 137 type and to get its virtual table. 138 (It also checks for conflicting definitions.) 139 140 Inside the function it is a simple conditional. If the type repersented by 141 @parent@ is or is an ancestor of the type repersented by @*child@ (it 142 requires one more level of derefence to pass through the object) then @child@ 143 is returned, otherwise the null pointer is returned. 144 145 The check itself is preformed is a simple linear search. If the child 146 virtual table or any of its ancestors (which are retreved through the first 147 field of every virtual table) are the same as the parent virtual table then 148 the cast succeeds. 107 149 108 150 \section{Exceptions} … … 121 163 stack. On function entry and return, unwinding is handled directly by the code 122 164 embedded in the function. Usually, the stack-frame size is known statically 123 based on parameter and local variable declarations. 165 based on parameter and local variable declarations. For dynamically-sized 124 166 local variables, a runtime computation is necessary to know the frame 125 167 size. Finally, a function's frame-size may change during execution as local … … 179 221 180 222 To use libunwind, each function must have a personality function and a Language 181 Specific Data Area (LSDA). 223 Specific Data Area (LSDA). The LSDA has the unique information for each 182 224 function to tell the personality function where a function is executing, its 183 current stack frame, and what handlers should be checked. 225 current stack frame, and what handlers should be checked. Theoretically, the 184 226 LSDA can contain any information but conventionally it is a table with entries 185 227 representing regions of the function and what has to be done there during … … 196 238 197 239 The GCC compilation flag @-fexceptions@ causes the generation of an LSDA and 198 attaches its personality function. \PAB{to what is it attached?} However, this 199 flag only handles the cleanup attribute 240 attaches its personality function. However, this 241 flag only handles the cleanup attribute: 242 \todo{Peter: What is attached? Andrew: It uses the .cfi\_personality directive 243 and that's all I know.} 200 244 \begin{cfa} 201 245 void clean_up( int * var ) { ... } 202 int avar __attribute__(( __cleanup(clean_up) ));246 int avar __attribute__(( cleanup(clean_up) )); 203 247 \end{cfa} 204 which is used on a variable and specifies a function, \eg @clean_up@, run when 205 the variable goes out of scope. The function is passed a pointer to the object 206 so it can be used to mimic destructors. However, this feature cannot be used to 207 mimic @try@ statements. 248 which is used on a variable and specifies a function, in this case @clean_up@, 249 run when the variable goes out of scope. 250 The function is passed a pointer to the object being removed from the stack 251 so it can be used to mimic destructors. 252 However, this feature cannot be used to mimic @try@ statements as it cannot 253 control the unwinding. 208 254 209 255 \subsection{Personality Functions} 210 Personality functions have a complex interface specified by libunwind. 256 Personality functions have a complex interface specified by libunwind. This 211 257 section covers some of the important parts of the interface. 212 258 213 A personality function performs four tasks, although not all have to be214 present.259 A personality function can preform different actions depending on how it is 260 called. 215 261 \begin{lstlisting}[language=C,{moredelim=**[is][\color{red}]{@}{@}}] 216 262 typedef _Unwind_Reason_Code (*@_Unwind_Personality_Fn@) ( … … 225 271 \item 226 272 @_UA_SEARCH_PHASE@ specifies a search phase and tells the personality function 227 to check for handlers. 273 to check for handlers. If there is a handler in a stack frame, as defined by 228 274 the language, the personality function returns @_URC_HANDLER_FOUND@; otherwise 229 275 it return @_URC_CONTINUE_UNWIND@. … … 296 342 \end{cfa} 297 343 It also unwinds the stack but it does not use the search phase. Instead another 298 function, the stop function, is used to stop searching. 344 function, the stop function, is used to stop searching. The exception is the 299 345 same as the one passed to raise exception. The extra arguments are the stop 300 346 function and the stop parameter. The stop function has a similar interface as a … … 318 364 319 365 \begin{sloppypar} 320 Its arguments are the same as the paired personality function. 366 Its arguments are the same as the paired personality function. The actions 321 367 @_UA_CLEANUP_PHASE@ and @_UA_FORCE_UNWIND@ are always set when it is 322 368 called. Beyond the libunwind standard, both GCC and Clang add an extra action … … 343 389 strong symbol replacing the sequential version. 344 390 345 % The version of the function defined in @libcfa@ is very simple. It returns a 346 % pointer to a global static variable. With only one stack this global instance 347 % is associated with the only stack. 348 349 For coroutines, @this_exception_context@ accesses the exception context stored 350 at the base of the stack. For threads, @this_exception_context@ uses the 351 concurrency library to access the current stack of the thread or coroutine 352 being executed by the thread, and then accesses the exception context stored at 353 the base of this stack. 391 The sequential @this_exception_context@ returns a hard-coded pointer to the 392 global execption context. 393 The concurrent version adds the exception context to the data stored at the 394 base of each stack. When @this_exception_context@ is called it retrieves the 395 active stack and returns the address of the context saved there. 354 396 355 397 \section{Termination} … … 369 411 per-exception storage. 370 412 371 Exceptions are stored in variable-sized blocks. \PAB{Show a memory layout 372 figure.} The first component is a fixed sized data structure that contains the 413 [Quick ASCII diagram to get started.] 414 \begin{verbatim} 415 Fixed Header | _Unwind_Exception <- pointer target 416 | 417 | Cforall storage 418 | 419 Variable Body | the exception <- fixed offset 420 V ... 421 \end{verbatim} 422 423 Exceptions are stored in variable-sized blocks. 424 The first component is a fixed sized data structure that contains the 373 425 information for libunwind and the exception system. The second component is an 374 426 area of memory big enough to store the exception. Macros with pointer arthritic … … 388 440 exception type. The size and copy function are used immediately to copy an 389 441 exception into managed memory. After the exception is handled the free function 390 is used to clean up the exception and then the entire node is passed to free. 442 is used to clean up the exception and then the entire node is passed to free 443 so the memory can be given back to the heap. 391 444 392 445 \subsection{Try Statements and Catch Clauses} … … 399 452 library. The contents of a try block and the termination handlers are converted 400 453 into functions. These are then passed to the try terminate function and it 401 calls them. This approach puts a try statement in its own functions so that no 402 function has to deal with both termination handlers and destructors. \PAB{I do 403 not understand the previous sentence.} 404 405 This function has some custom embedded assembly that defines \emph{its} 406 personality function and LSDA. The assembly is created with handcrafted C @asm@ 407 statements, which is why there is only one version of it. The personality 408 function is structured so that it can be expanded, but currently it only 409 handles this one function. Notably, it does not handle any destructors so the 410 function is constructed so that it does need to run it. \PAB{I do not 411 understand the previous sentence.} 454 calls them. 455 Because this function is known and fixed (and not an arbitrary function that 456 happens to contain a try statement) this means the LSDA can be generated ahead 457 of time. 458 459 Both the LSDA and the personality function are set ahead of time using 460 embedded assembly. This is handcrafted using C @asm@ statements and contains 461 enough information for the single try statement the function repersents. 412 462 413 463 The three functions passed to try terminate are: … … 419 469 420 470 \item[match function:] This function is called during the search phase and 421 decides if a catch clause matches the termination exception. 471 decides if a catch clause matches the termination exception. It is constructed 422 472 from the conditional part of each handler and runs each check, top to bottom, 423 473 in turn, first checking to see if the exception type matches and then if the … … 428 478 \item[handler function:] This function handles the exception. It takes a 429 479 pointer to the exception and the handler's id and returns nothing. It is called 430 after the cleanup phase. 480 after the cleanup phase. It is constructed by stitching together the bodies of 431 481 each handler and dispatches to the selected handler. 432 482 \end{description} … … 434 484 can be used to create closures, functions that can refer to the state of other 435 485 functions on the stack. This approach allows the functions to refer to all the 436 variables in scope for the function containing the @try@ statement. 486 variables in scope for the function containing the @try@ statement. These 437 487 nested functions and all other functions besides @__cfaehm_try_terminate@ in 438 488 \CFA use the GCC personality function and the @-fexceptions@ flag to generate … … 455 505 handler that matches. If no handler matches then the function returns 456 506 false. Otherwise the matching handler is run; if it completes successfully, the 457 function returns true. Re resume, through the @throwResume;@ statement, cause458 the function to return true.507 function returns true. Rethrowing, through the @throwResume;@ statement, 508 causes the function to return true. 459 509 460 510 % Recursive Resumption Stuff: … … 482 532 providing zero-cost enter/exit using the LSDA. Unfortunately, there is no way 483 533 to return from a libunwind search without installing a handler or raising an 484 error. 534 error. Although workarounds might be possible, they are beyond the scope of 485 535 this thesis. The current resumption implementation has simplicity in its 486 536 favour. … … 503 553 504 554 Cancellation also uses libunwind to do its stack traversal and unwinding, 505 however it uses a different primary function @_Unwind_ForcedUnwind@. 555 however it uses a different primary function @_Unwind_ForcedUnwind@. Details 506 556 of its interface can be found in the \VRef{s:ForcedUnwind}. 507 557 … … 511 561 its main coroutine and the coroutine it is currently executing. 512 562 513 The first check is if the current thread's main and current coroutine do not 514 match, implying a coroutine cancellation; otherwise, it is a thread 515 cancellation. Otherwise it is a main thread cancellation. \PAB{Previous 516 sentence does not make sense.} 563 So if the active thread's main and current coroutine are the same. If they 564 are then the current stack is a thread stack, otherwise it is a coroutine 565 stack. If it is a thread stack then an equality check with the stored main 566 thread pointer and current thread pointer is enough to tell if the current 567 thread is the main thread or not. 517 568 518 569 However, if the threading library is not linked, the sequential execution is on -
doc/theses/andrew_beach_MMath/uw-ethesis.tex
rfeacef9 r5407cdc 74 74 % ====================================================================== 75 75 % D O C U M E N T P R E A M B L E 76 % Specify the document class, default style attributes, page dimensions, etc. 77 % For hyperlinked PDF, suitable for viewing on a computer, use this: 78 \documentclass[letterpaper,12pt,titlepage,oneside,final]{book} 79 80 % For PDF, suitable for double-sided printing, change the PrintVersion 81 % variable below to "true" and use this \documentclass line instead of the 82 % one above: 83 %\documentclass[letterpaper,12pt,titlepage,openright,twoside,final]{book} 84 85 \usepackage{etoolbox} 76 \RequirePackage{etoolbox} 77 78 % Control if this for print (set true) or will stay digital (default). 79 % Print is two sided, digital uses more colours. 80 \newtoggle{printversion} 81 %\toggletrue{printversion} 82 83 \iftoggle{printversion}{% 84 \documentclass[letterpaper,12pt,titlepage,openright,twoside,final]{book} 85 }{% 86 \documentclass[letterpaper,12pt,titlepage,oneside,final]{book} 87 } 86 88 87 89 % Some LaTeX commands I define for my own nomenclature. … … 94 96 % Anything defined here may be redefined by packages added below... 95 97 96 % This package allows if-then-else control structures. 97 \usepackage{ifthen} 98 \newboolean{PrintVersion} 99 \setboolean{PrintVersion}{false} 100 % CHANGE THIS VALUE TO "true" as necessary, to improve printed results for 101 % hard copies by overriding some options of the hyperref package, called below. 102 103 %\usepackage{nomencl} % For a nomenclature (optional; available from ctan.org) 98 % For a nomenclature (optional; available from ctan.org) 99 %\usepackage{nomencl} 104 100 % Lots of math symbols and environments 105 101 \usepackage{amsmath,amssymb,amstext} 106 % For including graphics N.B. pdftex graphics driver 107 \usepackage[pdftex]{graphicx} 102 % For including graphics (must match graphics driver) 103 \usepackage{epic,eepic} 104 \usepackage{graphicx} 108 105 % Removes large sections of the document. 109 106 \usepackage{comment} 110 107 % Adds todos (Must be included after comment.) 111 108 \usepackage{todonotes} 112 113 109 114 110 % Hyperlinks make it very easy to navigate an electronic document. … … 117 113 % Use the "hyperref" package 118 114 % N.B. HYPERREF MUST BE THE LAST PACKAGE LOADED; ADD ADDITIONAL PKGS ABOVE 119 \usepackage[pdftex,pagebackref=true]{hyperref} % with basic options 120 %\usepackage[pdftex,pagebackref=true]{hyperref} 115 \usepackage[pagebackref=true]{hyperref} 121 116 % N.B. pagebackref=true provides links back from the References to the body 122 117 % text. This can cause trouble for printing. … … 128 123 pdffitwindow=false, % window fit to page when opened 129 124 pdfstartview={FitH}, % fits the width of the page to the window 130 % pdftitle={uWaterloo\ LaTeX\ Thesis\ Template}, % title: CHANGE THIS TEXT!131 % pdfauthor={Author}, % author: CHANGE THIS TEXT! and uncomment this line132 % pdfsubject={Subject}, % subject: CHANGE THIS TEXT! and uncomment this line133 % pdfkeywords={keyword1} {key2} {key3}, % optional list of keywords134 125 pdfnewwindow=true, % links in new window 135 126 colorlinks=true, % false: boxed links; true: colored links 136 linkcolor=blue, % color of internal links137 citecolor=green, % color of links to bibliography138 filecolor=magenta, % color of file links139 urlcolor=cyan % color of external links140 127 } 141 % for improved print quality, change some hyperref options 142 \ifthenelse{\boolean{PrintVersion}}{ 143 \hypersetup{ % override some previously defined hyperref options 144 % colorlinks,% 145 citecolor=black,% 146 filecolor=black,% 147 linkcolor=black,% 148 urlcolor=black} 149 }{} % end of ifthenelse (no else) 128 \iftoggle{printversion}{ 129 \hypersetup{ 130 citecolor=black, % colour of links to bibliography 131 filecolor=black, % colour of file links 132 linkcolor=black, % colour of internal links 133 urlcolor=black, % colour of external links 134 } 135 }{ % Digital Version 136 \hypersetup{ 137 citecolor=green, 138 filecolor=magenta, 139 linkcolor=blue, 140 urlcolor=cyan, 141 } 142 } 143 144 \hypersetup{ 145 pdftitle={Exception Handling in Cforall}, 146 pdfauthor={Andrew James Beach}, 147 pdfsubject={Computer Science}, 148 pdfkeywords={programming languages} {exceptions} 149 {language design} {language implementation}, 150 } 150 151 151 152 % Exception to the rule of hyperref being the last add-on package … … 217 218 \pdfstringdefDisableCommands{\def\Cpp{C++}} 218 219 220 % Wrappers for inline code snippits. 221 \newrobustcmd*\codeCFA[1]{\lstinline[language=CFA]{#1}} 222 \newrobustcmd*\codeC[1]{\lstinline[language=C]{#1}} 223 \newrobustcmd*\codeCpp[1]{\lstinline[language=C++]{#1}} 224 \newrobustcmd*\codePy[1]{\lstinline[language=Python]{#1}} 225 219 226 % Colour text, formatted in LaTeX style instead of TeX style. 220 227 \newcommand*\colour[2]{{\color{#1}#2}} -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/links.hpp
rfeacef9 r5407cdc 117 117 } 118 118 119 long long ts() const {119 unsigned long long ts() const { 120 120 return before._links.ts; 121 121 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list.hpp
rfeacef9 r5407cdc 39 39 while( __builtin_expect(ll.exchange(true),false) ) { 40 40 while(ll.load(std::memory_order_relaxed)) 41 asm volatile("pause");41 Pause(); 42 42 } 43 43 /* paranoid */ assert(ll); … … 93 93 && ready.compare_exchange_weak(copy, n + 1) ) 94 94 break; 95 asm volatile("pause");95 Pause(); 96 96 } 97 97 … … 133 133 // Step 1 : make sure no writer are in the middle of the critical section 134 134 while(lock.load(std::memory_order_relaxed)) 135 asm volatile("pause");135 Pause(); 136 136 137 137 // Fence needed because we don't want to start trying to acquire the lock … … 195 195 // to simply lock their own lock and enter. 196 196 while(lock.load(std::memory_order_relaxed)) 197 asm volatile("pause");197 Pause(); 198 198 199 199 // Step 2 : lock per-proc lock … … 204 204 for(uint_fast32_t i = 0; i < s; i++) { 205 205 while(data[i].lock.load(std::memory_order_relaxed)) 206 asm volatile("pause");206 Pause(); 207 207 } 208 208 -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp
rfeacef9 r5407cdc 21 21 target = (target - (target % total)) + total; 22 22 while(waiting < target) 23 asm volatile("pause");23 Pause(); 24 24 25 25 assert(waiting < (1ul << 60)); -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/randbit.cpp
rfeacef9 r5407cdc 123 123 target = (target - (target % total)) + total; 124 124 while(waiting < target) 125 asm volatile("pause");125 Pause(); 126 126 127 127 assert(waiting < (1ul << 60)); -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/relaxed_list.cpp
rfeacef9 r5407cdc 206 206 std::cout << "Total ops : " << ops << "(" << global.in << "i, " << global.out << "o, " << global.empty << "e)\n"; 207 207 #ifndef NO_STATS 208 LIST_VARIANT<Node>::stats_print(std::cout );208 LIST_VARIANT<Node>::stats_print(std::cout, duration); 209 209 #endif 210 210 } … … 368 368 369 369 for(Node * & node : nodes) { 370 node = list.pop(); 371 assert(node); 370 node = nullptr; 371 while(!node) { 372 node = list.pop(); 373 } 372 374 local.crc_out += node->value; 373 375 local.out++; … … 691 693 692 694 for(const auto & n : nodes) { 693 local.valmax = max(local.valmax, size_t(n.value));694 local.valmin = min(local.valmin, size_t(n.value));695 local.valmax = std::max(local.valmax, size_t(n.value)); 696 local.valmin = std::min(local.valmin, size_t(n.value)); 695 697 } 696 698 … … 773 775 try { 774 776 arg = optarg = argv[optind]; 775 nnodes = st oul(optarg, &len);777 nnodes = std::stoul(optarg, &len); 776 778 if(len != arg.size()) { throw std::invalid_argument(""); } 777 779 } catch(std::invalid_argument &) { … … 792 794 try { 793 795 arg = optarg = argv[optind]; 794 nnodes = st oul(optarg, &len);796 nnodes = std::stoul(optarg, &len); 795 797 if(len != arg.size()) { throw std::invalid_argument(""); } 796 798 } catch(std::invalid_argument &) { … … 812 814 try { 813 815 arg = optarg = argv[optind]; 814 nnodes = st oul(optarg, &len);816 nnodes = std::stoul(optarg, &len); 815 817 if(len != arg.size()) { throw std::invalid_argument(""); } 816 818 nslots = nnodes; … … 823 825 try { 824 826 arg = optarg = argv[optind]; 825 nnodes = st oul(optarg, &len);827 nnodes = std::stoul(optarg, &len); 826 828 if(len != arg.size()) { throw std::invalid_argument(""); } 827 829 } catch(std::invalid_argument &) { … … 831 833 try { 832 834 arg = optarg = argv[optind + 1]; 833 nslots = st oul(optarg, &len);835 nslots = std::stoul(optarg, &len); 834 836 if(len != arg.size()) { throw std::invalid_argument(""); } 835 837 } catch(std::invalid_argument &) { … … 884 886 case 'd': 885 887 try { 886 duration = st od(optarg, &len);888 duration = std::stod(optarg, &len); 887 889 if(len != arg.size()) { throw std::invalid_argument(""); } 888 890 } catch(std::invalid_argument &) { … … 893 895 case 't': 894 896 try { 895 nthreads = st oul(optarg, &len);897 nthreads = std::stoul(optarg, &len); 896 898 if(len != arg.size()) { throw std::invalid_argument(""); } 897 899 } catch(std::invalid_argument &) { … … 902 904 case 'q': 903 905 try { 904 nqueues = st oul(optarg, &len);906 nqueues = std::stoul(optarg, &len); 905 907 if(len != arg.size()) { throw std::invalid_argument(""); } 906 908 } catch(std::invalid_argument &) { -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp
rfeacef9 r5407cdc 168 168 for(int i = 0; i < width; i++) { 169 169 int idx = i % hwdith; 170 std::cout << i << " -> " << idx + width << std::endl;171 170 leafs[i].parent = &nodes[ idx ]; 172 171 } … … 174 173 for(int i = 0; i < root; i++) { 175 174 int idx = (i / 2) + hwdith; 176 std::cout << i + width << " -> " << idx + width << std::endl;177 175 nodes[i].parent = &nodes[ idx ]; 178 176 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp
rfeacef9 r5407cdc 159 159 std::cout << "SNZI: " << depth << "x" << width << "(" << mask - 1 << ") " << (sizeof(snzi_t::node) * (root + 1)) << " bytes" << std::endl; 160 160 for(int i = 0; i < root; i++) { 161 std::cout << i << " -> " << (i / base) + width << std::endl;162 161 nodes[i].parent = &nodes[(i / base) + width]; 163 162 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp
rfeacef9 r5407cdc 11 11 #include <sys/sysinfo.h> 12 12 13 #include <x86intrin.h> 14 15 // Barrier from 16 class barrier_t { 17 public: 18 barrier_t(size_t total) 19 : waiting(0) 20 , total(total) 21 {} 22 23 void wait(unsigned) { 24 size_t target = waiting++; 25 target = (target - (target % total)) + total; 26 while(waiting < target) 27 asm volatile("pause"); 28 29 assert(waiting < (1ul << 60)); 30 } 31 32 private: 33 std::atomic<size_t> waiting; 34 size_t total; 35 }; 13 // #include <x86intrin.h> 36 14 37 15 // class Random { … … 102 80 }; 103 81 104 static inline long long rdtscl(void) { 105 unsigned int lo, hi; 106 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 107 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 108 } 82 static inline long long int rdtscl(void) { 83 #if defined( __i386 ) || defined( __x86_64 ) 84 unsigned int lo, hi; 85 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); 86 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); 87 #elif defined( __aarch64__ ) || defined( __arm__ ) 88 // https://github.com/google/benchmark/blob/v1.1.0/src/cycleclock.h#L116 89 long long int virtual_timer_value; 90 asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); 91 return virtual_timer_value; 92 #else 93 #error unsupported hardware architecture 94 #endif 95 } 96 97 #if defined( __i386 ) || defined( __x86_64 ) 98 #define Pause() __asm__ __volatile__ ( "pause" : : : ) 99 #elif defined( __ARM_ARCH ) 100 #define Pause() __asm__ __volatile__ ( "YIELD" : : : ) 101 #else 102 #error unsupported architecture 103 #endif 109 104 110 105 static inline void affinity(int tid) { … … 195 190 } 196 191 192 // Barrier from 193 class barrier_t { 194 public: 195 barrier_t(size_t total) 196 : waiting(0) 197 , total(total) 198 {} 199 200 void wait(unsigned) { 201 size_t target = waiting++; 202 target = (target - (target % total)) + total; 203 while(waiting < target) 204 Pause(); 205 206 assert(waiting < (1ul << 60)); 207 } 208 209 private: 210 std::atomic<size_t> waiting; 211 size_t total; 212 }; 213 197 214 struct spinlock_t { 198 215 std::atomic_bool ll = { false }; … … 201 218 while( __builtin_expect(ll.exchange(true),false) ) { 202 219 while(ll.load(std::memory_order_relaxed)) 203 asm volatile("pause");220 Pause(); 204 221 } 205 222 } -
doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp
rfeacef9 r5407cdc 6 6 #include <memory> 7 7 #include <mutex> 8 #include <thread> 8 9 #include <type_traits> 9 10 … … 11 12 #include "utils.hpp" 12 13 #include "links.hpp" 14 #include "links2.hpp" 13 15 #include "snzi.hpp" 14 16 17 // #include <x86intrin.h> 18 15 19 using namespace std; 20 21 static const long long lim = 2000; 22 static const unsigned nqueues = 2; 23 24 struct __attribute__((aligned(128))) timestamp_t { 25 volatile unsigned long long val = 0; 26 }; 27 28 template<typename node_t> 29 struct __attribute__((aligned(128))) localQ_t { 30 #ifdef NO_MPSC 31 intrusive_queue_t<node_t> list; 32 33 inline auto ts() { return list.ts(); } 34 inline auto lock() { return list.lock.lock(); } 35 inline auto try_lock() { return list.lock.try_lock(); } 36 inline auto unlock() { return list.lock.unlock(); } 37 38 inline auto push( node_t * node ) { return list.push( node ); } 39 inline auto pop() { return list.pop(); } 40 #else 41 mpsc_queue<node_t> queue = {}; 42 spinlock_t _lock = {}; 43 44 inline auto ts() { auto h = queue.head(); return h ? h->_links.ts : 0ull; } 45 inline auto lock() { return _lock.lock(); } 46 inline auto try_lock() { return _lock.try_lock(); } 47 inline auto unlock() { return _lock.unlock(); } 48 49 inline auto push( node_t * node ) { return queue.push( node ); } 50 inline auto pop() { return queue.pop(); } 51 #endif 52 53 54 }; 16 55 17 56 template<typename node_t> … … 25 64 26 65 work_stealing(unsigned _numThreads, unsigned) 27 : numThreads(_numThreads) 28 , lists(new intrusive_queue_t<node_t>[numThreads]) 29 , snzi( std::log2( numThreads / 2 ), 2 ) 66 : numThreads(_numThreads * nqueues) 67 , lists(new localQ_t<node_t>[numThreads]) 68 // , lists(new intrusive_queue_t<node_t>[numThreads]) 69 , times(new timestamp_t[numThreads]) 70 // , snzi( std::log2( numThreads / 2 ), 2 ) 30 71 31 72 { … … 40 81 __attribute__((noinline, hot)) void push(node_t * node) { 41 82 node->_links.ts = rdtscl(); 42 if( node->_links.hint > numThreads ) { 43 node->_links.hint = tls.rng.next() % numThreads; 44 tls.stat.push.nhint++; 83 // node->_links.ts = 1; 84 85 auto & list = *({ 86 unsigned i; 87 #ifdef NO_MPSC 88 do { 89 #endif 90 tls.stats.push.attempt++; 91 // unsigned r = tls.rng1.next(); 92 unsigned r = tls.it++; 93 if(tls.my_queue == outside) { 94 i = r % numThreads; 95 } else { 96 i = tls.my_queue + (r % nqueues); 97 } 98 #ifdef NO_MPSC 99 } while(!lists[i].try_lock()); 100 #endif 101 &lists[i]; 102 }); 103 104 list.push( node ); 105 #ifdef NO_MPSC 106 list.unlock(); 107 #endif 108 // tls.rng2.set_raw_state( tls.rng1.get_raw_state()); 109 // count++; 110 tls.stats.push.success++; 111 } 112 113 __attribute__((noinline, hot)) node_t * pop() { 114 if(tls.my_queue != outside) { 115 // if( tls.myfriend == outside ) { 116 // auto r = tls.rng1.next(); 117 // tls.myfriend = r % numThreads; 118 // // assert(lists[(tls.it % nqueues) + tls.my_queue].ts() >= lists[((tls.it + 1) % nqueues) + tls.my_queue].ts()); 119 // tls.mytime = std::min(lists[(tls.it % nqueues) + tls.my_queue].ts(), lists[((tls.it + 1) % nqueues) + tls.my_queue].ts()); 120 // // times[tls.myfriend].val = 0; 121 // // lists[tls.myfriend].val = 0; 122 // } 123 // // else if(times[tls.myfriend].val == 0) { 124 // // else if(lists[tls.myfriend].val == 0) { 125 // else if(times[tls.myfriend].val < tls.mytime) { 126 // // else if(times[tls.myfriend].val < lists[(tls.it % nqueues) + tls.my_queue].ts()) { 127 // node_t * n = try_pop(tls.myfriend, tls.stats.pop.help); 128 // tls.stats.help++; 129 // tls.myfriend = outside; 130 // if(n) return n; 131 // } 132 // if( tls.myfriend == outside ) { 133 // auto r = tls.rng1.next(); 134 // tls.myfriend = r % numThreads; 135 // tls.mytime = lists[((tls.it + 1) % nqueues) + tls.my_queue].ts(); 136 // } 137 // else { 138 // if(times[tls.myfriend].val + 1000 < tls.mytime) { 139 // node_t * n = try_pop(tls.myfriend, tls.stats.pop.help); 140 // tls.stats.help++; 141 // if(n) return n; 142 // } 143 // tls.myfriend = outside; 144 // } 145 146 node_t * n = local(); 147 if(n) return n; 45 148 } 46 149 47 unsigned i = node->_links.hint; 48 auto & list = lists[i]; 49 list.lock.lock(); 50 51 if(list.push( node )) { 52 snzi.arrive(i); 150 // try steal 151 for(int i = 0; i < 25; i++) { 152 node_t * n = steal(); 153 if(n) return n; 53 154 } 54 155 55 list.lock.unlock(); 56 } 57 58 __attribute__((noinline, hot)) node_t * pop() { 59 node_t * node; 60 while(true) { 61 if(!snzi.query()) { 62 return nullptr; 63 } 64 65 { 66 unsigned i = tls.my_queue; 67 auto & list = lists[i]; 68 if( list.ts() != 0 ) { 69 list.lock.lock(); 70 if((node = try_pop(i))) { 71 tls.stat.pop.local.success++; 72 break; 73 } 74 else { 75 tls.stat.pop.local.elock++; 76 } 77 } 78 else { 79 tls.stat.pop.local.espec++; 80 } 81 } 82 83 tls.stat.pop.steal.tried++; 84 85 int i = tls.rng.next() % numThreads; 86 auto & list = lists[i]; 87 if( list.ts() == 0 ) { 88 tls.stat.pop.steal.empty++; 89 continue; 90 } 91 92 if( !list.lock.try_lock() ) { 93 tls.stat.pop.steal.locked++; 94 continue; 95 } 96 97 if((node = try_pop(i))) { 98 tls.stat.pop.steal.success++; 99 break; 156 return search(); 157 } 158 159 private: 160 inline node_t * local() { 161 unsigned i = (--tls.it % nqueues) + tls.my_queue; 162 node_t * n = try_pop(i, tls.stats.pop.local); 163 if(n) return n; 164 i = (--tls.it % nqueues) + tls.my_queue; 165 return try_pop(i, tls.stats.pop.local); 166 } 167 168 inline node_t * steal() { 169 unsigned i = tls.rng2.prev() % numThreads; 170 return try_pop(i, tls.stats.pop.steal); 171 } 172 173 inline node_t * search() { 174 unsigned offset = tls.rng2.prev(); 175 for(unsigned i = 0; i < numThreads; i++) { 176 unsigned idx = (offset + i) % numThreads; 177 node_t * thrd = try_pop(idx, tls.stats.pop.search); 178 if(thrd) { 179 return thrd; 100 180 } 101 181 } 102 182 103 #if defined(READ) 104 const unsigned f = READ; 105 if(0 == (tls.it % f)) { 106 unsigned i = tls.it / f; 107 lists[i % numThreads].ts(); 108 } 109 // lists[tls.it].ts(); 110 tls.it++; 111 #endif 112 113 114 return node; 115 } 116 117 private: 118 node_t * try_pop(unsigned i) { 183 return nullptr; 184 } 185 186 private: 187 struct attempt_stat_t { 188 std::size_t attempt = { 0 }; 189 std::size_t elock = { 0 }; 190 std::size_t eempty = { 0 }; 191 std::size_t espec = { 0 }; 192 std::size_t success = { 0 }; 193 }; 194 195 node_t * try_pop(unsigned i, attempt_stat_t & stat) { 196 assert(i < numThreads); 119 197 auto & list = lists[i]; 198 stat.attempt++; 199 200 // If the list is empty, don't try 201 if(list.ts() == 0) { stat.espec++; return nullptr; } 202 203 // If we can't get the lock, move on 204 if( !list.try_lock() ) { stat.elock++; return nullptr; } 120 205 121 206 // If list is empty, unlock and retry 122 207 if( list.ts() == 0 ) { 123 list.lock.unlock(); 208 list.unlock(); 209 stat.eempty++; 124 210 return nullptr; 125 211 } 126 212 127 // Actually pop the list 128 node_t * node; 129 bool emptied; 130 std::tie(node, emptied) = list.pop(); 131 assert(node); 132 133 if(emptied) { 134 snzi.depart(i); 135 } 136 137 // Unlock and return 138 list.lock.unlock(); 139 return node; 213 auto node = list.pop(); 214 list.unlock(); 215 stat.success++; 216 #ifdef NO_MPSC 217 // times[i].val = 1; 218 times[i].val = node.first->_links.ts; 219 // lists[i].val = node.first->_links.ts; 220 return node.first; 221 #else 222 times[i].val = node->_links.ts; 223 return node; 224 #endif 140 225 } 141 226 … … 144 229 145 230 static std::atomic_uint32_t ticket; 231 static const unsigned outside = 0xFFFFFFFF; 232 233 static inline unsigned calc_preferred() { 234 unsigned t = ticket++; 235 if(t == 0) return outside; 236 unsigned i = (t - 1) * nqueues; 237 return i; 238 } 239 146 240 static __attribute__((aligned(128))) thread_local struct TLS { 147 Random rng = { int(rdtscl()) }; 148 unsigned my_queue = ticket++; 241 Random rng1 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) }; 242 Random rng2 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) }; 243 unsigned it = 0; 244 unsigned my_queue = calc_preferred(); 245 unsigned myfriend = outside; 246 unsigned long long int mytime = 0; 149 247 #if defined(READ) 150 248 unsigned it = 0; … … 152 250 struct { 153 251 struct { 154 std::size_t nhint = { 0 }; 252 std::size_t attempt = { 0 }; 253 std::size_t success = { 0 }; 155 254 } push; 156 255 struct { 157 struct { 158 std::size_t success = { 0 }; 159 std::size_t espec = { 0 }; 160 std::size_t elock = { 0 }; 161 } local; 162 struct { 163 std::size_t tried = { 0 }; 164 std::size_t locked = { 0 }; 165 std::size_t empty = { 0 }; 166 std::size_t success = { 0 }; 167 } steal; 256 attempt_stat_t help; 257 attempt_stat_t local; 258 attempt_stat_t steal; 259 attempt_stat_t search; 168 260 } pop; 169 } stat; 261 std::size_t help = { 0 }; 262 } stats; 170 263 } tls; 171 264 172 265 private: 173 266 const unsigned numThreads; 174 std::unique_ptr<intrusive_queue_t<node_t> []> lists; 175 __attribute__((aligned(64))) snzi_t snzi; 267 std::unique_ptr<localQ_t<node_t> []> lists; 268 // std::unique_ptr<intrusive_queue_t<node_t> []> lists; 269 std::unique_ptr<timestamp_t []> times; 270 __attribute__((aligned(128))) std::atomic_size_t count; 176 271 177 272 #ifndef NO_STATS … … 179 274 static struct GlobalStats { 180 275 struct { 181 std::atomic_size_t nhint = { 0 }; 276 std::atomic_size_t attempt = { 0 }; 277 std::atomic_size_t success = { 0 }; 182 278 } push; 183 279 struct { 184 280 struct { 281 std::atomic_size_t attempt = { 0 }; 282 std::atomic_size_t elock = { 0 }; 283 std::atomic_size_t eempty = { 0 }; 284 std::atomic_size_t espec = { 0 }; 185 285 std::atomic_size_t success = { 0 }; 186 std::atomic_size_t espec = { 0 }; 187 std::atomic_size_t elock = { 0 }; 286 } help; 287 struct { 288 std::atomic_size_t attempt = { 0 }; 289 std::atomic_size_t elock = { 0 }; 290 std::atomic_size_t eempty = { 0 }; 291 std::atomic_size_t espec = { 0 }; 292 std::atomic_size_t success = { 0 }; 188 293 } local; 189 294 struct { 190 std::atomic_size_t tried = { 0 }; 191 std::atomic_size_t locked = { 0 }; 192 std::atomic_size_t empty = { 0 }; 295 std::atomic_size_t attempt = { 0 }; 296 std::atomic_size_t elock = { 0 }; 297 std::atomic_size_t eempty = { 0 }; 298 std::atomic_size_t espec = { 0 }; 193 299 std::atomic_size_t success = { 0 }; 194 300 } steal; 301 struct { 302 std::atomic_size_t attempt = { 0 }; 303 std::atomic_size_t elock = { 0 }; 304 std::atomic_size_t eempty = { 0 }; 305 std::atomic_size_t espec = { 0 }; 306 std::atomic_size_t success = { 0 }; 307 } search; 195 308 } pop; 309 std::atomic_size_t help = { 0 }; 196 310 } global_stats; 197 311 198 312 public: 199 313 static void stats_tls_tally() { 200 global_stats.push.nhint += tls.stat.push.nhint; 201 global_stats.pop.local.success += tls.stat.pop.local.success; 202 global_stats.pop.local.espec += tls.stat.pop.local.espec ; 203 global_stats.pop.local.elock += tls.stat.pop.local.elock ; 204 global_stats.pop.steal.tried += tls.stat.pop.steal.tried ; 205 global_stats.pop.steal.locked += tls.stat.pop.steal.locked ; 206 global_stats.pop.steal.empty += tls.stat.pop.steal.empty ; 207 global_stats.pop.steal.success += tls.stat.pop.steal.success; 208 } 209 210 static void stats_print(std::ostream & os ) { 314 global_stats.push.attempt += tls.stats.push.attempt; 315 global_stats.push.success += tls.stats.push.success; 316 global_stats.pop.help .attempt += tls.stats.pop.help .attempt; 317 global_stats.pop.help .elock += tls.stats.pop.help .elock ; 318 global_stats.pop.help .eempty += tls.stats.pop.help .eempty ; 319 global_stats.pop.help .espec += tls.stats.pop.help .espec ; 320 global_stats.pop.help .success += tls.stats.pop.help .success; 321 global_stats.pop.local .attempt += tls.stats.pop.local .attempt; 322 global_stats.pop.local .elock += tls.stats.pop.local .elock ; 323 global_stats.pop.local .eempty += tls.stats.pop.local .eempty ; 324 global_stats.pop.local .espec += tls.stats.pop.local .espec ; 325 global_stats.pop.local .success += tls.stats.pop.local .success; 326 global_stats.pop.steal .attempt += tls.stats.pop.steal .attempt; 327 global_stats.pop.steal .elock += tls.stats.pop.steal .elock ; 328 global_stats.pop.steal .eempty += tls.stats.pop.steal .eempty ; 329 global_stats.pop.steal .espec += tls.stats.pop.steal .espec ; 330 global_stats.pop.steal .success += tls.stats.pop.steal .success; 331 global_stats.pop.search.attempt += tls.stats.pop.search.attempt; 332 global_stats.pop.search.elock += tls.stats.pop.search.elock ; 333 global_stats.pop.search.eempty += tls.stats.pop.search.eempty ; 334 global_stats.pop.search.espec += tls.stats.pop.search.espec ; 335 global_stats.pop.search.success += tls.stats.pop.search.success; 336 global_stats.help += tls.stats.help; 337 } 338 339 static void stats_print(std::ostream & os, double duration ) { 211 340 std::cout << "----- Work Stealing Stats -----" << std::endl; 212 341 213 double stealSucc = double(global_stats.pop.steal.success) / global_stats.pop.steal.tried; 214 os << "Push to new Q : " << std::setw(15) << global_stats.push.nhint << "\n"; 215 os << "Local Pop : " << std::setw(15) << global_stats.pop.local.success << "\n"; 216 os << "Steal Pop : " << std::setw(15) << global_stats.pop.steal.success << "(" << global_stats.pop.local.espec << "s, " << global_stats.pop.local.elock << "l)\n"; 217 os << "Steal Success : " << std::setw(15) << stealSucc << "(" << global_stats.pop.steal.tried << " tries)\n"; 218 os << "Steal Fails : " << std::setw(15) << global_stats.pop.steal.empty << "e, " << global_stats.pop.steal.locked << "l\n"; 342 double push_suc = (100.0 * double(global_stats.push.success) / global_stats.push.attempt); 343 double push_len = double(global_stats.push.attempt ) / global_stats.push.success; 344 os << "Push Pick : " << push_suc << " %, len " << push_len << " (" << global_stats.push.attempt << " / " << global_stats.push.success << ")\n"; 345 346 double hlp_suc = (100.0 * double(global_stats.pop.help.success) / global_stats.pop.help.attempt); 347 double hlp_len = double(global_stats.pop.help.attempt ) / global_stats.pop.help.success; 348 os << "Help : " << hlp_suc << " %, len " << hlp_len << " (" << global_stats.pop.help.attempt << " / " << global_stats.pop.help.success << ")\n"; 349 os << "Help Fail : " << global_stats.pop.help.espec << "s, " << global_stats.pop.help.eempty << "e, " << global_stats.pop.help.elock << "l\n"; 350 351 double pop_suc = (100.0 * double(global_stats.pop.local.success) / global_stats.pop.local.attempt); 352 double pop_len = double(global_stats.pop.local.attempt ) / global_stats.pop.local.success; 353 os << "Local : " << pop_suc << " %, len " << pop_len << " (" << global_stats.pop.local.attempt << " / " << global_stats.pop.local.success << ")\n"; 354 os << "Local Fail : " << global_stats.pop.local.espec << "s, " << global_stats.pop.local.eempty << "e, " << global_stats.pop.local.elock << "l\n"; 355 356 double stl_suc = (100.0 * double(global_stats.pop.steal.success) / global_stats.pop.steal.attempt); 357 double stl_len = double(global_stats.pop.steal.attempt ) / global_stats.pop.steal.success; 358 os << "Steal : " << stl_suc << " %, len " << stl_len << " (" << global_stats.pop.steal.attempt << " / " << global_stats.pop.steal.success << ")\n"; 359 os << "Steal Fail : " << global_stats.pop.steal.espec << "s, " << global_stats.pop.steal.eempty << "e, " << global_stats.pop.steal.elock << "l\n"; 360 361 double srh_suc = (100.0 * double(global_stats.pop.search.success) / global_stats.pop.search.attempt); 362 double srh_len = double(global_stats.pop.search.attempt ) / global_stats.pop.search.success; 363 os << "Search : " << srh_suc << " %, len " << srh_len << " (" << global_stats.pop.search.attempt << " / " << global_stats.pop.search.success << ")\n"; 364 os << "Search Fail : " << global_stats.pop.search.espec << "s, " << global_stats.pop.search.eempty << "e, " << global_stats.pop.search.elock << "l\n"; 365 os << "Helps : " << std::setw(15) << std::scientific << global_stats.help / duration << "/sec (" << global_stats.help << ")\n"; 219 366 } 220 367 private: -
doc/user/figures/Cdecl.fig
rfeacef9 r5407cdc 1 #FIG 3.2 Produced by xfig version 3.2. 5b1 #FIG 3.2 Produced by xfig version 3.2.7b 2 2 Landscape 3 3 Center 4 4 Inches 5 Letter 5 Letter 6 6 100.00 7 7 Single … … 19 19 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 20 20 2850 1200 3600 1200 3600 1350 2850 1350 2850 1200 21 4 1 0 50 -1 4 11 0.0000 2 120 90 2925 1325 0\00122 4 1 0 50 -1 4 11 0.0000 2 120 90 3075 1325 1\00123 4 1 0 50 -1 4 11 0.0000 2 120 90 3225 1325 2\00124 4 1 0 50 -1 4 11 0.0000 2 120 90 3375 1325 3\00125 4 1 0 50 -1 4 11 0.0000 2 120 90 3525 1325 4\00121 4 1 0 50 -1 4 11 0.0000 2 120 105 3075 1335 1\001 22 4 1 0 50 -1 4 11 0.0000 2 120 105 3225 1335 2\001 23 4 1 0 50 -1 4 11 0.0000 2 120 105 3375 1335 3\001 24 4 1 0 50 -1 4 11 0.0000 2 120 105 3525 1335 4\001 25 4 1 0 50 -1 4 11 0.0000 2 120 105 2925 1335 0\001 26 26 -6 27 27 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 … … 55 55 1 1 1.00 45.00 60.00 56 56 2550 1275 2850 1275 57 4 1 0 50 -1 4 11 0.0000 2 120 901350 1650 0\00158 4 1 0 50 -1 4 11 0.0000 2 120 901500 1650 1\00159 4 1 0 50 -1 4 11 0.0000 2 120 901650 1650 2\00160 4 1 0 50 -1 4 11 0.0000 2 120 901800 1650 3\00161 4 1 0 50 -1 4 11 0.0000 2 120 901950 1650 4\00157 4 1 0 50 -1 4 11 0.0000 2 120 105 1350 1650 0\001 58 4 1 0 50 -1 4 11 0.0000 2 120 105 1500 1650 1\001 59 4 1 0 50 -1 4 11 0.0000 2 120 105 1650 1650 2\001 60 4 1 0 50 -1 4 11 0.0000 2 120 105 1800 1650 3\001 61 4 1 0 50 -1 4 11 0.0000 2 120 105 1950 1650 4\001 62 62 4 1 0 50 -1 4 11 0.0000 2 90 90 1200 1325 x\001 63 63 4 1 0 50 -1 4 11 0.0000 2 90 90 2400 1325 x\001 -
doc/user/user.tex
rfeacef9 r5407cdc 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Mon Feb 15 13:48:53 202114 %% Update Count : 4 45213 %% Last Modified On : Sun Apr 25 19:03:03 2021 14 %% Update Count : 4951 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 66 66 % math escape $...$ (dollar symbol) 67 67 \input{common} % common CFA document macros 68 \setlength{\gcolumnposn}{3in} 68 69 \CFAStyle % use default CFA format-style 69 70 \lstset{language=CFA} % CFA default lnaguage 70 71 \lstnewenvironment{C++}[1][] % use C++ style 71 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{ @}{@},#1}}72 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{®}{®},#1}} 72 73 {} 73 74 … … 81 82 \newcommand{\Textbf}[2][red]{{\color{#1}{\textbf{#2}}}} 82 83 \newcommand{\Emph}[2][red]{{\color{#1}\textbf{\emph{#2}}}} 83 \newcommand{\R}[1]{ \Textbf{#1}}84 \newcommand{\R C}[1]{\Textbf{\LstBasicStyle{#1}}}84 \newcommand{\R}[1]{{\color{red}#1}} 85 \newcommand{\RB}[1]{\Textbf{#1}} 85 86 \newcommand{\B}[1]{{\Textbf[blue]{#1}}} 86 87 \newcommand{\G}[1]{{\Textbf[OliveGreen]{#1}}} … … 176 177 int main( void ) { 177 178 int x = 0, y = 1, z = 2; 178 @printf( "%d %d %d\n", x, y, z );@179 ®printf( "%d %d %d\n", x, y, z );® 179 180 } 180 181 \end{cfa} … … 185 186 int main( void ) { 186 187 int x = 0, y = 1, z = 2; 187 @sout | x | y | z;@$\indexc{sout}$188 ®sout | x | y | z;®$\indexc{sout}$ 188 189 } 189 190 \end{cfa} … … 194 195 int main() { 195 196 int x = 0, y = 1, z = 2; 196 @cout<<x<<" "<<y<<" "<<z<<endl;@197 ®cout<<x<<" "<<y<<" "<<z<<endl;® 197 198 } 198 199 \end{cfa} … … 224 225 \begin{tabular}{@{}rcccccccc@{}} 225 226 & 2021 & 2016 & 2011 & 2006 & 2001 & 1996 & 1991 & 1986 \\ \hline 226 \R {C} & \R{1} & \R{2} & \R{2} & \R{1} & \R{1} & \R{1} & \R{1} & \R{1}\\227 \RB{C} & \RB{1}& \RB{2}& \RB{2}& \RB{1}& \RB{1}& \RB{1}& \RB{1}& \RB{1}\\ 227 228 Java & 2 & 1 & 1 & 2 & 3 & 28 & - & - \\ 228 229 Python & 3 & 5 & 6 & 7 & 23 & 13 & - & - \\ … … 258 259 The signature feature of \CFA is \emph{\Index{overload}able} \Index{parametric-polymorphic} functions~\cite{forceone:impl,Cormack90,Duggan96} with functions generalized using a ©forall© clause (giving the language its name): 259 260 \begin{cfa} 260 @forall( otype T )@T identity( T val ) { return val; }261 ®forall( otype T )® T identity( T val ) { return val; } 261 262 int forty_two = identity( 42 ); $\C{// T is bound to int, forty\_two == 42}$ 262 263 \end{cfa} … … 322 323 Whereas, \CFA wraps each of these routines into one overloaded name ©abs©: 323 324 \begin{cfa} 324 char @abs@( char );325 extern "C" { int @abs@( int ); } $\C{// use default C routine for int}$326 long int @abs@( long int );327 long long int @abs@( long long int );328 float @abs@( float );329 double @abs@( double );330 long double @abs@( long double );331 float _Complex @abs@( float _Complex );332 double _Complex @abs@( double _Complex );333 long double _Complex @abs@( long double _Complex );325 char ®abs®( char ); 326 extern "C" { int ®abs®( int ); } $\C{// use default C routine for int}$ 327 long int ®abs®( long int ); 328 long long int ®abs®( long long int ); 329 float ®abs®( float ); 330 double ®abs®( double ); 331 long double ®abs®( long double ); 332 float _Complex ®abs®( float _Complex ); 333 double _Complex ®abs®( double _Complex ); 334 long double _Complex ®abs®( long double _Complex ); 334 335 \end{cfa} 335 336 The problem is \Index{name clash} between the C name ©abs© and the \CFA names ©abs©, resulting in two name linkages\index{C linkage}: ©extern "C"© and ©extern "Cforall"© (default). … … 358 359 The 2011 C standard plus GNU extensions. 359 360 \item 360 \Indexc[deletekeywords=inline]{-fgnu89-inline}\index{compilation option!-fgnu89-inline@{\lstinline[deletekeywords=inline] $-fgnu89-inline$}}361 \Indexc[deletekeywords=inline]{-fgnu89-inline}\index{compilation option!-fgnu89-inline@{\lstinline[deletekeywords=inline]{-fgnu89-inline}}} 361 362 Use the traditional GNU semantics for inline routines in C11 mode, which allows inline routines in header files. 362 363 \end{description} … … 530 531 Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism: 531 532 \begin{cfa} 532 int @``@otype = 3; $\C{// make keyword an identifier}$533 double @``@forall = 3.5;533 int ®``®otype = 3; $\C{// make keyword an identifier}$ 534 double ®``®forall = 3.5; 534 535 \end{cfa} 535 536 … … 542 543 // include file uses the CFA keyword "with". 543 544 #if ! defined( with ) $\C{// nesting ?}$ 544 #define with @``@with $\C{// make keyword an identifier}$545 #define with ®``®with $\C{// make keyword an identifier}$ 545 546 #define __CFA_BFD_H__ 546 547 #endif … … 560 561 Numeric constants are extended to allow \Index{underscore}s\index{constant!underscore} as a separator, \eg: 561 562 \begin{cfa} 562 2 @_@147@_@483@_@648; $\C{// decimal constant}$563 56 @_@ul; $\C{// decimal unsigned long constant}$564 0 @_@377; $\C{// octal constant}$565 0x @_@ff@_@ff; $\C{// hexadecimal constant}$566 0x @_@ef3d@_@aa5c; $\C{// hexadecimal constant}$567 3.141 @_@592@_@654; $\C{// floating constant}$568 10 @_@e@_@+1@_@00; $\C{// floating constant}$569 0x @_@ff@_@ff@_@p@_@3; $\C{// hexadecimal floating}$570 0x @_@1.ffff@_@ffff@_@p@_@128@_@l; $\C{// hexadecimal floating long constant}$571 L @_@$"\texttt{\textbackslash{x}}$@_@$\texttt{ff}$@_@$\texttt{ee}"$; $\C{// wide character constant}$563 2®_®147®_®483®_®648; $\C{// decimal constant}$ 564 56®_®ul; $\C{// decimal unsigned long constant}$ 565 0®_®377; $\C{// octal constant}$ 566 0x®_®ff®_®ff; $\C{// hexadecimal constant}$ 567 0x®_®ef3d®_®aa5c; $\C{// hexadecimal constant}$ 568 3.141®_®592®_®654; $\C{// floating constant}$ 569 10®_®e®_®+1®_®00; $\C{// floating constant}$ 570 0x®_®ff®_®ff®_®p®_®3; $\C{// hexadecimal floating}$ 571 0x®_®1.ffff®_®ffff®_®p®_®128®_®l; $\C{// hexadecimal floating long constant}$ 572 L®_®$"\texttt{\textbackslash{x}}$®_®$\texttt{ff}$®_®$\texttt{ee}"$; $\C{// wide character constant}$ 572 573 \end{cfa} 573 574 The rules for placement of underscores are: … … 602 603 Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative. 603 604 \begin{cfa} 604 sout | 1 @\@ 0 | 1 @\@ 1 | 2 @\@ 8 | -4 @\@ 3 | 5 @\@ 3 | 5 @\@ 32 | 5L @\@ 32 | 5L @\@ 64 | -4 @\@ -3 | -4.0 @\@ -3 | 4.0 @\@2.1605 | (1.0f+2.0fi) @\@(3.0f+2.0fi);606 1 1 256 -64 125 @0@ 3273344365508751233 @0@ @0@-0.015625 18.3791736799526 0.264715-1.1922i605 sout | 1 ®\® 0 | 1 ®\® 1 | 2 ®\® 8 | -4 ®\® 3 | 5 ®\® 3 | 5 ®\® 32 | 5L ®\® 32 | 5L ®\® 64 | -4 ®\® -3 | -4.0 ®\® -3 | 4.0 ®\® 2.1 606 | (1.0f+2.0fi) ®\® (3.0f+2.0fi); 607 1 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i 607 608 \end{cfa} 608 609 Note, ©5 \ 32© and ©5L \ 64© overflow, and ©-4 \ -3© is a fraction but stored in an integer so all three computations generate an integral zero. … … 612 613 \begin{cfa} 613 614 forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } ) 614 T ? @\@?( T ep, unsigned int y );615 T ?®\®?( T ep, unsigned int y ); 615 616 forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } ) 616 T ? @\@?( T ep, unsigned long int y );617 T ?®\®?( T ep, unsigned long int y ); 617 618 \end{cfa} 618 619 The user type ©T© must define multiplication, one (©1©), and ©*©. … … 624 625 625 626 626 %\subsection{\texorpdfstring{\protect\lstinline @if@/\protect\lstinline@while@Statement}{if Statement}}627 %\subsection{\texorpdfstring{\protect\lstinline{if}/\protect\lstinline{while} Statement}{if Statement}} 627 628 \subsection{\texorpdfstring{\LstKeywordStyle{if} / \LstKeywordStyle{while} Statement}{if / while Statement}} 628 629 … … 630 631 Declarations in the ©do©-©while© condition are not useful because they appear after the loop body.} 631 632 \begin{cfa} 632 if ( @int x = f()@) ... $\C{// x != 0}$633 if ( @int x = f(), y = g()@) ... $\C{// x != 0 \&\& y != 0}$634 if ( @int x = f(), y = g(); x < y@) ... $\C{// relational expression}$635 if ( @struct S { int i; } x = { f() }; x.i < 4@) $\C{// relational expression}$636 637 while ( @int x = f()@) ... $\C{// x != 0}$638 while ( @int x = f(), y = g()@) ... $\C{// x != 0 \&\& y != 0}$639 while ( @int x = f(), y = g(); x < y@) ... $\C{// relational expression}$640 while ( @struct S { int i; } x = { f() }; x.i < 4@) ... $\C{// relational expression}$633 if ( ®int x = f()® ) ... $\C{// x != 0}$ 634 if ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$ 635 if ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$ 636 if ( ®struct S { int i; } x = { f() }; x.i < 4® ) $\C{// relational expression}$ 637 638 while ( ®int x = f()® ) ... $\C{// x != 0}$ 639 while ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$ 640 while ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$ 641 while ( ®struct S { int i; } x = { f() }; x.i < 4® ) ... $\C{// relational expression}$ 641 642 \end{cfa} 642 643 Unless a relational expression is specified, each variable is compared not equal to 0, which is the standard semantics for the ©if©/©while© expression, and the results are combined using the logical ©&&© operator. … … 645 646 646 647 647 %\section{\texorpdfstring{\protect\lstinline @case@Clause}{case Clause}}648 %\section{\texorpdfstring{\protect\lstinline{case} Clause}{case Clause}} 648 649 \subsection{\texorpdfstring{\LstKeywordStyle{case} Clause}{case Clause}} 649 650 \label{s:caseClause} … … 658 659 \begin{cfa} 659 660 switch ( i ) { 660 case @1, 3, 5@:661 case ®1, 3, 5®: 661 662 ... 662 case @2, 4, 6@:663 case ®2, 4, 6®: 663 664 ... 664 665 } … … 685 686 \end{cquote} 686 687 In addition, subranges are allowed to specify case values.\footnote{ 687 gcc has the same mechanism but awkward syntax, \lstinline @2 ...42@, because a space is required after a number, otherwise the period is a decimal point.}688 gcc has the same mechanism but awkward syntax, \lstinline{2 ...42}, because a space is required after a number, otherwise the period is a decimal point.} 688 689 \begin{cfa} 689 690 switch ( i ) { 690 case @1~5:@$\C{// 1, 2, 3, 4, 5}$691 case ®1~5:® $\C{// 1, 2, 3, 4, 5}$ 691 692 ... 692 case @10~15:@$\C{// 10, 11, 12, 13, 14, 15}$693 case ®10~15:® $\C{// 10, 11, 12, 13, 14, 15}$ 693 694 ... 694 695 } … … 696 697 Lists of subranges are also allowed. 697 698 \begin{cfa} 698 case @1~5, 12~21, 35~42@:699 \end{cfa} 700 701 702 %\section{\texorpdfstring{\protect\lstinline @switch@Statement}{switch Statement}}699 case ®1~5, 12~21, 35~42®: 700 \end{cfa} 701 702 703 %\section{\texorpdfstring{\protect\lstinline{switch} Statement}{switch Statement}} 703 704 \subsection{\texorpdfstring{\LstKeywordStyle{switch} Statement}{switch Statement}} 704 705 … … 740 741 if ( argc == 3 ) { 741 742 // open output file 742 @// open input file743 @} else if ( argc == 2 ) {744 @// open input file (duplicate)745 746 @} else {743 ®// open input file 744 ®} else if ( argc == 2 ) { 745 ®// open input file (duplicate) 746 747 ®} else { 747 748 // usage message 748 749 } … … 755 756 \begin{cfa} 756 757 switch ( i ) { 757 @case 1: case 3: case 5:@// odd values758 ®case 1: case 3: case 5:® // odd values 758 759 // odd action 759 760 break; 760 @case 2: case 4: case 6:@// even values761 ®case 2: case 4: case 6:® // even values 761 762 // even action 762 763 break; … … 774 775 if ( j < k ) { 775 776 ... 776 @case 1:@// transfer into "if" statement777 ®case 1:® // transfer into "if" statement 777 778 ... 778 779 } // if … … 780 781 while ( j < 5 ) { 781 782 ... 782 @case 3:@// transfer into "while" statement783 ®case 3:® // transfer into "while" statement 783 784 ... 784 785 } // while … … 821 822 \begin{cfa} 822 823 switch ( x ) { 823 @int y = 1;@$\C{// unreachable initialization}$824 @x = 7;@$\C{// unreachable code without label/branch}$824 ®int y = 1;® $\C{// unreachable initialization}$ 825 ®x = 7;® $\C{// unreachable code without label/branch}$ 825 826 case 0: ... 826 827 ... 827 @int z = 0;@$\C{// unreachable initialization, cannot appear after case}$828 ®int z = 0;® $\C{// unreachable initialization, cannot appear after case}$ 828 829 z = 2; 829 830 case 1: 830 @x = z;@$\C{// without fall through, z is uninitialized}$831 ®x = z;® $\C{// without fall through, z is uninitialized}$ 831 832 } 832 833 \end{cfa} … … 860 861 Therefore, to preserve backwards compatibility, it is necessary to introduce a new kind of ©switch© statement, called ©choose©, with no implicit fall-through semantics and an explicit fall-through if the last statement of a case-clause ends with the new keyword ©fallthrough©/©fallthru©, \eg: 861 862 \begin{cfa} 862 @choose@( i ) {863 ®choose® ( i ) { 863 864 case 1: case 2: case 3: 864 865 ... 865 @// implicit end of switch (break)866 @case 5:866 ®// implicit end of switch (break) 867 ®case 5: 867 868 ... 868 @fallthru@; $\C{// explicit fall through}$869 ®fallthru®; $\C{// explicit fall through}$ 869 870 case 7: 870 871 ... 871 @break@$\C{// explicit end of switch (redundant)}$872 ®break® $\C{// explicit end of switch (redundant)}$ 872 873 default: 873 874 j = 3; … … 890 891 \begin{cfa} 891 892 switch ( x ) { 892 @int i = 0;@$\C{// allowed only at start}$893 ®int i = 0;® $\C{// allowed only at start}$ 893 894 case 0: 894 895 ... 895 @int j = 0;@$\C{// disallowed}$896 ®int j = 0;® $\C{// disallowed}$ 896 897 case 1: 897 898 { 898 @int k = 0;@$\C{// allowed at different nesting levels}$899 ®int k = 0;® $\C{// allowed at different nesting levels}$ 899 900 ... 900 @case 2:@$\C{// disallow case in nested statements}$901 ®case 2:® $\C{// disallow case in nested statements}$ 901 902 } 902 903 ... … … 915 916 case 3: 916 917 if ( ... ) { 917 ... @fallthru;@// goto case 4918 ... ®fallthru;® // goto case 4 918 919 } else { 919 920 ... … … 930 931 choose ( ... ) { 931 932 case 3: 932 ... @fallthrough common;@933 ... ®fallthrough common;® 933 934 case 4: 934 ... @fallthrough common;@935 936 @common:@// below fallthrough935 ... ®fallthrough common;® 936 937 ®common:® // below fallthrough 937 938 // at case-clause level 938 939 ... // common code for cases 3/4 … … 950 951 for ( ... ) { 951 952 // multi-level transfer 952 ... @fallthru common;@953 ... ®fallthru common;® 953 954 } 954 955 ... 955 956 } 956 957 ... 957 @common:@// below fallthrough958 ®common:® // below fallthrough 958 959 // at case-clause level 959 960 \end{cfa} … … 970 971 \hline 971 972 \begin{cfa} 972 while @($\,$)@{ sout | "empty"; break; }973 do { sout | "empty"; break; } while @($\,$)@;974 for @($\,$)@{ sout | "empty"; break; }975 for ( @0@) { sout | "A"; } sout | "zero";976 for ( @1@) { sout | "A"; }977 for ( @10@) { sout | "A"; }978 for ( @= 10@) { sout | "A"; }979 for ( @1 ~= 10 ~ 2@) { sout | "B"; }980 for ( @10 -~= 1 ~ 2@) { sout | "C"; }981 for ( @0.5 ~ 5.5@) { sout | "D"; }982 for ( @5.5 -~ 0.5@) { sout | "E"; }983 for ( @i; 10@) { sout | i; }984 for ( @i; = 10@) { sout | i; }985 for ( @i; 1 ~= 10 ~ 2@) { sout | i; }986 for ( @i; 10 -~= 1 ~ 2@) { sout | i; }987 for ( @i; 0.5 ~ 5.5@) { sout | i; }988 for ( @i; 5.5 -~ 0.5@) { sout | i; }989 for ( @ui; 2u ~= 10u ~ 2u@) { sout | ui; }990 for ( @ui; 10u -~= 2u ~ 2u@) { sout | ui; }973 while ®($\,$)® { sout | "empty"; break; } 974 do { sout | "empty"; break; } while ®($\,$)®; 975 for ®($\,$)® { sout | "empty"; break; } 976 for ( ®0® ) { sout | "A"; } sout | "zero"; 977 for ( ®1® ) { sout | "A"; } 978 for ( ®10® ) { sout | "A"; } 979 for ( ®= 10® ) { sout | "A"; } 980 for ( ®1 ~= 10 ~ 2® ) { sout | "B"; } 981 for ( ®10 -~= 1 ~ 2® ) { sout | "C"; } 982 for ( ®0.5 ~ 5.5® ) { sout | "D"; } 983 for ( ®5.5 -~ 0.5® ) { sout | "E"; } 984 for ( ®i; 10® ) { sout | i; } 985 for ( ®i; = 10® ) { sout | i; } 986 for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; } 987 for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; } 988 for ( ®i; 0.5 ~ 5.5® ) { sout | i; } 989 for ( ®i; 5.5 -~ 0.5® ) { sout | i; } 990 for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; } 991 for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; } 991 992 enum { N = 10 }; 992 for ( @N@) { sout | "N"; }993 for ( @i; N@) { sout | i; }994 for ( @i; N -~ 0@) { sout | i; }993 for ( ®N® ) { sout | "N"; } 994 for ( ®i; N® ) { sout | i; } 995 for ( ®i; N -~ 0® ) { sout | i; } 995 996 const int start = 3, comp = 10, inc = 2; 996 for ( @i; start ~ comp ~ inc + 1@) { sout | i; }997 for ( i; 1 ~ $\R{@}$) { if ( i > 10 ) break; sout | i; }998 for ( i; 10 -~ $\R{@}$) { if ( i < 0 ) break; sout | i; }999 for ( i; 2 ~ $\R{@}$~ 2 ) { if ( i > 10 ) break; sout | i; }1000 for ( i; 2.1 ~ $\R{@}$ ~ $\R{@}$) { if ( i > 10.5 ) break; sout | i; i += 1.7; }1001 for ( i; 10 -~ $\R{@}$~ 2 ) { if ( i < 0 ) break; sout | i; }1002 for ( i; 12.1 ~ $\R{@}$ ~ $\R{@}$) { if ( i < 2.5 ) break; sout | i; i -= 1.7; }1003 for ( i; 5 @:@ j; -5 ~ $@$) { sout | i | j; }1004 for ( i; 5 @:@ j; -5 -~ $@$) { sout | i | j; }1005 for ( i; 5 @:@ j; -5 ~ $@$~ 2 ) { sout | i | j; }1006 for ( i; 5 @:@ j; -5 -~ $@$~ 2 ) { sout | i | j; }1007 for ( i; 5 @:@ j; -5 ~ $@$) { sout | i | j; }1008 for ( i; 5 @:@ j; -5 -~ $@$) { sout | i | j; }1009 for ( i; 5 @:@ j; -5 ~ $@$~ 2 ) { sout | i | j; }1010 for ( i; 5 @:@ j; -5 -~ $@$~ 2 ) { sout | i | j; }1011 for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 @:@ k; 1.5 ~ $@$) { sout | i | j | k; }1012 for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 @:@ k; 1.5 ~ $@$) { sout | i | j | k; }1013 for ( i; 5 @:@ k; 1.5 ~ $@$ @:@ j; -5 -~ $@$~ 2 ) { sout | i | j | k; }997 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; } 998 for ( i; 1 ~ ®@® ) { if ( i > 10 ) break; sout | i; } 999 for ( i; 10 -~ ®@® ) { if ( i < 0 ) break; sout | i; } 1000 for ( i; 2 ~ ®@® ~ 2 ) { if ( i > 10 ) break; sout | i; } 1001 for ( i; 2.1 ~ ®@® ~ ®@® ) { if ( i > 10.5 ) break; sout | i; i += 1.7; } 1002 for ( i; 10 -~ ®@® ~ 2 ) { if ( i < 0 ) break; sout | i; } 1003 for ( i; 12.1 ~ ®@® ~ ®@® ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; } 1004 for ( i; 5 ®:® j; -5 ~ @ ) { sout | i | j; } 1005 for ( i; 5 ®:® j; -5 -~ @ ) { sout | i | j; } 1006 for ( i; 5 ®:® j; -5 ~ @ ~ 2 ) { sout | i | j; } 1007 for ( i; 5 ®:® j; -5 -~ @ ~ 2 ) { sout | i | j; } 1008 for ( i; 5 ®:® j; -5 ~ @ ) { sout | i | j; } 1009 for ( i; 5 ®:® j; -5 -~ @ ) { sout | i | j; } 1010 for ( i; 5 ®:® j; -5 ~ @ ~ 2 ) { sout | i | j; } 1011 for ( i; 5 ®:® j; -5 -~ @ ~ 2 ) { sout | i | j; } 1012 for ( i; 5 ®:® j; -5 -~ @ ~ 2 ®:® k; 1.5 ~ @ ) { sout | i | j | k; } 1013 for ( i; 5 ®:® j; -5 -~ @ ~ 2 ®:® k; 1.5 ~ @ ) { sout | i | j | k; } 1014 for ( i; 5 ®:® k; 1.5 ~ @ ®:® j; -5 -~ @ ~ 2 ) { sout | i | j | k; } 1014 1015 \end{cfa} 1015 1016 & … … 1089 1090 The loop index is polymorphic in the type of the comparison value N (when the start value is implicit) or the start value M. 1090 1091 \begin{cfa} 1091 for ( i; @5@) $\C[2.5in]{// typeof(5) i; 5 is comparison value}$1092 for ( i; @1.5@~5.5~0.5 ) $\C{// typeof(1.5) i; 1.5 is start value}$1092 for ( i; ®5® ) $\C[2.5in]{// typeof(5) i; 5 is comparison value}$ 1093 for ( i; ®1.5®~5.5~0.5 ) $\C{// typeof(1.5) i; 1.5 is start value}$ 1093 1094 \end{cfa} 1094 1095 \item 1095 1096 An empty conditional implies comparison value of ©1© (true). 1096 1097 \begin{cfa} 1097 while ( $\R{/*empty*/}$ )$\C{// while ( true )}$1098 for ( $\R{/*empty*/}$) $\C{// for ( ; true; )}$1099 do ... while ( $\R{/*empty*/}$ )$\C{// do ... while ( true )}$1098 while ( ®/*empty*/® ) $\C{// while ( true )}$ 1099 for ( ®/*empty*/® ) $\C{// for ( ; true; )}$ 1100 do ... while ( ®/*empty*/® ) $\C{// do ... while ( true )}$ 1100 1101 \end{cfa} 1101 1102 \item 1102 1103 A comparison N is implicit up-to exclusive range [0,N\R{)}. 1103 1104 \begin{cfa} 1104 for ( @5@) $\C{// for ( typeof(5) i; i < 5; i += 1 )}$1105 for ( ®5® ) $\C{// for ( typeof(5) i; i < 5; i += 1 )}$ 1105 1106 \end{cfa} 1106 1107 \item 1107 1108 A comparison ©=© N is implicit up-to inclusive range [0,N\R{]}. 1108 1109 \begin{cfa} 1109 for ( @=@5 ) $\C{// for ( typeof(5) i; i <= 5; i += 1 )}$1110 for ( ®=®5 ) $\C{// for ( typeof(5) i; i <= 5; i += 1 )}$ 1110 1111 \end{cfa} 1111 1112 \item 1112 1113 The up-to range M ©~©\index{~@©~©} N means exclusive range [M,N\R{)}. 1113 1114 \begin{cfa} 1114 for ( 1 @~@5 ) $\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$1115 for ( 1®~®5 ) $\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$ 1115 1116 \end{cfa} 1116 1117 \item 1117 1118 The up-to range M ©~=©\index{~=@©~=©} N means inclusive range [M,N\R{]}. 1118 1119 \begin{cfa} 1119 for ( 1 @~=@5 ) $\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$1120 for ( 1®~=®5 ) $\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$ 1120 1121 \end{cfa} 1121 1122 \item 1122 1123 The down-to range M ©-~©\index{-~@©-~©} N means exclusive range [N,M\R{)}. 1123 1124 \begin{cfa} 1124 for ( 1 @-~@5 ) $\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$1125 for ( 1®-~®5 ) $\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$ 1125 1126 \end{cfa} 1126 1127 \item 1127 1128 The down-to range M ©-~=©\index{-~=@©-~=©} N means inclusive range [N,M\R{]}. 1128 1129 \begin{cfa} 1129 for ( 1 @-~=@5 ) $\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$1130 for ( 1®-~=®5 ) $\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$ 1130 1131 \end{cfa} 1131 1132 \item 1132 1133 ©@© means put nothing in this field. 1133 1134 \begin{cfa} 1134 for ( 1~ $\R{@}$~2 )$\C{// for ( typeof(1) i = 1; /*empty*/; i += 2 )}$1135 for ( 1~®@®~2 ) $\C{// for ( typeof(1) i = 1; /*empty*/; i += 2 )}$ 1135 1136 \end{cfa} 1136 1137 \item 1137 1138 ©:© means start another index. 1138 1139 \begin{cfa} 1139 for ( i; 5 @:@j; 2~12~3 ) $\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}\CRT$1140 for ( i; 5 ®:® j; 2~12~3 ) $\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}\CRT$ 1140 1141 \end{cfa} 1141 1142 \end{itemize} 1142 1143 1143 1144 1144 %\subsection{\texorpdfstring{Labelled \protect\lstinline @continue@ / \protect\lstinline@break@}{Labelled continue / break}}1145 %\subsection{\texorpdfstring{Labelled \protect\lstinline{continue} / \protect\lstinline{break}}{Labelled continue / break}} 1145 1146 \subsection{\texorpdfstring{Labelled \LstKeywordStyle{continue} / \LstKeywordStyle{break} Statement}{Labelled continue / break Statement}} 1146 1147 … … 1157 1158 \begin{lrbox}{\myboxA} 1158 1159 \begin{cfa}[tabsize=3] 1159 @Compound:@{1160 @Try:@try {1161 @For:@for ( ... ) {1162 @While:@while ( ... ) {1163 @Do:@do {1164 @If:@if ( ... ) {1165 @Switch:@switch ( ... ) {1160 ®Compound:® { 1161 ®Try:® try { 1162 ®For:® for ( ... ) { 1163 ®While:® while ( ... ) { 1164 ®Do:® do { 1165 ®If:® if ( ... ) { 1166 ®Switch:® switch ( ... ) { 1166 1167 case 3: 1167 @break Compound@;1168 @break Try@;1169 @break For@; /* or */ @continue For@;1170 @break While@; /* or */ @continue While@;1171 @break Do@; /* or */ @continue Do@;1172 @break If@;1173 @break Switch@;1168 ®break Compound®; 1169 ®break Try®; 1170 ®break For®; /* or */ ®continue For®; 1171 ®break While®; /* or */ ®continue While®; 1172 ®break Do®; /* or */ ®continue Do®; 1173 ®break If®; 1174 ®break Switch®; 1174 1175 } // switch 1175 1176 } else { 1176 ... @break If@; ... // terminate if1177 ... ®break If®; ... // terminate if 1177 1178 } // if 1178 1179 } while ( ... ); // do 1179 1180 } // while 1180 1181 } // for 1181 } @finally@{ // always executed1182 } ®finally® { // always executed 1182 1183 } // try 1183 1184 } // compound … … 1189 1190 { 1190 1191 1191 @ForC:@for ( ... ) {1192 @WhileC:@while ( ... ) {1193 @DoC:@do {1192 ®ForC:® for ( ... ) { 1193 ®WhileC:® while ( ... ) { 1194 ®DoC:® do { 1194 1195 if ( ... ) { 1195 1196 switch ( ... ) { 1196 1197 case 3: 1197 @goto Compound@;1198 @goto Try@;1199 @goto ForB@; /* or */ @goto ForC@;1200 @goto WhileB@; /* or */ @goto WhileC@;1201 @goto DoB@; /* or */ @goto DoC@;1202 @goto If@;1203 @goto Switch@;1204 } @Switch:@;1198 ®goto Compound®; 1199 ®goto Try®; 1200 ®goto ForB®; /* or */ ®goto ForC®; 1201 ®goto WhileB®; /* or */ ®goto WhileC®; 1202 ®goto DoB®; /* or */ ®goto DoC®; 1203 ®goto If®; 1204 ®goto Switch®; 1205 } ®Switch:® ; 1205 1206 } else { 1206 ... @goto If@; ... // terminate if1207 } @If:@;1208 } while ( ... ); @DoB:@;1209 } @WhileB:@;1210 } @ForB:@;1211 1212 1213 } @Compound:@;1207 ... ®goto If®; ... // terminate if 1208 } ®If:®; 1209 } while ( ... ); ®DoB:® ; 1210 } ®WhileB:® ; 1211 } ®ForB:® ; 1212 1213 1214 } ®Compound:® ; 1214 1215 \end{cfa} 1215 1216 \end{lrbox} … … 1240 1241 1241 1242 1242 %\subsection{\texorpdfstring{\protect\lstinline @with@Statement}{with Statement}}1243 %\subsection{\texorpdfstring{\protect\lstinline{with} Statement}{with Statement}} 1243 1244 \subsection{\texorpdfstring{\LstKeywordStyle{with} Statement}{with Statement}} 1244 1245 \label{s:WithStatement} … … 1255 1256 \begin{cfa} 1256 1257 Person p 1257 @p.@name; @p.@address; @p.@sex; $\C{// access containing fields}$1258 ®p.®name; ®p.®address; ®p.®sex; $\C{// access containing fields}$ 1258 1259 \end{cfa} 1259 1260 which extends to multiple levels of qualification for nested aggregates and multiple aggregates. 1260 1261 \begin{cfa} 1261 1262 struct Ticket { ... } t; 1262 @p.name@.first; @p.address@.street; $\C{// access nested fields}$1263 @t.@departure; @t.@cost; $\C{// access multiple aggregate}$1263 ®p.name®.first; ®p.address®.street; $\C{// access nested fields}$ 1264 ®t.®departure; ®t.®cost; $\C{// access multiple aggregate}$ 1264 1265 \end{cfa} 1265 1266 Repeated aggregate qualification is tedious and makes code difficult to read. … … 1284 1285 \begin{C++} 1285 1286 struct S { 1286 char @c@; int @i@; double @d@;1287 char ®c®; int ®i®; double ®d®; 1287 1288 void f( /* S * this */ ) { $\C{// implicit ``this'' parameter}$ 1288 @c@; @i@; @d@; $\C{// this->c; this->i; this->d;}$1289 ®c®; ®i®; ®d®; $\C{// this->c; this->i; this->d;}$ 1289 1290 } 1290 1291 } … … 1294 1295 \begin{cfa} 1295 1296 struct T { 1296 char @m@; int @i@; double @n@; $\C{// derived class variables}$1297 char ®m®; int ®i®; double ®n®; $\C{// derived class variables}$ 1297 1298 }; 1298 1299 struct S : public T { 1299 char @c@; int @i@; double @d@; $\C{// class variables}$1300 void g( double @d@, T & t ) {1301 d; @t@.m; @t@.i; @t@.n; $\C{// function parameter}$1302 c; i; @this->@d; @S::@d; $\C{// class S variables}$1303 m; @T::@i; n; $\C{// class T variables}$1300 char ®c®; int ®i®; double ®d®; $\C{// class variables}$ 1301 void g( double ®d®, T & t ) { 1302 d; ®t®.m; ®t®.i; ®t®.n; $\C{// function parameter}$ 1303 c; i; ®this->®d; ®S::®d; $\C{// class S variables}$ 1304 m; ®T::®i; n; $\C{// class T variables}$ 1304 1305 } 1305 1306 }; … … 1311 1312 Hence, the qualified fields become variables with the side-effect that it is simpler to write, easier to read, and optimize field references in a block. 1312 1313 \begin{cfa} 1313 void f( S & this ) @with ( this )@{ $\C{// with statement}$1314 @c@; @i@; @d@; $\C{// this.c, this.i, this.d}$1314 void f( S & this ) ®with ( this )® { $\C{// with statement}$ 1315 ®c®; ®i®; ®d®; $\C{// this.c, this.i, this.d}$ 1315 1316 } 1316 1317 \end{cfa} 1317 1318 with the generality of opening multiple aggregate-parameters: 1318 1319 \begin{cfa} 1319 void g( S & s, T & t ) @with ( s, t )@{ $\C{// multiple aggregate parameters}$1320 c; @s.@i; d; $\C{// s.c, s.i, s.d}$1321 m; @t.@i; n; $\C{// t.m, t.i, t.n}$1320 void g( S & s, T & t ) ®with ( s, t )® { $\C{// multiple aggregate parameters}$ 1321 c; ®s.®i; d; $\C{// s.c, s.i, s.d}$ 1322 m; ®t.®i; n; $\C{// t.m, t.i, t.n}$ 1322 1323 } 1323 1324 \end{cfa} … … 1338 1339 The difference between parallel and nesting occurs for fields with the same name and type: 1339 1340 \begin{cfa} 1340 struct Q { int @i@; int k; int @m@; } q, w;1341 struct R { int @i@; int j; double @m@; } r, w;1341 struct Q { int ®i®; int k; int ®m®; } q, w; 1342 struct R { int ®i®; int j; double ®m®; } r, w; 1342 1343 with ( r, q ) { 1343 1344 j + k; $\C{// unambiguous, r.j + q.k}$ … … 1372 1373 \begin{cfa} 1373 1374 void ?{}( S & s, int i ) with ( s ) { $\C{// constructor}$ 1374 @s.i = i;@j = 3; m = 5.5; $\C{// initialize fields}$1375 ®s.i = i;® j = 3; m = 5.5; $\C{// initialize fields}$ 1375 1376 } 1376 1377 \end{cfa} … … 1385 1386 and implicitly opened \emph{after} a function-body open, to give them higher priority: 1386 1387 \begin{cfa} 1387 void ?{}( S & s, int @i@ ) with ( s ) @with( $\emph{\R{params}}$ )@{ // syntax not allowed, illustration only1388 s.i = @i@; j = 3; m = 5.5;1388 void ?{}( S & s, int ®i® ) with ( s ) ®with( $\emph{\R{params}}$ )® { // syntax not allowed, illustration only 1389 s.i = ®i®; j = 3; m = 5.5; 1389 1390 } 1390 1391 \end{cfa} … … 1469 1470 For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way: 1470 1471 \begin{cfa} 1471 int @(*@f@())[@5@]@{...}; $\C{// definition}$1472 ... @(*@f@())[@3@]@+= 1; $\C{// usage}$1472 int ®(*®f®())[®5®]® {...}; $\C{// definition}$ 1473 ... ®(*®f®())[®3®]® += 1; $\C{// usage}$ 1473 1474 \end{cfa} 1474 1475 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}). … … 1486 1487 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1487 1488 \begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}] 1488 #[5] *# @int@x1;1489 #* [5]# @int@x2;1490 #[* [5] int]# f @( int p )@;1489 #[5] *# ®int® x1; 1490 #* [5]# ®int® x2; 1491 #[* [5] int]# f®( int p )®; 1491 1492 \end{cfa} 1492 1493 & 1493 1494 \begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}] 1494 @int@#*# x1 #[5]#;1495 @int@#(*#x2#)[5]#;1496 #int (*#f @( int p )@#)[5]#;1495 ®int® #*# x1 #[5]#; 1496 ®int® #(*#x2#)[5]#; 1497 #int (*#f®( int p )®#)[5]#; 1497 1498 \end{cfa} 1498 1499 \end{tabular} … … 1506 1507 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1507 1508 \begin{cfa} 1508 @*@int x, y;1509 ®*® int x, y; 1509 1510 \end{cfa} 1510 1511 & 1511 1512 \begin{cfa} 1512 int @*@x, @*@y;1513 int ®*®x, ®*®y; 1513 1514 \end{cfa} 1514 1515 \end{tabular} … … 1519 1520 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1520 1521 \begin{cfa} 1521 @*@int x;1522 ®*® int x; 1522 1523 int y; 1523 1524 \end{cfa} 1524 1525 & 1525 1526 \begin{cfa} 1526 int @*@x, y;1527 int ®*®x, y; 1527 1528 1528 1529 \end{cfa} … … 1660 1661 & 1661 1662 \begin{cfa} 1662 int * @const@x = (int *)1001663 int * ®const® x = (int *)100 1663 1664 *x = 3; // implicit dereference 1664 int * @const@y = (int *)104;1665 int * ®const® y = (int *)104; 1665 1666 *y = *x; // implicit dereference 1666 1667 \end{cfa} … … 1700 1701 \begin{tabular}{@{}l@{\hspace{2em}}l@{}} 1701 1702 \begin{cfa} 1702 int x, y, @*@ p1, @*@ p2, @**@p3;1703 p1 = @&@x; // p1 points to x1703 int x, y, ®*® p1, ®*® p2, ®**® p3; 1704 p1 = ®&®x; // p1 points to x 1704 1705 p2 = p1; // p2 points to x 1705 p1 = @&@y; // p1 points to y1706 p1 = ®&®y; // p1 points to y 1706 1707 p3 = &p2; // p3 points to p2 1707 1708 \end{cfa} … … 1729 1730 \begin{cfa} 1730 1731 p1 = p2; $\C{// pointer address assignment}$ 1731 @*@p2 = @*@p1 + x; $\C{// pointed-to value assignment / operation}$1732 ®*®p2 = ®*®p1 + x; $\C{// pointed-to value assignment / operation}$ 1732 1733 \end{cfa} 1733 1734 The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©). … … 1745 1746 To support this common case, a reference type is introduced in \CFA, denoted by ©&©, which is the opposite dereference semantics to a pointer type, making the value at the pointed-to location the implicit semantics for dereferencing (similar but not the same as \CC \Index{reference type}s). 1746 1747 \begin{cfa} 1747 int x, y, @&@ r1, @&@ r2, @&&@r3;1748 @&@r1 = &x; $\C{// r1 points to x}$1749 @&@r2 = &r1; $\C{// r2 points to x}$1750 @&@r1 = &y; $\C{// r1 points to y}$1751 @&&@r3 = @&@&r2; $\C{// r3 points to r2}$1748 int x, y, ®&® r1, ®&® r2, ®&&® r3; 1749 ®&®r1 = &x; $\C{// r1 points to x}$ 1750 ®&®r2 = &r1; $\C{// r2 points to x}$ 1751 ®&®r1 = &y; $\C{// r1 points to y}$ 1752 ®&&®r3 = ®&®&r2; $\C{// r3 points to r2}$ 1752 1753 r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); $\C{// implicit dereferencing}$ 1753 1754 \end{cfa} … … 1756 1757 One way to conceptualize a reference is via a rewrite rule, where the compiler inserts a dereference operator before the reference variable for each reference qualifier in a declaration, so the previous example becomes: 1757 1758 \begin{cfa} 1758 @*@r2 = ((@*@r1 + @*@r2) @*@ (@**@r3 - @*@r1)) / (@**@r3 - 15);1759 ®*®r2 = ((®*®r1 + ®*®r2) ®*® (®**®r3 - ®*®r1)) / (®**®r3 - 15); 1759 1760 \end{cfa} 1760 1761 When a reference operation appears beside a dereference operation, \eg ©&*©, they cancel out. … … 1765 1766 For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}): 1766 1767 \begin{cfa} 1767 (& @*@)r1 = &x; $\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}$1768 (&®*®)r1 = &x; $\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}$ 1768 1769 \end{cfa} 1769 1770 Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}): 1770 1771 \begin{cfa} 1771 (&(& @*@)@*@)r3 = &(&@*@)r2; $\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}$1772 (&(&®*®)®*®)r3 = &(&®*®)r2; $\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}$ 1772 1773 \end{cfa} 1773 1774 Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth. … … 1792 1793 const int cx = 5; $\C{// cannot change cx;}$ 1793 1794 const int & cr = cx; $\C{// cannot change what cr points to}$ 1794 @&@cr = &cx; $\C{// can change cr}$1795 ®&®cr = &cx; $\C{// can change cr}$ 1795 1796 cr = 7; $\C{// error, cannot change cx}$ 1796 1797 int & const rc = x; $\C{// must be initialized}$ 1797 @&@rc = &x; $\C{// error, cannot change rc}$1798 ®&®rc = &x; $\C{// error, cannot change rc}$ 1798 1799 const int & const crc = cx; $\C{// must be initialized}$ 1799 1800 crc = 7; $\C{// error, cannot change cx}$ 1800 @&@crc = &cx; $\C{// error, cannot change crc}$1801 ®&®crc = &cx; $\C{// error, cannot change crc}$ 1801 1802 \end{cfa} 1802 1803 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}: … … 1819 1820 \multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}} & \multicolumn{1}{c}{\textbf{C}} \\ 1820 1821 \begin{cfa} 1821 @const@ * @const@* const int ccp;1822 @const@ & @const@& const int ccr;1822 ®const® * ®const® * const int ccp; 1823 ®const® & ®const® & const int ccr; 1823 1824 \end{cfa} 1824 1825 & 1825 1826 \begin{cfa} 1826 const int * @const@ * @const@ccp;1827 const int * ®const® * ®const® ccp; 1827 1828 1828 1829 \end{cfa} … … 1856 1857 \begin{cfa} 1857 1858 int * p = &x; $\C{// assign address of x}$ 1858 @int * p = x;@$\C{// assign value of x}$1859 ®int * p = x;® $\C{// assign value of x}$ 1859 1860 int & r = x; $\C{// must have address of x}$ 1860 1861 \end{cfa} … … 1880 1881 When a pointer/reference parameter has a ©const© value (immutable), it is possible to pass literals and expressions. 1881 1882 \begin{cfa} 1882 void f( @const@int & cr );1883 void g( @const@int * cp );1884 f( 3 ); g( @&@3 );1885 f( x + y ); g( @&@(x + y) );1883 void f( ®const® int & cr ); 1884 void g( ®const® int * cp ); 1885 f( 3 ); g( ®&®3 ); 1886 f( x + y ); g( ®&®(x + y) ); 1886 1887 \end{cfa} 1887 1888 Here, the compiler passes the address to the literal 3 or the temporary for the expression ©x + y©, knowing the argument cannot be changed through the parameter. … … 1894 1895 void f( int & r ); 1895 1896 void g( int * p ); 1896 f( 3 ); g( @&@3 ); $\C{// compiler implicit generates temporaries}$1897 f( x + y ); g( @&@(x + y) ); $\C{// compiler implicit generates temporaries}$1897 f( 3 ); g( ®&®3 ); $\C{// compiler implicit generates temporaries}$ 1898 f( x + y ); g( ®&®(x + y) ); $\C{// compiler implicit generates temporaries}$ 1898 1899 \end{cfa} 1899 1900 Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{ … … 1916 1917 Instead, a routine object should be referenced by a ©const© reference: 1917 1918 \begin{cfa} 1918 @const@ void (@&@fr)( int ) = f; $\C{// routine reference}$1919 ®const® void (®&® fr)( int ) = f; $\C{// routine reference}$ 1919 1920 fr = ... $\C{// error, cannot change code}$ 1920 1921 &fr = ...; $\C{// changing routine reference}$ … … 1978 1979 \begin{cfa} 1979 1980 int x, &r = x, f( int p ); 1980 x = @r@ + f( @r@); $\C{// lvalue reference converts to rvalue}$1981 x = ®r® + f( ®r® ); $\C{// lvalue reference converts to rvalue}$ 1981 1982 \end{cfa} 1982 1983 An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped. 1983 1984 1984 1985 \item 1985 lvalue to reference conversion: \lstinline[deletekeywords=lvalue] @lvalue-type cv1 T@converts to ©cv2 T &©, which allows implicitly converting variables to references.1986 \begin{cfa} 1987 int x, &r = @x@, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$1988 f( @x@); $\C{// lvalue variable (int) convert to reference (int \&)}$1986 lvalue to reference conversion: \lstinline[deletekeywords=lvalue]{lvalue-type cv1 T} converts to ©cv2 T &©, which allows implicitly converting variables to references. 1987 \begin{cfa} 1988 int x, &r = ®x®, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$ 1989 f( ®x® ); $\C{// lvalue variable (int) convert to reference (int \&)}$ 1989 1990 \end{cfa} 1990 1991 Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost. … … 1996 1997 \begin{cfa} 1997 1998 int x, & f( int & p ); 1998 f( @x + 3@); $\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}$1999 @&f@(...) = &x; $\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT$1999 f( ®x + 3® ); $\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}$ 2000 ®&f®(...) = &x; $\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT$ 2000 2001 \end{cfa} 2001 2002 In both case, modifications to the temporary are inaccessible (\Index{warning}). … … 2164 2165 2165 2166 2167 \section{Enumeration} 2168 2169 An \newterm{enumeration} is a compile-time mechanism to alias names to constants, like ©typedef© is a mechanism to alias names to types. 2170 Its purpose is to define a restricted-value type providing code-readability and maintenance -- changing an enum's value automatically updates all name usages during compilation. 2171 2172 An enumeration type is a set of names, each called an \newterm{enumeration constant} (shortened to \newterm{enum}) aliased to a fixed value (constant). 2173 \begin{cfa} 2174 enum Days { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; // enumeration type definition, set of 7 names & values 2175 Days days = Mon; // enumeration type declaration and initialization 2176 \end{cfa} 2177 The set of enums are injected into the variable namespace at the definition scope. 2178 Hence, enums may be overloaded with enum/variable/function names. 2179 \begin{cfa} 2180 enum Foo { Bar }; 2181 enum Goo { Bar }; $\C[1.75in]{// overload Foo.Bar}$ 2182 int Foo; $\C{// type/variable separate namespace}$ 2183 double Bar; $\C{// overload Foo.Bar, Goo.Bar}\CRT$ 2184 \end{cfa} 2185 An anonymous enumeration injects enums with specific values into a scope. 2186 \begin{cfa} 2187 enum { Prime = 103, BufferSize = 1024 }; 2188 \end{cfa} 2189 An enumeration is better than using C \Index{preprocessor} or constant declarations. 2190 \begin{cquote} 2191 \begin{tabular}{@{}l@{\hspace{4em}}l@{}} 2192 \begin{cfa} 2193 #define Mon 0 2194 ... 2195 #define Sun 6 2196 \end{cfa} 2197 & 2198 \begin{cfa} 2199 const int Mon = 0, 2200 ..., 2201 Sun = 6; 2202 \end{cfa} 2203 \end{tabular} 2204 \end{cquote} 2205 because the enumeration is succinct, has automatic numbering, can appear in ©case© labels, does not use storage, and is part of the language type-system. 2206 Finally, the type of an enum is implicitly or explicitly specified and the constant value can be implicitly or explicitly specified. 2207 Note, enum values may be repeated in an enumeration. 2208 2209 2210 \subsection{Enum type} 2211 2212 The type of enums can be any type, and an enum's value comes from this type. 2213 Because an enum is a constant, it cannot appear in a mutable context, \eg ©Mon = Sun© is disallowed, and has no address (it is an rvalue). 2214 Therefore, an enum is automatically converted to its constant's base-type, \eg comparing/printing an enum compares/prints its value rather than the enum name; 2215 there is no mechanism to print the enum name. 2216 2217 The default enum type is ©int©. 2218 Hence, ©Days© is the set type ©Mon©, ©Tue©, ...\,, ©Sun©, while the type of each enum is ©int© and each enum represents a fixed integral value. 2219 If no values are specified for an integral enum type, the enums are automatically numbered by one from left to right starting at zero. 2220 Hence, the value of enum ©Mon© is 0, ©Tue© is 1, ...\,, ©Sun© is 6. 2221 If an enum value is specified, numbering continues by one from that value for subsequent unnumbered enums. 2222 If an enum value is an expression, the compiler performs constant-folding to obtain a constant value. 2223 2224 \CFA allows other integral types with associated values. 2225 \begin{cfa} 2226 enum( ®char® ) Letter { A ®= 'A'®, B, C, I ®= 'I'®, J, K }; 2227 enum( ®long long int® ) BigNum { X = 123_456_789_012_345, Y = 345_012_789_456_123 }; 2228 \end{cfa} 2229 For enumeration ©Letter©, enum ©A©'s value is explicitly set to ©'A'©, with ©B© and ©C© implicitly numbered with increasing values from ©'A'©, and similarly for enums ©I©, ©J©, and ©K©. 2230 2231 Non-integral enum types must be explicitly initialized, \eg ©double© is not automatically numbered by one. 2232 \begin{cfa} 2233 // non-integral numeric 2234 enum( ®double® ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 } 2235 // pointer 2236 enum( ®char *® ) Name { Fred = "Fred", Mary = "Mary", Jane = "Jane" }; 2237 int i, j, k; 2238 enum( ®int *® ) ptr { I = &i, J = &j, K = &k }; 2239 enum( ®int &® ) ref { I = i, J = j, K = k }; 2240 // tuple 2241 enum( ®[int, int]® ) { T = [ 1, 2 ] }; 2242 // function 2243 void f() {...} void g() {...} 2244 enum( ®void (*)()® ) funs { F = f, F = g }; 2245 // aggregate 2246 struct S { int i, j; }; 2247 enum( ®S® ) s { A = { 3, 4 }, B = { 7, 8 } }; 2248 // enumeration 2249 enum( ®Letter® ) Greek { Alph = A, Beta = B, /* more enums */ }; // alphabet intersection 2250 \end{cfa} 2251 Enumeration ©Greek© may have more or less enums than ©Letter©, but the enum values \emph{must} be from ©Letter©. 2252 Therefore, ©Greek© enums are a subset of type ©Letter© and are type compatible with enumeration ©Letter©, but ©Letter© enums are not type compatible with enumeration ©Greek©. 2253 2254 The following examples illustrate the difference between the enumeration type and the type of its enums. 2255 \begin{cfa} 2256 Math m = PI; $\C[1.5in]{// allowed}$ 2257 double d = PI; $\C{// allowed, conversion to base type}$ 2258 m = E; $\C{// allowed}$ 2259 m = Alph; $\C{// {\color{red}disallowed}}$ 2260 m = 3.141597; $\C{// {\color{red}disallowed}}$ 2261 d = m; $\C{// allowed}$ 2262 d = Alph; $\C{// {\color{red}disallowed}}$ 2263 Letter l = A; $\C{// allowed}$ 2264 Greek g = Alph; $\C{// allowed}$ 2265 l = Alph; $\C{// allowed, conversion to base type}$ 2266 g = A; $\C{// {\color{red}disallowed}}\CRT$ 2267 \end{cfa} 2268 2269 A constructor \emph{cannot} be used to initialize enums because a constructor executes at runtime. 2270 A fallback is explicit C-style initialization using ©@=©. 2271 \begin{cfa} 2272 enum( struct vec3 ) Axis { Up @= { 1, 0, 0 }, Left @= { 0, 1, 0 }, Front @= { 0, 0, 1 } } 2273 \end{cfa} 2274 Finally, enumeration variables are assignable and comparable only if the appropriate operators are defined for its enum type. 2275 2276 2277 \subsection{Inheritance} 2278 2279 \Index{Plan-9}\index{inheritance!enumeration} inheritance may be used with enumerations. 2280 \begin{cfa} 2281 enum( char * ) Name2 { ®inline Name®, Jack = "Jack", Jill = "Jill" }; 2282 enum ®/* inferred */® Name3 { ®inline Name2®, Sue = "Sue", Tom = "Tom" }; 2283 \end{cfa} 2284 Enumeration ©Name2© inherits all the enums and their values from enumeration ©Name© by containment, and a ©Name© enumeration is a subtype of enumeration ©Name2©. 2285 Note, enums must be unique in inheritance but enum values may be repeated. 2286 The enum type for the inheriting type must be the same as the inherited type; 2287 hence the enum type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for ©Name3©. 2288 When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important, \eg the placement of ©Sue© and ©Tom© before or after ©inline Name2©. 2289 2290 Specifically, the inheritance relationship for ©Name©s is: 2291 \begin{cfa} 2292 Name $\(\subseteq\)$ Name2 $\(\subseteq\)$ Name3 $\(\subseteq\)$ const char * // enum type of Name 2293 \end{cfa} 2294 Hence, given 2295 \begin{cfa} 2296 void f( Name ); 2297 void g( Name2 ); 2298 void h( Name3 ); 2299 void j( const char * ); 2300 \end{cfa} 2301 the following calls are valid 2302 \begin{cfa} 2303 f( Fred ); 2304 g( Fred ); g( Jill ); 2305 h( Fred ); h( Jill ); h( Sue ); 2306 j( Fred ); j( Jill ); j( Sue ); j( 'W' ); 2307 \end{cfa} 2308 Note, the validity of calls is the same for call-by-reference as for call-by-value, and ©const© restrictions are the same as for other types. 2309 2310 Enums cannot be created at runtime, so inheritence problems, such as contra-variance do not apply. 2311 Only instances of the enum base-type may be created at runtime. 2312 2313 \begin{comment} 2314 The invariance of references, as I show at the bottom, is easy to overlook. Not shown, but on the same topic, is that returns work in the opposite direction as parameters. Hopefully our existing type rules already know both those facts, so that we'd only have to provide the rules that I suggest using the by-value parameters. 2315 2316 The Fred, Jack, and Mary declarations are picked verbatim from our earlier whiteboard, just repeated here for reference. 2317 2318 \begin{cfa} 2319 // Fred is a subset of char * 2320 enum( char *) Fred { A = "A", B = "B", C = "C" }; 2321 // Jack is a subset of Fred 2322 enum( enum Fred ) Jack { W = A, Y = C}; 2323 // Mary is a superset of Fred 2324 enum Mary { inline Fred, D = "hello" }; 2325 2326 // Demonstrating invariance of references 2327 2328 [void] frcs( & * char x ) { char * x0 = x; x = "bye"; } 2329 [void] frf ( & Fred x ) { Fred x0 = x; x = B; } 2330 [void] frj ( & Jack x ) { Jack x0 = x; x = W; } 2331 [void] frm ( & Mary x ) { Mary x0 = x; x = D; } 2332 2333 char * vcs; 2334 Fred vf; 2335 Jack vj; 2336 Mary vm; 2337 2338 // all variant calls: bad (here are noteworthy examples) 2339 frcs( vf ); // can't assign "bye" to vf 2340 frm ( vf ); // can't assign D to vf 2341 frf ( vj ); // can't assign B to vj 2342 vf = B ; frj ( vf ); // can't assign B to frj.x0 2343 vcs = "bye"; frf ( vcs ); // can't assign "bye" to frf.x0 2344 \end{cfa} 2345 2346 This example is really great. However, I think it's work explicitly doing one with ©const &©. 2347 \end{comment} 2348 2349 2166 2350 \section{Routine Definition} 2167 2351 2168 \CFA alsosupports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax.2352 \CFA supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax. 2169 2353 The point of the new syntax is to allow returning multiple values from a routine~\cite{Galletly96,CLU}, \eg: 2170 2354 \begin{cfa} 2171 @[ int o1, int o2, char o3 ]@f( int i1, char i2, char i3 ) {2355 ®[ int o1, int o2, char o3 ]® f( int i1, char i2, char i3 ) { 2172 2356 $\emph{routine body}$ 2173 2357 } 2174 2358 \end{cfa} 2175 2359 where routine ©f© has three output (return values) and three input parameters. 2176 Existing C syntax cannot be extended with multiple return types because it is impossible to embed a single routine name within multiple return type 2360 Existing C syntax cannot be extended with multiple return types because it is impossible to embed a single routine name within multiple return type-specifications. 2177 2361 2178 2362 In detail, the brackets, ©[]©, enclose the result type, where each return value is named and that name is a local variable of the particular return type.\footnote{ … … 2181 2365 Declaration qualifiers can only appear at the start of a routine definition, \eg: 2182 2366 \begin{cfa} 2183 @extern@[ int x ] g( int y ) {$\,$}2367 ®extern® [ int x ] g( int y ) {$\,$} 2184 2368 \end{cfa} 2185 2369 Lastly, if there are no output parameters or input parameters, the brackets and/or parentheses must still be specified; … … 2200 2384 int (*f(x))[ 5 ] int x; {} 2201 2385 \end{cfa} 2202 The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter xof type array of 5 integers.2386 The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter ©x© of type array of 5 integers. 2203 2387 Since the strings overlap starting with the open bracket, ©[©, there is an ambiguous interpretation for the string. 2204 2388 As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity: … … 2239 2423 \begin{minipage}{\linewidth} 2240 2424 \begin{cfa} 2241 @[ int x, int y ]@f() {2425 ®[ int x, int y ]® f() { 2242 2426 int z; 2243 2427 ... x = 0; ... y = z; ... 2244 @return;@$\C{// implicitly return x, y}$2428 ®return;® $\C{// implicitly return x, y}$ 2245 2429 } 2246 2430 \end{cfa} … … 2574 2758 2575 2759 int fred() { 2576 s.t.c = @S.@R; // type qualification2577 struct @S.@T t = { @S.@R, 1, 2 };2578 enum @S.@C c;2579 union @S.T.@U u;2760 s.t.c = ®S.®R; // type qualification 2761 struct ®S.®T t = { ®S.®R, 1, 2 }; 2762 enum ®S.®C c; 2763 union ®S.T.®U u; 2580 2764 } 2581 2765 \end{cfa} … … 2603 2787 qsort( ia, size ); $\C{// sort ascending order using builtin ?<?}$ 2604 2788 { 2605 @int ?<?( int x, int y ) { return x > y; }@$\C{// nested routine}$2789 ®int ?<?( int x, int y ) { return x > y; }® $\C{// nested routine}$ 2606 2790 qsort( ia, size ); $\C{// sort descending order by local redefinition}$ 2607 2791 } … … 2613 2797 \begin{cfa} 2614 2798 [* [int]( int )] foo() { $\C{// int (* foo())( int )}$ 2615 int @i@= 7;2799 int ®i® = 7; 2616 2800 int bar( int p ) { 2617 @i@+= 1; $\C{// dependent on local variable}$2618 sout | @i@;2801 ®i® += 1; $\C{// dependent on local variable}$ 2802 sout | ®i®; 2619 2803 } 2620 2804 return bar; $\C{// undefined because of local dependence}$ … … 2634 2818 In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call. 2635 2819 \begin{cfa} 2636 f( @2, x, 3 + i@); $\C{// element list}$2820 f( ®2, x, 3 + i® ); $\C{// element list}$ 2637 2821 \end{cfa} 2638 2822 A list of elements is called a \newterm{tuple}, and is different from a \Index{comma expression}. … … 2747 2931 In \CFA, it is possible to overcome this restriction by declaring a \newterm{tuple variable}. 2748 2932 \begin{cfa} 2749 [int, int] @qr@= div( 13, 5 ); $\C{// initialize tuple variable}$2750 printf( "%d %d\n", @qr@); $\C{// print quotient/remainder}$2933 [int, int] ®qr® = div( 13, 5 ); $\C{// initialize tuple variable}$ 2934 printf( "%d %d\n", ®qr® ); $\C{// print quotient/remainder}$ 2751 2935 \end{cfa} 2752 2936 It is now possible to match the multiple return-values to a single variable, in much the same way as \Index{aggregation}. … … 3412 3596 \begin{cfa} 3413 3597 int x = 1, y = 2, z = 3; 3414 sout | x @|@ y @|@z;3598 sout | x ®|® y ®|® z; 3415 3599 \end{cfa} 3416 3600 & 3417 3601 \begin{cfa} 3418 3602 3419 cout << x @<< " "@ << y @<< " "@<< z << endl;3603 cout << x ®<< " "® << y ®<< " "® << z << endl; 3420 3604 \end{cfa} 3421 3605 & … … 3426 3610 \\ 3427 3611 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3428 1 @ @2@ @33612 1® ®2® ®3 3429 3613 \end{cfa} 3430 3614 & 3431 3615 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3432 1 @ @2@ @33616 1® ®2® ®3 3433 3617 \end{cfa} 3434 3618 & 3435 3619 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3436 1 @ @2@ @33620 1® ®2® ®3 3437 3621 \end{cfa} 3438 3622 \end{tabular} 3439 3623 \end{cquote} 3440 3624 The \CFA form has half the characters of the \CC form, and is similar to \Index*{Python} I/O with respect to implicit separators and newline. 3441 Similar simplification occurs for \Index{tuple} I/O, which flattens the tuple and prints each value separated by ``\lstinline[showspaces=true] @, @''.3625 Similar simplification occurs for \Index{tuple} I/O, which flattens the tuple and prints each value separated by ``\lstinline[showspaces=true]{, }''. 3442 3626 \begin{cfa} 3443 3627 [int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 4, [ 5, 6 ] ]; … … 3445 3629 \end{cfa} 3446 3630 \begin{cfa}[showspaces=true,aboveskip=0pt] 3447 1 @, @2@, @3 4@, @5@, @63631 1®, ®2®, ®3 4®, ®5®, ®6 3448 3632 \end{cfa} 3449 3633 Finally, \CFA uses the logical-or operator for I/O as it is the lowest-priority \emph{overloadable} operator, other than assignment. … … 3454 3638 & 3455 3639 \begin{cfa} 3456 sout | x * 3 | y + 1 | z << 2 | x == y | @(@x | y@)@ | @(@x || y@)@ | @(@x > z ? 1 : 2@)@;3640 sout | x * 3 | y + 1 | z << 2 | x == y | ®(®x | y®)® | ®(®x || y®)® | ®(®x > z ? 1 : 2®)®; 3457 3641 \end{cfa} 3458 3642 \\ … … 3460 3644 & 3461 3645 \begin{cfa} 3462 cout << x * 3 << y + 1 << @(@z << 2@)@ << @(@x == y@)@ << @(@x | y@)@ << @(@x || y@)@ << @(@x > z ? 1 : 2@)@<< endl;3646 cout << x * 3 << y + 1 << ®(®z << 2®)® << ®(®x == y®)® << ®(®x | y®)® << ®(®x || y®)® << ®(®x > z ? 1 : 2®)® << endl; 3463 3647 \end{cfa} 3464 3648 \\ … … 3495 3679 \\ 3496 3680 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3497 @1@ @2.5@ @A@ 3681 ®1® ®2.5® ®A® 3498 3682 3499 3683 … … 3501 3685 & 3502 3686 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3503 @1@ @2.5@ @A@ 3687 ®1® ®2.5® ®A® 3504 3688 3505 3689 … … 3507 3691 & 3508 3692 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3509 @1@ 3510 @2.5@ 3511 @A@ 3693 ®1® 3694 ®2.5® 3695 ®A® 3512 3696 \end{cfa} 3513 3697 \end{tabular} … … 3545 3729 3546 3730 \item 3547 A separator does not appear before a C string starting with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \LstStringStyle{,.;!?)]\}\%\textcent\guillemotright}, where \LstStringStyle{\guillemotright} a closing citation mark.3731 A separator does not appear before a C string starting with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \LstStringStyle{,.;!?)]\}\%\textcent\guillemotright}, where \LstStringStyle{\guillemotright} is a closing citation mark. 3548 3732 \begin{cfa} 3549 3733 sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x" … … 3551 3735 \end{cfa} 3552 3736 \begin{cfa}[showspaces=true] 3553 1 @,@ x 2@.@ x 3@;@ x 4@!@ x 5@?@ x 6@%@ x 7$\R{\LstStringStyle{\textcent}}$ x 8$\R{\LstStringStyle{\guillemotright}}$ x 9@)@ x 10@]@ x 11@}@x3737 1®,® x 2®.® x 3®;® x 4®!® x 5®?® x 6®%® x 7$\R{\LstStringStyle{\textcent}}$ x 8$\R{\LstStringStyle{\guillemotright}}$ x 9®)® x 10®]® x 11®}® x 3554 3738 \end{cfa} 3555 3739 … … 3558 3742 %$ 3559 3743 \begin{cfa} 3560 sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $ " | 5 | "x $\LstStringStyle{\textsterling}$" | 6 | "x $\LstStringStyle{\textyen}$"3744 sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $\LstStringStyle{\textdollar}$" | 5 | "x $\LstStringStyle{\textsterling}$" | 6 | "x $\LstStringStyle{\textyen}$" 3561 3745 | 7 | "x $\LstStringStyle{\textexclamdown}$" | 8 | "x $\LstStringStyle{\textquestiondown}$" | 9 | "x $\LstStringStyle{\guillemotleft}$" | 10; 3562 3746 \end{cfa} 3563 3747 %$ 3564 3748 \begin{cfa}[showspaces=true] 3565 x @(@1 x @[@2 x @{@3 x @=@4 x $\LstStringStyle{\textdollar}$5 x $\R{\LstStringStyle{\textsterling}}$6 x $\R{\LstStringStyle{\textyen}}$7 x $\R{\LstStringStyle{\textexclamdown}}$8 x $\R{\LstStringStyle{\textquestiondown}}$9 x $\R{\LstStringStyle{\guillemotleft}}$103749 x ®(®1 x ®[®2 x ®{®3 x ®=®4 x $\LstStringStyle{\textdollar}$5 x $\R{\LstStringStyle{\textsterling}}$6 x $\R{\LstStringStyle{\textyen}}$7 x $\R{\LstStringStyle{\textexclamdown}}$8 x $\R{\LstStringStyle{\textquestiondown}}$9 x $\R{\LstStringStyle{\guillemotleft}}$10 3566 3750 \end{cfa} 3567 3751 %$ 3568 3752 3569 3753 \item 3570 A sep erator does not appear before/after a C string starting/ending with the \Index*{ASCII} quote or whitespace characters: \lstinline[basicstyle=\tt,showspaces=true]{`'": \t\v\f\r\n}3754 A separator does not appear before/after a C string starting/ending with the \Index*{ASCII} quote or whitespace characters: \lstinline[basicstyle=\tt,showspaces=true]{`'": \t\v\f\r\n} 3571 3755 \begin{cfa} 3572 3756 sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx"; 3573 3757 \end{cfa} 3574 3758 \begin{cfa}[showspaces=true,showtabs=true] 3575 x @`@1@`@x$\R{\texttt{'}}$2$\R{\texttt{'}}$x$\R{\texttt{"}}$3$\R{\texttt{"}}$x@:@4@:@x@ @5@ @x@ @6@ @x3759 x®`®1®`®x$\R{\texttt{'}}$2$\R{\texttt{'}}$x$\R{\texttt{"}}$3$\R{\texttt{"}}$x®:®4®:®x® ®5® ®x® ®6® ®x 3576 3760 \end{cfa} 3577 3761 … … 3582 3766 \end{cfa} 3583 3767 \begin{cfa}[showspaces=true,showtabs=true] 3584 x ( @ @1@ @) x 2@ @, x 3@ @:x:@ @43768 x (® ®1® ®) x 2® ®, x 3® ®:x:® ®4 3585 3769 \end{cfa} 3586 3770 \end{enumerate} … … 3595 3779 \Indexc{sepSet}\index{manipulator!sepSet@©sepSet©} and \Indexc{sep}\index{manipulator!sep@©sep©}/\Indexc{sepGet}\index{manipulator!sepGet@©sepGet©} set and get the separator string. 3596 3780 The separator string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters). 3597 \begin{cfa}[escapechar=off,belowskip=0pt] 3598 sepSet( sout, ", $" ); $\C{// set separator from " " to ", \$"}$ 3599 sout | 1 | 2 | 3 | " \"" | @sep@ | "\""; 3600 \end{cfa} 3601 %$ 3602 \begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt] 3603 1@, $@2@, $@3 @", $"@ 3604 \end{cfa} 3605 %$ 3781 \begin{cfa}[belowskip=0pt] 3782 sepSet( sout, ", $\LstStringStyle{\textdollar}$" ); $\C{// set separator from " " to ", \$"}$ 3783 sout | 1 | 2 | 3 | " \"" | ®sep® | "\""; 3784 \end{cfa} 3785 \begin{cfa}[showspaces=true,aboveskip=0pt] 3786 1®, $\LstStringStyle{\textdollar}$®2®, $\LstStringStyle{\textdollar}$®3 ®", $\LstStringStyle{\textdollar}$"® 3787 \end{cfa} 3606 3788 \begin{cfa}[belowskip=0pt] 3607 3789 sepSet( sout, " " ); $\C{// reset separator to " "}$ 3608 sout | 1 | 2 | 3 | " \"" | @sepGet( sout )@| "\"";3790 sout | 1 | 2 | 3 | " \"" | ®sepGet( sout )® | "\""; 3609 3791 \end{cfa} 3610 3792 \begin{cfa}[showspaces=true,aboveskip=0pt] 3611 1 @ @2@ @3 @" "@3793 1® ®2® ®3 ®" "® 3612 3794 \end{cfa} 3613 3795 ©sepGet© can be used to store a separator and then restore it: 3614 3796 \begin{cfa}[belowskip=0pt] 3615 char store[ @sepSize@]; $\C{// sepSize is the maximum separator size}$3797 char store[®sepSize®]; $\C{// sepSize is the maximum separator size}$ 3616 3798 strcpy( store, sepGet( sout ) ); $\C{// copy current separator}$ 3617 3799 sepSet( sout, "_" ); $\C{// change separator to underscore}$ … … 3619 3801 \end{cfa} 3620 3802 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3621 1 @_@2@_@33803 1®_®2®_®3 3622 3804 \end{cfa} 3623 3805 \begin{cfa}[belowskip=0pt] … … 3626 3808 \end{cfa} 3627 3809 \begin{cfa}[showspaces=true,aboveskip=0pt] 3628 1 @ @2@ @33810 1® ®2® ®3 3629 3811 \end{cfa} 3630 3812 … … 3634 3816 \begin{cfa}[belowskip=0pt] 3635 3817 sepSetTuple( sout, " " ); $\C{// set tuple separator from ", " to " "}$ 3636 sout | t1 | t2 | " \"" | @sepTuple@| "\"";3818 sout | t1 | t2 | " \"" | ®sepTuple® | "\""; 3637 3819 \end{cfa} 3638 3820 \begin{cfa}[showspaces=true,aboveskip=0pt] 3639 1 2 3 4 5 6 @" "@3821 1 2 3 4 5 6 ®" "® 3640 3822 \end{cfa} 3641 3823 \begin{cfa}[belowskip=0pt] 3642 3824 sepSetTuple( sout, ", " ); $\C{// reset tuple separator to ", "}$ 3643 sout | t1 | t2 | " \"" | @sepGetTuple( sout )@| "\"";3825 sout | t1 | t2 | " \"" | ®sepGetTuple( sout )® | "\""; 3644 3826 \end{cfa} 3645 3827 \begin{cfa}[showspaces=true,aboveskip=0pt] 3646 1, 2, 3 4, 5, 6 @", "@3828 1, 2, 3 4, 5, 6 ®", "® 3647 3829 \end{cfa} 3648 3830 As for ©sepGet©, ©sepGetTuple© can be use to store a tuple separator and then restore it. … … 3696 3878 \end{cfa} 3697 3879 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3698 @ @1 2 3@ @ 3880 ® ®1 2 3® ® 3699 3881 \end{cfa} 3700 3882 \end{enumerate} … … 3716 3898 For example, in: 3717 3899 \begin{cfa} 3718 sin | i | @nl@| j;3719 1 @2@3900 sin | i | ®nl® | j; 3901 1 ®2® 3720 3902 3 3721 3903 \end{cfa} … … 3758 3940 0b0 0b11011 0b11011 0b11011 0b11011 3759 3941 sout | bin( -27HH ) | bin( -27H ) | bin( -27 ) | bin( -27L ); 3760 0b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b @(58 1s)@1001013942 0b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b®(58 1s)®100101 3761 3943 \end{cfa} 3762 3944 … … 3794 3976 3795 3977 \item 3978 \Indexc{eng}( floating-point )\index{manipulator!eng@©eng©} print value in engineering notation with exponent, which means the exponent is adjusted to a multiple of 3. 3979 \begin{cfa}[belowskip=0pt] 3980 sout | eng( 0.0 ) | eng( 27000.5 ) | eng( -27.5e7 ); 3981 0®e0® 27.0005®e3® -275®e6® 3982 \end{cfa} 3983 3984 \item 3985 \Indexc{unit}( engineering-notation )\index{manipulator!unit@©unit©} print engineering exponent as a letter between the range $10^{-24}$ and $10^{24}$: 3986 ©y© $\Rightarrow 10^{-24}$, ©z© $\Rightarrow 10^{-21}$, ©a© $\Rightarrow 10^{-18}$, ©f© $\Rightarrow 10^{-15}$, ©p© $\Rightarrow 10^{-12}$, ©n© $\Rightarrow 10^{-9}$, ©u© $\Rightarrow 10^{-6}$, ©m© $\Rightarrow 10^{-3}$, ©K© $\Rightarrow 10^{3}$, ©M© $\Rightarrow 10^{6}$, ©G© $\Rightarrow 10^{9}$, ©T© $\Rightarrow 10^{12}$, ©P© $\Rightarrow 10^{15}$, ©E© $\Rightarrow 10^{18}$, ©Z© $\Rightarrow 10^{21}$, ©Y© $\Rightarrow 10^{24}$. 3987 For exponent $10^{0}$, no decimal point or letter is printed. 3988 \begin{cfa}[belowskip=0pt] 3989 sout | unit(eng( 0.0 )) | unit(eng( 27000.5 )) | unit(eng( -27.5e7 )); 3990 0 27.0005®K® -275®M® 3991 \end{cfa} 3992 3993 \item 3796 3994 \Indexc{upcase}( bin / hex / floating-point )\index{manipulator!upcase@©upcase©} print letters in a value in upper case. Lower case is the default. 3797 3995 \begin{cfa}[belowskip=0pt] 3798 3996 sout | upcase( bin( 27 ) ) | upcase( hex( 27 ) ) | upcase( 27.5e-10 ) | upcase( hex( 27.5 ) ); 3799 0 @B@11011 0@X@1@B@ 2.75@E@-09 0@X@1.@B@8@P@+43997 0®B®11011 0®X®1®B® 2.75®E®-09 0®X®1.®B®8®P®+4 3800 3998 \end{cfa} 3801 3999 … … 3813 4011 \begin{cfa}[belowskip=0pt] 3814 4012 sout | 0. | nodp( 0. ) | 27.0 | nodp( 27.0 ) | nodp( 27.5 ); 3815 0.0 @0@ 27.0 @27@27.54013 0.0 ®0® 27.0 ®27® 27.5 3816 4014 \end{cfa} 3817 4015 … … 3820 4018 \begin{cfa}[belowskip=0pt] 3821 4019 sout | sign( 27 ) | sign( -27 ) | sign( 27. ) | sign( -27. ) | sign( 27.5 ) | sign( -27.5 ); 3822 @+@27 -27 @+@27.0 -27.0 @+@27.5 -27.53823 \end{cfa} 3824 3825 \item 3826 \Indexc{wd} ©( unsigned char minimum, T val )©\index{manipulator!wd@©wd©}, ©wd( unsigned char minimum, unsigned char precision, T val )©3827 For all types, ©minimum© is the minimumnumber of printed characters.4020 ®+®27 -27 ®+®27.0 -27.0 ®+®27.5 -27.5 4021 \end{cfa} 4022 4023 \item 4024 \Indexc{wd}( minimum, value )\index{manipulator!wd@©wd©}, ©wd©( minimum, precision, value ) 4025 For all types, minimum is the number of printed characters. 3828 4026 If the value is shorter than the minimum, it is padded on the right with spaces. 3829 4027 \begin{cfa}[belowskip=0pt] … … 3833 4031 \end{cfa} 3834 4032 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3835 @ @34 @ @34 343836 @ @4.000000 @ @4.000000 4.0000003837 @ @ab @ @ab ab3838 \end{cfa} 3839 If the value is larger, it is printed without truncation, ignoring the ©minimum©.4033 ® ®34 ® ®34 34 4034 ® ®4.000000 ® ®4.000000 4.000000 4035 ® ®ab ® ®ab ab 4036 \end{cfa} 4037 If the value is larger, it is printed without truncation, ignoring the minimum. 3840 4038 \begin{cfa}[belowskip=0pt] 3841 4039 sout | wd( 4, 34567 ) | wd( 3, 34567 ) | wd( 2, 34567 ); … … 3844 4042 \end{cfa} 3845 4043 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3846 3456 @7@ 345@67@ 34@567@3847 3456 @.@ 345@6.@ 34@56.@3848 abcd @e@ abc@de@ ab@cde@3849 \end{cfa} 3850 3851 For integer types, ©precision©is the minimum number of printed digits.4044 3456®7® 345®67® 34®567® 4045 3456®.® 345®6.® 34®56.® 4046 abcd®e® abc®de® ab®cde® 4047 \end{cfa} 4048 4049 For integer types, precision is the minimum number of printed digits. 3852 4050 If the value is shorter, it is padded on the left with leading zeros. 3853 4051 \begin{cfa}[belowskip=0pt] … … 3855 4053 \end{cfa} 3856 4054 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3857 @0@34 @00@34 @00000000@343858 \end{cfa} 3859 If the value is larger, it is printed without truncation, ignoring the ©precision©.4055 ®0®34 ®00®34 ®00000000®34 4056 \end{cfa} 4057 If the value is larger, it is printed without truncation, ignoring the precision. 3860 4058 \begin{cfa}[belowskip=0pt] 3861 4059 sout | wd( 4,1, 3456 ) | wd( 8,2, 3456 ) | wd( 10,3, 3456 ); … … 3864 4062 3456 3456 3456 3865 4063 \end{cfa} 3866 If ©precision©is 0, nothing is printed for zero.3867 If ©precision©is greater than the minimum, it becomes the minimum.4064 If precision is 0, nothing is printed for zero. 4065 If precision is greater than the minimum, it becomes the minimum. 3868 4066 \begin{cfa}[belowskip=0pt] 3869 4067 sout | wd( 4,0, 0 ) | wd( 3,10, 34 ); 3870 4068 \end{cfa} 3871 4069 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3872 @ @ @00000000@343873 \end{cfa} 3874 For floating-point types, ©precision©is the minimum number of digits after the decimal point.4070 ® ® ®00000000®34 4071 \end{cfa} 4072 For floating-point types, precision is the minimum number of digits after the decimal point. 3875 4073 \begin{cfa}[belowskip=0pt] 3876 4074 sout | wd( 6,3, 27.5 ) | wd( 8,1, 27.5 ) | wd( 8,0, 27.5 ) | wd( 3,8, 27.5 ); 3877 4075 \end{cfa} 3878 4076 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3879 27. @500@ 27.@5@ 28. 27.@50000000@3880 \end{cfa} 3881 For the C-string type, ©precision©is the maximum number of printed characters, so the string is truncated if it exceeds the maximum.4077 27.®500® 27.®5® 28. 27.®50000000® 4078 \end{cfa} 4079 For the C-string type, precision is the maximum number of printed characters, so the string is truncated if it exceeds the maximum. 3882 4080 \begin{cfa}[belowskip=0pt] 3883 4081 sout | wd( 6,8, "abcd" ) | wd( 6,8, "abcdefghijk" ) | wd( 6,3, "abcd" ); … … 3888 4086 3889 4087 \item 3890 \Indexc{ws( unsigned char minimum, unsigned char significant, floating-point )}\index{manipulator!ws@©ws©} 3891 For floating-point type, ©minimum© is the same as for manipulator ©wd©, but ©significant© is the maximum number of significant digits to be printed for both the integer and fractions (versus only the fraction for ©wd©). 3892 If a value's significant digits is greater than ©significant©, the last significant digit is rounded up. 4088 \begin{sloppypar} 4089 \Indexc{ws}( minimum, significant, floating-point )\index{manipulator!ws@©ws©} 4090 For floating-point types, minimum is the same as for manipulator ©wd©, but significant is the maximum number of significant digits to be printed for both the integer and fractions (versus only the fraction for ©wd©). 4091 If a value's significant digits is greater than significant, the last significant digit is rounded up. 4092 \end{sloppypar} 3893 4093 \begin{cfa}[belowskip=0pt] 3894 4094 sout | ws(6,6, 234.567) | ws(6,5, 234.567) | ws(6,4, 234.567) | ws(6,3, 234.567); 3895 4095 \end{cfa} 3896 4096 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3897 234.567 234.5 @7@ 234.@6@ 23@5@3898 \end{cfa} 3899 If a value's magnitude is greater than ©significant©, the value is printed in scientific notation with the specified number of significant digits.4097 234.567 234.5®7® 234.®6® 23®5® 4098 \end{cfa} 4099 If a value's magnitude is greater than significant, the value is printed in scientific notation with the specified number of significant digits. 3900 4100 \begin{cfa}[belowskip=0pt] 3901 4101 sout | ws(6,6, 234567.) | ws(6,5, 234567.) | ws(6,4, 234567.) | ws(6,3, 234567.); 3902 4102 \end{cfa} 3903 4103 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3904 234567. 2.3457 @e+05@ 2.346@e+05@ 2.35@e+05@3905 \end{cfa} 3906 If ©significant© is greater than ©minimum©, it defines the number of printed characters.4104 234567. 2.3457®e+05® 2.346®e+05® 2.35®e+05® 4105 \end{cfa} 4106 If significant is greater than minimum, it defines the number of printed characters. 3907 4107 \begin{cfa}[belowskip=0pt] 3908 4108 sout | ws(3,6, 234567.) | ws(4,6, 234567.) | ws(5,6, 234567.) | ws(6,6, 234567.); … … 3918 4118 \end{cfa} 3919 4119 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 3920 27 @ @ 27.000000 27.500000 027 27.500@ @4120 27® ® 27.000000 27.500000 027 27.500® ® 3921 4121 \end{cfa} 3922 4122 … … 3925 4125 \begin{cfa}[belowskip=0pt] 3926 4126 sout | pad0( wd( 4, 27 ) ) | pad0( wd( 4,3, 27 ) ) | pad0( wd( 8,3, 27.5 ) ); 3927 @00@27 @0@27 @00@27.5004127 ®00®27 ®0®27 ®00®27.500 3928 4128 \end{cfa} 3929 4129 \end{enumerate} … … 3989 4189 3990 4190 The format of numeric input values in the same as C constants without a trailing type suffix, as the input value-type is denoted by the input variable. 3991 For © _Bool© type, the constants are ©true© and ©false©.4191 For ©bool© type, the constants are ©true© and ©false©. 3992 4192 For integral types, any number of digits, optionally preceded by a sign (©+© or ©-©), where a 3993 4193 \begin{itemize} … … 4010 4210 \begin{enumerate} 4011 4211 \item 4012 \Indexc{skip( const char * pattern )}\index{manipulator!skip@©skip©} / ©skip( unsigned int length )© / ©const char * pattern© 4013 The argument defines a ©pattern© or ©length©. 4014 The ©pattern© is composed of white-space and non-white-space characters, where \emph{any} white-space character matches 0 or more input white-space characters (hence, consecutive white-space characters in the pattern are combined), and each non-white-space character matches exactly with an input character. 4015 The ©length© is composed of the next $N$ characters, including the newline character. 4212 \Indexc{skip}( pattern )\index{manipulator!skip@©skip©}, ©skip©( length ) 4213 The pattern is composed of white-space and non-white-space characters, where \emph{any} white-space character matches 0 or more input white-space characters (hence, consecutive white-space characters in the pattern are combined), and each non-white-space character matches exactly with an input character. 4214 The length is composed of the next $N$ characters, including the newline character. 4016 4215 If the match successes, the input characters are discarded, and input continues with the next character. 4017 4216 If the match fails, the input characters are left unread. … … 4021 4220 \end{cfa} 4022 4221 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4023 @abc @ 4024 @abc @ 4025 @xx@ 4026 \end{cfa} 4027 4028 \item 4029 \Indexc{wdi} ©( unsigned int maximum, T & val )©\index{manipulator!wdi@©wdi©}4030 For all types except ©char©, ©maximum©is the maximum number of characters read for the current operation.4222 ®abc ® 4223 ®abc ® 4224 ®xx® 4225 \end{cfa} 4226 4227 \item 4228 \Indexc{wdi}( maximum, reference-value )\index{manipulator!wdi@©wdi©} 4229 For all types except ©char©, maximum is the maximum number of characters read for the current operation. 4031 4230 \begin{cfa}[belowskip=0pt] 4032 4231 char s[10]; int i; double d; … … 4034 4233 \end{cfa} 4035 4234 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4036 @abcd1233.456E+2@ 4235 ®abcd1233.456E+2® 4037 4236 \end{cfa} 4038 4237 Note, input ©wdi© cannot be overloaded with output ©wd© because both have the same parameters but return different types. … … 4040 4239 4041 4240 \item 4042 \Indexc{ignore ( T & val )}\index{manipulator!ignore@©ignore©}4241 \Indexc{ignore}( reference-value )\index{manipulator!ignore@©ignore©} 4043 4242 For all types, the data is read from the stream depending on the argument type but ignored, \ie it is not stored in the argument. 4044 4243 \begin{cfa}[belowskip=0pt] … … 4047 4246 \end{cfa} 4048 4247 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4049 @ -75.35e-4@254050 \end{cfa} 4051 4052 \item 4053 \Indexc{incl ( const char * scanset, char * s )}\index{manipulator!incl@©incl©}4054 For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{in} the set.4055 Matching characters are read into the C string and null terminated.4248 ® -75.35e-4® 25 4249 \end{cfa} 4250 4251 \item 4252 \Indexc{incl}( scanset, input-string )\index{manipulator!incl@©incl©} 4253 For C-string types, the scanset matches any number of characters \emph{in} the set. 4254 Matching characters are read into the C input-string and null terminated. 4056 4255 \begin{cfa}[belowskip=0pt] 4057 4256 char s[10]; … … 4059 4258 \end{cfa} 4060 4259 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4061 @bca@xyz4062 \end{cfa} 4063 4064 \item 4065 \Indexc{excl ( const char * scanset, char * s )}\index{manipulator!excl@©excl©}4066 For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{not in} the set.4067 Non-matching characters are read into the C string and null terminated.4260 ®bca®xyz 4261 \end{cfa} 4262 4263 \item 4264 \Indexc{excl}( scanset, input-string )\index{manipulator!excl@©excl©} 4265 For C-string types, the scanset matches any number of characters \emph{not in} the set. 4266 Non-matching characters are read into the C input-string and null terminated. 4068 4267 \begin{cfa}[belowskip=0pt] 4069 4268 char s[10]; … … 4071 4270 \end{cfa} 4072 4271 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt] 4073 @xyz@bca4272 ®xyz®bca 4074 4273 \end{cfa} 4075 4274 \end{enumerate} 4076 4275 4077 4276 4277 \subsection{Concurrent Stream Access} 4278 4279 When a stream is shared by multiple threads, input or output characters can be intermixed or cause failure. 4280 For example, if two threads execute the following: 4281 \begin{cfa} 4282 $\emph{thread\(_1\)}$ : sout | "abc " | "def "; 4283 $\emph{thread\(_2\)}$ : sout | "uvw " | "xyz "; 4284 \end{cfa} 4285 possible outputs are: 4286 \begin{cquote} 4287 \begin{tabular}{@{}l|l|l|l|l@{}} 4288 \begin{cfa} 4289 abc def 4290 uvw xyz 4291 \end{cfa} 4292 & 4293 \begin{cfa} 4294 abc uvw xyz 4295 def 4296 \end{cfa} 4297 & 4298 \begin{cfa} 4299 uvw abc xyz def 4300 4301 \end{cfa} 4302 & 4303 \begin{cfa} 4304 abuvwc dexf 4305 yz 4306 \end{cfa} 4307 & 4308 \begin{cfa} 4309 uvw abc def 4310 xyz 4311 \end{cfa} 4312 \end{tabular} 4313 \end{cquote} 4314 Concurrent operations can even corrupt the internal state of the stream resulting in failure. 4315 As a result, some form of mutual exclusion is required for concurrent stream access. 4316 4317 A coarse-grained solution is to perform all stream operations via a single thread or within a monitor providing the necessary mutual exclusion for the stream. 4318 A fine-grained solution is to have a lock for each stream, which is acquired and released around stream operations by each thread. 4319 \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. 4320 4321 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: 4322 \begin{cfa} 4323 $\emph{thread\(_1\)}$ : sout | ®acquire® | "abc " | "def "; // manipulator 4324 $\emph{thread\(_2\)}$ : sout | ®acquire® | "uvw " | "xyz "; 4325 \end{cfa} 4326 Now, the order of the thread execution is still non-deterministic, but the output is constrained to two possible lines in either order. 4327 \begin{cquote} 4328 \def\VRfont{\fontfamily{pcr}\upshape\selectfont} 4329 \begin{tabular}{@{}l|l@{}} 4330 \begin{cfa} 4331 abc def 4332 uvw xyz 4333 \end{cfa} 4334 & 4335 \begin{cfa} 4336 uvw xyz 4337 abc def 4338 \end{cfa} 4339 \end{tabular} 4340 \end{cquote} 4341 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. 4342 4343 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: 4344 \begin{cfa} 4345 { // acquire sout for block duration 4346 ®osacquire® acq = { sout }; $\C{// named stream locker}$ 4347 sout | 1; 4348 sout | ®acquire® | 2 | 3; $\C{// unnecessary, but ok to acquire and release again}$ 4349 sout | 4; 4350 } // implicitly release the lock when "acq" is deallocated 4351 \end{cfa} 4352 Note, the unnecessary ©acquire© manipulator works because the recursive stream-lock can be acquired/released multiple times by the owner thread. 4353 Hence, calls to functions that also acquire a stream lock for their output do not result in \Index{deadlock}. 4354 4355 The previous values written by threads 1 and 2 can be read in concurrently: 4356 \begin{cfa} 4357 { // acquire sin lock for block duration 4358 ®isacquire acq = { sin };® $\C{// named stream locker}$ 4359 int x, y, z, w; 4360 sin | x; 4361 sin | ®acquire® | y | z; $\C{// unnecessary, but ok to acquire and release again}$ 4362 sin | w; 4363 } // implicitly release the lock when "acq" is deallocated 4364 \end{cfa} 4365 Again, the order of the reading threads is non-deterministic. 4366 Note, non-deterministic reading is rare. 4367 4368 \Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg: 4369 \begin{cfa} 4370 sout | ®acquire® | "data:" | rtn( mon ); $\C{// mutex call on monitor}$ 4371 \end{cfa} 4372 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. 4373 This scenario can lead to \Index{deadlock}, if the thread that is going to unblock the thread waiting in the monitor first writes to ©sout© (deadly embrace). 4374 To prevent nested locking, a simple precaution is to factor out the blocking call from the expression, \eg: 4375 \begin{cfa} 4376 int ®data® = rtn( mon ); 4377 sout | acquire | "data:" | ®data®; 4378 \end{cfa} 4379 4380 \Textbf{WARNING:} ©printf©\index{printf@©printf©}, ©scanf©\index{scanf@©scanf©} and their derivatives are unsafe when used with user-level threading, as in \CFA. 4381 These stream routines use kernel-thread locking (©futex©\index{futex@©futex©}), which block kernel threads, to prevent interleaving of I/O. 4382 However, the following simple example illustrates how a deadlock can occur (other complex scenarios are possible). 4383 Assume a single kernel thread and two user-level threads calling ©printf©. 4384 One user-level thread acquires the I/O lock and is time-sliced while performing ©printf©. 4385 The other user-level thread then starts execution, calls ©printf©, and blocks the only kernel thread because it cannot acquire the I/O lock. 4386 It does not help if the kernel lock is multiple acquisition, \ie, the lock owner can acquire it multiple times, because it then results in two user threads in the ©printf© critical section, corrupting the stream. 4387 4388 4389 \begin{comment} 4078 4390 \section{Types} 4079 4391 … … 4154 4466 process((int) s); // type is converted, no function is called 4155 4467 \end{cfa} 4468 \end{comment} 4156 4469 4157 4470 … … 4287 4600 In C, the integer constants 0 and 1 suffice because the integer promotion rules can convert them to any arithmetic type, and the rules for pointer expressions treat constant expressions evaluating to 0 as a special case. 4288 4601 However, user-defined arithmetic types often need the equivalent of a 1 or 0 for their functions or operators, polymorphic functions often need 0 and 1 constants of a type matching their polymorphic parameters, and user-defined pointer-like types may need a null value. 4289 Defining special constants for a user-defined type is more efficient than defining a conversion to the type from © _Bool©.4602 Defining special constants for a user-defined type is more efficient than defining a conversion to the type from ©bool©. 4290 4603 4291 4604 Why just 0 and 1? Why not other integers? No other integers have special status in C. … … 4369 4682 \begin{table}[hbt] 4370 4683 \centering 4371 \input{../refrat/operidents} 4684 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}} 4685 \begin{tabular}{@{}ll@{}} 4686 ©?[?]© & subscripting \impl{?[?]} \\ 4687 ©?()© & function call \impl{?()} \\ 4688 ©?++© & postfix increment \impl{?++} \\ 4689 ©?--© & postfix decrement \impl{?--} \\ 4690 ©++?© & prefix increment \impl{++?} \\ 4691 ©--?© & prefix decrement \impl{--?} \\ 4692 ©*?© & dereference \impl{*?} \\ 4693 ©+?© & unary plus \impl{+?} \\ 4694 ©-?© & arithmetic negation \impl{-?} \\ 4695 ©~?© & bitwise negation \impl{~?} \\ 4696 ©!?© & logical complement \impl{"!?} \\ 4697 ©?\?© & exponentiation \impl{?\?} \\ 4698 ©?*?© & multiplication \impl{?*?} \\ 4699 ©?/?© & division \impl{?/?} \\ 4700 ©?%?© & remainder \impl{?%?} \\ 4701 \end{tabular} 4702 & 4703 \begin{tabular}{@{}ll@{}} 4704 ©?+?© & addition \impl{?+?} \\ 4705 ©?-?© & subtraction \impl{?-?} \\ 4706 ©?<<?© & left shift \impl{?<<?} \\ 4707 ©?>>?© & right shift \impl{?>>?} \\ 4708 ©?<?© & less than \impl{?<?} \\ 4709 ©?<=?© & less than or equal \impl{?<=?} \\ 4710 ©?>=?© & greater than or equal \impl{?>=?} \\ 4711 ©?>?© & greater than \impl{?>?} \\ 4712 ©?==?© & equality \impl{?==?} \\ 4713 ©?!=?© & inequality \impl{?"!=?} \\ 4714 ©?&?© & bitwise AND \impl{?&?} \\ 4715 ©?^?© & exclusive OR \impl{?^?} \\ 4716 ©?|?© & inclusive OR \impl{?"|?} \\ 4717 \\ 4718 \\ 4719 \end{tabular} 4720 & 4721 \begin{tabular}{@{}ll@{}} 4722 ©?=?© & simple assignment \impl{?=?} \\ 4723 ©?\=?© & exponentiation assignment \impl{?\=?} \\ 4724 ©?*=?© & multiplication assignment \impl{?*=?} \\ 4725 ©?/=?© & division assignment \impl{?/=?} \\ 4726 ©?%=?© & remainder assignment \impl{?%=?} \\ 4727 ©?+=?© & addition assignment \impl{?+=?} \\ 4728 ©?-=?© & subtraction assignment \impl{?-=?} \\ 4729 ©?<<=?© & left-shift assignment \impl{?<<=?} \\ 4730 ©?>>=?© & right-shift assignment \impl{?>>=?} \\ 4731 ©?&=?© & bitwise AND assignment \impl{?&=?} \\ 4732 ©?^=?© & exclusive OR assignment \impl{?^=?} \\ 4733 ©?|=?© & inclusive OR assignment \impl{?"|=?} \\ 4734 \\ 4735 \\ 4736 \\ 4737 \end{tabular} 4738 \end{tabular} 4372 4739 \caption{Operator Identifiers} 4373 4740 \label{opids} … … 4457 4824 For example, given 4458 4825 \begin{cfa} 4459 auto j = @...@4826 auto j = ®...® 4460 4827 \end{cfa} 4461 4828 and the need to write a routine to compute using ©j© 4462 4829 \begin{cfa} 4463 void rtn( @...@parm );4830 void rtn( ®...® parm ); 4464 4831 rtn( j ); 4465 4832 \end{cfa} … … 4698 5065 \begin{figure} 4699 5066 \begin{cfa} 4700 #include <fstream >4701 #include <coroutine>4702 4703 coroutineFibonacci {5067 #include <fstream.hfa> 5068 #include ®<coroutine.hfa>® 5069 5070 ®coroutine® Fibonacci { 4704 5071 int fn; $\C{// used for communication}$ 4705 5072 }; 4706 void ?{}( Fibonacci * this ) { 4707 this->fn = 0; 4708 } 4709 void main( Fibonacci * this ) { 5073 5074 void main( Fibonacci & fib ) with( fib ) { $\C{// called on first resume}$ 4710 5075 int fn1, fn2; $\C{// retained between resumes}$ 4711 this->fn = 0; $\C{// case 0}$ 4712 fn1 = this->fn; 4713 suspend(); $\C{// return to last resume}$ 4714 4715 this->fn = 1; $\C{// case 1}$ 4716 fn2 = fn1; 4717 fn1 = this->fn; 4718 suspend(); $\C{// return to last resume}$ 4719 4720 for ( ;; ) { $\C{// general case}$ 4721 this->fn = fn1 + fn2; 4722 fn2 = fn1; 4723 fn1 = this->fn; 4724 suspend(); $\C{// return to last resume}$ 4725 } // for 4726 } 4727 int next( Fibonacci * this ) { 4728 resume( this ); $\C{// transfer to last suspend}$ 4729 return this->fn; 5076 fn = 0; fn1 = fn; $\C{// 1st case}$ 5077 ®suspend;® $\C{// restart last resume}$ 5078 fn = 1; fn2 = fn1; fn1 = fn; $\C{// 2nd case}$ 5079 ®suspend;® $\C{// restart last resume}$ 5080 for () { 5081 fn = fn1 + fn2; fn2 = fn1; fn1 = fn; $\C{// general case}$ 5082 ®suspend;® $\C{// restart last resume}$ 5083 } 5084 } 5085 int next( Fibonacci & fib ) with( fib ) { 5086 ®resume( fib );® $\C{// restart last suspend}$ 5087 return fn; 4730 5088 } 4731 5089 int main() { 4732 5090 Fibonacci f1, f2; 4733 for ( int i = 1; i <= 10; i += 1 ) { 4734 sout | next( &f1 ) | ' ' | next( &f2 ); 4735 } // for 4736 } 4737 \end{cfa} 5091 for ( 10 ) { $\C{// print N Fibonacci values}$ 5092 sout | next( f1 ) | next( f2 ); 5093 } 5094 } 5095 \end{cfa} 5096 \vspace*{-5pt} 4738 5097 \caption{Fibonacci Coroutine} 4739 5098 \label{f:FibonacciCoroutine} … … 4761 5120 \begin{figure} 4762 5121 \begin{cfa} 4763 #include <fstream> 4764 #include <kernel> 4765 #include <monitor> 4766 #include <thread> 4767 4768 monitor global_t { 4769 int value; 4770 }; 4771 4772 void ?{}(global_t * this) { 4773 this->value = 0; 4774 } 4775 4776 static global_t global; 4777 4778 void increment3( global_t * mutex this ) { 4779 this->value += 1; 4780 } 4781 void increment2( global_t * mutex this ) { 4782 increment3( this ); 4783 } 4784 void increment( global_t * mutex this ) { 4785 increment2( this ); 4786 } 5122 #include <fstream.hfa> 5123 #include ®<thread.hfa>® 5124 5125 ®monitor® AtomicCnt { int counter; }; 5126 void ?{}( AtomicCnt & c, int init = 0 ) with(c) { counter = init; } 5127 int inc( AtomicCnt & ®mutex® c, int inc = 1 ) with(c) { return counter += inc; } 5128 int dec( AtomicCnt & ®mutex® c, int dec = 1 ) with(c) { return counter -= dec; } 5129 forall( ostype & | ostream( ostype ) ) { $\C{// print any stream}$ 5130 ostype & ?|?( ostype & os, AtomicCnt c ) { return os | c.counter; } 5131 void ?|?( ostype & os, AtomicCnt c ) { (ostype &)(os | c.counter); ends( os ); } 5132 } 5133 5134 AtomicCnt global; $\C{// shared}$ 4787 5135 4788 5136 thread MyThread {}; 4789 4790 void main( MyThread* this) {4791 for(int i = 0; i < 1_000_000; i++) {4792 increment( &global );5137 void main( MyThread & ) { 5138 for ( i; 100_000 ) { 5139 inc( global ); 5140 dec( global ); 4793 5141 } 4794 5142 } 4795 int main(int argc, char* argv[]) { 4796 processor p; 5143 int main() { 5144 enum { Threads = 4 }; 5145 processor p[Threads - 1]; $\C{// + starting processor}$ 4797 5146 { 4798 MyThread f[4];5147 MyThread t[Threads]; 4799 5148 } 4800 sout | global .value;5149 sout | global; $\C{// print 0}$ 4801 5150 } 4802 5151 \end{cfa} 4803 5152 \caption{Atomic-Counter Monitor} 4804 \ caption{f:AtomicCounterMonitor}5153 \label{f:AtomicCounterMonitor} 4805 5154 \end{figure} 4806 5155 … … 6265 6614 6266 6615 C has a number of syntax ambiguities, which are resolved by taking the longest sequence of overlapping characters that constitute a token. 6267 For example, the program fragment ©x+++++y© is parsed as \lstinline[showspaces=true] @x ++ ++ + y@because operator tokens ©++© and ©+© overlap.6268 Unfortunately, the longest sequence violates a constraint on increment operators, even though the parse \lstinline[showspaces=true] @x ++ + ++ y@might yield a correct expression.6616 For example, the program fragment ©x+++++y© is parsed as \lstinline[showspaces=true]{x ++ ++ + y} because operator tokens ©++© and ©+© overlap. 6617 Unfortunately, the longest sequence violates a constraint on increment operators, even though the parse \lstinline[showspaces=true]{x ++ + ++ y} might yield a correct expression. 6269 6618 Hence, C programmers are aware that spaces have to added to disambiguate certain syntactic cases. 6270 6619 … … 6286 6635 requiring arbitrary whitespace look-ahead for the routine-call parameter-list to disambiguate. 6287 6636 However, the dereference operator \emph{must} have a parameter/argument to dereference ©*?(...)©. 6288 Hence, always interpreting the string ©*?()© as \lstinline[showspaces=true] @* ?()@does not preclude any meaningful program.6637 Hence, always interpreting the string ©*?()© as \lstinline[showspaces=true]{* ?()} does not preclude any meaningful program. 6289 6638 6290 6639 The remaining cases are with the increment/decrement operators and conditional expression, \eg: … … 6394 6743 \begin{cfa} 6395 6744 int i; $\C{// forward definition}$ 6396 int *j = @&i@; $\C{// forward reference, valid in C, invalid in \CFA}$6745 int *j = ®&i®; $\C{// forward reference, valid in C, invalid in \CFA}$ 6397 6746 int i = 0; $\C{// definition}$ 6398 6747 \end{cfa} … … 6402 6751 struct X { int i; struct X *next; }; 6403 6752 static struct X a; $\C{// forward definition}$ 6404 static struct X b = { 0, @&a@};$\C{// forward reference, valid in C, invalid in \CFA}$6753 static struct X b = { 0, ®&a® };$\C{// forward reference, valid in C, invalid in \CFA}$ 6405 6754 static struct X a = { 1, &b }; $\C{// definition}$ 6406 6755 \end{cfa} … … 6415 6764 \item[Change:] have ©struct© introduce a scope for nested types: 6416 6765 \begin{cfa} 6417 enum @Colour@{ R, G, B, Y, C, M };6766 enum ®Colour® { R, G, B, Y, C, M }; 6418 6767 struct Person { 6419 enum @Colour@{ R, G, B }; $\C[7cm]{// nested type}$6768 enum ®Colour® { R, G, B }; $\C[7cm]{// nested type}$ 6420 6769 struct Face { $\C{// nested type}$ 6421 @Colour@Eyes, Hair; $\C{// type defined outside (1 level)}$6770 ®Colour® Eyes, Hair; $\C{// type defined outside (1 level)}$ 6422 6771 }; 6423 @.Colour@shirt; $\C{// type defined outside (top level)}$6424 @Colour@pants; $\C{// type defined same level}$6772 ®.Colour® shirt; $\C{// type defined outside (top level)}$ 6773 ®Colour® pants; $\C{// type defined same level}$ 6425 6774 Face looks[10]; $\C{// type defined same level}$ 6426 6775 }; 6427 @Colour@c = R; $\C{// type/enum defined same level}$6428 Person @.Colour@ pc = Person@.@R;$\C{// type/enum defined inside}$6429 Person @.@Face pretty; $\C{// type defined inside}\CRT$6776 ®Colour® c = R; $\C{// type/enum defined same level}$ 6777 Person®.Colour® pc = Person®.®R;$\C{// type/enum defined inside}$ 6778 Person®.®Face pretty; $\C{// type defined inside}\CRT$ 6430 6779 \end{cfa} 6431 6780 In C, the name of the nested types belongs to the same scope as the name of the outermost enclosing structure, \ie the nested types are hoisted to the scope of the outer-most type, which is not useful and confusing. … … 6502 6851 \label{s:CFAKeywords} 6503 6852 6504 \CFA introduces the following new keywords.6853 \CFA introduces the following new \Index{keyword}s, which cannot be used as identifiers. 6505 6854 6506 6855 \begin{cquote} 6507 \input{../refrat/keywords} 6856 \begin{tabular}{@{}lllllll@{}} 6857 \begin{tabular}{@{}l@{}} 6858 \Indexc{basetypeof} \\ 6859 \Indexc{choose} \\ 6860 \Indexc{coroutine} \\ 6861 \Indexc{disable} \\ 6862 \end{tabular} 6863 & 6864 \begin{tabular}{@{}l@{}} 6865 \Indexc{enable} \\ 6866 \Indexc{exception} \\ 6867 \Indexc{fallthrough} \\ 6868 \Indexc{fallthru} \\ 6869 \end{tabular} 6870 & 6871 \begin{tabular}{@{}l@{}} 6872 \Indexc{finally} \\ 6873 \Indexc{fixup} \\ 6874 \Indexc{forall} \\ 6875 \Indexc{generator} \\ 6876 \end{tabular} 6877 & 6878 \begin{tabular}{@{}l@{}} 6879 \Indexc{int128} \\ 6880 \Indexc{monitor} \\ 6881 \Indexc{mutex} \\ 6882 \Indexc{one_t} \\ 6883 \end{tabular} 6884 & 6885 \begin{tabular}{@{}l@{}} 6886 \Indexc{report} \\ 6887 \Indexc{suspend} \\ 6888 \Indexc{throw} \\ 6889 \Indexc{throwResume} \\ 6890 \end{tabular} 6891 & 6892 \begin{tabular}{@{}l@{}} 6893 \Indexc{trait} \\ 6894 \Indexc{try} \\ 6895 \Indexc{virtual} \\ 6896 \Indexc{waitfor} \\ 6897 \end{tabular} 6898 & 6899 \begin{tabular}{@{}l@{}} 6900 \Indexc{when} \\ 6901 \Indexc{with} \\ 6902 \Indexc{zero_t} \\ 6903 \\ 6904 \end{tabular} 6905 \end{tabular} 6508 6906 \end{cquote} 6509 6907 \CFA introduces the following new \Index{quasi-keyword}s, which can be used as identifiers. 6908 \begin{cquote} 6909 \begin{tabular}{@{}ll@{}} 6910 \begin{tabular}{@{}l@{}} 6911 \Indexc{catch} \\ 6912 \Indexc{catchResume} \\ 6913 \Indexc{finally} \\ 6914 \end{tabular} 6915 & 6916 \begin{tabular}{@{}l@{}} 6917 \Indexc{fixup} \\ 6918 \Indexc{or} \\ 6919 \Indexc{timeout} \\ 6920 \end{tabular} 6921 \end{tabular} 6922 \end{cquote} 6510 6923 6511 6924 \section{Standard Headers} … … 6666 7079 // assume ?|? operator for printing an S 6667 7080 6668 S & sp = * @new@( 3 ); $\C{// call constructor after allocation}$7081 S & sp = *®new®( 3 ); $\C{// call constructor after allocation}$ 6669 7082 sout | sp.i; 6670 @delete@( &sp );6671 6672 S * spa = @anew@( 10, 5 ); $\C{// allocate array and initialize each array element}$7083 ®delete®( &sp ); 7084 7085 S * spa = ®anew®( 10, 5 ); $\C{// allocate array and initialize each array element}$ 6673 7086 for ( i; 10 ) sout | spa[i] | nonl; 6674 7087 sout | nl; 6675 @adelete@( 10, spa );7088 ®adelete®( 10, spa ); 6676 7089 \end{cfa} 6677 7090 Allocation routines ©new©/©anew© allocate a variable/array and initialize storage using the allocated type's constructor. … … 6909 7322 [ int, long double ] remquo( long double, long double ); 6910 7323 6911 float div( float, float, int * );$\indexc{div}$ $\C{// alternative name for remquo}$6912 double div( double, double, int * );6913 long double div( long double, long double, int * );6914 7324 [ int, float ] div( float, float ); 6915 7325 [ int, double ] div( double, double ); … … 6972 7382 long double _Complex log( long double _Complex ); 6973 7383 6974 float log2( float );$\indexc{log2}$ 7384 int log2( unsigned int );$\indexc{log2}$ 7385 long int log2( unsigned long int ); 7386 long long int log2( unsigned long long int ) 7387 float log2( float ); 6975 7388 double log2( double ); 6976 7389 long double log2( long double ); … … 7154 7567 \leavevmode 7155 7568 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7569 // n / align * align 7570 signed char floor( signed char n, signed char align ); 7571 unsigned char floor( unsigned char n, unsigned char align ); 7572 short int floor( short int n, short int align ); 7573 unsigned short int floor( unsigned short int n, unsigned short int align ); 7574 int floor( int n, int align ); 7575 unsigned int floor( unsigned int n, unsigned int align ); 7576 long int floor( long int n, long int align ); 7577 unsigned long int floor( unsigned long int n, unsigned long int align ); 7578 long long int floor( long long int n, long long int align ); 7579 unsigned long long int floor( unsigned long long int n, unsigned long long int align ); 7580 7581 // (n + (align - 1)) / align 7582 signed char ceiling_div( signed char n, char align ); 7583 unsigned char ceiling_div( unsigned char n, unsigned char align ); 7584 short int ceiling_div( short int n, short int align ); 7585 unsigned short int ceiling_div( unsigned short int n, unsigned short int align ); 7586 int ceiling_div( int n, int align ); 7587 unsigned int ceiling_div( unsigned int n, unsigned int align ); 7588 long int ceiling_div( long int n, long int align ); 7589 unsigned long int ceiling_div( unsigned long int n, unsigned long int align ); 7590 long long int ceiling_div( long long int n, long long int align ); 7591 unsigned long long int ceiling_div( unsigned long long int n, unsigned long long int align ); 7592 7593 // floor( n + (n % align != 0 ? align - 1 : 0), align ) 7594 signed char ceiling( signed char n, signed char align ); 7595 unsigned char ceiling( unsigned char n, unsigned char align ); 7596 short int ceiling( short int n, short int align ); 7597 unsigned short int ceiling( unsigned short int n, unsigned short int align ); 7598 int ceiling( int n, int align ); 7599 unsigned int ceiling( unsigned int n, unsigned int align ); 7600 long int ceiling( long int n, long int align ); 7601 unsigned long int ceiling( unsigned long int n, unsigned long int align ); 7602 long long int ceiling( long long int n, long long int align ); 7603 unsigned long long int ceiling( unsigned long long int n, unsigned long long int align ); 7604 7156 7605 float floor( float );$\indexc{floor}$ 7157 7606 double floor( double ); … … 7249 7698 7250 7699 7251 %\subsection{\texorpdfstring{\protect\lstinline @Duration@}{Duration}}7700 %\subsection{\texorpdfstring{\protect\lstinline{Duration}}{Duration}} 7252 7701 \subsection{\texorpdfstring{\LstBasicStyle{Duration}}{Duration}} 7253 7702 \label{s:Duration} … … 7256 7705 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7257 7706 struct Duration { 7258 int64_t t v; $\C{// nanoseconds}$7707 int64_t tn; $\C{// nanoseconds}$ 7259 7708 }; 7260 7709 7261 7710 void ?{}( Duration & dur ); 7262 7711 void ?{}( Duration & dur, zero_t ); 7712 void ?{}( Duration & dur, timeval t ) 7713 void ?{}( Duration & dur, timespec t ) 7263 7714 7264 7715 Duration ?=?( Duration & dur, zero_t ); 7716 Duration ?=?( Duration & dur, timeval t ) 7717 Duration ?=?( Duration & dur, timespec t ) 7265 7718 7266 7719 Duration +?( Duration rhs ); … … 7284 7737 Duration ?%=?( Duration & lhs, Duration rhs ); 7285 7738 7286 _Bool ?==?( Duration lhs, Duration rhs);7287 _Bool ?!=?( Duration lhs, Duration rhs);7288 _Bool ?<? ( Duration lhs, Duration rhs);7289 _Bool ?<=?( Duration lhs, Duration rhs);7290 _Bool ?>? ( Duration lhs, Duration rhs);7291 _Bool ?>=?( Duration lhs, Duration rhs);7292 7293 _Bool ?==?( Duration lhs, zero_t);7294 _Bool ?!=?( Duration lhs, zero_t);7295 _Bool ?<? ( Duration lhs, zero_t);7296 _Bool ?<=?( Duration lhs, zero_t);7297 _Bool ?>? ( Duration lhs, zero_t);7298 _Bool ?>=?( Duration lhs, zero_t);7739 bool ?==?( Duration lhs, zero_t ); 7740 bool ?!=?( Duration lhs, zero_t ); 7741 bool ?<? ( Duration lhs, zero_t ); 7742 bool ?<=?( Duration lhs, zero_t ); 7743 bool ?>? ( Duration lhs, zero_t ); 7744 bool ?>=?( Duration lhs, zero_t ); 7745 7746 bool ?==?( Duration lhs, Duration rhs ); 7747 bool ?!=?( Duration lhs, Duration rhs ); 7748 bool ?<? ( Duration lhs, Duration rhs ); 7749 bool ?<=?( Duration lhs, Duration rhs ); 7750 bool ?>? ( Duration lhs, Duration rhs ); 7751 bool ?>=?( Duration lhs, Duration rhs ); 7299 7752 7300 7753 Duration abs( Duration rhs ); … … 7323 7776 int64_t ?`w( Duration dur ); 7324 7777 7778 double ?`dns( Duration dur ); 7779 double ?`dus( Duration dur ); 7780 double ?`dms( Duration dur ); 7781 double ?`ds( Duration dur ); 7782 double ?`dm( Duration dur ); 7783 double ?`dh( Duration dur ); 7784 double ?`dd( Duration dur ); 7785 double ?`dw( Duration dur ); 7786 7325 7787 Duration max( Duration lhs, Duration rhs ); 7326 7788 Duration min( Duration lhs, Duration rhs ); 7327 \end{cfa} 7328 7329 7330 %\subsection{\texorpdfstring{\protect\lstinline@\timeval@}{timeval}} 7789 7790 forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype & os, Duration dur ); 7791 \end{cfa} 7792 7793 7794 %\subsection{\texorpdfstring{\protect\lstinline{timeval}}{timeval}} 7331 7795 \subsection{\texorpdfstring{\LstBasicStyle{timeval}}{timeval}} 7332 7796 \label{s:timeval} … … 7335 7799 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7336 7800 void ?{}( timeval & t ); 7801 void ?{}( timeval & t, zero_t ); 7337 7802 void ?{}( timeval & t, time_t sec, suseconds_t usec ); 7338 7803 void ?{}( timeval & t, time_t sec ); 7339 void ?{}( timeval & t, zero_t );7340 7804 void ?{}( timeval & t, Time time ); 7341 7805 … … 7343 7807 timeval ?+?( timeval & lhs, timeval rhs ); 7344 7808 timeval ?-?( timeval & lhs, timeval rhs ); 7345 _Bool ?==?( timeval lhs, timeval rhs );7346 _Bool ?!=?( timeval lhs, timeval rhs );7347 \end{cfa} 7348 7349 7350 %\subsection{\texorpdfstring{\protect\lstinline @timespec@}{timespec}}7809 bool ?==?( timeval lhs, timeval rhs ); 7810 bool ?!=?( timeval lhs, timeval rhs ); 7811 \end{cfa} 7812 7813 7814 %\subsection{\texorpdfstring{\protect\lstinline{timespec}}{timespec}} 7351 7815 \subsection{\texorpdfstring{\LstBasicStyle{timespec}}{timespec}} 7352 7816 \label{s:timespec} … … 7355 7819 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7356 7820 void ?{}( timespec & t ); 7821 void ?{}( timespec & t, zero_t ); 7357 7822 void ?{}( timespec & t, time_t sec, __syscall_slong_t nsec ); 7358 7823 void ?{}( timespec & t, time_t sec ); 7359 void ?{}( timespec & t, zero_t );7360 7824 void ?{}( timespec & t, Time time ); 7361 7825 … … 7363 7827 timespec ?+?( timespec & lhs, timespec rhs ); 7364 7828 timespec ?-?( timespec & lhs, timespec rhs ); 7365 _Bool ?==?( timespec lhs, timespec rhs );7366 _Bool ?!=?( timespec lhs, timespec rhs );7367 \end{cfa} 7368 7369 7370 %\subsection{\texorpdfstring{\protect\lstinline @itimerval@}{itimerval}}7829 bool ?==?( timespec lhs, timespec rhs ); 7830 bool ?!=?( timespec lhs, timespec rhs ); 7831 \end{cfa} 7832 7833 7834 %\subsection{\texorpdfstring{\protect\lstinline{itimerval}}{itimerval}} 7371 7835 \subsection{\texorpdfstring{\LstBasicStyle{itimerval}}{itimerval}} 7372 7836 \label{s:itimerval} … … 7379 7843 7380 7844 7381 %\subsection{\texorpdfstring{\protect\lstinline @Time@}{Time}}7845 %\subsection{\texorpdfstring{\protect\lstinline{Time}}{Time}} 7382 7846 \subsection{\texorpdfstring{\LstBasicStyle{Time}}{Time}} 7383 7847 \label{s:Time} … … 7386 7850 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7387 7851 struct Time { 7388 uint64_t t v; $\C{// nanoseconds since UNIX epoch}$7852 uint64_t tn; $\C{// nanoseconds since UNIX epoch}$ 7389 7853 }; 7390 7854 7391 7855 void ?{}( Time & time ); 7392 7856 void ?{}( Time & time, zero_t ); 7857 void ?{}( Time & time, timeval t ); 7858 void ?{}( Time & time, timespec t ); 7393 7859 7394 7860 Time ?=?( Time & time, zero_t ); 7395 7396 void ?{}( Time & time, timeval t );7397 7861 Time ?=?( Time & time, timeval t ); 7398 7399 void ?{}( Time & time, timespec t );7400 7862 Time ?=?( Time & time, timespec t ); 7401 7863 … … 7407 7869 Time ?-?( Time lhs, Duration rhs ); 7408 7870 Time ?-=?( Time & lhs, Duration rhs ); 7409 _Bool ?==?( Time lhs, Time rhs ); 7410 _Bool ?!=?( Time lhs, Time rhs ); 7411 _Bool ?<?( Time lhs, Time rhs ); 7412 _Bool ?<=?( Time lhs, Time rhs ); 7413 _Bool ?>?( Time lhs, Time rhs ); 7414 _Bool ?>=?( Time lhs, Time rhs ); 7871 bool ?==?( Time lhs, Time rhs ); 7872 bool ?!=?( Time lhs, Time rhs ); 7873 bool ?<?( Time lhs, Time rhs ); 7874 bool ?<=?( Time lhs, Time rhs ); 7875 bool ?>?( Time lhs, Time rhs ); 7876 bool ?>=?( Time lhs, Time rhs ); 7877 7878 int64_t ?`ns( Time t ); 7415 7879 7416 7880 char * yy_mm_dd( Time time, char * buf ); 7417 char * ?`ymd( Time time, char * buf ) { // short form 7418 return yy_mm_dd( time, buf ); 7419 } // ymd 7881 char * ?`ymd( Time time, char * buf ); // short form 7420 7882 7421 7883 char * mm_dd_yy( Time time, char * buf ); 7422 char * ?`mdy( Time time, char * buf ) { // short form 7423 return mm_dd_yy( time, buf ); 7424 } // mdy 7884 char * ?`mdy( Time time, char * buf ); // short form 7425 7885 7426 7886 char * dd_mm_yy( Time time, char * buf ); 7427 char * ?`dmy( Time time, char * buf ) { // short form 7428 return dd_mm_yy( time, buf );; 7429 } // dmy 7887 char * ?`dmy( Time time, char * buf ); // short form 7430 7888 7431 7889 size_t strftime( char * buf, size_t size, const char * fmt, Time time ); 7432 forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype & os, Time time ); 7890 7891 forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype & os, Time time ); 7433 7892 \end{cfa} 7434 7893 … … 7450 7909 7451 7910 7452 %\subsection{\texorpdfstring{\protect\lstinline @Clock@}{Clock}}7911 %\subsection{\texorpdfstring{\protect\lstinline{Clock}}{Clock}} 7453 7912 \subsection{\texorpdfstring{\LstBasicStyle{Clock}}{Clock}} 7454 7913 \label{s:Clock} … … 7456 7915 \leavevmode 7457 7916 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 7458 struct Clock { 7459 Duration offset; $\C{// for virtual clock: contains offset from real-time}$ 7460 int clocktype; $\C{// implementation only -1 (virtual), CLOCK\_REALTIME}$ 7917 struct Clock { $\C{// virtual clock}$ 7918 Duration offset; $\C{// offset from computer real-time}$ 7461 7919 }; 7462 7920 7463 void resetClock( Clock & clk ); 7464 void resetClock( Clock & clk, Duration adj ); 7465 void ?{}( Clock & clk ); 7466 void ?{}( Clock & clk, Duration adj ); 7467 7468 Duration getResNsec(); $\C{// with nanoseconds}$ 7469 Duration getRes(); $\C{// without nanoseconds}$ 7470 7471 Time getTimeNsec(); $\C{// with nanoseconds}$ 7472 Time getTime(); $\C{// without nanoseconds}$ 7473 Time getTime( Clock & clk ); 7474 Time ?()( Clock & clk ); 7475 timeval getTime( Clock & clk ); 7476 tm getTime( Clock & clk ); 7921 void ?{}( Clock & clk ); $\C{// create no offset}$ 7922 void ?{}( Clock & clk, Duration adj ); $\C{// create with offset}$ 7923 void reset( Clock & clk, Duration adj ); $\C{// change offset}$ 7924 7925 Duration resolutionHi(); $\C{// clock resolution in nanoseconds (fine)}$ 7926 Duration resolution(); $\C{// clock resolution without nanoseconds (coarse)}$ 7927 7928 Time timeHiRes(); $\C{// real time with nanoseconds}$ 7929 Time time(); $\C{// real time without nanoseconds}$ 7930 Time time( Clock & clk ); $\C{// real time for given clock}$ 7931 Time ?()( Clock & clk ); $\C{//\ \ \ \ alternative syntax}$ 7932 timeval time( Clock & clk ); $\C{// convert to C time format}$ 7933 tm time( Clock & clk ); 7934 Duration processor(); $\C{// non-monotonic duration of kernel thread}$ 7935 Duration program(); $\C{// non-monotonic duration of program CPU}$ 7936 Duration boot(); $\C{// monotonic duration since computer boot}$ 7477 7937 \end{cfa} 7478 7938 … … 7645 8105 forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp ); 7646 8106 \end{cfa} 7647 7648 The following factorial programs contrast using GMP with the \CFA and C interfaces, where the output from these programs appears in \VRef[Figure]{f:MultiPrecisionFactorials}. 8107 \VRef[Figure]{f:MultiPrecisionFactorials} shows \CFA and C factorial programs using the GMP interfaces. 7649 8108 (Compile with flag \Indexc{-lgmp} to link with the GMP library.) 8109 8110 \begin{figure} 7650 8111 \begin{cquote} 7651 8112 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}} 7652 \multicolumn{1}{ c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}} \\8113 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}@{}} \\ 7653 8114 \hline 7654 8115 \begin{cfa} … … 7659 8120 7660 8121 sout | 0 | fact; 7661 for ( unsigned int i = 1; i <= 40; i += 1) {8122 for ( i; 40 ) { 7662 8123 fact *= i; 7663 8124 sout | i | fact; … … 7669 8130 #include <gmp.h>$\indexc{gmp.h}$ 7670 8131 int main( void ) { 7671 @gmp_printf@( "Factorial Numbers\n" );7672 @mpz_t@fact;7673 @mpz_init_set_ui@( fact, 1 );7674 @gmp_printf@( "%d %Zd\n", 0, fact );8132 ®gmp_printf®( "Factorial Numbers\n" ); 8133 ®mpz_t® fact; 8134 ®mpz_init_set_ui®( fact, 1 ); 8135 ®gmp_printf®( "%d %Zd\n", 0, fact ); 7675 8136 for ( unsigned int i = 1; i <= 40; i += 1 ) { 7676 @mpz_mul_ui@( fact, fact, i );7677 @gmp_printf@( "%d %Zd\n", i, fact );8137 ®mpz_mul_ui®( fact, fact, i ); 8138 ®gmp_printf®( "%d %Zd\n", i, fact ); 7678 8139 } 7679 8140 } … … 7681 8142 \end{tabular} 7682 8143 \end{cquote} 7683 7684 \begin{figure} 8144 \small 7685 8145 \begin{cfa} 7686 8146 Factorial Numbers -
example/io/batch-readv.c
rfeacef9 r5407cdc 66 66 } 67 67 68 uint64_t getTimeNsec() {68 uint64_t timeHiRes() { 69 69 timespec curr; 70 70 clock_gettime( CLOCK_REALTIME, &curr ); … … 163 163 164 164 printf("Running for %f second, reading %d bytes in batches of %d\n", duration, buflen, batch); 165 uint64_t start = getTimeNsec();166 uint64_t end = getTimeNsec();167 uint64_t prev = getTimeNsec();165 uint64_t start = timeHiRes(); 166 uint64_t end = timeHiRes(); 167 uint64_t prev = timeHiRes(); 168 168 for(;;) { 169 169 submit_and_drain(&iov, batch); 170 end = getTimeNsec();170 end = timeHiRes(); 171 171 uint64_t delta = end - start; 172 172 if( to_fseconds(end - prev) > 0.1 ) { -
libcfa/configure.ac
rfeacef9 r5407cdc 169 169 AH_TEMPLATE([CFA_HAVE_IOSQE_FIXED_FILE],[Defined if io_uring support is present when compiling libcfathread and supports the flag FIXED_FILE.]) 170 170 AH_TEMPLATE([CFA_HAVE_IOSQE_IO_DRAIN],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_DRAIN.]) 171 AH_TEMPLATE([CFA_HAVE_IOSQE_ASYNC],[Defined if io_uring support is present when compiling libcfathread and supports the flag ASYNC.])172 171 AH_TEMPLATE([CFA_HAVE_IOSQE_IO_LINK],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_LINK.]) 173 172 AH_TEMPLATE([CFA_HAVE_IOSQE_IO_HARDLINK],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_HARDLINK.]) 173 AH_TEMPLATE([CFA_HAVE_IOSQE_ASYNC],[Defined if io_uring support is present when compiling libcfathread and supports the flag ASYNC.]) 174 AH_TEMPLATE([CFA_HAVE_IOSQE_BUFFER_SELECT],[Defined if io_uring support is present when compiling libcfathread and supports the flag BUFFER_SELEC.]) 174 175 AH_TEMPLATE([CFA_HAVE_SPLICE_F_FD_IN_FIXED],[Defined if io_uring support is present when compiling libcfathread and supports the flag SPLICE_F_FD_IN_FIXED.]) 175 176 AH_TEMPLATE([CFA_HAVE_IORING_SETUP_ATTACH_WQ],[Defined if io_uring support is present when compiling libcfathread and supports the flag IORING_SETUP_ATTACH_WQ.]) … … 182 183 183 184 define(ioring_ops, [IORING_OP_NOP,IORING_OP_READV,IORING_OP_WRITEV,IORING_OP_FSYNC,IORING_OP_READ_FIXED,IORING_OP_WRITE_FIXED,IORING_OP_POLL_ADD,IORING_OP_POLL_REMOVE,IORING_OP_SYNC_FILE_RANGE,IORING_OP_SENDMSG,IORING_OP_RECVMSG,IORING_OP_TIMEOUT,IORING_OP_TIMEOUT_REMOVE,IORING_OP_ACCEPT,IORING_OP_ASYNC_CANCEL,IORING_OP_LINK_TIMEOUT,IORING_OP_CONNECT,IORING_OP_FALLOCATE,IORING_OP_OPENAT,IORING_OP_CLOSE,IORING_OP_FILES_UPDATE,IORING_OP_STATX,IORING_OP_READ,IORING_OP_WRITE,IORING_OP_FADVISE,IORING_OP_MADVISE,IORING_OP_SEND,IORING_OP_RECV,IORING_OP_OPENAT2,IORING_OP_EPOLL_CTL,IORING_OP_SPLICE,IORING_OP_PROVIDE_BUFFERS,IORING_OP_REMOVE_BUFFER,IORING_OP_TEE]) 184 define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_ ASYNC,IOSQE_IO_LINK,IOSQE_IO_HARDLINK,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ])185 define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_IO_LINK,IOSQE_IO_HARDLINK,IOSQE_ASYNC,IOSQE_BUFFER_SELECT,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ]) 185 186 186 187 define(ioring_from_decls, [ -
libcfa/prelude/builtins.c
rfeacef9 r5407cdc 9 9 // Author : Peter A. Buhr 10 10 // Created On : Fri Jul 21 16:21:03 2017 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue Oct 27 14:42:00 202013 // Update Count : 11 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 13 17:26:32 2021 13 // Update Count : 117 14 14 // 15 15 … … 125 125 } // distribution 126 126 127 #define __CFA_BASE_COMP_1__() if ( ep== 1 ) return 1128 #define __CFA_BASE_COMP_2__() if ( ep == 2 ) return ep<< (y - 1)127 #define __CFA_BASE_COMP_1__() if ( x == 1 ) return 1 128 #define __CFA_BASE_COMP_2__() if ( x == 2 ) return x << (y - 1) 129 129 #define __CFA_EXP_OVERFLOW__() if ( y >= sizeof(y) * CHAR_BIT ) return 0 130 130 … … 134 134 __CFA_BASE_COMP_2__(); /* special case, positive shifting for integral types */ \ 135 135 __CFA_EXP_OVERFLOW__(); /* immediate overflow, negative exponent > 2^size-1 */ \ 136 typeof( ep) op = 1; /* accumulate odd product */ \136 typeof(x) op = 1; /* accumulate odd product */ \ 137 137 for ( ; y > 1; y >>= 1 ) { /* squaring exponentiation, O(log2 y) */ \ 138 if ( (y & 1) == 1 ) op = op * ep; /* odd ? */ \139 ep = ep * ep; \138 if ( (y & 1) == 1 ) op = op * x; /* odd ? */ \ 139 x = x * x; \ 140 140 } \ 141 return ep* op141 return x * op 142 142 143 143 static inline { 144 long int ?\?( int ep, unsigned int y ) { __CFA_EXP__(); } 145 long int ?\?( long int ep, unsigned long int y ) { __CFA_EXP__(); } 144 long int ?\?( int x, unsigned int y ) { __CFA_EXP__(); } 145 long int ?\?( long int x, unsigned long int y ) { __CFA_EXP__(); } 146 long long int ?\?( long long int x, unsigned long long int y ) { __CFA_EXP__(); } 146 147 // unsigned computation may be faster and larger 147 unsigned long int ?\?( unsigned int ep, unsigned int y ) { __CFA_EXP__(); } 148 unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { __CFA_EXP__(); } 148 unsigned long int ?\?( unsigned int x, unsigned int y ) { __CFA_EXP__(); } 149 unsigned long int ?\?( unsigned long int x, unsigned long int y ) { __CFA_EXP__(); } 150 unsigned long long int ?\?( unsigned long long int x, unsigned long long int y ) { __CFA_EXP__(); } 149 151 } // distribution 150 152 … … 157 159 158 160 static inline forall( OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) { 159 OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); } 160 OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); } 161 OT ?\?( OT x, unsigned int y ) { __CFA_EXP__(); } 162 OT ?\?( OT x, unsigned long int y ) { __CFA_EXP__(); } 163 OT ?\?( OT x, unsigned long long int y ) { __CFA_EXP__(); } 161 164 } // distribution 162 165 … … 166 169 167 170 static inline { 171 long int ?\=?( int & x, unsigned int y ) { x = x \ y; return x; } 168 172 long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; } 173 long long int ?\=?( long long int & x, unsigned long long int y ) { x = x \ y; return x; } 174 unsigned long int ?\=?( unsigned int & x, unsigned int y ) { x = x \ y; return x; } 169 175 unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; } 170 int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; } 171 unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; } 176 unsigned long long int ?\=?( unsigned long long int & x, unsigned long long int y ) { x = x \ y; return x; } 172 177 } // distribution 173 178 -
libcfa/prelude/defines.hfa.in
rfeacef9 r5407cdc 149 149 150 150 /* Defined if io_uring support is present when compiling libcfathread and 151 supports the flag BUFFER_SELEC. */ 152 #undef CFA_HAVE_IOSQE_BUFFER_SELECT 153 154 /* Defined if io_uring support is present when compiling libcfathread and 151 155 supports the flag FIXED_FILE. */ 152 156 #undef CFA_HAVE_IOSQE_FIXED_FILE -
libcfa/src/Makefile.am
rfeacef9 r5407cdc 11 11 ## Created On : Sun May 31 08:54:01 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Wed Dec 9 22:46:14 202014 ## Update Count : 25 013 ## Last Modified On : Sat Apr 24 09:09:56 2021 14 ## Update Count : 254 15 15 ############################################################################### 16 16 … … 56 56 bits/queue.hfa \ 57 57 bits/sequence.hfa \ 58 containers/array.hfa \ 58 59 concurrency/iofwd.hfa \ 59 60 containers/list.hfa \ 61 containers/queueLockFree.hfa \ 60 62 containers/stackLockFree.hfa \ 61 63 vec/vec.hfa \ … … 67 69 common.hfa \ 68 70 fstream.hfa \ 71 strstream.hfa \ 69 72 heap.hfa \ 70 73 iostream.hfa \ -
libcfa/src/bits/debug.hfa
rfeacef9 r5407cdc 101 101 __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_print_buffer(STDERR_FILENO, __VA_ARGS__)) 102 102 #define __cfadbg_print_buffer_decl(group, ...) \ 103 __CFADBG_PRINT_GROUP_##group(char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( __dbg_text, __dbg_len ))103 __CFADBG_PRINT_GROUP_##group(char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( STDERR_FILENO, __dbg_text, __dbg_len )) 104 104 #define __cfadbg_print_buffer_local(group, ...) \ 105 105 __CFADBG_PRINT_GROUP_##group(__dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write(STDERR_FILENO, __dbg_text, __dbg_len)) -
libcfa/src/bits/defs.hfa
rfeacef9 r5407cdc 74 74 #error unsupported architecture 75 75 #endif 76 77 #define CFA_IO_LAZY (1_l64u << 32_l64u) -
libcfa/src/bits/locks.hfa
rfeacef9 r5407cdc 37 37 extern "C" { 38 38 extern void disable_interrupts() OPTIONAL_THREAD; 39 extern void enable_interrupts _noPoll() OPTIONAL_THREAD;39 extern void enable_interrupts( bool poll = true ) OPTIONAL_THREAD; 40 40 41 41 #ifdef __CFA_DEBUG__ … … 57 57 __cfaabi_dbg_record_lock( this, caller ); 58 58 } else { 59 enable_interrupts _noPoll();59 enable_interrupts( false ); 60 60 } 61 61 return result; … … 90 90 static inline void unlock( __spinlock_t & this ) { 91 91 __atomic_clear( &this.lock, __ATOMIC_RELEASE ); 92 enable_interrupts _noPoll();92 enable_interrupts( false ); 93 93 } 94 94 #endif -
libcfa/src/bits/queue.hfa
rfeacef9 r5407cdc 15 15 }; 16 16 17 inline {17 static inline { 18 18 // wrappers to make Collection have T 19 19 T & head( Queue(T) & q ) with( q ) { … … 154 154 struct QueueIter { 155 155 inline ColIter; // Plan 9 inheritance 156 }; 156 }; 157 157 158 inline {158 static inline { 159 159 void ?{}( QueueIter(T) & qi ) with( qi ) { 160 160 ((ColIter &)qi){}; -
libcfa/src/bits/weakso_locks.cfa
rfeacef9 r5407cdc 18 18 #include "bits/weakso_locks.hfa" 19 19 20 void ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner) {}21 void ^?{}( blocking_lock & this) {}20 void ?{}( blocking_lock &, bool, bool ) {} 21 void ^?{}( blocking_lock & ) {} 22 22 23 void lock( blocking_lock & this ) {} 24 bool try_lock( blocking_lock & this ) { return false; } 25 void unlock( blocking_lock & this ) {} 26 void on_notify( blocking_lock & this, struct $thread * t ) {} 27 void on_wait( blocking_lock & this ) {} 28 size_t wait_count( blocking_lock & this ) { return 0; } 29 void set_recursion_count( blocking_lock & this, size_t recursion ) {} 30 size_t get_recursion_count( blocking_lock & this ) { return 0; } 23 void lock( blocking_lock & ) {} 24 bool try_lock( blocking_lock & ) { return false; } 25 void unlock( blocking_lock & ) {} 26 void on_notify( blocking_lock &, struct $thread * ) {} 27 size_t on_wait( blocking_lock & ) { return 0; } 28 void on_wakeup( blocking_lock &, size_t ) {} 29 size_t wait_count( blocking_lock & ) { return 0; } -
libcfa/src/bits/weakso_locks.hfa
rfeacef9 r5407cdc 56 56 void unlock( blocking_lock & this ) OPTIONAL_THREAD; 57 57 void on_notify( blocking_lock & this, struct $thread * t ) OPTIONAL_THREAD; 58 void on_wait( blocking_lock & this ) OPTIONAL_THREAD; 58 size_t on_wait( blocking_lock & this ) OPTIONAL_THREAD; 59 void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD; 59 60 size_t wait_count( blocking_lock & this ) OPTIONAL_THREAD; 60 void set_recursion_count( blocking_lock & this, size_t recursion ) OPTIONAL_THREAD;61 size_t get_recursion_count( blocking_lock & this ) OPTIONAL_THREAD;62 61 63 62 //---------- … … 69 68 static inline void ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };} 70 69 static inline void ^?{}( multiple_acquisition_lock & this ) {} 71 static inline void lock ( multiple_acquisition_lock & this ) { lock ( (blocking_lock &)this ); } 72 static inline void unlock ( multiple_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 73 static inline void on_wait ( multiple_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); } 70 static inline void lock ( multiple_acquisition_lock & this ) { lock ( (blocking_lock &)this ); } 71 static inline bool try_lock ( multiple_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); } 72 static inline void unlock ( multiple_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 73 static inline size_t on_wait ( multiple_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); } 74 static inline void on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 74 75 static inline void on_notify( multiple_acquisition_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); } 75 static inline void set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }76 static inline size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); } -
libcfa/src/clock.hfa
rfeacef9 r5407cdc 10 10 // Created On : Thu Apr 12 14:36:06 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 6 12:49:58 202013 // Update Count : 912 // Last Modified On : Sun Apr 18 08:12:16 2021 13 // Update Count : 28 14 14 // 15 15 … … 27 27 //######################### Clock ######################### 28 28 29 struct Clock { // private 30 Duration offset; // for virtual clock: contains offset from real-time 29 struct Clock { // virtual clock 30 // private 31 Duration offset; // offset from computer real-time 31 32 }; 32 33 33 34 static inline { 34 void reset Clock( Clock & clk, Duration adj ) with( clk ) {35 void reset( Clock & clk, Duration adj ) with( clk ) { // change offset 35 36 offset = adj + __timezone`s; // timezone (global) is (UTC - local time) in seconds 36 } // reset Clock37 } // reset 37 38 38 void ?{}( Clock & clk, Duration adj ) { resetClock( clk, adj ); } 39 void ?{}( Clock & clk ) { reset( clk, (Duration){ 0 } ); } // create no offset 40 void ?{}( Clock & clk, Duration adj ) { reset( clk, adj ); } // create with offset 39 41 40 Duration getResNsec() { 42 // System-wide clock that measures real, i.e., wall-clock) time. This clock is affected by discontinuous jumps in 43 // the system time. For example, manual changes of the clock, and incremental adjustments performed by adjtime(3) 44 // and NTP (daylight saving (Fall back). 45 Duration resolutionHi() { // clock resolution in nanoseconds (fine) 41 46 struct timespec res; 42 47 clock_getres( CLOCK_REALTIME, &res ); 43 48 return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns; 44 } // getRes49 } // resolutionHi 45 50 46 Duration getRes() {51 Duration resolution() { // clock resolution without nanoseconds (coarse) 47 52 struct timespec res; 48 53 clock_getres( CLOCK_REALTIME_COARSE, &res ); 49 54 return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns; 50 } // getRes55 } // resolution 51 56 52 Time getTimeNsec() { //with nanoseconds57 Time timeHiRes() { // real time with nanoseconds 53 58 timespec curr; 54 59 clock_gettime( CLOCK_REALTIME, &curr ); 55 60 return (Time){ curr }; 56 } // getTimeNsec61 } // timeHiRes 57 62 58 Time getTime() { //without nanoseconds63 Time time() { // real time without nanoseconds 59 64 timespec curr; 60 65 clock_gettime( CLOCK_REALTIME_COARSE, &curr ); 61 66 curr.tv_nsec = 0; 62 67 return (Time){ curr }; 63 } // getTime68 } // time 64 69 65 Time getTime( Clock & clk ) with( clk ) {66 return getTime() + offset;67 } // getTime70 Time time( Clock & clk ) with( clk ) { // real time for given clock 71 return time() + offset; 72 } // time 68 73 69 74 Time ?()( Clock & clk ) with( clk ) { // alternative syntax 70 return getTime() + offset;71 } // getTime75 return time() + offset; 76 } // ?() 72 77 73 timeval getTime( Clock & clk ) {78 timeval time( Clock & clk ) { // convert to C time format 74 79 return (timeval){ clk() }; 75 } // getTime80 } // time 76 81 77 tm getTime( Clock & clk ) with( clk ) {82 tm time( Clock & clk ) with( clk ) { 78 83 tm ret; 79 localtime_r( getTime( clk ).tv_sec, &ret );84 localtime_r( time( clk ).tv_sec, &ret ); 80 85 return ret; 81 } // getTime86 } // time 82 87 83 Time getCPUTime() { 88 // CFA processor CPU-time watch that ticks when the processor (kernel thread) is running. This watch is affected by 89 // discontinuous jumps when the OS is not running the kernal thread. A duration is returned because the value is 90 // relative and cannot be converted to real-time (wall-clock) time. 91 Duration processor() { // non-monotonic duration of kernel thread 84 92 timespec ts; 85 93 clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts ); 86 return (Time){ ts }; 87 } // getCPUTime 94 return (Duration){ ts }; 95 } // processor 96 97 // Program CPU-time watch measures CPU time consumed by all processors (kernel threads) in the UNIX process. This 98 // watch is affected by discontinuous jumps when the OS is not running the kernel threads. A duration is returned 99 // because the value is relative and cannot be converted to real-time (wall-clock) time. 100 Duration program() { // non-monotonic duration of program CPU 101 timespec ts; 102 clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &ts ); 103 return (Duration){ ts }; 104 } // program 105 106 // Monotonic duration from machine boot and including system suspension. This watch is unaffected by discontinuous 107 // jumps resulting from manual changes of the clock, and incremental adjustments performed by adjtime(3) and NTP 108 // (Fall back). A duration is returned because the value is relative and cannot be converted to real-time 109 // (wall-clock) time. 110 Duration boot() { // monotonic duration since computer boot 111 timespec ts; 112 clock_gettime( CLOCK_BOOTTIME, &ts ); 113 return (Duration){ ts }; 114 } // boot 88 115 } // distribution 89 116 -
libcfa/src/concurrency/alarm.cfa
rfeacef9 r5407cdc 15 15 16 16 #define __cforall_thread__ 17 // #define __CFA_DEBUG_PRINT_PREEMPTION__ 17 18 18 19 #include <errno.h> … … 107 108 bool first = ! & alarms`first; 108 109 110 __cfadbg_print_safe( preemption, " KERNEL: alarm inserting %p (%lu).\n", this, this->alarm.tn ); 109 111 insert( &alarms, this ); 110 112 if( first ) { … … 114 116 unlock( event_kernel->lock ); 115 117 this->set = true; 116 enable_interrupts( __cfaabi_dbg_ctx);118 enable_interrupts(); 117 119 } 118 120 … … 125 127 } 126 128 unlock( event_kernel->lock ); 127 enable_interrupts( __cfaabi_dbg_ctx);129 enable_interrupts(); 128 130 this->set = false; 129 131 } -
libcfa/src/concurrency/clib/cfathread.cfa
rfeacef9 r5407cdc 14 14 // 15 15 16 #include "fstream.hfa" 17 #include "locks.hfa" 16 18 #include "kernel.hfa" 19 #include "stats.hfa" 17 20 #include "thread.hfa" 18 19 thread CRunner { 20 void (*themain)( CRunner * ); 21 #include "time.hfa" 22 23 #include "cfathread.h" 24 25 extern void ?{}(processor &, const char[], cluster &, $thread *); 26 extern "C" { 27 extern void __cfactx_invoke_thread(void (*main)(void *), void * this); 28 } 29 30 //================================================================================ 31 // Thread run y the C Interface 32 33 struct cfathread_object { 34 $thread self; 35 void * (*themain)( void * ); 36 void * arg; 37 void * ret; 21 38 }; 22 23 static void ?{}( CRunner & this, void (*themain)( CRunner * ) ) { 39 void main(cfathread_object & this); 40 void ^?{}(cfathread_object & mutex this); 41 42 static inline $thread * get_thread( cfathread_object & this ) { return &this.self; } 43 44 typedef ThreadCancelled(cfathread_object) cfathread_exception; 45 typedef ThreadCancelled_vtable(cfathread_object) cfathread_vtable; 46 47 void defaultResumptionHandler(ThreadCancelled(cfathread_object) & except) { 48 abort | "A thread was cancelled"; 49 } 50 51 cfathread_vtable _cfathread_vtable_instance; 52 53 cfathread_vtable & const _default_vtable = _cfathread_vtable_instance; 54 55 cfathread_vtable const & get_exception_vtable(cfathread_exception *) { 56 return _cfathread_vtable_instance; 57 } 58 59 static void ?{}( cfathread_object & this, cluster & cl, void *(*themain)( void * ), void * arg ) { 24 60 this.themain = themain; 25 } 26 27 void main( CRunner & this ) { 28 this.themain( &this ); 29 } 30 31 processor * procs = 0p; 32 int proc_cnt = 1; 33 61 this.arg = arg; 62 (this.self){"C-thread", cl}; 63 __thrd_start(this, main); 64 } 65 66 void ^?{}(cfathread_object & mutex this) { 67 ^(this.self){}; 68 } 69 70 void main( cfathread_object & this ) { 71 __attribute__((unused)) void * const thrd_obj = (void*)&this; 72 __attribute__((unused)) void * const thrd_hdl = (void*)active_thread(); 73 /* paranoid */ verify( thrd_obj == thrd_hdl ); 74 75 this.ret = this.themain( this.arg ); 76 } 77 78 //================================================================================ 79 // Special Init Thread responsible for the initialization or processors 80 struct __cfainit { 81 $thread self; 82 void (*init)( void * ); 83 void * arg; 84 }; 85 void main(__cfainit & this); 86 void ^?{}(__cfainit & mutex this); 87 88 static inline $thread * get_thread( __cfainit & this ) { return &this.self; } 89 90 typedef ThreadCancelled(__cfainit) __cfainit_exception; 91 typedef ThreadCancelled_vtable(__cfainit) __cfainit_vtable; 92 93 void defaultResumptionHandler(ThreadCancelled(__cfainit) & except) { 94 abort | "The init thread was cancelled"; 95 } 96 97 __cfainit_vtable ___cfainit_vtable_instance; 98 99 __cfainit_vtable const & get_exception_vtable(__cfainit_exception *) { 100 return ___cfainit_vtable_instance; 101 } 102 103 static void ?{}( __cfainit & this, void (*init)( void * ), void * arg ) { 104 this.init = init; 105 this.arg = arg; 106 (this.self){"Processir Init"}; 107 108 // Don't use __thrd_start! just prep the context manually 109 $thread * this_thrd = get_thread(this); 110 void (*main_p)(__cfainit &) = main; 111 112 disable_interrupts(); 113 __cfactx_start(main_p, get_coroutine(this), this, __cfactx_invoke_thread); 114 115 this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP]; 116 /* paranoid */ verify( this_thrd->context.SP ); 117 118 this_thrd->state = Ready; 119 enable_interrupts(); 120 } 121 122 void ^?{}(__cfainit & mutex this) { 123 ^(this.self){}; 124 } 125 126 void main( __cfainit & this ) { 127 __attribute__((unused)) void * const thrd_obj = (void*)&this; 128 __attribute__((unused)) void * const thrd_hdl = (void*)active_thread(); 129 /* paranoid */ verify( thrd_obj == thrd_hdl ); 130 131 this.init( this.arg ); 132 } 133 134 //================================================================================ 135 // Main Api 34 136 extern "C" { 35 //-------------------- 36 // Basic thread management 37 CRunner * cfathread_create( void (*main)( CRunner * ) ) { 38 return new( main ); 39 } 40 41 void cfathread_join( CRunner * thrd ) { 42 delete( thrd ); 137 int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) { 138 *cl = new(); 139 return 0; 140 } 141 142 cfathread_cluster_t cfathread_cluster_self(void) { 143 return active_cluster(); 144 } 145 146 int cfathread_cluster_print_stats( cfathread_cluster_t cl ) { 147 #if !defined(__CFA_NO_STATISTICS__) 148 print_stats_at_exit( *cl, CFA_STATS_READY_Q | CFA_STATS_IO ); 149 print_stats_now( *cl, CFA_STATS_READY_Q | CFA_STATS_IO ); 150 #endif 151 return 0; 152 } 153 154 int cfathread_cluster_add_worker(cfathread_cluster_t cl, pthread_t* tid, void (*init_routine) (void *), void * arg) { 155 __cfainit * it = 0p; 156 if(init_routine) { 157 it = alloc(); 158 (*it){init_routine, arg}; 159 } 160 processor * proc = alloc(); 161 (*proc){ "C-processor", *cl, get_thread(*it) }; 162 163 // Wait for the init thread to return before continuing 164 if(it) { 165 ^(*it){}; 166 free(it); 167 } 168 169 if(tid) *tid = proc->kernel_thread; 170 return 0; 171 } 172 173 int cfathread_cluster_pause (cfathread_cluster_t) { 174 abort | "Pausing clusters is not supported"; 175 exit(1); 176 } 177 178 int cfathread_cluster_resume(cfathread_cluster_t) { 179 abort | "Resuming clusters is not supported"; 180 exit(1); 181 } 182 183 //-------------------- 184 // Thread attributes 185 int cfathread_attr_init(cfathread_attr_t *attr) __attribute__((nonnull (1))) { 186 attr->cl = active_cluster(); 187 return 0; 188 } 189 190 //-------------------- 191 // Thread 192 int cfathread_create( cfathread_t * handle, const cfathread_attr_t * attr, void *(*main)( void * ), void * arg ) __attribute__((nonnull (1))) { 193 cluster * cl = attr ? attr->cl : active_cluster(); 194 cfathread_t thrd = alloc(); 195 (*thrd){ *cl, main, arg }; 196 *handle = thrd; 197 return 0; 198 } 199 200 int cfathread_join( cfathread_t thrd, void ** retval ) { 201 void * ret = join( *thrd ).ret; 202 ^( *thrd ){}; 203 free(thrd); 204 if(retval) { 205 *retval = ret; 206 } 207 return 0; 208 } 209 210 int cfathread_get_errno(void) { 211 return errno; 212 } 213 214 cfathread_t cfathread_self(void) { 215 return (cfathread_t)active_thread(); 216 } 217 218 int cfathread_usleep(useconds_t usecs) { 219 sleep(usecs`us); 220 return 0; 221 } 222 223 int cfathread_sleep(unsigned int secs) { 224 sleep(secs`s); 225 return 0; 43 226 } 44 227 … … 47 230 } 48 231 49 void cfathread_unpark( CRunner *thrd ) {232 void cfathread_unpark( cfathread_t thrd ) { 50 233 unpark( *thrd ); 51 234 } … … 55 238 } 56 239 57 //-------------------- 58 // Basic kernel features 59 void cfathread_setproccnt( int ncnt ) { 60 assert( ncnt >= 1 ); 61 adelete( procs ); 62 63 proc_cnt = ncnt - 1; 64 procs = anew(proc_cnt); 65 } 66 } 240 typedef struct cfathread_mutex * cfathread_mutex_t; 241 242 //-------------------- 243 // Mutex 244 struct cfathread_mutex { 245 fast_lock impl; 246 }; 247 int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict) __attribute__((nonnull (1))) { *mut = new(); return 0; } 248 int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1))) { delete( *mut ); return 0; } 249 int cfathread_mutex_lock (cfathread_mutex_t *mut) __attribute__((nonnull (1))) { lock( (*mut)->impl ); return 0; } 250 int cfathread_mutex_unlock (cfathread_mutex_t *mut) __attribute__((nonnull (1))) { unlock( (*mut)->impl ); return 0; } 251 int cfathread_mutex_trylock(cfathread_mutex_t *mut) __attribute__((nonnull (1))) { 252 bool ret = try_lock( (*mut)->impl ); 253 if( ret ) return 0; 254 else return EBUSY; 255 } 256 257 //-------------------- 258 // Condition 259 struct cfathread_condition { 260 condition_variable(fast_lock) impl; 261 }; 262 int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict) __attribute__((nonnull (1))) { *cond = new(); return 0; } 263 int cfathread_cond_signal(cfathread_cond_t *cond) __attribute__((nonnull (1))) { notify_one( (*cond)->impl ); return 0; } 264 int cfathread_cond_wait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut) __attribute__((nonnull (1,2))) { wait( (*cond)->impl, (*mut)->impl ); return 0; } 265 int cfathread_cond_timedwait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut, const struct timespec *restrict abstime) __attribute__((nonnull (1,2,3))) { 266 Time t = { *abstime }; 267 if( wait( (*cond)->impl, (*mut)->impl, t ) ) { 268 return 0; 269 } 270 errno = ETIMEDOUT; 271 return ETIMEDOUT; 272 } 273 } 274 275 #include <iofwd.hfa> 276 277 extern "C" { 278 #include <unistd.h> 279 #include <sys/types.h> 280 #include <sys/socket.h> 281 282 //-------------------- 283 // IO operations 284 int cfathread_socket(int domain, int type, int protocol) { 285 return socket(domain, type, protocol); 286 } 287 int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) { 288 return bind(socket, address, address_len); 289 } 290 291 int cfathread_listen(int socket, int backlog) { 292 return listen(socket, backlog); 293 } 294 295 int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) { 296 return cfa_accept4(socket, address, address_len, 0, CFA_IO_LAZY); 297 } 298 299 int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) { 300 return cfa_connect(socket, address, address_len, CFA_IO_LAZY); 301 } 302 303 int cfathread_dup(int fildes) { 304 return dup(fildes); 305 } 306 307 int cfathread_close(int fildes) { 308 return cfa_close(fildes, CFA_IO_LAZY); 309 } 310 311 ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags) { 312 return cfa_sendmsg(socket, message, flags, CFA_IO_LAZY); 313 } 314 315 ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte) { 316 // Use send rather then write for socket since it's faster 317 return cfa_send(fildes, buf, nbyte, 0, CFA_IO_LAZY); 318 } 319 320 ssize_t cfathread_recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len) { 321 struct iovec iov; 322 iov.iov_base = buffer; 323 iov.iov_len = length; 324 325 struct msghdr msg; 326 msg.msg_name = address; 327 msg.msg_namelen = address_len ? (socklen_t)*address_len : (socklen_t)0; 328 msg.msg_iov = &iov; 329 msg.msg_iovlen = 1; 330 msg.msg_control = 0p; 331 msg.msg_controllen = 0; 332 333 ssize_t ret = cfa_recvmsg(socket, &msg, flags, CFA_IO_LAZY); 334 335 if(address_len) *address_len = msg.msg_namelen; 336 return ret; 337 } 338 339 ssize_t cfathread_read(int fildes, void *buf, size_t nbyte) { 340 // Use recv rather then read for socket since it's faster 341 return cfa_recv(fildes, buf, nbyte, 0, CFA_IO_LAZY); 342 } 343 344 } -
libcfa/src/concurrency/clib/cfathread.h
rfeacef9 r5407cdc 14 14 // 15 15 16 #include "stddef.h"17 #include "invoke.h"18 19 16 #if defined(__cforall) || defined(__cplusplus) 20 17 extern "C" { 21 18 #endif 19 #include <asm/types.h> 20 #include <errno.h> 21 #include <unistd.h> 22 23 22 24 //-------------------- 23 25 // Basic types 24 struct cfathread_CRunner_t; 25 typedef struct cfathread_CRunner_t * cfathread_t; 26 27 typedef struct cluster * cfathread_cluster_t; 28 29 int cfathread_cluster_create(cfathread_cluster_t * cluster); 30 cfathread_cluster_t cfathread_cluster_self(void); 31 int cfathread_cluster_print_stats(cfathread_cluster_t cluster); 32 int cfathread_cluster_add_worker(cfathread_cluster_t cluster, pthread_t* tid, void (*init_routine) (void *), void * arg); 33 int cfathread_cluster_pause (cfathread_cluster_t cluster); 34 int cfathread_cluster_resume(cfathread_cluster_t cluster); 26 35 27 36 //-------------------- 28 // Basic thread support 29 cfathread_t cfathread_create( void (*main)( cfathread_t ) ); 30 void cfathread_join( cfathread_t ); 37 // thread attribute 38 typedef struct cfathread_attr { 39 cfathread_cluster_t cl; 40 } cfathread_attr_t; 41 42 int cfathread_attr_init(cfathread_attr_t * attr) __attribute__((nonnull (1))); 43 static inline int cfathread_attr_destroy(cfathread_attr_t * attr) __attribute__((nonnull (1))); 44 static inline int cfathread_attr_destroy(cfathread_attr_t * attr) { return 0; } 45 static inline int cfathread_attr_setbackground(cfathread_attr_t * attr, int background) __attribute__((nonnull (1))); 46 static inline int cfathread_attr_setbackground(cfathread_attr_t * attr, int background) { return 0; } 47 static inline int cfathread_attr_setcluster(cfathread_attr_t * attr, cfathread_cluster_t cl) __attribute__((nonnull (1))); 48 static inline int cfathread_attr_setcluster(cfathread_attr_t * attr, cfathread_cluster_t cl) { attr->cl = cl; return 0; } 49 50 //-------------------- 51 // thread type 52 struct cfathread_object; 53 typedef struct cfathread_object * cfathread_t; 54 55 int cfathread_create( cfathread_t * h, const cfathread_attr_t * a, void *(*main)( void * ), void * arg ) __attribute__((nonnull (1))); 56 int cfathread_join( cfathread_t, void ** retval ); 57 58 int cfathread_get_errno(void); 59 cfathread_t cfathread_self(void); 60 61 int cfathread_usleep(useconds_t usecs); 62 int cfathread_sleep(unsigned int secs); 31 63 32 64 void cfathread_park( void ); … … 35 67 36 68 //-------------------- 37 // Basic kernel features38 void cfathread_setproccnt( int );69 // mutex and condition 70 struct timespec; 39 71 72 typedef struct cfathread_mutex_attr { 73 } cfathread_mutexattr_t; 74 typedef struct cfathread_mutex * cfathread_mutex_t; 75 int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict attr) __attribute__((nonnull (1))); 76 int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1))); 77 int cfathread_mutex_lock(cfathread_mutex_t *mut) __attribute__((nonnull (1))); 78 int cfathread_mutex_trylock(cfathread_mutex_t *mut) __attribute__((nonnull (1))); 79 int cfathread_mutex_unlock(cfathread_mutex_t *mut) __attribute__((nonnull (1))); 80 81 typedef struct cfathread_cond_attr { 82 } cfathread_condattr_t; 83 typedef struct cfathread_condition * cfathread_cond_t; 84 int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict attr) __attribute__((nonnull (1))); 85 int cfathread_cond_wait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut) __attribute__((nonnull (1,2))); 86 int cfathread_cond_timedwait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut, const struct timespec *restrict abstime) __attribute__((nonnull (1,2,3))); 87 int cfathread_cond_signal(cfathread_cond_t *cond) __attribute__((nonnull (1))); 88 89 //-------------------- 90 // IO operations 91 struct sockaddr; 92 struct msghdr; 93 int cfathread_socket(int domain, int type, int protocol); 94 int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len); 95 int cfathread_listen(int socket, int backlog); 96 int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len); 97 int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len); 98 int cfathread_dup(int fildes); 99 int cfathread_close(int fildes); 100 ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags); 101 ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte); 102 ssize_t cfathread_recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len); 103 ssize_t cfathread_read(int fildes, void *buf, size_t nbyte); 40 104 41 105 #if defined(__cforall) || defined(__cplusplus) -
libcfa/src/concurrency/coroutine.cfa
rfeacef9 r5407cdc 46 46 47 47 //----------------------------------------------------------------------------- 48 FORALL_DATA_INSTANCE(CoroutineCancelled, (coroutine_t &), (coroutine_t))49 50 forall(T &)51 void mark_exception(CoroutineCancelled(T) *) {}52 53 48 forall(T &) 54 49 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) { … … 65 60 // This code should not be inlined. It is the error path on resume. 66 61 forall(T & | is_coroutine(T)) 67 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ) { 62 void __cfaehm_cancelled_coroutine( 63 T & cor, $coroutine * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ) { 68 64 verify( desc->cancellation ); 69 65 desc->state = Cancelled; … … 72 68 // TODO: Remove explitate vtable set once trac#186 is fixed. 73 69 CoroutineCancelled(T) except; 74 except.virtual_table = & get_exception_vtable(&except);70 except.virtual_table = &_default_vtable; 75 71 except.the_coroutine = &cor; 76 72 except.the_exception = except; 77 throwResume except; 73 // Why does this need a cast? 74 throwResume (CoroutineCancelled(T) &)except; 78 75 79 76 except->virtual_table->free( except ); … … 148 145 // Part of the Public API 149 146 // Not inline since only ever called once per coroutine 150 forall(T & | is_coroutine(T) )147 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); }) 151 148 void prime(T& cor) { 152 149 $coroutine* this = get_coroutine(cor); … … 196 193 197 194 void __stack_clean ( __stack_info_t * this ) { 198 size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t);199 195 void * storage = this->storage->limit; 200 196 201 197 #if CFA_COROUTINE_USE_MMAP 198 size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t); 202 199 storage = (void *)(((intptr_t)storage) - __page_size); 203 200 if(munmap(storage, size + __page_size) == -1) { -
libcfa/src/concurrency/coroutine.hfa
rfeacef9 r5407cdc 22 22 //----------------------------------------------------------------------------- 23 23 // Exception thrown from resume when a coroutine stack is cancelled. 24 FORALL_DATA_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (24 EHM_FORALL_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) ( 25 25 coroutine_t * the_coroutine; 26 26 exception_t * the_exception; … … 60 60 //----------------------------------------------------------------------------- 61 61 // Public coroutine API 62 forall(T & | is_coroutine(T) )62 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); }) 63 63 void prime(T & cor); 64 64 … … 130 130 131 131 forall(T & | is_coroutine(T)) 132 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ); 132 void __cfaehm_cancelled_coroutine( 133 T & cor, $coroutine * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ); 133 134 134 135 // Resume implementation inlined for performance 135 forall(T & | is_coroutine(T) )136 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); }) 136 137 static inline T & resume(T & cor) { 137 138 // optimization : read TLS once and reuse it … … 163 164 $ctx_switch( src, dst ); 164 165 if ( unlikely(dst->cancellation) ) { 165 __cfaehm_cancelled_coroutine( cor, dst );166 __cfaehm_cancelled_coroutine( cor, dst, _default_vtable ); 166 167 } 167 168 -
libcfa/src/concurrency/future.hfa
rfeacef9 r5407cdc 37 37 38 38 // Fulfil the future, returns whether or not someone was unblocked 39 boolfulfil( future(T) & this, T result ) {39 $thread * fulfil( future(T) & this, T result ) { 40 40 this.result = result; 41 41 return fulfil( (future_t&)this ); … … 96 96 bool fulfil( multi_future(T) & this, T result ) { 97 97 this.result = result; 98 return fulfil( (future_t&)this ) ;98 return fulfil( (future_t&)this ) != 0p; 99 99 } 100 100 -
libcfa/src/concurrency/invoke.c
rfeacef9 r5407cdc 34 34 35 35 extern void disable_interrupts() OPTIONAL_THREAD; 36 extern void enable_interrupts( _ _cfaabi_dbg_ctx_param);36 extern void enable_interrupts( _Bool poll ); 37 37 38 38 void __cfactx_invoke_coroutine( … … 82 82 ) { 83 83 // Officially start the thread by enabling preemption 84 enable_interrupts( __cfaabi_dbg_ctx);84 enable_interrupts( true ); 85 85 86 86 // Call the main of the thread -
libcfa/src/concurrency/invoke.h
rfeacef9 r5407cdc 148 148 struct $thread * prev; 149 149 volatile unsigned long long ts; 150 intpreferred;150 unsigned preferred; 151 151 }; 152 152 … … 200 200 } node; 201 201 202 struct processor * last_proc; 203 202 204 #if defined( __CFA_WITH_VERIFY__ ) 203 205 void * canary; … … 224 226 } 225 227 228 static inline $thread * volatile & ?`next ( $thread * this ) __attribute__((const)) { 229 return this->seqable.next; 230 } 231 226 232 static inline $thread *& Back( $thread * this ) __attribute__((const)) { 227 233 return this->seqable.back; -
libcfa/src/concurrency/io.cfa
rfeacef9 r5407cdc 32 32 extern "C" { 33 33 #include <sys/syscall.h> 34 #include <sys/eventfd.h> 34 35 35 36 #include <linux/io_uring.h> … … 39 40 #include "kernel.hfa" 40 41 #include "kernel/fwd.hfa" 42 #include "kernel_private.hfa" 41 43 #include "io/types.hfa" 42 44 … … 79 81 }; 80 82 81 // returns true of acquired as leader or second leader 82 static inline bool try_lock( __leaderlock_t & this ) { 83 const uintptr_t thrd = 1z | (uintptr_t)active_thread(); 84 bool block; 85 disable_interrupts(); 86 for() { 87 struct $thread * expected = this.value; 88 if( 1p != expected && 0p != expected ) { 89 /* paranoid */ verify( thrd != (uintptr_t)expected ); // We better not already be the next leader 90 enable_interrupts( __cfaabi_dbg_ctx ); 91 return false; 92 } 93 struct $thread * desired; 94 if( 0p == expected ) { 95 // If the lock isn't locked acquire it, no need to block 96 desired = 1p; 97 block = false; 98 } 99 else { 100 // If the lock is already locked try becomming the next leader 101 desired = (struct $thread *)thrd; 102 block = true; 103 } 104 if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break; 105 } 106 if( block ) { 107 enable_interrupts( __cfaabi_dbg_ctx ); 108 park(); 109 disable_interrupts(); 110 } 111 return true; 112 } 113 114 static inline bool next( __leaderlock_t & this ) { 83 static $io_context * __ioarbiter_allocate( $io_arbiter & this, __u32 idxs[], __u32 want ); 84 static void __ioarbiter_submit( $io_context * , __u32 idxs[], __u32 have, bool lazy ); 85 static void __ioarbiter_flush ( $io_context & ); 86 static inline void __ioarbiter_notify( $io_context & ctx ); 87 //============================================================================================= 88 // I/O Polling 89 //============================================================================================= 90 static inline unsigned __flush( struct $io_context & ); 91 static inline __u32 __release_sqes( struct $io_context & ); 92 extern void __kernel_unpark( $thread * thrd ); 93 94 bool __cfa_io_drain( processor * proc ) { 115 95 /* paranoid */ verify( ! __preemption_enabled() ); 116 struct $thread * nextt; 117 for() { 118 struct $thread * expected = this.value; 119 /* paranoid */ verify( (1 & (uintptr_t)expected) == 1 ); // The lock better be locked 120 121 struct $thread * desired; 122 if( 1p == expected ) { 123 // No next leader, just unlock 124 desired = 0p; 125 nextt = 0p; 126 } 127 else { 128 // There is a next leader, remove but keep locked 129 desired = 1p; 130 nextt = (struct $thread *)(~1z & (uintptr_t)expected); 131 } 132 if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break; 133 } 134 135 if(nextt) { 136 unpark( nextt ); 137 enable_interrupts( __cfaabi_dbg_ctx ); 138 return true; 139 } 140 enable_interrupts( __cfaabi_dbg_ctx ); 141 return false; 142 } 143 144 //============================================================================================= 145 // I/O Syscall 146 //============================================================================================= 147 static int __io_uring_enter( struct __io_data & ring, unsigned to_submit, bool get ) { 148 bool need_sys_to_submit = false; 149 bool need_sys_to_complete = false; 150 unsigned flags = 0; 151 152 TO_SUBMIT: 153 if( to_submit > 0 ) { 154 if( !(ring.ring_flags & IORING_SETUP_SQPOLL) ) { 155 need_sys_to_submit = true; 156 break TO_SUBMIT; 157 } 158 if( (*ring.submit_q.flags) & IORING_SQ_NEED_WAKEUP ) { 159 need_sys_to_submit = true; 160 flags |= IORING_ENTER_SQ_WAKEUP; 161 } 162 } 163 164 if( get && !(ring.ring_flags & IORING_SETUP_SQPOLL) ) { 165 flags |= IORING_ENTER_GETEVENTS; 166 if( (ring.ring_flags & IORING_SETUP_IOPOLL) ) { 167 need_sys_to_complete = true; 168 } 169 } 170 171 int ret = 0; 172 if( need_sys_to_submit || need_sys_to_complete ) { 173 __cfadbg_print_safe(io_core, "Kernel I/O : IO_URING enter %d %u %u\n", ring.fd, to_submit, flags); 174 ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, 0, flags, (sigset_t *)0p, _NSIG / 8); 175 __cfadbg_print_safe(io_core, "Kernel I/O : IO_URING %d returned %d\n", ring.fd, ret); 176 177 if( ret < 0 ) { 178 switch((int)errno) { 179 case EAGAIN: 180 case EINTR: 181 case EBUSY: 182 ret = -1; 183 break; 184 default: 185 abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) ); 186 } 187 } 188 } 189 190 // Memory barrier 191 __atomic_thread_fence( __ATOMIC_SEQ_CST ); 192 return ret; 193 } 194 195 //============================================================================================= 196 // I/O Polling 197 //============================================================================================= 198 static unsigned __collect_submitions( struct __io_data & ring ); 199 static __u32 __release_consumed_submission( struct __io_data & ring ); 200 static inline void __clean( volatile struct io_uring_sqe * sqe ); 201 202 // Process a single completion message from the io_uring 203 // This is NOT thread-safe 204 static inline void process( volatile struct io_uring_cqe & cqe ) { 205 struct io_future_t * future = (struct io_future_t *)(uintptr_t)cqe.user_data; 206 __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future ); 207 208 fulfil( *future, cqe.res ); 209 } 210 211 static [int, bool] __drain_io( & struct __io_data ring ) { 212 /* paranoid */ verify( ! __preemption_enabled() ); 213 214 unsigned to_submit = 0; 215 if( ring.poller_submits ) { 216 // If the poller thread also submits, then we need to aggregate the submissions which are ready 217 to_submit = __collect_submitions( ring ); 218 } 219 220 int ret = __io_uring_enter(ring, to_submit, true); 221 if( ret < 0 ) { 222 return [0, true]; 223 } 224 225 // update statistics 226 if (to_submit > 0) { 227 __STATS__( true, 228 if( to_submit > 0 ) { 229 io.submit_q.submit_avg.rdy += to_submit; 230 io.submit_q.submit_avg.csm += ret; 231 io.submit_q.submit_avg.cnt += 1; 232 } 233 ) 234 } 235 236 __atomic_thread_fence( __ATOMIC_SEQ_CST ); 237 238 // Release the consumed SQEs 239 __release_consumed_submission( ring ); 96 /* paranoid */ verify( ready_schedule_islocked() ); 97 /* paranoid */ verify( proc ); 98 /* paranoid */ verify( proc->io.ctx ); 240 99 241 100 // Drain the queue 242 unsigned head = *ring.completion_q.head; 243 unsigned tail = *ring.completion_q.tail; 244 const __u32 mask = *ring.completion_q.mask; 245 246 // Nothing was new return 0 247 if (head == tail) { 248 return [0, to_submit > 0]; 249 } 101 $io_context * ctx = proc->io.ctx; 102 unsigned head = *ctx->cq.head; 103 unsigned tail = *ctx->cq.tail; 104 const __u32 mask = *ctx->cq.mask; 250 105 251 106 __u32 count = tail - head; 252 /* paranoid */ verify( count != 0 ); 107 __STATS__( false, io.calls.drain++; io.calls.completed += count; ) 108 109 if(count == 0) return false; 110 253 111 for(i; count) { 254 112 unsigned idx = (head + i) & mask; 255 volatile struct io_uring_cqe & cqe = ring.completion_q.cqes[idx];113 volatile struct io_uring_cqe & cqe = ctx->cq.cqes[idx]; 256 114 257 115 /* paranoid */ verify(&cqe); 258 116 259 process( cqe ); 260 } 117 struct io_future_t * future = (struct io_future_t *)(uintptr_t)cqe.user_data; 118 __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future ); 119 120 __kernel_unpark( fulfil( *future, cqe.res, false ) ); 121 } 122 123 __cfadbg_print_safe(io, "Kernel I/O : %u completed\n", count); 261 124 262 125 // Mark to the kernel that the cqe has been seen 263 126 // Ensure that the kernel only sees the new value of the head index after the CQEs have been read. 264 __atomic_fetch_add( ring.completion_q.head, count, __ATOMIC_SEQ_CST ); 265 266 return [count, count > 0 || to_submit > 0]; 267 } 268 269 void main( $io_ctx_thread & this ) { 270 __ioctx_register( this ); 271 272 __cfadbg_print_safe(io_core, "Kernel I/O : IO poller %d (%p) ready\n", this.ring->fd, &this); 273 274 const int reset_cnt = 5; 275 int reset = reset_cnt; 276 // Then loop until we need to start 277 LOOP: 278 while(!__atomic_load_n(&this.done, __ATOMIC_SEQ_CST)) { 279 // Drain the io 280 int count; 281 bool again; 282 disable_interrupts(); 283 [count, again] = __drain_io( *this.ring ); 284 285 if(!again) reset--; 286 127 __atomic_store_n( ctx->cq.head, head + count, __ATOMIC_SEQ_CST ); 128 129 /* paranoid */ verify( ready_schedule_islocked() ); 130 /* paranoid */ verify( ! __preemption_enabled() ); 131 132 return true; 133 } 134 135 void __cfa_io_flush( processor * proc ) { 136 /* paranoid */ verify( ! __preemption_enabled() ); 137 /* paranoid */ verify( proc ); 138 /* paranoid */ verify( proc->io.ctx ); 139 140 $io_context & ctx = *proc->io.ctx; 141 142 __ioarbiter_flush( ctx ); 143 144 __STATS__( true, io.calls.flush++; ) 145 int ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, 0, 0, (sigset_t *)0p, _NSIG / 8); 146 if( ret < 0 ) { 147 switch((int)errno) { 148 case EAGAIN: 149 case EINTR: 150 case EBUSY: 287 151 // Update statistics 288 __STATS__( true, 289 io.complete_q.completed_avg.val += count; 290 io.complete_q.completed_avg.cnt += 1; 291 ) 292 enable_interrupts( __cfaabi_dbg_ctx ); 293 294 // If we got something, just yield and check again 295 if(reset > 1) { 296 yield(); 297 continue LOOP; 152 __STATS__( false, io.calls.errors.busy ++; ) 153 return; 154 default: 155 abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) ); 298 156 } 299 300 // We alread failed to find completed entries a few time. 301 if(reset == 1) { 302 // Rearm the context so it can block 303 // but don't block right away 304 // we need to retry one last time in case 305 // something completed *just now* 306 __ioctx_prepare_block( this ); 307 continue LOOP; 308 } 309 310 __STATS__( false, 311 io.complete_q.blocks += 1; 312 ) 313 __cfadbg_print_safe(io_core, "Kernel I/O : Parking io poller %d (%p)\n", this.ring->fd, &this); 314 315 // block this thread 316 wait( this.sem ); 317 318 // restore counter 319 reset = reset_cnt; 320 } 321 322 __cfadbg_print_safe(io_core, "Kernel I/O : Fast poller %d (%p) stopping\n", this.ring->fd, &this); 323 324 __ioctx_unregister( this ); 157 } 158 159 __cfadbg_print_safe(io, "Kernel I/O : %u submitted to io_uring %d\n", ret, ctx.fd); 160 __STATS__( true, io.calls.submitted += ret; ) 161 /* paranoid */ verify( ctx.sq.to_submit <= *ctx.sq.num ); 162 /* paranoid */ verify( ctx.sq.to_submit >= ret ); 163 164 ctx.sq.to_submit -= ret; 165 166 /* paranoid */ verify( ctx.sq.to_submit <= *ctx.sq.num ); 167 168 // Release the consumed SQEs 169 __release_sqes( ctx ); 170 171 /* paranoid */ verify( ! __preemption_enabled() ); 172 173 ctx.proc->io.pending = false; 325 174 } 326 175 … … 344 193 // head and tail must be fully filled and shouldn't ever be touched again. 345 194 // 195 //============================================================================================= 196 // Allocation 197 // for user's convenience fill the sqes from the indexes 198 static inline void __fill(struct io_uring_sqe * out_sqes[], __u32 want, __u32 idxs[], struct $io_context * ctx) { 199 struct io_uring_sqe * sqes = ctx->sq.sqes; 200 for(i; want) { 201 __cfadbg_print_safe(io, "Kernel I/O : filling loop\n"); 202 out_sqes[i] = &sqes[idxs[i]]; 203 } 204 } 205 206 // Try to directly allocate from the a given context 207 // Not thread-safe 208 static inline bool __alloc(struct $io_context * ctx, __u32 idxs[], __u32 want) { 209 __sub_ring_t & sq = ctx->sq; 210 const __u32 mask = *sq.mask; 211 __u32 fhead = sq.free_ring.head; // get the current head of the queue 212 __u32 ftail = sq.free_ring.tail; // get the current tail of the queue 213 214 // If we don't have enough sqes, fail 215 if((ftail - fhead) < want) { return false; } 216 217 // copy all the indexes we want from the available list 218 for(i; want) { 219 __cfadbg_print_safe(io, "Kernel I/O : allocating loop\n"); 220 idxs[i] = sq.free_ring.array[(fhead + i) & mask]; 221 } 222 223 // Advance the head to mark the indexes as consumed 224 __atomic_store_n(&sq.free_ring.head, fhead + want, __ATOMIC_RELEASE); 225 226 // return success 227 return true; 228 } 346 229 347 230 // Allocate an submit queue entry. … … 350 233 // for convenience, return both the index and the pointer to the sqe 351 234 // sqe == &sqes[idx] 352 [* volatile struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ) { 353 /* paranoid */ verify( data != 0 ); 354 355 // Prepare the data we need 356 __attribute((unused)) int len = 0; 357 __attribute((unused)) int block = 0; 358 __u32 cnt = *ring.submit_q.num; 359 __u32 mask = *ring.submit_q.mask; 360 361 __u32 off = thread_rand(); 362 363 // Loop around looking for an available spot 364 for() { 365 // Look through the list starting at some offset 366 for(i; cnt) { 367 __u64 expected = 3; 368 __u32 idx = (i + off) & mask; // Get an index from a random 369 volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx]; 370 volatile __u64 * udata = &sqe->user_data; 371 372 // Allocate the entry by CASing the user_data field from 0 to the future address 373 if( *udata == expected && 374 __atomic_compare_exchange_n( udata, &expected, data, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) 375 { 376 // update statistics 377 __STATS__( false, 378 io.submit_q.alloc_avg.val += len; 379 io.submit_q.alloc_avg.block += block; 380 io.submit_q.alloc_avg.cnt += 1; 381 ) 382 383 // debug log 384 __cfadbg_print_safe( io, "Kernel I/O : allocated [%p, %u] for %p (%p)\n", sqe, idx, active_thread(), (void*)data ); 385 386 // Success return the data 387 return [sqe, idx]; 388 } 389 verify(expected != data); 390 391 // This one was used 392 len ++; 393 } 394 395 block++; 396 397 yield(); 398 } 399 } 400 401 static inline __u32 __submit_to_ready_array( struct __io_data & ring, __u32 idx, const __u32 mask ) { 402 /* paranoid */ verify( idx <= mask ); 403 /* paranoid */ verify( idx != -1ul32 ); 404 405 // We need to find a spot in the ready array 406 __attribute((unused)) int len = 0; 407 __attribute((unused)) int block = 0; 408 __u32 ready_mask = ring.submit_q.ready_cnt - 1; 409 410 __u32 off = thread_rand(); 411 412 __u32 picked; 413 LOOKING: for() { 414 for(i; ring.submit_q.ready_cnt) { 415 picked = (i + off) & ready_mask; 416 __u32 expected = -1ul32; 417 if( __atomic_compare_exchange_n( &ring.submit_q.ready[picked], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) { 418 break LOOKING; 419 } 420 verify(expected != idx); 421 422 len ++; 423 } 424 425 block++; 426 427 __u32 released = __release_consumed_submission( ring ); 428 if( released == 0 ) { 429 yield(); 430 } 431 } 432 433 // update statistics 434 __STATS__( false, 435 io.submit_q.look_avg.val += len; 436 io.submit_q.look_avg.block += block; 437 io.submit_q.look_avg.cnt += 1; 438 ) 439 440 return picked; 441 } 442 443 void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1))) { 444 __io_data & ring = *ctx->thrd.ring; 445 235 struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) { 236 __cfadbg_print_safe(io, "Kernel I/O : attempting to allocate %u\n", want); 237 238 disable_interrupts(); 239 processor * proc = __cfaabi_tls.this_processor; 240 $io_context * ctx = proc->io.ctx; 241 /* paranoid */ verify( __cfaabi_tls.this_processor ); 242 /* paranoid */ verify( ctx ); 243 244 __cfadbg_print_safe(io, "Kernel I/O : attempting to fast allocation\n"); 245 246 // We can proceed to the fast path 247 if( __alloc(ctx, idxs, want) ) { 248 // Allocation was successful 249 __STATS__( true, io.alloc.fast += 1; ) 250 enable_interrupts(); 251 252 __cfadbg_print_safe(io, "Kernel I/O : fast allocation successful from ring %d\n", ctx->fd); 253 254 __fill( sqes, want, idxs, ctx ); 255 return ctx; 256 } 257 // The fast path failed, fallback 258 __STATS__( true, io.alloc.fail += 1; ) 259 260 // Fast path failed, fallback on arbitration 261 __STATS__( true, io.alloc.slow += 1; ) 262 enable_interrupts(); 263 264 $io_arbiter * ioarb = proc->cltr->io.arbiter; 265 /* paranoid */ verify( ioarb ); 266 267 __cfadbg_print_safe(io, "Kernel I/O : falling back on arbiter for allocation\n"); 268 269 struct $io_context * ret = __ioarbiter_allocate(*ioarb, idxs, want); 270 271 __cfadbg_print_safe(io, "Kernel I/O : slow allocation completed from ring %d\n", ret->fd); 272 273 __fill( sqes, want, idxs,ret ); 274 return ret; 275 } 276 277 278 //============================================================================================= 279 // submission 280 static inline void __submit( struct $io_context * ctx, __u32 idxs[], __u32 have, bool lazy) { 281 // We can proceed to the fast path 282 // Get the right objects 283 __sub_ring_t & sq = ctx->sq; 284 const __u32 mask = *sq.mask; 285 __u32 tail = *sq.kring.tail; 286 287 // Add the sqes to the array 288 for( i; have ) { 289 __cfadbg_print_safe(io, "Kernel I/O : __submit loop\n"); 290 sq.kring.array[ (tail + i) & mask ] = idxs[i]; 291 } 292 293 // Make the sqes visible to the submitter 294 __atomic_store_n(sq.kring.tail, tail + have, __ATOMIC_RELEASE); 295 sq.to_submit++; 296 297 ctx->proc->io.pending = true; 298 ctx->proc->io.dirty = true; 299 if(sq.to_submit > 30 || !lazy) { 300 __cfa_io_flush( ctx->proc ); 301 } 302 } 303 304 void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) { 305 __cfadbg_print_safe(io, "Kernel I/O : attempting to submit %u (%s)\n", have, lazy ? "lazy" : "eager"); 306 307 disable_interrupts(); 308 processor * proc = __cfaabi_tls.this_processor; 309 $io_context * ctx = proc->io.ctx; 310 /* paranoid */ verify( __cfaabi_tls.this_processor ); 311 /* paranoid */ verify( ctx ); 312 313 // Can we proceed to the fast path 314 if( ctx == inctx ) // We have the right instance? 446 315 { 447 __attribute__((unused)) volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx]; 448 __cfadbg_print_safe( io, 449 "Kernel I/O : submitting %u (%p) for %p\n" 450 " data: %p\n" 451 " opcode: %s\n" 452 " fd: %d\n" 453 " flags: %d\n" 454 " prio: %d\n" 455 " off: %p\n" 456 " addr: %p\n" 457 " len: %d\n" 458 " other flags: %d\n" 459 " splice fd: %d\n" 460 " pad[0]: %llu\n" 461 " pad[1]: %llu\n" 462 " pad[2]: %llu\n", 463 idx, sqe, 464 active_thread(), 465 (void*)sqe->user_data, 466 opcodes[sqe->opcode], 467 sqe->fd, 468 sqe->flags, 469 sqe->ioprio, 470 (void*)sqe->off, 471 (void*)sqe->addr, 472 sqe->len, 473 sqe->accept_flags, 474 sqe->splice_fd_in, 475 sqe->__pad2[0], 476 sqe->__pad2[1], 477 sqe->__pad2[2] 478 ); 479 } 480 481 482 // Get now the data we definetely need 483 volatile __u32 * const tail = ring.submit_q.tail; 484 const __u32 mask = *ring.submit_q.mask; 485 486 // There are 2 submission schemes, check which one we are using 487 if( ring.poller_submits ) { 488 // If the poller thread submits, then we just need to add this to the ready array 489 __submit_to_ready_array( ring, idx, mask ); 490 491 post( ctx->thrd.sem ); 492 493 __cfadbg_print_safe( io, "Kernel I/O : Added %u to ready for %p\n", idx, active_thread() ); 494 } 495 else if( ring.eager_submits ) { 496 __attribute__((unused)) __u32 picked = __submit_to_ready_array( ring, idx, mask ); 497 498 #if defined(LEADER_LOCK) 499 if( !try_lock(ring.submit_q.submit_lock) ) { 500 __STATS__( false, 501 io.submit_q.helped += 1; 502 ) 503 return; 504 } 505 /* paranoid */ verify( ! __preemption_enabled() ); 506 __STATS__( true, 507 io.submit_q.leader += 1; 508 ) 509 #else 510 for() { 511 yield(); 512 513 if( try_lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2) ) { 514 __STATS__( false, 515 io.submit_q.leader += 1; 516 ) 517 break; 518 } 519 520 // If some one else collected our index, we are done 521 #warning ABA problem 522 if( ring.submit_q.ready[picked] != idx ) { 523 __STATS__( false, 524 io.submit_q.helped += 1; 525 ) 526 return; 527 } 528 529 __STATS__( false, 530 io.submit_q.busy += 1; 531 ) 532 } 533 #endif 534 535 // We got the lock 536 // Collect the submissions 537 unsigned to_submit = __collect_submitions( ring ); 538 539 // Actually submit 540 int ret = __io_uring_enter( ring, to_submit, false ); 541 542 #if defined(LEADER_LOCK) 543 /* paranoid */ verify( ! __preemption_enabled() ); 544 next(ring.submit_q.submit_lock); 545 #else 546 unlock(ring.submit_q.submit_lock); 547 #endif 548 if( ret < 0 ) { 549 return; 550 } 551 552 // Release the consumed SQEs 553 __release_consumed_submission( ring ); 554 555 // update statistics 556 __STATS__( false, 557 io.submit_q.submit_avg.rdy += to_submit; 558 io.submit_q.submit_avg.csm += ret; 559 io.submit_q.submit_avg.cnt += 1; 560 ) 561 562 __cfadbg_print_safe( io, "Kernel I/O : submitted %u (among %u) for %p\n", idx, ret, active_thread() ); 563 } 564 else 565 { 566 // get mutual exclusion 567 #if defined(LEADER_LOCK) 568 while(!try_lock(ring.submit_q.submit_lock)); 569 #else 570 lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2); 571 #endif 572 573 /* paranoid */ verifyf( ring.submit_q.sqes[ idx ].user_data != 3ul64, 574 /* paranoid */ "index %u already reclaimed\n" 575 /* paranoid */ "head %u, prev %u, tail %u\n" 576 /* paranoid */ "[-0: %u,-1: %u,-2: %u,-3: %u]\n", 577 /* paranoid */ idx, 578 /* paranoid */ *ring.submit_q.head, ring.submit_q.prev_head, *tail 579 /* paranoid */ ,ring.submit_q.array[ ((*ring.submit_q.head) - 0) & (*ring.submit_q.mask) ] 580 /* paranoid */ ,ring.submit_q.array[ ((*ring.submit_q.head) - 1) & (*ring.submit_q.mask) ] 581 /* paranoid */ ,ring.submit_q.array[ ((*ring.submit_q.head) - 2) & (*ring.submit_q.mask) ] 582 /* paranoid */ ,ring.submit_q.array[ ((*ring.submit_q.head) - 3) & (*ring.submit_q.mask) ] 583 /* paranoid */ ); 584 585 // Append to the list of ready entries 586 587 /* paranoid */ verify( idx <= mask ); 588 ring.submit_q.array[ (*tail) & mask ] = idx; 589 __atomic_fetch_add(tail, 1ul32, __ATOMIC_SEQ_CST); 590 591 // Submit however, many entries need to be submitted 592 int ret = __io_uring_enter( ring, 1, false ); 593 if( ret < 0 ) { 594 switch((int)errno) { 595 default: 596 abort( "KERNEL ERROR: IO_URING SUBMIT - %s\n", strerror(errno) ); 597 } 598 } 599 600 /* paranoid */ verify(ret == 1); 601 602 // update statistics 603 __STATS__( false, 604 io.submit_q.submit_avg.csm += 1; 605 io.submit_q.submit_avg.cnt += 1; 606 ) 607 608 { 609 __attribute__((unused)) volatile __u32 * const head = ring.submit_q.head; 610 __attribute__((unused)) __u32 last_idx = ring.submit_q.array[ ((*head) - 1) & mask ]; 611 __attribute__((unused)) volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[last_idx]; 612 613 __cfadbg_print_safe( io, 614 "Kernel I/O : last submitted is %u (%p)\n" 615 " data: %p\n" 616 " opcode: %s\n" 617 " fd: %d\n" 618 " flags: %d\n" 619 " prio: %d\n" 620 " off: %p\n" 621 " addr: %p\n" 622 " len: %d\n" 623 " other flags: %d\n" 624 " splice fd: %d\n" 625 " pad[0]: %llu\n" 626 " pad[1]: %llu\n" 627 " pad[2]: %llu\n", 628 last_idx, sqe, 629 (void*)sqe->user_data, 630 opcodes[sqe->opcode], 631 sqe->fd, 632 sqe->flags, 633 sqe->ioprio, 634 (void*)sqe->off, 635 (void*)sqe->addr, 636 sqe->len, 637 sqe->accept_flags, 638 sqe->splice_fd_in, 639 sqe->__pad2[0], 640 sqe->__pad2[1], 641 sqe->__pad2[2] 642 ); 643 } 644 645 __atomic_thread_fence( __ATOMIC_SEQ_CST ); 646 // Release the consumed SQEs 647 648 __release_consumed_submission( ring ); 649 // ring.submit_q.sqes[idx].user_data = 3ul64; 650 651 #if defined(LEADER_LOCK) 652 next(ring.submit_q.submit_lock); 653 #else 654 unlock(ring.submit_q.submit_lock); 655 #endif 656 657 __cfadbg_print_safe( io, "Kernel I/O : submitted %u for %p\n", idx, active_thread() ); 658 } 659 } 660 661 // #define PARTIAL_SUBMIT 32 662 663 // go through the list of submissions in the ready array and moved them into 664 // the ring's submit queue 665 static unsigned __collect_submitions( struct __io_data & ring ) { 666 /* paranoid */ verify( ring.submit_q.ready != 0p ); 667 /* paranoid */ verify( ring.submit_q.ready_cnt > 0 ); 668 669 unsigned to_submit = 0; 670 __u32 tail = *ring.submit_q.tail; 671 const __u32 mask = *ring.submit_q.mask; 672 #if defined(PARTIAL_SUBMIT) 673 #if defined(LEADER_LOCK) 674 #error PARTIAL_SUBMIT and LEADER_LOCK cannot co-exist 675 #endif 676 const __u32 cnt = ring.submit_q.ready_cnt > PARTIAL_SUBMIT ? PARTIAL_SUBMIT : ring.submit_q.ready_cnt; 677 const __u32 offset = ring.submit_q.prev_ready; 678 ring.submit_q.prev_ready += cnt; 679 #else 680 const __u32 cnt = ring.submit_q.ready_cnt; 681 const __u32 offset = 0; 682 #endif 683 684 // Go through the list of ready submissions 685 for( c; cnt ) { 686 __u32 i = (offset + c) % ring.submit_q.ready_cnt; 687 688 // replace any submission with the sentinel, to consume it. 689 __u32 idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED); 690 691 // If it was already the sentinel, then we are done 692 if( idx == -1ul32 ) continue; 693 694 // If we got a real submission, append it to the list 695 ring.submit_q.array[ (tail + to_submit) & mask ] = idx & mask; 696 to_submit++; 697 } 698 699 // Increment the tail based on how many we are ready to submit 700 __atomic_fetch_add(ring.submit_q.tail, to_submit, __ATOMIC_SEQ_CST); 701 702 return to_submit; 703 } 704 316 __submit(ctx, idxs, have, lazy); 317 318 // Mark the instance as no longer in-use, re-enable interrupts and return 319 __STATS__( true, io.submit.fast += 1; ) 320 enable_interrupts(); 321 322 __cfadbg_print_safe(io, "Kernel I/O : submitted on fast path\n"); 323 return; 324 } 325 326 // Fast path failed, fallback on arbitration 327 __STATS__( true, io.submit.slow += 1; ) 328 enable_interrupts(); 329 330 __cfadbg_print_safe(io, "Kernel I/O : falling back on arbiter for submission\n"); 331 332 __ioarbiter_submit(inctx, idxs, have, lazy); 333 } 334 335 //============================================================================================= 336 // Flushing 705 337 // Go through the ring's submit queue and release everything that has already been consumed 706 338 // by io_uring 707 static __u32 __release_consumed_submission( struct __io_data & ring ) { 708 const __u32 smask = *ring.submit_q.mask; 709 710 // We need to get the lock to copy the old head and new head 711 if( !try_lock(ring.submit_q.release_lock __cfaabi_dbg_ctx2) ) return 0; 339 // This cannot be done by multiple threads 340 static __u32 __release_sqes( struct $io_context & ctx ) { 341 const __u32 mask = *ctx.sq.mask; 342 712 343 __attribute__((unused)) 713 __u32 ctail = * ring.submit_q.tail;// get the current tail of the queue714 __u32 chead = * ring.submit_q.head;// get the current head of the queue715 __u32 phead = ring.submit_q.prev_head;// get the head the last time we were here716 ring.submit_q.prev_head = chead; // note up to were we processed 717 unlock(ring.submit_q.release_lock);344 __u32 ctail = *ctx.sq.kring.tail; // get the current tail of the queue 345 __u32 chead = *ctx.sq.kring.head; // get the current head of the queue 346 __u32 phead = ctx.sq.kring.released; // get the head the last time we were here 347 348 __u32 ftail = ctx.sq.free_ring.tail; // get the current tail of the queue 718 349 719 350 // the 3 fields are organized like this diagram … … 734 365 __u32 count = chead - phead; 735 366 367 if(count == 0) { 368 return 0; 369 } 370 736 371 // We acquired an previous-head/current-head range 737 372 // go through the range and release the sqes 738 373 for( i; count ) { 739 __u32 idx = ring.submit_q.array[ (phead + i) & smask ]; 740 741 /* paranoid */ verify( 0 != ring.submit_q.sqes[ idx ].user_data ); 742 __clean( &ring.submit_q.sqes[ idx ] ); 743 } 374 __cfadbg_print_safe(io, "Kernel I/O : release loop\n"); 375 __u32 idx = ctx.sq.kring.array[ (phead + i) & mask ]; 376 ctx.sq.free_ring.array[ (ftail + i) & mask ] = idx; 377 } 378 379 ctx.sq.kring.released = chead; // note up to were we processed 380 __atomic_store_n(&ctx.sq.free_ring.tail, ftail + count, __ATOMIC_SEQ_CST); 381 382 __ioarbiter_notify(ctx); 383 744 384 return count; 745 385 } 746 386 747 void __sqe_clean( volatile struct io_uring_sqe * sqe ) { 748 __clean( sqe ); 749 } 750 751 static inline void __clean( volatile struct io_uring_sqe * sqe ) { 752 // If we are in debug mode, thrash the fields to make sure we catch reclamation errors 753 __cfaabi_dbg_debug_do( 754 memset(sqe, 0xde, sizeof(*sqe)); 755 sqe->opcode = (sizeof(opcodes) / sizeof(const char *)) - 1; 756 ); 757 758 // Mark the entry as unused 759 __atomic_store_n(&sqe->user_data, 3ul64, __ATOMIC_SEQ_CST); 387 //============================================================================================= 388 // I/O Arbiter 389 //============================================================================================= 390 static inline void block(__outstanding_io_queue & queue, __outstanding_io & item) { 391 // Lock the list, it's not thread safe 392 lock( queue.lock __cfaabi_dbg_ctx2 ); 393 { 394 // Add our request to the list 395 add( queue.queue, item ); 396 397 // Mark as pending 398 __atomic_store_n( &queue.empty, false, __ATOMIC_SEQ_CST ); 399 } 400 unlock( queue.lock ); 401 402 wait( item.sem ); 403 } 404 405 static inline bool empty(__outstanding_io_queue & queue ) { 406 return __atomic_load_n( &queue.empty, __ATOMIC_SEQ_CST); 407 } 408 409 static $io_context * __ioarbiter_allocate( $io_arbiter & this, __u32 idxs[], __u32 want ) { 410 __cfadbg_print_safe(io, "Kernel I/O : arbiter allocating\n"); 411 412 __STATS__( false, io.alloc.block += 1; ) 413 414 // No one has any resources left, wait for something to finish 415 // We need to add ourself to a list of pending allocs and wait for an answer 416 __pending_alloc pa; 417 pa.idxs = idxs; 418 pa.want = want; 419 420 block(this.pending, (__outstanding_io&)pa); 421 422 return pa.ctx; 423 424 } 425 426 static void __ioarbiter_notify( $io_arbiter & this, $io_context * ctx ) { 427 /* paranoid */ verify( !empty(this.pending.queue) ); 428 429 lock( this.pending.lock __cfaabi_dbg_ctx2 ); 430 { 431 while( !empty(this.pending.queue) ) { 432 __cfadbg_print_safe(io, "Kernel I/O : notifying\n"); 433 __u32 have = ctx->sq.free_ring.tail - ctx->sq.free_ring.head; 434 __pending_alloc & pa = (__pending_alloc&)head( this.pending.queue ); 435 436 if( have > pa.want ) goto DONE; 437 drop( this.pending.queue ); 438 439 /* paranoid */__attribute__((unused)) bool ret = 440 441 __alloc(ctx, pa.idxs, pa.want); 442 443 /* paranoid */ verify( ret ); 444 445 pa.ctx = ctx; 446 447 post( pa.sem ); 448 } 449 450 this.pending.empty = true; 451 DONE:; 452 } 453 unlock( this.pending.lock ); 454 } 455 456 static void __ioarbiter_notify( $io_context & ctx ) { 457 if(!empty( ctx.arbiter->pending )) { 458 __ioarbiter_notify( *ctx.arbiter, &ctx ); 459 } 460 } 461 462 // Simply append to the pending 463 static void __ioarbiter_submit( $io_context * ctx, __u32 idxs[], __u32 have, bool lazy ) { 464 __cfadbg_print_safe(io, "Kernel I/O : submitting %u from the arbiter to context %u\n", have, ctx->fd); 465 466 __cfadbg_print_safe(io, "Kernel I/O : waiting to submit %u\n", have); 467 468 __external_io ei; 469 ei.idxs = idxs; 470 ei.have = have; 471 ei.lazy = lazy; 472 473 block(ctx->ext_sq, (__outstanding_io&)ei); 474 475 __cfadbg_print_safe(io, "Kernel I/O : %u submitted from arbiter\n", have); 476 } 477 478 static void __ioarbiter_flush( $io_context & ctx ) { 479 if(!empty( ctx.ext_sq )) { 480 __STATS__( false, io.flush.external += 1; ) 481 482 __cfadbg_print_safe(io, "Kernel I/O : arbiter flushing\n"); 483 484 lock( ctx.ext_sq.lock __cfaabi_dbg_ctx2 ); 485 { 486 while( !empty(ctx.ext_sq.queue) ) { 487 __external_io & ei = (__external_io&)drop( ctx.ext_sq.queue ); 488 489 __submit(&ctx, ei.idxs, ei.have, ei.lazy); 490 491 post( ei.sem ); 492 } 493 494 ctx.ext_sq.empty = true; 495 } 496 unlock(ctx.ext_sq.lock ); 497 } 760 498 } 761 499 #endif -
libcfa/src/concurrency/io/call.cfa.in
rfeacef9 r5407cdc 54 54 | IOSQE_IO_DRAIN 55 55 #endif 56 #if defined(CFA_HAVE_IOSQE_IO_LINK) 57 | IOSQE_IO_LINK 58 #endif 59 #if defined(CFA_HAVE_IOSQE_IO_HARDLINK) 60 | IOSQE_IO_HARDLINK 61 #endif 56 62 #if defined(CFA_HAVE_IOSQE_ASYNC) 57 63 | IOSQE_ASYNC 58 64 #endif 59 ; 60 61 static const __u32 LINK_FLAGS = 0 62 #if defined(CFA_HAVE_IOSQE_IO_LINK) 63 | IOSQE_IO_LINK 64 #endif 65 #if defined(CFA_HAVE_IOSQE_IO_HARDLINK) 66 | IOSQE_IO_HARDLINK 65 #if defined(CFA_HAVE_IOSQE_BUFFER_SELECTED) 66 | IOSQE_BUFFER_SELECTED 67 67 #endif 68 68 ; … … 74 74 ; 75 75 76 extern [* volatile struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ); 77 extern void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1))); 78 79 static inline io_context * __get_io_context( void ) { 80 cluster * cltr = active_cluster(); 81 82 /* paranoid */ verifyf( cltr, "No active cluster for io operation\\n"); 83 assertf( cltr->io.cnt > 0, "Cluster %p has no default io contexts and no context was specified\\n", cltr ); 84 85 /* paranoid */ verifyf( cltr->io.ctxs, "default io contexts for cluster %p are missing\\n", cltr); 86 return &cltr->io.ctxs[ thread_rand() % cltr->io.cnt ]; 87 } 76 extern struct $io_context * cfa_io_allocate(struct io_uring_sqe * out_sqes[], __u32 out_idxs[], __u32 want) __attribute__((nonnull (1,2))); 77 extern void cfa_io_submit( struct $io_context * in_ctx, __u32 in_idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1,2))); 88 78 #endif 89 79 … … 98 88 99 89 extern "C" { 100 #include < sys/types.h>90 #include <asm/types.h> 101 91 #include <sys/socket.h> 102 92 #include <sys/syscall.h> … … 142 132 extern int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 143 133 144 extern ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);134 extern ssize_t splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags); 145 135 extern ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags); 146 136 } … … 195 185 return ', '.join(args_a) 196 186 197 AsyncTemplate = """inline void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context) {{187 AsyncTemplate = """inline void async_{name}(io_future_t & future, {params}, __u64 submit_flags) {{ 198 188 #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_{op}) 199 189 ssize_t res = {name}({args}); … … 205 195 }} 206 196 #else 207 // we don't support LINK yet208 if( 0 != (submit_flags & LINK_FLAGS) ) {{209 errno = ENOTSUP; return -1;210 }}211 212 if( !context ) {{213 context = __get_io_context();214 }}215 if(cancellation) {{216 cancellation->target = (__u64)(uintptr_t)&future;217 }}218 219 197 __u8 sflags = REGULAR_FLAGS & submit_flags; 220 struct __io_data & ring = *context->thrd.ring;221 222 198 __u32 idx; 223 199 struct io_uring_sqe * sqe; 224 [(volatile struct io_uring_sqe *) sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&future);200 struct $io_context * ctx = cfa_io_allocate( &sqe, &idx, 1 ); 225 201 226 202 sqe->opcode = IORING_OP_{op}; 203 sqe->user_data = (uintptr_t)&future; 227 204 sqe->flags = sflags; 228 205 sqe->ioprio = 0; … … 238 215 asm volatile("": : :"memory"); 239 216 240 verify( sqe->user_data == ( __u64)(uintptr_t)&future );241 __submit( context, idx);217 verify( sqe->user_data == (uintptr_t)&future ); 218 cfa_io_submit( ctx, &idx, 1, 0 != (submit_flags & CFA_IO_LAZY) ); 242 219 #endif 243 220 }}""" 244 221 245 SyncTemplate = """{ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {{ 246 if( timeout >= 0 ) {{ 247 errno = ENOTSUP; 248 return -1; 249 }} 222 SyncTemplate = """{ret} cfa_{name}({params}, __u64 submit_flags) {{ 250 223 io_future_t future; 251 224 252 async_{name}( future, {args}, submit_flags , cancellation, context);225 async_{name}( future, {args}, submit_flags ); 253 226 254 227 wait( future ); … … 265 238 'fd' : 'fd', 266 239 'off' : 'offset', 267 'addr': '( __u64)iov',240 'addr': '(uintptr_t)iov', 268 241 'len' : 'iovcnt', 269 242 }, define = 'CFA_HAVE_PREADV2'), … … 272 245 'fd' : 'fd', 273 246 'off' : 'offset', 274 'addr': '( __u64)iov',247 'addr': '(uintptr_t)iov', 275 248 'len' : 'iovcnt' 276 249 }, define = 'CFA_HAVE_PWRITEV2'), … … 284 257 'addr': 'fd', 285 258 'len': 'op', 286 'off': '( __u64)event'259 'off': '(uintptr_t)event' 287 260 }), 288 261 # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE … … 296 269 Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)', { 297 270 'fd': 'sockfd', 298 'addr': '( __u64)(struct msghdr *)msg',271 'addr': '(uintptr_t)(struct msghdr *)msg', 299 272 'len': '1', 300 273 'msg_flags': 'flags' … … 303 276 Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)', { 304 277 'fd': 'sockfd', 305 'addr': '( __u64)(struct msghdr *)msg',278 'addr': '(uintptr_t)(struct msghdr *)msg', 306 279 'len': '1', 307 280 'msg_flags': 'flags' … … 310 283 Call('SEND', 'ssize_t send(int sockfd, const void *buf, size_t len, int flags)', { 311 284 'fd': 'sockfd', 312 'addr': '( __u64)buf',285 'addr': '(uintptr_t)buf', 313 286 'len': 'len', 314 287 'msg_flags': 'flags' … … 317 290 Call('RECV', 'ssize_t recv(int sockfd, void *buf, size_t len, int flags)', { 318 291 'fd': 'sockfd', 319 'addr': '( __u64)buf',292 'addr': '(uintptr_t)buf', 320 293 'len': 'len', 321 294 'msg_flags': 'flags' … … 324 297 Call('ACCEPT', 'int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)', { 325 298 'fd': 'sockfd', 326 'addr': '( __u64)addr',327 'addr2': '( __u64)addrlen',299 'addr': '(uintptr_t)addr', 300 'addr2': '(uintptr_t)addrlen', 328 301 'accept_flags': 'flags' 329 302 }), … … 331 304 Call('CONNECT', 'int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)', { 332 305 'fd': 'sockfd', 333 'addr': '( __u64)addr',306 'addr': '(uintptr_t)addr', 334 307 'off': 'addrlen' 335 308 }), … … 337 310 Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', { 338 311 'fd': 'fd', 339 'addr': '( __u64)len',312 'addr': '(uintptr_t)len', 340 313 'len': 'mode', 341 314 'off': 'offset' … … 350 323 # CFA_HAVE_IORING_OP_MADVISE 351 324 Call('MADVISE', 'int madvise(void *addr, size_t length, int advice)', { 352 'addr': '( __u64)addr',325 'addr': '(uintptr_t)addr', 353 326 'len': 'length', 354 327 'fadvise_advice': 'advice' … … 357 330 Call('OPENAT', 'int openat(int dirfd, const char *pathname, int flags, mode_t mode)', { 358 331 'fd': 'dirfd', 359 'addr': '( __u64)pathname',332 'addr': '(uintptr_t)pathname', 360 333 'len': 'mode', 361 334 'open_flags': 'flags;' … … 366 339 'addr': 'pathname', 367 340 'len': 'sizeof(*how)', 368 'off': '( __u64)how',341 'off': '(uintptr_t)how', 369 342 }, define = 'CFA_HAVE_OPENAT2'), 370 343 # CFA_HAVE_IORING_OP_CLOSE … … 375 348 Call('STATX', 'int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf)', { 376 349 'fd': 'dirfd', 377 'off': '( __u64)statxbuf',350 'off': '(uintptr_t)statxbuf', 378 351 'addr': 'pathname', 379 352 'len': 'mask', … … 383 356 Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', { 384 357 'fd': 'fd', 385 'addr': '( __u64)buf',358 'addr': '(uintptr_t)buf', 386 359 'len': 'count' 387 360 }), … … 389 362 Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', { 390 363 'fd': 'fd', 391 'addr': '( __u64)buf',364 'addr': '(uintptr_t)buf', 392 365 'len': 'count' 393 366 }), 394 367 # CFA_HAVE_IORING_OP_SPLICE 395 Call('SPLICE', 'ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags)', {368 Call('SPLICE', 'ssize_t splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags)', { 396 369 'splice_fd_in': 'fd_in', 397 370 'splice_off_in': 'off_in ? (__u64)*off_in : (__u64)-1', … … 415 388 if c.define: 416 389 print("""#if defined({define}) 417 {ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);390 {ret} cfa_{name}({params}, __u64 submit_flags); 418 391 #endif""".format(define=c.define,ret=c.ret, name=c.name, params=c.params)) 419 392 else: 420 print("{ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);"393 print("{ret} cfa_{name}({params}, __u64 submit_flags);" 421 394 .format(ret=c.ret, name=c.name, params=c.params)) 422 395 … … 426 399 if c.define: 427 400 print("""#if defined({define}) 428 void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context);401 void async_{name}(io_future_t & future, {params}, __u64 submit_flags); 429 402 #endif""".format(define=c.define,name=c.name, params=c.params)) 430 403 else: 431 print("void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context);"404 print("void async_{name}(io_future_t & future, {params}, __u64 submit_flags);" 432 405 .format(name=c.name, params=c.params)) 433 406 print("\n") … … 474 447 475 448 print(""" 476 //-----------------------------------------------------------------------------477 bool cancel(io_cancellation & this) {478 #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_ASYNC_CANCEL)479 return false;480 #else481 io_future_t future;482 483 io_context * context = __get_io_context();484 485 __u8 sflags = 0;486 struct __io_data & ring = *context->thrd.ring;487 488 __u32 idx;489 volatile struct io_uring_sqe * sqe;490 [sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&future );491 492 sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;493 sqe->opcode = IORING_OP_ASYNC_CANCEL;494 sqe->flags = sflags;495 sqe->addr = this.target;496 497 verify( sqe->user_data == (__u64)(uintptr_t)&future );498 __submit( context, idx );499 500 wait(future);501 502 if( future.result == 0 ) return true; // Entry found503 if( future.result == -EALREADY) return true; // Entry found but in progress504 if( future.result == -ENOENT ) return false; // Entry not found505 return false;506 #endif507 }508 509 449 //----------------------------------------------------------------------------- 510 450 // Check if a function is has asynchronous -
libcfa/src/concurrency/io/setup.cfa
rfeacef9 r5407cdc 26 26 27 27 #if !defined(CFA_HAVE_LINUX_IO_URING_H) 28 void __kernel_io_startup() {29 // Nothing to do without io_uring30 }31 32 void __kernel_io_shutdown() {33 // Nothing to do without io_uring34 }35 36 28 void ?{}(io_context_params & this) {} 37 29 38 void ?{}(io_context & this, struct cluster & cl) {} 39 void ?{}(io_context & this, struct cluster & cl, const io_context_params & params) {} 40 41 void ^?{}(io_context & this) {} 42 void ^?{}(io_context & this, bool cluster_context) {} 43 44 void register_fixed_files( io_context &, int *, unsigned ) {} 45 void register_fixed_files( cluster &, int *, unsigned ) {} 30 void ?{}($io_context & this, struct cluster & cl) {} 31 void ^?{}($io_context & this) {} 32 33 void __cfa_io_start( processor * proc ) {} 34 void __cfa_io_flush( processor * proc ) {} 35 void __cfa_io_stop ( processor * proc ) {} 36 37 $io_arbiter * create(void) { return 0p; } 38 void destroy($io_arbiter *) {} 46 39 47 40 #else … … 68 61 void ?{}(io_context_params & this) { 69 62 this.num_entries = 256; 70 this.num_ready = 256;71 this.submit_aff = -1;72 this.eager_submits = false;73 this.poller_submits = false;74 this.poll_submit = false;75 this.poll_complete = false;76 63 } 77 64 … … 106 93 107 94 //============================================================================================= 108 // I/O Startup / Shutdown logic + Master Poller109 //=============================================================================================110 111 // IO Master poller loop forward112 static void * iopoll_loop( __attribute__((unused)) void * args );113 114 static struct {115 pthread_t thrd; // pthread handle to io poller thread116 void * stack; // pthread stack for io poller thread117 int epollfd; // file descriptor to the epoll instance118 volatile bool run; // Whether or not to continue119 volatile bool stopped; // Whether the poller has finished running120 volatile uint64_t epoch; // Epoch used for memory reclamation121 } iopoll;122 123 void __kernel_io_startup(void) {124 __cfadbg_print_safe(io_core, "Kernel : Creating EPOLL instance\n" );125 126 iopoll.epollfd = epoll_create1(0);127 if (iopoll.epollfd == -1) {128 abort( "internal error, epoll_create1\n");129 }130 131 __cfadbg_print_safe(io_core, "Kernel : Starting io poller thread\n" );132 133 iopoll.stack = __create_pthread( &iopoll.thrd, iopoll_loop, 0p );134 iopoll.run = true;135 iopoll.stopped = false;136 iopoll.epoch = 0;137 }138 139 void __kernel_io_shutdown(void) {140 // Notify the io poller thread of the shutdown141 iopoll.run = false;142 sigval val = { 1 };143 pthread_sigqueue( iopoll.thrd, SIGUSR1, val );144 145 // Wait for the io poller thread to finish146 147 __destroy_pthread( iopoll.thrd, iopoll.stack, 0p );148 149 int ret = close(iopoll.epollfd);150 if (ret == -1) {151 abort( "internal error, close epoll\n");152 }153 154 // Io polling is now fully stopped155 156 __cfadbg_print_safe(io_core, "Kernel : IO poller stopped\n" );157 }158 159 static void * iopoll_loop( __attribute__((unused)) void * args ) {160 __processor_id_t id;161 id.full_proc = false;162 id.id = doregister(&id);163 __cfaabi_tls.this_proc_id = &id;164 __cfadbg_print_safe(io_core, "Kernel : IO poller thread starting\n" );165 166 // Block signals to control when they arrive167 sigset_t mask;168 sigfillset(&mask);169 if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {170 abort( "internal error, pthread_sigmask" );171 }172 173 sigdelset( &mask, SIGUSR1 );174 175 // Create sufficient events176 struct epoll_event events[10];177 // Main loop178 while( iopoll.run ) {179 __cfadbg_print_safe(io_core, "Kernel I/O - epoll : waiting on io_uring contexts\n");180 181 // increment the epoch to notify any deleters we are starting a new cycle182 __atomic_fetch_add(&iopoll.epoch, 1, __ATOMIC_SEQ_CST);183 184 // Wait for events185 int nfds = epoll_pwait( iopoll.epollfd, events, 10, -1, &mask );186 187 __cfadbg_print_safe(io_core, "Kernel I/O - epoll : %d io contexts events, waking up\n", nfds);188 189 // Check if an error occured190 if (nfds == -1) {191 if( errno == EINTR ) continue;192 abort( "internal error, pthread_sigmask" );193 }194 195 for(i; nfds) {196 $io_ctx_thread * io_ctx = ($io_ctx_thread *)(uintptr_t)events[i].data.u64;197 /* paranoid */ verify( io_ctx );198 __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Unparking io poller %d (%p)\n", io_ctx->ring->fd, io_ctx);199 #if !defined( __CFA_NO_STATISTICS__ )200 __cfaabi_tls.this_stats = io_ctx->self.curr_cluster->stats;201 #endif202 203 eventfd_t v;204 eventfd_read(io_ctx->ring->efd, &v);205 206 post( io_ctx->sem );207 }208 }209 210 __atomic_store_n(&iopoll.stopped, true, __ATOMIC_SEQ_CST);211 212 __cfadbg_print_safe(io_core, "Kernel : IO poller thread stopping\n" );213 unregister(&id);214 return 0p;215 }216 217 //=============================================================================================218 95 // I/O Context Constrution/Destruction 219 96 //============================================================================================= 220 97 221 void ?{}($io_ctx_thread & this, struct cluster & cl) { (this.self){ "IO Poller", cl }; } 222 void main( $io_ctx_thread & this ); 223 static inline $thread * get_thread( $io_ctx_thread & this ) { return &this.self; } 224 void ^?{}( $io_ctx_thread & mutex this ) {} 225 226 static void __io_create ( __io_data & this, const io_context_params & params_in ); 227 static void __io_destroy( __io_data & this ); 228 229 void ?{}(io_context & this, struct cluster & cl, const io_context_params & params) { 230 (this.thrd){ cl }; 231 this.thrd.ring = malloc(); 232 __cfadbg_print_safe(io_core, "Kernel I/O : Creating ring for io_context %p\n", &this); 233 __io_create( *this.thrd.ring, params ); 234 235 __cfadbg_print_safe(io_core, "Kernel I/O : Starting poller thread for io_context %p\n", &this); 236 this.thrd.done = false; 237 __thrd_start( this.thrd, main ); 238 239 __cfadbg_print_safe(io_core, "Kernel I/O : io_context %p ready\n", &this); 240 } 241 242 void ?{}(io_context & this, struct cluster & cl) { 243 io_context_params params; 244 (this){ cl, params }; 245 } 246 247 void ^?{}(io_context & this, bool cluster_context) { 248 __cfadbg_print_safe(io_core, "Kernel I/O : tearing down io_context %p\n", &this); 249 250 // Notify the thread of the shutdown 251 __atomic_store_n(&this.thrd.done, true, __ATOMIC_SEQ_CST); 252 253 // If this is an io_context within a cluster, things get trickier 254 $thread & thrd = this.thrd.self; 255 if( cluster_context ) { 256 // We are about to do weird things with the threads 257 // we don't need interrupts to complicate everything 258 disable_interrupts(); 259 260 // Get cluster info 261 cluster & cltr = *thrd.curr_cluster; 262 /* paranoid */ verify( cltr.idles.total == 0 || &cltr == mainCluster ); 263 /* paranoid */ verify( !ready_mutate_islocked() ); 264 265 // We need to adjust the clean-up based on where the thread is 266 if( thrd.state == Ready || thrd.preempted != __NO_PREEMPTION ) { 267 // This is the tricky case 268 // The thread was preempted or ready to run and now it is on the ready queue 269 // but the cluster is shutting down, so there aren't any processors to run the ready queue 270 // the solution is to steal the thread from the ready-queue and pretend it was blocked all along 271 272 ready_schedule_lock(); 273 // The thread should on the list 274 /* paranoid */ verify( thrd.link.next != 0p ); 275 276 // Remove the thread from the ready queue of this cluster 277 // The thread should be the last on the list 278 __attribute__((unused)) bool removed = remove_head( &cltr, &thrd ); 279 /* paranoid */ verify( removed ); 280 thrd.link.next = 0p; 281 thrd.link.prev = 0p; 282 283 // Fixup the thread state 284 thrd.state = Blocked; 285 thrd.ticket = TICKET_BLOCKED; 286 thrd.preempted = __NO_PREEMPTION; 287 288 ready_schedule_unlock(); 289 290 // Pretend like the thread was blocked all along 291 } 292 // !!! This is not an else if !!! 293 // Ok, now the thread is blocked (whether we cheated to get here or not) 294 if( thrd.state == Blocked ) { 295 // This is the "easy case" 296 // The thread is parked and can easily be moved to active cluster 297 verify( thrd.curr_cluster != active_cluster() || thrd.curr_cluster == mainCluster ); 298 thrd.curr_cluster = active_cluster(); 299 300 // unpark the fast io_poller 301 unpark( &thrd ); 302 } 303 else { 304 // The thread is in a weird state 305 // I don't know what to do here 306 abort("io_context poller thread is in unexpected state, cannot clean-up correctly\n"); 307 } 308 309 // The weird thread kidnapping stuff is over, restore interrupts. 310 enable_interrupts( __cfaabi_dbg_ctx ); 311 } else { 312 post( this.thrd.sem ); 313 } 314 315 ^(this.thrd){}; 316 __cfadbg_print_safe(io_core, "Kernel I/O : Stopped poller thread for io_context %p\n", &this); 317 318 __io_destroy( *this.thrd.ring ); 319 __cfadbg_print_safe(io_core, "Kernel I/O : Destroyed ring for io_context %p\n", &this); 320 321 free(this.thrd.ring); 322 } 323 324 void ^?{}(io_context & this) { 325 ^(this){ false }; 98 99 100 static void __io_uring_setup ( $io_context & this, const io_context_params & params_in, int procfd ); 101 static void __io_uring_teardown( $io_context & this ); 102 static void __epoll_register($io_context & ctx); 103 static void __epoll_unregister($io_context & ctx); 104 void __ioarbiter_register( $io_arbiter & mutex, $io_context & ctx ); 105 void __ioarbiter_unregister( $io_arbiter & mutex, $io_context & ctx ); 106 107 void ?{}($io_context & this, processor * proc, struct cluster & cl) { 108 /* paranoid */ verify( cl.io.arbiter ); 109 this.proc = proc; 110 this.arbiter = cl.io.arbiter; 111 this.ext_sq.empty = true; 112 (this.ext_sq.queue){}; 113 __io_uring_setup( this, cl.io.params, proc->idle ); 114 __cfadbg_print_safe(io_core, "Kernel I/O : Created ring for io_context %u (%p)\n", this.fd, &this); 115 } 116 117 void ^?{}($io_context & this) { 118 __cfadbg_print_safe(io_core, "Kernel I/O : tearing down io_context %u\n", this.fd); 119 120 __io_uring_teardown( this ); 121 __cfadbg_print_safe(io_core, "Kernel I/O : Destroyed ring for io_context %u\n", this.fd); 326 122 } 327 123 … … 329 125 extern void __enable_interrupts_hard(); 330 126 331 static void __io_ create( __io_data & this, const io_context_params & params_in) {127 static void __io_uring_setup( $io_context & this, const io_context_params & params_in, int procfd ) { 332 128 // Step 1 : call to setup 333 129 struct io_uring_params params; 334 130 memset(¶ms, 0, sizeof(params)); 335 if( params_in.poll_submit ) params.flags |= IORING_SETUP_SQPOLL;336 if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL;131 // if( params_in.poll_submit ) params.flags |= IORING_SETUP_SQPOLL; 132 // if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL; 337 133 338 134 __u32 nentries = params_in.num_entries != 0 ? params_in.num_entries : 256; … … 340 136 abort("ERROR: I/O setup 'num_entries' must be a power of 2\n"); 341 137 } 342 if( params_in.poller_submits && params_in.eager_submits ) {343 abort("ERROR: I/O setup 'poller_submits' and 'eager_submits' cannot be used together\n");344 }345 138 346 139 int fd = syscall(__NR_io_uring_setup, nentries, ¶ms ); … … 350 143 351 144 // Step 2 : mmap result 352 memset( &this, 0, sizeof(struct __io_data) ); 353 struct __submition_data & sq = this.submit_q; 354 struct __completion_data & cq = this.completion_q; 145 struct __sub_ring_t & sq = this.sq; 146 struct __cmp_ring_t & cq = this.cq; 355 147 356 148 // calculate the right ring size … … 401 193 // Get the pointers from the kernel to fill the structure 402 194 // submit queue 403 sq.head = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head); 404 sq.tail = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail); 405 sq.mask = ( const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask); 406 sq.num = ( const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries); 407 sq.flags = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags); 408 sq.dropped = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped); 409 sq.array = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array); 410 sq.prev_head = *sq.head; 411 412 { 413 const __u32 num = *sq.num; 414 for( i; num ) { 415 __sqe_clean( &sq.sqes[i] ); 416 } 417 } 418 419 (sq.submit_lock){}; 420 (sq.release_lock){}; 421 422 if( params_in.poller_submits || params_in.eager_submits ) { 423 /* paranoid */ verify( is_pow2( params_in.num_ready ) || (params_in.num_ready < 8) ); 424 sq.ready_cnt = max( params_in.num_ready, 8 ); 425 sq.ready = alloc( sq.ready_cnt, 64`align ); 426 for(i; sq.ready_cnt) { 427 sq.ready[i] = -1ul32; 428 } 429 sq.prev_ready = 0; 430 } 431 else { 432 sq.ready_cnt = 0; 433 sq.ready = 0p; 434 sq.prev_ready = 0; 435 } 195 sq.kring.head = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head); 196 sq.kring.tail = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail); 197 sq.kring.array = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array); 198 sq.mask = ( const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask); 199 sq.num = ( const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries); 200 sq.flags = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags); 201 sq.dropped = ( __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped); 202 203 sq.kring.released = 0; 204 205 sq.free_ring.head = 0; 206 sq.free_ring.tail = *sq.num; 207 sq.free_ring.array = alloc( *sq.num, 128`align ); 208 for(i; (__u32)*sq.num) { 209 sq.free_ring.array[i] = i; 210 } 211 212 sq.to_submit = 0; 436 213 437 214 // completion queue … … 446 223 // io_uring_register is so f*cking slow on some machine that it 447 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 448 227 __disable_interrupts_hard(); 449 228 450 int efd = eventfd(0, 0); 451 if (efd < 0) { 452 abort("KERNEL ERROR: IO_URING EVENTFD - %s\n", strerror(errno)); 453 } 454 455 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &efd, 1); 229 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1); 456 230 if (ret < 0) { 457 231 abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno)); … … 459 233 460 234 __enable_interrupts_hard(); 235 236 __cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd); 461 237 462 238 // some paranoid checks … … 468 244 /* paranoid */ verifyf( (*sq.mask) == ((*sq.num) - 1ul32), "IO_URING Expected mask to be %u (%u entries), was %u", (*sq.num) - 1ul32, *sq.num, *sq.mask ); 469 245 /* paranoid */ verifyf( (*sq.num) >= nentries, "IO_URING Expected %u entries, got %u", nentries, *sq.num ); 470 /* paranoid */ verifyf( (*sq. head) == 0, "IO_URING Expected head to be 0, got %u", *sq.head );471 /* paranoid */ verifyf( (*sq. tail) == 0, "IO_URING Expected tail to be 0, got %u", *sq.tail );246 /* paranoid */ verifyf( (*sq.kring.head) == 0, "IO_URING Expected head to be 0, got %u", *sq.kring.head ); 247 /* paranoid */ verifyf( (*sq.kring.tail) == 0, "IO_URING Expected tail to be 0, got %u", *sq.kring.tail ); 472 248 473 249 // Update the global ring info 474 this.ring_flags = params.flags;250 this.ring_flags = 0; 475 251 this.fd = fd; 476 this.efd = efd; 477 this.eager_submits = params_in.eager_submits; 478 this.poller_submits = params_in.poller_submits; 479 } 480 481 static void __io_destroy( __io_data & this ) { 252 } 253 254 static void __io_uring_teardown( $io_context & this ) { 482 255 // Shutdown the io rings 483 struct __sub mition_data & sq = this.submit_q;484 struct __c ompletion_data & cq = this.completion_q;256 struct __sub_ring_t & sq = this.sq; 257 struct __cmp_ring_t & cq = this.cq; 485 258 486 259 // unmap the submit queue entries … … 497 270 // close the file descriptor 498 271 close(this.fd); 499 close(this.efd); 500 501 free( this.submit_q.ready ); // Maybe null, doesn't matter 272 273 free( this.sq.free_ring.array ); // Maybe null, doesn't matter 274 } 275 276 void __cfa_io_start( processor * proc ) { 277 proc->io.ctx = alloc(); 278 (*proc->io.ctx){proc, *proc->cltr}; 279 } 280 void __cfa_io_stop ( processor * proc ) { 281 ^(*proc->io.ctx){}; 282 free(proc->io.ctx); 502 283 } 503 284 … … 505 286 // I/O Context Sleep 506 287 //============================================================================================= 507 static inline void __ioctx_epoll_ctl($io_ctx_thread & ctx, int op, const char * error) { 508 struct epoll_event ev; 509 ev.events = EPOLLIN | EPOLLONESHOT; 510 ev.data.u64 = (__u64)&ctx; 511 int ret = epoll_ctl(iopoll.epollfd, op, ctx.ring->efd, &ev); 512 if (ret < 0) { 513 abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) ); 514 } 515 } 516 517 void __ioctx_register($io_ctx_thread & ctx) { 518 __ioctx_epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD"); 519 } 520 521 void __ioctx_prepare_block($io_ctx_thread & ctx) { 522 __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.ring->fd, &ctx); 523 __ioctx_epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM"); 524 } 525 526 void __ioctx_unregister($io_ctx_thread & ctx) { 527 // Read the current epoch so we know when to stop 528 size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST); 529 530 // Remove the fd from the iopoller 531 __ioctx_epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE"); 532 533 // Notify the io poller thread of the shutdown 534 iopoll.run = false; 535 sigval val = { 1 }; 536 pthread_sigqueue( iopoll.thrd, SIGUSR1, val ); 537 538 // Make sure all this is done 539 __atomic_thread_fence(__ATOMIC_SEQ_CST); 540 541 // Wait for the next epoch 542 while(curr == iopoll.epoch && !iopoll.stopped) Pause(); 543 } 288 // static inline void __epoll_ctl($io_context & ctx, int op, const char * error) { 289 // struct epoll_event ev; 290 // ev.events = EPOLLIN | EPOLLONESHOT; 291 // ev.data.u64 = (__u64)&ctx; 292 // int ret = epoll_ctl(iopoll.epollfd, op, ctx.efd, &ev); 293 // if (ret < 0) { 294 // abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) ); 295 // } 296 // } 297 298 // static void __epoll_register($io_context & ctx) { 299 // __epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD"); 300 // } 301 302 // static void __epoll_unregister($io_context & ctx) { 303 // // Read the current epoch so we know when to stop 304 // size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST); 305 306 // // Remove the fd from the iopoller 307 // __epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE"); 308 309 // // Notify the io poller thread of the shutdown 310 // iopoll.run = false; 311 // sigval val = { 1 }; 312 // pthread_sigqueue( iopoll.thrd, SIGUSR1, val ); 313 314 // // Make sure all this is done 315 // __atomic_thread_fence(__ATOMIC_SEQ_CST); 316 317 // // Wait for the next epoch 318 // while(curr == iopoll.epoch && !iopoll.stopped) Pause(); 319 // } 320 321 // void __ioctx_prepare_block($io_context & ctx) { 322 // __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.fd, &ctx); 323 // __epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM"); 324 // } 325 544 326 545 327 //============================================================================================= 546 328 // I/O Context Misc Setup 547 329 //============================================================================================= 548 void register_fixed_files( io_context & ctx, int * files, unsigned count ) { 549 int ret = syscall( __NR_io_uring_register, ctx.thrd.ring->fd, IORING_REGISTER_FILES, files, count ); 550 if( ret < 0 ) { 551 abort( "KERNEL ERROR: IO_URING REGISTER - (%d) %s\n", (int)errno, strerror(errno) ); 552 } 553 554 __cfadbg_print_safe( io_core, "Kernel I/O : Performed io_register for %p, returned %d\n", active_thread(), ret ); 555 } 556 557 void register_fixed_files( cluster & cltr, int * files, unsigned count ) { 558 for(i; cltr.io.cnt) { 559 register_fixed_files( cltr.io.ctxs[i], files, count ); 560 } 561 } 330 void ?{}( $io_arbiter & this ) { 331 this.pending.empty = true; 332 } 333 334 void ^?{}( $io_arbiter & this ) {} 335 336 $io_arbiter * create(void) { 337 return new(); 338 } 339 void destroy($io_arbiter * arbiter) { 340 delete(arbiter); 341 } 342 343 //============================================================================================= 344 // I/O Context Misc Setup 345 //============================================================================================= 346 562 347 #endif -
libcfa/src/concurrency/io/types.hfa
rfeacef9 r5407cdc 22 22 23 23 #include "bits/locks.hfa" 24 #include "bits/queue.hfa" 24 25 #include "kernel/fwd.hfa" 25 26 26 27 #if defined(CFA_HAVE_LINUX_IO_URING_H) 27 #define LEADER_LOCK 28 struct __leaderlock_t { 29 struct $thread * volatile value; // ($thread) next_leader | (bool:1) is_locked 30 }; 28 #include "bits/sequence.hfa" 29 #include "monitor.hfa" 31 30 32 static inline void ?{}( __leaderlock_t & this ) { this.value = 0p; } 31 struct processor; 32 monitor $io_arbiter; 33 33 34 34 //----------------------------------------------------------------------- 35 35 // Ring Data structure 36 struct __submition_data { 37 // Head and tail of the ring (associated with array) 38 volatile __u32 * head; 39 volatile __u32 * tail; 40 volatile __u32 prev_head; 36 struct __sub_ring_t { 37 struct { 38 // Head and tail of the ring (associated with array) 39 volatile __u32 * head; // one passed last index consumed by the kernel 40 volatile __u32 * tail; // one passed last index visible to the kernel 41 volatile __u32 released; // one passed last index released back to the free list 41 42 42 // The actual kernel ring which uses head/tail 43 // indexes into the sqes arrays 44 __u32 * array; 43 // The actual kernel ring which uses head/tail 44 // indexes into the sqes arrays 45 __u32 * array; 46 } kring; 47 48 struct { 49 volatile __u32 head; 50 volatile __u32 tail; 51 // The ring which contains free allocations 52 // indexes into the sqes arrays 53 __u32 * array; 54 } free_ring; 55 56 // number of sqes to submit on next system call. 57 __u32 to_submit; 45 58 46 59 // number of entries and mask to go with it … … 48 61 const __u32 * mask; 49 62 50 // Submission flags (Not sure what for)63 // Submission flags, currently only IORING_SETUP_SQPOLL 51 64 __u32 * flags; 52 65 53 // number of sqes not submitted (whatever that means) 66 // number of sqes not submitted 67 // From documentation : [dropped] is incremented for each invalid submission queue entry encountered in the ring buffer. 54 68 __u32 * dropped; 55 69 56 // Like head/tail but not seen by the kernel57 volatile __u32 * ready;58 __u32 ready_cnt;59 __u32 prev_ready;60 61 #if defined(LEADER_LOCK)62 __leaderlock_t submit_lock;63 #else64 __spinlock_t submit_lock;65 #endif66 __spinlock_t release_lock;67 68 70 // A buffer of sqes (not the actual ring) 69 volatilestruct io_uring_sqe * sqes;71 struct io_uring_sqe * sqes; 70 72 71 73 // The location and size of the mmaped area … … 74 76 }; 75 77 76 struct __c ompletion_data{78 struct __cmp_ring_t { 77 79 // Head and tail of the ring 78 80 volatile __u32 * head; … … 83 85 const __u32 * num; 84 86 85 // number of cqes not submitted (whatever that means)87 // I don't know what this value is for 86 88 __u32 * overflow; 87 89 … … 94 96 }; 95 97 96 struct __io_data { 97 struct __submition_data submit_q; 98 struct __completion_data completion_q; 98 struct __outstanding_io { 99 inline Colable; 100 single_sem sem; 101 }; 102 static inline __outstanding_io *& Next( __outstanding_io * n ) { return (__outstanding_io *)Next( (Colable *)n ); } 103 104 struct __outstanding_io_queue { 105 __spinlock_t lock; 106 Queue(__outstanding_io) queue; 107 volatile bool empty; 108 }; 109 110 struct __external_io { 111 inline __outstanding_io; 112 __u32 * idxs; 113 __u32 have; 114 bool lazy; 115 }; 116 117 118 struct __attribute__((aligned(128))) $io_context { 119 $io_arbiter * arbiter; 120 processor * proc; 121 122 __outstanding_io_queue ext_sq; 123 124 struct __sub_ring_t sq; 125 struct __cmp_ring_t cq; 99 126 __u32 ring_flags; 100 127 int fd; 101 int efd; 102 bool eager_submits:1; 103 bool poller_submits:1; 128 }; 129 130 struct __pending_alloc { 131 inline __outstanding_io; 132 __u32 * idxs; 133 __u32 want; 134 $io_context * ctx; 135 }; 136 137 struct __attribute__((aligned(128))) $io_arbiter { 138 __outstanding_io_queue pending; 104 139 }; 105 140 … … 133 168 #endif 134 169 135 struct $io_ctx_thread; 136 void __ioctx_register($io_ctx_thread & ctx); 137 void __ioctx_unregister($io_ctx_thread & ctx); 138 void __ioctx_prepare_block($io_ctx_thread & ctx); 139 void __sqe_clean( volatile struct io_uring_sqe * sqe ); 170 // void __ioctx_prepare_block($io_context & ctx); 140 171 #endif 141 172 … … 148 179 149 180 static inline { 150 bool fulfil( io_future_t & this, __s32 result) {181 $thread * fulfil( io_future_t & this, __s32 result, bool do_unpark = true ) { 151 182 this.result = result; 152 return fulfil(this.self );183 return fulfil(this.self, do_unpark); 153 184 } 154 185 -
libcfa/src/concurrency/iofwd.hfa
rfeacef9 r5407cdc 18 18 #include <unistd.h> 19 19 extern "C" { 20 #include < sys/types.h>20 #include <asm/types.h> 21 21 #if CFA_HAVE_LINUX_IO_URING_H 22 22 #include <linux/io_uring.h> … … 48 48 struct cluster; 49 49 struct io_future_t; 50 struct io_context; 51 struct io_cancellation; 50 struct $io_context; 52 51 53 52 struct iovec; … … 55 54 struct sockaddr; 56 55 struct statx; 56 struct epoll_event; 57 58 struct io_uring_sqe; 59 60 //---------- 61 // underlying calls 62 extern struct $io_context * cfa_io_allocate(struct io_uring_sqe * out_sqes[], __u32 out_idxs[], __u32 want) __attribute__((nonnull (1,2))); 63 extern void cfa_io_submit( struct $io_context * in_ctx, __u32 in_idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1,2))); 57 64 58 65 //---------- 59 66 // synchronous calls 60 67 #if defined(CFA_HAVE_PREADV2) 61 extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);68 extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags); 62 69 #endif 63 70 #if defined(CFA_HAVE_PWRITEV2) 64 extern ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);71 extern ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags); 65 72 #endif 66 extern int cfa_fsync(int fd, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);67 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);68 extern int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);69 extern ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);70 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);71 extern ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);72 extern ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);73 extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);74 extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);75 extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);76 extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);77 extern int cfa_madvise(void *addr, size_t length, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);78 extern int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);73 extern int cfa_fsync(int fd, __u64 submit_flags); 74 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags); 75 extern int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags); 76 extern ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags); 77 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags, __u64 submit_flags); 78 extern ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags); 79 extern ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags, __u64 submit_flags); 80 extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags); 81 extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags); 82 extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, __u64 submit_flags); 83 extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, __u64 submit_flags); 84 extern int cfa_madvise(void *addr, size_t length, int advice, __u64 submit_flags); 85 extern int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags); 79 86 #if defined(CFA_HAVE_OPENAT2) 80 extern int cfa_openat2(int dirfd, const char *pathname, struct open_how * how, size_t size, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);87 extern int cfa_openat2(int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags); 81 88 #endif 82 extern int cfa_close(int fd, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);89 extern int cfa_close(int fd, __u64 submit_flags); 83 90 #if defined(CFA_HAVE_STATX) 84 extern int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);91 extern int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags); 85 92 #endif 86 extern ssize_t cfa_read(int fd, void * buf, size_t count, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);87 extern ssize_t cfa_write(int fd, void * buf, size_t count, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);88 extern ssize_t cfa_splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);89 extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);93 extern ssize_t cfa_read(int fd, void * buf, size_t count, __u64 submit_flags); 94 extern ssize_t cfa_write(int fd, void * buf, size_t count, __u64 submit_flags); 95 extern ssize_t cfa_splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags); 96 extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags); 90 97 91 98 //---------- 92 99 // asynchronous calls 93 100 #if defined(CFA_HAVE_PREADV2) 94 extern void async_preadv2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);101 extern void async_preadv2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags); 95 102 #endif 96 103 #if defined(CFA_HAVE_PWRITEV2) 97 extern void async_pwritev2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);104 extern void async_pwritev2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags); 98 105 #endif 99 extern void async_fsync(io_future_t & future, int fd, int submit_flags, io_cancellation * cancellation, io_context * context);100 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event *event, int submit_flags, io_cancellation * cancellation, io_context * context);101 extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context);102 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr *msg, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);103 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr *msg, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);104 extern void async_send(io_future_t & future, int sockfd, const void *buf, size_t len, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);105 extern void async_recv(io_future_t & future, int sockfd, void *buf, size_t len, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);106 extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);107 extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, int submit_flags, io_cancellation * cancellation, io_context * context);108 extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, int submit_flags, io_cancellation * cancellation, io_context * context);109 extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, int submit_flags, io_cancellation * cancellation, io_context * context);110 extern void async_madvise(io_future_t & future, void *addr, size_t length, int advice, int submit_flags, io_cancellation * cancellation, io_context * context);111 extern void async_openat(io_future_t & future, int dirfd, const char *pathname, int flags, mode_t mode, int submit_flags, io_cancellation * cancellation, io_context * context);106 extern void async_fsync(io_future_t & future, int fd, __u64 submit_flags); 107 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags); 108 extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags); 109 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags); 110 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr *msg, int flags, __u64 submit_flags); 111 extern void async_send(io_future_t & future, int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags); 112 extern void async_recv(io_future_t & future, int sockfd, void *buf, size_t len, int flags, __u64 submit_flags); 113 extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags); 114 extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags); 115 extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, __u64 submit_flags); 116 extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, __u64 submit_flags); 117 extern void async_madvise(io_future_t & future, void *addr, size_t length, int advice, __u64 submit_flags); 118 extern void async_openat(io_future_t & future, int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags); 112 119 #if defined(CFA_HAVE_OPENAT2) 113 extern void async_openat2(io_future_t & future, int dirfd, const char *pathname, struct open_how * how, size_t size, int submit_flags, io_cancellation * cancellation, io_context * context);120 extern void async_openat2(io_future_t & future, int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags); 114 121 #endif 115 extern void async_close(io_future_t & future, int fd, int submit_flags, io_cancellation * cancellation, io_context * context);122 extern void async_close(io_future_t & future, int fd, __u64 submit_flags); 116 123 #if defined(CFA_HAVE_STATX) 117 extern void async_statx(io_future_t & future, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, int submit_flags, io_cancellation * cancellation, io_context * context);124 extern void async_statx(io_future_t & future, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags); 118 125 #endif 119 void async_read(io_future_t & future, int fd, void * buf, size_t count, int submit_flags, io_cancellation * cancellation, io_context * context);120 extern void async_write(io_future_t & future, int fd, void * buf, size_t count, int submit_flags, io_cancellation * cancellation, io_context * context);121 extern void async_splice(io_future_t & future, int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context);122 extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context);126 void async_read(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags); 127 extern void async_write(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags); 128 extern void async_splice(io_future_t & future, int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags); 129 extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags); 123 130 124 131 … … 126 133 // Check if a function is blocks a only the user thread 127 134 bool has_user_level_blocking( fptr_t func ); 128 129 //-----------------------------------------------------------------------------130 void register_fixed_files( io_context & ctx , int * files, unsigned count );131 void register_fixed_files( cluster & cltr, int * files, unsigned count ); -
libcfa/src/concurrency/kernel.cfa
rfeacef9 r5407cdc 22 22 #include <signal.h> 23 23 #include <unistd.h> 24 extern "C" { 25 #include <sys/eventfd.h> 26 } 24 27 25 28 //CFA Includes … … 31 34 #include "invoke.h" 32 35 36 #if !defined(__CFA_NO_STATISTICS__) 37 #define __STATS( ...) __VA_ARGS__ 38 #else 39 #define __STATS( ...) 40 #endif 33 41 34 42 //----------------------------------------------------------------------------- … … 107 115 static $thread * __next_thread(cluster * this); 108 116 static $thread * __next_thread_slow(cluster * this); 117 static inline bool __must_unpark( $thread * thrd ) __attribute((nonnull(1))); 109 118 static void __run_thread(processor * this, $thread * dst); 110 119 static void __wake_one(cluster * cltr); 111 120 112 static void push (__cluster_idles & idles, processor & proc); 113 static void remove(__cluster_idles & idles, processor & proc); 114 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles ); 115 121 static void mark_idle (__cluster_proc_list & idles, processor & proc); 122 static void mark_awake(__cluster_proc_list & idles, processor & proc); 123 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list idles ); 124 125 extern void __cfa_io_start( processor * ); 126 extern bool __cfa_io_drain( processor * ); 127 extern void __cfa_io_flush( processor * ); 128 extern void __cfa_io_stop ( processor * ); 129 static inline bool __maybe_io_drain( processor * ); 130 131 extern void __disable_interrupts_hard(); 132 extern void __enable_interrupts_hard(); 133 134 static inline void __disable_interrupts_checked() { 135 /* paranoid */ verify( __preemption_enabled() ); 136 disable_interrupts(); 137 /* paranoid */ verify( ! __preemption_enabled() ); 138 } 139 140 static inline void __enable_interrupts_checked( bool poll = true ) { 141 /* paranoid */ verify( ! __preemption_enabled() ); 142 enable_interrupts( poll ); 143 /* paranoid */ verify( __preemption_enabled() ); 144 } 116 145 117 146 //============================================================================================= … … 129 158 verify(this); 130 159 160 __cfa_io_start( this ); 161 131 162 __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this); 132 163 #if !defined(__CFA_NO_STATISTICS__) … … 140 171 preemption_scope scope = { this }; 141 172 142 #if !defined(__CFA_NO_STATISTICS__) 143 unsigned long long last_tally = rdtscl(); 144 #endif 145 173 __STATS( unsigned long long last_tally = rdtscl(); ) 174 175 // if we need to run some special setup, now is the time to do it. 176 if(this->init.thrd) { 177 this->init.thrd->curr_cluster = this->cltr; 178 __run_thread(this, this->init.thrd); 179 } 146 180 147 181 __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this); … … 150 184 MAIN_LOOP: 151 185 for() { 186 // Check if there is pending io 187 __maybe_io_drain( this ); 188 152 189 // Try to get the next thread 153 190 readyThread = __next_thread( this->cltr ); 154 191 155 192 if( !readyThread ) { 193 __cfa_io_flush( this ); 156 194 readyThread = __next_thread_slow( this->cltr ); 157 195 } … … 167 205 168 206 // Push self to idle stack 169 push(this->cltr->idles, * this);207 mark_idle(this->cltr->procs, * this); 170 208 171 209 // Confirm the ready-queue is empty … … 173 211 if( readyThread ) { 174 212 // A thread was found, cancel the halt 175 remove(this->cltr->idles, * this);213 mark_awake(this->cltr->procs, * this); 176 214 177 215 #if !defined(__CFA_NO_STATISTICS__) … … 189 227 #endif 190 228 191 wait( this->idle ); 229 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 230 231 __disable_interrupts_hard(); 232 eventfd_t val; 233 eventfd_read( this->idle, &val ); 234 __enable_interrupts_hard(); 192 235 193 236 #if !defined(__CFA_NO_STATISTICS__) … … 198 241 199 242 // We were woken up, remove self from idle 200 remove(this->cltr->idles, * this);243 mark_awake(this->cltr->procs, * this); 201 244 202 245 // DON'T just proceed, start looking again … … 205 248 206 249 /* paranoid */ verify( readyThread ); 250 251 // Reset io dirty bit 252 this->io.dirty = false; 207 253 208 254 // We found a thread run it … … 219 265 } 220 266 #endif 267 268 if(this->io.pending && !this->io.dirty) { 269 __cfa_io_flush( this ); 270 } 271 272 // SEARCH: { 273 // /* paranoid */ verify( ! __preemption_enabled() ); 274 // /* paranoid */ verify( kernelTLS().this_proc_id ); 275 276 // // First, lock the scheduler since we are searching for a thread 277 278 // // Try to get the next thread 279 // ready_schedule_lock(); 280 // readyThread = pop_fast( this->cltr ); 281 // ready_schedule_unlock(); 282 // if(readyThread) { break SEARCH; } 283 284 // // If we can't find a thread, might as well flush any outstanding I/O 285 // if(this->io.pending) { __cfa_io_flush( this ); } 286 287 // // Spin a little on I/O, just in case 288 // for(25) { 289 // __maybe_io_drain( this ); 290 // ready_schedule_lock(); 291 // readyThread = pop_fast( this->cltr ); 292 // ready_schedule_unlock(); 293 // if(readyThread) { break SEARCH; } 294 // } 295 296 // // no luck, try stealing a few times 297 // for(25) { 298 // if( __maybe_io_drain( this ) ) { 299 // ready_schedule_lock(); 300 // readyThread = pop_fast( this->cltr ); 301 // } else { 302 // ready_schedule_lock(); 303 // readyThread = pop_slow( this->cltr ); 304 // } 305 // ready_schedule_unlock(); 306 // if(readyThread) { break SEARCH; } 307 // } 308 309 // // still no luck, search for a thread 310 // ready_schedule_lock(); 311 // readyThread = pop_search( this->cltr ); 312 // ready_schedule_unlock(); 313 // if(readyThread) { break SEARCH; } 314 315 // // Don't block if we are done 316 // if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 317 318 // __STATS( __tls_stats()->ready.sleep.halts++; ) 319 320 // // Push self to idle stack 321 // mark_idle(this->cltr->procs, * this); 322 323 // // Confirm the ready-queue is empty 324 // __maybe_io_drain( this ); 325 // ready_schedule_lock(); 326 // readyThread = pop_search( this->cltr ); 327 // ready_schedule_unlock(); 328 329 // if( readyThread ) { 330 // // A thread was found, cancel the halt 331 // mark_awake(this->cltr->procs, * this); 332 333 // __STATS( __tls_stats()->ready.sleep.cancels++; ) 334 335 // // continue the main loop 336 // break SEARCH; 337 // } 338 339 // __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); ) 340 // __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 341 342 // // __disable_interrupts_hard(); 343 // eventfd_t val; 344 // eventfd_read( this->idle, &val ); 345 // // __enable_interrupts_hard(); 346 347 // __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); ) 348 349 // // We were woken up, remove self from idle 350 // mark_awake(this->cltr->procs, * this); 351 352 // // DON'T just proceed, start looking again 353 // continue MAIN_LOOP; 354 // } 355 356 // RUN_THREAD: 357 // /* paranoid */ verify( kernelTLS().this_proc_id ); 358 // /* paranoid */ verify( ! __preemption_enabled() ); 359 // /* paranoid */ verify( readyThread ); 360 361 // // Reset io dirty bit 362 // this->io.dirty = false; 363 364 // // We found a thread run it 365 // __run_thread(this, readyThread); 366 367 // // Are we done? 368 // if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP; 369 370 // #if !defined(__CFA_NO_STATISTICS__) 371 // unsigned long long curr = rdtscl(); 372 // if(curr > (last_tally + 500000000)) { 373 // __tally_stats(this->cltr->stats, __cfaabi_tls.this_stats); 374 // last_tally = curr; 375 // } 376 // #endif 377 378 // if(this->io.pending && !this->io.dirty) { 379 // __cfa_io_flush( this ); 380 // } 381 382 // // Check if there is pending io 383 // __maybe_io_drain( this ); 221 384 } 222 385 … … 224 387 } 225 388 389 __cfa_io_stop( this ); 390 226 391 post( this->terminated ); 392 227 393 228 394 if(this == mainProcessor) { … … 247 413 /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next ); 248 414 __builtin_prefetch( thrd_dst->context.SP ); 415 416 __cfadbg_print_safe(runtime_core, "Kernel : core %p running thread %p (%s)\n", this, thrd_dst, thrd_dst->self_cor.name); 249 417 250 418 $coroutine * proc_cor = get_coroutine(this->runner); … … 297 465 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) { 298 466 // The thread was preempted, reschedule it and reset the flag 299 __schedule_thread( thrd_dst );467 schedule_thread$( thrd_dst ); 300 468 break RUNNING; 301 469 } … … 318 486 break RUNNING; 319 487 case TICKET_UNBLOCK: 488 #if !defined(__CFA_NO_STATISTICS__) 489 __tls_stats()->ready.threads.threads++; 490 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this ); 491 #endif 320 492 // This is case 2, the racy case, someone tried to run this thread before it finished blocking 321 493 // In this case, just run it again. … … 330 502 proc_cor->state = Active; 331 503 504 __cfadbg_print_safe(runtime_core, "Kernel : core %p finished running thread %p\n", this, thrd_dst); 505 506 #if !defined(__CFA_NO_STATISTICS__) 507 __tls_stats()->ready.threads.threads--; 508 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this ); 509 #endif 510 332 511 /* paranoid */ verify( ! __preemption_enabled() ); 333 512 } … … 339 518 $thread * thrd_src = kernelTLS().this_thread; 340 519 341 #if !defined(__CFA_NO_STATISTICS__) 342 struct processor * last_proc = kernelTLS().this_processor; 343 #endif 520 __STATS( thrd_src->last_proc = kernelTLS().this_processor; ) 344 521 345 522 // Run the thread on this processor … … 360 537 361 538 #if !defined(__CFA_NO_STATISTICS__) 362 if(last_proc != kernelTLS().this_processor) { 539 /* paranoid */ verify( thrd_src->last_proc != 0p ); 540 if(thrd_src->last_proc != kernelTLS().this_processor) { 363 541 __tls_stats()->ready.threads.migration++; 364 542 } … … 373 551 // Scheduler routines 374 552 // KERNEL ONLY 375 void __schedule_thread( $thread * thrd ) {553 static void __schedule_thread( $thread * thrd ) { 376 554 /* paranoid */ verify( ! __preemption_enabled() ); 377 555 /* paranoid */ verify( kernelTLS().this_proc_id ); 556 /* paranoid */ verify( ready_schedule_islocked()); 378 557 /* paranoid */ verify( thrd ); 379 558 /* paranoid */ verify( thrd->state != Halted ); … … 391 570 if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready; 392 571 572 // Dereference the thread now because once we push it, there is not guaranteed it's still valid. 573 struct cluster * cl = thrd->curr_cluster; 574 __STATS(bool outside = thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; ) 575 576 // push the thread to the cluster ready-queue 577 push( cl, thrd ); 578 579 // variable thrd is no longer safe to use 580 thrd = 0xdeaddeaddeaddeadp; 581 582 // wake the cluster using the save variable. 583 __wake_one( cl ); 584 585 #if !defined(__CFA_NO_STATISTICS__) 586 if( kernelTLS().this_stats ) { 587 __tls_stats()->ready.threads.threads++; 588 if(outside) { 589 __tls_stats()->ready.threads.extunpark++; 590 } 591 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", kernelTLS().this_processor ); 592 } 593 else { 594 __atomic_fetch_add(&cl->stats->ready.threads.threads, 1, __ATOMIC_RELAXED); 595 __atomic_fetch_add(&cl->stats->ready.threads.extunpark, 1, __ATOMIC_RELAXED); 596 __push_stat( cl->stats, cl->stats->ready.threads.threads, true, "Cluster", cl ); 597 } 598 #endif 599 600 /* paranoid */ verify( ready_schedule_islocked()); 601 /* paranoid */ verify( ! __preemption_enabled() ); 602 } 603 604 void schedule_thread$( $thread * thrd ) { 393 605 ready_schedule_lock(); 394 // Dereference the thread now because once we push it, there is not guaranteed it's still valid. 395 struct cluster * cl = thrd->curr_cluster; 396 397 // push the thread to the cluster ready-queue 398 push( cl, thrd ); 399 400 // variable thrd is no longer safe to use 401 402 // wake the cluster using the save variable. 403 __wake_one( cl ); 606 __schedule_thread( thrd ); 404 607 ready_schedule_unlock(); 405 406 /* paranoid */ verify( ! __preemption_enabled() );407 608 } 408 609 … … 413 614 414 615 ready_schedule_lock(); 415 $thread * thrd = pop ( this );616 $thread * thrd = pop_fast( this ); 416 617 ready_schedule_unlock(); 417 618 … … 427 628 428 629 ready_schedule_lock(); 429 $thread * thrd = pop_slow( this ); 630 $thread * thrd; 631 for(25) { 632 thrd = pop_slow( this ); 633 if(thrd) goto RET; 634 } 635 thrd = pop_search( this ); 636 637 RET: 430 638 ready_schedule_unlock(); 431 639 … … 435 643 } 436 644 437 void unpark( $thread * thrd ) { 438 if( !thrd ) return; 439 645 static inline bool __must_unpark( $thread * thrd ) { 440 646 int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST); 441 647 switch(old_ticket) { 442 648 case TICKET_RUNNING: 443 649 // Wake won the race, the thread will reschedule/rerun itself 444 break;650 return false; 445 651 case TICKET_BLOCKED: 446 652 /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION ); 447 653 /* paranoid */ verify( thrd->state == Blocked ); 448 449 { 450 /* paranoid */ verify( publicTLS_get(this_proc_id) ); 451 bool full = publicTLS_get(this_proc_id)->full_proc; 452 if(full) disable_interrupts(); 453 454 /* paranoid */ verify( ! __preemption_enabled() ); 455 456 // Wake lost the race, 457 __schedule_thread( thrd ); 458 459 /* paranoid */ verify( ! __preemption_enabled() ); 460 461 if(full) enable_interrupts( __cfaabi_dbg_ctx ); 462 /* paranoid */ verify( publicTLS_get(this_proc_id) ); 463 } 464 465 break; 654 return true; 466 655 default: 467 656 // This makes no sense, something is wrong abort … … 470 659 } 471 660 661 void __kernel_unpark( $thread * thrd ) { 662 /* paranoid */ verify( ! __preemption_enabled() ); 663 /* paranoid */ verify( ready_schedule_islocked()); 664 665 if( !thrd ) return; 666 667 if(__must_unpark(thrd)) { 668 // Wake lost the race, 669 __schedule_thread( thrd ); 670 } 671 672 /* paranoid */ verify( ready_schedule_islocked()); 673 /* paranoid */ verify( ! __preemption_enabled() ); 674 } 675 676 void unpark( $thread * thrd ) { 677 if( !thrd ) return; 678 679 if(__must_unpark(thrd)) { 680 disable_interrupts(); 681 // Wake lost the race, 682 schedule_thread$( thrd ); 683 enable_interrupts(false); 684 } 685 } 686 472 687 void park( void ) { 473 /* paranoid */ verify( __preemption_enabled() ); 474 disable_interrupts(); 475 /* paranoid */ verify( ! __preemption_enabled() ); 476 /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION ); 477 478 returnToKernel(); 479 480 /* paranoid */ verify( ! __preemption_enabled() ); 481 enable_interrupts( __cfaabi_dbg_ctx ); 482 /* paranoid */ verify( __preemption_enabled() ); 688 __disable_interrupts_checked(); 689 /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION ); 690 returnToKernel(); 691 __enable_interrupts_checked(); 483 692 484 693 } … … 520 729 // KERNEL ONLY 521 730 bool force_yield( __Preemption_Reason reason ) { 522 /* paranoid */ verify( __preemption_enabled() ); 523 disable_interrupts(); 524 /* paranoid */ verify( ! __preemption_enabled() ); 525 526 $thread * thrd = kernelTLS().this_thread; 527 /* paranoid */ verify(thrd->state == Active); 528 529 // SKULLDUGGERY: It is possible that we are preempting this thread just before 530 // it was going to park itself. If that is the case and it is already using the 531 // intrusive fields then we can't use them to preempt the thread 532 // If that is the case, abandon the preemption. 533 bool preempted = false; 534 if(thrd->link.next == 0p) { 535 preempted = true; 536 thrd->preempted = reason; 537 returnToKernel(); 538 } 539 540 /* paranoid */ verify( ! __preemption_enabled() ); 541 enable_interrupts_noPoll(); 542 /* paranoid */ verify( __preemption_enabled() ); 543 731 __disable_interrupts_checked(); 732 $thread * thrd = kernelTLS().this_thread; 733 /* paranoid */ verify(thrd->state == Active); 734 735 // SKULLDUGGERY: It is possible that we are preempting this thread just before 736 // it was going to park itself. If that is the case and it is already using the 737 // intrusive fields then we can't use them to preempt the thread 738 // If that is the case, abandon the preemption. 739 bool preempted = false; 740 if(thrd->link.next == 0p) { 741 preempted = true; 742 thrd->preempted = reason; 743 returnToKernel(); 744 } 745 __enable_interrupts_checked( false ); 544 746 return preempted; 545 747 } … … 557 759 unsigned idle; 558 760 unsigned total; 559 [idle, total, p] = query (this->idles);761 [idle, total, p] = query_idles(this->procs); 560 762 561 763 // If no one is sleeping, we are done … … 563 765 564 766 // We found a processor, wake it up 565 post( p->idle ); 767 eventfd_t val; 768 val = 1; 769 eventfd_write( p->idle, val ); 566 770 567 771 #if !defined(__CFA_NO_STATISTICS__) 568 __tls_stats()->ready.sleep.wakes++; 772 if( kernelTLS().this_stats ) { 773 __tls_stats()->ready.sleep.wakes++; 774 } 775 else { 776 __atomic_fetch_add(&this->stats->ready.sleep.wakes, 1, __ATOMIC_RELAXED); 777 } 569 778 #endif 570 779 … … 579 788 __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this); 580 789 581 disable_interrupts();790 __disable_interrupts_checked(); 582 791 /* paranoid */ verify( ! __preemption_enabled() ); 583 post( this->idle ); 584 enable_interrupts( __cfaabi_dbg_ctx ); 585 } 586 587 static void push (__cluster_idles & this, processor & proc) { 792 eventfd_t val; 793 val = 1; 794 eventfd_write( this->idle, val ); 795 __enable_interrupts_checked(); 796 } 797 798 static void mark_idle(__cluster_proc_list & this, processor & proc) { 588 799 /* paranoid */ verify( ! __preemption_enabled() ); 589 800 lock( this ); 590 801 this.idle++; 591 802 /* paranoid */ verify( this.idle <= this.total ); 592 593 insert_first(this. list, proc);803 remove(proc); 804 insert_first(this.idles, proc); 594 805 unlock( this ); 595 806 /* paranoid */ verify( ! __preemption_enabled() ); 596 807 } 597 808 598 static void remove(__cluster_idles& this, processor & proc) {809 static void mark_awake(__cluster_proc_list & this, processor & proc) { 599 810 /* paranoid */ verify( ! __preemption_enabled() ); 600 811 lock( this ); 601 812 this.idle--; 602 813 /* paranoid */ verify( this.idle >= 0 ); 603 604 814 remove(proc); 815 insert_last(this.actives, proc); 605 816 unlock( this ); 606 817 /* paranoid */ verify( ! __preemption_enabled() ); 607 818 } 608 819 609 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) { 820 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list this ) { 821 /* paranoid */ verify( ! __preemption_enabled() ); 822 /* paranoid */ verify( ready_schedule_islocked() ); 823 610 824 for() { 611 825 uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST); … … 613 827 unsigned idle = this.idle; 614 828 unsigned total = this.total; 615 processor * proc = &this. list`first;829 processor * proc = &this.idles`first; 616 830 // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it 617 831 asm volatile("": : :"memory"); … … 619 833 return [idle, total, proc]; 620 834 } 835 836 /* paranoid */ verify( ready_schedule_islocked() ); 837 /* paranoid */ verify( ! __preemption_enabled() ); 621 838 } 622 839 … … 664 881 // Kernel Utilities 665 882 //============================================================================================= 883 #if defined(CFA_HAVE_LINUX_IO_URING_H) 884 #include "io/types.hfa" 885 #endif 886 887 static inline bool __maybe_io_drain( processor * proc ) { 888 bool ret = false; 889 #if defined(CFA_HAVE_LINUX_IO_URING_H) 890 __cfadbg_print_safe(runtime_core, "Kernel : core %p checking io for ring %d\n", proc, proc->io.ctx->fd); 891 892 // Check if we should drain the queue 893 $io_context * ctx = proc->io.ctx; 894 unsigned head = *ctx->cq.head; 895 unsigned tail = *ctx->cq.tail; 896 if(head == tail) return false; 897 ready_schedule_lock(); 898 ret = __cfa_io_drain( proc ); 899 ready_schedule_unlock(); 900 #endif 901 return ret; 902 } 903 666 904 //----------------------------------------------------------------------------- 667 905 // Debug … … 691 929 __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this ); 692 930 } 693 694 extern int __print_alarm_stats;695 void print_alarm_stats() {696 __print_alarm_stats = -1;697 }698 931 #endif 699 932 // Local Variables: // -
libcfa/src/concurrency/kernel.hfa
rfeacef9 r5407cdc 28 28 } 29 29 30 //-----------------------------------------------------------------------------31 // Underlying Locks32 30 #ifdef __CFA_WITH_VERIFY__ 33 31 extern bool __cfaabi_dbg_in_kernel(); 34 32 #endif 35 33 36 extern "C" { 37 char * strerror(int); 38 } 39 #define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); } 40 41 struct __bin_sem_t { 42 pthread_mutex_t lock; 43 pthread_cond_t cond; 44 int val; 45 }; 46 47 static inline void ?{}(__bin_sem_t & this) with( this ) { 48 // Create the mutex with error checking 49 pthread_mutexattr_t mattr; 50 pthread_mutexattr_init( &mattr ); 51 pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP); 52 pthread_mutex_init(&lock, &mattr); 53 54 pthread_cond_init (&cond, (const pthread_condattr_t *)0p); // workaround trac#208: cast should not be required 55 val = 0; 56 } 57 58 static inline void ^?{}(__bin_sem_t & this) with( this ) { 59 CHECKED( pthread_mutex_destroy(&lock) ); 60 CHECKED( pthread_cond_destroy (&cond) ); 61 } 62 63 static inline void wait(__bin_sem_t & this) with( this ) { 64 verify(__cfaabi_dbg_in_kernel()); 65 CHECKED( pthread_mutex_lock(&lock) ); 66 while(val < 1) { 67 pthread_cond_wait(&cond, &lock); 68 } 69 val -= 1; 70 CHECKED( pthread_mutex_unlock(&lock) ); 71 } 72 73 static inline bool post(__bin_sem_t & this) with( this ) { 74 bool needs_signal = false; 75 76 CHECKED( pthread_mutex_lock(&lock) ); 77 if(val < 1) { 78 val += 1; 79 pthread_cond_signal(&cond); 80 needs_signal = true; 81 } 82 CHECKED( pthread_mutex_unlock(&lock) ); 83 84 return needs_signal; 85 } 86 87 #undef CHECKED 88 34 //----------------------------------------------------------------------------- 35 // I/O 36 struct cluster; 37 struct $io_context; 38 struct $io_arbiter; 39 40 struct io_context_params { 41 int num_entries; 42 }; 43 44 void ?{}(io_context_params & this); 89 45 90 46 //----------------------------------------------------------------------------- … … 95 51 struct __processor_id_t { 96 52 unsigned id:24; 97 bool full_proc:1;98 53 99 54 #if !defined(__CFA_NO_STATISTICS__) … … 114 69 struct cluster * cltr; 115 70 71 // Ready Queue state per processor 72 struct { 73 unsigned short its; 74 unsigned short itr; 75 unsigned id; 76 unsigned target; 77 unsigned long long int cutoff; 78 } rdq; 79 116 80 // Set to true to notify the processor should terminate 117 81 volatile bool do_terminate; … … 125 89 // Handle to pthreads 126 90 pthread_t kernel_thread; 91 92 struct { 93 $io_context * ctx; 94 bool pending; 95 bool dirty; 96 } io; 127 97 128 98 // Preemption data … … 134 104 135 105 // Idle lock (kernel semaphore) 136 __bin_sem_t idle;106 int idle; 137 107 138 108 // Termination synchronisation (user semaphore) … … 144 114 // Link lists fields 145 115 DLISTED_MGD_IMPL_IN(processor) 116 117 // special init fields 118 // This is needed for memcached integration 119 // once memcached experiments are done this should probably be removed 120 // it is not a particularly safe scheme as it can make processors less homogeneous 121 struct { 122 $thread * thrd; 123 } init; 146 124 147 125 #if !defined(__CFA_NO_STATISTICS__) … … 159 137 void ^?{}(processor & this); 160 138 161 static inline void ?{}(processor & this) { this{ "Anonymous Processor", *mainCluster}; }162 static inline void ?{}(processor & this, struct cluster & cltr) 163 static inline void ?{}(processor & this, const char name[]) { this{name, *mainCluster}; }139 static inline void ?{}(processor & this) { this{ "Anonymous Processor", *mainCluster}; } 140 static inline void ?{}(processor & this, struct cluster & cltr) { this{ "Anonymous Processor", cltr}; } 141 static inline void ?{}(processor & this, const char name[]) { this{name, *mainCluster}; } 164 142 165 143 DLISTED_MGD_IMPL_OUT(processor) 166 144 167 145 //----------------------------------------------------------------------------- 168 // I/O169 struct __io_data;170 171 // IO poller user-thread172 // Not using the "thread" keyword because we want to control173 // more carefully when to start/stop it174 struct $io_ctx_thread {175 struct __io_data * ring;176 single_sem sem;177 volatile bool done;178 $thread self;179 };180 181 182 struct io_context {183 $io_ctx_thread thrd;184 };185 186 struct io_context_params {187 int num_entries;188 int num_ready;189 int submit_aff;190 bool eager_submits:1;191 bool poller_submits:1;192 bool poll_submit:1;193 bool poll_complete:1;194 };195 196 void ?{}(io_context_params & this);197 198 void ?{}(io_context & this, struct cluster & cl);199 void ?{}(io_context & this, struct cluster & cl, const io_context_params & params);200 void ^?{}(io_context & this);201 202 struct io_cancellation {203 __u64 target;204 };205 206 static inline void ?{}(io_cancellation & this) { this.target = -1u; }207 static inline void ^?{}(io_cancellation &) {}208 bool cancel(io_cancellation & this);209 210 //-----------------------------------------------------------------------------211 146 // Cluster Tools 212 147 213 // Intrusives lanes which are used by the re laxed ready queue148 // Intrusives lanes which are used by the ready queue 214 149 struct __attribute__((aligned(128))) __intrusive_lane_t; 215 150 void ?{}(__intrusive_lane_t & this); 216 151 void ^?{}(__intrusive_lane_t & this); 217 152 218 // Counter used for wether or not the lanes are all empty 219 struct __attribute__((aligned(128))) __snzi_node_t; 220 struct __snzi_t { 221 unsigned mask; 222 int root; 223 __snzi_node_t * nodes; 224 }; 225 226 void ?{}( __snzi_t & this, unsigned depth ); 227 void ^?{}( __snzi_t & this ); 153 // Aligned timestamps which are used by the relaxed ready queue 154 struct __attribute__((aligned(128))) __timestamp_t; 155 void ?{}(__timestamp_t & this); 156 void ^?{}(__timestamp_t & this); 228 157 229 158 //TODO adjust cache size to ARCHITECTURE 230 159 // Structure holding the relaxed ready queue 231 160 struct __ready_queue_t { 232 // Data tracking how many/which lanes are used233 // Aligned to 128 for cache locality234 __snzi_t snzi;235 236 161 // Data tracking the actual lanes 237 162 // On a seperate cacheline from the used struct since … … 242 167 __intrusive_lane_t * volatile data; 243 168 169 // Array of times 170 __timestamp_t * volatile tscs; 171 244 172 // Number of lanes (empty or not) 245 173 volatile size_t count; … … 251 179 252 180 // Idle Sleep 253 struct __cluster_ idles{181 struct __cluster_proc_list { 254 182 // Spin lock protecting the queue 255 183 volatile uint64_t lock; … … 262 190 263 191 // List of idle processors 264 dlist(processor, processor) list; 192 dlist(processor, processor) idles; 193 194 // List of active processors 195 dlist(processor, processor) actives; 265 196 }; 266 197 … … 278 209 279 210 // List of idle processors 280 __cluster_ idles idles;211 __cluster_proc_list procs; 281 212 282 213 // List of threads … … 292 223 293 224 struct { 294 io_context * ctxs;295 unsigned cnt;225 $io_arbiter * arbiter; 226 io_context_params params; 296 227 } io; 297 228 -
libcfa/src/concurrency/kernel/fwd.hfa
rfeacef9 r5407cdc 108 108 109 109 extern void disable_interrupts(); 110 extern void enable_interrupts_noPoll(); 111 extern void enable_interrupts( __cfaabi_dbg_ctx_param ); 110 extern void enable_interrupts( bool poll = false ); 112 111 113 112 extern "Cforall" { … … 220 219 // Mark as fulfilled, wake thread if needed 221 220 // return true if a thread was unparked 222 bool post(oneshot & this) {221 $thread * post(oneshot & this, bool do_unpark = true) { 223 222 struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST); 224 if( got == 0p ) return false;225 unpark( got );226 return true;223 if( got == 0p ) return 0p; 224 if(do_unpark) unpark( got ); 225 return got; 227 226 } 228 227 } … … 336 335 // from the server side, mark the future as fulfilled 337 336 // delete it if needed 338 bool fulfil( future_t & this) {337 $thread * fulfil( future_t & this, bool do_unpark = true ) { 339 338 for() { 340 339 struct oneshot * expected = this.ptr; … … 344 343 #pragma GCC diagnostic ignored "-Wfree-nonheap-object" 345 344 #endif 346 if( expected == 3p ) { free( &this ); return false; }345 if( expected == 3p ) { free( &this ); return 0p; } 347 346 #if defined(__GNUC__) && __GNUC__ >= 7 348 347 #pragma GCC diagnostic pop … … 356 355 struct oneshot * want = expected == 0p ? 1p : 2p; 357 356 if(__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 358 if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return false; }359 bool ret = post( *expected);357 if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return 0p; } 358 $thread * ret = post( *expected, do_unpark ); 360 359 __atomic_store_n( &this.ptr, 1p, __ATOMIC_SEQ_CST); 361 360 return ret; … … 403 402 __VA_ARGS__ \ 404 403 } \ 405 if( !(in_kernel) ) enable_interrupts( __cfaabi_dbg_ctx); \404 if( !(in_kernel) ) enable_interrupts(); \ 406 405 } 407 406 #else -
libcfa/src/concurrency/kernel/startup.cfa
rfeacef9 r5407cdc 22 22 extern "C" { 23 23 #include <limits.h> // PTHREAD_STACK_MIN 24 #include <sys/eventfd.h> // eventfd 24 25 #include <sys/mman.h> // mprotect 25 26 #include <sys/resource.h> // getrlimit … … 72 73 static void __kernel_first_resume( processor * this ); 73 74 static void __kernel_last_resume ( processor * this ); 74 static void init(processor & this, const char name[], cluster & _cltr );75 static void init(processor & this, const char name[], cluster & _cltr, $thread * initT); 75 76 static void deinit(processor & this); 76 77 static void doregister( struct cluster & cltr ); … … 89 90 extern void __kernel_alarm_startup(void); 90 91 extern void __kernel_alarm_shutdown(void); 91 extern void __kernel_io_startup (void);92 extern void __kernel_io_shutdown(void);93 92 94 93 //----------------------------------------------------------------------------- … … 102 101 KERNEL_STORAGE($thread, mainThread); 103 102 KERNEL_STORAGE(__stack_t, mainThreadCtx); 104 KERNEL_STORAGE(io_context, mainPollerThread);105 103 KERNEL_STORAGE(__scheduler_RWLock_t, __scheduler_lock); 106 104 #if !defined(__CFA_NO_STATISTICS__) … … 198 196 199 197 void ?{}(processor & this) with( this ) { 200 ( this.idle ){};201 198 ( this.terminated ){}; 202 199 ( this.runner ){}; 203 init( this, "Main Processor", *mainCluster );200 init( this, "Main Processor", *mainCluster, 0p ); 204 201 kernel_thread = pthread_self(); 205 202 … … 226 223 __kernel_alarm_startup(); 227 224 228 // Start IO229 __kernel_io_startup();230 231 225 // Add the main thread to the ready queue 232 226 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread 233 __schedule_thread(mainThread);227 schedule_thread$(mainThread); 234 228 235 229 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX … … 241 235 // THE SYSTEM IS NOW COMPLETELY RUNNING 242 236 243 244 // SKULLDUGGERY: The constructor for the mainCluster will call alloc with a dimension of 0245 // malloc *can* return a non-null value, we should free it if that is the case246 free( mainCluster->io.ctxs );247 248 // Now that the system is up, finish creating systems that need threading249 mainCluster->io.ctxs = (io_context *)&storage_mainPollerThread;250 mainCluster->io.cnt = 1;251 (*mainCluster->io.ctxs){ *mainCluster };252 253 237 __cfadbg_print_safe(runtime_core, "Kernel : Started\n--------------------------------------------------\n\n"); 254 238 255 239 /* paranoid */ verify( ! __preemption_enabled() ); 256 enable_interrupts( __cfaabi_dbg_ctx);240 enable_interrupts(); 257 241 /* paranoid */ verify( __preemption_enabled() ); 258 242 … … 260 244 261 245 static void __kernel_shutdown(void) { 262 //Before we start shutting things down, wait for systems that need threading to shutdown263 ^(*mainCluster->io.ctxs){};264 mainCluster->io.cnt = 0;265 mainCluster->io.ctxs = 0p;266 267 246 /* paranoid */ verify( __preemption_enabled() ); 268 247 disable_interrupts(); … … 283 262 __kernel_alarm_shutdown(); 284 263 285 // Stop IO 286 __kernel_io_shutdown(); 264 #if !defined( __CFA_NO_STATISTICS__ ) 265 __stats_t * st = (__stats_t *)& storage_mainProcStats; 266 __tally_stats(mainCluster->stats, st); 267 if( 0 != mainProcessor->print_stats ) { 268 __print_stats( st, mainProcessor->print_stats, "Processor ", mainProcessor->name, (void*)mainProcessor ); 269 } 270 #if defined(CFA_STATS_ARRAY) 271 __flush_stat( st, "Processor", mainProcessor ); 272 #endif 273 #endif 287 274 288 275 // Destroy the main processor and its context in reverse order of construction … … 364 351 __print_stats( &local_stats, proc->print_stats, "Processor ", proc->name, (void*)proc ); 365 352 } 353 #if defined(CFA_STATS_ARRAY) 354 __flush_stat( &local_stats, "Processor", proc ); 355 #endif 366 356 #endif 367 357 … … 457 447 link.next = 0p; 458 448 link.prev = 0p; 449 link.preferred = -1u; 450 last_proc = 0p; 459 451 #if defined( __CFA_WITH_VERIFY__ ) 460 452 canary = 0x0D15EA5E0D15EA5Ep; … … 476 468 } 477 469 478 static void init(processor & this, const char name[], cluster & _cltr ) with( this ) {470 static void init(processor & this, const char name[], cluster & _cltr, $thread * initT) with( this ) { 479 471 this.name = name; 480 472 this.cltr = &_cltr; 481 full_proc = true; 473 this.rdq.its = 0; 474 this.rdq.itr = 0; 475 this.rdq.id = -1u; 476 this.rdq.target = -1u; 477 this.rdq.cutoff = -1ull; 482 478 do_terminate = false; 483 479 preemption_alarm = 0p; 484 480 pending_preemption = false; 485 481 482 this.io.ctx = 0p; 483 this.io.pending = false; 484 this.io.dirty = false; 485 486 this.init.thrd = initT; 487 488 this.idle = eventfd(0, 0); 489 if (idle < 0) { 490 abort("KERNEL ERROR: PROCESSOR EVENTFD - %s\n", strerror(errno)); 491 } 492 486 493 #if !defined(__CFA_NO_STATISTICS__) 487 494 print_stats = 0; … … 489 496 #endif 490 497 491 lock( this.cltr->idles ); 492 int target = this.cltr->idles.total += 1u; 493 unlock( this.cltr->idles ); 494 495 id = doregister((__processor_id_t*)&this); 496 498 // Register and Lock the RWlock so no-one pushes/pops while we are changing the queue 499 uint_fast32_t last_size = ready_mutate_register((__processor_id_t*)&this); 500 this.cltr->procs.total += 1u; 501 insert_last(this.cltr->procs.actives, this); 502 503 // Adjust the ready queue size 504 ready_queue_grow( cltr ); 505 506 // Unlock the RWlock 507 ready_mutate_unlock( last_size ); 508 509 __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this); 510 } 511 512 // Not a ctor, it just preps the destruction but should not destroy members 513 static void deinit(processor & this) { 497 514 // Lock the RWlock so no-one pushes/pops while we are changing the queue 498 515 uint_fast32_t last_size = ready_mutate_lock(); 516 this.cltr->procs.total -= 1u; 517 remove(this); 499 518 500 519 // Adjust the ready queue size 501 ready_queue_grow( cltr, target ); 502 503 // Unlock the RWlock 504 ready_mutate_unlock( last_size ); 505 506 __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this); 507 } 508 509 // Not a ctor, it just preps the destruction but should not destroy members 510 static void deinit(processor & this) { 511 lock( this.cltr->idles ); 512 int target = this.cltr->idles.total -= 1u; 513 unlock( this.cltr->idles ); 514 515 // Lock the RWlock so no-one pushes/pops while we are changing the queue 516 uint_fast32_t last_size = ready_mutate_lock(); 517 518 // Adjust the ready queue size 519 ready_queue_shrink( this.cltr, target ); 520 521 // Unlock the RWlock 522 ready_mutate_unlock( last_size ); 523 524 // Finally we don't need the read_lock any more 525 unregister((__processor_id_t*)&this); 526 } 527 528 void ?{}(processor & this, const char name[], cluster & _cltr) { 529 ( this.idle ){}; 520 ready_queue_shrink( this.cltr ); 521 522 // Unlock the RWlock and unregister: we don't need the read_lock any more 523 ready_mutate_unregister((__processor_id_t*)&this, last_size ); 524 525 close(this.idle); 526 } 527 528 void ?{}(processor & this, const char name[], cluster & _cltr, $thread * initT) { 530 529 ( this.terminated ){}; 531 530 ( this.runner ){}; 532 531 533 532 disable_interrupts(); 534 init( this, name, _cltr );535 enable_interrupts( __cfaabi_dbg_ctx);533 init( this, name, _cltr, initT ); 534 enable_interrupts(); 536 535 537 536 __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this); 538 537 539 538 this.stack = __create_pthread( &this.kernel_thread, __invoke_processor, (void *)&this ); 540 539 } 540 541 void ?{}(processor & this, const char name[], cluster & _cltr) { 542 (this){name, _cltr, 0p}; 541 543 } 542 544 … … 557 559 disable_interrupts(); 558 560 deinit( this ); 559 enable_interrupts( __cfaabi_dbg_ctx);561 enable_interrupts(); 560 562 } 561 563 562 564 //----------------------------------------------------------------------------- 563 565 // Cluster 564 static void ?{}(__cluster_ idles& this) {566 static void ?{}(__cluster_proc_list & this) { 565 567 this.lock = 0; 566 568 this.idle = 0; 567 569 this.total = 0; 568 (this.list){};569 570 } 570 571 … … 582 583 threads{ __get }; 583 584 585 io.arbiter = create(); 586 io.params = io_params; 587 584 588 doregister(this); 585 589 … … 589 593 590 594 // Adjust the ready queue size 591 ready_queue_grow( &this , 0);595 ready_queue_grow( &this ); 592 596 593 597 // Unlock the RWlock 594 598 ready_mutate_unlock( last_size ); 595 enable_interrupts_noPoll(); // Don't poll, could be in main cluster 596 597 598 this.io.cnt = num_io; 599 this.io.ctxs = aalloc(num_io); 600 for(i; this.io.cnt) { 601 (this.io.ctxs[i]){ this, io_params }; 602 } 599 enable_interrupts( false ); // Don't poll, could be in main cluster 603 600 } 604 601 605 602 void ^?{}(cluster & this) { 606 for(i; this.io.cnt) { 607 ^(this.io.ctxs[i]){ true }; 608 } 609 free(this.io.ctxs); 603 destroy(this.io.arbiter); 610 604 611 605 // Lock the RWlock so no-one pushes/pops while we are changing the queue … … 614 608 615 609 // Adjust the ready queue size 616 ready_queue_shrink( &this , 0);610 ready_queue_shrink( &this ); 617 611 618 612 // Unlock the RWlock 619 613 ready_mutate_unlock( last_size ); 620 enable_interrupts _noPoll(); // Don't poll, could be in main cluster614 enable_interrupts( false ); // Don't poll, could be in main cluster 621 615 622 616 #if !defined(__CFA_NO_STATISTICS__) … … 624 618 __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this ); 625 619 } 620 #if defined(CFA_STATS_ARRAY) 621 __flush_stat( this.stats, "Cluster", &this ); 622 #endif 626 623 free( this.stats ); 627 624 #endif … … 736 733 } 737 734 738 739 735 #if defined(__CFA_WITH_VERIFY__) 740 736 static bool verify_fwd_bck_rng(void) { -
libcfa/src/concurrency/kernel_private.hfa
rfeacef9 r5407cdc 29 29 extern "C" { 30 30 void disable_interrupts() OPTIONAL_THREAD; 31 void enable_interrupts_noPoll(); 32 void enable_interrupts( __cfaabi_dbg_ctx_param ); 33 } 34 35 void __schedule_thread( $thread * ) 36 #if defined(NDEBUG) || (!defined(__CFA_DEBUG__) && !defined(__CFA_VERIFY__)) 37 __attribute__((nonnull (1))) 38 #endif 39 ; 31 void enable_interrupts( bool poll = true ); 32 } 33 34 void schedule_thread$( $thread * ) __attribute__((nonnull (1))); 40 35 41 36 extern bool __preemption_enabled(); … … 77 72 //----------------------------------------------------------------------------- 78 73 // I/O 79 void ^?{}(io_context & this, bool ); 74 $io_arbiter * create(void); 75 void destroy($io_arbiter *); 80 76 81 77 //======================================================================= 82 78 // Cluster lock API 83 79 //======================================================================= 84 // Cells use by the reader writer lock85 // while not generic it only relies on a opaque pointer86 struct __attribute__((aligned(128))) __scheduler_lock_id_t {87 // Spin lock used as the underlying lock88 volatile bool lock;89 90 // Handle pointing to the proc owning this cell91 // Used for allocating cells and debugging92 __processor_id_t * volatile handle;93 94 #ifdef __CFA_WITH_VERIFY__95 // Debug, check if this is owned for reading96 bool owned;97 #endif98 };99 100 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));101 102 80 // Lock-Free registering/unregistering of threads 103 81 // Register a processor to a given cluster and get its unique id in return 104 unsigned doregister( struct __processor_id_t * proc);82 void register_proc_id( struct __processor_id_t * ); 105 83 106 84 // Unregister a processor from a given cluster using its id, getting back the original pointer 107 void unregister( struct __processor_id_t * proc ); 108 109 //----------------------------------------------------------------------- 110 // Cluster idle lock/unlock 111 static inline void lock(__cluster_idles & this) { 112 for() { 113 uint64_t l = this.lock; 114 if( 115 (0 == (l % 2)) 116 && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) 117 ) return; 118 Pause(); 119 } 120 } 121 122 static inline void unlock(__cluster_idles & this) { 123 /* paranoid */ verify( 1 == (this.lock % 2) ); 124 __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST ); 125 } 85 void unregister_proc_id( struct __processor_id_t * proc ); 126 86 127 87 //======================================================================= … … 151 111 __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE); 152 112 } 113 114 // Cells use by the reader writer lock 115 // while not generic it only relies on a opaque pointer 116 struct __attribute__((aligned(128))) __scheduler_lock_id_t { 117 // Spin lock used as the underlying lock 118 volatile bool lock; 119 120 // Handle pointing to the proc owning this cell 121 // Used for allocating cells and debugging 122 __processor_id_t * volatile handle; 123 124 #ifdef __CFA_WITH_VERIFY__ 125 // Debug, check if this is owned for reading 126 bool owned; 127 #endif 128 }; 129 130 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t)); 153 131 154 132 //----------------------------------------------------------------------- … … 246 224 void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ ); 247 225 226 //----------------------------------------------------------------------- 227 // Lock-Free registering/unregistering of threads 228 // Register a processor to a given cluster and get its unique id in return 229 // For convenience, also acquires the lock 230 static inline uint_fast32_t ready_mutate_register( struct __processor_id_t * proc ) { 231 register_proc_id( proc ); 232 return ready_mutate_lock(); 233 } 234 235 // Unregister a processor from a given cluster using its id, getting back the original pointer 236 // assumes the lock is acquired 237 static inline void ready_mutate_unregister( struct __processor_id_t * proc, uint_fast32_t last_s ) { 238 ready_mutate_unlock( last_s ); 239 unregister_proc_id( proc ); 240 } 241 242 //----------------------------------------------------------------------- 243 // Cluster idle lock/unlock 244 static inline void lock(__cluster_proc_list & this) { 245 /* paranoid */ verify( ! __preemption_enabled() ); 246 247 // Start by locking the global RWlock so that we know no-one is 248 // adding/removing processors while we mess with the idle lock 249 ready_schedule_lock(); 250 251 // Simple counting lock, acquired, acquired by incrementing the counter 252 // to an odd number 253 for() { 254 uint64_t l = this.lock; 255 if( 256 (0 == (l % 2)) 257 && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) 258 ) return; 259 Pause(); 260 } 261 262 /* paranoid */ verify( ! __preemption_enabled() ); 263 } 264 265 static inline void unlock(__cluster_proc_list & this) { 266 /* paranoid */ verify( ! __preemption_enabled() ); 267 268 /* paranoid */ verify( 1 == (this.lock % 2) ); 269 // Simple couting lock, release by incrementing to an even number 270 __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST ); 271 272 // Release the global lock, which we acquired when locking 273 ready_schedule_unlock(); 274 275 /* paranoid */ verify( ! __preemption_enabled() ); 276 } 277 248 278 //======================================================================= 249 279 // Ready-Queue API 250 280 //----------------------------------------------------------------------- 251 // pop thread from the ready queue of a cluster252 // returns 0p if empty253 __attribute__((hot)) bool query(struct cluster * cltr);254 255 //-----------------------------------------------------------------------256 281 // push thread onto a ready queue for a cluster 257 282 // returns true if the list was previously empty, false otherwise 258 __attribute__((hot)) boolpush(struct cluster * cltr, struct $thread * thrd);259 260 //----------------------------------------------------------------------- 261 // pop thread from the ready queueof a cluster283 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd); 284 285 //----------------------------------------------------------------------- 286 // pop thread from the local queues of a cluster 262 287 // returns 0p if empty 263 288 // May return 0p spuriously 264 __attribute__((hot)) struct $thread * pop(struct cluster * cltr); 265 266 //----------------------------------------------------------------------- 267 // pop thread from the ready queue of a cluster 289 __attribute__((hot)) struct $thread * pop_fast(struct cluster * cltr); 290 291 //----------------------------------------------------------------------- 292 // pop thread from any ready queue of a cluster 293 // returns 0p if empty 294 // May return 0p spuriously 295 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr); 296 297 //----------------------------------------------------------------------- 298 // search all ready queues of a cluster for any thread 268 299 // returns 0p if empty 269 300 // guaranteed to find any threads added before this call 270 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr); 271 272 //----------------------------------------------------------------------- 273 // remove thread from the ready queue of a cluster 274 // returns bool if it wasn't found 275 bool remove_head(struct cluster * cltr, struct $thread * thrd); 301 __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr); 276 302 277 303 //----------------------------------------------------------------------- 278 304 // Increase the width of the ready queue (number of lanes) by 4 279 void ready_queue_grow (struct cluster * cltr , int target);305 void ready_queue_grow (struct cluster * cltr); 280 306 281 307 //----------------------------------------------------------------------- 282 308 // Decrease the width of the ready queue (number of lanes) by 4 283 void ready_queue_shrink(struct cluster * cltr , int target);309 void ready_queue_shrink(struct cluster * cltr); 284 310 285 311 -
libcfa/src/concurrency/locks.cfa
rfeacef9 r5407cdc 134 134 lock( lock __cfaabi_dbg_ctx2 ); 135 135 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); 136 /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 136 /* paranoid */ verifyf( owner == active_thread() || !strict_owner , "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 137 /* paranoid */ verifyf( recursion_count == 1 || multi_acquisition, "Thread %p attempted to release owner lock %p which is not recursive but has a recursive count of %zu", active_thread(), &this, recursion_count ); 137 138 138 139 // if recursion count is zero release lock and set new owner if one is waiting … … 146 147 size_t wait_count( blocking_lock & this ) with( this ) { 147 148 return wait_count; 148 }149 150 void set_recursion_count( blocking_lock & this, size_t recursion ) with( this ) {151 recursion_count = recursion;152 }153 154 size_t get_recursion_count( blocking_lock & this ) with( this ) {155 return recursion_count;156 149 } 157 150 … … 173 166 } 174 167 175 voidon_wait( blocking_lock & this ) with( this ) {168 size_t on_wait( blocking_lock & this ) with( this ) { 176 169 lock( lock __cfaabi_dbg_ctx2 ); 177 170 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); 178 171 /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 179 172 173 size_t ret = recursion_count; 174 180 175 pop_and_set_new_owner( this ); 181 176 unlock( lock ); 177 return ret; 178 } 179 180 void on_wakeup( blocking_lock & this, size_t recursion ) with( this ) { 181 recursion_count = recursion; 182 182 } 183 183 … … 274 274 } 275 275 276 bool empty( condition_variable(L) & this ) with(this) { return empty(blocked_threads); } 276 bool empty( condition_variable(L) & this ) with(this) { 277 lock( lock __cfaabi_dbg_ctx2 ); 278 bool ret = empty(blocked_threads); 279 unlock( lock ); 280 return ret; 281 } 277 282 278 283 int counter( condition_variable(L) & this ) with(this) { return count; } … … 285 290 if (i->lock) { 286 291 // if lock was passed get recursion count to reset to after waking thread 287 recursion_count = get_recursion_count(*i->lock); 288 on_wait( *i->lock ); 292 recursion_count = on_wait( *i->lock ); 289 293 } 290 294 return recursion_count; … … 301 305 302 306 // resets recursion count here after waking 303 if (i.lock) set_recursion_count(*i.lock, recursion_count);307 if (i.lock) on_wakeup(*i.lock, recursion_count); 304 308 } 305 309 … … 323 327 324 328 // resets recursion count here after waking 325 if (info.lock) set_recursion_count(*info.lock, recursion_count);329 if (info.lock) on_wakeup(*info.lock, recursion_count); 326 330 } 327 331 … … 373 377 } 374 378 375 bool V(semaphore & this) with( this ) {379 $thread * V (semaphore & this, const bool doUnpark ) with( this ) { 376 380 $thread * thrd = 0p; 377 381 lock( lock __cfaabi_dbg_ctx2 ); … … 385 389 386 390 // make new owner 387 unpark( thrd ); 388 391 if( doUnpark ) unpark( thrd ); 392 393 return thrd; 394 } 395 396 bool V(semaphore & this) with( this ) { 397 $thread * thrd = V(this, true); 389 398 return thrd != 0p; 390 399 } -
libcfa/src/concurrency/locks.hfa
rfeacef9 r5407cdc 20 20 21 21 #include "bits/weakso_locks.hfa" 22 #include "containers/queueLockFree.hfa" 23 24 #include "thread.hfa" 22 25 23 26 #include "time_t.hfa" 24 27 #include "time.hfa" 28 29 //----------------------------------------------------------------------------- 30 // Semaphores 31 32 // '0-nary' semaphore 33 // Similar to a counting semaphore except the value of one is never reached 34 // as a consequence, a V() that would bring the value to 1 *spins* until 35 // a P consumes it 36 struct Semaphore0nary { 37 __spinlock_t lock; // needed to protect 38 mpsc_queue($thread) queue; 39 }; 40 41 static inline bool P(Semaphore0nary & this, $thread * thrd) { 42 /* paranoid */ verify(!(thrd->seqable.next)); 43 /* paranoid */ verify(!(thrd`next)); 44 45 push(this.queue, thrd); 46 return true; 47 } 48 49 static inline bool P(Semaphore0nary & this) { 50 $thread * thrd = active_thread(); 51 P(this, thrd); 52 park(); 53 return true; 54 } 55 56 static inline $thread * V(Semaphore0nary & this, bool doUnpark = true) { 57 $thread * next; 58 lock(this.lock __cfaabi_dbg_ctx2); 59 for (;;) { 60 next = pop(this.queue); 61 if (next) break; 62 Pause(); 63 } 64 unlock(this.lock); 65 66 if (doUnpark) unpark(next); 67 return next; 68 } 69 70 // Wrapper used on top of any sempahore to avoid potential locking 71 struct BinaryBenaphore { 72 volatile ssize_t counter; 73 }; 74 75 static inline { 76 void ?{}(BinaryBenaphore & this) { this.counter = 0; } 77 void ?{}(BinaryBenaphore & this, zero_t) { this.counter = 0; } 78 void ?{}(BinaryBenaphore & this, one_t ) { this.counter = 1; } 79 80 // returns true if no blocking needed 81 bool P(BinaryBenaphore & this) { 82 return __atomic_fetch_sub(&this.counter, 1, __ATOMIC_SEQ_CST) > 0; 83 } 84 85 bool tryP(BinaryBenaphore & this) { 86 ssize_t c = this.counter; 87 return (c >= 1) && __atomic_compare_exchange_n(&this.counter, &c, c-1, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); 88 } 89 90 // returns true if notify needed 91 bool V(BinaryBenaphore & this) { 92 ssize_t c = 0; 93 for () { 94 if (__atomic_compare_exchange_n(&this.counter, &c, c+1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 95 if (c == 0) return true; 96 /* paranoid */ verify(c < 0); 97 return false; 98 } else { 99 if (c == 1) return true; 100 /* paranoid */ verify(c < 1); 101 Pause(); 102 } 103 } 104 } 105 } 106 107 // Binary Semaphore based on the BinaryBenaphore on top of the 0-nary Semaphore 108 struct ThreadBenaphore { 109 BinaryBenaphore ben; 110 Semaphore0nary sem; 111 }; 112 113 static inline void ?{}(ThreadBenaphore & this) {} 114 static inline void ?{}(ThreadBenaphore & this, zero_t) { (this.ben){ 0 }; } 115 static inline void ?{}(ThreadBenaphore & this, one_t ) { (this.ben){ 1 }; } 116 117 static inline bool P(ThreadBenaphore & this) { return P(this.ben) ? false : P(this.sem); } 118 static inline bool tryP(ThreadBenaphore & this) { return tryP(this.ben); } 119 static inline bool P(ThreadBenaphore & this, bool wait) { return wait ? P(this) : tryP(this); } 120 121 static inline $thread * V(ThreadBenaphore & this, bool doUnpark = true) { 122 if (V(this.ben)) return 0p; 123 return V(this.sem, doUnpark); 124 } 125 126 //----------------------------------------------------------------------------- 127 // Semaphore 128 struct semaphore { 129 __spinlock_t lock; 130 int count; 131 __queue_t($thread) waiting; 132 }; 133 134 void ?{}(semaphore & this, int count = 1); 135 void ^?{}(semaphore & this); 136 bool P (semaphore & this); 137 bool V (semaphore & this); 138 bool V (semaphore & this, unsigned count); 139 $thread * V (semaphore & this, bool ); 25 140 26 141 //---------- … … 31 146 static inline void ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };} 32 147 static inline void ^?{}( single_acquisition_lock & this ) {} 33 static inline void lock ( single_acquisition_lock & this ) { lock( (blocking_lock &)this ); }34 static inline void unlock ( single_acquisition_lock & this ) { unlock( (blocking_lock &)this ); }35 static inline void on_wait ( single_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); }36 static inline void on_notify ( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t); }37 static inline void set_recursion_count( single_acquisition_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion); }38 static inline size_t get_recursion_count( single_acquisition_lock & this ) { return get_recursion_count( (blocking_lock &)this); }148 static inline void lock ( single_acquisition_lock & this ) { lock ( (blocking_lock &)this ); } 149 static inline bool try_lock ( single_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); } 150 static inline void unlock ( single_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); } 151 static inline size_t on_wait ( single_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); } 152 static inline void on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 153 static inline void on_notify( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); } 39 154 40 155 //---------- … … 45 160 static inline void ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };} 46 161 static inline void ^?{}( owner_lock & this ) {} 47 static inline void lock ( owner_lock & this ) { lock ( (blocking_lock &)this ); } 48 static inline void unlock ( owner_lock & this ) { unlock ( (blocking_lock &)this ); } 49 static inline void on_wait ( owner_lock & this ) { on_wait( (blocking_lock &)this ); } 162 static inline void lock ( owner_lock & this ) { lock ( (blocking_lock &)this ); } 163 static inline bool try_lock ( owner_lock & this ) { return try_lock( (blocking_lock &)this ); } 164 static inline void unlock ( owner_lock & this ) { unlock ( (blocking_lock &)this ); } 165 static inline size_t on_wait ( owner_lock & this ) { return on_wait ( (blocking_lock &)this ); } 166 static inline void on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 50 167 static inline void on_notify( owner_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); } 51 static inline void set_recursion_count( owner_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); } 52 static inline size_t get_recursion_count( owner_lock & this ) { return get_recursion_count( (blocking_lock &)this ); } 168 169 struct fast_lock { 170 $thread * volatile owner; 171 ThreadBenaphore sem; 172 }; 173 174 static inline bool $try_lock(fast_lock & this, $thread * thrd) { 175 $thread * exp = 0p; 176 return __atomic_compare_exchange_n(&this.owner, &exp, thrd, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); 177 } 178 179 static inline void lock( fast_lock & this ) __attribute__((artificial)); 180 static inline void lock( fast_lock & this ) { 181 $thread * thrd = active_thread(); 182 /* paranoid */verify(thrd != this.owner); 183 184 for (;;) { 185 if ($try_lock(this, thrd)) return; 186 P(this.sem); 187 } 188 } 189 190 static inline bool try_lock( fast_lock & this ) __attribute__((artificial)); 191 static inline bool try_lock ( fast_lock & this ) { 192 $thread * thrd = active_thread(); 193 /* paranoid */ verify(thrd != this.owner); 194 return $try_lock(this, thrd); 195 } 196 197 static inline $thread * unlock( fast_lock & this ) __attribute__((artificial)); 198 static inline $thread * unlock( fast_lock & this ) { 199 /* paranoid */ verify(active_thread() == this.owner); 200 201 // open 'owner' before unlocking anyone 202 // so new and unlocked threads don't park incorrectly. 203 // This may require additional fencing on ARM. 204 this.owner = 0p; 205 206 return V(this.sem); 207 } 208 209 static inline size_t on_wait( fast_lock & this ) { unlock(this); return 0; } 210 static inline void on_wakeup( fast_lock & this, size_t ) { lock(this); } 211 static inline void on_notify( fast_lock &, struct $thread * t ) { unpark(t); } 212 213 struct mcs_node { 214 mcs_node * volatile next; 215 single_sem sem; 216 }; 217 218 static inline void ?{}(mcs_node & this) { this.next = 0p; } 219 220 static inline mcs_node * volatile & ?`next ( mcs_node * node ) { 221 return node->next; 222 } 223 224 struct mcs_lock { 225 mcs_queue(mcs_node) queue; 226 }; 227 228 static inline void lock(mcs_lock & l, mcs_node & n) { 229 if(push(l.queue, &n)) 230 wait(n.sem); 231 } 232 233 static inline void unlock(mcs_lock & l, mcs_node & n) { 234 mcs_node * next = advance(l.queue, &n); 235 if(next) post(next->sem); 236 } 53 237 54 238 //----------------------------------------------------------------------------- … … 59 243 60 244 // For synchronization locks to use when releasing 61 void on_wait( L & ); 62 63 // to get recursion count for cond lock to reset after waking 64 size_t get_recursion_count( L & ); 245 size_t on_wait( L & ); 65 246 66 247 // to set recursion count after getting signalled; 67 void set_recursion_count( L &, size_t recursion );248 void on_wakeup( L &, size_t recursion ); 68 249 }; 69 250 … … 119 300 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ); 120 301 } 121 122 //-----------------------------------------------------------------------------123 // Semaphore124 struct semaphore {125 __spinlock_t lock;126 int count;127 __queue_t($thread) waiting;128 };129 130 void ?{}(semaphore & this, int count = 1);131 void ^?{}(semaphore & this);132 bool P (semaphore & this);133 bool V (semaphore & this);134 bool V (semaphore & this, unsigned count); -
libcfa/src/concurrency/monitor.hfa
rfeacef9 r5407cdc 61 61 static inline forall( T & | sized(T) | { void ^?{}( T & mutex ); } ) 62 62 void delete( T * th ) { 63 ^(*th){};63 if(th) ^(*th){}; 64 64 free( th ); 65 65 } -
libcfa/src/concurrency/preemption.cfa
rfeacef9 r5407cdc 15 15 16 16 #define __cforall_thread__ 17 // #define __CFA_DEBUG_PRINT_PREEMPTION__ 17 18 18 19 #include "preemption.hfa" … … 28 29 #include "kernel_private.hfa" 29 30 31 30 32 #if !defined(__CFA_DEFAULT_PREEMPTION__) 31 33 #define __CFA_DEFAULT_PREEMPTION__ 10`ms 32 34 #endif 33 35 34 Duration default_preemption() __attribute__((weak)) { 35 return __CFA_DEFAULT_PREEMPTION__; 36 __attribute__((weak)) Duration default_preemption() { 37 const char * preempt_rate_s = getenv("CFA_DEFAULT_PREEMPTION"); 38 if(!preempt_rate_s) { 39 __cfadbg_print_safe(preemption, "No CFA_DEFAULT_PREEMPTION in ENV\n"); 40 return __CFA_DEFAULT_PREEMPTION__; 41 } 42 43 char * endptr = 0p; 44 long int preempt_rate_l = strtol(preempt_rate_s, &endptr, 10); 45 if(preempt_rate_l < 0 || preempt_rate_l > 65535) { 46 __cfadbg_print_safe(preemption, "CFA_DEFAULT_PREEMPTION out of range : %ld\n", preempt_rate_l); 47 return __CFA_DEFAULT_PREEMPTION__; 48 } 49 if('\0' != *endptr) { 50 __cfadbg_print_safe(preemption, "CFA_DEFAULT_PREEMPTION not a decimal number : %s\n", preempt_rate_s); 51 return __CFA_DEFAULT_PREEMPTION__; 52 } 53 54 return preempt_rate_l`ms; 36 55 } 37 56 … … 98 117 //Loop throught every thing expired 99 118 while( node = get_expired( alarms, currtime ) ) { 100 // __cfaabi_dbg_print_buffer_decl( " KERNEL: preemption tick.\n");119 __cfadbg_print_buffer_decl( preemption, " KERNEL: preemption tick %lu\n", currtime.tn); 101 120 Duration period = node->period; 102 121 if( period == 0) { … … 104 123 } 105 124 125 __cfadbg_print_buffer_local( preemption, " KERNEL: alarm ticking node %p.\n", node ); 126 127 106 128 // Check if this is a kernel 107 129 if( node->type == Kernel ) { … … 109 131 } 110 132 else if( node->type == User ) { 133 __cfadbg_print_buffer_local( preemption, " KERNEL: alarm unparking %p.\n", node->thrd ); 111 134 timeout( node->thrd ); 112 135 } … … 117 140 // Check if this is a periodic alarm 118 141 if( period > 0 ) { 119 // __cfaabi_dbg_print_buffer_local( " KERNEL: alarm period is %lu.\n", period.tv);142 __cfadbg_print_buffer_local( preemption, " KERNEL: alarm period is %lu.\n", period`ns ); 120 143 node->alarm = currtime + period; // Alarm is periodic, add currtime to it (used cached current time) 121 144 insert( alarms, node ); // Reinsert the node for the next time it triggers … … 125 148 // If there are still alarms pending, reset the timer 126 149 if( & (*alarms)`first ) { 127 __cfadbg_print_buffer_decl(preemption, " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);128 150 Duration delta = (*alarms)`first.alarm - currtime; 129 151 Duration capped = max(delta, 50`us); 130 // itimerval tim = { caped };131 // __cfaabi_dbg_print_buffer_local( " Values are %lu, %lu, %lu %lu.\n", delta.tv, caped.tv, tim.it_value.tv_sec, tim.it_value.tv_usec);132 133 152 __kernel_set_timer( capped ); 134 153 } … … 296 315 // Enable interrupts by decrementing the counter 297 316 // If counter reaches 0, execute any pending __cfactx_switch 298 void enable_interrupts( __cfaabi_dbg_ctx_param) {317 void enable_interrupts( bool poll ) { 299 318 // Cache the processor now since interrupts can start happening after the atomic store 300 319 processor * proc = __cfaabi_tls.this_processor; 301 /* paranoid */ verify( proc );320 /* paranoid */ verify( !poll || proc ); 302 321 303 322 with( __cfaabi_tls.preemption_state ){ … … 321 340 // Signal the compiler that a fence is needed but only for signal handlers 322 341 __atomic_signal_fence(__ATOMIC_RELEASE); 323 if( p roc->pending_preemption ) {342 if( poll && proc->pending_preemption ) { 324 343 proc->pending_preemption = false; 325 344 force_yield( __POLL_PREEMPTION ); 326 345 } 327 346 } 328 }329 330 // For debugging purposes : keep track of the last person to enable the interrupts331 __cfaabi_dbg_debug_do( proc->last_enable = caller; )332 }333 334 // Disable interrupts by incrementint the counter335 // Don't execute any pending __cfactx_switch even if counter reaches 0336 void enable_interrupts_noPoll() {337 unsigned short prev = __cfaabi_tls.preemption_state.disable_count;338 __cfaabi_tls.preemption_state.disable_count -= 1;339 // If this triggers someone is enabled already enabled interrupts340 /* paranoid */ verifyf( prev != 0u, "Incremented from %u\n", prev );341 if( prev == 1 ) {342 #if GCC_VERSION > 50000343 static_assert(__atomic_always_lock_free(sizeof(__cfaabi_tls.preemption_state.enabled), &__cfaabi_tls.preemption_state.enabled), "Must be lock-free");344 #endif345 // Set enabled flag to true346 // should be atomic to avoid preemption in the middle of the operation.347 // use memory order RELAXED since there is no inter-thread on this variable requirements348 __atomic_store_n(&__cfaabi_tls.preemption_state.enabled, true, __ATOMIC_RELAXED);349 350 // Signal the compiler that a fence is needed but only for signal handlers351 __atomic_signal_fence(__ATOMIC_RELEASE);352 347 } 353 348 } … … 585 580 586 581 // Setup proper signal handlers 587 __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART); // __cfactx_switch handler588 __cfaabi_sigaction( SIGALRM, sigHandler_alarm , SA_SIGINFO | SA_RESTART); // debug handler582 __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO ); // __cfactx_switch handler 583 __cfaabi_sigaction( SIGALRM, sigHandler_alarm , SA_SIGINFO ); // debug handler 589 584 590 585 signal_block( SIGALRM ); … … 689 684 } 690 685 691 #if !defined(__CFA_NO_STATISTICS__)692 int __print_alarm_stats = 0;693 #endif694 695 686 // Main of the alarm thread 696 687 // Waits on SIGALRM and send SIGUSR1 to whom ever needs it 697 688 static void * alarm_loop( __attribute__((unused)) void * args ) { 698 689 __processor_id_t id; 699 id.full_proc = false; 700 id.id = doregister(&id); 690 register_proc_id(&id); 701 691 __cfaabi_tls.this_proc_id = &id; 702 692 703 #if !defined(__CFA_NO_STATISTICS__)704 struct __stats_t local_stats;705 __cfaabi_tls.this_stats = &local_stats;706 __init_stats( &local_stats );707 #endif708 693 709 694 // Block sigalrms to control when they arrive … … 764 749 EXIT: 765 750 __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" ); 766 unregister(&id); 767 768 #if !defined(__CFA_NO_STATISTICS__) 769 if( 0 != __print_alarm_stats ) { 770 __print_stats( &local_stats, __print_alarm_stats, "Alarm", "Thread", 0p ); 771 } 772 #endif 751 register_proc_id(&id); 752 773 753 return 0p; 774 754 } -
libcfa/src/concurrency/ready_queue.cfa
rfeacef9 r5407cdc 17 17 // #define __CFA_DEBUG_PRINT_READY_QUEUE__ 18 18 19 // #define USE_SNZI 19 // #define USE_MPSC 20 21 #define USE_RELAXED_FIFO 22 // #define USE_WORK_STEALING 20 23 21 24 #include "bits/defs.hfa" … … 28 31 #include <unistd.h> 29 32 30 #include "snzi.hfa"31 33 #include "ready_subqueue.hfa" 32 34 33 35 static const size_t cache_line_size = 64; 36 37 #if !defined(__CFA_NO_STATISTICS__) 38 #define __STATS(...) __VA_ARGS__ 39 #else 40 #define __STATS(...) 41 #endif 34 42 35 43 // No overriden function, no environment variable, no define … … 39 47 #endif 40 48 41 #define BIAS 16 49 #if defined(USE_RELAXED_FIFO) 50 #define BIAS 4 51 #define READYQ_SHARD_FACTOR 4 52 #define SEQUENTIAL_SHARD 1 53 #elif defined(USE_WORK_STEALING) 54 #define READYQ_SHARD_FACTOR 2 55 #define SEQUENTIAL_SHARD 2 56 #else 57 #error no scheduling strategy selected 58 #endif 59 60 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats)); 61 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats)); 62 static inline struct $thread * search(struct cluster * cltr); 63 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred); 64 42 65 43 66 // returns the maximum number of processors the RWLock support … … 93 116 //======================================================================= 94 117 // Lock-Free registering/unregistering of threads 95 unsigned doregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {118 void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) { 96 119 __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc); 97 120 … … 107 130 /*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size)); 108 131 /*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0); 109 returni;132 proc->id = i; 110 133 } 111 134 } … … 134 157 /*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size)); 135 158 /*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0); 136 returnn;137 } 138 139 void unregister ( struct __processor_id_t * proc ) with(*__scheduler_lock) {159 proc->id = n; 160 } 161 162 void unregister_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) { 140 163 unsigned id = proc->id; 141 164 /*paranoid*/ verify(id < ready); … … 192 215 193 216 //======================================================================= 194 // Cforall Re qdy Queue used for scheduling217 // Cforall Ready Queue used for scheduling 195 218 //======================================================================= 196 219 void ?{}(__ready_queue_t & this) with (this) { 197 220 lanes.data = 0p; 221 lanes.tscs = 0p; 198 222 lanes.count = 0; 199 223 } 200 224 201 225 void ^?{}(__ready_queue_t & this) with (this) { 202 verify( 1 == lanes.count ); 203 #ifdef USE_SNZI 204 verify( !query( snzi ) ); 205 #endif 226 verify( SEQUENTIAL_SHARD == lanes.count ); 206 227 free(lanes.data); 228 free(lanes.tscs); 207 229 } 208 230 209 231 //----------------------------------------------------------------------- 210 __attribute__((hot)) bool query(struct cluster * cltr) { 211 #ifdef USE_SNZI 212 return query(cltr->ready_queue.snzi); 213 #endif 214 return true; 215 } 216 217 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) { 218 unsigned i; 219 bool local; 220 #if defined(BIAS) 232 #if defined(USE_RELAXED_FIFO) 233 //----------------------------------------------------------------------- 234 // get index from random number with or without bias towards queues 235 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) { 236 unsigned i; 237 bool local; 221 238 unsigned rlow = r % BIAS; 222 239 unsigned rhigh = r / BIAS; … … 224 241 // (BIAS - 1) out of BIAS chances 225 242 // Use perferred queues 226 i = preferred + (rhigh % 4);243 i = preferred + (rhigh % READYQ_SHARD_FACTOR); 227 244 local = true; 228 245 } … … 233 250 local = false; 234 251 } 235 #else 236 i = r; 237 local = false; 252 return [i, local]; 253 } 254 255 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 256 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 257 258 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 259 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 260 261 // write timestamp 262 thrd->link.ts = rdtscl(); 263 264 bool local; 265 int preferred = external ? -1 : kernelTLS().this_processor->rdq.id; 266 267 // Try to pick a lane and lock it 268 unsigned i; 269 do { 270 // Pick the index of a lane 271 unsigned r = __tls_rand_fwd(); 272 [i, local] = idx_from_r(r, preferred); 273 274 i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 275 276 #if !defined(__CFA_NO_STATISTICS__) 277 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED); 278 else if(local) __tls_stats()->ready.push.local.attempt++; 279 else __tls_stats()->ready.push.share.attempt++; 280 #endif 281 282 #if defined(USE_MPSC) 283 // mpsc always succeeds 284 } while( false ); 285 #else 286 // If we can't lock it retry 287 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 288 #endif 289 290 // Actually push it 291 push(lanes.data[i], thrd); 292 293 #if !defined(USE_MPSC) 294 // Unlock and return 295 __atomic_unlock( &lanes.data[i].lock ); 296 #endif 297 298 // Mark the current index in the tls rng instance as having an item 299 __tls_rand_advance_bck(); 300 301 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first); 302 303 // Update statistics 304 #if !defined(__CFA_NO_STATISTICS__) 305 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED); 306 else if(local) __tls_stats()->ready.push.local.success++; 307 else __tls_stats()->ready.push.share.success++; 308 #endif 309 } 310 311 // Pop from the ready queue from a given cluster 312 __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) { 313 /* paranoid */ verify( lanes.count > 0 ); 314 /* paranoid */ verify( kernelTLS().this_processor ); 315 /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count ); 316 317 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 318 int preferred = kernelTLS().this_processor->rdq.id; 319 320 321 // As long as the list is not empty, try finding a lane that isn't empty and pop from it 322 for(25) { 323 // Pick two lists at random 324 unsigned ri = __tls_rand_bck(); 325 unsigned rj = __tls_rand_bck(); 326 327 unsigned i, j; 328 __attribute__((unused)) bool locali, localj; 329 [i, locali] = idx_from_r(ri, preferred); 330 [j, localj] = idx_from_r(rj, preferred); 331 332 i %= count; 333 j %= count; 334 335 // try popping from the 2 picked lists 336 struct $thread * thrd = try_pop(cltr, i, j __STATS(, *(locali || localj ? &__tls_stats()->ready.pop.local : &__tls_stats()->ready.pop.help))); 337 if(thrd) { 338 return thrd; 339 } 340 } 341 342 // All lanes where empty return 0p 343 return 0p; 344 } 345 346 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) { return pop_fast(cltr); } 347 __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr) { 348 return search(cltr); 349 } 350 #endif 351 #if defined(USE_WORK_STEALING) 352 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 353 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 354 355 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 356 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 357 358 // write timestamp 359 thrd->link.ts = rdtscl(); 360 361 // Try to pick a lane and lock it 362 unsigned i; 363 do { 364 #if !defined(__CFA_NO_STATISTICS__) 365 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED); 366 else __tls_stats()->ready.push.local.attempt++; 367 #endif 368 369 if(unlikely(external)) { 370 i = __tls_rand() % lanes.count; 371 } 372 else { 373 processor * proc = kernelTLS().this_processor; 374 unsigned r = proc->rdq.its++; 375 i = proc->rdq.id + (r % READYQ_SHARD_FACTOR); 376 } 377 378 379 #if defined(USE_MPSC) 380 // mpsc always succeeds 381 } while( false ); 382 #else 383 // If we can't lock it retry 384 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 385 #endif 386 387 // Actually push it 388 push(lanes.data[i], thrd); 389 390 #if !defined(USE_MPSC) 391 // Unlock and return 392 __atomic_unlock( &lanes.data[i].lock ); 393 #endif 394 395 #if !defined(__CFA_NO_STATISTICS__) 396 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED); 397 else __tls_stats()->ready.push.local.success++; 398 #endif 399 400 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first); 401 } 402 403 // Pop from the ready queue from a given cluster 404 __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) { 405 /* paranoid */ verify( lanes.count > 0 ); 406 /* paranoid */ verify( kernelTLS().this_processor ); 407 /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count ); 408 409 processor * proc = kernelTLS().this_processor; 410 411 if(proc->rdq.target == -1u) { 412 proc->rdq.target = __tls_rand() % lanes.count; 413 unsigned it1 = proc->rdq.itr; 414 unsigned it2 = proc->rdq.itr + 1; 415 unsigned idx1 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR); 416 unsigned idx2 = proc->rdq.id + (it2 % READYQ_SHARD_FACTOR); 417 unsigned long long tsc1 = ts(lanes.data[idx1]); 418 unsigned long long tsc2 = ts(lanes.data[idx2]); 419 proc->rdq.cutoff = min(tsc1, tsc2); 420 if(proc->rdq.cutoff == 0) proc->rdq.cutoff = -1ull; 421 } 422 else { 423 unsigned target = proc->rdq.target; 424 proc->rdq.target = -1u; 425 if(lanes.tscs[target].tv < proc->rdq.cutoff) { 426 $thread * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help)); 427 if(t) return t; 428 } 429 } 430 431 for(READYQ_SHARD_FACTOR) { 432 unsigned i = proc->rdq.id + (--proc->rdq.itr % READYQ_SHARD_FACTOR); 433 if($thread * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t; 434 } 435 return 0p; 436 } 437 438 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) { 439 unsigned i = __tls_rand() % lanes.count; 440 return try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.steal)); 441 } 442 443 __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr) with (cltr->ready_queue) { 444 return search(cltr); 445 } 446 #endif 447 448 //======================================================================= 449 // Various Ready Queue utilities 450 //======================================================================= 451 // these function work the same or almost the same 452 // whether they are using work-stealing or relaxed fifo scheduling 453 454 //----------------------------------------------------------------------- 455 // try to pop from a lane given by index w 456 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) { 457 __STATS( stats.attempt++; ) 458 459 // Get relevant elements locally 460 __intrusive_lane_t & lane = lanes.data[w]; 461 462 // If list looks empty retry 463 if( is_empty(lane) ) { 464 __STATS( stats.espec++; ) 465 return 0p; 466 } 467 468 // If we can't get the lock retry 469 if( !__atomic_try_acquire(&lane.lock) ) { 470 __STATS( stats.elock++; ) 471 return 0p; 472 } 473 474 // If list is empty, unlock and retry 475 if( is_empty(lane) ) { 476 __atomic_unlock(&lane.lock); 477 __STATS( stats.eempty++; ) 478 return 0p; 479 } 480 481 // Actually pop the list 482 struct $thread * thrd; 483 thrd = pop(lane); 484 485 /* paranoid */ verify(thrd); 486 /* paranoid */ verify(lane.lock); 487 488 // Unlock and return 489 __atomic_unlock(&lane.lock); 490 491 // Update statistics 492 __STATS( stats.success++; ) 493 494 #if defined(USE_WORK_STEALING) 495 lanes.tscs[w].tv = thrd->link.ts; 238 496 #endif 239 return [i, local]; 497 498 // return the popped thread 499 return thrd; 240 500 } 241 501 242 502 //----------------------------------------------------------------------- 243 __attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 244 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 245 246 // write timestamp 247 thrd->link.ts = rdtscl(); 248 249 __attribute__((unused)) bool local; 250 __attribute__((unused)) int preferred; 251 #if defined(BIAS) 252 preferred = 253 //* 254 kernelTLS().this_processor ? kernelTLS().this_processor->id * 4 : -1; 255 /*/ 256 thrd->link.preferred * 4; 257 //*/ 258 #endif 259 260 // Try to pick a lane and lock it 261 unsigned i; 262 do { 263 // Pick the index of a lane 264 // unsigned r = __tls_rand(); 265 unsigned r = __tls_rand_fwd(); 266 [i, local] = idx_from_r(r, preferred); 267 268 #if !defined(__CFA_NO_STATISTICS__) 269 if(local) { 270 __tls_stats()->ready.pick.push.local++; 271 } 272 #endif 273 274 i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 275 276 #if !defined(__CFA_NO_STATISTICS__) 277 __tls_stats()->ready.pick.push.attempt++; 278 #endif 279 280 // If we can't lock it retry 281 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); 282 283 bool first = false; 284 285 // Actually push it 286 #ifdef USE_SNZI 287 bool lane_first = 288 #endif 289 290 push(lanes.data[i], thrd); 291 292 #ifdef USE_SNZI 293 // If this lane used to be empty we need to do more 294 if(lane_first) { 295 // Check if the entire queue used to be empty 296 first = !query(snzi); 297 298 // Update the snzi 299 arrive( snzi, i ); 300 } 301 #endif 302 303 __tls_rand_advance_bck(); 304 305 // Unlock and return 306 __atomic_unlock( &lanes.data[i].lock ); 307 308 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first); 309 310 // Update statistics 311 #if !defined(__CFA_NO_STATISTICS__) 312 #if defined(BIAS) 313 if( local ) __tls_stats()->ready.pick.push.lsuccess++; 314 #endif 315 __tls_stats()->ready.pick.push.success++; 316 #endif 317 318 // return whether or not the list was empty before this push 319 return first; 320 } 321 322 static struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j); 323 static struct $thread * try_pop(struct cluster * cltr, unsigned i); 324 325 // Pop from the ready queue from a given cluster 326 __attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) { 327 /* paranoid */ verify( lanes.count > 0 ); 328 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 329 int preferred; 330 #if defined(BIAS) 331 // Don't bother trying locally too much 332 int local_tries = 8; 333 preferred = kernelTLS().this_processor->id * 4; 334 #endif 335 336 337 // As long as the list is not empty, try finding a lane that isn't empty and pop from it 338 #ifdef USE_SNZI 339 while( query(snzi) ) { 340 #else 341 for(25) { 342 #endif 343 // Pick two lists at random 344 // unsigned ri = __tls_rand(); 345 // unsigned rj = __tls_rand(); 346 unsigned ri = __tls_rand_bck(); 347 unsigned rj = __tls_rand_bck(); 348 349 unsigned i, j; 350 __attribute__((unused)) bool locali, localj; 351 [i, locali] = idx_from_r(ri, preferred); 352 [j, localj] = idx_from_r(rj, preferred); 353 354 #if !defined(__CFA_NO_STATISTICS__) 355 if(locali) { 356 __tls_stats()->ready.pick.pop.local++; 357 } 358 if(localj) { 359 __tls_stats()->ready.pick.pop.local++; 360 } 361 #endif 362 363 i %= count; 364 j %= count; 365 366 // try popping from the 2 picked lists 367 struct $thread * thrd = try_pop(cltr, i, j); 368 if(thrd) { 369 #if defined(BIAS) && !defined(__CFA_NO_STATISTICS__) 370 if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++; 371 #endif 372 return thrd; 373 } 374 } 375 376 // All lanes where empty return 0p 377 return 0p; 378 } 379 380 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) { 503 // try to pop from any lanes making sure you don't miss any threads push 504 // before the start of the function 505 static inline struct $thread * search(struct cluster * cltr) with (cltr->ready_queue) { 381 506 /* paranoid */ verify( lanes.count > 0 ); 382 507 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); … … 384 509 for(i; count) { 385 510 unsigned idx = (offset + i) % count; 386 struct $thread * thrd = try_pop(cltr, idx );511 struct $thread * thrd = try_pop(cltr, idx __STATS(, __tls_stats()->ready.pop.search)); 387 512 if(thrd) { 388 513 return thrd; … … 394 519 } 395 520 396 397 521 //----------------------------------------------------------------------- 398 // Given 2 indexes, pick the list with the oldest push an try to pop from it 399 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j) with (cltr->ready_queue) { 400 #if !defined(__CFA_NO_STATISTICS__) 401 __tls_stats()->ready.pick.pop.attempt++; 402 #endif 403 404 // Pick the bet list 405 int w = i; 406 if( __builtin_expect(!is_empty(lanes.data[j]), true) ) { 407 w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j; 408 } 409 410 return try_pop(cltr, w); 411 } 412 413 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w) with (cltr->ready_queue) { 414 // Get relevant elements locally 415 __intrusive_lane_t & lane = lanes.data[w]; 416 417 // If list looks empty retry 418 if( is_empty(lane) ) return 0p; 419 420 // If we can't get the lock retry 421 if( !__atomic_try_acquire(&lane.lock) ) return 0p; 422 423 424 // If list is empty, unlock and retry 425 if( is_empty(lane) ) { 426 __atomic_unlock(&lane.lock); 427 return 0p; 428 } 429 430 // Actually pop the list 431 struct $thread * thrd; 432 thrd = pop(lane); 433 434 /* paranoid */ verify(thrd); 435 /* paranoid */ verify(lane.lock); 436 437 #ifdef USE_SNZI 438 // If this was the last element in the lane 439 if(emptied) { 440 depart( snzi, w ); 441 } 442 #endif 443 444 // Unlock and return 445 __atomic_unlock(&lane.lock); 446 447 // Update statistics 448 #if !defined(__CFA_NO_STATISTICS__) 449 __tls_stats()->ready.pick.pop.success++; 450 #endif 451 452 // Update the thread bias 453 thrd->link.preferred = w / 4; 454 455 // return the popped thread 456 return thrd; 457 } 458 //----------------------------------------------------------------------- 459 460 bool remove_head(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) { 461 for(i; lanes.count) { 462 __intrusive_lane_t & lane = lanes.data[i]; 463 464 bool removed = false; 465 466 __atomic_acquire(&lane.lock); 467 if(head(lane)->link.next == thrd) { 468 $thread * pthrd; 469 pthrd = pop(lane); 470 471 /* paranoid */ verify( pthrd == thrd ); 472 473 removed = true; 474 #ifdef USE_SNZI 475 if(emptied) { 476 depart( snzi, i ); 477 } 478 #endif 479 } 480 __atomic_unlock(&lane.lock); 481 482 if( removed ) return true; 483 } 484 return false; 485 } 486 487 //----------------------------------------------------------------------- 488 522 // Check that all the intrusive queues in the data structure are still consistent 489 523 static void check( __ready_queue_t & q ) with (q) { 490 #if defined(__CFA_WITH_VERIFY__) 524 #if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC) 491 525 { 492 526 for( idx ; lanes.count ) { … … 499 533 assert(tail(sl)->link.prev->link.next == tail(sl) ); 500 534 501 if( sl.before.link.ts == 0l) {535 if(is_empty(sl)) { 502 536 assert(tail(sl)->link.prev == head(sl)); 503 537 assert(head(sl)->link.next == tail(sl)); … … 511 545 } 512 546 547 //----------------------------------------------------------------------- 548 // Given 2 indexes, pick the list with the oldest push an try to pop from it 549 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) { 550 // Pick the bet list 551 int w = i; 552 if( __builtin_expect(!is_empty(lanes.data[j]), true) ) { 553 w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j; 554 } 555 556 return try_pop(cltr, w __STATS(, stats)); 557 } 558 513 559 // Call this function of the intrusive list was moved using memcpy 514 560 // fixes the list so that the pointers back to anchors aren't left dangling 515 561 static inline void fix(__intrusive_lane_t & ll) { 516 // if the list is not empty then follow he pointer and fix its reverse 517 if(!is_empty(ll)) { 518 head(ll)->link.next->link.prev = head(ll); 519 tail(ll)->link.prev->link.next = tail(ll); 520 } 521 // Otherwise just reset the list 522 else { 523 verify(tail(ll)->link.next == 0p); 524 tail(ll)->link.prev = head(ll); 525 head(ll)->link.next = tail(ll); 526 verify(head(ll)->link.prev == 0p); 527 } 562 #if !defined(USE_MPSC) 563 // if the list is not empty then follow he pointer and fix its reverse 564 if(!is_empty(ll)) { 565 head(ll)->link.next->link.prev = head(ll); 566 tail(ll)->link.prev->link.next = tail(ll); 567 } 568 // Otherwise just reset the list 569 else { 570 verify(tail(ll)->link.next == 0p); 571 tail(ll)->link.prev = head(ll); 572 head(ll)->link.next = tail(ll); 573 verify(head(ll)->link.prev == 0p); 574 } 575 #endif 576 } 577 578 static void assign_list(unsigned & value, dlist(processor, processor) & list, unsigned count) { 579 processor * it = &list`first; 580 for(unsigned i = 0; i < count; i++) { 581 /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count); 582 it->rdq.id = value; 583 it->rdq.target = -1u; 584 value += READYQ_SHARD_FACTOR; 585 it = &(*it)`next; 586 } 587 } 588 589 static void reassign_cltr_id(struct cluster * cltr) { 590 unsigned preferred = 0; 591 assign_list(preferred, cltr->procs.actives, cltr->procs.total - cltr->procs.idle); 592 assign_list(preferred, cltr->procs.idles , cltr->procs.idle ); 593 } 594 595 static void fix_times( struct cluster * cltr ) with( cltr->ready_queue ) { 596 #if defined(USE_WORK_STEALING) 597 lanes.tscs = alloc(lanes.count, lanes.tscs`realloc); 598 for(i; lanes.count) { 599 lanes.tscs[i].tv = ts(lanes.data[i]); 600 } 601 #endif 528 602 } 529 603 530 604 // Grow the ready queue 531 void ready_queue_grow (struct cluster * cltr, int target) { 605 void ready_queue_grow(struct cluster * cltr) { 606 size_t ncount; 607 int target = cltr->procs.total; 608 532 609 /* paranoid */ verify( ready_mutate_islocked() ); 533 610 __cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue\n"); … … 538 615 // grow the ready queue 539 616 with( cltr->ready_queue ) { 540 #ifdef USE_SNZI541 ^(snzi){};542 #endif543 544 617 // Find new count 545 618 // Make sure we always have atleast 1 list 546 size_t ncount = target >= 2 ? target * 4: 1; 619 if(target >= 2) { 620 ncount = target * READYQ_SHARD_FACTOR; 621 } else { 622 ncount = SEQUENTIAL_SHARD; 623 } 547 624 548 625 // Allocate new array (uses realloc and memcpies the data) … … 561 638 // Update original 562 639 lanes.count = ncount; 563 564 #ifdef USE_SNZI 565 // Re-create the snzi 566 snzi{ log2( lanes.count / 8 ) }; 567 for( idx; (size_t)lanes.count ) { 568 if( !is_empty(lanes.data[idx]) ) { 569 arrive(snzi, idx); 570 } 571 } 572 #endif 573 } 640 } 641 642 fix_times(cltr); 643 644 reassign_cltr_id(cltr); 574 645 575 646 // Make sure that everything is consistent … … 582 653 583 654 // Shrink the ready queue 584 void ready_queue_shrink(struct cluster * cltr , int target) {655 void ready_queue_shrink(struct cluster * cltr) { 585 656 /* paranoid */ verify( ready_mutate_islocked() ); 586 657 __cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue\n"); … … 589 660 /* paranoid */ check( cltr->ready_queue ); 590 661 662 int target = cltr->procs.total; 663 591 664 with( cltr->ready_queue ) { 592 #ifdef USE_SNZI593 ^(snzi){};594 #endif595 596 665 // Remember old count 597 666 size_t ocount = lanes.count; … … 599 668 // Find new count 600 669 // Make sure we always have atleast 1 list 601 lanes.count = target >= 2 ? target * 4: 1;670 lanes.count = target >= 2 ? target * READYQ_SHARD_FACTOR: SEQUENTIAL_SHARD; 602 671 /* paranoid */ verify( ocount >= lanes.count ); 603 /* paranoid */ verify( lanes.count == target * 4|| target < 2 );672 /* paranoid */ verify( lanes.count == target * READYQ_SHARD_FACTOR || target < 2 ); 604 673 605 674 // for printing count the number of displaced threads … … 644 713 fix(lanes.data[idx]); 645 714 } 646 647 #ifdef USE_SNZI 648 // Re-create the snzi 649 snzi{ log2( lanes.count / 8 ) }; 650 for( idx; (size_t)lanes.count ) { 651 if( !is_empty(lanes.data[idx]) ) { 652 arrive(snzi, idx); 653 } 654 } 655 #endif 656 } 715 } 716 717 fix_times(cltr); 718 719 reassign_cltr_id(cltr); 657 720 658 721 // Make sure that everything is consistent -
libcfa/src/concurrency/ready_subqueue.hfa
rfeacef9 r5407cdc 2 2 3 3 #define __CFA_NO_SCHED_STATS__ 4 5 #include "containers/queueLockFree.hfa" 4 6 5 7 // Intrusives lanes which are used by the relaxed ready queue 6 8 struct __attribute__((aligned(128))) __intrusive_lane_t { 7 9 8 // anchor for the head and the tail of the queue 9 __attribute__((aligned(128))) struct __sentinel_t { 10 // Link lists fields 11 // instrusive link field for threads 12 // must be exactly as in $thread 13 __thread_desc_link link; 14 } before, after; 10 #if defined(USE_MPSC) 11 mpsc_queue($thread) queue; 12 __attribute__((aligned(128))) 13 #else 14 // anchor for the head and the tail of the queue 15 __attribute__((aligned(128))) struct __sentinel_t { 16 // Link lists fields 17 // instrusive link field for threads 18 // must be exactly as in $thread 19 __thread_desc_link link; 20 } before, after; 21 #endif 15 22 16 23 // spin lock protecting the queue … … 35 42 // Get the head pointer (one before the first element) from the anchor 36 43 static inline $thread * head(const __intrusive_lane_t & this) { 37 $thread * rhead = ($thread *)( 38 (uintptr_t)( &this.before ) - offsetof( $thread, link ) 39 ); 40 /* paranoid */ verify(rhead); 41 return rhead; 44 #if defined(USE_MPSC) 45 return this.queue.head; 46 #else 47 $thread * rhead = ($thread *)( 48 (uintptr_t)( &this.before ) - offsetof( $thread, link ) 49 ); 50 /* paranoid */ verify(rhead); 51 return rhead; 52 #endif 42 53 } 43 54 44 55 // Get the tail pointer (one after the last element) from the anchor 45 56 static inline $thread * tail(const __intrusive_lane_t & this) { 46 $thread * rtail = ($thread *)( 47 (uintptr_t)( &this.after ) - offsetof( $thread, link ) 48 ); 49 /* paranoid */ verify(rtail); 50 return rtail; 57 #if defined(USE_MPSC) 58 return this.queue.tail; 59 #else 60 $thread * rtail = ($thread *)( 61 (uintptr_t)( &this.after ) - offsetof( $thread, link ) 62 ); 63 /* paranoid */ verify(rtail); 64 return rtail; 65 #endif 51 66 } 52 67 … … 55 70 this.lock = false; 56 71 57 this.before.link.prev = 0p; 58 this.before.link.next = tail(this); 59 this.before.link.ts = 0; 60 61 this.after .link.prev = head(this); 62 this.after .link.next = 0p; 63 this.after .link.ts = 0; 64 65 #if !defined(__CFA_NO_SCHED_STATS__) 66 this.stat.diff = 0; 67 this.stat.push = 0; 68 this.stat.pop = 0; 69 #endif 70 71 // We add a boat-load of assertions here because the anchor code is very fragile 72 /* paranoid */ verify(((uintptr_t)( head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.before)); 73 /* paranoid */ verify(((uintptr_t)( tail(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.after )); 74 /* paranoid */ verify(head(this)->link.prev == 0p ); 75 /* paranoid */ verify(head(this)->link.next == tail(this) ); 76 /* paranoid */ verify(tail(this)->link.next == 0p ); 77 /* paranoid */ verify(tail(this)->link.prev == head(this) ); 78 /* paranoid */ verify(&head(this)->link.prev == &this.before.link.prev ); 79 /* paranoid */ verify(&head(this)->link.next == &this.before.link.next ); 80 /* paranoid */ verify(&tail(this)->link.prev == &this.after .link.prev ); 81 /* paranoid */ verify(&tail(this)->link.next == &this.after .link.next ); 82 /* paranoid */ verify(__alignof__(__intrusive_lane_t) == 128); 83 /* paranoid */ verify(__alignof__(this) == 128); 84 /* paranoid */ verifyf(((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128)); 72 #if !defined(USE_MPSC) 73 this.before.link.prev = 0p; 74 this.before.link.next = tail(this); 75 this.before.link.ts = 0; 76 77 this.after .link.prev = head(this); 78 this.after .link.next = 0p; 79 this.after .link.ts = 0; 80 81 #if !defined(__CFA_NO_SCHED_STATS__) 82 this.stat.diff = 0; 83 this.stat.push = 0; 84 this.stat.pop = 0; 85 #endif 86 87 // We add a boat-load of assertions here because the anchor code is very fragile 88 /* paranoid */ verify(((uintptr_t)( head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.before)); 89 /* paranoid */ verify(((uintptr_t)( tail(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.after )); 90 /* paranoid */ verify(head(this)->link.prev == 0p ); 91 /* paranoid */ verify(head(this)->link.next == tail(this) ); 92 /* paranoid */ verify(tail(this)->link.next == 0p ); 93 /* paranoid */ verify(tail(this)->link.prev == head(this) ); 94 /* paranoid */ verify(&head(this)->link.prev == &this.before.link.prev ); 95 /* paranoid */ verify(&head(this)->link.next == &this.before.link.next ); 96 /* paranoid */ verify(&tail(this)->link.prev == &this.after .link.prev ); 97 /* paranoid */ verify(&tail(this)->link.next == &this.after .link.next ); 98 /* paranoid */ verify(__alignof__(__intrusive_lane_t) == 128); 99 /* paranoid */ verify(__alignof__(this) == 128); 100 /* paranoid */ verifyf(((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128)); 101 #endif 85 102 } 86 103 87 104 // Dtor is trivial 88 105 void ^?{}( __intrusive_lane_t & this ) { 89 // Make sure the list is empty 90 /* paranoid */ verify(head(this)->link.prev == 0p ); 91 /* paranoid */ verify(head(this)->link.next == tail(this) ); 92 /* paranoid */ verify(tail(this)->link.next == 0p ); 93 /* paranoid */ verify(tail(this)->link.prev == head(this) ); 106 #if !defined(USE_MPSC) 107 // Make sure the list is empty 108 /* paranoid */ verify(head(this)->link.prev == 0p ); 109 /* paranoid */ verify(head(this)->link.next == tail(this) ); 110 /* paranoid */ verify(tail(this)->link.next == 0p ); 111 /* paranoid */ verify(tail(this)->link.prev == head(this) ); 112 #endif 94 113 } 95 114 … … 97 116 // returns true of lane was empty before push, false otherwise 98 117 bool push(__intrusive_lane_t & this, $thread * node) { 99 #if defined(__CFA_WITH_VERIFY__) 100 /* paranoid */ verify(this.lock); 101 /* paranoid */ verify(node->link.ts != 0); 102 /* paranoid */ verify(node->link.next == 0p); 103 /* paranoid */ verify(node->link.prev == 0p); 104 /* paranoid */ verify(tail(this)->link.next == 0p); 105 /* paranoid */ verify(head(this)->link.prev == 0p); 106 118 #if defined(USE_MPSC) 119 inline $thread * volatile & ?`next ( $thread * this ) __attribute__((const)) { 120 return this->link.next; 121 } 122 push(this.queue, node); 123 #else 124 #if defined(__CFA_WITH_VERIFY__) 125 /* paranoid */ verify(this.lock); 126 /* paranoid */ verify(node->link.ts != 0); 127 /* paranoid */ verify(node->link.next == 0p); 128 /* paranoid */ verify(node->link.prev == 0p); 129 /* paranoid */ verify(tail(this)->link.next == 0p); 130 /* paranoid */ verify(head(this)->link.prev == 0p); 131 132 if(this.before.link.ts == 0l) { 133 /* paranoid */ verify(tail(this)->link.prev == head(this)); 134 /* paranoid */ verify(head(this)->link.next == tail(this)); 135 } else { 136 /* paranoid */ verify(tail(this)->link.prev != head(this)); 137 /* paranoid */ verify(head(this)->link.next != tail(this)); 138 } 139 #endif 140 141 // Get the relevant nodes locally 142 $thread * tail = tail(this); 143 $thread * prev = tail->link.prev; 144 145 // Do the push 146 node->link.next = tail; 147 node->link.prev = prev; 148 prev->link.next = node; 149 tail->link.prev = node; 150 151 // Update stats 152 #if !defined(__CFA_NO_SCHED_STATS__) 153 this.stat.diff++; 154 this.stat.push++; 155 #endif 156 157 verify(node->link.next == tail(this)); 158 159 // Check if the queue used to be empty 107 160 if(this.before.link.ts == 0l) { 108 /* paranoid */ verify(tail(this)->link.prev == head(this)); 109 /* paranoid */ verify(head(this)->link.next == tail(this)); 110 } else { 111 /* paranoid */ verify(tail(this)->link.prev != head(this)); 112 /* paranoid */ verify(head(this)->link.next != tail(this)); 113 } 114 #endif 115 116 // Get the relevant nodes locally 117 $thread * tail = tail(this); 118 $thread * prev = tail->link.prev; 119 120 // Do the push 121 node->link.next = tail; 122 node->link.prev = prev; 123 prev->link.next = node; 124 tail->link.prev = node; 125 126 // Update stats 127 #if !defined(__CFA_NO_SCHED_STATS__) 128 this.stat.diff++; 129 this.stat.push++; 130 #endif 131 132 verify(node->link.next == tail(this)); 133 134 // Check if the queue used to be empty 135 if(this.before.link.ts == 0l) { 136 this.before.link.ts = node->link.ts; 137 /* paranoid */ verify(node->link.prev == head(this)); 138 return true; 139 } 140 return false; 161 this.before.link.ts = node->link.ts; 162 /* paranoid */ verify(node->link.prev == head(this)); 163 return true; 164 } 165 return false; 166 #endif 141 167 } 142 168 … … 146 172 $thread * pop(__intrusive_lane_t & this) { 147 173 /* paranoid */ verify(this.lock); 148 /* paranoid */ verify(this.before.link.ts != 0ul); 149 150 // Get anchors locally 151 $thread * head = head(this); 152 $thread * tail = tail(this); 153 154 // Get the relevant nodes locally 155 $thread * node = head->link.next; 156 $thread * next = node->link.next; 157 158 /* paranoid */ verify(node != tail); 159 /* paranoid */ verify(node); 160 161 // Do the pop 162 head->link.next = next; 163 next->link.prev = head; 164 node->link.next = 0p; 165 node->link.prev = 0p; 166 167 // Update head time stamp 168 this.before.link.ts = next->link.ts; 169 170 // Update stats 171 #ifndef __CFA_NO_SCHED_STATS__ 172 this.stat.diff--; 173 this.stat.pop ++; 174 #endif 175 176 // Check if we emptied list and return accordingly 177 /* paranoid */ verify(tail(this)->link.next == 0p); 178 /* paranoid */ verify(head(this)->link.prev == 0p); 179 if(next == tail) { 180 /* paranoid */ verify(this.before.link.ts == 0); 181 /* paranoid */ verify(tail(this)->link.prev == head(this)); 182 /* paranoid */ verify(head(this)->link.next == tail(this)); 183 return node; 184 } 185 else { 186 /* paranoid */ verify(next->link.ts != 0); 187 /* paranoid */ verify(tail(this)->link.prev != head(this)); 188 /* paranoid */ verify(head(this)->link.next != tail(this)); 189 /* paranoid */ verify(this.before.link.ts != 0); 190 return node; 191 } 174 #if defined(USE_MPSC) 175 inline $thread * volatile & ?`next ( $thread * this ) __attribute__((const)) { 176 return this->link.next; 177 } 178 return pop(this.queue); 179 #else 180 /* paranoid */ verify(this.before.link.ts != 0ul); 181 182 // Get anchors locally 183 $thread * head = head(this); 184 $thread * tail = tail(this); 185 186 // Get the relevant nodes locally 187 $thread * node = head->link.next; 188 $thread * next = node->link.next; 189 190 /* paranoid */ verify(node != tail); 191 /* paranoid */ verify(node); 192 193 // Do the pop 194 head->link.next = next; 195 next->link.prev = head; 196 node->link.next = 0p; 197 node->link.prev = 0p; 198 199 // Update head time stamp 200 this.before.link.ts = next->link.ts; 201 202 // Update stats 203 #ifndef __CFA_NO_SCHED_STATS__ 204 this.stat.diff--; 205 this.stat.pop ++; 206 #endif 207 208 // Check if we emptied list and return accordingly 209 /* paranoid */ verify(tail(this)->link.next == 0p); 210 /* paranoid */ verify(head(this)->link.prev == 0p); 211 if(next == tail) { 212 /* paranoid */ verify(this.before.link.ts == 0); 213 /* paranoid */ verify(tail(this)->link.prev == head(this)); 214 /* paranoid */ verify(head(this)->link.next == tail(this)); 215 return node; 216 } 217 else { 218 /* paranoid */ verify(next->link.ts != 0); 219 /* paranoid */ verify(tail(this)->link.prev != head(this)); 220 /* paranoid */ verify(head(this)->link.next != tail(this)); 221 /* paranoid */ verify(this.before.link.ts != 0); 222 return node; 223 } 224 #endif 192 225 } 193 226 194 227 // Check whether or not list is empty 195 228 static inline bool is_empty(__intrusive_lane_t & this) { 196 // Cannot verify here since it may not be locked 197 return this.before.link.ts == 0; 229 #if defined(USE_MPSC) 230 return this.queue.head == 0p; 231 #else 232 // Cannot verify here since it may not be locked 233 return this.before.link.ts == 0; 234 #endif 198 235 } 199 236 200 237 // Return the timestamp 201 238 static inline unsigned long long ts(__intrusive_lane_t & this) { 202 // Cannot verify here since it may not be locked 203 return this.before.link.ts; 204 } 239 #if defined(USE_MPSC) 240 $thread * tl = this.queue.head; 241 if(!tl) return -1ull; 242 return tl->link.ts; 243 #else 244 // Cannot verify here since it may not be locked 245 return this.before.link.ts; 246 #endif 247 } 248 249 // Aligned timestamps which are used by the relaxed ready queue 250 struct __attribute__((aligned(128))) __timestamp_t { 251 volatile unsigned long long tv; 252 }; 253 254 void ?{}(__timestamp_t & this) { this.tv = 0; } 255 void ^?{}(__timestamp_t & this) {} -
libcfa/src/concurrency/stats.cfa
rfeacef9 r5407cdc 5 5 #include <inttypes.h> 6 6 #include "bits/debug.hfa" 7 #include "bits/locks.hfa" 7 8 #include "stats.hfa" 9 #include "strstream.hfa" 8 10 9 11 #if !defined(__CFA_NO_STATISTICS__) 10 12 void __init_stats( struct __stats_t * stats ) { 11 stats->ready.pick.push.attempt = 0; 12 stats->ready.pick.push.success = 0; 13 stats->ready.pick.push.local = 0; 14 stats->ready.pick.push.lsuccess = 0; 15 stats->ready.pick.pop .probe = 0; 16 stats->ready.pick.pop .attempt = 0; 17 stats->ready.pick.pop .success = 0; 18 stats->ready.pick.pop .local = 0; 19 stats->ready.pick.pop .lsuccess = 0; 13 stats->ready.push.local.attempt = 0; 14 stats->ready.push.local.success = 0; 15 stats->ready.push.share.attempt = 0; 16 stats->ready.push.share.success = 0; 17 stats->ready.push.extrn.attempt = 0; 18 stats->ready.push.extrn.success = 0; 19 stats->ready.pop.local .attempt = 0; 20 stats->ready.pop.local .success = 0; 21 stats->ready.pop.local .elock = 0; 22 stats->ready.pop.local .eempty = 0; 23 stats->ready.pop.local .espec = 0; 24 stats->ready.pop.help .attempt = 0; 25 stats->ready.pop.help .success = 0; 26 stats->ready.pop.help .elock = 0; 27 stats->ready.pop.help .eempty = 0; 28 stats->ready.pop.help .espec = 0; 29 stats->ready.pop.steal .attempt = 0; 30 stats->ready.pop.steal .success = 0; 31 stats->ready.pop.steal .elock = 0; 32 stats->ready.pop.steal .eempty = 0; 33 stats->ready.pop.steal .espec = 0; 34 stats->ready.pop.search.attempt = 0; 35 stats->ready.pop.search.success = 0; 36 stats->ready.pop.search.elock = 0; 37 stats->ready.pop.search.eempty = 0; 38 stats->ready.pop.search.espec = 0; 20 39 stats->ready.threads.migration = 0; 40 stats->ready.threads.extunpark = 0; 41 stats->ready.threads.threads = 0; 21 42 stats->ready.sleep.halts = 0; 22 43 stats->ready.sleep.cancels = 0; … … 25 46 26 47 #if defined(CFA_HAVE_LINUX_IO_URING_H) 27 stats->io.submit_q.submit_avg.rdy = 0; 28 stats->io.submit_q.submit_avg.csm = 0; 29 stats->io.submit_q.submit_avg.cnt = 0; 30 stats->io.submit_q.look_avg.val = 0; 31 stats->io.submit_q.look_avg.cnt = 0; 32 stats->io.submit_q.look_avg.block = 0; 33 stats->io.submit_q.alloc_avg.val = 0; 34 stats->io.submit_q.alloc_avg.cnt = 0; 35 stats->io.submit_q.alloc_avg.block = 0; 36 stats->io.submit_q.helped = 0; 37 stats->io.submit_q.leader = 0; 38 stats->io.submit_q.busy = 0; 39 stats->io.complete_q.completed_avg.val = 0; 40 stats->io.complete_q.completed_avg.cnt = 0; 41 stats->io.complete_q.blocks = 0; 48 stats->io.alloc.fast = 0; 49 stats->io.alloc.slow = 0; 50 stats->io.alloc.fail = 0; 51 stats->io.alloc.revoke = 0; 52 stats->io.alloc.block = 0; 53 stats->io.submit.fast = 0; 54 stats->io.submit.slow = 0; 55 stats->io.flush.external = 0; 56 stats->io.calls.flush = 0; 57 stats->io.calls.submitted = 0; 58 stats->io.calls.drain = 0; 59 stats->io.calls.completed = 0; 60 stats->io.calls.errors.busy = 0; 61 stats->io.poller.sleeps = 0; 62 #endif 63 64 #if defined(CFA_STATS_ARRAY) 65 stats->array.values = alloc(CFA_STATS_ARRAY); 66 stats->array.cnt = 0; 42 67 #endif 43 68 } 44 69 45 70 void __tally_stats( struct __stats_t * cltr, struct __stats_t * proc ) { 46 __atomic_fetch_add( &cltr->ready.pick.push.attempt , proc->ready.pick.push.attempt , __ATOMIC_SEQ_CST ); proc->ready.pick.push.attempt = 0; 47 __atomic_fetch_add( &cltr->ready.pick.push.success , proc->ready.pick.push.success , __ATOMIC_SEQ_CST ); proc->ready.pick.push.success = 0; 48 __atomic_fetch_add( &cltr->ready.pick.push.local , proc->ready.pick.push.local , __ATOMIC_SEQ_CST ); proc->ready.pick.push.local = 0; 49 __atomic_fetch_add( &cltr->ready.pick.push.lsuccess, proc->ready.pick.push.lsuccess, __ATOMIC_SEQ_CST ); proc->ready.pick.push.lsuccess = 0; 50 __atomic_fetch_add( &cltr->ready.pick.pop .probe , proc->ready.pick.pop .probe , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .probe = 0; 51 __atomic_fetch_add( &cltr->ready.pick.pop .attempt , proc->ready.pick.pop .attempt , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .attempt = 0; 52 __atomic_fetch_add( &cltr->ready.pick.pop .success , proc->ready.pick.pop .success , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .success = 0; 53 __atomic_fetch_add( &cltr->ready.pick.pop .local , proc->ready.pick.pop .local , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .local = 0; 54 __atomic_fetch_add( &cltr->ready.pick.pop .lsuccess, proc->ready.pick.pop .lsuccess, __ATOMIC_SEQ_CST ); proc->ready.pick.pop .lsuccess = 0; 71 __atomic_fetch_add( &cltr->ready.push.local.attempt, proc->ready.push.local.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.local.attempt = 0; 72 __atomic_fetch_add( &cltr->ready.push.local.success, proc->ready.push.local.success, __ATOMIC_SEQ_CST ); proc->ready.push.local.success = 0; 73 __atomic_fetch_add( &cltr->ready.push.share.attempt, proc->ready.push.share.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.share.attempt = 0; 74 __atomic_fetch_add( &cltr->ready.push.share.success, proc->ready.push.share.success, __ATOMIC_SEQ_CST ); proc->ready.push.share.success = 0; 75 __atomic_fetch_add( &cltr->ready.push.extrn.attempt, proc->ready.push.extrn.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.attempt = 0; 76 __atomic_fetch_add( &cltr->ready.push.extrn.success, proc->ready.push.extrn.success, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.success = 0; 77 __atomic_fetch_add( &cltr->ready.pop.local .attempt, proc->ready.pop.local .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.local .attempt = 0; 78 __atomic_fetch_add( &cltr->ready.pop.local .success, proc->ready.pop.local .success, __ATOMIC_SEQ_CST ); proc->ready.pop.local .success = 0; 79 __atomic_fetch_add( &cltr->ready.pop.local .elock , proc->ready.pop.local .elock , __ATOMIC_SEQ_CST ); proc->ready.pop.local .elock = 0; 80 __atomic_fetch_add( &cltr->ready.pop.local .eempty , proc->ready.pop.local .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.local .eempty = 0; 81 __atomic_fetch_add( &cltr->ready.pop.local .espec , proc->ready.pop.local .espec , __ATOMIC_SEQ_CST ); proc->ready.pop.local .espec = 0; 82 __atomic_fetch_add( &cltr->ready.pop.help .attempt, proc->ready.pop.help .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.help .attempt = 0; 83 __atomic_fetch_add( &cltr->ready.pop.help .success, proc->ready.pop.help .success, __ATOMIC_SEQ_CST ); proc->ready.pop.help .success = 0; 84 __atomic_fetch_add( &cltr->ready.pop.help .elock , proc->ready.pop.help .elock , __ATOMIC_SEQ_CST ); proc->ready.pop.help .elock = 0; 85 __atomic_fetch_add( &cltr->ready.pop.help .eempty , proc->ready.pop.help .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.help .eempty = 0; 86 __atomic_fetch_add( &cltr->ready.pop.help .espec , proc->ready.pop.help .espec , __ATOMIC_SEQ_CST ); proc->ready.pop.help .espec = 0; 87 __atomic_fetch_add( &cltr->ready.pop.steal .attempt, proc->ready.pop.steal .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .attempt = 0; 88 __atomic_fetch_add( &cltr->ready.pop.steal .success, proc->ready.pop.steal .success, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .success = 0; 89 __atomic_fetch_add( &cltr->ready.pop.steal .elock , proc->ready.pop.steal .elock , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .elock = 0; 90 __atomic_fetch_add( &cltr->ready.pop.steal .eempty , proc->ready.pop.steal .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .eempty = 0; 91 __atomic_fetch_add( &cltr->ready.pop.steal .espec , proc->ready.pop.steal .espec , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .espec = 0; 92 __atomic_fetch_add( &cltr->ready.pop.search.attempt, proc->ready.pop.search.attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.search.attempt = 0; 93 __atomic_fetch_add( &cltr->ready.pop.search.success, proc->ready.pop.search.success, __ATOMIC_SEQ_CST ); proc->ready.pop.search.success = 0; 94 __atomic_fetch_add( &cltr->ready.pop.search.elock , proc->ready.pop.search.elock , __ATOMIC_SEQ_CST ); proc->ready.pop.search.elock = 0; 95 __atomic_fetch_add( &cltr->ready.pop.search.eempty , proc->ready.pop.search.eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.search.eempty = 0; 96 __atomic_fetch_add( &cltr->ready.pop.search.espec , proc->ready.pop.search.espec , __ATOMIC_SEQ_CST ); proc->ready.pop.search.espec = 0; 55 97 __atomic_fetch_add( &cltr->ready.threads.migration , proc->ready.threads.migration , __ATOMIC_SEQ_CST ); proc->ready.threads.migration = 0; 98 __atomic_fetch_add( &cltr->ready.threads.extunpark , proc->ready.threads.extunpark , __ATOMIC_SEQ_CST ); proc->ready.threads.extunpark = 0; 99 __atomic_fetch_add( &cltr->ready.threads.threads , proc->ready.threads.threads , __ATOMIC_SEQ_CST ); proc->ready.threads.threads = 0; 56 100 __atomic_fetch_add( &cltr->ready.sleep.halts , proc->ready.sleep.halts , __ATOMIC_SEQ_CST ); proc->ready.sleep.halts = 0; 57 101 __atomic_fetch_add( &cltr->ready.sleep.cancels , proc->ready.sleep.cancels , __ATOMIC_SEQ_CST ); proc->ready.sleep.cancels = 0; … … 60 104 61 105 #if defined(CFA_HAVE_LINUX_IO_URING_H) 62 __atomic_fetch_add( &cltr->io.submit_q.submit_avg.rdy , proc->io.submit_q.submit_avg.rdy , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.rdy = 0; 63 __atomic_fetch_add( &cltr->io.submit_q.submit_avg.csm , proc->io.submit_q.submit_avg.csm , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.csm = 0; 64 __atomic_fetch_add( &cltr->io.submit_q.submit_avg.avl , proc->io.submit_q.submit_avg.avl , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.avl = 0; 65 __atomic_fetch_add( &cltr->io.submit_q.submit_avg.cnt , proc->io.submit_q.submit_avg.cnt , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.cnt = 0; 66 __atomic_fetch_add( &cltr->io.submit_q.look_avg.val , proc->io.submit_q.look_avg.val , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.val = 0; 67 __atomic_fetch_add( &cltr->io.submit_q.look_avg.cnt , proc->io.submit_q.look_avg.cnt , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.cnt = 0; 68 __atomic_fetch_add( &cltr->io.submit_q.look_avg.block , proc->io.submit_q.look_avg.block , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.block = 0; 69 __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.val , proc->io.submit_q.alloc_avg.val , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.val = 0; 70 __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.cnt , proc->io.submit_q.alloc_avg.cnt , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.cnt = 0; 71 __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.block , proc->io.submit_q.alloc_avg.block , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.block = 0; 72 __atomic_fetch_add( &cltr->io.submit_q.helped , proc->io.submit_q.helped , __ATOMIC_SEQ_CST ); proc->io.submit_q.helped = 0; 73 __atomic_fetch_add( &cltr->io.submit_q.leader , proc->io.submit_q.leader , __ATOMIC_SEQ_CST ); proc->io.submit_q.leader = 0; 74 __atomic_fetch_add( &cltr->io.submit_q.busy , proc->io.submit_q.busy , __ATOMIC_SEQ_CST ); proc->io.submit_q.busy = 0; 75 __atomic_fetch_add( &cltr->io.complete_q.completed_avg.val, proc->io.complete_q.completed_avg.val, __ATOMIC_SEQ_CST ); proc->io.complete_q.completed_avg.val = 0; 76 __atomic_fetch_add( &cltr->io.complete_q.completed_avg.cnt, proc->io.complete_q.completed_avg.cnt, __ATOMIC_SEQ_CST ); proc->io.complete_q.completed_avg.cnt = 0; 77 __atomic_fetch_add( &cltr->io.complete_q.blocks , proc->io.complete_q.blocks , __ATOMIC_SEQ_CST ); proc->io.complete_q.blocks = 0; 106 __atomic_fetch_add( &cltr->io.alloc.fast , proc->io.alloc.fast , __ATOMIC_SEQ_CST ); proc->io.alloc.fast = 0; 107 __atomic_fetch_add( &cltr->io.alloc.slow , proc->io.alloc.slow , __ATOMIC_SEQ_CST ); proc->io.alloc.slow = 0; 108 __atomic_fetch_add( &cltr->io.alloc.fail , proc->io.alloc.fail , __ATOMIC_SEQ_CST ); proc->io.alloc.fail = 0; 109 __atomic_fetch_add( &cltr->io.alloc.revoke , proc->io.alloc.revoke , __ATOMIC_SEQ_CST ); proc->io.alloc.revoke = 0; 110 __atomic_fetch_add( &cltr->io.alloc.block , proc->io.alloc.block , __ATOMIC_SEQ_CST ); proc->io.alloc.block = 0; 111 __atomic_fetch_add( &cltr->io.submit.fast , proc->io.submit.fast , __ATOMIC_SEQ_CST ); proc->io.submit.fast = 0; 112 __atomic_fetch_add( &cltr->io.submit.slow , proc->io.submit.slow , __ATOMIC_SEQ_CST ); proc->io.submit.slow = 0; 113 __atomic_fetch_add( &cltr->io.flush.external , proc->io.flush.external , __ATOMIC_SEQ_CST ); proc->io.flush.external = 0; 114 __atomic_fetch_add( &cltr->io.calls.flush , proc->io.calls.flush , __ATOMIC_SEQ_CST ); proc->io.calls.flush = 0; 115 __atomic_fetch_add( &cltr->io.calls.submitted , proc->io.calls.submitted , __ATOMIC_SEQ_CST ); proc->io.calls.submitted = 0; 116 __atomic_fetch_add( &cltr->io.calls.drain , proc->io.calls.drain , __ATOMIC_SEQ_CST ); proc->io.calls.drain = 0; 117 __atomic_fetch_add( &cltr->io.calls.completed , proc->io.calls.completed , __ATOMIC_SEQ_CST ); proc->io.calls.completed = 0; 118 __atomic_fetch_add( &cltr->io.calls.errors.busy, proc->io.calls.errors.busy, __ATOMIC_SEQ_CST ); proc->io.calls.errors.busy = 0; 119 __atomic_fetch_add( &cltr->io.poller.sleeps , proc->io.poller.sleeps , __ATOMIC_SEQ_CST ); proc->io.poller.sleeps = 0; 78 120 #endif 79 121 } 80 122 123 #define eng3(X) (ws(3, 3, unit(eng( X )))) 124 81 125 void __print_stats( struct __stats_t * stats, int flags, const char * type, const char * name, void * id ) with( *stats ) { 82 126 127 char buf[1024]; 128 ostrstream sstr = { buf, 1024 }; 129 83 130 if( flags & CFA_STATS_READY_Q ) { 84 double push_sur = (100.0 * ((double)ready.pick.push.success) / ready.pick.push.attempt); 85 double pop_sur = (100.0 * ((double)ready.pick.pop .success) / ready.pick.pop .attempt); 86 87 double push_len = ((double)ready.pick.push.attempt) / ready.pick.push.success; 88 double pop_len = ((double)ready.pick.pop .attempt) / ready.pick.pop .success; 89 90 double lpush_sur = (100.0 * ((double)ready.pick.push.lsuccess) / ready.pick.push.local); 91 double lpop_sur = (100.0 * ((double)ready.pick.pop .lsuccess) / ready.pick.pop .local); 92 93 double lpush_len = ((double)ready.pick.push.local) / ready.pick.push.lsuccess; 94 double lpop_len = ((double)ready.pick.pop .local) / ready.pick.pop .lsuccess; 95 96 __cfaabi_bits_print_safe( STDOUT_FILENO, 97 "----- %s \"%s\" (%p) - Ready Q Stats -----\n" 98 "- total threads run : %'15" PRIu64 "\n" 99 "- total threads scheduled: %'15" PRIu64 "\n" 100 "- push average probe len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n" 101 "- pop average probe len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n" 102 "- local push avg prb len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n" 103 "- local pop avg prb len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n" 104 "- thread migrations : %'15" PRIu64 "\n" 105 "- Idle Sleep -\n" 106 "-- halts : %'15" PRIu64 "\n" 107 "-- cancelled halts : %'15" PRIu64 "\n" 108 "-- schedule wake : %'15" PRIu64 "\n" 109 "-- wake on exit : %'15" PRIu64 "\n" 110 "\n" 111 , type, name, id 112 , ready.pick.pop.success 113 , ready.pick.push.success 114 , push_len, push_sur, ready.pick.push.attempt 115 , pop_len , pop_sur , ready.pick.pop .attempt 116 , lpush_len, lpush_sur, ready.pick.push.local 117 , lpop_len , lpop_sur , ready.pick.pop .local 118 , ready.threads.migration 119 , ready.sleep.halts, ready.sleep.cancels, ready.sleep.wakes, ready.sleep.exits 120 ); 131 132 sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - Ready Q Stats -----"; 133 134 uint64_t totalR = ready.pop.local.success + ready.pop.help.success + ready.pop.steal.success + ready.pop.search.success; 135 uint64_t totalS = ready.push.local.success + ready.push.share.success + ready.push.extrn.success; 136 sstr | "- totals : " | eng3(totalR) | "run," | eng3(totalS) | "schd (" | eng3(ready.push.extrn.success) | "ext," | eng3(ready.threads.migration) | "mig," | eng3(ready.threads.extunpark) | " eupk)"; 137 138 double push_len = ((double)ready.push.local.attempt + ready.push.share.attempt + ready.push.extrn.attempt) / totalS; 139 double sLcl_len = ready.push.local.success ? ((double)ready.push.local.attempt) / ready.push.local.success : 0; 140 double sOth_len = ready.push.share.success ? ((double)ready.push.share.attempt) / ready.push.share.success : 0; 141 double sExt_len = ready.push.extrn.success ? ((double)ready.push.extrn.attempt) / ready.push.extrn.success : 0; 142 sstr | "- push avg : " | ws(3, 3, push_len) 143 | "- l: " | eng3(ready.push.local.attempt) | " (" | ws(3, 3, sLcl_len) | ")" 144 | ", s: " | eng3(ready.push.share.attempt) | " (" | ws(3, 3, sOth_len) | ")" 145 | ", e: " | eng3(ready.push.extrn.attempt) | " (" | ws(3, 3, sExt_len) | ")"; 146 147 double rLcl_pc = (100.0 * (double)ready.pop.local .success) / totalR; 148 sstr | "- local : " | eng3(ready.pop.local .success) | "-"| ws(3, 3, rLcl_pc) | '%' 149 | " (" | eng3(ready.pop.local .attempt) | " try," | eng3(ready.pop.local .espec) | " spc," | eng3(ready.pop.local .elock) | " lck," | eng3(ready.pop.local .eempty) | " ept)"; 150 double rHlp_pc = (100.0 * (double)ready.pop.help .success) / totalR; 151 sstr | "- help : " | eng3(ready.pop.help .success) | "-"| ws(3, 3, rHlp_pc) | '%' 152 | " (" | eng3(ready.pop.help .attempt) | " try," | eng3(ready.pop.help .espec) | " spc," | eng3(ready.pop.help .elock) | " lck," | eng3(ready.pop.help .eempty) | " ept)"; 153 double rStl_pc = (100.0 * (double)ready.pop.steal .success) / totalR; 154 sstr | "- steal : " | eng3(ready.pop.steal .success) | "-"| ws(3, 3, rStl_pc) | '%' 155 | " (" | eng3(ready.pop.steal .attempt) | " try," | eng3(ready.pop.steal .espec) | " spc," | eng3(ready.pop.steal .elock) | " lck," | eng3(ready.pop.steal .eempty) | " ept)"; 156 double rSch_pc = (100.0 * (double)ready.pop.search.success) / totalR; 157 sstr | "- search : " | eng3(ready.pop.search.success) | "-"| ws(3, 3, rSch_pc) | '%' 158 | " (" | eng3(ready.pop.search.attempt) | " try," | eng3(ready.pop.search.espec) | " spc," | eng3(ready.pop.search.elock) | " lck," | eng3(ready.pop.search.eempty) | " ept)"; 159 160 sstr | "- Idle Slp : " | eng3(ready.sleep.halts) | "halt," | eng3(ready.sleep.cancels) | "cancel," | eng3(ready.sleep.wakes) | "wake," | eng3(ready.sleep.exits) | "exit"; 161 sstr | nl; 121 162 } 122 163 123 164 #if defined(CFA_HAVE_LINUX_IO_URING_H) 124 165 if( flags & CFA_STATS_IO ) { 125 double avgrdy = ((double)io.submit_q.submit_avg.rdy) / io.submit_q.submit_avg.cnt; 126 double avgcsm = ((double)io.submit_q.submit_avg.csm) / io.submit_q.submit_avg.cnt; 127 128 double lavgv = 0; 129 double lavgb = 0; 130 if(io.submit_q.look_avg.cnt != 0) { 131 lavgv = ((double)io.submit_q.look_avg.val ) / io.submit_q.look_avg.cnt; 132 lavgb = ((double)io.submit_q.look_avg.block) / io.submit_q.look_avg.cnt; 133 } 134 135 double aavgv = 0; 136 double aavgb = 0; 137 if(io.submit_q.alloc_avg.cnt != 0) { 138 aavgv = ((double)io.submit_q.alloc_avg.val ) / io.submit_q.alloc_avg.cnt; 139 aavgb = ((double)io.submit_q.alloc_avg.block) / io.submit_q.alloc_avg.cnt; 140 } 141 142 __cfaabi_bits_print_safe( STDOUT_FILENO, 143 "----- %s \"%s\" (%p) - I/O Stats -----\n" 144 "- total submit calls : %'15" PRIu64 "\n" 145 "- avg ready entries : %'18.2lf\n" 146 "- avg submitted entries : %'18.2lf\n" 147 "- total helped entries : %'15" PRIu64 "\n" 148 "- total leader entries : %'15" PRIu64 "\n" 149 "- total busy submit : %'15" PRIu64 "\n" 150 "- total ready search : %'15" PRIu64 "\n" 151 "- avg ready search len : %'18.2lf\n" 152 "- avg ready search block : %'18.2lf\n" 153 "- total alloc search : %'15" PRIu64 "\n" 154 "- avg alloc search len : %'18.2lf\n" 155 "- avg alloc search block : %'18.2lf\n" 156 "- total wait calls : %'15" PRIu64 "\n" 157 "- avg completion/wait : %'18.2lf\n" 158 "- total completion blocks: %'15" PRIu64 "\n" 159 "\n" 160 , type, name, id 161 , io.submit_q.submit_avg.cnt 162 , avgrdy, avgcsm 163 , io.submit_q.helped, io.submit_q.leader, io.submit_q.busy 164 , io.submit_q.look_avg.cnt 165 , lavgv, lavgb 166 , io.submit_q.alloc_avg.cnt 167 , aavgv, aavgb 168 , io.complete_q.completed_avg.cnt 169 , ((double)io.complete_q.completed_avg.val) / io.complete_q.completed_avg.cnt 170 , io.complete_q.blocks 171 ); 166 sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - I/O Stats -----"; 167 168 uint64_t total_allocs = io.alloc.fast + io.alloc.slow; 169 double avgfasta = (100.0 * (double)io.alloc.fast) / total_allocs; 170 sstr | "- total allocations : " | eng3(io.alloc.fast) | "fast," | eng3(io.alloc.slow) | "slow (" | ws(3, 3, avgfasta) | "%)"; 171 sstr | "- failures : " | eng3(io.alloc.fail) | "oom, " | eng3(io.alloc.revoke) | "rvk, " | eng3(io.alloc.block) | "blk"; 172 173 uint64_t total_submits = io.submit.fast + io.submit.slow; 174 double avgfasts = (100.0 * (double)io.submit.fast) / total_submits; 175 sstr | "- total submits : " | eng3(io.submit.fast) | "fast," | eng3(io.submit.slow) | "slow (" | ws(3, 3, avgfasts) | "%)"; 176 sstr | "- flush external : " | eng3(io.flush.external); 177 178 sstr | "- io_uring_enter : " | eng3(io.calls.flush) | " (" | eng3(io.calls.drain) | ", " | eng3(io.calls.errors.busy) | " EBUSY)"; 179 180 double avgsubs = ((double)io.calls.submitted) / io.calls.flush; 181 double avgcomp = ((double)io.calls.completed) / io.calls.drain; 182 sstr | "- submits : " | eng3(io.calls.submitted) | "(" | ws(3, 3, avgsubs) | "/flush)"; 183 sstr | "- completes : " | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)"; 184 185 sstr | "- poller sleeping : " | eng3(io.poller.sleeps); 186 sstr | nl; 172 187 } 173 188 #endif 189 190 if(flags) write( sstr, stdout ); 174 191 } 192 193 #if defined(CFA_STATS_ARRAY) 194 extern "C" { 195 #include <stdio.h> 196 #include <errno.h> 197 #include <sys/stat.h> 198 #include <fcntl.h> 199 } 200 201 void __flush_stat( struct __stats_t * this, const char * name, void * handle) { 202 int ret = mkdir(".cfadata", 0755); 203 if(ret < 0 && errno != EEXIST) abort("Failed to create directory .cfadata: %d\n", errno); 204 205 char filename[100]; 206 snprintf(filename, 100, ".cfadata/%s%p.data", name, handle); 207 208 int fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0644); 209 if(fd < 0) abort("Failed to create file %s: %d\n", filename, errno); 210 211 for(i; this->array.cnt) { 212 char line[100]; 213 size_t n = snprintf(line, 100, "%llu, %lld\n", this->array.values[i].ts, this->array.values[i].value); 214 write(fd, line, n); 215 } 216 217 this->array.cnt = 0; 218 close(fd); 219 } 220 221 static __spinlock_t stats_lock; 222 223 void __push_stat( struct __stats_t * this, int64_t value, bool external, const char * name, void * handle ) { 224 if(external) lock(stats_lock __cfaabi_dbg_ctx2); 225 226 if( this->array.cnt >= CFA_STATS_ARRAY ) __flush_stat( this, name, handle ); 227 228 size_t idx = this->array.cnt; 229 this->array.cnt++; 230 231 if(external) unlock(stats_lock); 232 233 this->array.values[idx].ts = rdtscl(); 234 this->array.values[idx].value = value; 235 } 236 #endif 175 237 #endif -
libcfa/src/concurrency/stats.hfa
rfeacef9 r5407cdc 1 1 #pragma once 2 3 // #define CFA_STATS_ARRAY 10000 2 4 3 5 #include <stdint.h> … … 14 16 static inline void __print_stats( struct __stats_t *, int, const char *, const char *, void * ) {} 15 17 #else 18 struct __stats_readyQ_pop_t { 19 // number of attemps at poping something 20 volatile uint64_t attempt; 16 21 17 struct __attribute__((aligned(64))) __stats_readQ_t { 22 // number of successes at poping 23 volatile uint64_t success; 24 25 // number of attempts failed due to the lock being held 26 volatile uint64_t elock; 27 28 // number of attempts failed due to the queue being empty (lock held) 29 volatile uint64_t eempty; 30 31 // number of attempts failed due to the queue looking empty (lock not held) 32 volatile uint64_t espec; 33 }; 34 35 struct __attribute__((aligned(64))) __stats_readyQ_t { 36 // Push statistic 18 37 struct { 19 // Push statistic20 38 struct { 21 // number of attemps at pushing something 39 // number of attemps at pushing something to preferred queues 22 40 volatile uint64_t attempt; 23 41 24 // number of successes at pushing 42 // number of successes at pushing to preferred queues 25 43 volatile uint64_t success; 44 } 45 // Stats for local queue within cluster 46 local, 26 47 27 // number of attemps at pushing something to preferred queues28 volatile uint64_t local;48 // Stats for non-local queues within cluster 49 share, 29 50 30 // number of successes at pushing to preferred queues31 volatile uint64_t lsuccess;32 51 // Stats from outside cluster 52 extrn; 53 } push; 33 54 34 // Pop statistic 35 struct { 36 // number of reads of the mask 37 // picking an empty __cfa_readyQ_mask_t counts here 38 // but not as an attempt 39 volatile uint64_t probe; 55 // Pop statistic 56 struct { 57 // pop from local queue 58 __stats_readyQ_pop_t local; 40 59 41 // number of attemps at poping something42 volatile uint64_t attempt;60 // pop before looking at local queue 61 __stats_readyQ_pop_t help; 43 62 44 // number of successes at poping45 volatile uint64_t success;63 // pop from some other queue 64 __stats_readyQ_pop_t steal; 46 65 47 // number of attemps at poping something to preferred queues 48 volatile uint64_t local; 66 // pop when searching queues sequentially 67 __stats_readyQ_pop_t search; 68 } pop; 49 69 50 // number of successes at poping to preferred queues51 volatile uint64_t lsuccess;52 } pop;53 } pick;54 70 struct { 55 71 volatile uint64_t migration; 72 volatile uint64_t extunpark; 73 volatile int64_t threads; // number of threads in the system, includes only local change 56 74 } threads; 57 75 struct { … … 66 84 struct __attribute__((aligned(64))) __stats_io_t{ 67 85 struct { 86 volatile uint64_t fast; 87 volatile uint64_t slow; 88 volatile uint64_t fail; 89 volatile uint64_t revoke; 90 volatile uint64_t block; 91 } alloc; 92 struct { 93 volatile uint64_t fast; 94 volatile uint64_t slow; 95 } submit; 96 struct { 97 volatile uint64_t external; 98 } flush; 99 struct { 100 volatile uint64_t drain; 101 volatile uint64_t completed; 102 volatile uint64_t flush; 103 volatile uint64_t submitted; 68 104 struct { 69 volatile uint64_t rdy; 70 volatile uint64_t csm; 71 volatile uint64_t avl; 72 volatile uint64_t cnt; 73 } submit_avg; 74 struct { 75 volatile uint64_t val; 76 volatile uint64_t cnt; 77 volatile uint64_t block; 78 } look_avg; 79 struct { 80 volatile uint64_t val; 81 volatile uint64_t cnt; 82 volatile uint64_t block; 83 } alloc_avg; 84 volatile uint64_t helped; 85 volatile uint64_t leader; 86 volatile uint64_t busy; 87 } submit_q; 105 volatile uint64_t busy; 106 } errors; 107 } calls; 88 108 struct { 89 struct { 90 volatile uint64_t val; 91 volatile uint64_t cnt; 92 } completed_avg; 93 volatile uint64_t blocks; 94 } complete_q; 109 volatile uint64_t sleeps; 110 } poller; 111 }; 112 #endif 113 114 #if defined(CFA_STATS_ARRAY) 115 struct __stats_elem_t { 116 long long int ts; 117 int64_t value; 95 118 }; 96 119 #endif 97 120 98 121 struct __attribute__((aligned(128))) __stats_t { 99 __stats_read Q_t ready;122 __stats_readyQ_t ready; 100 123 #if defined(CFA_HAVE_LINUX_IO_URING_H) 101 124 __stats_io_t io; 102 125 #endif 126 127 #if defined(CFA_STATS_ARRAY) 128 struct { 129 __stats_elem_t * values; 130 volatile size_t cnt; 131 } array; 132 #endif 133 103 134 }; 104 135 … … 106 137 void __tally_stats( struct __stats_t *, struct __stats_t * ); 107 138 void __print_stats( struct __stats_t *, int, const char *, const char *, void * ); 139 #if defined(CFA_STATS_ARRAY) 140 void __push_stat ( struct __stats_t *, int64_t value, bool external, const char * name, void * handle); 141 void __flush_stat( struct __stats_t *, const char *, void * ); 142 #else 143 static inline void __push_stat ( struct __stats_t *, int64_t, bool, const char *, void * ) {} 144 static inline void __flush_stat( struct __stats_t *, const char *, void * ) {} 145 #endif 108 146 #endif 109 147 -
libcfa/src/concurrency/thread.cfa
rfeacef9 r5407cdc 39 39 link.next = 0p; 40 40 link.prev = 0p; 41 link.preferred = -1; 41 link.preferred = -1u; 42 last_proc = 0p; 42 43 #if defined( __CFA_WITH_VERIFY__ ) 43 44 canary = 0x0D15EA5E0D15EA5Ep; … … 62 63 } 63 64 64 FORALL_DATA_INSTANCE(ThreadCancelled, (thread_t &), (thread_t))65 66 65 forall(T &) 67 66 void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src) { … … 73 72 forall(T &) 74 73 const char * msg(ThreadCancelled(T) *) { 75 return "ThreadCancelled ";74 return "ThreadCancelled(...)"; 76 75 } 77 76 78 77 forall(T &) 79 78 static void default_thread_cancel_handler(ThreadCancelled(T) & ) { 79 // Improve this error message, can I do formatting? 80 80 abort( "Unhandled thread cancellation.\n" ); 81 81 } 82 82 83 forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))) 83 forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) 84 | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); }) 84 85 void ?{}( thread_dtor_guard_t & this, 85 86 T & thrd, void(*cancelHandler)(ThreadCancelled(T) &)) { 86 87 $monitor * m = get_monitor(thrd); 87 88 $thread * desc = get_thread(thrd); 88 89 … … 103 104 } 104 105 desc->state = Cancelled; 105 void(*defaultResumptionHandler)(ThreadCancelled(T) &) = 106 void(*defaultResumptionHandler)(ThreadCancelled(T) &) = 106 107 join ? cancelHandler : default_thread_cancel_handler; 107 108 109 // TODO: Remove explitate vtable set once trac#186 is fixed. 108 110 ThreadCancelled(T) except; 109 // TODO: Remove explitate vtable set once trac#186 is fixed. 110 except.virtual_table = &get_exception_vtable(&except); 111 except.virtual_table = &_default_vtable; 111 112 except.the_thread = &thrd; 112 113 except.the_exception = __cfaehm_cancellation_exception( cancellation ); 113 throwResume except; 114 // Why is this cast required? 115 throwResume (ThreadCancelled(T) &)except; 114 116 115 117 except.the_exception->virtual_table->free( except.the_exception ); … … 134 136 /* paranoid */ verify( this_thrd->context.SP ); 135 137 136 __schedule_thread( this_thrd );137 enable_interrupts( __cfaabi_dbg_ctx);138 schedule_thread$( this_thrd ); 139 enable_interrupts(); 138 140 } 139 141 … … 158 160 159 161 //----------------------------------------------------------------------------- 160 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))) 162 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) 163 | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); }) 161 164 T & join( T & this ) { 162 165 thread_dtor_guard_t guard = { this, defaultResumptionHandler }; … … 167 170 disable_interrupts(); 168 171 uint64_t ret = __tls_rand(); 169 enable_interrupts( __cfaabi_dbg_ctx);172 enable_interrupts(); 170 173 return ret; 171 174 } -
libcfa/src/concurrency/thread.hfa
rfeacef9 r5407cdc 32 32 }; 33 33 34 FORALL_DATA_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (34 EHM_FORALL_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) ( 35 35 thread_t * the_thread; 36 36 exception_t * the_exception; … … 42 42 forall(T &) 43 43 const char * msg(ThreadCancelled(T) *); 44 45 // define that satisfies the trait without using the thread keyword46 #define DECL_THREAD(X) $thread* get_thread(X& this) __attribute__((const)) { return &this.__thrd; } void main(X& this)47 44 48 45 // Inline getters for threads/coroutines/monitors … … 82 79 }; 83 80 84 forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) ) 81 forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) 82 | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); }) 85 83 void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) ); 86 84 void ^?{}( thread_dtor_guard_t & this ); … … 128 126 //---------- 129 127 // join 130 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) ) 128 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) 129 | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); }) 131 130 T & join( T & this ); 132 131 -
libcfa/src/containers/list.hfa
rfeacef9 r5407cdc 83 83 (this.is_terminator){ 1 }; 84 84 } 85 forall ( tInit | { void ?{}( $mgd_link(tE) &, tInit); } ) 86 static inline void ?=?( $mgd_link(tE) &this, tInit i ) { 87 ^?{}( this ); 88 ?{}( this, i ); 85 static inline void ?=?( $mgd_link(tE) &this, tE* elem ) { 86 this.elem = elem ; 87 this.terminator = 0p; 88 this.is_terminator = 0; 89 } 90 static inline void ?=?( $mgd_link(tE) &this, void * terminator ) { 91 this.elem = 0p; 92 this.terminator = terminator; 93 this.is_terminator = 1; 89 94 } 90 95 struct $dlinks { … … 181 186 182 187 static inline void insert_after(Tnode &list_pos, Telem &to_insert) { 183 assert(&list_pos != 0p);184 assert(&to_insert != 0p);188 verify (&list_pos != 0p); 189 verify (&to_insert != 0p); 185 190 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 186 assert($prev_link(singleton_to_insert).elem == 0p);187 assert($next_link(singleton_to_insert).elem == 0p);191 verify($prev_link(singleton_to_insert).elem == 0p); 192 verify($next_link(singleton_to_insert).elem == 0p); 188 193 $prev_link(singleton_to_insert) = & $tempcv_n2e(list_pos); 189 194 $next_link(singleton_to_insert) = $next_link(list_pos); … … 204 209 205 210 static inline void insert_before(Tnode &list_pos, Telem &to_insert) { 206 assert(&list_pos != 0p);207 assert(&to_insert != 0p);211 verify (&list_pos != 0p); 212 verify (&to_insert != 0p); 208 213 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 209 assert($prev_link(singleton_to_insert).elem == 0p);210 assert($next_link(singleton_to_insert).elem == 0p);214 verify($prev_link(singleton_to_insert).elem == 0p); 215 verify($next_link(singleton_to_insert).elem == 0p); 211 216 $next_link(singleton_to_insert) = & $tempcv_n2e(list_pos); 212 217 $prev_link(singleton_to_insert) = $prev_link(list_pos); … … 227 232 228 233 static inline void insert_first(dlist(Tnode, Telem) &list, Telem &to_insert) { 229 assert(&list != 0p);230 assert(&to_insert != 0p);234 verify (&list != 0p); 235 verify (&to_insert != 0p); 231 236 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 232 assert($prev_link(singleton_to_insert).elem == 0p);233 assert($next_link(singleton_to_insert).elem == 0p);237 verify($prev_link(singleton_to_insert).elem == 0p); 238 verify($next_link(singleton_to_insert).elem == 0p); 234 239 235 240 $prev_link(singleton_to_insert) = (void*) &list; … … 249 254 250 255 static inline void insert_last(dlist(Tnode, Telem) &list, Telem &to_insert) { 251 assert(&list != 0p);252 assert(&to_insert != 0p);256 verify (&list != 0p); 257 verify (&to_insert != 0p); 253 258 Tnode &singleton_to_insert = $tempcv_e2n(to_insert); 254 assert($next_link(singleton_to_insert).elem == 0p);255 assert($prev_link(singleton_to_insert).elem == 0p);259 verify($next_link(singleton_to_insert).elem == 0p); 260 verify($prev_link(singleton_to_insert).elem == 0p); 256 261 257 262 $next_link(singleton_to_insert) = (void*) &list; … … 271 276 272 277 static inline void remove(Tnode &list_pos) { 273 assert( &list_pos != 0p );278 verify( &list_pos != 0p ); 274 279 275 280 $mgd_link(Telem) &incoming_from_prev = *0p; … … 308 313 309 314 static inline bool ?`is_empty(dlist(Tnode, Telem) &list) { 310 assert( &list != 0p );315 verify( &list != 0p ); 311 316 $dlinks(Telem) *listLinks = & list.$links; 312 317 if (listLinks->next.is_terminator) { 313 assert(listLinks->prev.is_terminator);314 assert(listLinks->next.terminator);315 assert(listLinks->prev.terminator);318 verify(listLinks->prev.is_terminator); 319 verify(listLinks->next.terminator); 320 verify(listLinks->prev.terminator); 316 321 return true; 317 322 } else { 318 assert(!listLinks->prev.is_terminator);319 assert(listLinks->next.elem);320 assert(listLinks->prev.elem);323 verify(!listLinks->prev.is_terminator); 324 verify(listLinks->next.elem); 325 verify(listLinks->prev.elem); 321 326 return false; 322 327 } … … 324 329 325 330 static inline Telem & pop_first(dlist(Tnode, Telem) &list) { 326 assert( &list != 0p );327 assert( !list`is_empty );331 verify( &list != 0p ); 332 verify( !list`is_empty ); 328 333 $dlinks(Telem) *listLinks = & list.$links; 329 334 Telem & first = *listLinks->next.elem; … … 334 339 335 340 static inline Telem & pop_last(dlist(Tnode, Telem) &list) { 336 assert( &list != 0p );337 assert( !list`is_empty );341 verify( &list != 0p ); 342 verify( !list`is_empty ); 338 343 $dlinks(Telem) *listLinks = & list.$links; 339 344 Telem & last = *listLinks->prev.elem; -
libcfa/src/exception.c
rfeacef9 r5407cdc 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 27 16:27:00 202013 // Update Count : 3 512 // Last Modified On : Wed Feb 24 13:40:00 2021 13 // Update Count : 36 14 14 // 15 15 … … 26 26 #include "concurrency/invoke.h" 27 27 #include "stdhdr/assert.h" 28 #include "virtual.h" 28 29 29 30 #if defined( __ARM_ARCH ) … … 46 47 const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643; 47 48 48 // Base exception vtable is abstract, you should not have base exceptions. 49 struct __cfaehm_base_exception_t_vtable 50 ___cfaehm_base_exception_t_vtable_instance = { 51 .parent = NULL, 52 .size = 0, 53 .copy = NULL, 54 .free = NULL, 55 .msg = NULL 49 // Base Exception type id: 50 struct __cfa__parent_vtable __cfatid_exception_t = { 51 NULL, 56 52 }; 57 53 -
libcfa/src/exception.h
rfeacef9 r5407cdc 10 10 // Created On : Mon Jun 26 15:11:00 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Oct 27 14:45:00 202013 // Update Count : 1 112 // Last Modified On : Thr Apr 8 15:20:00 2021 13 // Update Count : 12 14 14 // 15 15 … … 29 29 struct __cfaehm_base_exception_t; 30 30 typedef struct __cfaehm_base_exception_t exception_t; 31 struct __cfa__parent_vtable; 31 32 struct __cfaehm_base_exception_t_vtable { 32 const struct __cfa ehm_base_exception_t_vtable * parent;33 const struct __cfa__parent_vtable * __cfavir_typeid; 33 34 size_t size; 34 35 void (*copy)(struct __cfaehm_base_exception_t *this, … … 40 41 struct __cfaehm_base_exception_t_vtable const * virtual_table; 41 42 }; 42 extern struct __cfaehm_base_exception_t_vtable 43 ___cfaehm_base_exception_t_vtable_instance; 43 extern struct __cfa__parent_vtable __cfatid_exception_t; 44 44 45 45 … … 104 104 /* The first field must be a pointer to a virtual table. 105 105 * That virtual table must be a decendent of the base exception virtual table. 106 * The virtual table must point at the prober type-id. 107 * None of these can be enforced in an assertion. 106 108 */ 107 virtualT const & get_exception_vtable(exceptT *);108 // Always returns the virtual table for this type (associated types hack).109 109 }; 110 110 -
libcfa/src/exception.hfa
rfeacef9 r5407cdc 10 10 // Created On : Thu Apr 7 10:25:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Aug 4 16:22:00 202013 // Update Count : 312 // Last Modified On : Thr Apr 8 15:16:00 2021 13 // Update Count : 4 14 14 // 15 15 … … 18 18 // ----------------------------------------------------------------------------------------------- 19 19 20 // TRIVIAL_EXCEPTION_DECLARATION(exception_name); 21 // Declare a trivial exception, one that adds no fields or features. 22 // This will make the exception visible and may go in a .hfa or .cfa file. 23 #define TRIVIAL_EXCEPTION_DECLARATION(...) \ 24 _EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__) 20 // EHM_EXCEPTION(exception_name)(fields...); 21 // Create an exception (a virtual structure that inherits from exception_t) 22 // with the given name and fields. 23 #define EHM_EXCEPTION(exception_name) \ 24 _EHM_TYPE_ID_STRUCT(exception_name, ); \ 25 _EHM_TYPE_ID_VALUE(exception_name, ); \ 26 _EHM_VIRTUAL_TABLE_STRUCT(exception_name, , ); \ 27 _EHM_EXCEPTION_STRUCT(exception_name, , ) 25 28 26 // TRIVIAL_EXCEPTION_INSTANCE(exception_name);27 // Create the trival exception. This must be used exactly once and should be used in a .cfa file,28 // as it creates the unique instance of the virtual table. 29 #define TRIVIAL_EXCEPTION_INSTANCE(...) _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__)29 // EHM_EXTERN_VTABLE(exception_name, table_name); 30 // Forward declare a virtual table called table_name for exception_name type. 31 #define EHM_EXTERN_VTABLE(exception_name, table_name) \ 32 _EHM_EXTERN_VTABLE(exception_name, , table_name) 30 33 31 // TRIVIAL_EXCEPTION(exception_name[, parent_name]); 32 // Does both of the above, a short hand if the exception is only used in one .cfa file. 33 // For legacy reasons this is the only one that official supports having a parent other than the 34 // base exception. This feature may be removed or changed. 35 #define TRIVIAL_EXCEPTION(...) \ 36 _EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__); \ 37 _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__) 34 // EHM_VIRTUAL_TABLE(exception_name, table_name); 35 // Define a virtual table called table_name for exception_name type. 36 #define EHM_VIRTUAL_TABLE(exception_name, table_name) \ 37 _EHM_DEFINE_COPY(exception_name, ) \ 38 _EHM_DEFINE_MSG(exception_name, ) \ 39 _EHM_VIRTUAL_TABLE(exception_name, , table_name) 38 40 39 // FORALL_TRIVIAL_EXCEPTION(exception_name, (assertions...), (parameters...)); 40 // Forward declare a polymorphic but otherwise trivial exception type. You must provide the entire 41 // assertion list (exactly what would go in the forall clause) and parameters list (only the 42 // parameter names from the assertion list, same order and comma seperated). This should be 43 // visible where ever use the exception. This just generates the polymorphic framework, see 44 // POLY_VTABLE_DECLARATION to allow instantiations. 45 #define FORALL_TRIVIAL_EXCEPTION(exception_name, assertions, parameters) \ 46 _FORALL_TRIVIAL_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, ) 41 // EHM_FORALL_EXCEPTION(exception_name, (assertions), (parameters))(fields...); 42 // As EHM_EXCEPTION but for polymorphic types instead of monomorphic ones. 43 // The assertions list should include all polymorphic parameters and 44 // assertions inside a parentisized list. Parameters should include all the 45 // polymorphic parameter names inside a parentisized list (same order). 46 #define EHM_FORALL_EXCEPTION(exception_name, assertions, parameters) \ 47 _EHM_TYPE_ID_STRUCT(exception_name, forall assertions); \ 48 _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall assertions, parameters); \ 49 _EHM_EXCEPTION_STRUCT(exception_name, forall assertions, parameters) 47 50 48 // FORALL_TRIVIAL_INSTANCE(exception_name, (assertions...), (parameters...)) 49 // Create the forall trivial exception. The assertion list and parameters must match. 50 // There must be exactly one use of this in a program for each exception type. This just 51 // generates the polymorphic framework, see POLY_VTABLE_INSTANCE to allow instantiations. 52 #define FORALL_TRIVIAL_INSTANCE(exception_name, assertions, parameters) \ 53 _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) 51 // EHM_FORALL_EXTERN_VTABLE(exception_name, (arguments), table_name); 52 // As EHM_EXTERN_VTABLE but for polymorphic types instead of monomorphic ones. 53 // Arguments should be the parentisized list of polymorphic arguments. 54 #define EHM_FORALL_EXTERN_VTABLE(exception_name, arguments, table_name) \ 55 _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) 54 56 55 // DATA_EXCEPTION(exception_name)(fields...); 56 // Forward declare an exception that adds fields but no features. The added fields go in the 57 // second argument list. The virtual table instance must be provided later (see VTABLE_INSTANCE). 58 #define DATA_EXCEPTION(...) _EXC_DISPATCH(_DATA_EXCEPTION, __VA_ARGS__) 57 // EHM_FORALL_VIRTUAL_TABLE(exception_name, (arguments), table_name); 58 // As EHM_VIRTUAL_TABLE but for polymorphic types instead of monomorphic ones. 59 // Arguments should be the parentisized list of polymorphic arguments. 60 #define EHM_FORALL_VIRTUAL_TABLE(exception_name, arguments, table_name) \ 61 _EHM_TYPE_ID_VALUE(exception_name, arguments); \ 62 _EHM_DEFINE_COPY(exception_name, arguments) \ 63 _EHM_DEFINE_MSG(exception_name, arguments) \ 64 _EHM_VIRTUAL_TABLE(exception_name, arguments, table_name) 59 65 60 // FORALL_DATA_EXCEPTION(exception_name, (assertions...), (parameters...))(fields...); 61 // Define a polymorphic exception that adds fields but no additional features. The assertion list 62 // and matching parameters must match. Then you can give the list of fields. This should be 63 // visible where ever you use the exception. This just generates the polymorphic framework, see 64 // POLY_VTABLE_DECLARATION to allow instantiations. 65 #define FORALL_DATA_EXCEPTION(exception_name, assertions, parameters) \ 66 _FORALL_DATA_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, ) 67 68 // FORALL_DATA_INSTANCE(exception_name, (assertions...), (parameters...)) 69 // Create a polymorphic data exception. The assertion list and parameters must match. This should 70 // appear once in each program. This just generates the polymorphic framework, see 71 // POLY_VTABLE_INSTANCE to allow instantiations. 72 #define FORALL_DATA_INSTANCE(exception_name, assertions, parameters) \ 73 _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) 74 75 // VTABLE_DECLARATION(exception_name)([new_features...]); 76 // Declare a virtual table type for an exception with exception_name. You may also add features 77 // (fields on the virtual table) by including them in the second list. 78 #define VTABLE_DECLARATION(...) _EXC_DISPATCH(_VTABLE_DECLARATION, __VA_ARGS__) 79 80 // VTABLE_INSTANCE(exception_name)(msg [, others...]); 81 // Create the instance of the virtual table. There must be exactly one instance of a virtual table 82 // for each exception type. This fills in most of the fields of the virtual table (uses ?=? and 83 // ^?{}) but you must provide the message function and any other fields added in the declaration. 84 #define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__) 85 86 // FORALL_VTABLE_DECLARATION(exception_name, (assertions...), (parameters...))([new_features...]); 87 // Declare a polymorphic virtual table type for an exception with exception_name, the given 88 // assertions and parameters. You may also add features (fields on the virtual table). This just 89 // generates the polymorphic framework, see POLY_VTABLE_DECLARATION to allow instantiations. 90 #define FORALL_VTABLE_DECLARATION(exception_name, assertions, parameters) \ 91 _FORALL_VTABLE_DECLARATION(exception_name, __cfaehm_base_exception_t, assertions, parameters, ) 92 93 // POLY_VTABLE_DECLARATION(exception_name, types...); 94 // Declares that an instantiation for this exception exists for the given types. This should be 95 // visible anywhere you use the instantiation of the exception is used. 96 #define POLY_VTABLE_DECLARATION(exception_name, ...) \ 97 VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable(exception_name(__VA_ARGS__) *); \ 98 extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name) 99 100 // POLY_VTABLE_INSTANCE(exception_name, types...)(msg [, others...]); 101 // Creates an instantiation for the given exception for the given types. This should occur only 102 // once in the entire program. You must fill in all features, message and any others given in the 103 // initial declaration. 104 #define POLY_VTABLE_INSTANCE(exception_name, ...) \ 105 _POLY_VTABLE_INSTANCE(exception_name, __cfaehm_base_exception_t, __VA_ARGS__) 106 107 // VTABLE_TYPE(exception_name) | VTABLE_NAME(exception_name) 108 // Get the name of the vtable type or the name of the vtable instance for an exception type. 109 #define VTABLE_TYPE(exception_name) struct _GLUE2(exception_name,_vtable) 110 #define VTABLE_NAME(exception_name) _GLUE3(_,exception_name,_vtable_instance) 111 112 // VTABLE_FIELD(exception_name); 113 // FORALL_VTABLE_FIELD(exception_name, (parameters-or-types)); 114 // The declaration of the virtual table field. Should be the first declaration in a virtual type. 115 #define VTABLE_FIELD(exception_name) VTABLE_TYPE(exception_name) const * virtual_table 116 #define FORALL_VTABLE_FIELD(exception_name, parameters) \ 117 VTABLE_TYPE(exception_name) parameters const * virtual_table 118 119 // VTABLE_INIT(object_reference, exception_name); 120 // Sets a virtual table field on an object to the virtual table instance for the type. 121 #define VTABLE_INIT(this, exception_name) (this).virtual_table = &VTABLE_NAME(exception_name) 122 123 // VTABLE_ASSERTION(exception_name, (parameters...)) 124 // The assertion that there is an instantiation of the vtable for the exception and types. 125 #define VTABLE_ASSERTION(exception_name, parameters) \ 126 { VTABLE_TYPE(exception_name) parameters VTABLE_NAME(exception_name); } 66 // EHM_DEFAULT_VTABLE(exception_name, (arguments)) 67 // Create a declaration for a (possibly polymorphic) default vtable. 68 #define EHM_DEFAULT_VTABLE(exception_name, arguments) \ 69 _EHM_VTABLE_TYPE(exception_name) arguments & const _default_vtable 127 70 128 71 // IS_EXCEPTION(exception_name [, (...parameters)]) … … 135 78 #define IS_TERMINATION_EXCEPTION(...) _IS_EXCEPTION(is_termination_exception, __VA_ARGS__, , ~) 136 79 137 // All internal helper macros begin with an underscore. 138 #define _CLOSE(...) __VA_ARGS__ } 139 #define _GLUE2(left, right) left##right 140 #define _GLUE3(left, middle, right) left##middle##right 141 #define _EXC_DISPATCH(to, ...) to(__VA_ARGS__,__cfaehm_base_exception_t,) 142 #define _UNPACK(...) __VA_ARGS__ 80 // Macros starting with a leading underscore are internal. 143 81 144 #define _TRIVIAL_EXCEPTION_DECLARATION(exception_name, parent_name, ...) \ 145 _VTABLE_DECLARATION(exception_name, parent_name)(); \ 146 struct exception_name { \ 147 VTABLE_FIELD(exception_name); \ 148 }; \ 149 void ?{}(exception_name & this); \ 150 const char * _GLUE2(exception_name,_msg)(exception_name * this) 82 // Create an exception type definition. must be tailing, can be polymorphic. 83 #define _EHM_EXCEPTION_STRUCT(exception_name, forall_clause, parameters) \ 84 forall_clause struct exception_name { \ 85 _EHM_VTABLE_TYPE(exception_name) parameters const * virtual_table; \ 86 _CLOSE 151 87 152 #define _TRIVIAL_EXCEPTION_INSTANCE(exception_name, parent_name, ...) \ 153 void ?{}(exception_name & this) { \ 154 VTABLE_INIT(this, exception_name); \ 155 } \ 156 const char * _GLUE2(exception_name,_msg)(exception_name * this) { \ 157 return #exception_name; \ 158 } \ 159 _VTABLE_INSTANCE(exception_name, parent_name,)(_GLUE2(exception_name,_msg)) 88 // Create a (possibly polymorphic) virtual table forward declaration. 89 #define _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) \ 90 extern const _EHM_VTABLE_TYPE(exception_name) arguments table_name 160 91 161 #define _FORALL_TRIVIAL_EXCEPTION(exception_name, parent_name, assertions, \ 162 parameters, parent_parameters) \ 163 _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \ 164 parameters, parent_parameters)(); \ 165 forall assertions struct exception_name { \ 166 FORALL_VTABLE_FIELD(exception_name, parameters); \ 167 }; \ 168 _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) 169 170 #define _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) \ 171 forall(_UNPACK assertions | \ 172 is_exception(exception_name parameters, VTABLE_TYPE(exception_name) parameters)) \ 173 void ?{}(exception_name parameters & this) 174 175 #define _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) \ 176 _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) { \ 177 (this).virtual_table = &get_exception_vtable(&this); \ 92 // Create a (possibly polymorphic) virtual table definition. 93 #define _EHM_VIRTUAL_TABLE(exception_type, arguments, table_name) \ 94 const _EHM_VTABLE_TYPE(exception_type) arguments table_name @= { \ 95 .__cfavir_typeid : &_EHM_TYPE_ID_NAME(exception_type), \ 96 .size : sizeof(struct exception_type arguments), \ 97 .copy : copy, \ 98 .^?{} : ^?{}, \ 99 .msg : msg, \ 178 100 } 179 101 180 #define _DATA_EXCEPTION(exception_name, parent_name, ...) \ 181 _VTABLE_DECLARATION(exception_name, parent_name)(); \ 182 struct exception_name { \ 183 VTABLE_FIELD(exception_name); \ 184 _CLOSE 102 // Create a (possibly polymorphic) copy function from an assignment operator. 103 #define _EHM_DEFINE_FORALL_COPY(exception_name, forall_clause, parameters) \ 104 forall_clause void copy(exception_name parameters * this, \ 105 exception_name parameters * that) { \ 106 *this = *that; \ 107 } 185 108 186 #define _FORALL_DATA_EXCEPTION(exception_name, parent_name, \ 187 assertions, parameters, parent_parameters) \ 188 _FORALL_VTABLE_DECLARATION(exception_name, parent_name, \ 189 assertions, parameters, parent_parameters)(); \ 190 _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters); \ 191 forall assertions struct exception_name { \ 192 FORALL_VTABLE_FIELD(exception_name, parameters); \ 193 _CLOSE 109 #define _EHM_DEFINE_COPY(exception_name, arguments) \ 110 void copy(exception_name arguments * this, exception_name arguments * that) { \ 111 *this = *that; \ 112 } 194 113 195 #define _VTABLE_DECLARATION(exception_name, parent_name, ...) \ 196 struct exception_name; \ 197 VTABLE_TYPE(exception_name); \ 198 VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *); \ 199 extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \ 200 VTABLE_TYPE(exception_name) { \ 201 VTABLE_TYPE(parent_name) const * parent; \ 202 size_t size; \ 203 void (*copy)(exception_name * this, exception_name * other); \ 204 void (*^?{})(exception_name & this); \ 205 const char * (*msg)(exception_name * this); \ 206 _CLOSE 114 // Create a (possibly polymorphic) msg function 115 #define _EHM_DEFINE_FORALL_MSG(exception_name, forall_clause, parameters) \ 116 forall_clause const char * msg(exception_name parameters * this) { \ 117 return #exception_name #parameters; \ 118 } 207 119 208 #define _VTABLE_INSTANCE(exception_name, parent_name, ...) \ 209 VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *) { \ 210 return VTABLE_NAME(exception_name); \ 211 } \ 212 void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \ 213 *this = *other; \ 214 } \ 215 VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name) @= { \ 216 &VTABLE_NAME(parent_name), sizeof(exception_name), \ 217 _GLUE2(exception_name,_copy), ^?{}, \ 218 _CLOSE 120 #define _EHM_DEFINE_MSG(exception_name, arguments) \ 121 const char * msg(exception_name arguments * this) { \ 122 return #exception_name #arguments; \ 123 } 219 124 220 #define _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \ 221 parameters, parent_parameters) \ 222 forall assertions struct exception_name; \ 223 forall assertions VTABLE_TYPE(exception_name) { \ 224 VTABLE_TYPE(parent_name) parent_parameters const * parent; \ 125 // Produces the C compatable name of the virtual table type for a virtual type. 126 #define _EHM_VTABLE_TYPE(type_name) struct _GLUE2(type_name,_vtable) 127 128 // Create the vtable type for exception name. 129 #define _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall_clause, parameters) \ 130 forall_clause struct exception_name; \ 131 forall_clause _EHM_VTABLE_TYPE(exception_name) { \ 132 _EHM_TYPE_ID_TYPE(exception_name) parameters const * __cfavir_typeid; \ 225 133 size_t size; \ 226 134 void (*copy)(exception_name parameters * this, exception_name parameters * other); \ 227 135 void (*^?{})(exception_name parameters & this); \ 228 136 const char * (*msg)(exception_name parameters * this); \ 229 _CLOSE137 } 230 138 231 #define _POLY_VTABLE_INSTANCE(exception_name, parent_name, ...) \ 232 extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name); \ 233 VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable( \ 234 exception_name(__VA_ARGS__) *) { \ 235 return VTABLE_NAME(exception_name); \ 236 } \ 237 void _GLUE2(exception_name,_copy)( \ 238 exception_name(__VA_ARGS__) * this, exception_name(__VA_ARGS__) * other) { \ 239 *this = *other; \ 240 } \ 241 VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name) @= { \ 242 &VTABLE_NAME(parent_name), sizeof(exception_name(__VA_ARGS__)), \ 243 _GLUE2(exception_name,_copy), ^?{}, \ 244 _CLOSE 139 // Define the function required to satify the trait for exceptions. 140 #define _EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \ 141 forall_clause inline void mark_exception( \ 142 exception_name parameters const &, \ 143 _EHM_VTABLE_TYPE(exception_name) parameters const &) {} \ 144 145 #define __EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \ 146 forall_clause inline _EHM_VTABLE_TYPE(exception_name) parameters const & \ 147 get_exception_vtable(exception_name parameters const & this) { \ 148 /* This comes before the structure definition, but we know the offset. */ \ 149 /* return (_EHM_VTABLE_TYPE(exception_name) parameters const &)this; */ \ 150 assert(false); \ 151 } 152 153 // Generates a new type-id structure. This is used to mangle the name of the 154 // type-id instance so it also includes polymorphic information. Must be the 155 // direct decendent of exception_t. 156 // The second field is used to recover type information about the exception. 157 #define _EHM_TYPE_ID_STRUCT(exception_name, forall_clause) \ 158 forall_clause _EHM_TYPE_ID_TYPE(exception_name) { \ 159 __cfa__parent_vtable const * parent; \ 160 } 161 162 // Generate a new type-id value. 163 #define _EHM_TYPE_ID_VALUE(exception_name, arguments) \ 164 __attribute__(( section(".gnu.linkonce." "__cfatid_" #exception_name) )) \ 165 _EHM_TYPE_ID_TYPE(exception_name) arguments const \ 166 _EHM_TYPE_ID_NAME(exception_name) = { \ 167 &__cfatid_exception_t, \ 168 } 169 170 // _EHM_TYPE_ID_STRUCT and _EHM_TYPE_ID_VALUE are the two that would need to 171 // be updated to extend the hierarchy if we are still using macros when that 172 // is added. 173 174 // Produce the C compatable name of the type-id type for an exception type. 175 #define _EHM_TYPE_ID_TYPE(exception_name) \ 176 struct _GLUE2(__cfatid_struct_, exception_name) 177 178 // Produce the name of the instance of the type-id for an exception type. 179 #define _EHM_TYPE_ID_NAME(exception_name) _GLUE2(__cfatid_,exception_name) 245 180 246 181 #define _IS_EXCEPTION(kind, exception_name, parameters, ...) \ 247 kind(exception_name parameters, VTABLE_TYPE(exception_name) parameters) 182 kind(exception_name parameters, _EHM_VTABLE_TYPE(exception_name) parameters) 183 184 // Internal helper macros: 185 #define _CLOSE(...) __VA_ARGS__ } 186 #define _GLUE2(left, right) left##right -
libcfa/src/fstream.cfa
rfeacef9 r5407cdc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jun 19 16:24:54 202013 // Update Count : 38414 // 15 16 #include "fstream.hfa" 12 // Last Modified On : Tue Apr 27 22:08:57 2021 13 // Update Count : 442 14 // 15 16 #include "fstream.hfa" // also includes iostream.hfa 17 17 18 18 #include <stdio.h> // vfprintf, vfscanf 19 19 #include <stdlib.h> // exit 20 20 #include <stdarg.h> // varargs 21 #include <string.h> // strlen 22 #include <float.h> // DBL_DIG, LDBL_DIG 23 #include <complex.h> // creal, cimag 21 #include <string.h> // strncpy, strerror 24 22 #include <assert.h> 25 23 #include <errno.h> // errno 26 24 27 28 25 // *********************************** ofstream *********************************** 29 26 … … 32 29 33 30 void ?{}( ofstream & os, void * file ) { 34 os.$file = file; 35 os.$sepDefault = true; 36 os.$sepOnOff = false; 37 os.$nlOnOff = true; 38 os.$prt = false; 39 os.$sawNL = false; 40 $sepSetCur( os, sepGet( os ) ); 31 os.file$ = file; 32 os.sepDefault$ = true; 33 os.sepOnOff$ = false; 34 os.nlOnOff$ = true; 35 os.prt$ = false; 36 os.sawNL$ = false; 37 os.acquired$ = false; 38 sepSetCur$( os, sepGet( os ) ); 41 39 sepSet( os, " " ); 42 40 sepSetTuple( os, ", " ); … … 44 42 45 43 // private 46 bool $sepPrt( ofstream & os ) { $setNL( os, false ); return os.$sepOnOff; }47 void $sepReset( ofstream & os ) { os.$sepOnOff = os.$sepDefault; }48 void $sepReset( ofstream & os, bool reset ) { os.$sepDefault = reset; os.$sepOnOff = os.$sepDefault; }49 const char * $sepGetCur( ofstream & os ) { return os.$sepCur; }50 void $sepSetCur( ofstream & os, const char sepCur[] ) { os.$sepCur= sepCur; }51 bool $getNL( ofstream & os ) { return os.$sawNL; }52 void $setNL( ofstream & os, bool state ) { os.$sawNL= state; }53 bool $getANL( ofstream & os ) { return os.$nlOnOff; }54 bool $getPrt( ofstream & os ) { return os.$prt; }55 void $setPrt( ofstream & os, bool state ) { os.$prt= state; }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; } 56 54 57 55 // public 58 void ?{}( ofstream & os ) { os. $file= 0p; }56 void ?{}( ofstream & os ) { os.file$ = 0p; } 59 57 60 58 void ?{}( ofstream & os, const char name[], const char mode[] ) { … … 70 68 } // ^?{} 71 69 72 void sepOn( ofstream & os ) { os. $sepOnOff = ! $getNL( os ); }73 void sepOff( ofstream & os ) { os. $sepOnOff= false; }70 void sepOn( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); } 71 void sepOff( ofstream & os ) { os.sepOnOff$ = false; } 74 72 75 73 bool sepDisable( ofstream & os ) { 76 bool temp = os. $sepDefault;77 os. $sepDefault= false;78 $sepReset( os );74 bool temp = os.sepDefault$; 75 os.sepDefault$ = false; 76 sepReset$( os ); 79 77 return temp; 80 78 } // sepDisable 81 79 82 80 bool sepEnable( ofstream & os ) { 83 bool temp = os. $sepDefault;84 os. $sepDefault= true;85 if ( os. $sepOnOff ) $sepReset( os ); // start of line ?81 bool temp = os.sepDefault$; 82 os.sepDefault$ = true; 83 if ( os.sepOnOff$ ) sepReset$( os ); // start of line ? 86 84 return temp; 87 85 } // sepEnable 88 86 89 void nlOn( ofstream & os ) { os. $nlOnOff= true; }90 void nlOff( ofstream & os ) { os. $nlOnOff= false; }91 92 const char * sepGet( ofstream & os ) { return os. $separator; }87 void nlOn( ofstream & os ) { os.nlOnOff$ = true; } 88 void nlOff( ofstream & os ) { os.nlOnOff$ = false; } 89 90 const char * sepGet( ofstream & os ) { return os.separator$; } 93 91 void sepSet( ofstream & os, const char s[] ) { 94 92 assert( s ); 95 strncpy( os. $separator, s,sepSize - 1 );96 os. $separator[sepSize - 1] = '\0';93 strncpy( os.separator$, s, ofstream_sepSize - 1 ); 94 os.separator$[ofstream_sepSize - 1] = '\0'; 97 95 } // sepSet 98 96 99 const char * sepGetTuple( ofstream & os ) { return os. $tupleSeparator; }97 const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator$; } 100 98 void sepSetTuple( ofstream & os, const char s[] ) { 101 99 assert( s ); 102 strncpy( os. $tupleSeparator, s,sepSize - 1 );103 os. $tupleSeparator[sepSize - 1] = '\0';100 strncpy( os.tupleSeparator$, s, ofstream_sepSize - 1 ); 101 os.tupleSeparator$[ofstream_sepSize - 1] = '\0'; 104 102 } // sepSet 105 103 106 104 void ends( ofstream & os ) { 107 if ( $getANL( os ) ) nl( os );108 else $setPrt( os, false ); // turn off105 if ( getANL$( os ) ) nl( os ); 106 else setPrt$( os, false ); // turn off 109 107 if ( &os == &exit ) exit( EXIT_FAILURE ); 110 108 if ( &os == &abort ) abort(); 109 if ( os.acquired$ ) { os.acquired$ = false; release( os ); } 111 110 } // ends 112 111 113 intfail( ofstream & os ) {114 return os. $file == 0 || ferror( (FILE *)(os.$file) );112 bool fail( ofstream & os ) { 113 return os.file$ == 0 || ferror( (FILE *)(os.file$) ); 115 114 } // fail 116 115 117 116 int flush( ofstream & os ) { 118 return fflush( (FILE *)(os. $file) );117 return fflush( (FILE *)(os.file$) ); 119 118 } // flush 120 119 … … 135 134 136 135 void close( ofstream & os ) { 137 if ( (FILE *)(os. $file) == 0p ) return;138 if ( (FILE *)(os. $file) == (FILE *)stdout || (FILE *)(os.$file) == (FILE *)stderr ) return;139 140 if ( fclose( (FILE *)(os. $file) ) == EOF ) {136 if ( (FILE *)(os.file$) == 0p ) return; 137 if ( (FILE *)(os.file$) == (FILE *)stdout || (FILE *)(os.file$) == (FILE *)stderr ) return; 138 139 if ( fclose( (FILE *)(os.file$) ) == EOF ) { 141 140 abort | IO_MSG "close output" | nl | strerror( errno ); 142 141 } // if 143 os. $file= 0p;142 os.file$ = 0p; 144 143 } // close 145 144 … … 149 148 } // if 150 149 151 if ( fwrite( data, 1, size, (FILE *)(os. $file) ) != size ) {150 if ( fwrite( data, 1, size, (FILE *)(os.file$) ) != size ) { 152 151 abort | IO_MSG "write" | nl | strerror( errno ); 153 152 } // if … … 158 157 va_list args; 159 158 va_start( args, format ); 160 int len = vfprintf( (FILE *)(os. $file), format, args );159 int len = vfprintf( (FILE *)(os.file$), format, args ); 161 160 if ( len == EOF ) { 162 if ( ferror( (FILE *)(os. $file) ) ) {161 if ( ferror( (FILE *)(os.file$) ) ) { 163 162 abort | IO_MSG "invalid write"; 164 163 } // if … … 166 165 va_end( args ); 167 166 168 $setPrt( os, true ); // called in output cascade169 $sepReset( os ); // reset separator167 setPrt$( os, true ); // called in output cascade 168 sepReset$( os ); // reset separator 170 169 return len; 171 170 } // fmt 171 172 inline void acquire( ofstream & os ) { 173 lock( os.lock$ ); 174 if ( ! os.acquired$ ) os.acquired$ = true; 175 else unlock( os.lock$ ); 176 } // acquire 177 178 inline void release( ofstream & os ) { 179 unlock( os.lock$ ); 180 } // release 181 182 void ?{}( osacquire & acq, ofstream & os ) { &acq.os = &os; lock( os.lock$ ); } 183 void ^?{}( osacquire & acq ) { release( acq.os ); } 172 184 173 185 static ofstream soutFile = { (FILE *)stdout }; … … 176 188 ofstream & serr = serrFile, & stderr = serrFile; 177 189 190 static ofstream lsoutFile = { (FILE *)stdout }; 191 ofstream & lsout = lsoutFile; 192 178 193 static ofstream exitFile = { (FILE *)stdout }; 179 194 ofstream & exit = exitFile; … … 181 196 ofstream & abort = abortFile; 182 197 198 ofstream & nl( ofstream & os ) { 199 nl$( os ); // call basic_ostream nl 200 flush( os ); 201 return os; 202 // (ofstream &)(os | '\n'); 203 // setPrt$( os, false ); // turn off 204 // setNL$( os, true ); 205 // flush( os ); 206 // return sepOff( os ); // prepare for next line 207 } // nl 183 208 184 209 // *********************************** ifstream *********************************** … … 187 212 // private 188 213 void ?{}( ifstream & is, void * file ) { 189 is.$file = file; 190 is.$nlOnOff = false; 214 is.file$ = file; 215 is.nlOnOff$ = false; 216 is.acquired$ = false; 191 217 } // ?{} 192 218 193 219 // public 194 void ?{}( ifstream & is ) { is. $file= 0p; }220 void ?{}( ifstream & is ) { is.file$ = 0p; } 195 221 196 222 void ?{}( ifstream & is, const char name[], const char mode[] ) { … … 206 232 } // ^?{} 207 233 208 void nlOn( ifstream & os ) { os. $nlOnOff= true; }209 void nlOff( ifstream & os ) { os. $nlOnOff= false; }210 bool getANL( ifstream & os ) { return os. $nlOnOff; }211 212 intfail( ifstream & is ) {213 return is. $file == 0p || ferror( (FILE *)(is.$file) );234 void nlOn( ifstream & os ) { os.nlOnOff$ = true; } 235 void nlOff( ifstream & os ) { os.nlOnOff$ = false; } 236 bool getANL( ifstream & os ) { return os.nlOnOff$; } 237 238 bool fail( ifstream & is ) { 239 return is.file$ == 0p || ferror( (FILE *)(is.file$) ); 214 240 } // fail 215 241 242 void ends( ifstream & is ) { 243 if ( is.acquired$ ) { is.acquired$ = false; release( is ); } 244 } // ends 245 216 246 int eof( ifstream & is ) { 217 return feof( (FILE *)(is. $file) );247 return feof( (FILE *)(is.file$) ); 218 248 } // eof 219 249 … … 226 256 } // if 227 257 #endif // __CFA_DEBUG__ 228 is. $file= file;258 is.file$ = file; 229 259 } // open 230 260 … … 234 264 235 265 void close( ifstream & is ) { 236 if ( (FILE *)(is. $file) == 0p ) return;237 if ( (FILE *)(is. $file) == (FILE *)stdin ) return;238 239 if ( fclose( (FILE *)(is. $file) ) == EOF ) {266 if ( (FILE *)(is.file$) == 0p ) return; 267 if ( (FILE *)(is.file$) == (FILE *)stdin ) return; 268 269 if ( fclose( (FILE *)(is.file$) ) == EOF ) { 240 270 abort | IO_MSG "close input" | nl | strerror( errno ); 241 271 } // if 242 is. $file= 0p;272 is.file$ = 0p; 243 273 } // close 244 274 … … 248 278 } // if 249 279 250 if ( fread( data, size, 1, (FILE *)(is. $file) ) == 0 ) {280 if ( fread( data, size, 1, (FILE *)(is.file$) ) == 0 ) { 251 281 abort | IO_MSG "read" | nl | strerror( errno ); 252 282 } // if … … 259 289 } // if 260 290 261 if ( ungetc( c, (FILE *)(is. $file) ) == EOF ) {291 if ( ungetc( c, (FILE *)(is.file$) ) == EOF ) { 262 292 abort | IO_MSG "ungetc" | nl | strerror( errno ); 263 293 } // if … … 269 299 270 300 va_start( args, format ); 271 int len = vfscanf( (FILE *)(is. $file), format, args );301 int len = vfscanf( (FILE *)(is.file$), format, args ); 272 302 if ( len == EOF ) { 273 if ( ferror( (FILE *)(is. $file) ) ) {303 if ( ferror( (FILE *)(is.file$) ) ) { 274 304 abort | IO_MSG "invalid read"; 275 305 } // if … … 279 309 } // fmt 280 310 311 inline void acquire( ifstream & is ) { 312 lock( is.lock$ ); 313 if ( ! is.acquired$ ) is.acquired$ = true; 314 else unlock( is.lock$ ); 315 } // acquire 316 317 inline void release( ifstream & is ) { 318 unlock( is.lock$ ); 319 } // release 320 321 void ?{}( isacquire & acq, ifstream & is ) { &acq.is = &is; lock( is.lock$ ); } 322 void ^?{}( isacquire & acq ) { release( acq.is ); } 323 281 324 static ifstream sinFile = { (FILE *)stdin }; 282 325 ifstream & sin = sinFile, & stdin = sinFile; … … 286 329 287 330 331 EHM_VIRTUAL_TABLE(Open_Failure, Open_Failure_main_table); 288 332 void ?{}( Open_Failure & this, ofstream & ostream ) { 289 VTABLE_INIT(this, Open_Failure);333 this.virtual_table = &Open_Failure_main_table; 290 334 this.ostream = &ostream; 291 335 this.tag = 1; 292 336 } 293 337 void ?{}( Open_Failure & this, ifstream & istream ) { 294 VTABLE_INIT(this, Open_Failure);338 this.virtual_table = &Open_Failure_main_table; 295 339 this.istream = &istream; 296 340 this.tag = 0; 297 341 } 298 const char * Open_Failure_msg(Open_Failure * this) {299 return "Open_Failure";300 }301 VTABLE_INSTANCE(Open_Failure)(Open_Failure_msg);302 342 void throwOpen_Failure( ofstream & ostream ) { 303 343 Open_Failure exc = { ostream }; -
libcfa/src/fstream.hfa
rfeacef9 r5407cdc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Jun 19 16:29:17 202013 // Update Count : 18912 // Last Modified On : Tue Apr 27 22:00:30 2021 13 // Update Count : 226 14 14 // 15 15 16 16 #pragma once 17 17 18 #include "bits/weakso_locks.hfa" 18 #include "bits/weakso_locks.hfa" // mutex_lock 19 19 #include "iostream.hfa" 20 20 #include <exception.hfa> … … 24 24 25 25 26 enum { sepSize = 16 };26 enum { ofstream_sepSize = 16 }; 27 27 struct ofstream { 28 void * $file; 29 bool $sepDefault; 30 bool $sepOnOff; 31 bool $nlOnOff; 32 bool $prt; // print text 33 bool $sawNL; 34 const char * $sepCur; 35 char $separator[sepSize]; 36 char $tupleSeparator[sepSize]; 37 // multiple_acquisition_lock lock; 28 void * file$; 29 bool sepDefault$; 30 bool sepOnOff$; 31 bool nlOnOff$; 32 bool prt$; // print text 33 bool sawNL$; 34 const char * sepCur$; 35 char separator$[ofstream_sepSize]; 36 char tupleSeparator$[ofstream_sepSize]; 37 multiple_acquisition_lock lock$; 38 bool acquired$; 38 39 }; // ofstream 39 40 41 // Satisfies ostream 42 40 43 // private 41 bool $sepPrt( ofstream & );42 void $sepReset( ofstream & );43 void $sepReset( ofstream &, bool );44 const char * $sepGetCur( ofstream & );45 void $sepSetCur( ofstream &, const char [] );46 bool $getNL( ofstream & );47 void $setNL( ofstream &, bool );48 bool $getANL( ofstream & );49 bool $getPrt( ofstream & );50 void $setPrt( ofstream &, bool );44 bool sepPrt$( ofstream & ); 45 void sepReset$( ofstream & ); 46 void sepReset$( ofstream &, bool ); 47 const char * sepGetCur$( ofstream & ); 48 void sepSetCur$( ofstream &, const char [] ); 49 bool getNL$( ofstream & ); 50 void setNL$( ofstream &, bool ); 51 bool getANL$( ofstream & ); 52 bool getPrt$( ofstream & ); 53 void setPrt$( ofstream &, bool ); 51 54 52 55 // public … … 63 66 void sepSetTuple( ofstream &, const char [] ); 64 67 65 void ends( ofstream & os ); 66 int fail( ofstream & ); 68 void ends( ofstream & ); 69 int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) )); 70 71 bool fail( ofstream & ); 67 72 int flush( ofstream & ); 68 void open( ofstream &, const char name[], const char mode[] ); 73 void open( ofstream &, const char name[], const char mode[] ); // FIX ME: use default = "w" 69 74 void open( ofstream &, const char name[] ); 70 75 void close( ofstream & ); 71 76 ofstream & write( ofstream &, const char data[], size_t size ); 72 int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));73 77 74 void ?{}( ofstream & os ); 75 void ?{}( ofstream & os, const char name[], const char mode[] ); 76 void ?{}( ofstream & os, const char name[] ); 77 void ^?{}( ofstream & os ); 78 void acquire( ofstream & ); 79 void release( ofstream & ); 80 81 struct osacquire { 82 ofstream & os; 83 }; 84 void ?{}( osacquire & acq, ofstream & ); 85 void ^?{}( osacquire & acq ); 86 87 void ?{}( ofstream & ); 88 void ?{}( ofstream &, const char name[], const char mode[] ); // FIX ME: use default = "w" 89 void ?{}( ofstream &, const char name[] ); 90 void ^?{}( ofstream & ); 91 92 // private 93 static inline ofstream & nl$( ofstream & os ) { return nl( os ); } // remember basic_ostream nl 94 // public 95 ofstream & nl( ofstream & os ); // override basic_ostream nl 78 96 79 97 extern ofstream & sout, & stdout, & serr, & stderr; // aliases … … 85 103 86 104 struct ifstream { 87 void * $file; 88 bool $nlOnOff; 105 void * file$; 106 bool nlOnOff$; 107 multiple_acquisition_lock lock$; 108 bool acquired$; 89 109 }; // ifstream 110 111 // Satisfies istream 90 112 91 113 // public … … 93 115 void nlOff( ifstream & ); 94 116 bool getANL( ifstream & ); 95 int fail( ifstream & is ); 117 void ends( ifstream & ); 118 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 119 120 bool fail( ifstream & is ); 96 121 int eof( ifstream & is ); 97 void open( ifstream & is, const char name[], const char mode[] ); 122 void open( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r" 98 123 void open( ifstream & is, const char name[] ); 99 124 void close( ifstream & is ); 100 125 ifstream & read( ifstream & is, char * data, size_t size ); 101 126 ifstream & ungetc( ifstream & is, char c ); 102 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 127 128 void acquire( ifstream & is ); 129 void release( ifstream & is ); 130 131 struct isacquire { 132 ifstream & is; 133 }; 134 void ?{}( isacquire & acq, ifstream & is ); 135 void ^?{}( isacquire & acq ); 103 136 104 137 void ?{}( ifstream & is ); 105 void ?{}( ifstream & is, const char name[], const char mode[] ); 138 void ?{}( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r" 106 139 void ?{}( ifstream & is, const char name[] ); 107 140 void ^?{}( ifstream & is ); … … 113 146 114 147 115 DATA_EXCEPTION(Open_Failure)(148 EHM_EXCEPTION(Open_Failure)( 116 149 union { 117 150 ofstream * ostream; … … 122 155 ); 123 156 124 void ?{}( Open_Failure & this, ofstream & ostream);125 void ?{}( Open_Failure & this, ifstream & istream);157 void ?{}( Open_Failure & this, ofstream & ); 158 void ?{}( Open_Failure & this, ifstream & ); 126 159 127 160 // Local Variables: // -
libcfa/src/gmp.hfa
rfeacef9 r5407cdc 10 10 // Created On : Tue Apr 19 08:43:43 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 9 09:56:54 202013 // Update Count : 3 112 // Last Modified On : Tue Apr 20 20:59:21 2021 13 // Update Count : 32 14 14 // 15 15 … … 263 263 forall( ostype & | ostream( ostype ) ) { 264 264 ostype & ?|?( ostype & os, Int mp ) { 265 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );265 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 266 266 gmp_printf( "%Zd", mp.mpz ); 267 267 sepOn( os ); -
libcfa/src/heap.cfa
rfeacef9 r5407cdc 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 10 11:20:49202113 // Update Count : 103 112 // Last Modified On : Tue Apr 20 21:20:48 2021 13 // Update Count : 1033 14 14 // 15 15 … … 52 52 static bool prtFree = false; 53 53 54 inlinebool prtFree() {54 bool prtFree() { 55 55 return prtFree; 56 56 } // prtFree … … 1128 1128 1129 1129 // Set the alignment for an the allocation and return previous alignment or 0 if no alignment. 1130 size_t $malloc_alignment_set( void * addr, size_t alignment ) {1130 size_t malloc_alignment_set$( void * addr, size_t alignment ) { 1131 1131 if ( unlikely( addr == 0p ) ) return libAlign(); // minimum alignment 1132 1132 size_t ret; … … 1139 1139 } // if 1140 1140 return ret; 1141 } // $malloc_alignment_set1141 } // malloc_alignment_set$ 1142 1142 1143 1143 … … 1153 1153 1154 1154 // Set allocation is zero filled and return previous zero filled. 1155 bool $malloc_zero_fill_set( void * addr ) {1155 bool malloc_zero_fill_set$( void * addr ) { 1156 1156 if ( unlikely( addr == 0p ) ) return false; // null allocation is not zero fill 1157 1157 HeapManager.Storage.Header * header = headerAddr( addr ); … … 1162 1162 header->kind.real.blockSize |= 2; // mark as zero filled 1163 1163 return ret; 1164 } // $malloc_zero_fill_set1164 } // malloc_zero_fill_set$ 1165 1165 1166 1166 … … 1176 1176 1177 1177 // Set allocation size and return previous size. 1178 size_t $malloc_size_set( void * addr, size_t size ) {1178 size_t malloc_size_set$( void * addr, size_t size ) { 1179 1179 if ( unlikely( addr == 0p ) ) return 0; // null allocation has 0 size 1180 1180 HeapManager.Storage.Header * header = headerAddr( addr ); … … 1185 1185 header->kind.real.size = size; 1186 1186 return ret; 1187 } // $malloc_size_set1187 } // malloc_size_set$ 1188 1188 1189 1189 -
libcfa/src/iostream.cfa
rfeacef9 r5407cdc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Aug 24 08:31:35 202013 // Update Count : 1 13012 // Last Modified On : Tue Apr 27 18:01:03 2021 13 // Update Count : 1330 14 14 // 15 15 … … 36 36 37 37 38 forall( ostype & | ostream( ostype ) ) {38 forall( ostype & | basic_ostream( ostype ) ) { 39 39 ostype & ?|?( ostype & os, bool b ) { 40 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );40 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 41 41 fmt( os, "%s", b ? "true" : "false" ); 42 42 return os; … … 48 48 ostype & ?|?( ostype & os, char c ) { 49 49 fmt( os, "%c", c ); 50 if ( c == '\n' ) $setNL( os, true );50 if ( c == '\n' ) setNL$( os, true ); 51 51 return sepOff( os ); 52 52 } // ?|? … … 56 56 57 57 ostype & ?|?( ostype & os, signed char sc ) { 58 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );58 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 59 59 fmt( os, "%hhd", sc ); 60 60 return os; … … 65 65 66 66 ostype & ?|?( ostype & os, unsigned char usc ) { 67 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );67 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 68 68 fmt( os, "%hhu", usc ); 69 69 return os; … … 74 74 75 75 ostype & ?|?( ostype & os, short int si ) { 76 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );76 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 77 77 fmt( os, "%hd", si ); 78 78 return os; … … 83 83 84 84 ostype & ?|?( ostype & os, unsigned short int usi ) { 85 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );85 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 86 86 fmt( os, "%hu", usi ); 87 87 return os; … … 92 92 93 93 ostype & ?|?( ostype & os, int i ) { 94 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );94 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 95 95 fmt( os, "%d", i ); 96 96 return os; … … 101 101 102 102 ostype & ?|?( ostype & os, unsigned int ui ) { 103 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );103 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 104 104 fmt( os, "%u", ui ); 105 105 return os; … … 110 110 111 111 ostype & ?|?( ostype & os, long int li ) { 112 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );112 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 113 113 fmt( os, "%ld", li ); 114 114 return os; … … 119 119 120 120 ostype & ?|?( ostype & os, unsigned long int uli ) { 121 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );121 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 122 122 fmt( os, "%lu", uli ); 123 123 return os; … … 128 128 129 129 ostype & ?|?( ostype & os, long long int lli ) { 130 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );130 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 131 131 fmt( os, "%lld", lli ); 132 132 return os; … … 137 137 138 138 ostype & ?|?( ostype & os, unsigned long long int ulli ) { 139 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );139 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 140 140 fmt( os, "%llu", ulli ); 141 141 return os; … … 145 145 } // ?|? 146 146 147 #if defined( __SIZEOF_INT128__ )147 #if defined( __SIZEOF_INT128__ ) 148 148 // UINT64_MAX 18_446_744_073_709_551_615_ULL 149 149 #define P10_UINT64 10_000_000_000_000_000_000_ULL // 19 zeroes 150 150 151 151 static inline void base10_128( ostype & os, unsigned int128 val ) { 152 #if defined(__GNUC__) && __GNUC_PREREQ(7,0)// gcc version >= 7152 #if defined(__GNUC__) && __GNUC_PREREQ(7,0) // gcc version >= 7 153 153 if ( val > P10_UINT64 ) { 154 #else154 #else 155 155 if ( (uint64_t)(val >> 64) != 0 || (uint64_t)val > P10_UINT64 ) { // patch gcc 5 & 6 -O3 bug 156 #endif // __GNUC_PREREQ(7,0)156 #endif // __GNUC_PREREQ(7,0) 157 157 base10_128( os, val / P10_UINT64 ); // recursive 158 158 fmt( os, "%.19lu", (uint64_t)(val % P10_UINT64) ); … … 171 171 172 172 ostype & ?|?( ostype & os, int128 llli ) { 173 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );173 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 174 174 base10_128( os, llli ); 175 175 return os; … … 180 180 181 181 ostype & ?|?( ostype & os, unsigned int128 ullli ) { 182 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );182 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 183 183 base10_128( os, ullli ); 184 184 return os; … … 187 187 (ostype &)(os | ullli); ends( os ); 188 188 } // ?|? 189 #endif // __SIZEOF_INT128__189 #endif // __SIZEOF_INT128__ 190 190 191 191 #define PrintWithDP( os, format, val, ... ) \ … … 195 195 int len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \ 196 196 fmt( os, "%s", buf ); \ 197 if ( isfinite( val ) ) { /* if number, always print decimal point */ \197 if ( isfinite( val ) ) { /* if number, print decimal point when no fraction or exponent */ \ 198 198 for ( int i = 0;; i += 1 ) { \ 199 199 if ( i == len ) { fmt( os, "." ); break; } \ 200 if ( buf[i] == '.' ) break;\200 if ( buf[i] == '.' || buf[i] == 'e' || buf[i] == 'E' ) break; /* decimal point or scientific ? */ \ 201 201 } /* for */ \ 202 202 } /* if */ \ … … 204 204 205 205 ostype & ?|?( ostype & os, float f ) { 206 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );206 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 207 207 PrintWithDP( os, "%g", f ); 208 208 return os; … … 213 213 214 214 ostype & ?|?( ostype & os, double d ) { 215 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );215 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 216 216 PrintWithDP( os, "%.*lg", d, DBL_DIG ); 217 217 return os; … … 222 222 223 223 ostype & ?|?( ostype & os, long double ld ) { 224 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );224 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 225 225 PrintWithDP( os, "%.*Lg", ld, LDBL_DIG ); 226 226 return os; … … 231 231 232 232 ostype & ?|?( ostype & os, float _Complex fc ) { 233 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );233 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 234 234 // os | crealf( fc ) | nonl; 235 235 PrintWithDP( os, "%g", crealf( fc ) ); … … 243 243 244 244 ostype & ?|?( ostype & os, double _Complex dc ) { 245 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );245 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 246 246 // os | creal( dc ) | nonl; 247 247 PrintWithDP( os, "%.*lg", creal( dc ), DBL_DIG ); … … 255 255 256 256 ostype & ?|?( ostype & os, long double _Complex ldc ) { 257 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );257 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 258 258 // os | creall( ldc ) || nonl; 259 259 PrintWithDP( os, "%.*Lg", creall( ldc ), LDBL_DIG ); … … 266 266 } // ?|? 267 267 268 ostype & ?|?( ostype & os, const char s tr[] ) {268 ostype & ?|?( ostype & os, const char s[] ) { 269 269 enum { Open = 1, Close, OpenClose }; 270 270 static const unsigned char mask[256] @= { … … 282 282 }; // mask 283 283 284 if ( s tr[0] == '\0' ) { sepOff( os ); return os; } // null string => no separator284 if ( s[0] == '\0' ) { sepOff( os ); return os; } // null string => no separator 285 285 286 286 // first character IS NOT spacing or closing punctuation => add left separator 287 unsigned char ch = s tr[0]; // must make unsigned288 if ( $sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {289 fmt( os, "%s", $sepGetCur( os ) );287 unsigned char ch = s[0]; // must make unsigned 288 if ( sepPrt$( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) { 289 fmt( os, "%s", sepGetCur$( os ) ); 290 290 } // if 291 291 292 292 // if string starts line, must reset to determine open state because separator is off 293 $sepReset( os ); // reset separator293 sepReset$( os ); // reset separator 294 294 295 295 // last character IS spacing or opening punctuation => turn off separator for next item 296 size_t len = strlen( str ); 297 ch = str[len - 1]; // must make unsigned 298 if ( $sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) { 296 int len = strlen( s ); 297 ch = s[len - 1]; // must make unsigned 298 fmt( os, "%s", s ); // fmt resets seperator, but reset it again 299 if ( sepPrt$( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) { 299 300 sepOn( os ); 300 301 } else { 301 302 sepOff( os ); 302 303 } // if 303 if ( ch == '\n' ) $setNL( os, true ); // check *AFTER* $sepPrtcall above as it resets NL flag304 return write( os, str, len );305 } // ?|? 306 307 void ?|?( ostype & os, const char s tr[] ) {308 (ostype &)(os | s tr); ends( os );309 } // ?|? 310 311 // ostype & ?|?( ostype & os, const char16_t * s tr) {312 // if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );313 // fmt( os, "%ls", s tr);304 if ( ch == '\n' ) setNL$( os, true ); // check *AFTER* sepPrt$ call above as it resets NL flag 305 return os; 306 // return write( os, s, len ); 307 } // ?|? 308 void ?|?( ostype & os, const char s[] ) { 309 (ostype &)(os | s); ends( os ); 310 } // ?|? 311 312 // ostype & ?|?( ostype & os, const char16_t * s ) { 313 // if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 314 // fmt( os, "%ls", s ); 314 315 // return os; 315 316 // } // ?|? 316 317 317 318 // #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous 318 // ostype & ?|?( ostype & os, const char32_t * s tr) {319 // if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );320 // fmt( os, "%ls", s tr);319 // ostype & ?|?( ostype & os, const char32_t * s ) { 320 // if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 321 // fmt( os, "%ls", s ); 321 322 // return os; 322 323 // } // ?|? 323 324 // #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) 324 325 325 // ostype & ?|?( ostype & os, const wchar_t * s tr) {326 // if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );327 // fmt( os, "%ls", s tr);326 // ostype & ?|?( ostype & os, const wchar_t * s ) { 327 // if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 328 // fmt( os, "%ls", s ); 328 329 // return os; 329 330 // } // ?|? 330 331 331 332 ostype & ?|?( ostype & os, const void * p ) { 332 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );333 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 333 334 fmt( os, "%p", p ); 334 335 return os; … … 340 341 // manipulators 341 342 ostype & ?|?( ostype & os, ostype & (* manip)( ostype & ) ) { 342 (ostype &)(manip( os )); 343 return os; 343 return manip( os ); 344 344 } // ?|? 345 345 void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) { 346 (ostype &)(manip( os ));347 if ( $getPrt( os ) ) ends( os ); // something printed ?348 $setPrt( os, false ); // turn off346 manip( os ); 347 if ( getPrt$( os ) ) ends( os ); // something printed ? 348 setPrt$( os, false ); // turn off 349 349 } // ?|? 350 350 … … 359 359 ostype & nl( ostype & os ) { 360 360 (ostype &)(os | '\n'); 361 $setPrt( os, false ); // turn off 362 $setNL( os, true ); 363 flush( os ); 361 setPrt$( os, false ); // turn off 362 setNL$( os, true ); 364 363 return sepOff( os ); // prepare for next line 365 364 } // nl 366 365 367 366 ostype & nonl( ostype & os ) { 368 $setPrt( os, false ); // turn off367 setPrt$( os, false ); // turn off 369 368 return os; 370 369 } // nonl … … 399 398 return os; 400 399 } // nlOff 400 } // distribution 401 402 forall( ostype & | ostream( ostype ) ) { 403 ostype & acquire( ostype & os ) { 404 acquire( os ); // call void returning 405 return os; 406 } // acquire 401 407 } // distribution 402 408 … … 405 411 ostype & ?|?( ostype & os, T arg, Params rest ) { 406 412 (ostype &)(os | arg); // print first argument 407 $sepSetCur( os, sepGetTuple( os ) ); // switch to tuple separator413 sepSetCur$( os, sepGetTuple( os ) ); // switch to tuple separator 408 414 (ostype &)(os | rest); // print remaining arguments 409 $sepSetCur( os, sepGet( os ) ); // switch to regular separator415 sepSetCur$( os, sepGet( os ) ); // switch to regular separator 410 416 return os; 411 417 } // ?|? … … 413 419 // (ostype &)(?|?( os, arg, rest )); ends( os ); 414 420 (ostype &)(os | arg); // print first argument 415 $sepSetCur( os, sepGetTuple( os ) ); // switch to tuple separator421 sepSetCur$( os, sepGetTuple( os ) ); // switch to tuple separator 416 422 (ostype &)(os | rest); // print remaining arguments 417 $sepSetCur( os, sepGet( os ) ); // switch to regular separator423 sepSetCur$( os, sepGet( os ) ); // switch to regular separator 418 424 ends( os ); 419 425 } // ?|? … … 442 448 // Default prefix for non-decimal prints is 0b, 0, 0x. 443 449 #define IntegralFMTImpl( T, IFMTNP, IFMTP ) \ 444 forall( ostype & | ostream( ostype ) ) { \450 forall( ostype & | basic_ostream( ostype ) ) { \ 445 451 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 446 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \452 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \ 447 453 \ 448 454 if ( f.base == 'b' || f.base == 'B' ) { /* bespoke binary format */ \ … … 517 523 return os; \ 518 524 } /* ?|? */ \ 519 void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \ 520 } // distribution 521 522 IntegralFMTImpl( signed char, "% *hh ", "% *.*hh " ) 523 IntegralFMTImpl( unsigned char, "% *hh ", "% *.*hh " ) 524 IntegralFMTImpl( signed short int, "% *h ", "% *.*h " ) 525 IntegralFMTImpl( unsigned short int, "% *h ", "% *.*h " ) 526 IntegralFMTImpl( signed int, "% * ", "% *.* " ) 527 IntegralFMTImpl( unsigned int, "% * ", "% *.* " ) 528 IntegralFMTImpl( signed long int, "% *l ", "% *.*l " ) 529 IntegralFMTImpl( unsigned long int, "% *l ", "% *.*l " ) 530 IntegralFMTImpl( signed long long int, "% *ll ", "% *.*ll " ) 531 IntegralFMTImpl( unsigned long long int, "% *ll ", "% *.*ll " ) 532 533 #if 0 525 void ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 526 (ostype &)(os | f); ends( os ); \ 527 } /* ?|? */ \ 528 } // distribution 529 530 IntegralFMTImpl( signed char, " *hh ", " *.*hh " ) 531 IntegralFMTImpl( unsigned char, " *hh ", " *.*hh " ) 532 IntegralFMTImpl( signed short int, " *h ", " *.*h " ) 533 IntegralFMTImpl( unsigned short int, " *h ", " *.*h " ) 534 IntegralFMTImpl( signed int, " * ", " *.* " ) 535 IntegralFMTImpl( unsigned int, " * ", " *.* " ) 536 IntegralFMTImpl( signed long int, " *l ", " *.*l " ) 537 IntegralFMTImpl( unsigned long int, " *l ", " *.*l " ) 538 IntegralFMTImpl( signed long long int, " *ll ", " *.*ll " ) 539 IntegralFMTImpl( unsigned long long int, " *ll ", " *.*ll " ) 540 541 534 542 #if defined( __SIZEOF_INT128__ ) 535 543 // Default prefix for non-decimal prints is 0b, 0, 0x. 536 #define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \ 537 forall( ostype & | ostream( ostype ) ) \ 538 static void base10_128( ostype & os, _Ostream_Manip(T) f ) { \ 539 if ( f.val > UINT64_MAX ) { \ 540 unsigned long long int lsig = f.val % P10_UINT64; \ 541 f.val /= P10_UINT64; /* msig */ \ 542 base10_128( os, f ); /* recursion */ \ 543 _Ostream_Manip(unsigned long long int) fmt @= { lsig, 0, 19, 'u', { .all : 0 } }; \ 544 fmt.flags.nobsdp = true; \ 545 /* printf( "fmt1 %c %lld %d\n", fmt.base, fmt.val, fmt.all ); */ \ 546 sepOff( os ); \ 547 (ostype &)(os | fmt); \ 548 } else { \ 549 /* printf( "fmt2 %c %lld %d\n", f.base, (unsigned long long int)f.val, f.all ); */ \ 550 _Ostream_Manip(SIGNED long long int) fmt @= { (SIGNED long long int)f.val, f.wd, f.pc, f.base, { .all : f.all } }; \ 551 (ostype &)(os | fmt); \ 552 } /* if */ \ 553 } /* base10_128 */ \ 554 forall( ostype & | ostream( ostype ) ) { \ 555 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 556 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \ 557 \ 558 if ( f.base == 'b' | f.base == 'B' | f.base == 'o' | f.base == 'x' | f.base == 'X' ) { \ 559 unsigned long long int msig = (unsigned long long int)(f.val >> 64); \ 560 unsigned long long int lsig = (unsigned long long int)(f.val); \ 561 _Ostream_Manip(SIGNED long long int) fmt @= { msig, f.wd, f.pc, f.base, { .all : f.all } }; \ 562 _Ostream_Manip(unsigned long long int) fmt2 @= { lsig, 0, 0, f.base, { .all : 0 } }; \ 563 if ( msig == 0 ) { \ 564 fmt.val = lsig; \ 565 (ostype &)(os | fmt); \ 566 } else { \ 567 fmt2.flags.pad0 = fmt2.flags.nobsdp = true; \ 568 if ( f.base == 'b' | f.base == 'B' ) { \ 569 if ( fmt.flags.pc && fmt.pc > 64 ) fmt.pc -= 64; else { fmt.flags.pc = false; fmt.pc = 0; } \ 570 if ( fmt.flags.left ) { \ 571 fmt.flags.left = false; \ 572 fmt.wd = 0; \ 573 /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 574 fmt2.flags.left = true; \ 575 int msigd = high1( msig ); \ 576 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \ 577 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0b base specifier */ \ 578 if ( (int)fmt2.wd < 64 ) fmt2.wd = 64; /* cast deals with negative value */ \ 579 fmt2.flags.pc = true; fmt2.pc = 64; \ 580 } else { \ 581 if ( fmt.wd > 64 ) fmt.wd -= 64; \ 582 else fmt.wd = 1; \ 583 /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 584 fmt2.wd = 64; \ 585 } /* if */ \ 586 /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 587 (ostype &)(os | fmt | "" | fmt2); \ 588 } else if ( f.base == 'o' ) { \ 589 if ( fmt.flags.pc && fmt.pc > 22 ) fmt.pc -= 22; else { fmt.flags.pc = false; fmt.pc = 0; } \ 590 fmt.val = (unsigned long long int)fmt.val >> 2; \ 591 fmt2.val = ((msig & 0x3) << 1) + ((lsig & 0x8000000000000000U) != 0); \ 592 if ( fmt.flags.left ) { \ 593 fmt.flags.left = false; \ 594 fmt.wd = 0; \ 595 /* printf( "L %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 596 (ostype &)(os | fmt | "" | fmt2); \ 597 sepOff( os ); \ 598 fmt2.flags.left = true; \ 599 int msigd = ceiling_div( high1( fmt.val ), 3 ); \ 600 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \ 601 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 1; /* compensate for 0 base specifier */ \ 602 if ( (int)fmt2.wd < 21 ) fmt2.wd = 21; /* cast deals with negative value */ \ 603 fmt2.flags.pc = true; fmt2.pc = 21; \ 604 } else { \ 605 if ( fmt.wd > 22 ) fmt.wd -= 22; \ 606 else fmt.wd = 1; \ 607 /* printf( "R %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 608 (ostype &)(os | fmt | "" | fmt2); \ 609 sepOff( os ); \ 610 fmt2.wd = 21; \ 611 } /* if */ \ 612 fmt2.val = lsig & 0x7fffffffffffffffU; \ 613 /* printf( "\nC %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 614 (ostype &)(os | fmt2); \ 615 } else { /* f.base == 'x' | f.base == 'X' */ \ 616 if ( fmt.flags.pc && fmt.pc > 16 ) fmt.pc -= 16; else { fmt.flags.pc = false; fmt.pc = 0; } \ 617 if ( fmt.flags.left ) { \ 618 fmt.flags.left = false; \ 619 fmt.wd = 0; \ 620 /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 621 fmt2.flags.left = true; \ 622 int msigd = high1( msig ); \ 623 fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \ 624 if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0x base specifier */ \ 625 if ( (int)fmt2.wd < 16 ) fmt2.wd = 16; /* cast deals with negative value */ \ 626 fmt2.flags.pc = true; fmt2.pc = 16; \ 627 } else { \ 628 if ( fmt.wd > 16 ) fmt.wd -= 16; \ 629 else fmt.wd = 1; \ 630 /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \ 631 fmt2.wd = 16; \ 632 } /* if */ \ 633 /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \ 634 (ostype &)(os | fmt | "" | fmt2); \ 635 } /* if */ \ 636 } /* if */ \ 637 } else { \ 638 if ( CODE == 'd' ) { \ 639 if ( f.val < 0 ) { fmt( os, "-" ); sepOff( os ); f.val = -f.val; f.flags.sign = false; } \ 640 } /* if */ \ 641 base10_128( os, f ); \ 642 } /* if */ \ 643 return os; \ 644 } /* ?|? */ \ 645 void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \ 646 } // distribution 647 648 IntegralFMTImpl128( int128, signed, 'd', "% *ll ", "% *.*ll " ) 649 IntegralFMTImpl128( unsigned int128, unsigned, 'u', "% *ll ", "% *.*ll " ) 650 #endif // __SIZEOF_INT128__ 651 #endif // 0 652 653 #if 1 654 #if defined( __SIZEOF_INT128__ ) 655 // Default prefix for non-decimal prints is 0b, 0, 0x. 656 forall( ostype & | ostream( ostype ) ) 544 forall( ostype & | basic_ostream( ostype ) ) 657 545 static inline void base_128( ostype & os, unsigned int128 val, unsigned int128 power, _Ostream_Manip(uint64_t) & f, unsigned int maxdig, unsigned int bits, unsigned int cnt = 0 ) { 658 546 int wd = 1; // f.wd is never 0 because 0 implies left-pad … … 719 607 720 608 #define IntegralFMTImpl128( T ) \ 721 forall( ostype & | ostream( ostype ) ) { \609 forall( ostype & | basic_ostream( ostype ) ) { \ 722 610 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 723 611 _Ostream_Manip(uint64_t) fmt; \ … … 741 629 IntegralFMTImpl128( unsigned int128 ) 742 630 #endif // __SIZEOF_INT128__ 743 #endif // 0744 631 745 632 // *********************************** floating point *********************************** 746 633 747 #define PrintWithDP2( os, format, val, ... ) \ 634 static const char *suffixes[] = { 635 "y", "z", "a", "f", "p", "n", "u", "m", "", 636 "K", "M", "G", "T", "P", "E", "Z", "Y" 637 }; 638 #define SUFFIXES_START (-24) /* Smallest power for which there is a suffix defined. */ 639 #define SUFFIXES_END (SUFFIXES_START + (int)((sizeof(suffixes) / sizeof(char *) - 1) * 3)) 640 641 #define PrintWithDP2( os, format, ... ) \ 748 642 { \ 749 enum { size = 48 };\750 char buf[size]; \751 int bufbeg = 0, i, len = snprintf( buf, size, format, ##__VA_ARGS__, val );\752 if ( isfinite( val ) && (f.base != 'g' || f.pc != 0) ) { /* if number, print decimal point*/ \753 for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */\754 if ( i == len && ! f.flags.nobsdp) { \755 if ( ! f.flags.left ) {\756 buf[i] = '.'; buf[i + 1] = '\0';\757 if ( buf[0] == ' ' ) bufbeg = 1; /* decimal point within width */\758 } else {\759 for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */\760 buf[i] = '.'; \761 if ( i == len ) buf[i + 1] = '\0';\643 if ( ! f.flags.eng ) { \ 644 len = snprintf( buf, size, format, ##__VA_ARGS__ ); \ 645 if ( isfinite( f.val ) && ( f.pc != 0 || ! f.flags.nobsdp ) ) { /* if number, print decimal point when no fraction or exponent */ \ 646 for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */ \ 647 if ( i == len ) { \ 648 if ( ! f.flags.left ) { \ 649 buf[i] = '.'; buf[i + 1] = '\0'; \ 650 if ( buf[0] == ' ' ) bufbeg = 1; /* decimal point within width */ \ 651 } else { \ 652 for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \ 653 buf[i] = '.'; \ 654 if ( i == len ) buf[i + 1] = '\0'; \ 655 } /* if */ \ 762 656 } /* if */ \ 763 657 } /* if */ \ 658 } else { \ 659 int exp10, len2; \ 660 eng( f.val, f.pc, exp10 ); /* changes arguments */ \ 661 if ( ! f.flags.left && f.wd > 1 ) { \ 662 /* Exponent size (number of digits, 'e', optional minus sign) */ \ 663 f.wd -= lrint( floor( log10( abs( exp10 ) ) ) ) + 1 + 1 + (exp10 < 0 ? 1 : 0); \ 664 if ( f.wd < 1 ) f.wd = 1; \ 665 } /* if */ \ 666 len = snprintf( buf, size, format, ##__VA_ARGS__ ); \ 667 if ( f.flags.left ) { \ 668 for ( len -= 1; len > 0 && buf[len] == ' '; len -= 1 ); \ 669 len += 1; \ 670 } /* if */ \ 671 if ( ! f.flags.nobsdp || (exp10 < SUFFIXES_START) || (exp10 > SUFFIXES_END) ) { \ 672 len2 = snprintf( &buf[len], size - len, "e%d", exp10 ); \ 673 } else { \ 674 len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \ 675 } /* if */ \ 676 if ( f.flags.left && len + len2 < f.wd ) buf[len + len2] = ' '; \ 764 677 } /* if */ \ 765 678 fmt( os, "%s", &buf[bufbeg] ); \ … … 767 680 768 681 #define FloatingPointFMTImpl( T, DFMTNP, DFMTP ) \ 769 forall( ostype & | ostream( ostype ) ) { \ 682 forall( ostype & | basic_ostream( ostype ) ) { \ 683 static void eng( T &value, int & pc, int & exp10 ) { \ 684 exp10 = lrint( floor( log10( abs( value ) ) ) ); /* round to desired precision */ \ 685 if ( exp10 < 0 ) exp10 -= 2; \ 686 exp10 = floor( exp10, 3 ); \ 687 value *= pow( 10.0, -exp10 ); \ 688 if ( pc <= 3 ) pc = 3; \ 689 } /* eng */ \ 690 \ 770 691 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \ 771 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \ 772 char fmtstr[sizeof(DFMTP)]; /* sizeof includes '\0' */ \ 692 enum { size = 48 }; \ 693 char buf[size]; \ 694 int bufbeg = 0, i, len; \ 695 \ 696 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \ 697 char fmtstr[sizeof(DFMTP) + 8]; /* sizeof includes '\0' */ \ 773 698 if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \ 774 699 else memcpy( &fmtstr, DFMTP, sizeof(DFMTP) ); \ … … 784 709 fmtstr[sizeof(DFMTNP)-2] = f.base; /* sizeof includes '\0' */ \ 785 710 /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star]); */ \ 786 PrintWithDP2( os, &fmtstr[star], f. val, f.wd) \711 PrintWithDP2( os, &fmtstr[star], f.wd, f.val ) \ 787 712 } else { /* precision */ \ 788 713 fmtstr[sizeof(DFMTP)-2] = f.base; /* sizeof includes '\0' */ \ 789 714 /* printf( "%g %d %d %s\n", f.val, f.wd, f.pc, &fmtstr[star] ); */ \ 790 PrintWithDP2( os, &fmtstr[star], f. val, f.wd, f.pc) \715 PrintWithDP2( os, &fmtstr[star], f.wd, f.pc, f.val ) \ 791 716 } /* if */ \ 792 717 return os; \ … … 796 721 } // distribution 797 722 798 FloatingPointFMTImpl( double, " % * ", "%*.* " )799 FloatingPointFMTImpl( long double, " % *L ", "%*.*L " )723 FloatingPointFMTImpl( double, " * ", " *.* " ) 724 FloatingPointFMTImpl( long double, " *L ", " *.*L " ) 800 725 801 726 // *********************************** character *********************************** 802 727 803 forall( ostype & | ostream( ostype ) ) {728 forall( ostype & | basic_ostream( ostype ) ) { 804 729 ostype & ?|?( ostype & os, _Ostream_Manip(char) f ) { 805 730 if ( f.base != 'c' ) { // bespoke binary/octal/hex format … … 812 737 } // if 813 738 814 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );739 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 815 740 816 741 #define CFMTNP "% * " … … 834 759 // *********************************** C string *********************************** 835 760 836 forall( ostype & | ostream( ostype ) ) {761 forall( ostype & | basic_ostream( ostype ) ) { 837 762 ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f ) { 838 763 if ( ! f.val ) return os; // null pointer ? … … 850 775 } // if 851 776 852 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );777 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); 853 778 854 779 #define SFMTNP "% * " … … 882 807 883 808 884 forall( istype & | istream( istype ) ) {809 forall( istype & | basic_istream( istype ) ) { 885 810 istype & ?|?( istype & is, bool & b ) { 886 811 char val[6]; … … 894 819 return is; 895 820 } // ?|? 821 void ?|?( istype & is, bool & b ) { 822 (istype &)(is | b); ends( is ); 823 } // ?|? 896 824 897 825 istype & ?|?( istype & is, char & c ) { … … 905 833 return is; 906 834 } // ?|? 835 void ?|?( istype & is, char & c ) { 836 (istype &)(is | c); ends( is ); 837 } // ?|? 907 838 908 839 istype & ?|?( istype & is, signed char & sc ) { … … 910 841 return is; 911 842 } // ?|? 843 void ?|?( istype & is, signed char & sc ) { 844 (istype &)(is | sc); ends( is ); 845 } // ?|? 912 846 913 847 istype & ?|?( istype & is, unsigned char & usc ) { … … 915 849 return is; 916 850 } // ?|? 851 void ?|?( istype & is, unsigned char & usc ) { 852 (istype &)(is | usc); ends( is ); 853 } // ?|? 917 854 918 855 istype & ?|?( istype & is, short int & si ) { … … 920 857 return is; 921 858 } // ?|? 859 void ?|?( istype & is, short int & si ) { 860 (istype &)(is | si); ends( is ); 861 } // ?|? 922 862 923 863 istype & ?|?( istype & is, unsigned short int & usi ) { … … 925 865 return is; 926 866 } // ?|? 867 void ?|?( istype & is, unsigned short int & usi ) { 868 (istype &)(is | usi); ends( is ); 869 } // ?|? 927 870 928 871 istype & ?|?( istype & is, int & i ) { … … 930 873 return is; 931 874 } // ?|? 875 void ?|?( istype & is, int & i ) { 876 (istype &)(is | i); ends( is ); 877 } // ?|? 932 878 933 879 istype & ?|?( istype & is, unsigned int & ui ) { … … 935 881 return is; 936 882 } // ?|? 883 void ?|?( istype & is, unsigned int & ui ) { 884 (istype &)(is | ui); ends( is ); 885 } // ?|? 937 886 938 887 istype & ?|?( istype & is, long int & li ) { … … 940 889 return is; 941 890 } // ?|? 891 void ?|?( istype & is, long int & li ) { 892 (istype &)(is | li); ends( is ); 893 } // ?|? 942 894 943 895 istype & ?|?( istype & is, unsigned long int & ulli ) { … … 945 897 return is; 946 898 } // ?|? 899 void ?|?( istype & is, unsigned long int & ulli ) { 900 (istype &)(is | ulli); ends( is ); 901 } // ?|? 947 902 948 903 istype & ?|?( istype & is, long long int & lli ) { … … 950 905 return is; 951 906 } // ?|? 907 void ?|?( istype & is, long long int & lli ) { 908 (istype &)(is | lli); ends( is ); 909 } // ?|? 952 910 953 911 istype & ?|?( istype & is, unsigned long long int & ulli ) { … … 955 913 return is; 956 914 } // ?|? 957 958 #if defined( __SIZEOF_INT128__ ) 959 istype & ?|?( istype & is, int128 & i128 ) { 960 return (istype &)(is | (unsigned int128 &)i128); 961 } // ?|? 962 963 istype & ?|?( istype & is, unsigned int128 & ui128 ) { 915 void & ?|?( istype & is, unsigned long long int & ulli ) { 916 (istype &)(is | ulli); ends( is ); 917 } // ?|? 918 919 #if defined( __SIZEOF_INT128__ ) 920 istype & ?|?( istype & is, int128 & llli ) { 921 return (istype &)(is | (unsigned int128 &)llli); 922 } // ?|? 923 void ?|?( istype & is, int128 & llli ) { 924 (istype &)(is | llli); ends( is ); 925 } // ?|? 926 927 istype & ?|?( istype & is, unsigned int128 & ullli ) { 964 928 char s[40]; 965 929 bool sign = false; … … 968 932 // If the input is too large, the value returned is undefined. If there is no input, no value is returned 969 933 if ( fmt( is, "%39[0-9]%*[0-9]", s ) == 1 ) { // take first 39 characters, ignore remaining 970 u i128= 0;934 ullli = 0; 971 935 for ( unsigned int i = 0; s[i] != '\0'; i += 1 ) { 972 u i128 = ui128* 10 + s[i] - '0';936 ullli = ullli * 10 + s[i] - '0'; 973 937 } // for 974 if ( sign ) u i128 = -ui128;938 if ( sign ) ullli = -ullli; 975 939 } else if ( sign ) ungetc( is, '-' ); // return minus when no digits 976 940 return is; 977 941 } // ?|? 978 #endif // __SIZEOF_INT128__ 942 void ?|?( istype & is, unsigned int128 & ullli ) { 943 (istype &)(is | ullli); ends( is ); 944 } // ?|? 945 #endif // __SIZEOF_INT128__ 979 946 980 947 istype & ?|?( istype & is, float & f ) { … … 982 949 return is; 983 950 } // ?|? 951 void ?|?( istype & is, float & f ) { 952 (istype &)(is | f); ends( is ); 953 } // ?|? 984 954 985 955 istype & ?|?( istype & is, double & d ) { … … 987 957 return is; 988 958 } // ?|? 959 void ?|?( istype & is, double & d ) { 960 (istype &)(is | d); ends( is ); 961 } // ?|? 989 962 990 963 istype & ?|?( istype & is, long double & ld ) { … … 992 965 return is; 993 966 } // ?|? 994 967 void ?|?( istype & is, long double & ld ) { 968 (istype &)(is | ld); ends( is ); 969 } // ?|? 995 970 996 971 istype & ?|?( istype & is, float _Complex & fc ) { … … 1000 975 return is; 1001 976 } // ?|? 977 void ?|?( istype & is, float _Complex & fc ) { 978 (istype &)(is | fc); ends( is ); 979 } // ?|? 1002 980 1003 981 istype & ?|?( istype & is, double _Complex & dc ) { … … 1007 985 return is; 1008 986 } // ?|? 987 void ?|?( istype & is, double _Complex & dc ) { 988 (istype &)(is | dc); ends( is ); 989 } // ?|? 1009 990 1010 991 istype & ?|?( istype & is, long double _Complex & ldc ) { … … 1014 995 return is; 1015 996 } // ?|? 997 void ?|?( istype & is, long double _Complex & ldc ) { 998 (istype &)(is | ldc); ends( is ); 999 } // ?|? 1016 1000 1017 1001 // istype & ?|?( istype & is, const char fmt[] ) { … … 1020 1004 // } // ?|? 1021 1005 1022 istype & ?|?( istype & is, char * s) {1006 istype & ?|?( istype & is, char s[] ) { 1023 1007 fmt( is, "%s", s ); 1024 1008 return is; 1009 } // ?|? 1010 void ?|?( istype & is, char s[] ) { 1011 (istype &)(is | s); ends( is ); 1025 1012 } // ?|? 1026 1013 … … 1029 1016 return manip( is ); 1030 1017 } // ?|? 1018 void ?|?( istype & is, istype & (* manip)( istype & ) ) { 1019 manip( is ); ends( is ); 1020 } // ?|? 1031 1021 1032 1022 istype & nl( istype & is ) { … … 1046 1036 } // distribution 1047 1037 1038 forall( istype & | istream( istype ) ) { 1039 istype & acquire( istype & is ) { 1040 acquire( is ); // call void returning 1041 return is; 1042 } // acquire 1043 } // distribution 1044 1048 1045 // *********************************** manipulators *********************************** 1049 1046 1050 forall( istype & | istream( istype ) ) 1051 istype & ?|?( istype & is, _Istream_Cstr f ) { 1052 // skip xxx 1053 if ( ! f.s ) { 1054 // printf( "skip %s %d\n", f.scanset, f.wd ); 1055 if ( f.wd == -1 ) fmt( is, f.scanset, "" ); // no input arguments 1056 else for ( f.wd ) fmt( is, "%*c" ); 1057 return is; 1058 } // if 1059 size_t len = 0; 1060 if ( f.scanset ) len = strlen( f.scanset ); 1061 char fmtstr[len + 16]; 1062 int start = 1; 1063 fmtstr[0] = '%'; 1064 if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; } 1065 if ( f.wd != -1 ) { start += sprintf( &fmtstr[start], "%d", f.wd ); } 1066 // cstr %s, %*s, %ws, %*ws 1067 if ( ! f.scanset ) { 1068 fmtstr[start] = 's'; fmtstr[start + 1] = '\0'; 1069 // printf( "cstr %s\n", fmtstr ); 1047 forall( istype & | basic_istream( istype ) ) { 1048 istype & ?|?( istype & is, _Istream_Cstr f ) { 1049 // skip xxx 1050 if ( ! f.s ) { 1051 // printf( "skip %s %d\n", f.scanset, f.wd ); 1052 if ( f.wd == -1 ) fmt( is, f.scanset, "" ); // no input arguments 1053 else for ( f.wd ) fmt( is, "%*c" ); 1054 return is; 1055 } // if 1056 size_t len = 0; 1057 if ( f.scanset ) len = strlen( f.scanset ); 1058 char fmtstr[len + 16]; 1059 int start = 1; 1060 fmtstr[0] = '%'; 1061 if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; } 1062 if ( f.wd != -1 ) { start += sprintf( &fmtstr[start], "%d", f.wd ); } 1063 // cstr %s, %*s, %ws, %*ws 1064 if ( ! f.scanset ) { 1065 fmtstr[start] = 's'; fmtstr[start + 1] = '\0'; 1066 // printf( "cstr %s\n", fmtstr ); 1067 fmt( is, fmtstr, f.s ); 1068 return is; 1069 } // if 1070 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx] 1071 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx] 1072 fmtstr[start] = '['; start += 1; 1073 if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; } 1074 strcpy( &fmtstr[start], f.scanset ); // copy includes '\0' 1075 len += start; 1076 fmtstr[len] = ']'; fmtstr[len + 1] = '\0'; 1077 // printf( "incl/excl %s\n", fmtstr ); 1070 1078 fmt( is, fmtstr, f.s ); 1071 1079 return is; 1072 } // if 1073 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx] 1074 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx] 1075 fmtstr[start] = '['; start += 1; 1076 if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; } 1077 strcpy( &fmtstr[start], f.scanset ); // copy includes '\0' 1078 len += start; 1079 fmtstr[len] = ']'; fmtstr[len + 1] = '\0'; 1080 // printf( "incl/excl %s\n", fmtstr ); 1081 fmt( is, fmtstr, f.s ); 1082 return is; 1083 } // ?|? 1084 1085 forall( istype & | istream( istype ) ) 1086 istype & ?|?( istype & is, _Istream_Char f ) { 1087 fmt( is, "%*c" ); // argument variable unused 1088 return is; 1089 } // ?|? 1080 } // ?|? 1081 void ?|?( istype & is, _Istream_Cstr f ) { 1082 (istype &)(is | f); ends( is ); 1083 } // ?|? 1084 1085 istype & ?|?( istype & is, _Istream_Char f ) { 1086 fmt( is, "%*c" ); // argument variable unused 1087 return is; 1088 } // ?|? 1089 void ?|?( istype & is, _Istream_Char f ) { 1090 (istype &)(is | f); ends( is ); 1091 } // ?|? 1092 } // distribution 1090 1093 1091 1094 #define InputFMTImpl( T, CODE ) \ 1092 forall( istype & | istream( istype ) ) \ 1093 istype & ?|?( istype & is, _Istream_Manip(T) f ) { \ 1094 enum { size = 16 }; \ 1095 char fmtstr[size]; \ 1096 if ( f.wd == -1 ) { \ 1097 snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \ 1098 } else { \ 1099 snprintf( fmtstr, size, "%%%s%d%s", f.ignore ? "*" : "", f.wd, CODE ); \ 1100 } /* if */ \ 1101 /* printf( "%d %s %p\n", f.wd, fmtstr, &f.val ); */ \ 1102 fmt( is, fmtstr, &f.val ); \ 1103 return is; \ 1104 } // ?|? 1095 forall( istype & | basic_istream( istype ) ) { \ 1096 istype & ?|?( istype & is, _Istream_Manip(T) f ) { \ 1097 enum { size = 16 }; \ 1098 char fmtstr[size]; \ 1099 if ( f.wd == -1 ) { \ 1100 snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \ 1101 } else { \ 1102 snprintf( fmtstr, size, "%%%s%d%s", f.ignore ? "*" : "", f.wd, CODE ); \ 1103 } /* if */ \ 1104 /* printf( "%d %s %p\n", f.wd, fmtstr, &f.val ); */ \ 1105 fmt( is, fmtstr, &f.val ); \ 1106 return is; \ 1107 } /* ?|? */ \ 1108 void ?|?( istype & is, _Istream_Manip(T) f ) { \ 1109 (istype &)(is | f); ends( is ); \ 1110 } /* ?|? */ \ 1111 } // distribution 1105 1112 1106 1113 InputFMTImpl( signed char, "hhi" ) … … 1119 1126 InputFMTImpl( long double, "Lf" ) 1120 1127 1121 forall( istype & | istream( istype ) ) 1122 istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) { 1123 float re, im; 1124 _Istream_Manip(float) fmtuc @= { re, fc.wd, fc.ignore }; 1125 is | fmtuc; 1126 &fmtuc.val = &im; 1127 is | fmtuc; 1128 if ( ! fc.ignore ) fc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1129 return is; 1130 } // ?|? 1131 1132 forall( istype & | istream( istype ) ) 1133 istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) { 1134 double re, im; 1135 _Istream_Manip(double) fmtuc @= { re, dc.wd, dc.ignore }; 1136 is | fmtuc; 1137 &fmtuc.val = &im; 1138 is | fmtuc; 1139 if ( ! dc.ignore ) dc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1140 return is; 1141 } // ?|? 1142 1143 forall( istype & | istream( istype ) ) 1144 istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) { 1145 long double re, im; 1146 _Istream_Manip(long double) fmtuc @= { re, ldc.wd, ldc.ignore }; 1147 is | fmtuc; 1148 &fmtuc.val = &im; 1149 is | fmtuc; 1150 if ( ! ldc.ignore ) ldc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1151 return is; 1152 } // ?|? 1128 forall( istype & | basic_istream( istype ) ) { 1129 istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) { 1130 float re, im; 1131 _Istream_Manip(float) fmtuc @= { re, fc.wd, fc.ignore }; 1132 is | fmtuc; 1133 &fmtuc.val = &im; 1134 is | fmtuc; 1135 if ( ! fc.ignore ) fc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1136 return is; 1137 } // ?|? 1138 void ?|?( istype & is, _Istream_Manip(float _Complex) fc ) { 1139 (istype &)(is | fc); ends( is ); 1140 } // ?|? 1141 1142 istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) { 1143 double re, im; 1144 _Istream_Manip(double) fmtuc @= { re, dc.wd, dc.ignore }; 1145 is | fmtuc; 1146 &fmtuc.val = &im; 1147 is | fmtuc; 1148 if ( ! dc.ignore ) dc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1149 return is; 1150 } // ?|? 1151 void ?|?( istype & is, _Istream_Manip(double _Complex) dc ) { 1152 (istype &)(is | dc); ends( is ); 1153 } // ?|? 1154 1155 istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) { 1156 long double re, im; 1157 _Istream_Manip(long double) fmtuc @= { re, ldc.wd, ldc.ignore }; 1158 is | fmtuc; 1159 &fmtuc.val = &im; 1160 is | fmtuc; 1161 if ( ! ldc.ignore ) ldc.val = re + im * _Complex_I; // re/im are uninitialized for ignore 1162 return is; 1163 } // ?|? 1164 void ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) { 1165 (istype &)(is | ldc); ends( is ); 1166 } // ?|? 1167 } // distribution 1153 1168 1154 1169 // Local Variables: // -
libcfa/src/iostream.hfa
rfeacef9 r5407cdc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue A ug 11 22:16:14 202013 // Update Count : 3 5012 // Last Modified On : Tue Apr 27 17:59:21 2021 13 // Update Count : 398 14 14 // 15 15 … … 22 22 23 23 24 trait ostream( ostype & ) {24 trait basic_ostream( ostype & ) { 25 25 // private 26 bool $sepPrt( ostype & ); // get separator state (on/off)27 void $sepReset( ostype & ); // set separator state to default state28 void $sepReset( ostype &, bool ); // set separator and default state29 const char * $sepGetCur( ostype & ); // get current separator string30 void $sepSetCur( ostype &, const char [] ); // set current separator string31 bool $getNL( ostype & ); // check newline32 void $setNL( ostype &, bool ); // saw newline33 bool $getANL( ostype & ); // get auto newline (on/off)34 bool $getPrt( ostype & ); // get fmt called in output cascade35 void $setPrt( ostype &, bool ); // set fmt called in output cascade26 bool sepPrt$( ostype & ); // get separator state (on/off) 27 void sepReset$( ostype & ); // set separator state to default state 28 void sepReset$( ostype &, bool ); // set separator and default state 29 const char * sepGetCur$( ostype & ); // get current separator string 30 void sepSetCur$( ostype &, const char [] ); // set current separator string 31 bool getNL$( ostype & ); // check newline 32 void setNL$( ostype &, bool ); // saw newline 33 bool getANL$( ostype & ); // get auto newline (on/off) 34 bool getPrt$( ostype & ); // get fmt called in output cascade 35 void setPrt$( ostype &, bool ); // set fmt called in output cascade 36 36 // public 37 37 void sepOn( ostype & ); // turn separator state on … … 47 47 void sepSetTuple( ostype &, const char [] ); // set tuple separator to string (15 character maximum) 48 48 49 void ends( ostype & os ); // end of output statement 50 int fail( ostype & ); 49 void ends( ostype & ); // end of output statement 50 int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) )); 51 }; // basic_ostream 52 53 trait ostream( ostype & | basic_ostream( ostype ) ) { 51 54 int flush( ostype & ); 52 void open( ostype & os, const char name[], const char mode[] ); 53 void close( ostype & os ); 55 bool fail( ostype & ); // operation failed? 56 void open( ostype &, const char name[], const char mode[] ); 57 void close( ostype & ); 54 58 ostype & write( ostype &, const char [], size_t ); 55 int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));59 void acquire( ostype & ); // concurrent access 56 60 }; // ostream 57 61 … … 66 70 // implement writable for intrinsic types 67 71 68 forall( ostype & | ostream( ostype ) ) {72 forall( ostype & | basic_ostream( ostype ) ) { 69 73 ostype & ?|?( ostype &, bool ); 70 74 void ?|?( ostype &, bool ); … … 93 97 ostype & ?|?( ostype &, unsigned long long int ); 94 98 void ?|?( ostype &, unsigned long long int ); 95 #if defined( __SIZEOF_INT128__ )99 #if defined( __SIZEOF_INT128__ ) 96 100 ostype & ?|?( ostype &, int128 ); 97 101 void ?|?( ostype &, int128 ); 98 102 ostype & ?|?( ostype &, unsigned int128 ); 99 103 void ?|?( ostype &, unsigned int128 ); 100 #endif // __SIZEOF_INT128__104 #endif // __SIZEOF_INT128__ 101 105 102 106 ostype & ?|?( ostype &, float ); … … 117 121 void ?|?( ostype &, const char [] ); 118 122 // ostype & ?|?( ostype &, const char16_t * ); 119 #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous123 #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous 120 124 // ostype & ?|?( ostype &, const char32_t * ); 121 #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )125 #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) 122 126 // ostype & ?|?( ostype &, const wchar_t * ); 123 127 ostype & ?|?( ostype &, const void * ); … … 139 143 } // distribution 140 144 145 forall( ostype & | ostream( ostype ) ) { 146 ostype & acquire( ostype & ); 147 } // distribution 148 141 149 // tuples 142 150 forall( ostype &, T, Params... | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) { … … 156 164 struct _Ostream_Manip { 157 165 T val; // polymorphic base-type 158 unsigned int wd, pc; // width, precision166 int wd, pc; // width, precision: signed for computations 159 167 char base; // numeric base / floating-point style 160 168 union { 161 169 unsigned char all; 162 170 struct { 171 unsigned char eng:1; // engineering notation 163 172 unsigned char neg:1; // val is negative 164 173 unsigned char pc:1; // precision specified … … 183 192 _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'x', { .all : 0 } }; } \ 184 193 _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, CODE, { .all : 0 } }; } \ 185 _Ostream_Manip(T) wd( unsigned int w, unsigned charpc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \194 _Ostream_Manip(T) wd( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \ 186 195 _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \ 187 _Ostream_Manip(T) & wd( unsigned int w, unsigned charpc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \196 _Ostream_Manip(T) & wd( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \ 188 197 _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \ 189 198 _Ostream_Manip(T) & upcase( _Ostream_Manip(T) & fmt ) { if ( fmt.base == 'x' || fmt.base == 'b' ) fmt.base -= 32; /* upper case */ return fmt; } \ … … 193 202 _Ostream_Manip(T) & sign( _Ostream_Manip(T) & fmt ) { fmt.flags.sign = true; return fmt; } \ 194 203 } /* distribution */ \ 195 forall( ostype & | ostream( ostype ) ) { \204 forall( ostype & | basic_ostream( ostype ) ) { \ 196 205 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \ 197 206 void ?|?( ostype & os, _Ostream_Manip(T) f ); \ … … 220 229 _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'a', { .all : 0 } }; } \ 221 230 _Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'e', { .all : 0 } }; } \ 222 _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .all : 0 } }; } \ 223 _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \ 224 _Ostream_Manip(T) ws( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \ 225 _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \ 226 _Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \ 231 _Ostream_Manip(T) eng( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.eng : true } }; } \ 232 _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'g', { .all : 0 } }; } \ 233 _Ostream_Manip(T) wd( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \ 234 _Ostream_Manip(T) ws( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \ 235 _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; return fmt; } \ 236 _Ostream_Manip(T) & wd( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \ 237 _Ostream_Manip(T) & ws( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \ 227 238 _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \ 228 239 _Ostream_Manip(T) upcase( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'G', { .all : 0 } }; } \ … … 233 244 _Ostream_Manip(T) nodp( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \ 234 245 _Ostream_Manip(T) & nodp( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \ 246 _Ostream_Manip(T) unit( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \ 247 _Ostream_Manip(T) & unit( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \ 235 248 } /* distribution */ \ 236 forall( ostype & | ostream( ostype ) ) { \249 forall( ostype & | basic_ostream( ostype ) ) { \ 237 250 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \ 238 251 void ?|?( ostype & os, _Ostream_Manip(T) f ); \ … … 254 267 _Ostream_Manip(char) & nobase( _Ostream_Manip(char) & fmt ) { fmt.flags.nobsdp = true; return fmt; } 255 268 } // distribution 256 forall( ostype & | ostream( ostype ) ) {269 forall( ostype & | basic_ostream( ostype ) ) { 257 270 ostype & ?|?( ostype & os, _Ostream_Manip(char) f ); 258 271 void ?|?( ostype & os, _Ostream_Manip(char) f ); … … 266 279 _Ostream_Manip(const char *) hex( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; } 267 280 _Ostream_Manip(const char *) wd( unsigned int w, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; } 268 _Ostream_Manip(const char *) wd( unsigned int w, unsigned charpc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }281 _Ostream_Manip(const char *) wd( unsigned int w, unsigned int pc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; } 269 282 _Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; } 270 _Ostream_Manip(const char *) & wd( unsigned int w, unsigned charpc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }283 _Ostream_Manip(const char *) & wd( unsigned int w, unsigned int pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } 271 284 _Ostream_Manip(const char *) & left( _Ostream_Manip(const char *) & fmt ) { fmt.flags.left = true; return fmt; } 272 285 _Ostream_Manip(const char *) & nobase( _Ostream_Manip(const char *) & fmt ) { fmt.flags.nobsdp = true; return fmt; } 273 286 } // distribution 274 forall( ostype & | ostream( ostype ) ) {287 forall( ostype & | basic_ostream( ostype ) ) { 275 288 ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f ); 276 289 void ?|?( ostype & os, _Ostream_Manip(const char *) f ); … … 281 294 282 295 283 trait istream( istype & ) { 296 trait basic_istream( istype & ) { 297 bool getANL( istype & ); // get scan newline (on/off) 284 298 void nlOn( istype & ); // read newline 285 299 void nlOff( istype & ); // scan newline 286 bool getANL( istype & ); // get scan newline (on/off) 287 int fail( istype & ); 300 301 void ends( istype & os ); // end of output statement 302 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 303 istype & ungetc( istype &, char ); 288 304 int eof( istype & ); 305 }; // basic_istream 306 307 trait istream( istype & | basic_istream( istype ) ) { 308 bool fail( istype & ); 289 309 void open( istype & is, const char name[] ); 290 310 void close( istype & is ); 291 311 istype & read( istype &, char *, size_t ); 292 istype & ungetc( istype &, char ); 293 int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) )); 312 void acquire( istype & ); // concurrent access 294 313 }; // istream 295 314 … … 298 317 }; // readable 299 318 300 forall( istype & | istream( istype ) ) {319 forall( istype & | basic_istream( istype ) ) { 301 320 istype & ?|?( istype &, bool & ); 321 void ?|?( istype &, bool & ); 302 322 303 323 istype & ?|?( istype &, char & ); 324 void ?|?( istype &, char & ); 304 325 istype & ?|?( istype &, signed char & ); 326 void ?|?( istype &, signed char & ); 305 327 istype & ?|?( istype &, unsigned char & ); 328 void ?|?( istype &, unsigned char & ); 306 329 307 330 istype & ?|?( istype &, short int & ); 331 void ?|?( istype &, short int & ); 308 332 istype & ?|?( istype &, unsigned short int & ); 333 void ?|?( istype &, unsigned short int & ); 309 334 istype & ?|?( istype &, int & ); 335 void ?|?( istype &, int & ); 310 336 istype & ?|?( istype &, unsigned int & ); 337 void ?|?( istype &, unsigned int & ); 311 338 istype & ?|?( istype &, long int & ); 339 void ?|?( istype &, long int & ); 312 340 istype & ?|?( istype &, unsigned long int & ); 341 void ?|?( istype &, unsigned long int & ); 313 342 istype & ?|?( istype &, long long int & ); 343 void ?|?( istype &, long long int & ); 314 344 istype & ?|?( istype &, unsigned long long int & ); 315 #if defined( __SIZEOF_INT128__ ) 345 void ?|?( istype &, unsigned long long int & ); 346 #if defined( __SIZEOF_INT128__ ) 316 347 istype & ?|?( istype &, int128 & ); 348 void ?|?( istype &, int128 & ); 317 349 istype & ?|?( istype &, unsigned int128 & ); 318 #endif // __SIZEOF_INT128__ 350 void ?|?( istype &, unsigned int128 & ); 351 #endif // __SIZEOF_INT128__ 319 352 320 353 istype & ?|?( istype &, float & ); 354 void ?|?( istype &, float & ); 321 355 istype & ?|?( istype &, double & ); 356 void ?|?( istype &, double & ); 322 357 istype & ?|?( istype &, long double & ); 358 void ?|?( istype &, long double & ); 323 359 324 360 istype & ?|?( istype &, float _Complex & ); 361 void ?|?( istype &, float _Complex & ); 325 362 istype & ?|?( istype &, double _Complex & ); 363 void ?|?( istype &, double _Complex & ); 326 364 istype & ?|?( istype &, long double _Complex & ); 365 void ?|?( istype &, long double _Complex & ); 327 366 328 367 // istype & ?|?( istype &, const char [] ); 329 istype & ?|?( istype &, char * ); 368 istype & ?|?( istype &, char [] ); 369 void ?|?( istype &, char [] ); 330 370 331 371 // manipulators 332 372 istype & ?|?( istype &, istype & (*)( istype & ) ); 373 void ?|?( istype &, istype & (*)( istype & ) ); 333 374 istype & nl( istype & is ); 334 375 istype & nlOn( istype & ); 335 376 istype & nlOff( istype & ); 377 } // distribution 378 379 forall( istype & | istream( istype ) ) { 380 istype & acquire( istype & ); 336 381 } // distribution 337 382 … … 352 397 353 398 static inline { 399 _Istream_Cstr skip( const char scanset[] ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; } 354 400 _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; } 355 _Istream_Cstr skip( const char scanset[] ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }356 401 _Istream_Cstr incl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; } 357 402 _Istream_Cstr & incl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; } … … 363 408 _Istream_Cstr & wdi( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; } 364 409 } // distribution 365 forall( istype & | istream( istype ) ) istype & ?|?( istype & is, _Istream_Cstr f ); 410 forall( istype & | basic_istream( istype ) ) { 411 istype & ?|?( istype & is, _Istream_Cstr f ); 412 void ?|?( istype & is, _Istream_Cstr f ); 413 } 366 414 367 415 struct _Istream_Char { … … 373 421 _Istream_Char & ignore( _Istream_Char & fmt ) { fmt.ignore = true; return fmt; } 374 422 } // distribution 375 forall( istype & | istream( istype ) ) istype & ?|?( istype & is, _Istream_Char f ); 423 forall( istype & | basic_istream( istype ) ) { 424 istype & ?|?( istype & is, _Istream_Char f ); 425 void ?|?( istype & is, _Istream_Char f ); 426 } 376 427 377 428 forall( T & | sized( T ) ) … … 389 440 _Istream_Manip(T) & wdi( unsigned int w, _Istream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \ 390 441 } /* distribution */ \ 391 forall( istype & | istream( istype ) ) { \442 forall( istype & | basic_istream( istype ) ) { \ 392 443 istype & ?|?( istype & is, _Istream_Manip(T) f ); \ 444 void ?|?( istype & is, _Istream_Manip(T) f ); \ 393 445 } // ?|? 394 446 -
libcfa/src/math.hfa
rfeacef9 r5407cdc 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // math --7 // math.hfa -- 8 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Mon Apr 18 23:37:04 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Aug 24 08:56:20 202013 // Update Count : 1 2612 // Last Modified On : Thu Apr 15 11:47:56 2021 13 // Update Count : 132 14 14 // 15 15 … … 100 100 long double _Complex log( long double _Complex x ) { return clogl( x ); } 101 101 102 // O(1) polymorphic integer log2, using clz, which returns the number of leading 0-bits, starting at the most 103 // significant bit (single instruction on x86) 104 int log2( unsigned int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clz( n ); } 105 long int log2( unsigned long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzl( n ); } 106 long long int log2( unsigned long long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzll( n ); } 102 107 float log2( float x ) { return log2f( x ); } 103 108 // extern "C" { double log2( double ); } -
libcfa/src/startup.cfa
rfeacef9 r5407cdc 39 39 40 40 void disable_interrupts() __attribute__(( weak )) {} 41 void enable_interrupts _noPoll() __attribute__(( weak )) {}41 void enable_interrupts() __attribute__(( weak )) {} 42 42 } // extern "C" 43 43 -
libcfa/src/stdlib.hfa
rfeacef9 r5407cdc 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Jan 21 22:02:13 202113 // Update Count : 57 412 // Last Modified On : Tue Apr 20 21:20:03 2021 13 // Update Count : 575 14 14 // 15 15 … … 44 44 45 45 // Macro because of returns 46 #define $ARRAY_ALLOC( allocation, alignment, dim ) \46 #define ARRAY_ALLOC$( allocation, alignment, dim ) \ 47 47 if ( _Alignof(T) <= libAlign() ) return (T *)(void *)allocation( dim, (size_t)sizeof(T) ); /* C allocation */ \ 48 48 else return (T *)alignment( _Alignof(T), dim, sizeof(T) ) … … 57 57 58 58 T * aalloc( size_t dim ) { 59 $ARRAY_ALLOC( aalloc, amemalign, dim );59 ARRAY_ALLOC$( aalloc, amemalign, dim ); 60 60 } // aalloc 61 61 62 62 T * calloc( size_t dim ) { 63 $ARRAY_ALLOC( calloc, cmemalign, dim );63 ARRAY_ALLOC$( calloc, cmemalign, dim ); 64 64 } // calloc 65 65 … … 119 119 S_fill(T) ?`fill( T a[], size_t nmemb ) { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; } 120 120 121 3. Replace the $alloc_internalfunction which is outside ttype forall-block with following function:122 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) {121 3. Replace the alloc_internal$ function which is outside ttype forall-block with following function: 122 T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) { 123 123 T * ptr = NULL; 124 124 size_t size = sizeof(T); … … 145 145 146 146 return ptr; 147 } // $alloc_internal147 } // alloc_internal$ 148 148 */ 149 149 … … 175 175 S_realloc(T) ?`realloc ( T * a ) { return (S_realloc(T)){a}; } 176 176 177 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {177 T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) { 178 178 T * ptr = NULL; 179 179 size_t size = sizeof(T); … … 206 206 207 207 return ptr; 208 } // $alloc_internal209 210 forall( TT... | { T * $alloc_internal( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {211 212 T * $alloc_internal( void * , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) {213 return $alloc_internal( Resize, (T*)0p, Align, Dim, Fill, rest);214 } 215 216 T * $alloc_internal( void * Resize, T * , size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest) {217 return $alloc_internal( (void*)0p, Realloc, Align, Dim, Fill, rest);218 } 219 220 T * $alloc_internal( void * Resize, T * Realloc, size_t , size_t Dim, S_fill(T) Fill, T_align Align, TT rest) {221 return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest);222 } 223 224 T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) , S_fill(T) Fill, TT rest) {225 return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest);208 } // alloc_internal$ 209 210 forall( TT... | { T * alloc_internal$( void *, T *, size_t, size_t, S_fill(T), TT ); } ) { 211 212 T * alloc_internal$( void * , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) { 213 return alloc_internal$( Resize, (T*)0p, Align, Dim, Fill, rest); 214 } 215 216 T * alloc_internal$( void * Resize, T * , size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest) { 217 return alloc_internal$( (void*)0p, Realloc, Align, Dim, Fill, rest); 218 } 219 220 T * alloc_internal$( void * Resize, T * Realloc, size_t , size_t Dim, S_fill(T) Fill, T_align Align, TT rest) { 221 return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest); 222 } 223 224 T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) , S_fill(T) Fill, TT rest) { 225 return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest); 226 226 } 227 227 228 228 T * alloc( TT all ) { 229 return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all);229 return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all); 230 230 } 231 231 232 232 T * alloc( size_t dim, TT all ) { 233 return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all);233 return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all); 234 234 } 235 235 -
libcfa/src/time.hfa
rfeacef9 r5407cdc 10 10 // Created On : Wed Mar 14 23:18:57 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jun 17 16:13:00 202013 // Update Count : 66 312 // Last Modified On : Wed Apr 21 06:32:31 2021 13 // Update Count : 667 14 14 // 15 15 … … 28 28 29 29 static inline { 30 void ?{}( Duration & dur, timeval t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; } 31 void ?{}( Duration & dur, timespec t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; } 32 30 33 Duration ?=?( Duration & dur, __attribute__((unused)) zero_t ) { return dur{ 0 }; } 34 Duration ?=?( Duration & dur, timeval t ) with( dur ) { 35 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL); 36 return dur; 37 } // ?=? 38 Duration ?=?( Duration & dur, timespec t ) with( dur ) { 39 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; 40 return dur; 41 } // ?=? 31 42 32 43 Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tn }; } … … 49 60 Duration ?%?( Duration lhs, Duration rhs ) { return (Duration)@{ lhs.tn % rhs.tn }; } 50 61 Duration ?%=?( Duration & lhs, Duration rhs ) { lhs = lhs % rhs; return lhs; } 62 63 bool ?==?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn == 0; } 64 bool ?!=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn != 0; } 65 bool ?<? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn < 0; } 66 bool ?<=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn <= 0; } 67 bool ?>? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn > 0; } 68 bool ?>=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >= 0; } 51 69 52 70 bool ?==?( Duration lhs, Duration rhs ) { return lhs.tn == rhs.tn; } … … 56 74 bool ?>? ( Duration lhs, Duration rhs ) { return lhs.tn > rhs.tn; } 57 75 bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tn >= rhs.tn; } 58 59 bool ?==?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn == 0; }60 bool ?!=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn != 0; }61 bool ?<? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn < 0; }62 bool ?<=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn <= 0; }63 bool ?>? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn > 0; }64 bool ?>=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >= 0; }65 76 66 77 Duration abs( Duration rhs ) { return rhs.tn >= 0 ? rhs : -rhs; } … … 152 163 void ?{}( Time & time, int year, int month = 1, int day = 1, int hour = 0, int min = 0, int sec = 0, int64_t nsec = 0 ); 153 164 static inline { 165 void ?{}( Time & time, timeval t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; } 166 void ?{}( Time & time, timespec t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; } 167 154 168 Time ?=?( Time & time, __attribute__((unused)) zero_t ) { return time{ 0 }; } 155 156 void ?{}( Time & time, timeval t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }157 169 Time ?=?( Time & time, timeval t ) with( time ) { 158 170 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL); 159 171 return time; 160 172 } // ?=? 161 162 void ?{}( Time & time, timespec t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }163 173 Time ?=?( Time & time, timespec t ) with( time ) { 164 174 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; -
libcfa/src/virtual.c
rfeacef9 r5407cdc 15 15 16 16 #include "virtual.h" 17 #include "assert.h" 17 18 18 19 int __cfa__is_parent( struct __cfa__parent_vtable const * parent, 19 20 struct __cfa__parent_vtable const * child ) { 21 assert( child ); 20 22 do { 21 23 if ( parent == child ) … … 28 30 void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent, 29 31 struct __cfa__parent_vtable const * const * child ) { 32 assert( child ); 30 33 return (__cfa__is_parent(parent, *child)) ? (void *)child : (void *)0; 31 34 } -
src/AST/Convert.cpp
rfeacef9 r5407cdc 9 9 // Author : Thierry Delisle 10 10 // Created On : Thu May 09 15::37::05 2019 11 // Last Modified By : Andrew Beach12 // Last Modified On : Thr Nov 12 10:07:00 202013 // Update Count : 3 411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:43:51 2021 13 // Update Count : 36 14 14 // 15 15 … … 327 327 const ast::AsmDecl * visit( const ast::AsmDecl * node ) override final { 328 328 auto decl = new AsmDecl( get<AsmStmt>().accept1( node->stmt ) ); 329 declPostamble( decl, node ); 330 return nullptr; 331 } 332 333 const ast::DirectiveDecl * visit( const ast::DirectiveDecl * node ) override final { 334 auto decl = new DirectiveDecl( get<DirectiveStmt>().accept1( node->stmt ) ); 329 335 declPostamble( decl, node ); 330 336 return nullptr; … … 1769 1775 } 1770 1776 1777 virtual void visit( const DirectiveDecl * old ) override final { 1778 auto decl = new ast::DirectiveDecl{ 1779 old->location, 1780 GET_ACCEPT_1(stmt, DirectiveStmt) 1781 }; 1782 decl->extension = old->extension; 1783 decl->uniqueId = old->uniqueId; 1784 decl->storage = { old->storageClasses.val }; 1785 1786 this->node = decl; 1787 } 1788 1771 1789 virtual void visit( const StaticAssertDecl * old ) override final { 1772 1790 auto decl = new ast::StaticAssertDecl{ -
src/AST/Decl.hpp
rfeacef9 r5407cdc 10 10 // Created On : Thu May 9 10:00:00 2019 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 11 20:48:38202113 // Update Count : 3 012 // Last Modified On : Fri Mar 12 18:25:05 2021 13 // Update Count : 32 14 14 // 15 15 … … 365 365 }; 366 366 367 /// C-preprocessor directive `#...` 368 class DirectiveDecl : public Decl { 369 public: 370 ptr<DirectiveStmt> stmt; 371 372 DirectiveDecl( const CodeLocation & loc, DirectiveStmt * stmt ) 373 : Decl( loc, "", {}, {} ), stmt(stmt) {} 374 375 const DirectiveDecl * accept( Visitor & v ) const override { return v.visit( this ); } 376 private: 377 DirectiveDecl * clone() const override { return new DirectiveDecl( *this ); } 378 MUTATE_FRIEND 379 }; 380 367 381 class StaticAssertDecl : public Decl { 368 382 public: -
src/AST/Expr.cpp
rfeacef9 r5407cdc 260 260 } 261 261 262 ConstantExpr * ConstantExpr::from_string( const CodeLocation & loc, const std::string & str ) { 263 const Type * charType = new BasicType( BasicType::Char ); 264 // Adjust the length of the string for the terminator. 265 const Expr * strSize = from_ulong( loc, str.size() + 1 ); 266 const Type * strType = new ArrayType( charType, strSize, FixedLen, StaticDim ); 267 const std::string strValue = "\"" + str + "\""; 268 return new ConstantExpr( loc, strType, strValue, std::nullopt ); 269 } 270 262 271 ConstantExpr * ConstantExpr::null( const CodeLocation & loc, const Type * ptrType ) { 263 272 return new ConstantExpr{ -
src/AST/Expr.hpp
rfeacef9 r5407cdc 438 438 long long int intValue() const; 439 439 440 /// generates a boolean constant of the given bool440 /// Generates a boolean constant of the given bool. 441 441 static ConstantExpr * from_bool( const CodeLocation & loc, bool b ); 442 /// generates an integer constant of the given int442 /// Generates an integer constant of the given int. 443 443 static ConstantExpr * from_int( const CodeLocation & loc, int i ); 444 /// generates an integer constant of the given unsigned long int444 /// Generates an integer constant of the given unsigned long int. 445 445 static ConstantExpr * from_ulong( const CodeLocation & loc, unsigned long i ); 446 /// generates a null pointer value for the given type. void * if omitted. 446 /// Generates a string constant from the given string (char type, unquoted string). 447 static ConstantExpr * from_string( const CodeLocation & loc, const std::string & string ); 448 /// Generates a null pointer value for the given type. void * if omitted. 447 449 static ConstantExpr * null( const CodeLocation & loc, const Type * ptrType = nullptr ); 448 450 -
src/AST/Fwd.hpp
rfeacef9 r5407cdc 9 9 // Author : Andrew Beach 10 10 // Created On : Wed May 8 16:05:00 2019 11 // Last Modified By : Andrew Beach12 // Last Modified On : Thr Jul 23 14:15:00 202013 // Update Count : 211 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:37:39 2021 13 // Update Count : 4 14 14 // 15 15 … … 35 35 class TypedefDecl; 36 36 class AsmDecl; 37 class DirectiveDecl; 37 38 class StaticAssertDecl; 38 39 -
src/AST/Node.cpp
rfeacef9 r5407cdc 9 9 // Author : Thierry Delisle 10 10 // Created On : Thu May 16 14:16:00 2019 11 // Last Modified By : Andrew Beach12 // Last Modified On : Fri Jun 5 10:21:00 202013 // Update Count : 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:25:06 2021 13 // Update Count : 2 14 14 // 15 15 … … 130 130 template class ast::ptr_base< ast::AsmDecl, ast::Node::ref_type::weak >; 131 131 template class ast::ptr_base< ast::AsmDecl, ast::Node::ref_type::strong >; 132 template class ast::ptr_base< ast::DirectiveDecl, ast::Node::ref_type::weak >; 133 template class ast::ptr_base< ast::DirectiveDecl, ast::Node::ref_type::strong >; 132 134 template class ast::ptr_base< ast::StaticAssertDecl, ast::Node::ref_type::weak >; 133 135 template class ast::ptr_base< ast::StaticAssertDecl, ast::Node::ref_type::strong >; -
src/AST/Pass.hpp
rfeacef9 r5407cdc 139 139 const ast::Decl * visit( const ast::TypedefDecl * ) override final; 140 140 const ast::AsmDecl * visit( const ast::AsmDecl * ) override final; 141 const ast::DirectiveDecl * visit( const ast::DirectiveDecl * ) override final; 141 142 const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * ) override final; 142 143 const ast::CompoundStmt * visit( const ast::CompoundStmt * ) override final; -
src/AST/Pass.impl.hpp
rfeacef9 r5407cdc 646 646 647 647 //-------------------------------------------------------------------------- 648 // DirectiveDecl 649 template< typename core_t > 650 const ast::DirectiveDecl * ast::Pass< core_t >::visit( const ast::DirectiveDecl * node ) { 651 VISIT_START( node ); 652 653 VISIT( 654 maybe_accept( node, &DirectiveDecl::stmt ); 655 ) 656 657 VISIT_END( DirectiveDecl, node ); 658 } 659 660 //-------------------------------------------------------------------------- 648 661 // StaticAssertDecl 649 662 template< typename core_t > -
src/AST/Print.cpp
rfeacef9 r5407cdc 387 387 388 388 virtual const ast::AsmDecl * visit( const ast::AsmDecl * node ) override final { 389 safe_print( node->stmt ); 390 return node; 391 } 392 393 virtual const ast::DirectiveDecl * visit( const ast::DirectiveDecl * node ) override final { 389 394 safe_print( node->stmt ); 390 395 return node; -
src/AST/Type.cpp
rfeacef9 r5407cdc 105 105 } 106 106 107 // --- BaseInstType 108 107 109 std::vector<readonly<Decl>> BaseInstType::lookup( const std::string& name ) const { 108 110 assertf( aggr(), "Must have aggregate to perform lookup" ); … … 119 121 template<typename decl_t> 120 122 SueInstType<decl_t>::SueInstType( 121 const decl_t* b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )122 : BaseInstType( b->name, q, move(as) ), base( b ) {}123 const base_type * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 124 : BaseInstType( b->name, q, std::move(as) ), base( b ) {} 123 125 124 126 template<typename decl_t> … … 142 144 const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 143 145 : BaseInstType( b->name, q, move(as) ), base( b ) {} 146 147 // --- TypeInstType 144 148 145 149 void TypeInstType::set_base( const TypeDecl * b ) { -
src/AST/Visitor.hpp
rfeacef9 r5407cdc 9 9 // Author : Andrew Beach 10 10 // Created On : Thr May 9 15:28:00 2019 11 // Last Modified By : Andrew Beach12 // Last Modified On : Thr May 9 15:33:00 201913 // Update Count : 011 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:25:07 2021 13 // Update Count : 1 14 14 // 15 15 … … 31 31 virtual const ast::Decl * visit( const ast::TypedefDecl * ) = 0; 32 32 virtual const ast::AsmDecl * visit( const ast::AsmDecl * ) = 0; 33 virtual const ast::DirectiveDecl * visit( const ast::DirectiveDecl * ) = 0; 33 34 virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * ) = 0; 34 35 virtual const ast::CompoundStmt * visit( const ast::CompoundStmt * ) = 0; -
src/CodeGen/CodeGenerator.cc
rfeacef9 r5407cdc 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 16 08:32:48 202013 // Update Count : 53 212 // Last Modified On : Fri Mar 12 19:00:42 2021 13 // Update Count : 536 14 14 // 15 15 #include "CodeGenerator.h" … … 935 935 if ( asmStmt->get_instruction() ) asmStmt->get_instruction()->accept( *visitor ); 936 936 output << " )"; 937 } 938 939 void CodeGenerator::postvisit( DirectiveDecl * directiveDecl ) { 940 output << endl << directiveDecl->get_stmt()->directive; // endl prevents spaces before directive 937 941 } 938 942 -
src/CodeGen/CodeGenerator.h
rfeacef9 r5407cdc 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Feb 16 03:58:31 202013 // Update Count : 6 212 // Last Modified On : Fri Mar 12 18:35:38 2021 13 // Update Count : 63 14 14 // 15 15 … … 105 105 void postvisit( DirectiveStmt * ); 106 106 void postvisit( AsmDecl * ); // special: statement in declaration context 107 void postvisit( DirectiveDecl * ); // special: statement in declaration context 107 108 void postvisit( IfStmt * ); 108 109 void postvisit( SwitchStmt * ); -
src/Common/CodeLocationTools.cpp
rfeacef9 r5407cdc 9 9 // Author : Andrew Beach 10 10 // Created On : Fri Dec 4 15:42:00 2020 11 // Last Modified By : Andrew Beach12 // Last Modified On : Wed Dec 9 9:42:00 202013 // Update Count : 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:35:37 2021 13 // Update Count : 2 14 14 // 15 15 … … 102 102 macro(TypedefDecl, Decl) \ 103 103 macro(AsmDecl, AsmDecl) \ 104 macro(DirectiveDecl, DirectiveDecl) \ 104 105 macro(StaticAssertDecl, StaticAssertDecl) \ 105 106 macro(CompoundStmt, CompoundStmt) \ -
src/Common/PassVisitor.h
rfeacef9 r5407cdc 77 77 virtual void visit( AsmDecl * asmDecl ) override final; 78 78 virtual void visit( const AsmDecl * asmDecl ) override final; 79 virtual void visit( DirectiveDecl * directiveDecl ) override final; 80 virtual void visit( const DirectiveDecl * directiveDecl ) override final; 79 81 virtual void visit( StaticAssertDecl * assertDecl ) override final; 80 82 virtual void visit( const StaticAssertDecl * assertDecl ) override final; … … 261 263 virtual Declaration * mutate( TypedefDecl * typeDecl ) override final; 262 264 virtual AsmDecl * mutate( AsmDecl * asmDecl ) override final; 265 virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) override final; 263 266 virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) override final; 264 267 -
src/Common/PassVisitor.impl.h
rfeacef9 r5407cdc 973 973 974 974 //-------------------------------------------------------------------------- 975 // DirectiveDecl 976 template< typename pass_type > 977 void PassVisitor< pass_type >::visit( DirectiveDecl * node ) { 978 VISIT_START( node ); 979 980 maybeAccept_impl( node->stmt, *this ); 981 982 VISIT_END( node ); 983 } 984 985 template< typename pass_type > 986 void PassVisitor< pass_type >::visit( const DirectiveDecl * node ) { 987 VISIT_START( node ); 988 989 maybeAccept_impl( node->stmt, *this ); 990 991 VISIT_END( node ); 992 } 993 994 template< typename pass_type > 995 DirectiveDecl * PassVisitor< pass_type >::mutate( DirectiveDecl * node ) { 996 MUTATE_START( node ); 997 998 maybeMutate_impl( node->stmt, *this ); 999 1000 MUTATE_END( DirectiveDecl, node ); 1001 } 1002 1003 //-------------------------------------------------------------------------- 975 1004 // StaticAssertDecl 976 1005 template< typename pass_type > -
src/Concurrency/Keywords.cc
rfeacef9 r5407cdc 42 42 43 43 namespace Concurrency { 44 inline static std::string getTypeIdName( std::string const & exception_name ) { 45 return exception_name.empty() ? std::string() : Virtual::typeIdType( exception_name ); 46 } 44 47 inline static std::string getVTableName( std::string const & exception_name ) { 45 return exception_name.empty() ? std::string() : Virtual::vtableTypeName( exception_name);48 return exception_name.empty() ? std::string() : Virtual::vtableTypeName( exception_name ); 46 49 } 47 50 … … 75 78 type_name( type_name ), field_name( field_name ), getter_name( getter_name ), 76 79 context_error( context_error ), exception_name( exception_name ), 80 typeid_name( getTypeIdName( exception_name ) ), 77 81 vtable_name( getVTableName( exception_name ) ), 78 82 needs_main( needs_main ), cast_target( cast_target ) {} … … 84 88 85 89 void handle( StructDecl * ); 90 void addTypeId( StructDecl * ); 86 91 void addVtableForward( StructDecl * ); 87 92 FunctionDecl * forwardDeclare( StructDecl * ); … … 99 104 const std::string context_error; 100 105 const std::string exception_name; 106 const std::string typeid_name; 101 107 const std::string vtable_name; 102 108 bool needs_main; … … 106 112 FunctionDecl * dtor_decl = nullptr; 107 113 StructDecl * except_decl = nullptr; 114 StructDecl * typeid_decl = nullptr; 108 115 StructDecl * vtable_decl = nullptr; 109 116 }; … … 393 400 except_decl = decl; 394 401 } 402 else if ( !typeid_decl && typeid_name == decl->name && decl->body ) { 403 typeid_decl = decl; 404 } 395 405 else if ( !vtable_decl && vtable_name == decl->name && decl->body ) { 396 406 vtable_decl = decl; … … 404 414 if ( type_decl && isDestructorFor( decl, type_decl ) ) 405 415 dtor_decl = decl; 406 else if ( vtable_name.empty() ) 407 ; 408 else if( !decl->has_body() ) 416 else if ( vtable_name.empty() || !decl->has_body() ) 409 417 ; 410 418 else if ( auto param = isMainFor( decl, cast_target ) ) { … … 418 426 std::list< Expression * > poly_args = { new TypeExpr( struct_type->clone() ) }; 419 427 ObjectDecl * vtable_object = Virtual::makeVtableInstance( 428 "_default_vtable_object_declaration", 420 429 vtable_decl->makeInst( poly_args ), struct_type, nullptr ); 421 430 declsToAddAfter.push_back( vtable_object ); 431 declsToAddAfter.push_back( 432 new ObjectDecl( 433 Virtual::concurrentDefaultVTableName(), 434 Type::Const, 435 LinkageSpec::Cforall, 436 /* bitfieldWidth */ nullptr, 437 new ReferenceType( Type::Const, vtable_object->type->clone() ), 438 new SingleInit( new VariableExpr( vtable_object ) ) 439 ) 440 ); 422 441 declsToAddAfter.push_back( Virtual::makeGetExceptionFunction( 423 442 vtable_object, except_decl->makeInst( std::move( poly_args ) ) … … 448 467 if( !dtor_decl ) SemanticError( decl, context_error ); 449 468 450 addVtableForward( decl ); 469 if ( !exception_name.empty() ) { 470 if( !typeid_decl ) SemanticError( decl, context_error ); 471 if( !vtable_decl ) SemanticError( decl, context_error ); 472 473 addTypeId( decl ); 474 addVtableForward( decl ); 475 } 451 476 FunctionDecl * func = forwardDeclare( decl ); 452 477 ObjectDecl * field = addField( decl ); … … 454 479 } 455 480 481 void ConcurrentSueKeyword::addTypeId( StructDecl * decl ) { 482 assert( typeid_decl ); 483 StructInstType typeid_type( Type::Const, typeid_decl ); 484 typeid_type.parameters.push_back( new TypeExpr( 485 new StructInstType( noQualifiers, decl ) 486 ) ); 487 declsToAddBefore.push_back( Virtual::makeTypeIdInstance( &typeid_type ) ); 488 } 489 456 490 void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) { 457 if ( vtable_decl ) { 458 std::list< Expression * > poly_args = { 459 new TypeExpr( new StructInstType( noQualifiers, decl ) ), 460 }; 461 declsToAddBefore.push_back( Virtual::makeGetExceptionForward( 462 vtable_decl->makeInst( poly_args ), 463 except_decl->makeInst( poly_args ) 464 ) ); 465 declsToAddBefore.push_back( Virtual::makeVtableForward( 466 vtable_decl->makeInst( move( poly_args ) ) ) ); 467 // Its only an error if we want a vtable and don't have one. 468 } else if ( ! vtable_name.empty() ) { 469 SemanticError( decl, context_error ); 470 } 491 assert( vtable_decl ); 492 std::list< Expression * > poly_args = { 493 new TypeExpr( new StructInstType( noQualifiers, decl ) ), 494 }; 495 declsToAddBefore.push_back( Virtual::makeGetExceptionForward( 496 vtable_decl->makeInst( poly_args ), 497 except_decl->makeInst( poly_args ) 498 ) ); 499 ObjectDecl * vtable_object = Virtual::makeVtableForward( 500 "_default_vtable_object_declaration", 501 vtable_decl->makeInst( move( poly_args ) ) ); 502 declsToAddBefore.push_back( vtable_object ); 503 declsToAddBefore.push_back( 504 new ObjectDecl( 505 Virtual::concurrentDefaultVTableName(), 506 Type::Const, 507 LinkageSpec::Cforall, 508 /* bitfieldWidth */ nullptr, 509 new ReferenceType( Type::Const, vtable_object->type->clone() ), 510 /* init */ nullptr 511 ) 512 ); 471 513 } 472 514 -
src/Parser/DeclarationNode.cc
rfeacef9 r5407cdc 10 10 // Created On : Sat May 16 12:34:05 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 11 20:58:07202113 // Update Count : 11 3712 // Last Modified On : Tue Mar 23 08:44:08 2021 13 // Update Count : 1149 14 14 // 15 15 … … 167 167 } 168 168 169 DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {170 DeclarationNode * newnode = new DeclarationNode;171 newnode->name = name;172 newnode->type = new TypeData( TypeData::Function );173 newnode->type->function.params = param;174 newnode->type->function.body = body;175 176 if ( ret ) {177 newnode->type->base = ret->type;178 ret->type = nullptr;179 delete ret;180 } // if181 182 return newnode;183 } // DeclarationNode::newFunction184 185 186 169 DeclarationNode * DeclarationNode::newStorageClass( Type::StorageClasses sc ) { 187 170 DeclarationNode * newnode = new DeclarationNode; … … 237 220 return newnode; 238 221 } // DeclarationNode::newForall 239 240 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) {241 DeclarationNode * newnode = new DeclarationNode;242 newnode->type = new TypeData( TypeData::SymbolicInst );243 newnode->type->symbolic.name = name;244 newnode->type->symbolic.isTypedef = true;245 newnode->type->symbolic.params = nullptr;246 return newnode;247 } // DeclarationNode::newFromTypedef248 222 249 223 DeclarationNode * DeclarationNode::newFromGlobalScope() { … … 289 263 } // DeclarationNode::newEnum 290 264 265 DeclarationNode * DeclarationNode::newName( const string * name ) { 266 DeclarationNode * newnode = new DeclarationNode; 267 assert( ! newnode->name ); 268 newnode->name = name; 269 return newnode; 270 } // DeclarationNode::newName 271 291 272 DeclarationNode * DeclarationNode::newEnumConstant( const string * name, ExpressionNode * constant ) { 292 DeclarationNode * newnode = new DeclarationNode; 293 newnode->name = name; 273 DeclarationNode * newnode = newName( name ); 294 274 newnode->enumeratorValue.reset( constant ); 295 275 return newnode; 296 276 } // DeclarationNode::newEnumConstant 297 277 298 DeclarationNode * DeclarationNode::newName( const string * name ) { 299 DeclarationNode * newnode = new DeclarationNode; 300 newnode->name = name; 301 return newnode; 302 } // DeclarationNode::newName 278 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) { 279 DeclarationNode * newnode = new DeclarationNode; 280 newnode->type = new TypeData( TypeData::SymbolicInst ); 281 newnode->type->symbolic.name = name; 282 newnode->type->symbolic.isTypedef = true; 283 newnode->type->symbolic.params = nullptr; 284 return newnode; 285 } // DeclarationNode::newFromTypedef 303 286 304 287 DeclarationNode * DeclarationNode::newFromTypeGen( const string * name, ExpressionNode * params ) { … … 312 295 313 296 DeclarationNode * DeclarationNode::newTypeParam( TypeDecl::Kind tc, const string * name ) { 314 DeclarationNode * newnode = new DeclarationNode;297 DeclarationNode * newnode = newName( name ); 315 298 newnode->type = nullptr; 316 assert( ! newnode->name );317 // newnode->variable.name = name;318 newnode->name = name;319 299 newnode->variable.tyClass = tc; 320 300 newnode->variable.assertions = nullptr; … … 343 323 344 324 DeclarationNode * DeclarationNode::newTypeDecl( const string * name, DeclarationNode * typeParams ) { 345 DeclarationNode * newnode = new DeclarationNode; 346 newnode->name = name; 325 DeclarationNode * newnode = newName( name ); 347 326 newnode->type = new TypeData( TypeData::Symbolic ); 348 327 newnode->type->symbolic.isTypedef = false; … … 417 396 } // DeclarationNode::newBuiltinType 418 397 398 DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) { 399 DeclarationNode * newnode = newName( name ); 400 newnode->type = new TypeData( TypeData::Function ); 401 newnode->type->function.params = param; 402 newnode->type->function.body = body; 403 404 if ( ret ) { 405 newnode->type->base = ret->type; 406 ret->type = nullptr; 407 delete ret; 408 } // if 409 410 return newnode; 411 } // DeclarationNode::newFunction 412 419 413 DeclarationNode * DeclarationNode::newAttribute( const string * name, ExpressionNode * expr ) { 420 414 DeclarationNode * newnode = new DeclarationNode; … … 424 418 newnode->attributes.push_back( new Attribute( *name, exprs ) ); 425 419 delete name; 420 return newnode; 421 } 422 423 DeclarationNode * DeclarationNode::newDirectiveStmt( StatementNode * stmt ) { 424 DeclarationNode * newnode = new DeclarationNode; 425 newnode->directiveStmt = stmt; 426 426 return newnode; 427 427 } … … 879 879 } 880 880 881 DeclarationNode * DeclarationNode::cloneType( string * n ewName ) {882 DeclarationNode * newnode = new DeclarationNode;881 DeclarationNode * DeclarationNode::cloneType( string * name ) { 882 DeclarationNode * newnode = newName( name ); 883 883 newnode->type = maybeClone( type ); 884 884 newnode->copySpecifiers( this ); 885 assert( newName );886 newnode->name = newName;887 885 return newnode; 888 886 } … … 1072 1070 return new AsmDecl( strict_dynamic_cast<AsmStmt *>( asmStmt->build() ) ); 1073 1071 } // if 1072 if ( directiveStmt ) { 1073 return new DirectiveDecl( strict_dynamic_cast<DirectiveStmt *>( directiveStmt->build() ) ); 1074 } // if 1074 1075 1075 1076 if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) { -
src/Parser/ParseNode.h
rfeacef9 r5407cdc 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Jan 3 18:23:01202113 // Update Count : 89 612 // Last Modified On : Fri Mar 12 15:19:04 2021 13 // Update Count : 897 14 14 // 15 15 … … 249 249 static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false ); 250 250 static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes 251 static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement 251 252 static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement 252 253 static DeclarationNode * newStaticAssert( ExpressionNode * condition, Expression * message ); … … 345 346 std::string error; 346 347 StatementNode * asmStmt = nullptr; 348 StatementNode * directiveStmt = nullptr; 347 349 348 350 static UniqueName anonymous; -
src/Parser/TypeData.h
rfeacef9 r5407cdc 7 7 // TypeData.h -- 8 8 // 9 // Author : Rodolfo G. Esteves9 // Author : Peter A. Buhr 10 10 // Created On : Sat May 16 15:18:36 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 23:42:35 201913 // Update Count : 19912 // Last Modified On : Sat Mar 27 09:05:35 2021 13 // Update Count : 200 14 14 // 15 15 16 16 #pragma once 17 17 18 #include <iosfwd> 19 #include <list> 20 #include <string> 18 #include <iosfwd> // for ostream 19 #include <list> // for list 20 #include <string> // for string 21 21 22 #include "ParseNode.h" 23 #include "SynTree/LinkageSpec.h" 24 #include "SynTree/Type.h" 25 #include "SynTree/SynTree.h" 22 #include "ParseNode.h" // for DeclarationNode, DeclarationNode::Ag... 23 #include "SynTree/LinkageSpec.h" // for Spec 24 #include "SynTree/Type.h" // for Type, ReferenceToType (ptr only) 25 #include "SynTree/SynTree.h" // for Visitor Nodes 26 26 27 27 struct TypeData { … … 33 33 const std::string * name = nullptr; 34 34 DeclarationNode * params = nullptr; 35 ExpressionNode * actuals = nullptr; 35 ExpressionNode * actuals = nullptr; // holds actual parameters later applied to AggInst 36 36 DeclarationNode * fields = nullptr; 37 37 bool body; … … 62 62 63 63 struct Function_t { 64 mutable DeclarationNode * params = nullptr; 65 mutable DeclarationNode * idList = nullptr; 64 mutable DeclarationNode * params = nullptr; // mutables modified in buildKRFunction 65 mutable DeclarationNode * idList = nullptr; // old-style 66 66 mutable DeclarationNode * oldDeclList = nullptr; 67 67 StatementNode * body = nullptr; 68 ExpressionNode * withExprs = nullptr; 68 ExpressionNode * withExprs = nullptr; // expressions from function's with_clause 69 69 }; 70 70 -
src/Parser/TypedefTable.cc
rfeacef9 r5407cdc 10 10 // Created On : Sat May 16 15:20:13 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Feb 15 08:06:36 202013 // Update Count : 2 5912 // Last Modified On : Mon Mar 15 20:56:47 2021 13 // Update Count : 260 14 14 // 15 15 … … 89 89 debugPrint( cerr << "Adding enclosing at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl ); 90 90 auto ret = kindTable.insertAt( scope, identifier, kind ); 91 if ( ! ret.second ) ret.first->second = kind; // exists => update91 if ( ! ret.second ) ret.first->second = kind; // exists => update 92 92 } // TypedefTable::addToEnclosingScope 93 93 -
src/Parser/lex.ll
rfeacef9 r5407cdc 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : T ue Oct 6 18:15:41 202013 * Update Count : 7 4312 * Last Modified On : Thu Apr 1 13:22:31 2021 13 * Update Count : 754 14 14 */ 15 15 … … 221 221 break { KEYWORD_RETURN(BREAK); } 222 222 case { KEYWORD_RETURN(CASE); } 223 catch { KEYWORD_RETURN(CATCH); } // CFA224 catchResume { KEYWORD_RETURN(CATCHRESUME); } // CFA223 catch { QKEYWORD_RETURN(CATCH); } // CFA 224 catchResume { QKEYWORD_RETURN(CATCHRESUME); } // CFA 225 225 char { KEYWORD_RETURN(CHAR); } 226 226 choose { KEYWORD_RETURN(CHOOSE); } // CFA … … 247 247 fallthrough { KEYWORD_RETURN(FALLTHROUGH); } // CFA 248 248 fallthru { KEYWORD_RETURN(FALLTHRU); } // CFA 249 finally { KEYWORD_RETURN(FINALLY); } // CFA 249 finally { QKEYWORD_RETURN(FINALLY); } // CFA 250 fixup { QKEYWORD_RETURN(FIXUP); } // CFA 250 251 float { KEYWORD_RETURN(FLOAT); } 251 252 __float80 { KEYWORD_RETURN(uuFLOAT80); } // GCC … … 287 288 or { QKEYWORD_RETURN(WOR); } // CFA 288 289 otype { KEYWORD_RETURN(OTYPE); } // CFA 290 recover { QKEYWORD_RETURN(RECOVER); } // CFA 289 291 register { KEYWORD_RETURN(REGISTER); } 292 report { KEYWORD_RETURN(THROWRESUME); } // CFA 290 293 restrict { KEYWORD_RETURN(RESTRICT); } // C99 291 294 __restrict { KEYWORD_RETURN(RESTRICT); } // GCC … … 315 318 __typeof { KEYWORD_RETURN(TYPEOF); } // GCC 316 319 __typeof__ { KEYWORD_RETURN(TYPEOF); } // GCC 320 typeid { KEYWORD_RETURN(TYPEID); } // GCC 317 321 union { KEYWORD_RETURN(UNION); } 318 322 __uint128_t { KEYWORD_RETURN(UINT128); } // GCC … … 324 328 __volatile { KEYWORD_RETURN(VOLATILE); } // GCC 325 329 __volatile__ { KEYWORD_RETURN(VOLATILE); } // GCC 326 waitfor { KEYWORD_RETURN(WAITFOR); } 327 when { KEYWORD_RETURN(WHEN); } 330 vtable { KEYWORD_RETURN(VTABLE); } // CFA 331 waitfor { KEYWORD_RETURN(WAITFOR); } // CFA 332 when { KEYWORD_RETURN(WHEN); } // CFA 328 333 while { KEYWORD_RETURN(WHILE); } 329 334 with { KEYWORD_RETURN(WITH); } // CFA -
src/Parser/parser.yy
rfeacef9 r5407cdc 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 3 18:30:12202113 // Update Count : 4 70012 // Last Modified On : Mon Apr 26 18:41:54 2021 13 // Update Count : 4990 14 14 // 15 15 … … 32 32 // 33 33 // 1. designation with and without '=' (use ':' instead) 34 // 2. attributes not allowed in parenthesis of declarator 34 35 35 // 36 36 // All of the syntactic extensions for GCC C are marked with the comment "GCC". The second extensions are for Cforall … … 211 211 } // forCtrl 212 212 213 bool forall = false , yyy = false;// aggregate have one or more forall qualifiers ?213 bool forall = false; // aggregate have one or more forall qualifiers ? 214 214 215 215 // https://www.gnu.org/software/bison/manual/bison.html#Location-Type … … 264 264 %token RESTRICT // C99 265 265 %token ATOMIC // C11 266 %token FORALL MUTEX VIRTUAL COERCE// CFA266 %token FORALL MUTEX VIRTUAL VTABLE COERCE // CFA 267 267 %token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED 268 268 %token BOOL COMPLEX IMAGINARY // C99 … … 270 270 %token uFLOAT16 uFLOAT32 uFLOAT32X uFLOAT64 uFLOAT64X uFLOAT128 // GCC 271 271 %token ZERO_T ONE_T // CFA 272 %token VALIST // GCC 273 %token AUTO_TYPE // GCC 274 %token TYPEOF BASETYPEOF LABEL // GCC 272 %token SIZEOF TYPEOF VALIST AUTO_TYPE // GCC 273 %token OFFSETOF BASETYPEOF TYPEID // CFA 275 274 %token ENUM STRUCT UNION 276 275 %token EXCEPTION // CFA 277 276 %token GENERATOR COROUTINE MONITOR THREAD // CFA 278 277 %token OTYPE FTYPE DTYPE TTYPE TRAIT // CFA 279 %token SIZEOF OFFSETOF280 278 // %token RESUME // CFA 279 %token LABEL // GCC 281 280 %token SUSPEND // CFA 282 281 %token ATTRIBUTE EXTENSION // GCC 283 282 %token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN 284 %token CHOOSE DISABLE ENABLE FALLTHRU FALLTHROUGH TRY CATCH CATCHRESUME FINALLY THROW THROWRESUME AT WITH WHEN WAITFOR // CFA 283 %token CHOOSE FALLTHRU FALLTHROUGH WITH WHEN WAITFOR // CFA 284 %token DISABLE ENABLE TRY THROW THROWRESUME AT // CFA 285 285 %token ASM // C99, extension ISO/IEC 9899:1999 Section J.5.10(1) 286 286 %token ALIGNAS ALIGNOF GENERIC STATICASSERT // C11 287 287 288 288 // names and constants: lexer differentiates between identifier and typedef names 289 %token<tok> IDENTIFIER QUOTED_IDENTIFIER TYPEDEFnameTYPEGENname290 %token<tok> TIMEOUT WOR291 %token<tok> INTEGERconstant CHARACTERconstantSTRINGliteral289 %token<tok> IDENTIFIER QUOTED_IDENTIFIER TYPEDEFname TYPEGENname 290 %token<tok> TIMEOUT WOR CATCH RECOVER CATCHRESUME FIXUP FINALLY // CFA 291 %token<tok> INTEGERconstant CHARACTERconstant STRINGliteral 292 292 %token<tok> DIRECTIVE 293 293 // Floating point constant is broken into three kinds of tokens because of the ambiguity with tuple indexing and … … 321 321 %type<en> constant 322 322 %type<en> tuple tuple_expression_list 323 %type<op> ptrref_operator unary_operator assignment_operator 323 %type<op> ptrref_operator unary_operator assignment_operator simple_assignment_operator compound_assignment_operator 324 324 %type<en> primary_expression postfix_expression unary_expression 325 325 %type<en> cast_expression_list cast_expression exponential_expression multiplicative_expression additive_expression … … 373 373 374 374 %type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type 375 %type<decl> vtable vtable_opt default_opt 375 376 376 377 %type<decl> trait_declaration trait_declaration_list trait_declaring_list trait_specifier … … 428 429 429 430 %type<decl> type_declaration_specifier type_type_specifier type_name typegen_name 430 %type<decl> typedef typedef_declaration typedef_expression431 %type<decl> typedef_name typedef_declaration typedef_expression 431 432 432 433 %type<decl> variable_type_redeclarator type_ptr type_array type_function … … 440 441 441 442 %type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list 442 %type<decl> type_specifier type_specifier_nobody enum_specifier_nobody443 %type<decl> type_specifier type_specifier_nobody 443 444 444 445 %type<decl> variable_declarator variable_ptr variable_array variable_function 445 446 %type<decl> variable_abstract_declarator variable_abstract_ptr variable_abstract_array variable_abstract_function 446 447 447 %type<decl> attribute_list_opt attribute_list attribute _opt attributeattribute_name_list attribute_name448 %type<decl> attribute_list_opt attribute_list attribute attribute_name_list attribute_name 448 449 449 450 // initializers … … 462 463 // Order of these lines matters (low-to-high precedence). THEN is left associative over WOR/TIMEOUT/ELSE, WOR is left 463 464 // associative over TIMEOUT/ELSE, and TIMEOUT is left associative over ELSE. 464 %precedence THEN // rule precedence for IF/WAITFOR statement 465 %precedence WOR // token precedence for start of WOR in WAITFOR statement 466 %precedence TIMEOUT // token precedence for start of TIMEOUT in WAITFOR statement 467 %precedence ELSE // token precedence for start of else clause in IF/WAITFOR statement 465 %precedence THEN // rule precedence for IF/WAITFOR statement 466 %precedence WOR // token precedence for start of WOR in WAITFOR statement 467 %precedence TIMEOUT // token precedence for start of TIMEOUT in WAITFOR statement 468 %precedence CATCH // token precedence for start of TIMEOUT in WAITFOR statement 469 %precedence RECOVER // token precedence for start of TIMEOUT in WAITFOR statement 470 %precedence CATCHRESUME // token precedence for start of TIMEOUT in WAITFOR statement 471 %precedence FIXUP // token precedence for start of TIMEOUT in WAITFOR statement 472 %precedence FINALLY // token precedence for start of TIMEOUT in WAITFOR statement 473 %precedence ELSE // token precedence for start of else clause in IF/WAITFOR statement 474 468 475 469 476 // Handle shift/reduce conflict for generic type by shifting the '(' token. For example, this string is ambiguous: … … 544 551 TIMEOUT 545 552 | WOR 553 | CATCH 554 | RECOVER 555 | CATCHRESUME 556 | FIXUP 557 | FINALLY 546 558 ; 547 559 … … 774 786 | OFFSETOF '(' type_no_function ',' identifier ')' 775 787 { $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) ); } 788 | TYPEID '(' type_no_function ')' 789 { 790 SemanticError( yylloc, "typeid name is currently unimplemented." ); $$ = nullptr; 791 // $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) ); 792 } 776 793 ; 777 794 … … 795 812 { $$ = new ExpressionNode( build_cast( $2, $4 ) ); } 796 813 | '(' aggregate_control '&' ')' cast_expression // CFA 814 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); } 815 | '(' aggregate_control '*' ')' cast_expression // CFA 797 816 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); } 798 817 | '(' VIRTUAL ')' cast_expression // CFA … … 939 958 940 959 assignment_operator: 960 simple_assignment_operator 961 | compound_assignment_operator 962 ; 963 964 simple_assignment_operator: 941 965 '=' { $$ = OperKinds::Assign; } 942 | ATassign { $$ = OperKinds::AtAssn; } 943 | EXPassign { $$ = OperKinds::ExpAssn; } 966 | ATassign { $$ = OperKinds::AtAssn; } // CFA 967 ; 968 969 compound_assignment_operator: 970 EXPassign { $$ = OperKinds::ExpAssn; } 944 971 | MULTassign { $$ = OperKinds::MulAssn; } 945 972 | DIVassign { $$ = OperKinds::DivAssn; } … … 1019 1046 { $$ = new StatementNode( build_compound( (StatementNode *)0 ) ); } 1020 1047 | '{' push 1021 local_label_declaration_opt // GCC, local labels 1048 local_label_declaration_opt // GCC, local labels appear at start of block 1022 1049 statement_decl_list // C99, intermix declarations and statements 1023 1050 pop '}' … … 1217 1244 | comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA 1218 1245 { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, $7 ); } 1246 1247 | comma_expression ';' TYPEDEFname // CFA, array type 1248 { 1249 SemanticError( yylloc, "Array interator is currently unimplemented." ); $$ = nullptr; 1250 $$ = forCtrl( new ExpressionNode( build_varref( $3 ) ), $1, nullptr, OperKinds::Range, nullptr, nullptr ); 1251 } 1219 1252 1220 1253 // There is a S/R conflicit if ~ and -~ are factored out. … … 1366 1399 1367 1400 exception_statement: 1368 TRY compound_statement handler_clause 1401 TRY compound_statement handler_clause %prec THEN 1369 1402 { $$ = new StatementNode( build_try( $2, $3, 0 ) ); } 1370 1403 | TRY compound_statement finally_clause … … 1389 1422 handler_key: 1390 1423 CATCH { $$ = CatchStmt::Terminate; } 1424 | RECOVER { $$ = CatchStmt::Terminate; } 1391 1425 | CATCHRESUME { $$ = CatchStmt::Resume; } 1426 | FIXUP { $$ = CatchStmt::Resume; } 1392 1427 ; 1393 1428 … … 1741 1776 ; 1742 1777 1743 enum_specifier_nobody: // type specifier - {...}1744 // Preclude SUE declarations in restricted scopes (see type_specifier_nobody)1745 basic_type_specifier1746 | sue_type_specifier_nobody1747 ;1748 1749 1778 type_qualifier_list_opt: // GCC, used in asm_statement 1750 1779 // empty … … 1766 1795 type_qualifier: 1767 1796 type_qualifier_name 1768 | attribute 1797 | attribute // trick handles most atrribute locations 1769 1798 ; 1770 1799 … … 1874 1903 | AUTO_TYPE 1875 1904 { $$ = DeclarationNode::newBuiltinType( DeclarationNode::AutoType ); } 1905 | vtable 1906 ; 1907 1908 vtable_opt: 1909 // empty 1910 { $$ = nullptr; } 1911 | vtable; 1912 ; 1913 1914 vtable: 1915 VTABLE '(' type_list ')' default_opt 1916 { SemanticError( yylloc, "vtable is currently unimplemented." ); $$ = nullptr; } 1917 ; 1918 1919 default_opt: 1920 // empty 1921 { $$ = nullptr; } 1922 | DEFAULT 1923 { SemanticError( yylloc, "vtable default is currently unimplemented." ); $$ = nullptr; } 1876 1924 ; 1877 1925 … … 2025 2073 '{' field_declaration_list_opt '}' type_parameters_opt 2026 2074 { $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); } 2027 | aggregate_key attribute_list_opt type_name 2028 { 2029 // for type_name can be a qualified type name S.T, in which case only the last name in the chain needs a typedef (other names in the chain should already have one) 2030 typedefTable.makeTypedef( *$3->type->leafName(), forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef 2075 | aggregate_key attribute_list_opt TYPEDEFname // unqualified type name 2076 { 2077 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef 2031 2078 forall = false; // reset 2032 2079 } 2033 2080 '{' field_declaration_list_opt '}' type_parameters_opt 2034 { $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, $8, $6, true )->addQualifiers( $2 ); } 2081 { 2082 DeclarationNode::newFromTypedef( $3 ); 2083 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); 2084 } 2085 | aggregate_key attribute_list_opt TYPEGENname // unqualified type name 2086 { 2087 typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef 2088 forall = false; // reset 2089 } 2090 '{' field_declaration_list_opt '}' type_parameters_opt 2091 { 2092 DeclarationNode::newFromTypeGen( $3, nullptr ); 2093 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); 2094 } 2035 2095 | aggregate_type_nobody 2036 2096 ; … … 2069 2129 2070 2130 aggregate_data: 2071 STRUCT 2072 { yyy = true;$$ = AggregateDecl::Struct; }2131 STRUCT vtable_opt 2132 { $$ = AggregateDecl::Struct; } 2073 2133 | UNION 2074 { yyy = true;$$ = AggregateDecl::Union; }2134 { $$ = AggregateDecl::Union; } 2075 2135 | EXCEPTION // CFA 2076 // { yyy = true;$$ = AggregateDecl::Exception; }2077 { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }2136 { $$ = AggregateDecl::Exception; } 2137 // { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2078 2138 ; 2079 2139 2080 2140 aggregate_control: // CFA 2081 2141 MONITOR 2082 { yyy = true;$$ = AggregateDecl::Monitor; }2142 { $$ = AggregateDecl::Monitor; } 2083 2143 | MUTEX STRUCT 2084 { yyy = true;$$ = AggregateDecl::Monitor; }2144 { $$ = AggregateDecl::Monitor; } 2085 2145 | GENERATOR 2086 { yyy = true;$$ = AggregateDecl::Generator; }2146 { $$ = AggregateDecl::Generator; } 2087 2147 | MUTEX GENERATOR 2088 2148 { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2089 2149 | COROUTINE 2090 { yyy = true;$$ = AggregateDecl::Coroutine; }2150 { $$ = AggregateDecl::Coroutine; } 2091 2151 | MUTEX COROUTINE 2092 2152 { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } 2093 2153 | THREAD 2094 { yyy = true;$$ = AggregateDecl::Thread; }2154 { $$ = AggregateDecl::Thread; } 2095 2155 | MUTEX THREAD 2096 2156 { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; } … … 2188 2248 ; 2189 2249 2190 // Cannot use attribute_list_opt because of ambiguity with enum_specifier_nobody, which already parses attribute.2191 // Hence, only a single attribute is allowed after the "ENUM".2192 2250 enum_type: // enum 2193 ENUM attribute_ opt '{' enumerator_list comma_opt '}'2251 ENUM attribute_list_opt '{' enumerator_list comma_opt '}' 2194 2252 { $$ = DeclarationNode::newEnum( nullptr, $4, true )->addQualifiers( $2 ); } 2195 | ENUM attribute_ opt identifier2253 | ENUM attribute_list_opt identifier 2196 2254 { typedefTable.makeTypedef( *$3 ); } 2197 2255 '{' enumerator_list comma_opt '}' 2198 2256 { $$ = DeclarationNode::newEnum( $3, $6, true )->addQualifiers( $2 ); } 2199 | ENUM attribute_ opt typedef // enum cannot be generic2257 | ENUM attribute_list_opt typedef_name // unqualified type name 2200 2258 '{' enumerator_list comma_opt '}' 2201 2259 { $$ = DeclarationNode::newEnum( $3->name, $5, true )->addQualifiers( $2 ); } 2202 | ENUM enum_specifier_nobody '{' enumerator_list comma_opt '}' 2203 // { $$ = DeclarationNode::newEnum( nullptr, $4, true ); } 2204 { SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; } 2205 | ENUM enum_specifier_nobody declarator '{' enumerator_list comma_opt '}' 2206 // { 2207 // typedefTable.makeTypedef( *$3->name ); 2208 // $$ = DeclarationNode::newEnum( nullptr, $5, true ); 2209 // } 2210 { SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; } 2260 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}' 2261 { 2262 if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2263 SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; 2264 } 2265 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt 2266 { 2267 if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2268 typedefTable.makeTypedef( *$6 ); 2269 } 2270 '{' enumerator_list comma_opt '}' 2271 { 2272 SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; 2273 } 2274 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}' 2275 { 2276 if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2277 typedefTable.makeTypedef( *$6->name ); 2278 SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; 2279 } 2211 2280 | enum_type_nobody 2212 2281 ; 2213 2282 2214 2283 enum_type_nobody: // enum - {...} 2215 ENUM attribute_opt identifier 2216 { 2217 typedefTable.makeTypedef( *$3 ); 2218 $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 ); 2219 } 2220 | ENUM attribute_opt type_name // enum cannot be generic 2221 { 2222 typedefTable.makeTypedef( *$3->type->symbolic.name ); 2223 $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 ); 2224 } 2284 ENUM attribute_list_opt identifier 2285 { typedefTable.makeTypedef( *$3 ); $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 ); } 2286 | ENUM attribute_list_opt type_name // qualified type name 2287 { typedefTable.makeTypedef( *$3->type->symbolic.name ); $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 ); } 2225 2288 ; 2226 2289 … … 2228 2291 identifier_or_type_name enumerator_value_opt 2229 2292 { $$ = DeclarationNode::newEnumConstant( $1, $2 ); } 2293 | INLINE type_name 2294 { $$ = DeclarationNode::newEnumConstant( new string("inline"), nullptr ); } 2230 2295 | enumerator_list ',' identifier_or_type_name enumerator_value_opt 2231 2296 { $$ = $1->appendList( DeclarationNode::newEnumConstant( $3, $4 ) ); } 2297 | enumerator_list ',' INLINE type_name enumerator_value_opt 2298 { $$ = $1->appendList( DeclarationNode::newEnumConstant( new string("inline"), nullptr ) ); } 2232 2299 ; 2233 2300 … … 2237 2304 // | '=' constant_expression 2238 2305 // { $$ = $2; } 2239 | '='initializer2306 | simple_assignment_operator initializer 2240 2307 { $$ = $2->get_expression(); } // FIX ME: enum only deals with constant_expression 2241 2308 ; … … 2365 2432 // empty 2366 2433 { $$ = nullptr; } 2367 | '=' initializer 2368 { $$ = $2; } 2369 | '=' VOID 2370 { $$ = new InitializerNode( true ); } 2371 | ATassign initializer 2372 { $$ = $2->set_maybeConstructed( false ); } 2434 | simple_assignment_operator initializer { $$ = $1 == OperKinds::Assign ? $2 : $2->set_maybeConstructed( false ); } 2435 | '=' VOID { $$ = new InitializerNode( true ); } 2373 2436 ; 2374 2437 … … 2626 2689 2627 2690 external_definition: 2628 declaration 2691 DIRECTIVE 2692 { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( $1 ) ) ); } 2693 | declaration 2629 2694 | external_function_definition 2630 2695 | EXTENSION external_definition // GCC, multiple __extension__ allowed, meaning unknown … … 2634 2699 } 2635 2700 | ASM '(' string_literal ')' ';' // GCC, global assembler statement 2636 { 2637 $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) ); 2638 } 2701 { $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) ); } 2639 2702 | EXTERN STRINGliteral // C++-style linkage specifier 2640 2703 { … … 2782 2845 ; 2783 2846 2784 attribute_opt:2785 // empty2786 { $$ = nullptr; }2787 | attribute2788 ;2789 2790 2847 attribute: // GCC 2791 2848 ATTRIBUTE '(' '(' attribute_name_list ')' ')' … … 2849 2906 // declaring an array of functions versus a pointer to an array of functions. 2850 2907 2908 paren_identifier: 2909 identifier 2910 { $$ = DeclarationNode::newName( $1 ); } 2911 | '(' paren_identifier ')' // redundant parenthesis 2912 { $$ = $2; } 2913 ; 2914 2851 2915 variable_declarator: 2852 2916 paren_identifier attribute_list_opt … … 2859 2923 ; 2860 2924 2861 paren_identifier:2862 identifier2863 { $$ = DeclarationNode::newName( $1 ); }2864 | '(' paren_identifier ')' // redundant parenthesis2865 { $$ = $2; }2866 ;2867 2868 2925 variable_ptr: 2869 2926 ptrref_operator variable_declarator … … 2871 2928 | ptrref_operator type_qualifier_list variable_declarator 2872 2929 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 2873 | '(' variable_ptr ')' attribute_list_opt 2874 { $$ = $2->addQualifiers( $4 ); } // redundant parenthesis 2930 | '(' variable_ptr ')' attribute_list_opt // redundant parenthesis 2931 { $$ = $2->addQualifiers( $4 ); } 2932 | '(' attribute_list variable_ptr ')' attribute_list_opt // redundant parenthesis 2933 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); } 2875 2934 ; 2876 2935 … … 2880 2939 | '(' variable_ptr ')' array_dimension 2881 2940 { $$ = $2->addArray( $4 ); } 2882 | '(' variable_array ')' multi_array_dimension // redundant parenthesis 2941 | '(' attribute_list variable_ptr ')' array_dimension 2942 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 2943 | '(' variable_array ')' multi_array_dimension // redundant parenthesis 2883 2944 { $$ = $2->addArray( $4 ); } 2945 | '(' attribute_list variable_array ')' multi_array_dimension // redundant parenthesis 2946 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 2884 2947 | '(' variable_array ')' // redundant parenthesis 2885 2948 { $$ = $2; } 2949 | '(' attribute_list variable_array ')' // redundant parenthesis 2950 { $$ = $3->addQualifiers( $2 ); } 2886 2951 ; 2887 2952 … … 2889 2954 '(' variable_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 2890 2955 { $$ = $2->addParamList( $6 ); } 2956 | '(' attribute_list variable_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 2957 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); } 2891 2958 | '(' variable_function ')' // redundant parenthesis 2892 2959 { $$ = $2; } 2960 | '(' attribute_list variable_function ')' // redundant parenthesis 2961 { $$ = $3->addQualifiers( $2 ); } 2893 2962 ; 2894 2963 … … 2910 2979 | '(' function_ptr ')' '(' push parameter_type_list_opt pop ')' 2911 2980 { $$ = $2->addParamList( $6 ); } 2981 | '(' attribute_list function_ptr ')' '(' push parameter_type_list_opt pop ')' 2982 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); } 2912 2983 | '(' function_no_ptr ')' // redundant parenthesis 2913 2984 { $$ = $2; } 2985 | '(' attribute_list function_no_ptr ')' // redundant parenthesis 2986 { $$ = $3->addQualifiers( $2 ); } 2914 2987 ; 2915 2988 … … 2919 2992 | ptrref_operator type_qualifier_list function_declarator 2920 2993 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 2921 | '(' function_ptr ')' 2922 { $$ = $2; } 2994 | '(' function_ptr ')' attribute_list_opt 2995 { $$ = $2->addQualifiers( $4 ); } 2996 | '(' attribute_list function_ptr ')' attribute_list_opt 2997 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); } 2923 2998 ; 2924 2999 … … 2926 3001 '(' function_ptr ')' array_dimension 2927 3002 { $$ = $2->addArray( $4 ); } 3003 | '(' attribute_list function_ptr ')' array_dimension 3004 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 2928 3005 | '(' function_array ')' multi_array_dimension // redundant parenthesis 2929 3006 { $$ = $2->addArray( $4 ); } 3007 | '(' attribute_list function_array ')' multi_array_dimension // redundant parenthesis 3008 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 2930 3009 | '(' function_array ')' // redundant parenthesis 2931 3010 { $$ = $2; } 3011 | '(' attribute_list function_array ')' // redundant parenthesis 3012 { $$ = $3->addQualifiers( $2 ); } 2932 3013 ; 2933 3014 … … 2950 3031 | '(' KR_function_ptr ')' '(' push parameter_type_list_opt pop ')' 2951 3032 { $$ = $2->addParamList( $6 ); } 3033 | '(' attribute_list KR_function_ptr ')' '(' push parameter_type_list_opt pop ')' 3034 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); } 2952 3035 | '(' KR_function_no_ptr ')' // redundant parenthesis 2953 3036 { $$ = $2; } 3037 | '(' attribute_list KR_function_no_ptr ')' // redundant parenthesis 3038 { $$ = $3->addQualifiers( $2 ); } 2954 3039 ; 2955 3040 … … 2961 3046 | '(' KR_function_ptr ')' 2962 3047 { $$ = $2; } 3048 | '(' attribute_list KR_function_ptr ')' 3049 { $$ = $3->addQualifiers( $2 ); } 2963 3050 ; 2964 3051 … … 2966 3053 '(' KR_function_ptr ')' array_dimension 2967 3054 { $$ = $2->addArray( $4 ); } 3055 | '(' attribute_list KR_function_ptr ')' array_dimension 3056 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 2968 3057 | '(' KR_function_array ')' multi_array_dimension // redundant parenthesis 2969 3058 { $$ = $2->addArray( $4 ); } 3059 | '(' attribute_list KR_function_array ')' multi_array_dimension // redundant parenthesis 3060 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 2970 3061 | '(' KR_function_array ')' // redundant parenthesis 2971 3062 { $$ = $2; } 3063 | '(' attribute_list KR_function_array ')' // redundant parenthesis 3064 { $$ = $3->addQualifiers( $2 ); } 2972 3065 ; 2973 3066 … … 2981 3074 // The pattern precludes declaring an array of functions versus a pointer to an array of functions, and returning arrays 2982 3075 // and functions versus pointers to arrays and functions. 3076 3077 paren_type: 3078 typedef_name 3079 { 3080 // hide type name in enclosing scope by variable name 3081 typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "ID" ); 3082 } 3083 | '(' paren_type ')' 3084 { $$ = $2; } 3085 ; 2983 3086 2984 3087 variable_type_redeclarator: … … 2992 3095 ; 2993 3096 2994 paren_type:2995 typedef2996 // hide type name in enclosing scope by variable name2997 {2998 // if ( ! typedefTable.existsCurr( *$1->name ) ) {2999 typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "ID" );3000 // } else {3001 // SemanticError( yylloc, string("'") + *$1->name + "' redeclared as different kind of symbol." ); $$ = nullptr;3002 // } // if3003 }3004 | '(' paren_type ')'3005 { $$ = $2; }3006 ;3007 3008 3097 type_ptr: 3009 3098 ptrref_operator variable_type_redeclarator … … 3011 3100 | ptrref_operator type_qualifier_list variable_type_redeclarator 3012 3101 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3013 | '(' type_ptr ')' attribute_list_opt 3014 { $$ = $2->addQualifiers( $4 ); } // redundant parenthesis 3102 | '(' type_ptr ')' attribute_list_opt // redundant parenthesis 3103 { $$ = $2->addQualifiers( $4 ); } 3104 | '(' attribute_list type_ptr ')' attribute_list_opt // redundant parenthesis 3105 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); } 3015 3106 ; 3016 3107 … … 3020 3111 | '(' type_ptr ')' array_dimension 3021 3112 { $$ = $2->addArray( $4 ); } 3113 | '(' attribute_list type_ptr ')' array_dimension 3114 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 3022 3115 | '(' type_array ')' multi_array_dimension // redundant parenthesis 3023 3116 { $$ = $2->addArray( $4 ); } 3117 | '(' attribute_list type_array ')' multi_array_dimension // redundant parenthesis 3118 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); } 3024 3119 | '(' type_array ')' // redundant parenthesis 3025 3120 { $$ = $2; } 3121 | '(' attribute_list type_array ')' // redundant parenthesis 3122 { $$ = $3->addQualifiers( $2 ); } 3026 3123 ; 3027 3124 … … 3031 3128 | '(' type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 3032 3129 { $$ = $2->addParamList( $6 ); } 3130 | '(' attribute_list type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 3131 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); } 3033 3132 | '(' type_function ')' // redundant parenthesis 3034 3133 { $$ = $2; } 3134 | '(' attribute_list type_function ')' // redundant parenthesis 3135 { $$ = $3->addQualifiers( $2 ); } 3035 3136 ; 3036 3137 … … 3057 3158 | ptrref_operator type_qualifier_list identifier_parameter_declarator 3058 3159 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3059 | '(' identifier_parameter_ptr ')' attribute_list_opt 3160 | '(' identifier_parameter_ptr ')' attribute_list_opt // redundant parenthesis 3060 3161 { $$ = $2->addQualifiers( $4 ); } 3061 3162 ; … … 3091 3192 3092 3193 type_parameter_redeclarator: 3093 typedef attribute_list_opt3194 typedef_name attribute_list_opt 3094 3195 { $$ = $1->addQualifiers( $2 ); } 3095 | '&' MUTEX typedef attribute_list_opt3196 | '&' MUTEX typedef_name attribute_list_opt 3096 3197 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); } 3097 3198 | type_parameter_ptr … … 3102 3203 ; 3103 3204 3104 typedef :3205 typedef_name: 3105 3206 TYPEDEFname 3106 3207 { $$ = DeclarationNode::newName( $1 ); } … … 3114 3215 | ptrref_operator type_qualifier_list type_parameter_redeclarator 3115 3216 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3116 | '(' type_parameter_ptr ')' attribute_list_opt 3217 | '(' type_parameter_ptr ')' attribute_list_opt // redundant parenthesis 3117 3218 { $$ = $2->addQualifiers( $4 ); } 3118 3219 ; 3119 3220 3120 3221 type_parameter_array: 3121 typedef array_parameter_dimension3222 typedef_name array_parameter_dimension 3122 3223 { $$ = $1->addArray( $2 ); } 3123 3224 | '(' type_parameter_ptr ')' array_parameter_dimension … … 3126 3227 3127 3228 type_parameter_function: 3128 typedef '(' push parameter_type_list_opt pop ')'// empty parameter list OBSOLESCENT (see 3)3229 typedef_name '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) 3129 3230 { $$ = $1->addParamList( $4 ); } 3130 3231 | '(' type_parameter_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3) … … 3255 3356 | ptrref_operator type_qualifier_list abstract_parameter_declarator 3256 3357 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3257 | '(' abstract_parameter_ptr ')' attribute_list_opt 3358 | '(' abstract_parameter_ptr ')' attribute_list_opt // redundant parenthesis 3258 3359 { $$ = $2->addQualifiers( $4 ); } 3259 3360 ; … … 3334 3435 | ptrref_operator type_qualifier_list variable_abstract_declarator 3335 3436 { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); } 3336 | '(' variable_abstract_ptr ')' attribute_list_opt 3437 | '(' variable_abstract_ptr ')' attribute_list_opt // redundant parenthesis 3337 3438 { $$ = $2->addQualifiers( $4 ); } 3338 3439 ; -
src/ResolvExpr/CurrentObject.cc
rfeacef9 r5407cdc 925 925 if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) { 926 926 if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) { 927 assert( sit->base ); 927 928 return new StructIterator{ loc, sit }; 928 929 } else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) { 930 assert( uit->base ); 929 931 return new UnionIterator{ loc, uit }; 930 932 } else { -
src/SynTree/Constant.cc
rfeacef9 r5407cdc 42 42 } 43 43 44 Constant Constant::from_string( const std::string & str ) { 45 Type * charType = new BasicType( noQualifiers, BasicType::Char ); 46 // Adjust the length of the string for the terminator. 47 Expression * strSize = new ConstantExpr( Constant::from_ulong( str.size() + 1 ) ); 48 Type * strType = new ArrayType( noQualifiers, charType, strSize, false, false ); 49 const std::string strValue = "\"" + str + "\""; 50 return Constant( strType, strValue, std::nullopt ); 51 } 52 44 53 Constant Constant::null( Type * ptrtype ) { 45 54 if ( nullptr == ptrtype ) { -
src/SynTree/Constant.h
rfeacef9 r5407cdc 47 47 /// generates an integer constant of the given unsigned long int 48 48 static Constant from_ulong( unsigned long i ); 49 /// generates a string constant from the given string (char type, unquoted string) 50 static Constant from_string( const std::string & string ); 49 51 50 52 /// generates a null pointer value for the given type. void * if omitted. -
src/SynTree/Declaration.cc
rfeacef9 r5407cdc 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Dec 11 16:39:56 201913 // Update Count : 3 612 // Last Modified On : Fri Mar 12 18:35:39 2021 13 // Update Count : 37 14 14 // 15 15 … … 66 66 67 67 68 DirectiveDecl::DirectiveDecl( DirectiveStmt *stmt ) : Declaration( "", Type::StorageClasses(), LinkageSpec::C ), stmt( stmt ) { 69 } 70 71 DirectiveDecl::DirectiveDecl( const DirectiveDecl &other ) : Declaration( other ), stmt( maybeClone( other.stmt ) ) { 72 } 73 74 DirectiveDecl::~DirectiveDecl() { 75 delete stmt; 76 } 77 78 void DirectiveDecl::print( std::ostream &os, Indenter indent ) const { 79 stmt->print( os, indent ); 80 } 81 82 void DirectiveDecl::printShort( std::ostream &os, Indenter indent ) const { 83 stmt->print( os, indent ); 84 } 85 86 68 87 StaticAssertDecl::StaticAssertDecl( Expression * condition, ConstantExpr * message ) : Declaration( "", Type::StorageClasses(), LinkageSpec::C ), condition( condition ), message( message ) { 69 88 } -
src/SynTree/Declaration.h
rfeacef9 r5407cdc 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 11 20:48:39202113 // Update Count : 15 812 // Last Modified On : Fri Mar 12 18:35:36 2021 13 // Update Count : 159 14 14 // 15 15 … … 400 400 }; 401 401 402 class DirectiveDecl : public Declaration { 403 public: 404 DirectiveStmt * stmt; 405 406 DirectiveDecl( DirectiveStmt * stmt ); 407 DirectiveDecl( const DirectiveDecl & other ); 408 virtual ~DirectiveDecl(); 409 410 DirectiveStmt * get_stmt() { return stmt; } 411 void set_stmt( DirectiveStmt * newValue ) { stmt = newValue; } 412 413 virtual DirectiveDecl * clone() const override { return new DirectiveDecl( *this ); } 414 virtual void accept( Visitor & v ) override { v.visit( this ); } 415 virtual void accept( Visitor & v ) const override { v.visit( this ); } 416 virtual DirectiveDecl * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 417 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 418 virtual void printShort( std::ostream & os, Indenter indent = {} ) const override; 419 }; 420 402 421 class StaticAssertDecl : public Declaration { 403 422 public: -
src/SynTree/Mutator.h
rfeacef9 r5407cdc 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 25 22:37:46 201913 // Update Count : 1 712 // Last Modified On : Fri Mar 12 18:35:36 2021 13 // Update Count : 18 14 14 // 15 15 #pragma once … … 34 34 virtual Declaration * mutate( TypedefDecl * typeDecl ) = 0; 35 35 virtual AsmDecl * mutate( AsmDecl * asmDecl ) = 0; 36 virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) = 0; 36 37 virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) = 0; 37 38 -
src/SynTree/SynTree.h
rfeacef9 r5407cdc 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 25 22:37:45 201913 // Update Count : 1 212 // Last Modified On : Fri Mar 12 18:56:44 2021 13 // Update Count : 13 14 14 // 15 15 … … 36 36 class TypedefDecl; 37 37 class AsmDecl; 38 class DirectiveDecl; 38 39 class StaticAssertDecl; 39 40 -
src/SynTree/Visitor.h
rfeacef9 r5407cdc 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 25 22:21:49 201913 // Update Count : 1 412 // Last Modified On : Fri Mar 12 18:35:35 2021 13 // Update Count : 15 14 14 // 15 15 … … 45 45 virtual void visit( AsmDecl * node ) { visit( const_cast<const AsmDecl *>(node) ); } 46 46 virtual void visit( const AsmDecl * asmDecl ) = 0; 47 virtual void visit( DirectiveDecl * node ) { visit( const_cast<const DirectiveDecl *>(node) ); } 48 virtual void visit( const DirectiveDecl * directiveDecl ) = 0; 47 49 virtual void visit( StaticAssertDecl * node ) { visit( const_cast<const StaticAssertDecl *>(node) ); } 48 50 virtual void visit( const StaticAssertDecl * assertDecl ) = 0; -
src/Virtual/ExpandCasts.cc
rfeacef9 r5407cdc 32 32 namespace Virtual { 33 33 34 static bool is_prefix( const std::string & prefix, const std::string& entire ) { 35 size_t const p_size = prefix.size(); 36 return (p_size < entire.size() && prefix == entire.substr(0, p_size)); 37 } 38 39 static bool is_type_id_object( const ObjectDecl * objectDecl ) { 40 const std::string & objectName = objectDecl->name; 41 return is_prefix( "__cfatid_", objectName ); 42 } 43 34 44 // Indented until the new ast code gets added. 35 45 … … 66 76 }; 67 77 68 /* Currently virtual depends on the rather brittle name matching between69 * a (strict/explicate) virtual type, its vtable type and the vtable70 * instance.71 * A stronger implementation, would probably keep track of those triads72 * and use that information to create better error messages.73 */74 75 namespace {76 77 std::string get_vtable_name( std::string const & name ) {78 return name + "_vtable";79 }80 81 std::string get_vtable_inst_name( std::string const & name ) {82 return std::string("_") + get_vtable_name( name ) + "_instance";83 }84 85 std::string get_vtable_name_root( std::string const & name ) {86 return name.substr(0, name.size() - 7 );87 }88 89 std::string get_vtable_inst_name_root( std::string const & name ) {90 return get_vtable_name_root( name.substr(1, name.size() - 10 ) );91 }92 93 bool is_vtable_inst_name( std::string const & name ) {94 return 17 < name.size() &&95 name == get_vtable_inst_name( get_vtable_inst_name_root( name ) );96 }97 98 } // namespace99 100 78 class VirtualCastCore { 101 Type * pointer_to_pvt(int level_of_indirection) {79 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) { 102 80 Type * type = new StructInstType( 103 81 Type::Qualifiers( Type::Const ), pvt_decl ); … … 105 83 type = new PointerType( noQualifiers, type ); 106 84 } 107 return type;85 return new CastExpr( expr, type ); 108 86 } 109 87 … … 141 119 142 120 void VirtualCastCore::premutate( ObjectDecl * objectDecl ) { 143 if ( is_vtable_inst_name( objectDecl->get_name() ) ) { 144 if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) { 145 std::string msg = "Repeated instance of virtual table, original found at: "; 146 msg += existing->location.filename; 147 msg += ":" + toString( existing->location.first_line ); 148 SemanticError( objectDecl->location, msg ); 149 } 121 if ( is_type_id_object( objectDecl ) ) { 122 // Multiple definitions should be fine because of linkonce. 123 indexer.insert( objectDecl ); 150 124 } 151 125 } … … 170 144 } 171 145 172 /// Get the virtual table type used in a virtual cast. 173 Type * getVirtualTableType( const VirtualCastExpr * castExpr ) { 174 const Type * objectType; 175 if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) { 176 objectType = target->base; 177 } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) { 178 objectType = target->base; 146 /// Get the base type from a pointer or reference. 147 const Type * getBaseType( const Type * type ) { 148 if ( auto target = dynamic_cast<const PointerType *>( type ) ) { 149 return target->base; 150 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) { 151 return target->base; 179 152 } else { 180 castError( castExpr, "Virtual cast type must be a pointer or reference type." ); 181 } 182 assert( objectType ); 183 184 const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType ); 185 if ( nullptr == structType ) { 186 castError( castExpr, "Virtual cast type must refer to a structure type." ); 187 } 188 const StructDecl * structDecl = structType->baseStruct; 189 assert( structDecl ); 190 191 const ObjectDecl * fieldDecl = nullptr; 192 if ( 0 < structDecl->members.size() ) { 193 const Declaration * memberDecl = structDecl->members.front(); 153 return nullptr; 154 } 155 } 156 157 /* Attempt to follow the "head" field of the structure to get the... 158 * Returns nullptr on error, otherwise owner must free returned node. 159 */ 160 StructInstType * followHeadPointerType( 161 const StructInstType * oldType, 162 const std::string& fieldName, 163 const CodeLocation& errorLocation ) { 164 165 // First section of the function is all about trying to fill this variable in. 166 StructInstType * newType = nullptr; 167 { 168 const StructDecl * oldDecl = oldType->baseStruct; 169 assert( oldDecl ); 170 171 // Helper function for throwing semantic errors. 172 auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) { 173 const std::string& context = "While following head pointer of " + 174 oldDecl->name + " named '" + fieldName + "': "; 175 SemanticError( errorLocation, context + message ); 176 }; 177 178 if ( oldDecl->members.empty() ) { 179 throwError( "Type has no fields." ); 180 } 181 const Declaration * memberDecl = oldDecl->members.front(); 194 182 assert( memberDecl ); 195 fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl ); 196 if ( fieldDecl && fieldDecl->name != "virtual_table" ) { 197 fieldDecl = nullptr; 198 } 199 } 200 if ( nullptr == fieldDecl ) { 201 castError( castExpr, "Virtual cast type must have a leading virtual_table field." ); 202 } 203 const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type ); 204 if ( nullptr == fieldType ) { 205 castError( castExpr, "Virtual cast type virtual_table field is not a pointer." ); 206 } 207 assert( fieldType->base ); 208 auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base ); 209 assert( virtualStructType ); 210 211 // Here is the type, but if it is polymorphic it will have lost information. 212 // (Always a clone so that it may always be deleted.) 213 StructInstType * virtualType = virtualStructType->clone(); 214 if ( ! structType->parameters.empty() ) { 215 deleteAll( virtualType->parameters ); 216 virtualType->parameters.clear(); 217 cloneAll( structType->parameters, virtualType->parameters ); 218 } 219 return virtualType; 183 const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl ); 184 assert( fieldDecl ); 185 if ( fieldName != fieldDecl->name ) { 186 throwError( "Head field did not have expected name." ); 187 } 188 189 const Type * fieldType = fieldDecl->type; 190 if ( nullptr == fieldType ) { 191 throwError( "Could not get head field." ); 192 } 193 const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType ); 194 if ( nullptr == ptrType ) { 195 throwError( "First field is not a pointer type." ); 196 } 197 assert( ptrType->base ); 198 newType = dynamic_cast<StructInstType *>( ptrType->base ); 199 if ( nullptr == newType ) { 200 throwError( "First field does not point to a structure type." ); 201 } 202 } 203 204 // Now we can look into copying it. 205 newType = newType->clone(); 206 if ( ! oldType->parameters.empty() ) { 207 deleteAll( newType->parameters ); 208 newType->parameters.clear(); 209 cloneAll( oldType->parameters, newType->parameters ); 210 } 211 return newType; 212 } 213 214 /// Get the type-id type from a virtual type. 215 StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) { 216 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type ); 217 if ( nullptr == typeInst ) { 218 return nullptr; 219 } 220 StructInstType * tableInst = 221 followHeadPointerType( typeInst, "virtual_table", errorLocation ); 222 if ( nullptr == tableInst ) { 223 return nullptr; 224 } 225 StructInstType * typeIdInst = 226 followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation ); 227 delete tableInst; 228 return typeIdInst; 220 229 } 221 230 … … 228 237 assert( pvt_decl ); 229 238 230 const Type * vtable_type = getVirtualTableType( castExpr ); 231 ObjectDecl * table = indexer.lookup( vtable_type ); 232 if ( nullptr == table ) { 233 SemanticError( castLocation( castExpr ), 234 "Could not find virtual table instance." ); 239 const Type * base_type = getBaseType( castExpr->result ); 240 if ( nullptr == base_type ) { 241 castError( castExpr, "Virtual cast target must be a pointer or reference type." ); 242 } 243 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) ); 244 if ( nullptr == type_id_type ) { 245 castError( castExpr, "Ill formed virtual cast target type." ); 246 } 247 ObjectDecl * type_id = indexer.lookup( type_id_type ); 248 delete type_id_type; 249 if ( nullptr == type_id ) { 250 castError( castExpr, "Virtual cast does not target a virtual type." ); 235 251 } 236 252 237 253 Expression * result = new CastExpr( 238 254 new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), { 239 new CastExpr( 240 new AddressExpr( new VariableExpr( table ) ), 241 pointer_to_pvt(1) 242 ), 243 new CastExpr( 244 castExpr->get_arg(), 245 pointer_to_pvt(2) 246 ) 255 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ), 256 cast_to_type_id( castExpr->get_arg(), 2 ), 247 257 } ), 248 258 castExpr->get_result()->clone() … … 252 262 castExpr->set_result( nullptr ); 253 263 delete castExpr; 254 delete vtable_type;255 264 return result; 256 265 } -
src/Virtual/Tables.cc
rfeacef9 r5407cdc 10 10 // Created On : Mon Aug 31 11:11:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Sep 3 14:56:00 202013 // Update Count : 012 // Last Modified On : Wed Apr 21 15:36:00 2021 13 // Update Count : 2 14 14 // 15 15 … … 22 22 namespace Virtual { 23 23 24 std::string typeIdType( std::string const & type_name ) { 25 return "__cfatid_struct_" + type_name; 26 } 27 28 std::string typeIdName( std::string const & type_name ) { 29 return "__cfatid_" + type_name; 30 } 31 32 static std::string typeIdTypeToInstance( std::string const & type_name ) { 33 return typeIdName(type_name.substr(16)); 34 } 35 24 36 std::string vtableTypeName( std::string const & name ) { 25 37 return name + "_vtable"; 26 38 } 27 39 40 std::string baseTypeName( std::string const & vtable_type_name ) { 41 return vtable_type_name.substr(0, vtable_type_name.size() - 7); 42 } 43 28 44 std::string instanceName( std::string const & name ) { 29 45 return std::string("_") + name + "_instance"; … … 32 48 std::string vtableInstanceName( std::string const & name ) { 33 49 return instanceName( vtableTypeName( name ) ); 50 } 51 52 std::string concurrentDefaultVTableName() { 53 return "_default_vtable"; 34 54 } 35 55 … … 41 61 42 62 static ObjectDecl * makeVtableDeclaration( 63 std::string const & name, 43 64 StructInstType * type, Initializer * init ) { 44 std::string const & name = instanceName( type->name );45 65 Type::StorageClasses storage = noStorageClasses; 46 66 if ( nullptr == init ) { … … 57 77 } 58 78 59 ObjectDecl * makeVtableForward( StructInstType * type ) {79 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) { 60 80 assert( type ); 61 return makeVtableDeclaration( type, nullptr );81 return makeVtableDeclaration( name, type, nullptr ); 62 82 } 63 83 64 84 ObjectDecl * makeVtableInstance( 65 StructInstType * vtableType, Type * objectType, Initializer * init ) { 85 std::string const & name, StructInstType * vtableType, 86 Type * objectType, Initializer * init ) { 66 87 assert( vtableType ); 67 88 assert( objectType ); … … 81 102 inits.push_back( 82 103 new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) ); 104 } else if ( std::string( "__cfavir_typeid" ) == field->name ) { 105 std::string const & baseType = baseTypeName( vtableType->name ); 106 std::string const & typeId = typeIdName( baseType ); 107 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) ); 83 108 } else if ( std::string( "size" ) == field->name ) { 84 109 inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) ); … … 95 120 assert(false); 96 121 } 97 return makeVtableDeclaration( vtableType, init );122 return makeVtableDeclaration( name, vtableType, init ); 98 123 } 99 124 … … 147 172 } 148 173 149 } 174 Attribute * linkonce( const std::string & subsection ) { 175 const std::string section = ".gnu.linkonce." + subsection; 176 return new Attribute( "section", { 177 new ConstantExpr( Constant::from_string( section ) ), 178 } ); 179 } 180 181 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) { 182 assert( typeIdType ); 183 StructInstType * type = typeIdType->clone(); 184 type->tq.is_const = true; 185 std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name ); 186 return new ObjectDecl( 187 typeid_name, 188 noStorageClasses, 189 LinkageSpec::Cforall, 190 /* bitfieldWidth */ nullptr, 191 type, 192 new ListInit( { new SingleInit( 193 new AddressExpr( new NameExpr( "__cfatid_exception_t" ) ) 194 ) } ), 195 { linkonce( typeid_name ) }, 196 noFuncSpecifiers 197 ); 198 } 199 200 } -
src/Virtual/Tables.h
rfeacef9 r5407cdc 10 10 // Created On : Mon Aug 31 11:07:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Sep 1 14:29:00 202013 // Update Count : 012 // Last Modified On : Wed Apr 21 10:30:00 2021 13 // Update Count : 2 14 14 // 15 15 … … 22 22 namespace Virtual { 23 23 24 std::string typeIdType( std::string const & type_name ); 25 std::string typeIdName( std::string const & type_name ); 24 26 std::string vtableTypeName( std::string const & type_name ); 25 27 std::string instanceName( std::string const & vtable_name ); 26 28 std::string vtableInstanceName( std::string const & type_name ); 29 std::string concurrentDefaultVTableName(); 27 30 bool isVTableInstanceName( std::string const & name ); 28 31 29 ObjectDecl * makeVtableForward( StructInstType * vtableType ); 32 ObjectDecl * makeVtableForward( 33 std::string const & name, StructInstType * vtableType ); 30 34 /* Create a forward declaration of a vtable of the given type. 31 35 * vtableType node is consumed. 32 36 */ 33 37 34 ObjectDecl * makeVtableInstance( StructInstType * vtableType, Type * objectType, 38 ObjectDecl * makeVtableInstance( 39 std::string const & name, 40 StructInstType * vtableType, Type * objectType, 35 41 Initializer * init = nullptr ); 36 42 /* Create an initialized definition of a vtable. … … 50 56 */ 51 57 58 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ); 59 /* Build an instance of the type-id from the type of the type-id. 60 * TODO: Should take the parent type. Currently locked to the exception_t. 61 */ 62 52 63 } -
src/main.cc
rfeacef9 r5407cdc 10 10 // Created On : Fri May 15 23:12:02 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Feb 8 21:10:16202113 // Update Count : 6 4212 // Last Modified On : Sat Mar 6 15:49:00 2021 13 // Update Count : 656 14 14 // 15 15 … … 101 101 static string PreludeDirector = ""; 102 102 103 static void parse_cmdline( int argc, char * argv[] );103 static void parse_cmdline( int argc, char * argv[] ); 104 104 static void parse( FILE * input, LinkageSpec::Spec linkage, bool shouldExit = false ); 105 105 static void dump( list< Declaration * > & translationUnit, ostream & out = cout ); 106 static void dump( ast::TranslationUnit && transUnit, ostream & out = cout ); 106 107 107 108 static void backtrace( int start ) { // skip first N stack frames … … 158 159 #define SIGPARMS int sig __attribute__(( unused )), siginfo_t * sfp __attribute__(( unused )), ucontext_t * cxt __attribute__(( unused )) 159 160 160 static void Signal( int sig, void (* handler)(SIGPARMS), int flags ) {161 static void Signal( int sig, void (* handler)(SIGPARMS), int flags ) { 161 162 struct sigaction act; 162 163 … … 165 166 166 167 if ( sigaction( sig, &act, nullptr ) == -1 ) { 167 cerr << "* CFA runtimeerror* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl;168 cerr << "*cfa-cpp compilation error* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl; 168 169 _exit( EXIT_FAILURE ); 169 170 } // if … … 349 350 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 350 351 if ( exprp ) { 351 translationUnit = convert( move( transUnit ) ); 352 dump( translationUnit ); 352 dump( move( transUnit ) ); 353 353 return EXIT_SUCCESS; 354 354 } // if … … 421 421 delete output; 422 422 } // if 423 } catch ( SemanticErrorException & e ) {423 } catch ( SemanticErrorException & e ) { 424 424 if ( errorp ) { 425 425 cerr << "---AST at error:---" << endl; … … 432 432 } // if 433 433 return EXIT_FAILURE; 434 } catch ( UnimplementedError & e ) {434 } catch ( UnimplementedError & e ) { 435 435 cout << "Sorry, " << e.get_what() << " is not currently implemented" << endl; 436 436 if ( output != &cout ) { … … 438 438 } // if 439 439 return EXIT_FAILURE; 440 } catch ( CompilerError & e ) {440 } catch ( CompilerError & e ) { 441 441 cerr << "Compiler Error: " << e.get_what() << endl; 442 442 cerr << "(please report bugs to [REDACTED])" << endl; … … 445 445 } // if 446 446 return EXIT_FAILURE; 447 } catch ( std::bad_alloc & ) { 448 cerr << "*cfa-cpp compilation error* std::bad_alloc" << endl; 449 backtrace( 1 ); 450 abort(); 447 451 } catch ( ... ) { 448 452 exception_ptr eptr = current_exception(); … … 451 455 rethrow_exception(eptr); 452 456 } else { 453 cerr << " Exception Uncaught and Unknown" << endl;454 } // if 455 } catch( const exception& e) {456 cerr << " Uncaught Exception \"" << e.what() << "\"\n";457 cerr << "*cfa-cpp compilation error* exception uncaught and unknown" << endl; 458 } // if 459 } catch( const exception & e ) { 460 cerr << "*cfa-cpp compilation error* uncaught exception \"" << e.what() << "\"\n"; 457 461 } // try 458 462 return EXIT_FAILURE; … … 544 548 enum { printoptsSize = sizeof( printopts ) / sizeof( printopts[0] ) }; 545 549 546 static void usage( char * argv[] ) {550 static void usage( char * argv[] ) { 547 551 cout << "Usage: " << argv[0] << " [options] [input-file (default stdin)] [output-file (default stdout)], where options are:" << endl; 548 552 int i = 0, j = 1; // j skips starting colon … … 732 736 } // dump 733 737 738 static void dump( ast::TranslationUnit && transUnit, ostream & out ) { 739 std::list< Declaration * > translationUnit = convert( move( transUnit ) ); 740 dump( translationUnit, out ); 741 } 742 734 743 // Local Variables: // 735 744 // tab-width: 4 // -
tests/.expect/KRfunctions.nast.arm64.txt
rfeacef9 r5407cdc 104 104 signed int _X1bi_2; 105 105 { 106 signed int *(*_tmp_cp_ret 4)(signed int __param_0, signed int __param_1);107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret 4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));106 signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1); 107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6))); 108 108 } 109 109 -
tests/.expect/KRfunctions.nast.x64.txt
rfeacef9 r5407cdc 104 104 signed int _X1bi_2; 105 105 { 106 signed int *(*_tmp_cp_ret 4)(signed int __param_0, signed int __param_1);107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret 4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));106 signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1); 107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6))); 108 108 } 109 109 -
tests/.expect/KRfunctions.nast.x86.txt
rfeacef9 r5407cdc 104 104 signed int _X1bi_2; 105 105 { 106 signed int *(*_tmp_cp_ret 4)(signed int __param_0, signed int __param_1);107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret 4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));106 signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1); 107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6))); 108 108 } 109 109 -
tests/.expect/KRfunctions.oast.x64.txt
rfeacef9 r5407cdc 104 104 signed int _X1bi_2; 105 105 { 106 signed int *(*_tmp_cp_ret 4)(signed int _X1xi_1, signed int _X1yi_1);107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret 4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));106 signed int *(*_tmp_cp_ret6)(signed int _X1xi_1, signed int _X1yi_1); 107 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6))); 108 108 } 109 109 -
tests/.expect/attributes.nast.arm64.txt
rfeacef9 r5407cdc 6 6 7 7 } 8 struct __a ttribute__ ((unused)) __anonymous0 {8 struct __anonymous0 { 9 9 }; 10 10 static inline void _X12_constructorFv_S12__anonymous0_autogen___1(struct __anonymous0 *_X4_dstS12__anonymous0_1); … … 26 26 return _X4_retS12__anonymous0_1; 27 27 } 28 __attribute__ ((unused)) struct __anonymous0 _X5DummyS12__anonymous0_1; 28 29 struct __attribute__ ((unused)) Agn1; 29 30 struct __attribute__ ((unused)) Agn2 { … … 103 104 __attribute__ ((used,unused,unused)) signed int _X2f7i_1; 104 105 __attribute__ ((used,used,unused)) signed int _X2f8i_1; 105 __attribute__ ((unused,unused)) signed int *_X2f9Pi_1; 106 __attribute__ ((unused)) signed int *_X2f9Pi_1; 107 __attribute__ ((unused,used)) signed int *_X3f10Pi_1; 108 __attribute__ ((unused,unused)) signed int *_X3f11Pi_1; 109 __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1; 110 __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1; 111 __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1; 106 112 }; 107 113 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1); … … 117 123 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1); 118 124 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1); 119 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1); 125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1); 126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1); 127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1); 128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1); 129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1); 130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1); 120 131 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 121 132 { … … 155 166 } 156 167 168 { 169 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 170 } 171 172 { 173 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 174 } 175 176 { 177 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 178 } 179 180 { 181 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 182 } 183 184 { 185 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 186 } 187 157 188 } 158 189 static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){ … … 193 224 } 194 225 226 { 227 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */); 228 } 229 230 { 231 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */); 232 } 233 234 { 235 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */); 236 } 237 238 { 239 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */); 240 } 241 242 { 243 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */); 244 } 245 195 246 } 196 247 static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 248 { 249 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */); 250 } 251 252 { 253 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */); 254 } 255 256 { 257 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */); 258 } 259 260 { 261 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */); 262 } 263 264 { 265 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */); 266 } 267 197 268 { 198 269 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */); … … 271 342 272 343 { 344 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1)); 345 } 346 347 { 348 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1)); 349 } 350 351 { 352 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1)); 353 } 354 355 { 356 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1)); 357 } 358 359 { 360 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1)); 361 } 362 363 { 273 364 ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1))); 274 365 } … … 313 404 } 314 405 406 { 407 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 408 } 409 410 { 411 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 412 } 413 414 { 415 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 416 } 417 418 { 419 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 420 } 421 422 { 423 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 424 } 425 315 426 } 316 427 static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){ … … 351 462 } 352 463 464 { 465 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 466 } 467 468 { 469 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 470 } 471 472 { 473 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 474 } 475 476 { 477 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 478 } 479 480 { 481 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 482 } 483 353 484 } 354 485 static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){ … … 389 520 } 390 521 522 { 523 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 524 } 525 526 { 527 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 528 } 529 530 { 531 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 532 } 533 534 { 535 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 536 } 537 538 { 539 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 540 } 541 391 542 } 392 543 static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){ … … 427 578 } 428 579 580 { 581 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 582 } 583 584 { 585 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 586 } 587 588 { 589 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 590 } 591 592 { 593 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 594 } 595 596 { 597 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 598 } 599 429 600 } 430 601 static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){ … … 465 636 } 466 637 638 { 639 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 640 } 641 642 { 643 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 644 } 645 646 { 647 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 648 } 649 650 { 651 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 652 } 653 654 { 655 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 656 } 657 467 658 } 468 659 static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){ … … 503 694 } 504 695 696 { 697 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 698 } 699 700 { 701 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 702 } 703 704 { 705 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 706 } 707 708 { 709 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 710 } 711 712 { 713 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 714 } 715 505 716 } 506 717 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){ … … 541 752 } 542 753 754 { 755 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 756 } 757 758 { 759 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 760 } 761 762 { 763 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 764 } 765 766 { 767 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 768 } 769 770 { 771 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 772 } 773 543 774 } 544 775 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){ … … 579 810 } 580 811 581 } 582 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){ 812 { 813 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 814 } 815 816 { 817 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 818 } 819 820 { 821 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 822 } 823 824 { 825 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 826 } 827 828 { 829 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 830 } 831 832 } 833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){ 583 834 { 584 835 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); … … 615 866 { 616 867 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 868 } 869 870 { 871 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 872 } 873 874 { 875 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 876 } 877 878 { 879 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 880 } 881 882 { 883 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 884 } 885 886 { 887 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 888 } 889 890 } 891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){ 892 { 893 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 894 } 895 896 { 897 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 898 } 899 900 { 901 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 902 } 903 904 { 905 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 906 } 907 908 { 909 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 910 } 911 912 { 913 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 914 } 915 916 { 917 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 918 } 919 920 { 921 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 922 } 923 924 { 925 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 926 } 927 928 { 929 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 930 } 931 932 { 933 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 934 } 935 936 { 937 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 938 } 939 940 { 941 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 942 } 943 944 { 945 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 946 } 947 948 } 949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){ 950 { 951 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 952 } 953 954 { 955 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 956 } 957 958 { 959 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 960 } 961 962 { 963 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 964 } 965 966 { 967 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 968 } 969 970 { 971 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 972 } 973 974 { 975 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 976 } 977 978 { 979 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 980 } 981 982 { 983 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 984 } 985 986 { 987 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 988 } 989 990 { 991 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 992 } 993 994 { 995 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 996 } 997 998 { 999 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 1000 } 1001 1002 { 1003 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1004 } 1005 1006 } 1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){ 1008 { 1009 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1010 } 1011 1012 { 1013 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1014 } 1015 1016 { 1017 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1018 } 1019 1020 { 1021 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1022 } 1023 1024 { 1025 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1026 } 1027 1028 { 1029 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1030 } 1031 1032 { 1033 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1034 } 1035 1036 { 1037 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1038 } 1039 1040 { 1041 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1042 } 1043 1044 { 1045 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1046 } 1047 1048 { 1049 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1050 } 1051 1052 { 1053 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1054 } 1055 1056 { 1057 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 1058 } 1059 1060 { 1061 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1062 } 1063 1064 } 1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){ 1066 { 1067 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1068 } 1069 1070 { 1071 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1072 } 1073 1074 { 1075 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1076 } 1077 1078 { 1079 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1080 } 1081 1082 { 1083 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1084 } 1085 1086 { 1087 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1088 } 1089 1090 { 1091 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1092 } 1093 1094 { 1095 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1096 } 1097 1098 { 1099 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1100 } 1101 1102 { 1103 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1104 } 1105 1106 { 1107 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1108 } 1109 1110 { 1111 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1112 } 1113 1114 { 1115 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */); 1116 } 1117 1118 { 1119 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1120 } 1121 1122 } 1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){ 1124 { 1125 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1126 } 1127 1128 { 1129 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1130 } 1131 1132 { 1133 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1134 } 1135 1136 { 1137 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1138 } 1139 1140 { 1141 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1142 } 1143 1144 { 1145 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1146 } 1147 1148 { 1149 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1150 } 1151 1152 { 1153 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1154 } 1155 1156 { 1157 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1158 } 1159 1160 { 1161 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1162 } 1163 1164 { 1165 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1166 } 1167 1168 { 1169 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1170 } 1171 1172 { 1173 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */); 1174 } 1175 1176 { 1177 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */); 617 1178 } 618 1179 … … 627 1188 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)(); 628 1189 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)(); 1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)(); 1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)(); 629 1192 __attribute__ ((unused,used)) signed int _X2f1Fi___1(); 630 1193 __attribute__ ((unused)) signed int _X2f1Fi___1(){ … … 636 1199 } 637 1200 __attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[]; 638 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{ 639 __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[]; 640 } 641 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0); 642 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){ 643 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0); 1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[]; 1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{ 1203 __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[]; 1204 } 1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{ 1206 __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[]; 1207 } 1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0); 1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){ 1210 __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0); 1211 } 1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){ 1213 __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0); 1214 } 1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){ 1216 __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0); 644 1217 } 645 1218 signed int _X3vtrFi___1(){ … … 649 1222 __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)]; 650 1223 __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)]; 651 __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2(); 1224 __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)]; 1225 __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2(); 652 1226 __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2(); 653 1227 } … … 671 1245 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1); 672 1246 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1); 673 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 1)(signed int __param_0[((unsigned long int )5)]));1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int __param_0[((unsigned long int )5)])); 674 1248 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 675 1249 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 676 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 2)(signed int (*__param_0)(signed int __param_0)));1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object3)(signed int (*__param_0)(signed int __param_0))); 677 1251 signed int _X2adFi___1(){ 678 1252 __attribute__ ((unused)) signed int _X10_retval_adi_1; … … 776 1350 777 1351 } 778 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4);779 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object 5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6);780 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8);781 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)());782 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 1)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0));783 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 3)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)());784 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 5)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0));1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5); 1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7); 1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9); 1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)()); 1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0)); 1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)()); 1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0)); 785 1359 struct Vad { 786 1360 __attribute__ ((unused)) signed int :4; -
tests/.expect/attributes.nast.x64.txt
rfeacef9 r5407cdc 104 104 __attribute__ ((used,unused,unused)) signed int _X2f7i_1; 105 105 __attribute__ ((used,used,unused)) signed int _X2f8i_1; 106 __attribute__ ((unused,unused)) signed int *_X2f9Pi_1; 106 __attribute__ ((unused)) signed int *_X2f9Pi_1; 107 __attribute__ ((unused,used)) signed int *_X3f10Pi_1; 108 __attribute__ ((unused,unused)) signed int *_X3f11Pi_1; 109 __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1; 110 __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1; 111 __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1; 107 112 }; 108 113 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1); … … 118 123 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1); 119 124 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1); 120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1); 125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1); 126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1); 127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1); 128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1); 129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1); 130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1); 121 131 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 122 132 { … … 156 166 } 157 167 168 { 169 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 170 } 171 172 { 173 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 174 } 175 176 { 177 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 178 } 179 180 { 181 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 182 } 183 184 { 185 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 186 } 187 158 188 } 159 189 static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){ … … 194 224 } 195 225 226 { 227 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */); 228 } 229 230 { 231 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */); 232 } 233 234 { 235 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */); 236 } 237 238 { 239 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */); 240 } 241 242 { 243 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */); 244 } 245 196 246 } 197 247 static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 248 { 249 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */); 250 } 251 252 { 253 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */); 254 } 255 256 { 257 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */); 258 } 259 260 { 261 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */); 262 } 263 264 { 265 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */); 266 } 267 198 268 { 199 269 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */); … … 272 342 273 343 { 344 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1)); 345 } 346 347 { 348 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1)); 349 } 350 351 { 352 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1)); 353 } 354 355 { 356 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1)); 357 } 358 359 { 360 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1)); 361 } 362 363 { 274 364 ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1))); 275 365 } … … 314 404 } 315 405 406 { 407 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 408 } 409 410 { 411 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 412 } 413 414 { 415 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 416 } 417 418 { 419 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 420 } 421 422 { 423 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 424 } 425 316 426 } 317 427 static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){ … … 352 462 } 353 463 464 { 465 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 466 } 467 468 { 469 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 470 } 471 472 { 473 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 474 } 475 476 { 477 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 478 } 479 480 { 481 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 482 } 483 354 484 } 355 485 static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){ … … 390 520 } 391 521 522 { 523 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 524 } 525 526 { 527 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 528 } 529 530 { 531 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 532 } 533 534 { 535 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 536 } 537 538 { 539 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 540 } 541 392 542 } 393 543 static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){ … … 428 578 } 429 579 580 { 581 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 582 } 583 584 { 585 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 586 } 587 588 { 589 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 590 } 591 592 { 593 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 594 } 595 596 { 597 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 598 } 599 430 600 } 431 601 static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){ … … 466 636 } 467 637 638 { 639 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 640 } 641 642 { 643 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 644 } 645 646 { 647 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 648 } 649 650 { 651 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 652 } 653 654 { 655 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 656 } 657 468 658 } 469 659 static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){ … … 504 694 } 505 695 696 { 697 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 698 } 699 700 { 701 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 702 } 703 704 { 705 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 706 } 707 708 { 709 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 710 } 711 712 { 713 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 714 } 715 506 716 } 507 717 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){ … … 542 752 } 543 753 754 { 755 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 756 } 757 758 { 759 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 760 } 761 762 { 763 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 764 } 765 766 { 767 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 768 } 769 770 { 771 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 772 } 773 544 774 } 545 775 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){ … … 580 810 } 581 811 582 } 583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){ 812 { 813 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 814 } 815 816 { 817 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 818 } 819 820 { 821 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 822 } 823 824 { 825 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 826 } 827 828 { 829 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 830 } 831 832 } 833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){ 584 834 { 585 835 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); … … 616 866 { 617 867 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 868 } 869 870 { 871 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 872 } 873 874 { 875 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 876 } 877 878 { 879 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 880 } 881 882 { 883 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 884 } 885 886 { 887 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 888 } 889 890 } 891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){ 892 { 893 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 894 } 895 896 { 897 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 898 } 899 900 { 901 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 902 } 903 904 { 905 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 906 } 907 908 { 909 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 910 } 911 912 { 913 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 914 } 915 916 { 917 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 918 } 919 920 { 921 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 922 } 923 924 { 925 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 926 } 927 928 { 929 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 930 } 931 932 { 933 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 934 } 935 936 { 937 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 938 } 939 940 { 941 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 942 } 943 944 { 945 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 946 } 947 948 } 949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){ 950 { 951 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 952 } 953 954 { 955 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 956 } 957 958 { 959 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 960 } 961 962 { 963 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 964 } 965 966 { 967 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 968 } 969 970 { 971 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 972 } 973 974 { 975 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 976 } 977 978 { 979 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 980 } 981 982 { 983 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 984 } 985 986 { 987 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 988 } 989 990 { 991 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 992 } 993 994 { 995 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 996 } 997 998 { 999 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 1000 } 1001 1002 { 1003 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1004 } 1005 1006 } 1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){ 1008 { 1009 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1010 } 1011 1012 { 1013 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1014 } 1015 1016 { 1017 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1018 } 1019 1020 { 1021 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1022 } 1023 1024 { 1025 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1026 } 1027 1028 { 1029 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1030 } 1031 1032 { 1033 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1034 } 1035 1036 { 1037 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1038 } 1039 1040 { 1041 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1042 } 1043 1044 { 1045 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1046 } 1047 1048 { 1049 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1050 } 1051 1052 { 1053 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1054 } 1055 1056 { 1057 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 1058 } 1059 1060 { 1061 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1062 } 1063 1064 } 1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){ 1066 { 1067 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1068 } 1069 1070 { 1071 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1072 } 1073 1074 { 1075 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1076 } 1077 1078 { 1079 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1080 } 1081 1082 { 1083 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1084 } 1085 1086 { 1087 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1088 } 1089 1090 { 1091 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1092 } 1093 1094 { 1095 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1096 } 1097 1098 { 1099 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1100 } 1101 1102 { 1103 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1104 } 1105 1106 { 1107 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1108 } 1109 1110 { 1111 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1112 } 1113 1114 { 1115 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */); 1116 } 1117 1118 { 1119 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1120 } 1121 1122 } 1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){ 1124 { 1125 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1126 } 1127 1128 { 1129 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1130 } 1131 1132 { 1133 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1134 } 1135 1136 { 1137 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1138 } 1139 1140 { 1141 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1142 } 1143 1144 { 1145 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1146 } 1147 1148 { 1149 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1150 } 1151 1152 { 1153 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1154 } 1155 1156 { 1157 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1158 } 1159 1160 { 1161 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1162 } 1163 1164 { 1165 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1166 } 1167 1168 { 1169 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1170 } 1171 1172 { 1173 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */); 1174 } 1175 1176 { 1177 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */); 618 1178 } 619 1179 … … 628 1188 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)(); 629 1189 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)(); 1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)(); 1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)(); 630 1192 __attribute__ ((unused,used)) signed int _X2f1Fi___1(); 631 1193 __attribute__ ((unused)) signed int _X2f1Fi___1(){ … … 637 1199 } 638 1200 __attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[]; 639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{ 640 __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[]; 641 } 642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0); 643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){ 644 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0); 1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[]; 1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{ 1203 __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[]; 1204 } 1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{ 1206 __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[]; 1207 } 1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0); 1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){ 1210 __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0); 1211 } 1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){ 1213 __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0); 1214 } 1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){ 1216 __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0); 645 1217 } 646 1218 signed int _X3vtrFi___1(){ … … 650 1222 __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)]; 651 1223 __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)]; 652 __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2(); 1224 __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)]; 1225 __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2(); 653 1226 __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2(); 654 1227 } … … 672 1245 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1); 673 1246 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1); 674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 1)(signed int __param_0[((unsigned long int )5)]));1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int __param_0[((unsigned long int )5)])); 675 1248 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 676 1249 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 2)(signed int (*__param_0)(signed int __param_0)));1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object3)(signed int (*__param_0)(signed int __param_0))); 678 1251 signed int _X2adFi___1(){ 679 1252 __attribute__ ((unused)) signed int _X10_retval_adi_1; … … 777 1350 778 1351 } 779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4);780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object 5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6);781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8);782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)());783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 1)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0));784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 3)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)());785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 5)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0));1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5); 1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7); 1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9); 1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)()); 1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0)); 1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)()); 1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0)); 786 1359 struct Vad { 787 1360 __attribute__ ((unused)) signed int :4; -
tests/.expect/attributes.nast.x86.txt
rfeacef9 r5407cdc 104 104 __attribute__ ((used,unused,unused)) signed int _X2f7i_1; 105 105 __attribute__ ((used,used,unused)) signed int _X2f8i_1; 106 __attribute__ ((unused,unused)) signed int *_X2f9Pi_1; 106 __attribute__ ((unused)) signed int *_X2f9Pi_1; 107 __attribute__ ((unused,used)) signed int *_X3f10Pi_1; 108 __attribute__ ((unused,unused)) signed int *_X3f11Pi_1; 109 __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1; 110 __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1; 111 __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1; 107 112 }; 108 113 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1); … … 118 123 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1); 119 124 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1); 120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1); 125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1); 126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1); 127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1); 128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1); 129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1); 130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1); 121 131 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 122 132 { … … 156 166 } 157 167 168 { 169 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 170 } 171 172 { 173 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 174 } 175 176 { 177 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 178 } 179 180 { 181 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 182 } 183 184 { 185 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 186 } 187 158 188 } 159 189 static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){ … … 194 224 } 195 225 226 { 227 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */); 228 } 229 230 { 231 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */); 232 } 233 234 { 235 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */); 236 } 237 238 { 239 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */); 240 } 241 242 { 243 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */); 244 } 245 196 246 } 197 247 static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 248 { 249 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */); 250 } 251 252 { 253 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */); 254 } 255 256 { 257 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */); 258 } 259 260 { 261 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */); 262 } 263 264 { 265 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */); 266 } 267 198 268 { 199 269 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */); … … 272 342 273 343 { 344 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1)); 345 } 346 347 { 348 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1)); 349 } 350 351 { 352 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1)); 353 } 354 355 { 356 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1)); 357 } 358 359 { 360 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1)); 361 } 362 363 { 274 364 ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1))); 275 365 } … … 314 404 } 315 405 406 { 407 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 408 } 409 410 { 411 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 412 } 413 414 { 415 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 416 } 417 418 { 419 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 420 } 421 422 { 423 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 424 } 425 316 426 } 317 427 static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){ … … 352 462 } 353 463 464 { 465 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 466 } 467 468 { 469 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 470 } 471 472 { 473 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 474 } 475 476 { 477 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 478 } 479 480 { 481 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 482 } 483 354 484 } 355 485 static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){ … … 390 520 } 391 521 522 { 523 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 524 } 525 526 { 527 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 528 } 529 530 { 531 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 532 } 533 534 { 535 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 536 } 537 538 { 539 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 540 } 541 392 542 } 393 543 static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){ … … 428 578 } 429 579 580 { 581 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 582 } 583 584 { 585 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 586 } 587 588 { 589 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 590 } 591 592 { 593 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 594 } 595 596 { 597 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 598 } 599 430 600 } 431 601 static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){ … … 466 636 } 467 637 638 { 639 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 640 } 641 642 { 643 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 644 } 645 646 { 647 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 648 } 649 650 { 651 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 652 } 653 654 { 655 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 656 } 657 468 658 } 469 659 static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){ … … 504 694 } 505 695 696 { 697 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 698 } 699 700 { 701 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 702 } 703 704 { 705 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 706 } 707 708 { 709 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 710 } 711 712 { 713 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 714 } 715 506 716 } 507 717 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){ … … 542 752 } 543 753 754 { 755 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 756 } 757 758 { 759 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 760 } 761 762 { 763 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 764 } 765 766 { 767 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 768 } 769 770 { 771 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 772 } 773 544 774 } 545 775 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){ … … 580 810 } 581 811 582 } 583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){ 812 { 813 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 814 } 815 816 { 817 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 818 } 819 820 { 821 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 822 } 823 824 { 825 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 826 } 827 828 { 829 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 830 } 831 832 } 833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){ 584 834 { 585 835 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); … … 616 866 { 617 867 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 868 } 869 870 { 871 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 872 } 873 874 { 875 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 876 } 877 878 { 879 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 880 } 881 882 { 883 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 884 } 885 886 { 887 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 888 } 889 890 } 891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){ 892 { 893 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 894 } 895 896 { 897 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 898 } 899 900 { 901 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 902 } 903 904 { 905 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 906 } 907 908 { 909 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 910 } 911 912 { 913 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 914 } 915 916 { 917 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 918 } 919 920 { 921 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 922 } 923 924 { 925 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 926 } 927 928 { 929 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 930 } 931 932 { 933 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 934 } 935 936 { 937 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 938 } 939 940 { 941 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 942 } 943 944 { 945 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 946 } 947 948 } 949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){ 950 { 951 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 952 } 953 954 { 955 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 956 } 957 958 { 959 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 960 } 961 962 { 963 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 964 } 965 966 { 967 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 968 } 969 970 { 971 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 972 } 973 974 { 975 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 976 } 977 978 { 979 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 980 } 981 982 { 983 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 984 } 985 986 { 987 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 988 } 989 990 { 991 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 992 } 993 994 { 995 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 996 } 997 998 { 999 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 1000 } 1001 1002 { 1003 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1004 } 1005 1006 } 1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){ 1008 { 1009 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1010 } 1011 1012 { 1013 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1014 } 1015 1016 { 1017 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1018 } 1019 1020 { 1021 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1022 } 1023 1024 { 1025 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1026 } 1027 1028 { 1029 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1030 } 1031 1032 { 1033 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1034 } 1035 1036 { 1037 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1038 } 1039 1040 { 1041 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1042 } 1043 1044 { 1045 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1046 } 1047 1048 { 1049 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1050 } 1051 1052 { 1053 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1054 } 1055 1056 { 1057 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 1058 } 1059 1060 { 1061 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1062 } 1063 1064 } 1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){ 1066 { 1067 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1068 } 1069 1070 { 1071 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1072 } 1073 1074 { 1075 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1076 } 1077 1078 { 1079 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1080 } 1081 1082 { 1083 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1084 } 1085 1086 { 1087 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1088 } 1089 1090 { 1091 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1092 } 1093 1094 { 1095 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1096 } 1097 1098 { 1099 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1100 } 1101 1102 { 1103 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1104 } 1105 1106 { 1107 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1108 } 1109 1110 { 1111 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1112 } 1113 1114 { 1115 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */); 1116 } 1117 1118 { 1119 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1120 } 1121 1122 } 1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){ 1124 { 1125 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1126 } 1127 1128 { 1129 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1130 } 1131 1132 { 1133 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1134 } 1135 1136 { 1137 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1138 } 1139 1140 { 1141 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1142 } 1143 1144 { 1145 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1146 } 1147 1148 { 1149 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1150 } 1151 1152 { 1153 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1154 } 1155 1156 { 1157 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1158 } 1159 1160 { 1161 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1162 } 1163 1164 { 1165 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1166 } 1167 1168 { 1169 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1170 } 1171 1172 { 1173 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */); 1174 } 1175 1176 { 1177 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */); 618 1178 } 619 1179 … … 628 1188 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)(); 629 1189 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)(); 1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)(); 1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)(); 630 1192 __attribute__ ((unused,used)) signed int _X2f1Fi___1(); 631 1193 __attribute__ ((unused)) signed int _X2f1Fi___1(){ … … 637 1199 } 638 1200 __attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[]; 639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{ 640 __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[]; 641 } 642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0); 643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){ 644 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0); 1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[]; 1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{ 1203 __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[]; 1204 } 1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{ 1206 __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[]; 1207 } 1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0); 1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){ 1210 __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0); 1211 } 1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){ 1213 __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0); 1214 } 1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){ 1216 __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0); 645 1217 } 646 1218 signed int _X3vtrFi___1(){ … … 650 1222 __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned int )5)]; 651 1223 __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned int )5)]; 652 __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2(); 1224 __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned int )5)]; 1225 __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2(); 653 1226 __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2(); 654 1227 } … … 672 1245 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1); 673 1246 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1); 674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 1)(signed int __param_0[((unsigned int )5)]));1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int __param_0[((unsigned int )5)])); 675 1248 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 676 1249 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 2)(signed int (*__param_0)(signed int __param_0)));1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object3)(signed int (*__param_0)(signed int __param_0))); 678 1251 signed int _X2adFi___1(){ 679 1252 __attribute__ ((unused)) signed int _X10_retval_adi_1; … … 777 1350 778 1351 } 779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4);780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object 5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6);781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8);782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)());783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 1)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0));784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 3)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)());785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object1 5)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0));1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5); 1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7); 1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9); 1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)()); 1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0)); 1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)()); 1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0)); 786 1359 struct Vad { 787 1360 __attribute__ ((unused)) signed int :4; -
tests/.expect/attributes.oast.x64.txt
rfeacef9 r5407cdc 104 104 __attribute__ ((used,unused,unused)) signed int _X2f7i_1; 105 105 __attribute__ ((used,used,unused)) signed int _X2f8i_1; 106 __attribute__ ((unused,unused)) signed int *_X2f9Pi_1; 106 __attribute__ ((unused)) signed int *_X2f9Pi_1; 107 __attribute__ ((unused,used)) signed int *_X3f10Pi_1; 108 __attribute__ ((unused,unused)) signed int *_X3f11Pi_1; 109 __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1; 110 __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1; 111 __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1; 107 112 }; 108 113 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1); … … 118 123 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1); 119 124 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1); 120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1); 125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1); 126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1); 127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1); 128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1); 129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1); 130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1); 121 131 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 122 132 { … … 156 166 } 157 167 168 { 169 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 170 } 171 172 { 173 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 174 } 175 176 { 177 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 178 } 179 180 { 181 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 182 } 183 184 { 185 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 186 } 187 158 188 } 159 189 static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){ … … 194 224 } 195 225 226 { 227 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */); 228 } 229 230 { 231 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */); 232 } 233 234 { 235 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */); 236 } 237 238 { 239 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */); 240 } 241 242 { 243 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */); 244 } 245 196 246 } 197 247 static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 248 { 249 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */); 250 } 251 252 { 253 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */); 254 } 255 256 { 257 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */); 258 } 259 260 { 261 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */); 262 } 263 264 { 265 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */); 266 } 267 198 268 { 199 269 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */); … … 272 342 273 343 { 344 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1)); 345 } 346 347 { 348 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1)); 349 } 350 351 { 352 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1)); 353 } 354 355 { 356 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1)); 357 } 358 359 { 360 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1)); 361 } 362 363 { 274 364 ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1))); 275 365 } … … 314 404 } 315 405 406 { 407 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 408 } 409 410 { 411 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 412 } 413 414 { 415 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 416 } 417 418 { 419 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 420 } 421 422 { 423 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 424 } 425 316 426 } 317 427 static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){ … … 352 462 } 353 463 464 { 465 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 466 } 467 468 { 469 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 470 } 471 472 { 473 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 474 } 475 476 { 477 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 478 } 479 480 { 481 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 482 } 483 354 484 } 355 485 static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){ … … 390 520 } 391 521 522 { 523 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 524 } 525 526 { 527 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 528 } 529 530 { 531 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 532 } 533 534 { 535 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 536 } 537 538 { 539 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 540 } 541 392 542 } 393 543 static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){ … … 428 578 } 429 579 580 { 581 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 582 } 583 584 { 585 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 586 } 587 588 { 589 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 590 } 591 592 { 593 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 594 } 595 596 { 597 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 598 } 599 430 600 } 431 601 static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){ … … 466 636 } 467 637 638 { 639 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 640 } 641 642 { 643 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 644 } 645 646 { 647 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 648 } 649 650 { 651 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 652 } 653 654 { 655 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 656 } 657 468 658 } 469 659 static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){ … … 504 694 } 505 695 696 { 697 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 698 } 699 700 { 701 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 702 } 703 704 { 705 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 706 } 707 708 { 709 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 710 } 711 712 { 713 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 714 } 715 506 716 } 507 717 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){ … … 542 752 } 543 753 754 { 755 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 756 } 757 758 { 759 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 760 } 761 762 { 763 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 764 } 765 766 { 767 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 768 } 769 770 { 771 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 772 } 773 544 774 } 545 775 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){ … … 580 810 } 581 811 582 } 583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){ 812 { 813 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 814 } 815 816 { 817 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 818 } 819 820 { 821 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 822 } 823 824 { 825 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 826 } 827 828 { 829 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 830 } 831 832 } 833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){ 584 834 { 585 835 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); … … 616 866 { 617 867 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 868 } 869 870 { 871 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 872 } 873 874 { 875 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 876 } 877 878 { 879 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 880 } 881 882 { 883 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 884 } 885 886 { 887 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 888 } 889 890 } 891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){ 892 { 893 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 894 } 895 896 { 897 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 898 } 899 900 { 901 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 902 } 903 904 { 905 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 906 } 907 908 { 909 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 910 } 911 912 { 913 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 914 } 915 916 { 917 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 918 } 919 920 { 921 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 922 } 923 924 { 925 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 926 } 927 928 { 929 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 930 } 931 932 { 933 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 934 } 935 936 { 937 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 938 } 939 940 { 941 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 942 } 943 944 { 945 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 946 } 947 948 } 949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){ 950 { 951 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 952 } 953 954 { 955 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 956 } 957 958 { 959 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 960 } 961 962 { 963 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 964 } 965 966 { 967 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 968 } 969 970 { 971 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 972 } 973 974 { 975 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 976 } 977 978 { 979 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 980 } 981 982 { 983 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 984 } 985 986 { 987 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 988 } 989 990 { 991 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 992 } 993 994 { 995 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 996 } 997 998 { 999 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 1000 } 1001 1002 { 1003 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1004 } 1005 1006 } 1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){ 1008 { 1009 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1010 } 1011 1012 { 1013 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1014 } 1015 1016 { 1017 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1018 } 1019 1020 { 1021 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1022 } 1023 1024 { 1025 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1026 } 1027 1028 { 1029 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1030 } 1031 1032 { 1033 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1034 } 1035 1036 { 1037 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1038 } 1039 1040 { 1041 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1042 } 1043 1044 { 1045 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1046 } 1047 1048 { 1049 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1050 } 1051 1052 { 1053 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1054 } 1055 1056 { 1057 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 1058 } 1059 1060 { 1061 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1062 } 1063 1064 } 1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){ 1066 { 1067 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1068 } 1069 1070 { 1071 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1072 } 1073 1074 { 1075 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1076 } 1077 1078 { 1079 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1080 } 1081 1082 { 1083 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1084 } 1085 1086 { 1087 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1088 } 1089 1090 { 1091 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1092 } 1093 1094 { 1095 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1096 } 1097 1098 { 1099 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1100 } 1101 1102 { 1103 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1104 } 1105 1106 { 1107 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1108 } 1109 1110 { 1111 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1112 } 1113 1114 { 1115 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */); 1116 } 1117 1118 { 1119 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1120 } 1121 1122 } 1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){ 1124 { 1125 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1126 } 1127 1128 { 1129 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1130 } 1131 1132 { 1133 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1134 } 1135 1136 { 1137 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1138 } 1139 1140 { 1141 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1142 } 1143 1144 { 1145 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1146 } 1147 1148 { 1149 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1150 } 1151 1152 { 1153 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1154 } 1155 1156 { 1157 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1158 } 1159 1160 { 1161 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1162 } 1163 1164 { 1165 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1166 } 1167 1168 { 1169 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1170 } 1171 1172 { 1173 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */); 1174 } 1175 1176 { 1177 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */); 618 1178 } 619 1179 … … 628 1188 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)(); 629 1189 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)(); 1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)(); 1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)(); 630 1192 __attribute__ ((unused,used)) signed int _X2f1Fi___1(); 631 1193 __attribute__ ((unused)) signed int _X2f1Fi___1(){ … … 637 1199 } 638 1200 __attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[]; 639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{ 640 __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[]; 641 } 642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1); 643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){ 644 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3); 1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[]; 1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{ 1203 __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[]; 1204 } 1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{ 1206 __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[]; 1207 } 1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __anonymous_object2); 1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object3){ 1210 __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __anonymous_object4); 1211 } 1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object5){ 1213 __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __anonymous_object6); 1214 } 1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object7){ 1216 __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __anonymous_object8); 645 1217 } 646 1218 signed int _X3vtrFi___1(){ … … 650 1222 __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)]; 651 1223 __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)]; 652 __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2(); 1224 __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)]; 1225 __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2(); 653 1226 __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2(); 654 1227 } … … 672 1245 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1); 673 1246 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1); 674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 4)(__attribute__ ((unused,unused)) signed int __anonymous_object5[((unsigned long int )5)]));1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object9)(__attribute__ ((unused,unused)) signed int __anonymous_object10[((unsigned long int )5)])); 675 1248 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 676 1249 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 6)(__attribute__ ((unused)) signed int (*__anonymous_object7)(__attribute__ ((unused,unused)) signed int __anonymous_object8)));1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object11)(__attribute__ ((unused)) signed int (*__anonymous_object12)(__attribute__ ((unused,unused)) signed int __anonymous_object13))); 678 1251 signed int _X2adFi___1(){ 679 1252 __attribute__ ((unused)) signed int _X10_retval_adi_1; … … 777 1350 778 1351 } 779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 9, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object10);780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object1 1, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object12);781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object1 3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object14);782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 15)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)());783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 17)(__attribute__ ((unused)) signed int __anonymous_object18), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object19)(__attribute__ ((unused)) signed int __anonymous_object20));784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object2 1)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)());785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object2 3)(__attribute__ ((unused)) signed int __anonymous_object24), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object25)(__attribute__ ((unused)) signed int __anonymous_object26));1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object14, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object15); 1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object16, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object17); 1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object18, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object19); 1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object20)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)()); 1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)(__attribute__ ((unused)) signed int __anonymous_object23), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object24)(__attribute__ ((unused)) signed int __anonymous_object25)); 1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object26)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object27)()); 1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object28)(__attribute__ ((unused)) signed int __anonymous_object29), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object30)(__attribute__ ((unused)) signed int __anonymous_object31)); 786 1359 struct Vad { 787 1360 __attribute__ ((unused)) signed int :4; -
tests/.expect/attributes.oast.x86.txt
rfeacef9 r5407cdc 104 104 __attribute__ ((used,unused,unused)) signed int _X2f7i_1; 105 105 __attribute__ ((used,used,unused)) signed int _X2f8i_1; 106 __attribute__ ((unused,unused)) signed int *_X2f9Pi_1; 106 __attribute__ ((unused)) signed int *_X2f9Pi_1; 107 __attribute__ ((unused,used)) signed int *_X3f10Pi_1; 108 __attribute__ ((unused,unused)) signed int *_X3f11Pi_1; 109 __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1; 110 __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1; 111 __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1; 107 112 }; 108 113 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1); … … 118 123 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1); 119 124 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1); 120 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1); 125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1); 126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1); 127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1); 128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1); 129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1); 130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1); 121 131 static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 122 132 { … … 156 166 } 157 167 168 { 169 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 170 } 171 172 { 173 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 174 } 175 176 { 177 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 178 } 179 180 { 181 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 182 } 183 184 { 185 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 186 } 187 158 188 } 159 189 static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){ … … 194 224 } 195 225 226 { 227 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */); 228 } 229 230 { 231 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */); 232 } 233 234 { 235 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */); 236 } 237 238 { 239 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */); 240 } 241 242 { 243 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */); 244 } 245 196 246 } 197 247 static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){ 248 { 249 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */); 250 } 251 252 { 253 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */); 254 } 255 256 { 257 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */); 258 } 259 260 { 261 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */); 262 } 263 264 { 265 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */); 266 } 267 198 268 { 199 269 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */); … … 272 342 273 343 { 344 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1)); 345 } 346 347 { 348 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1)); 349 } 350 351 { 352 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1)); 353 } 354 355 { 356 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1)); 357 } 358 359 { 360 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1)); 361 } 362 363 { 274 364 ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1))); 275 365 } … … 314 404 } 315 405 406 { 407 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 408 } 409 410 { 411 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 412 } 413 414 { 415 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 416 } 417 418 { 419 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 420 } 421 422 { 423 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 424 } 425 316 426 } 317 427 static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){ … … 352 462 } 353 463 464 { 465 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 466 } 467 468 { 469 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 470 } 471 472 { 473 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 474 } 475 476 { 477 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 478 } 479 480 { 481 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 482 } 483 354 484 } 355 485 static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){ … … 390 520 } 391 521 522 { 523 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 524 } 525 526 { 527 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 528 } 529 530 { 531 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 532 } 533 534 { 535 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 536 } 537 538 { 539 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 540 } 541 392 542 } 393 543 static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){ … … 428 578 } 429 579 580 { 581 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 582 } 583 584 { 585 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 586 } 587 588 { 589 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 590 } 591 592 { 593 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 594 } 595 596 { 597 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 598 } 599 430 600 } 431 601 static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){ … … 466 636 } 467 637 638 { 639 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 640 } 641 642 { 643 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 644 } 645 646 { 647 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 648 } 649 650 { 651 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 652 } 653 654 { 655 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 656 } 657 468 658 } 469 659 static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){ … … 504 694 } 505 695 696 { 697 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 698 } 699 700 { 701 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 702 } 703 704 { 705 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 706 } 707 708 { 709 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 710 } 711 712 { 713 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 714 } 715 506 716 } 507 717 static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){ … … 542 752 } 543 753 754 { 755 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 756 } 757 758 { 759 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 760 } 761 762 { 763 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 764 } 765 766 { 767 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 768 } 769 770 { 771 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 772 } 773 544 774 } 545 775 static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){ … … 580 810 } 581 811 582 } 583 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){ 812 { 813 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 814 } 815 816 { 817 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 818 } 819 820 { 821 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 822 } 823 824 { 825 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 826 } 827 828 { 829 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 830 } 831 832 } 833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){ 584 834 { 585 835 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); … … 616 866 { 617 867 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 868 } 869 870 { 871 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */); 872 } 873 874 { 875 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 876 } 877 878 { 879 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 880 } 881 882 { 883 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 884 } 885 886 { 887 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 888 } 889 890 } 891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){ 892 { 893 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 894 } 895 896 { 897 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 898 } 899 900 { 901 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 902 } 903 904 { 905 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 906 } 907 908 { 909 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 910 } 911 912 { 913 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 914 } 915 916 { 917 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 918 } 919 920 { 921 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 922 } 923 924 { 925 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 926 } 927 928 { 929 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 930 } 931 932 { 933 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */); 934 } 935 936 { 937 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 938 } 939 940 { 941 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 942 } 943 944 { 945 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 946 } 947 948 } 949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){ 950 { 951 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 952 } 953 954 { 955 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 956 } 957 958 { 959 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 960 } 961 962 { 963 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 964 } 965 966 { 967 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 968 } 969 970 { 971 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 972 } 973 974 { 975 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 976 } 977 978 { 979 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 980 } 981 982 { 983 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 984 } 985 986 { 987 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 988 } 989 990 { 991 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 992 } 993 994 { 995 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */); 996 } 997 998 { 999 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 1000 } 1001 1002 { 1003 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1004 } 1005 1006 } 1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){ 1008 { 1009 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1010 } 1011 1012 { 1013 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1014 } 1015 1016 { 1017 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1018 } 1019 1020 { 1021 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1022 } 1023 1024 { 1025 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1026 } 1027 1028 { 1029 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1030 } 1031 1032 { 1033 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1034 } 1035 1036 { 1037 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1038 } 1039 1040 { 1041 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1042 } 1043 1044 { 1045 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1046 } 1047 1048 { 1049 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1050 } 1051 1052 { 1053 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1054 } 1055 1056 { 1057 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */); 1058 } 1059 1060 { 1061 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1062 } 1063 1064 } 1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){ 1066 { 1067 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1068 } 1069 1070 { 1071 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1072 } 1073 1074 { 1075 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1076 } 1077 1078 { 1079 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1080 } 1081 1082 { 1083 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1084 } 1085 1086 { 1087 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1088 } 1089 1090 { 1091 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1092 } 1093 1094 { 1095 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1096 } 1097 1098 { 1099 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1100 } 1101 1102 { 1103 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1104 } 1105 1106 { 1107 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1108 } 1109 1110 { 1111 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1112 } 1113 1114 { 1115 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */); 1116 } 1117 1118 { 1119 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */); 1120 } 1121 1122 } 1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){ 1124 { 1125 ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */); 1126 } 1127 1128 { 1129 ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */); 1130 } 1131 1132 { 1133 ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */); 1134 } 1135 1136 { 1137 ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */); 1138 } 1139 1140 { 1141 ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */); 1142 } 1143 1144 { 1145 ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */); 1146 } 1147 1148 { 1149 ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */); 1150 } 1151 1152 { 1153 ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */); 1154 } 1155 1156 { 1157 ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */); 1158 } 1159 1160 { 1161 ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */); 1162 } 1163 1164 { 1165 ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */); 1166 } 1167 1168 { 1169 ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */); 1170 } 1171 1172 { 1173 ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */); 1174 } 1175 1176 { 1177 ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */); 618 1178 } 619 1179 … … 628 1188 __attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)(); 629 1189 __attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)(); 1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)(); 1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)(); 630 1192 __attribute__ ((unused,used)) signed int _X2f1Fi___1(); 631 1193 __attribute__ ((unused)) signed int _X2f1Fi___1(){ … … 637 1199 } 638 1200 __attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[]; 639 __attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{ 640 __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[]; 641 } 642 __attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1); 643 __attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){ 644 __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3); 1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[]; 1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{ 1203 __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[]; 1204 } 1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{ 1206 __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[]; 1207 } 1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __anonymous_object2); 1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object3){ 1210 __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __anonymous_object4); 1211 } 1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object5){ 1213 __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __anonymous_object6); 1214 } 1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object7){ 1216 __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __anonymous_object8); 645 1217 } 646 1218 signed int _X3vtrFi___1(){ … … 650 1222 __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned int )5)]; 651 1223 __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned int )5)]; 652 __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2(); 1224 __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned int )5)]; 1225 __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2(); 653 1226 __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2(); 654 1227 } … … 672 1245 signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1); 673 1246 signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1); 674 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 4)(__attribute__ ((unused,unused)) signed int __anonymous_object5[((unsigned int )5)]));1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object9)(__attribute__ ((unused,unused)) signed int __anonymous_object10[((unsigned int )5)])); 675 1248 signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 676 1249 signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)()); 677 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object 6)(__attribute__ ((unused)) signed int (*__anonymous_object7)(__attribute__ ((unused,unused)) signed int __anonymous_object8)));1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object11)(__attribute__ ((unused)) signed int (*__anonymous_object12)(__attribute__ ((unused,unused)) signed int __anonymous_object13))); 678 1251 signed int _X2adFi___1(){ 679 1252 __attribute__ ((unused)) signed int _X10_retval_adi_1; … … 777 1350 778 1351 } 779 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object 9, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object10);780 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object1 1, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object12);781 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object1 3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object14);782 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 15)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)());783 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object 17)(__attribute__ ((unused)) signed int __anonymous_object18), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object19)(__attribute__ ((unused)) signed int __anonymous_object20));784 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object2 1)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)());785 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object2 3)(__attribute__ ((unused)) signed int __anonymous_object24), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object25)(__attribute__ ((unused)) signed int __anonymous_object26));1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object14, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object15); 1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object16, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object17); 1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object18, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object19); 1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object20)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)()); 1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)(__attribute__ ((unused)) signed int __anonymous_object23), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object24)(__attribute__ ((unused)) signed int __anonymous_object25)); 1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object26)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object27)()); 1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object28)(__attribute__ ((unused)) signed int __anonymous_object29), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object30)(__attribute__ ((unused)) signed int __anonymous_object31)); 786 1359 struct Vad { 787 1360 __attribute__ ((unused)) signed int :4; -
tests/.expect/declarationSpecifier.arm64.txt
rfeacef9 r5407cdc 1147 1147 1148 1148 { 1149 signed int _tmp_cp_ret 4;1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);1149 signed int _tmp_cp_ret6; 1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */); 1151 1151 } 1152 1152 -
tests/.expect/declarationSpecifier.x64.txt
rfeacef9 r5407cdc 1147 1147 1148 1148 { 1149 signed int _tmp_cp_ret 4;1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);1149 signed int _tmp_cp_ret6; 1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */); 1151 1151 } 1152 1152 -
tests/.expect/declarationSpecifier.x86.txt
rfeacef9 r5407cdc 1147 1147 1148 1148 { 1149 signed int _tmp_cp_ret 4;1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);1149 signed int _tmp_cp_ret6; 1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */); 1151 1151 } 1152 1152 -
tests/.expect/extension.arm64.txt
rfeacef9 r5407cdc 457 457 458 458 { 459 signed int _tmp_cp_ret 4;460 ((void)(((void)(_tmp_cp_ret 4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));459 signed int _tmp_cp_ret6; 460 ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6)); 461 461 } 462 462 -
tests/.expect/extension.x64.txt
rfeacef9 r5407cdc 457 457 458 458 { 459 signed int _tmp_cp_ret 4;460 ((void)(((void)(_tmp_cp_ret 4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));459 signed int _tmp_cp_ret6; 460 ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6)); 461 461 } 462 462 -
tests/.expect/extension.x86.txt
rfeacef9 r5407cdc 457 457 458 458 { 459 signed int _tmp_cp_ret 4;460 ((void)(((void)(_tmp_cp_ret 4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));459 signed int _tmp_cp_ret6; 460 ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6)); 461 461 } 462 462 -
tests/.expect/gccExtensions.arm64.txt
rfeacef9 r5407cdc 339 339 340 340 { 341 signed int _tmp_cp_ret 4;342 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);341 signed int _tmp_cp_ret6; 342 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */); 343 343 } 344 344 -
tests/.expect/gccExtensions.x64.txt
rfeacef9 r5407cdc 339 339 340 340 { 341 signed int _tmp_cp_ret 4;342 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);341 signed int _tmp_cp_ret6; 342 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */); 343 343 } 344 344 -
tests/.expect/gccExtensions.x86.txt
rfeacef9 r5407cdc 317 317 318 318 { 319 signed int _tmp_cp_ret 4;320 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);319 signed int _tmp_cp_ret6; 320 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */); 321 321 } 322 322 -
tests/Makefile.am
rfeacef9 r5407cdc 11 11 ## Created On : Sun May 31 09:08:15 2015 12 12 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Fri Oct 9 23:13:07 202014 ## Update Count : 8613 ## Last Modified On : Tue Mar 2 21:39:01 2021 14 ## Update Count : 90 15 15 ############################################################################### 16 16 … … 26 26 archiveerrors= 27 27 28 DEBUG_FLAGS=-debug - O028 DEBUG_FLAGS=-debug -g -O0 29 29 30 30 quick_test=avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes … … 44 44 -Wall \ 45 45 -Wno-unused-function \ 46 - quiet @CFA_FLAGS@\47 - DIN_DIR="${abs_srcdir}/.in/"46 -Wno-psabi \ 47 -quiet @CFA_FLAGS@ 48 48 49 49 AM_CFAFLAGS = -XCFA --deterministic-out … … 75 75 pybin/tools.py \ 76 76 long_tests.hfa \ 77 .in/io.data \ 77 io/.in/io.data \ 78 io/.in/many_read.data \ 78 79 avltree/avl.h \ 79 80 avltree/avl-private.h \ 80 81 concurrent/clib.c \ 82 concurrent/clib_tls.c \ 81 83 exceptions/with-threads.hfa \ 82 84 exceptions/except-io.hfa … … 142 144 # don't use distcc to do the linking because distcc doesn't do linking 143 145 % : %.cfa $(CFACCBIN) 144 $(CFACOMPILETEST) -c -o $(abspath ${@}).o 146 $(CFACOMPILETEST) -c -o $(abspath ${@}).o -DIN_DIR="$(abspath $(dir ${<}))/.in/" 145 147 $(CFACCLINK) ${@}.o -o $(abspath ${@}) 146 148 rm $(abspath ${@}).o … … 170 172 171 173 SYNTAX_ONLY_CODE = expression typedefRedef variableDeclarator switch numericConstants identFuncDeclarator forall \ 172 init1 limits nested-types stdincludes cast labelledExit array builtins/sync warnings/self-assignment174 init1 limits nested-types stdincludes cast labelledExit array quasiKeyword include/includes builtins/sync warnings/self-assignment 173 175 $(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN) 174 176 $(CFACOMPILE_SYNTAX) -
tests/attributes.cfa
rfeacef9 r5407cdc 10 10 // Created On : Mon Feb 6 16:07:02 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Jan 25 21:26:41 202113 // Update Count : 2012 // Last Modified On : Mon Mar 15 13:53:31 2021 13 // Update Count : 38 14 14 // 15 15 … … 42 42 __attribute__(( unused )) int f5 __attribute__(( unused )); 43 43 __attribute__(( used )) int f6 __attribute__(( packed )), f7 __attribute__(( unused )) __attribute__(( unused )), __attribute__(( used )) f8 __attribute__(( unused )); 44 int ( ( * (f9) __attribute__(( unused )) ) __attribute__(( unused )) ); 44 int * f9 __attribute__(( unused )); 45 __attribute__(( used )) int __attribute__(( unused )) * f10; 46 int ( ( * f11 __attribute__(( unused )) ) __attribute__(( unused )) ); 47 int ( ( __attribute__(( unused )) * f12 __attribute__(( unused )) ) __attribute__(( unused )) ); 48 int ( ( __attribute__(( unused )) * (f13) __attribute__(( unused )) ) __attribute__(( unused )) ); 49 int ( ( ( __attribute__(( unused )) * (f14) ) __attribute__(( unused )) ) __attribute__(( unused )) ); 45 50 }; 46 51 … … 55 60 const __attribute__(( used )) int __attribute__(( used )) vd5[5] __attribute__(( used )), __attribute__(( unused )) ((vd6)[5]) __attribute__(( used )); 56 61 const __attribute__(( used )) int __attribute__(( used )) (* __attribute__(( used )) vd7)() __attribute__(( used )), __attribute__(( unused )) ((* __attribute__(( used )) vd8)()) __attribute__(( used )); 57 62 const __attribute__(( used )) int __attribute__(( used )) ( __attribute__(( used )) * vd9)() __attribute__(( used )), __attribute__(( unused )) (( __attribute__(( used )) * vd10)()) __attribute__(( used )); 58 63 59 64 // function_declarator … … 63 68 __attribute__(( unused )) int * __attribute__(( unused )) * const __attribute__(( unused )) f2() {} 64 69 __attribute__(( unused )) int (* __attribute__(( unused )) f3(int))[] __attribute__(( used )); 65 __attribute__(( unused )) int (* __attribute__(( unused )) f3(int p))[] {} 66 __attribute__(( unused )) int (* __attribute__(( unused )) f4())(int) __attribute__(( used )); 67 __attribute__(( unused )) int (* __attribute__(( unused )) f4())(int) {} 70 __attribute__(( unused )) int ( __attribute__(( unused )) * __attribute__(( unused )) f4(int))[] __attribute__(( used )); 71 __attribute__(( unused )) int (* __attribute__(( unused )) f5(int p))[] {} 72 __attribute__(( unused )) int ( __attribute__(( unused )) * (f6)(int p))[] {} 73 __attribute__(( unused )) int (* __attribute__(( unused )) f7())(int) __attribute__(( used )); 74 __attribute__(( unused )) int (* __attribute__(( unused )) f8())(int) {} 75 __attribute__(( unused )) int ( __attribute__(( unused )) * f9())(int) {} 76 __attribute__(( unused )) int ( __attribute__(( unused )) * (f10)())(int) {} 68 77 69 78 … … 76 85 __attribute__(( unused )) int __attribute__(( unused )) t3[5] __attribute__(( unused )); 77 86 __attribute__(( unused )) int __attribute__(( unused )) (* (* __attribute__(( unused )) t4[5]) __attribute__(( unused )) ) __attribute__(( unused )); 78 __attribute__(( unused )) int __attribute__(( unused )) t5() __attribute__(( unused )); 87 __attribute__(( unused )) int __attribute__(( unused )) ( __attribute__(( unused )) * ( __attribute__(( unused )) * t5[5]) __attribute__(( unused )) ) __attribute__(( unused )); 88 __attribute__(( unused )) int __attribute__(( unused )) t6() __attribute__(( unused )); 79 89 __attribute__(( unused )) int __attribute__(( unused )) * __attribute__(( unused )) ((t6))() __attribute__(( unused )); 80 90 } -
tests/concurrent/clib.c
rfeacef9 r5407cdc 1 #include <clib/cfathread.h>2 3 1 #include <stdio.h> 4 2 #include <stdlib.h> 3 #include <clib/cfathread.h> 4 #include <bits/defs.hfa> 5 6 extern "C" { 7 void _exit(int status); 8 } 5 9 6 10 thread_local struct drand48_data buffer = { 0 }; … … 15 19 cfathread_t volatile blocked[blocked_size]; 16 20 17 void Worker( cfathread_t this) {21 void * Worker( void * ) { 18 22 for(int i = 0; i < 1000; i++) { 19 23 int idx = myrand() % blocked_size; … … 22 26 cfathread_unpark( thrd ); 23 27 } else { 24 cfathread_t thrd = __atomic_exchange_n(&blocked[idx], this, __ATOMIC_SEQ_CST);28 cfathread_t thrd = __atomic_exchange_n(&blocked[idx], cfathread_self(), __ATOMIC_SEQ_CST); 25 29 cfathread_unpark( thrd ); 26 30 cfathread_park(); … … 28 32 } 29 33 printf("Done\n"); 34 return NULL; 30 35 } 31 36 32 37 volatile bool stop; 33 void Unparker( cfathread_t this) {38 void * Unparker( void * ) { 34 39 while(!stop) { 35 40 int idx = myrand() % blocked_size; … … 42 47 } 43 48 printf("Done Unparker\n"); 49 return NULL; 44 50 } 45 51 … … 51 57 } 52 58 53 cfathread_setproccnt( 4 ); 54 cfathread_t u = cfathread_create( Unparker ); 59 cfathread_cluster_t cl = cfathread_cluster_self(); 60 61 cfathread_cluster_add_worker( cl, NULL, NULL, NULL ); 62 cfathread_cluster_add_worker( cl, NULL, NULL, NULL ); 63 cfathread_cluster_add_worker( cl, NULL, NULL, NULL ); 64 65 cfathread_attr_t attr; 66 cfathread_attr_init(&attr); 67 cfathread_attr_setcluster(&attr, cl); 68 69 cfathread_t u; 70 cfathread_create( &u, &attr, Unparker, NULL ); 55 71 { 56 72 cfathread_t t[20]; 57 73 for(int i = 0; i < 20; i++) { 58 t[i] = cfathread_create( Worker);74 cfathread_create( &t[i], &attr, Worker, NULL ); 59 75 } 60 76 for(int i = 0; i < 20; i++) { 61 cfathread_join( t[i] );77 cfathread_join( t[i], NULL ); 62 78 } 63 79 } 64 80 stop = true; 65 cfathread_join(u); 66 cfathread_setproccnt( 1 ); 81 cfathread_join(u, NULL); 82 cfathread_attr_destroy(&attr); 83 fflush(stdout); 84 _exit(0); 67 85 } -
tests/concurrent/coroutineYield.cfa
rfeacef9 r5407cdc 38 38 39 39 40 Coroutine c; 40 41 int main(int argc, char* argv[]) { 41 Coroutine c;42 42 for(int i = 0; TEST(i < N); i++) { 43 43 #if !defined(TEST_FOREVER) -
tests/concurrent/futures/multi.cfa
rfeacef9 r5407cdc 5 5 6 6 thread Server { 7 int cnt, iteration;7 int pending, done, iteration; 8 8 multi_future(int) * request; 9 9 }; 10 10 11 11 void ?{}( Server & this ) { 12 this.cnt = 0; 12 ((thread&)this){"Server Thread"}; 13 this.pending = 0; 14 this.done = 0; 13 15 this.iteration = 0; 14 16 this.request = 0p; … … 16 18 17 19 void ^?{}( Server & mutex this ) { 18 assert(this. cnt== 0);19 20 assert(this.pending == 0); 21 this.request = 0p; 20 22 } 21 23 … … 24 26 } 25 27 26 void process( Server & mutex this ) { 27 fulfil( *this.request, this.iteration ); 28 this.iteration++; 28 void call( Server & mutex this ) { 29 this.pending++; 29 30 } 30 31 31 void call( Server & mutex this ) {32 this. cnt++;32 void finish( Server & mutex this ) { 33 this.done++; 33 34 } 34 35 35 void finish( Server & mutex this ) { }36 37 36 void main( Server & this ) { 37 MAIN_LOOP: 38 38 for() { 39 39 waitfor( ^?{} : this ) { 40 40 break; 41 41 } 42 or when( this.cnt < NFUTURES ) waitfor( call: this ) { 43 if (this.cnt == NFUTURES) { 44 process(this); 42 or waitfor( call: this ) { 43 if (this.pending != NFUTURES) { continue MAIN_LOOP; } 44 45 this.pending = 0; 46 fulfil( *this.request, this.iteration ); 47 this.iteration++; 48 49 for(NFUTURES) { 50 waitfor( finish: this ); 45 51 } 46 } 47 or waitfor( finish: this ) { 48 if (this.cnt == NFUTURES) { 49 reset( *this.request ); 50 this.cnt = 0; 51 } 52 53 reset( *this.request ); 54 this.done = 0; 52 55 } 53 56 } … … 57 60 Server * the_server; 58 61 thread Worker {}; 62 void ?{}(Worker & this) { 63 ((thread&)this){"Worker Thread"}; 64 } 65 59 66 multi_future(int) * shared_future; 60 67 -
tests/errors/.expect/completeType.nast.arm64.txt
rfeacef9 r5407cdc 12 12 Application of 13 13 Variable Expression: *?: forall 14 DT: data type14 instance of type DT (not function type) 15 15 function 16 16 ... with parameters … … 21 21 ... with resolved type: 22 22 pointer to forall 23 [unbound]:data type 23 instance of type [unbound] (not function type) 24 function 25 ... with parameters 26 pointer to instance of type [unbound] (not function type) 27 ... returning 28 reference to instance of type [unbound] (not function type) 29 30 ... to arguments 31 Variable Expression: x: pointer to instance of struct A without body 32 ... with resolved type: 33 pointer to instance of struct A without body 34 35 ... with resolved type: 36 reference to instance of struct A without body 37 ... to: nothing 38 ... with resolved type: 39 void 40 (types: 41 void 42 ) 43 Environment:([unbound]DT) -> instance of struct A without body (no widening) 44 45 46 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of: 47 Application of 48 Variable Expression: *?: forall 49 instance of type DT (not function type) 50 function 51 ... with parameters 52 pointer to instance of type DT (not function type) 53 ... returning 54 reference to instance of type DT (not function type) 55 56 ... with resolved type: 57 pointer to forall 58 instance of type [unbound] (not function type) 24 59 function 25 60 ... with parameters … … 41 76 void 42 77 ) 43 Environment:([unbound]) -> instance of struct B with body (no widening) 44 45 46 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of: 47 Application of 48 Variable Expression: *?: forall 49 DT: data type 50 function 51 ... with parameters 52 pointer to instance of type DT (not function type) 53 ... returning 54 reference to instance of type DT (not function type) 55 56 ... with resolved type: 57 pointer to forall 58 [unbound]:data type 59 function 60 ... with parameters 61 pointer to instance of type [unbound] (not function type) 62 ... returning 63 reference to instance of type [unbound] (not function type) 64 65 ... to arguments 66 Variable Expression: x: pointer to instance of struct A without body 67 ... with resolved type: 68 pointer to instance of struct A without body 69 70 ... with resolved type: 71 reference to instance of struct A without body 72 ... to: nothing 73 ... with resolved type: 74 void 75 (types: 76 void 77 ) 78 Environment:([unbound]) -> instance of struct A without body (no widening) 78 Environment:([unbound]DT) -> instance of struct B with body (no widening) 79 79 80 80 … … 113 113 Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of 114 114 Variable Expression: baz: forall 115 T: sized data type 116 ... with assertions 117 ?=?: pointer to function 115 instance of type T (not function type) 116 with assertions 117 Variable Expression: ?=?: pointer to function 118 ... with parameters 119 reference to instance of type T (not function type) 120 instance of type T (not function type) 121 ... returning 122 instance of type T (not function type) 123 124 ... with resolved type: 125 pointer to function 118 126 ... with parameters 119 127 reference to instance of type T (not function type) … … 122 130 instance of type T (not function type) 123 131 124 ?{}: pointer to function 125 ... with parameters 126 reference to instance of type T (not function type) 127 ... returning nothing 128 129 ?{}: pointer to function 130 ... with parameters 131 reference to instance of type T (not function type) 132 instance of type T (not function type) 133 ... returning nothing 134 135 ^?{}: pointer to function 136 ... with parameters 137 reference to instance of type T (not function type) 138 ... returning nothing 139 132 Variable Expression: ?{}: pointer to function 133 ... with parameters 134 reference to instance of type T (not function type) 135 ... returning nothing 136 137 ... with resolved type: 138 pointer to function 139 ... with parameters 140 reference to instance of type T (not function type) 141 ... returning nothing 142 143 Variable Expression: ?{}: pointer to function 144 ... with parameters 145 reference to instance of type T (not function type) 146 instance of type T (not function type) 147 ... returning nothing 148 149 ... with resolved type: 150 pointer to function 151 ... with parameters 152 reference to instance of type T (not function type) 153 instance of type T (not function type) 154 ... returning nothing 155 156 Variable Expression: ^?{}: pointer to function 157 ... with parameters 158 reference to instance of type T (not function type) 159 ... returning nothing 160 161 ... with resolved type: 162 pointer to function 163 ... with parameters 164 reference to instance of type T (not function type) 165 ... returning nothing 140 166 141 167 function … … 146 172 ... with resolved type: 147 173 pointer to forall 148 [unbound]:sized data type 149 ... with assertions 150 ?=?: pointer to function 174 instance of type [unbound] (not function type) 175 with assertions 176 Variable Expression: ?=?: pointer to function 177 ... with parameters 178 reference to instance of type T (not function type) 179 instance of type T (not function type) 180 ... returning 181 instance of type T (not function type) 182 183 ... with resolved type: 184 pointer to function 151 185 ... with parameters 152 186 reference to instance of type [unbound] (not function type) … … 155 189 instance of type [unbound] (not function type) 156 190 157 ?{}: pointer to function 191 Variable Expression: ?{}: pointer to function 192 ... with parameters 193 reference to instance of type T (not function type) 194 ... returning nothing 195 196 ... with resolved type: 197 pointer to function 158 198 ... with parameters 159 199 reference to instance of type [unbound] (not function type) 160 200 ... returning nothing 161 201 162 ?{}: pointer to function 202 Variable Expression: ?{}: pointer to function 203 ... with parameters 204 reference to instance of type T (not function type) 205 instance of type T (not function type) 206 ... returning nothing 207 208 ... with resolved type: 209 pointer to function 163 210 ... with parameters 164 211 reference to instance of type [unbound] (not function type) … … 166 213 ... returning nothing 167 214 168 ^?{}: pointer to function 215 Variable Expression: ^?{}: pointer to function 216 ... with parameters 217 reference to instance of type T (not function type) 218 ... returning nothing 219 220 ... with resolved type: 221 pointer to function 169 222 ... with parameters 170 223 reference to instance of type [unbound] (not function type) 171 224 ... returning nothing 172 173 225 174 226 function … … 188 240 void 189 241 ) 190 Environment:([unbound] ) -> instance of type T (not function type) (no widening)242 Environment:([unbound]T) -> instance of type T (not function type) (no widening) 191 243 192 244 Could not satisfy assertion: 193 ?=?: pointer to function245 Variable Expression: ?=?: pointer to function 194 246 ... with parameters 195 reference to instance of type [unbound](not function type)196 instance of type [unbound](not function type)247 reference to instance of type T (not function type) 248 instance of type T (not function type) 197 249 ... returning 198 instance of type [unbound] (not function type) 199 250 instance of type T (not function type) 251 252 ... with resolved type: 253 pointer to function 254 ... with parameters 255 reference to instance of type [unbound] (not function type) 256 instance of type [unbound] (not function type) 257 ... returning 258 instance of type [unbound] (not function type) 259 -
tests/exceptions/.expect/resume-threads.txt
rfeacef9 r5407cdc 6 6 7 7 catch-all 8 9 throwing child exception10 inner parent match11 8 12 9 caught yin as yin -
tests/exceptions/.expect/resume.txt
rfeacef9 r5407cdc 6 6 7 7 catch-all 8 9 throwing child exception10 inner parent match11 8 12 9 caught yin as yin -
tests/exceptions/.expect/terminate-threads.txt
rfeacef9 r5407cdc 5 5 6 6 catch-all 7 8 throwing child exception9 inner parent match10 7 11 8 caught yin as yin -
tests/exceptions/.expect/terminate.txt
rfeacef9 r5407cdc 5 5 6 6 catch-all 7 8 throwing child exception9 inner parent match10 7 11 8 caught yin as yin -
tests/exceptions/cancel/coroutine.cfa
rfeacef9 r5407cdc 4 4 #include <exception.hfa> 5 5 6 TRIVIAL_EXCEPTION(internal_error); 6 EHM_EXCEPTION(internal_error)(); 7 EHM_VIRTUAL_TABLE(internal_error, internal_vt); 7 8 8 9 coroutine WillCancel {}; … … 14 15 void main(WillCancel & wc) { 15 16 printf("1"); 16 cancel_stack((internal_error){ });17 cancel_stack((internal_error){&internal_vt}); 17 18 printf("!"); 18 19 } -
tests/exceptions/cancel/thread.cfa
rfeacef9 r5407cdc 4 4 #include <exception.hfa> 5 5 6 TRIVIAL_EXCEPTION(internal_error); 6 EHM_EXCEPTION(internal_error)(); 7 EHM_VIRTUAL_TABLE(internal_error, internal_vt); 7 8 8 9 thread WillCancel {}; … … 14 15 void main(WillCancel &) { 15 16 printf("1"); 16 cancel_stack((internal_error){ });17 cancel_stack((internal_error){&internal_vt}); 17 18 printf("!"); 18 19 } -
tests/exceptions/conditional.cfa
rfeacef9 r5407cdc 6 6 #include <exception.hfa> 7 7 8 VTABLE_DECLARATION(num_error)(9 int (*code)(num_error *this);8 EHM_EXCEPTION(num_error)( 9 int num; 10 10 ); 11 11 12 struct num_error { 13 VTABLE_FIELD(num_error); 14 char * msg; 15 int num; 16 }; 17 18 const char * num_error_msg(num_error * this) { 19 if ( ! this->msg ) { 20 static const char * base = "Num Error with code: X"; 21 this->msg = (char *)malloc(22); 22 for (int i = 0 ; (this->msg[i] = base[i]) ; ++i); 23 } 24 this->msg[21] = '0' + this->num; 25 return this->msg; 26 } 27 void ?{}(num_error & this, int num) { 28 VTABLE_INIT(this, num_error); 29 this.msg = 0; 30 this.num = num; 31 } 32 void ?{}(num_error & this, num_error & other) { 33 this.virtual_table = other.virtual_table; 34 this.msg = 0; 35 this.num = other.num; 36 } 37 void ^?{}(num_error & this) { 38 if( this.msg ) free( this.msg ); 39 } 40 int num_error_code( num_error * this ) { 41 return this->num; 42 } 43 44 VTABLE_INSTANCE(num_error)( 45 num_error_msg, 46 num_error_code, 47 ); 12 EHM_VIRTUAL_TABLE(num_error, num_error_vt); 48 13 49 14 void caught_num_error(int expect, num_error * actual) { … … 52 17 53 18 int main(int argc, char * argv[]) { 54 num_error exc = 2;19 num_error exc = {&num_error_vt, 2}; 55 20 56 21 try { 57 22 throw exc; 58 } catch (num_error * error ; 3 == error-> virtual_table->code( error )) {23 } catch (num_error * error ; 3 == error->num ) { 59 24 caught_num_error(3, error); 60 } catch (num_error * error ; 2 == error-> virtual_table->code( error )) {25 } catch (num_error * error ; 2 == error->num ) { 61 26 caught_num_error(2, error); 62 27 } … … 64 29 try { 65 30 throwResume exc; 66 } catchResume (num_error * error ; 3 == error-> virtual_table->code( error )) {31 } catchResume (num_error * error ; 3 == error->num ) { 67 32 caught_num_error(3, error); 68 } catchResume (num_error * error ; 2 == error-> virtual_table->code( error )) {33 } catchResume (num_error * error ; 2 == error->num ) { 69 34 caught_num_error(2, error); 70 35 } -
tests/exceptions/data-except.cfa
rfeacef9 r5407cdc 3 3 #include <exception.hfa> 4 4 5 DATA_EXCEPTION(paired)(5 EHM_EXCEPTION(paired)( 6 6 int first; 7 7 int second; 8 8 ); 9 9 10 void ?{}(paired & this, int first, int second) { 11 VTABLE_INIT(this, paired); 12 this.first = first; 13 this.second = second; 14 } 10 EHM_VIRTUAL_TABLE(paired, paired_vt); 15 11 16 const char * paired_msg(paired * this) { 17 return "paired"; 18 } 19 20 VTABLE_INSTANCE(paired)(paired_msg); 21 22 void throwPaired(int first, int second) { 23 paired exc = {first, second}; 12 const char * virtual_msg(paired * this) { 13 return this->virtual_table->msg(this); 24 14 } 25 15 26 16 int main(int argc, char * argv[]) { 27 paired except = { 3, 13};17 paired except = {&paired_vt, 3, 13}; 28 18 29 19 try { 30 20 throw except; 31 21 } catch (paired * exc) { 32 printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);22 printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second); 33 23 ++exc->first; 34 24 } 35 25 36 printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);26 printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second); 37 27 38 28 try { 39 29 throwResume except; 40 30 } catchResume (paired * exc) { 41 printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);31 printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second); 42 32 ++exc->first; 43 33 } 44 34 45 printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);35 printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second); 46 36 } -
tests/exceptions/defaults.cfa
rfeacef9 r5407cdc 4 4 #include <exception.hfa> 5 5 6 DATA_EXCEPTION(log_message)(6 EHM_EXCEPTION(log_message)( 7 7 char * msg; 8 8 ); 9 9 10 void ?{}(log_message & this, char * msg) { 11 VTABLE_INIT(this, log_message); 12 this.msg = msg; 13 } 14 15 const char * get_log_message(log_message * this) { 10 _EHM_DEFINE_COPY(log_message, ) 11 const char * msg(log_message * this) { 16 12 return this->msg; 17 13 } 18 19 VTABLE_INSTANCE(log_message)(get_log_message); 14 _EHM_VIRTUAL_TABLE(log_message, , log_vt); 20 15 21 16 // Logging messages don't have to be handled. … … 28 23 // We can catch log: 29 24 try { 30 throwResume (log_message){ "Should be printed.\n"};25 throwResume (log_message){&log_vt, "Should be printed.\n"}; 31 26 } catchResume (log_message * this) { 32 27 printf("%s", this->virtual_table->msg(this)); 33 28 } 34 29 // But we don't have to: 35 throwResume (log_message){ "Should not be printed.\n"};30 throwResume (log_message){&log_vt, "Should not be printed.\n"}; 36 31 } 37 32 38 33 // I don't have a good use case for doing the same with termination. 39 TRIVIAL_EXCEPTION(jump);34 EHM_EXCEPTION(jump)(); 40 35 void defaultTerminationHandler(jump &) { 41 36 printf("jump default handler.\n"); 42 37 } 43 38 39 EHM_VIRTUAL_TABLE(jump, jump_vt); 40 44 41 void jump_test(void) { 45 42 try { 46 throw (jump){ };43 throw (jump){&jump_vt}; 47 44 } catch (jump * this) { 48 45 printf("jump catch handler.\n"); 49 46 } 50 throw (jump){ };47 throw (jump){&jump_vt}; 51 48 } 52 49 53 TRIVIAL_EXCEPTION(first); 54 TRIVIAL_EXCEPTION(unhandled_exception); 50 EHM_EXCEPTION(first)(); 51 EHM_VIRTUAL_TABLE(first, first_vt); 52 53 EHM_EXCEPTION(unhandled_exception)(); 54 EHM_VIRTUAL_TABLE(unhandled_exception, unhandled_vt); 55 55 56 56 void unhandled_test(void) { 57 57 forall(T &, V & | is_exception(T, V)) 58 58 void defaultTerminationHandler(T &) { 59 throw (unhandled_exception){ };59 throw (unhandled_exception){&unhandled_vt}; 60 60 } 61 61 void defaultTerminationHandler(unhandled_exception &) { … … 63 63 } 64 64 try { 65 throw (first){ };65 throw (first){&first_vt}; 66 66 } catch (unhandled_exception * t) { 67 67 printf("Catch unhandled_exception.\n"); … … 69 69 } 70 70 71 TRIVIAL_EXCEPTION(second); 71 EHM_EXCEPTION(second)(); 72 EHM_VIRTUAL_TABLE(second, second_vt); 72 73 73 74 void cross_test(void) { 74 75 void defaultTerminationHandler(first &) { 75 76 printf("cross terminate default\n"); 76 throw (second){ };77 throw (second){&second_vt}; 77 78 } 78 79 void defaultResumptionHandler(first &) { 79 80 printf("cross resume default\n"); 80 throwResume (second){ };81 throwResume (second){&second_vt}; 81 82 } 82 83 try { 83 84 printf("cross terminate throw\n"); 84 throw (first){ };85 throw (first){&first_vt}; 85 86 } catch (second *) { 86 87 printf("cross terminate catch\n"); … … 88 89 try { 89 90 printf("cross resume throw\n"); 90 throwResume (first){ };91 throwResume (first){&first_vt}; 91 92 } catchResume (second *) { 92 93 printf("cross resume catch\n"); -
tests/exceptions/finally.cfa
rfeacef9 r5407cdc 4 4 #include "except-io.hfa" 5 5 6 TRIVIAL_EXCEPTION(myth); 6 EHM_EXCEPTION(myth)(); 7 8 EHM_VIRTUAL_TABLE(myth, myth_vt); 7 9 8 10 int main(int argc, char * argv[]) { 9 myth exc ;11 myth exc = {&myth_vt}; 10 12 11 13 try { -
tests/exceptions/interact.cfa
rfeacef9 r5407cdc 4 4 #include "except-io.hfa" 5 5 6 TRIVIAL_EXCEPTION(star); 7 TRIVIAL_EXCEPTION(moon); 6 EHM_EXCEPTION(star)(); 7 EHM_EXCEPTION(moon)(); 8 9 EHM_VIRTUAL_TABLE(star, star_vt); 10 EHM_VIRTUAL_TABLE(moon, moon_vt); 8 11 9 12 int main(int argc, char * argv[]) { 10 13 // Resume falls back to terminate. 11 14 try { 12 throwResume (star){ };15 throwResume (star){&star_vt}; 13 16 } catch (star *) { 14 17 printf("caught as termination\n"); … … 17 20 try { 18 21 loud_region a = "try block with resume throw"; 19 throwResume (star){ };22 throwResume (star){&star_vt}; 20 23 } catch (star *) { 21 24 printf("caught as termination\n"); … … 29 32 try { 30 33 try { 31 throw (star){ };34 throw (star){&star_vt}; 32 35 } catchResume (star *) { 33 36 printf("resume catch on terminate\n"); … … 43 46 try { 44 47 try { 45 throwResume (star){ };48 throwResume (star){&star_vt}; 46 49 } catch (star *) { 47 50 printf("terminate catch on resume\n"); … … 58 61 try { 59 62 try { 60 throw (star){ };63 throw (star){&star_vt}; 61 64 } catchResume (star *) { 62 65 printf("inner resume catch (error)\n"); … … 75 78 try { 76 79 try { 77 throwResume (star){ };80 throwResume (star){&star_vt}; 78 81 } catch (star *) { 79 82 printf("inner termination catch\n"); … … 94 97 try { 95 98 printf("throwing resume moon\n"); 96 throwResume (moon){ };99 throwResume (moon){&moon_vt}; 97 100 } catch (star *) { 98 101 printf("termination catch\n"); 99 102 } 100 103 printf("throwing resume star\n"); 101 throwResume (star){ };104 throwResume (star){&star_vt}; 102 105 } catchResume (star *) { 103 106 printf("resumption star catch\n"); … … 105 108 } catchResume (moon *) { 106 109 printf("resumption moon catch, will terminate\n"); 107 throw (star){ };110 throw (star){&star_vt}; 108 111 } 109 112 } catchResume (star *) { -
tests/exceptions/polymorphic.cfa
rfeacef9 r5407cdc 3 3 #include <exception.hfa> 4 4 5 FORALL_TRIVIAL_EXCEPTION(proxy, (T), (T)); 6 FORALL_TRIVIAL_INSTANCE(proxy, (U), (U)) 5 EHM_FORALL_EXCEPTION(proxy, (T&), (T))(); 7 6 8 const char * msg(proxy(int) * this) { return "proxy(int)"; } 9 const char * msg(proxy(char) * this) { return "proxy(char)"; } 10 POLY_VTABLE_INSTANCE(proxy, int)(msg); 11 POLY_VTABLE_INSTANCE(proxy, char)(msg); 7 EHM_FORALL_VIRTUAL_TABLE(proxy, (int), proxy_int); 8 EHM_FORALL_VIRTUAL_TABLE(proxy, (char), proxy_char); 12 9 13 10 void proxy_test(void) { 11 proxy(int) an_int = {&proxy_int}; 12 proxy(char) a_char = {&proxy_char}; 13 14 14 try { 15 throw (proxy(int)){};15 throw an_int; 16 16 } catch (proxy(int) *) { 17 17 printf("terminate catch\n"); … … 19 19 20 20 try { 21 throwResume (proxy(char)){};21 throwResume a_char; 22 22 } catchResume (proxy(char) *) { 23 23 printf("resume catch\n"); … … 25 25 26 26 try { 27 throw (proxy(char)){};27 throw a_char; 28 28 } catch (proxy(int) *) { 29 29 printf("caught proxy(int)\n"); … … 33 33 } 34 34 35 FORALL_DATA_EXCEPTION(cell, (T), (T))(35 EHM_FORALL_EXCEPTION(cell, (T), (T))( 36 36 T data; 37 37 ); 38 38 39 FORALL_DATA_INSTANCE(cell, (T), (T)) 40 41 const char * msg(cell(int) * this) { return "cell(int)"; } 42 const char * msg(cell(char) * this) { return "cell(char)"; } 43 const char * msg(cell(bool) * this) { return "cell(bool)"; } 44 POLY_VTABLE_INSTANCE(cell, int)(msg); 45 POLY_VTABLE_INSTANCE(cell, char)(msg); 46 POLY_VTABLE_INSTANCE(cell, bool)(msg); 39 EHM_FORALL_VIRTUAL_TABLE(cell, (int), int_cell); 40 EHM_FORALL_VIRTUAL_TABLE(cell, (char), char_cell); 41 EHM_FORALL_VIRTUAL_TABLE(cell, (bool), bool_cell); 47 42 48 43 void cell_test(void) { 49 44 try { 50 cell(int) except; 51 except.data = -7; 45 cell(int) except = {&int_cell, -7}; 52 46 throw except; 53 47 } catch (cell(int) * error) { … … 56 50 57 51 try { 58 cell(bool) ball; 59 ball.data = false; 52 cell(bool) ball = {&bool_cell, false}; 60 53 throwResume ball; 61 54 printf("%i\n", ball.data); -
tests/exceptions/resume.cfa
rfeacef9 r5407cdc 4 4 #include "except-io.hfa" 5 5 6 TRIVIAL_EXCEPTION(yin); 7 TRIVIAL_EXCEPTION(yang); 8 TRIVIAL_EXCEPTION(zen); 9 TRIVIAL_EXCEPTION(moment_of, zen); 6 EHM_EXCEPTION(yin)(); 7 EHM_EXCEPTION(yang)(); 8 EHM_EXCEPTION(zen)(); 9 10 EHM_VIRTUAL_TABLE(yin, yin_vt); 11 EHM_VIRTUAL_TABLE(yang, yang_vt); 12 EHM_VIRTUAL_TABLE(zen, zen_vt); 10 13 11 14 void in_void(void); 12 15 13 16 int main(int argc, char * argv[]) { 17 yin a_yin = {&yin_vt}; 18 yang a_yang = {&yang_vt}; 19 zen a_zen = {&zen_vt}; 20 14 21 // The simple throw catchResume test. 15 22 try { 16 23 loud_exit a = "simple try clause"; 17 24 printf("simple throw\n"); 18 throwResume (zen){};25 throwResume a_zen; 19 26 printf("end of try clause\n"); 20 27 } catchResume (zen * error) { … … 26 33 // Throw catch-all test. 27 34 try { 28 throwResume (zen){};35 throwResume a_zen; 29 36 } catchResume (exception_t * error) { 30 37 printf("catch-all\n"); 31 }32 printf("\n");33 34 // Catch a parent of the given exception.35 try {36 printf("throwing child exception\n");37 throwResume (moment_of){};38 } catchResume (zen *) {39 printf("inner parent match\n");40 } catchResume (moment_of *) {41 printf("outer exact match\n");42 38 } 43 39 printf("\n"); … … 46 42 try { 47 43 try { 48 throwResume (yin){};44 throwResume a_yin; 49 45 } catchResume (zen *) { 50 46 printf("caught yin as zen\n"); … … 62 58 loud_exit a = "rethrow inner try"; 63 59 printf("rethrow inner try\n"); 64 throwResume (zen){};60 throwResume a_zen; 65 61 } catchResume (zen *) { 66 62 loud_exit a = "rethrowing catch clause"; … … 77 73 try { 78 74 try { 79 throwResume (yin){};75 throwResume a_yin; 80 76 } catchResume (yin *) { 81 77 printf("caught yin, will throw yang\n"); 82 throwResume (yang){};78 throwResume a_yang; 83 79 } catchResume (yang *) { 84 80 printf("caught exception from same try\n"); … … 93 89 try { 94 90 printf("throwing first exception\n"); 95 throwResume (yin){};91 throwResume a_yin; 96 92 } catchResume (yin *) { 97 93 printf("caught first exception\n"); 98 94 try { 99 95 printf("throwing second exception\n"); 100 throwResume (yang){};96 throwResume a_yang; 101 97 } catchResume (yang *) { 102 98 printf("caught second exception\n"); … … 114 110 try { 115 111 try { 116 throwResume (zen){};117 throwResume (zen){};112 throwResume a_zen; 113 throwResume a_zen; 118 114 } catchResume (zen *) { 119 115 printf("inner catch\n"); 120 116 } 121 throwResume (zen){};117 throwResume a_zen; 122 118 } catchResume (zen *) { 123 119 printf("outer catch\n"); … … 130 126 // Do a throw and rethrow in a void function. 131 127 void in_void(void) { 128 zen a_zen = {&zen_vt}; 132 129 try { 133 130 try { 134 131 printf("throw\n"); 135 throwResume (zen){};132 throwResume a_zen; 136 133 } catchResume (zen *) { 137 134 printf("rethrow\n"); -
tests/exceptions/terminate.cfa
rfeacef9 r5407cdc 4 4 #include "except-io.hfa" 5 5 6 TRIVIAL_EXCEPTION(yin); 7 TRIVIAL_EXCEPTION(yang); 8 TRIVIAL_EXCEPTION(zen); 9 TRIVIAL_EXCEPTION(moment_of, zen); 6 EHM_EXCEPTION(yin)(); 7 EHM_EXCEPTION(yang)(); 8 EHM_EXCEPTION(zen)(); 9 10 EHM_VIRTUAL_TABLE(yin, yin_vt); 11 EHM_VIRTUAL_TABLE(yang, yang_vt); 12 EHM_VIRTUAL_TABLE(zen, zen_vt); 10 13 11 14 void in_void(void); 12 15 13 16 int main(int argc, char * argv[]) { 17 yin a_yin = {&yin_vt}; 18 yang a_yang = {&yang_vt}; 19 zen a_zen = {&zen_vt}; 20 14 21 // The simple throw catch test. 15 22 try { 16 23 loud_exit a = "simple try clause"; 17 24 printf("simple throw\n"); 18 throw (zen){};25 throw a_zen; 19 26 printf("end of try clause\n"); 20 27 } catch (zen * error) { … … 26 33 // Throw catch-all test. 27 34 try { 28 throw (zen){};35 throw a_zen; 29 36 } catch (exception_t * error) { 30 37 printf("catch-all\n"); 31 }32 printf("\n");33 34 // Catch a parent of the given exception.35 try {36 printf("throwing child exception\n");37 throw (moment_of){};38 } catch (zen *) {39 printf("inner parent match\n");40 } catch (moment_of *) {41 printf("outer exact match\n");42 38 } 43 39 printf("\n"); … … 46 42 try { 47 43 try { 48 throw (yin){};44 throw a_yin; 49 45 } catch (zen *) { 50 46 printf("caught yin as zen\n"); … … 62 58 loud_exit a = "rethrow inner try"; 63 59 printf("rethrow inner try\n"); 64 throw (zen){};60 throw a_zen; 65 61 } catch (zen *) { 66 62 loud_exit a = "rethrowing catch clause"; … … 77 73 try { 78 74 try { 79 throw (yin){};75 throw a_yin; 80 76 } catch (yin *) { 81 77 printf("caught yin, will throw yang\n"); 82 throw (yang){};78 throw a_yang; 83 79 } catch (yang *) { 84 80 printf("caught exception from same try\n"); … … 93 89 try { 94 90 printf("throwing first exception\n"); 95 throw (yin){};91 throw a_yin; 96 92 } catch (yin *) { 97 93 printf("caught first exception\n"); 98 94 try { 99 95 printf("throwing second exception\n"); 100 throw (yang){};96 throw a_yang; 101 97 } catch (yang *) { 102 98 printf("caught second exception\n"); … … 114 110 try { 115 111 try { 116 throw (zen){};117 throw (zen){};112 throw a_zen; 113 throw a_zen; 118 114 } catch (zen *) { 119 115 printf("inner catch\n"); 120 116 } 121 throw (zen){};117 throw a_zen; 122 118 } catch (zen *) { 123 119 printf("outer catch\n"); … … 130 126 // Do a throw and rethrow in a void function. 131 127 void in_void(void) { 128 zen a_zen = {&zen_vt}; 132 129 try { 133 130 try { 134 131 printf("throw\n"); 135 throw (zen){};132 throw a_zen; 136 133 } catch (zen *) { 137 134 printf("rethrow\n"); -
tests/exceptions/trash.cfa
rfeacef9 r5407cdc 3 3 #include <exception.hfa> 4 4 5 TRIVIAL_EXCEPTION(yin); 6 TRIVIAL_EXCEPTION(yang); 5 EHM_EXCEPTION(yin)(); 6 EHM_EXCEPTION(yang)(); 7 8 EHM_VIRTUAL_TABLE(yin, yin_vt); 9 EHM_VIRTUAL_TABLE(yang, yang_vt); 7 10 8 11 int main(int argc, char * argv[]) { 9 12 try { 10 13 try { 11 throw (yin){ };14 throw (yin){&yin_vt}; 12 15 } finally { 13 16 try { 14 throw (yang){ };17 throw (yang){&yang_vt}; 15 18 } catch (yin *) { 16 19 printf("inner yin\n"); -
tests/exceptions/type-check.cfa
rfeacef9 r5407cdc 3 3 #include <exception.hfa> 4 4 5 TRIVIAL_EXCEPTION(truth);5 EHM_EXCEPTION(truth)(); 6 6 7 7 int main(int argc, char * argv[]) { -
tests/exceptions/virtual-cast.cfa
rfeacef9 r5407cdc 12 12 #include <assert.h> 13 13 14 15 16 // Hand defined alpha virtual type: 17 struct __cfatid_struct_alpha { 18 __cfa__parent_vtable const * parent; 19 }; 20 21 __attribute__(( section(".gnu.linkonce.__cfatid_alpha") )) 22 struct __cfatid_struct_alpha __cfatid_alpha = { 23 (__cfa__parent_vtable *)0, 24 }; 25 14 26 struct alpha_vtable { 15 alpha_vtable const * const parent;27 struct __cfatid_struct_alpha const * const __cfavir_typeid; 16 28 char (*code)(void); 17 29 }; … … 27 39 28 40 41 // Hand defined beta virtual type: 42 struct __cfatid_struct_beta { 43 __cfatid_struct_alpha const * parent; 44 }; 45 46 __attribute__(( section(".gnu.linkonce.__cfatid_beta") )) 47 struct __cfatid_struct_beta __cfatid_beta = { 48 &__cfatid_alpha, 49 }; 50 29 51 struct beta_vtable { 30 alpha_vtable const * const parent;52 struct __cfatid_struct_beta const * const __cfavir_typeid; 31 53 char (*code)(void); 32 54 }; … … 42 64 43 65 66 // Hand defined gamma virtual type: 67 struct __cfatid_struct_gamma { 68 __cfatid_struct_beta const * parent; 69 }; 70 71 __attribute__(( section(".gnu.linkonce.__cfatid_gamma") )) 72 struct __cfatid_struct_gamma __cfatid_gamma = { 73 &__cfatid_beta, 74 }; 75 44 76 struct gamma_vtable { 45 beta_vtable const * const parent;77 struct __cfatid_struct_gamma const * const __cfavir_typeid; 46 78 char (*code)(void); 47 79 }; … … 57 89 58 90 extern "C" { 59 alpha_vtable _alpha_vtable_instance = { 0, ret_a };60 beta_vtable _beta_vtable_instance = { &_ alpha_vtable_instance, ret_b };61 gamma_vtable _gamma_vtable_instance = { &_ beta_vtable_instance, ret_g };91 alpha_vtable _alpha_vtable_instance = { &__cfatid_alpha, ret_a }; 92 beta_vtable _beta_vtable_instance = { &__cfatid_beta, ret_b }; 93 gamma_vtable _gamma_vtable_instance = { &__cfatid_gamma, ret_g }; 62 94 } 63 95 -
tests/exceptions/virtual-poly.cfa
rfeacef9 r5407cdc 8 8 #include <assert.h> 9 9 10 11 struct __cfatid_struct_mono_base { 12 __cfa__parent_vtable const * parent; 13 }; 14 15 __attribute__(( section(".gnu.linkonce.__cfatid_mono_base") )) 16 struct __cfatid_struct_mono_base __cfatid_mono_base = { 17 (__cfa__parent_vtable *)0, 18 }; 19 10 20 struct mono_base_vtable { 11 mono_base_vtable const * const parent;21 __cfatid_struct_mono_base const * const __cfavir_typeid; 12 22 }; 13 23 … … 17 27 18 28 forall(T) 29 struct __cfatid_struct_mono_child { 30 __cfatid_struct_mono_base const * parent; 31 }; 32 33 forall(T) 19 34 struct mono_child_vtable { 20 mono_base_vtable const * const parent;35 __cfatid_struct_mono_child(T) const * const __cfavir_typeid; 21 36 }; 22 37 … … 26 41 }; 27 42 28 mono_base_vtable _mono_base_vtable_instance @= { 0 }; 43 __cfatid_struct_mono_child(int) __cfatid_mono_child @= { 44 &__cfatid_mono_base, 45 }; 46 29 47 mono_child_vtable(int) _mono_child_vtable_instance @= { 30 &_ mono_base_vtable_instance48 &__cfatid_mono_child, 31 49 }; 32 50 … … 37 55 } 38 56 57 58 forall(U) 59 struct __cfatid_struct_poly_base { 60 __cfa__parent_vtable const * parent; 61 }; 62 39 63 forall(U) 40 64 struct poly_base_vtable { 41 poly_base_vtable(U) const * const parent;65 __cfatid_struct_poly_base(U) const * const __cfavir_typeid; 42 66 }; 43 67 … … 48 72 49 73 forall(V) 74 struct __cfatid_struct_poly_child { 75 __cfatid_struct_poly_base(V) const * parent; 76 }; 77 78 forall(V) 50 79 struct poly_child_vtable { 51 poly_base_vtable(V) const * const parent;80 __cfatid_struct_poly_child(V) const * const __cfavir_typeid; 52 81 }; 53 82 … … 57 86 }; 58 87 59 poly_base_vtable(int) _poly_base_vtable_instance @= { 0 }; 88 __cfatid_struct_poly_base(int) __cfatid_poly_base @= { 89 (__cfa__parent_vtable *)0, 90 }; 91 __cfatid_struct_poly_child(int) __cfatid_poly_child = { 92 &__cfatid_poly_base, 93 }; 60 94 poly_child_vtable(int) _poly_child_vtable_instance @= { 61 &_ poly_base_vtable_instance95 &__cfatid_poly_child, 62 96 }; 63 /* Resolver bug keeps me from adding these.64 poly_base_vtable(char) _poly_base_vtable_instance @= { 0 };65 poly_child_vtable(char) _poly_child_vtable_instance @= {66 &_poly_base_vtable_instance67 };68 */69 97 70 98 void poly_poly_test() { … … 77 105 mono_poly_test(); 78 106 poly_poly_test(); 79 printf( "done\n" ); // non-empty .expect file107 printf( "done\n" ); 80 108 } -
tests/linking/exception-nothreads.cfa
rfeacef9 r5407cdc 17 17 #include <exception.hfa> 18 18 19 TRIVIAL_EXCEPTION(ping); 19 EHM_EXCEPTION(ping)(); 20 EHM_VIRTUAL_TABLE(ping, ping_vt); 20 21 21 22 int main(void) { 22 23 try { 23 throwResume (ping){ };24 throwResume (ping){&ping_vt}; 24 25 } catchResume (ping *) { 25 26 printf("%s threads\n", threading_enabled() ? "with" : "no"); -
tests/linking/exception-withthreads.cfa
rfeacef9 r5407cdc 18 18 #include "../exceptions/with-threads.hfa" 19 19 20 TRIVIAL_EXCEPTION(ping); 20 EHM_EXCEPTION(ping)(); 21 EHM_VIRTUAL_TABLE(ping, ping_vt); 21 22 22 23 int main(void) { 23 24 try { 24 throwResume (ping){ };25 throwResume (ping){&ping_vt}; 25 26 } catchResume (ping *) { 26 27 printf("%s threads\n", threading_enabled() ? "with" : "no"); -
tests/linking/weakso_nothd.cfa
rfeacef9 r5407cdc 6 6 // 7 7 // weakso_nothd.cfa -- 8 // test whether or not usin da weakso locks pulls in threads8 // test whether or not using a weakso locks pulls in threads 9 9 // 10 10 // Author : Thierry Delisle -
tests/meta/.expect/archVast.nast.arm64.txt
rfeacef9 r5407cdc 7 7 char Alternatives are: 8 8 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of: 9 Variable Expression: FA64: signed int9 Variable Expression: FA64: double 10 10 ... with resolved type: 11 signed int11 double 12 12 ... to: 13 13 char … … 39 39 40 40 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of: 41 Variable Expression: FA64: double41 Variable Expression: FA64: signed int 42 42 ... with resolved type: 43 double43 signed int 44 44 ... to: 45 45 char -
tests/time.cfa
rfeacef9 r5407cdc 10 10 // Created On : Tue Mar 27 17:24:56 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jun 18 18:14:49 202013 // Update Count : 3 712 // Last Modified On : Fri Apr 16 14:59:53 2021 13 // Update Count : 38 14 14 // 15 15 … … 53 53 // | "Newfoundland" | getTime( Newfoundland ) 54 54 // | "local" | getTime() 55 // | "local nsec" | getTimeNsec()55 // | "local nsec" | timeHiRes() 56 56 // | "PST" | PST(); // getTime short form 57 57 // sout | nl; -
tests/unified_locking/.expect/locks.txt
rfeacef9 r5407cdc 11 11 Start Test 6: owner lock and condition variable 3 wait/notify all 12 12 Done Test 6 13 Start Test 7: multi acquisiton lock and condition variable multiple acquire andwait/notify13 Start Test 7: fast lock and condition variable single wait/notify 14 14 Done Test 7 15 Start Test 8: owner lock and condition variable multiple acquire and wait/notify15 Start Test 8: fast lock and condition variable 3 wait/notify all 16 16 Done Test 8 17 Start Test 9: no lock condition variablewait/notify17 Start Test 9: multi acquisiton lock and condition variable multiple acquire and wait/notify 18 18 Done Test 9 19 Start Test 10: locked condition variable wait/notify with front()19 Start Test 10: owner lock and condition variable multiple acquire and wait/notify 20 20 Done Test 10 21 Start Test 11: no lock condition variable wait/notify 22 Done Test 11 23 Start Test 12: locked condition variable wait/notify with front() 24 Done Test 12 -
tests/unified_locking/locks.cfa
rfeacef9 r5407cdc 15 15 condition_variable( owner_lock ) c_o; 16 16 17 fast_lock f; 18 condition_variable( fast_lock ) c_f; 19 17 20 thread T_C_M_WS1 {}; 18 21 … … 68 71 } 69 72 unlock(s); 73 } 74 } 75 76 thread T_C_F_WS1 {}; 77 78 void main( T_C_F_WS1 & this ) { 79 for (unsigned int i = 0; i < num_times; i++) { 80 lock(f); 81 if(empty(c_f) && i != num_times - 1) { 82 wait(c_f,f); 83 }else{ 84 notify_one(c_f); 85 } 86 unlock(f); 87 } 88 } 89 90 thread T_C_F_WB1 {}; 91 92 void main( T_C_F_WB1 & this ) { 93 for (unsigned int i = 0; i < num_times; i++) { 94 lock(f); 95 if(counter(c_f) == 3 || i == num_times - 1) { 96 notify_all(c_f); 97 }else{ 98 wait(c_f,f); 99 } 100 unlock(f); 70 101 } 71 102 } … … 255 286 printf("Done Test 6\n"); 256 287 257 printf("Start Test 7: multi acquisiton lock and condition variable multiple acquire and wait/notify\n"); 288 printf("Start Test 7: fast lock and condition variable single wait/notify\n"); 289 { 290 T_C_F_WS1 t1[2]; 291 } 292 printf("Done Test 7\n"); 293 294 printf("Start Test 8: fast lock and condition variable 3 wait/notify all\n"); 295 { 296 T_C_F_WB1 t1[4]; 297 } 298 printf("Done Test 8\n"); 299 300 printf("Start Test 9: multi acquisiton lock and condition variable multiple acquire and wait/notify\n"); 258 301 { 259 302 T_C_M_WS2 t1[2]; 260 303 } 261 printf("Done Test 7\n");262 263 printf("Start Test 8: owner lock and condition variable multiple acquire and wait/notify\n");304 printf("Done Test 9\n"); 305 306 printf("Start Test 10: owner lock and condition variable multiple acquire and wait/notify\n"); 264 307 { 265 308 T_C_O_WS2 t1[2]; 266 309 } 267 printf("Done Test 8\n");268 269 printf("Start Test 9: no lock condition variable wait/notify\n");310 printf("Done Test 10\n"); 311 312 printf("Start Test 11: no lock condition variable wait/notify\n"); 270 313 { 271 314 T_C_NLW t1; 272 315 T_C_NLS t2; 273 316 } 274 printf("Done Test 9\n");275 276 printf("Start Test 1 0: locked condition variable wait/notify with front()\n");317 printf("Done Test 11\n"); 318 319 printf("Start Test 12: locked condition variable wait/notify with front()\n"); 277 320 { 278 321 T_C_S_WNF t1[2]; 279 322 } 280 printf("Done Test 1 0\n");323 printf("Done Test 12\n"); 281 324 282 325 // removed to limit test duration. Full test is in long run tests -
tests/vector_math/.expect/vec4_float.txt
rfeacef9 r5407cdc 6 6 zero-assign:<0.,0.,0.,0.> 7 7 fill-ctor:<1.23,1.23,1.23,1.23> 8 ?-?:<0.02,0.43,-0.999998,-1e-06 .>9 ?-=?:<0.02,0.43,-0.999998,-1e-06 .>10 -?:<-0.02,-0.43,0.999998,1e-06 .>8 ?-?:<0.02,0.43,-0.999998,-1e-06> 9 ?-=?:<0.02,0.43,-0.999998,-1e-06> 10 -?:<-0.02,-0.43,0.999998,1e-06> 11 11 ?+?:<2.3,2.45,-9.2,-12.5> 12 12 ?+=?:<2.3,2.45,-9.2,-12.5> -
tools/gdb/utils-gdb.py
rfeacef9 r5407cdc 23 23 gdb.execute('handle SIGUSR1 nostop noprint pass') 24 24 25 CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state ')25 CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state yield_state') 26 26 27 27 class ThreadInfo: … … 52 52 # GDB types for various structures/types in CFA 53 53 return CfaTypes(cluster_ptr = gdb.lookup_type('struct cluster').pointer(), 54 processor_ptr = gdb.lookup_type('struct processor').pointer(), 55 thread_ptr = gdb.lookup_type('struct $thread').pointer(), 56 int_ptr = gdb.lookup_type('int').pointer(), 57 thread_state = gdb.lookup_type('enum __Coroutine_State')) 54 processor_ptr = gdb.lookup_type('struct processor').pointer(), 55 thread_ptr = gdb.lookup_type('struct $thread').pointer(), 56 int_ptr = gdb.lookup_type('int').pointer(), 57 thread_state = gdb.lookup_type('enum __Coroutine_State'), 58 yield_state = gdb.lookup_type('enum __Preemption_Reason')) 58 59 59 60 def get_addr(addr): … … 371 372 def print_thread(self, thread, tid, marked): 372 373 cfa_t = get_cfa_types() 373 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread)) 374 ys = str(thread['preempted'].cast(cfa_t.yield_state)) 375 if ys == '_X15__NO_PREEMPTIONKM19__Preemption_Reason_1': 376 state = str(thread['state'].cast(cfa_t.thread_state)) 377 elif ys == '_X18__ALARM_PREEMPTIONKM19__Preemption_Reason_1': 378 state = 'preempted' 379 elif ys == '_X19__MANUAL_PREEMPTIONKM19__Preemption_Reason_1': 380 state = 'yield' 381 elif ys == '_X17__POLL_PREEMPTIONKM19__Preemption_Reason_1': 382 state = 'poll' 383 else: 384 print("error: thread {} in undefined preemption state {}".format(thread, ys)) 385 state = 'error' 386 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), state, str(thread)) 374 387 375 388 def print_threads_by_cluster(self, cluster, print_system = False): … … 480 493 context = thread['context'] 481 494 495 496 497 # must be at frame 0 to set pc register 498 gdb.execute('select-frame 0') 499 if gdb.selected_frame().architecture().name() != 'i386:x86-64': 500 print('gdb debugging only supported for i386:x86-64 for now') 501 return 502 503 # gdb seems to handle things much better if we pretend we just entered the context switch 504 # pretend the pc is __cfactx_switch and adjust the sp, base pointer doesn't need to change 482 505 # lookup for sp,fp and uSwitch 483 xsp = context['SP'] + 4 8506 xsp = context['SP'] + 40 # 40 = 5 64bit registers : %r15, %r14, %r13, %r12, %rbx WARNING: x64 specific 484 507 xfp = context['FP'] 485 508 486 509 # convert string so we can strip out the address 487 510 try: 488 xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address + 28)511 xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address) 489 512 except: 490 513 print("here") 491 514 return 492 493 # must be at frame 0 to set pc register494 gdb.execute('select-frame 0')495 515 496 516 # push sp, fp, pc into a global stack … … 503 523 504 524 # update registers for new task 505 print('switching to ') 525 # print('switching to {} ({}) : [{}, {}, {}]'.format(thread['self_cor']['name'].string(), str(thread), str(xsp), str(xfp), str(xpc))) 526 print('switching to thread {} ({})'.format(str(thread), thread['self_cor']['name'].string())) 506 527 gdb.execute('set $rsp={}'.format(xsp)) 507 528 gdb.execute('set $rbp={}'.format(xfp)) … … 552 573 553 574 argv = parse(arg) 554 print(argv)555 575 if argv[0].isdigit(): 556 576 cname = " ".join(argv[1:]) if len(argv) > 1 else None
Note:
See TracChangeset
for help on using the changeset viewer.