Changes in / [6091b88a:d45ed83]
- Files:
-
- 1 added
- 11 edited
-
benchmark/io/readv.cfa (modified) (6 diffs)
-
examples/io/simple/server.cfa (modified) (5 diffs)
-
libcfa/prelude/defines.hfa.in (modified) (1 diff)
-
libcfa/src/bits/locks.hfa (modified) (2 diffs)
-
libcfa/src/bits/signal.hfa (modified) (1 diff)
-
libcfa/src/concurrency/io.cfa (modified) (12 diffs)
-
libcfa/src/concurrency/iofwd.hfa (added)
-
libcfa/src/concurrency/kernel.cfa (modified) (23 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (7 diffs)
-
libcfa/src/concurrency/kernel_private.hfa (modified) (1 diff)
-
libcfa/src/concurrency/preemption.cfa (modified) (4 diffs)
-
tools/gdb/utils-gdb.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
benchmark/io/readv.cfa
r6091b88a rd45ed83 17 17 #include <time.hfa> 18 18 19 #if !defined(HAVE_LINUX_IO_URING_H) 20 #warning no io uring 21 #endif 22 19 23 extern bool traceHeapOn(); 20 extern ssize_t async_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);24 extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags); 21 25 22 26 int fd; … … 26 30 unsigned long int buflen = 50; 27 31 32 cluster * the_cluster; 33 28 34 thread Reader {}; 35 void ?{}( Reader & this ) { 36 ((thread&)this){ "Reader Thread", *the_cluster }; 37 } 38 39 struct my_processor { 40 processor p; 41 }; 42 43 void ?{}( my_processor & this ) { 44 (this.p){ "I/O Processor", *the_cluster }; 45 } 46 29 47 void main( Reader & ) { 30 48 while(!__atomic_load_n(&run, __ATOMIC_RELAXED)) yield(); … … 34 52 35 53 while(__atomic_load_n(&run, __ATOMIC_RELAXED)) { 36 async_preadv2(fd, &iov, 1, 0, 0); 54 int r = cfa_preadv2(fd, &iov, 1, 0, 0); 55 if(r < 0) abort(strerror(-r)); 56 37 57 __atomic_fetch_add( &count, 1, __ATOMIC_SEQ_CST ); 38 58 } … … 46 66 printf("Setting local\n"); 47 67 setlocale(LC_NUMERIC, ""); 48 49 68 50 69 arg_loop: … … 110 129 } 111 130 112 intfd = open(__FILE__, 0);131 fd = open(__FILE__, 0); 113 132 if(fd < 0) { 114 133 fprintf(stderr, "Could not open source file\n"); … … 118 137 printf("Running %lu threads over %lu processors for %lf seconds\n", nthreads, nprocs, duration); 119 138 120 Time start, end;121 139 { 122 processor procs[nprocs - 1]; 140 Time start, end; 141 cluster cl = { "IO Cluster" }; 142 the_cluster = &cl; 143 #if !defined(__CFA_NO_STATISTICS__) 144 print_stats_at_exit( cl ); 145 #endif 123 146 { 124 Reader threads[nthreads]; 147 my_processor procs[nprocs]; 148 { 149 Reader threads[nthreads]; 125 150 126 printf("Starting\n"); 127 start = getTime(); 128 run = true; 129 do { 130 sleep(500`ms); 151 printf("Starting\n"); 152 start = getTime(); 153 run = true; 154 do { 155 sleep(500`ms); 156 end = getTime(); 157 } while( (end - start) < duration`s ); 158 run = false; 131 159 end = getTime(); 132 } while( (end - start) < duration`s ); 133 run = false; 134 end = getTime(); 160 printf("Done\n"); 161 } 135 162 } 163 printf("Took %ld ms\n", (end - start)`ms); 164 printf("Total reads: %'zu\n", count); 165 printf("Reads per second: %'lf\n", ((double)count) / (end - start)`s); 136 166 } 137 printf("Took %ld ms\n", (end - start)`ms);138 printf("Total reads: %'zu\n", count);139 printf("Reads per second: %'lf\n", ((double)count) / (end - start)`s);140 167 141 168 close(fd); 142 printf("Done\n");143 169 } -
examples/io/simple/server.cfa
r6091b88a rd45ed83 51 51 52 52 //---------- 53 extern ssize_t async_recvmsg(int sockfd, struct msghdr *msg, int flags);54 extern int async_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);55 extern int async_close(int fd);53 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags); 54 extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); 55 extern int cfa_close(int fd); 56 56 57 57 //---------- … … 88 88 struct sockaddr_in cli_addr; 89 89 __socklen_t clilen = sizeof(cli_addr); 90 int newsock = async_accept4(sock, (struct sockaddr *) &cli_addr, &clilen, 0);90 int newsock = cfa_accept4(sock, (struct sockaddr *) &cli_addr, &clilen, 0); 91 91 if (newsock < 0) { 92 92 error( printer, "accept", -newsock); … … 97 97 98 98 while(1) { 99 int res = async_recvmsg(newsock, &msg, 0);99 int res = cfa_recvmsg(newsock, &msg, 0); 100 100 if(res == 0) break; 101 101 if(res < 0) { … … 107 107 } 108 108 109 ret = async_close(newsock);109 ret = cfa_close(newsock); 110 110 if(ret < 0) { 111 111 error( printer, "close new", -ret); … … 113 113 } 114 114 115 ret = async_close(sock);115 ret = cfa_close(sock); 116 116 if(ret < 0) { 117 117 error( printer, "close old", -ret); -
libcfa/prelude/defines.hfa.in
r6091b88a rd45ed83 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo 3 // 4 // The contents of this file are covered under the licence agreement in the 5 // file "LICENCE" distributed with Cforall. 6 // 7 // defines.hfa.in -- 8 // 9 // Author : Thierry Delisle 10 // Created On : Thu Apr 30 15:23:00 2020 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 14 // 1 15 2 16 #undef HAVE_LINUX_IO_URING_H 17 18 // #define __CFA_IO_POLLING_USER__ 19 // #define __CFA_IO_POLLING_KERNEL__ -
libcfa/src/bits/locks.hfa
r6091b88a rd45ed83 113 113 114 114 struct __bin_sem_t { 115 bool signaled;116 115 pthread_mutex_t lock; 117 116 pthread_cond_t cond; 117 int val; 118 118 }; 119 119 120 120 static inline void ?{}(__bin_sem_t & this) with( this ) { 121 signaled = false;122 121 pthread_mutex_init(&lock, NULL); 123 122 pthread_cond_init (&cond, NULL); 123 val = 0; 124 124 } 125 125 … … 132 132 verify(__cfaabi_dbg_in_kernel()); 133 133 pthread_mutex_lock(&lock); 134 if(!signaled) { // this must be a loop, not if!134 while(val < 1) { 135 135 pthread_cond_wait(&cond, &lock); 136 136 } 137 signaled = false;137 val -= 1; 138 138 pthread_mutex_unlock(&lock); 139 139 } 140 140 141 141 static inline bool post(__bin_sem_t & this) with( this ) { 142 bool needs_signal = false; 143 142 144 pthread_mutex_lock(&lock); 143 bool needs_signal = !signaled; 144 signaled = true; 145 if(val < 1) { 146 val += 1; 147 pthread_cond_signal(&cond); 148 needs_signal = true; 149 } 145 150 pthread_mutex_unlock(&lock); 146 147 if (needs_signal) pthread_cond_signal(&cond);148 151 149 152 return needs_signal; -
libcfa/src/bits/signal.hfa
r6091b88a rd45ed83 54 54 sig, handler, flags, errno, strerror( errno ) 55 55 ); 56 _ exit( EXIT_FAILURE );56 _Exit( EXIT_FAILURE ); 57 57 } // if 58 58 } -
libcfa/src/concurrency/io.cfa
r6091b88a rd45ed83 1 // 2 // Cforall Version 1.0.0 Copyright (C) 2020 University of Waterloo 3 // 4 // The contents of this file are covered under the licence agreement in the 5 // file "LICENCE" distributed with Cforall. 6 // 7 // io.cfa -- 8 // 9 // Author : Thierry Delisle 10 // Created On : Thu Apr 23 17:31:00 2020 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 14 // 15 16 // #define __CFA_DEBUG_PRINT_IO__ 17 1 18 #include "kernel.hfa" 2 19 3 20 #if !defined(HAVE_LINUX_IO_URING_H) 4 void __kernel_io_startup( cluster & this) {21 void __kernel_io_startup( cluster & ) { 5 22 // Nothing to do without io_uring 6 23 } 7 24 8 void __kernel_io_s hutdown( cluster & this) {25 void __kernel_io_start_thrd( cluster & ) { 9 26 // Nothing to do without io_uring 10 27 } 11 28 12 bool is_async( void (*)() ) { 13 return false; 29 void __kernel_io_stop_thrd ( cluster & ) { 30 // Nothing to do without io_uring 31 } 32 33 void __kernel_io_shutdown( cluster & ) { 34 // Nothing to do without io_uring 14 35 } 15 36 … … 35 56 } 36 57 37 static void * __io_poller( void * arg ); 38 39 // Weirdly, some systems that do support io_uring don't actually define these 40 #ifdef __alpha__ 41 /* 42 * alpha is the only exception, all other architectures 43 * have common numbers for new system calls. 44 */ 45 # ifndef __NR_io_uring_setup 46 # define __NR_io_uring_setup 535 47 # endif 48 # ifndef __NR_io_uring_enter 49 # define __NR_io_uring_enter 536 50 # endif 51 # ifndef __NR_io_uring_register 52 # define __NR_io_uring_register 537 53 # endif 54 #else /* !__alpha__ */ 55 # ifndef __NR_io_uring_setup 56 # define __NR_io_uring_setup 425 57 # endif 58 # ifndef __NR_io_uring_enter 59 # define __NR_io_uring_enter 426 60 # endif 61 # ifndef __NR_io_uring_register 62 # define __NR_io_uring_register 427 63 # endif 64 #endif 65 58 static void * __io_poller_slow( void * arg ); 59 60 // Weirdly, some systems that do support io_uring don't actually define these 61 #ifdef __alpha__ 62 /* 63 * alpha is the only exception, all other architectures 64 * have common numbers for new system calls. 65 */ 66 #ifndef __NR_io_uring_setup 67 #define __NR_io_uring_setup 535 68 #endif 69 #ifndef __NR_io_uring_enter 70 #define __NR_io_uring_enter 536 71 #endif 72 #ifndef __NR_io_uring_register 73 #define __NR_io_uring_register 537 74 #endif 75 #else /* !__alpha__ */ 76 #ifndef __NR_io_uring_setup 77 #define __NR_io_uring_setup 425 78 #endif 79 #ifndef __NR_io_uring_enter 80 #define __NR_io_uring_enter 426 81 #endif 82 #ifndef __NR_io_uring_register 83 #define __NR_io_uring_register 427 84 #endif 85 #endif 86 87 #if defined(__CFA_IO_POLLING_USER__) 88 void ?{}( __io_poller_fast & this, struct cluster & cltr ) { 89 this.ring = &cltr.io; 90 (this.thrd){ "I/O Poller", cltr }; 91 } 92 void ^?{}( __io_poller_fast & mutex this ); 93 void main( __io_poller_fast & this ); 94 static inline $thread * get_thread( __io_poller_fast & this ) { return &this.thrd; } 95 void ^?{}( __io_poller_fast & mutex this ) {} 96 #endif 66 97 67 98 //============================================================================================= 68 99 // I/O Startup / Shutdown logic 69 100 //============================================================================================= 70 void __kernel_io_startup( cluster & this ) {101 void __kernel_io_startup( cluster & this, bool main_cluster ) { 71 102 // Step 1 : call to setup 72 103 struct io_uring_params params; … … 90 121 91 122 // Requires features 92 // // adjust the size according to the parameters 93 // if ((params.features & IORING_FEAT_SINGLE_MMAP) != 0) { 94 // cq->ring_sz = sq->ring_sz = max(cq->ring_sz, sq->ring_sz); 95 // } 123 #if defined(IORING_FEAT_SINGLE_MMAP) 124 // adjust the size according to the parameters 125 if ((params.features & IORING_FEAT_SINGLE_MMAP) != 0) { 126 cq->ring_sz = sq->ring_sz = max(cq->ring_sz, sq->ring_sz); 127 } 128 #endif 96 129 97 130 // mmap the Submit Queue into existence … … 101 134 } 102 135 103 // mmap the Completion Queue into existence (may or may not be needed)104 136 // Requires features 105 // if ((params.features & IORING_FEAT_SINGLE_MMAP) != 0) { 106 // cq->ring_ptr = sq->ring_ptr; 107 // } 108 // else { 137 #if defined(IORING_FEAT_SINGLE_MMAP) 138 // mmap the Completion Queue into existence (may or may not be needed) 139 if ((params.features & IORING_FEAT_SINGLE_MMAP) != 0) { 140 cq->ring_ptr = sq->ring_ptr; 141 } 142 else 143 #endif 144 { 109 145 // We need multiple call to MMAP 110 146 cq.ring_ptr = mmap(0, cq.ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_CQ_RING); … … 113 149 abort("KERNEL ERROR: IO_URING MMAP2 - %s\n", strerror(errno)); 114 150 } 115 //}151 } 116 152 117 153 // mmap the submit queue entries … … 134 170 sq.array = ( uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array); 135 171 sq.alloc = *sq.tail; 172 sq.ready = *sq.tail; 136 173 137 174 // completion queue … … 160 197 (this.io.submit){ min(*sq.num, *cq.num) }; 161 198 199 // Initialize statistics 200 #if !defined(__CFA_NO_STATISTICS__) 201 this.io.submit_q.stats.submit_avg.val = 0; 202 this.io.submit_q.stats.submit_avg.cnt = 0; 203 this.io.completion_q.stats.completed_avg.val = 0; 204 this.io.completion_q.stats.completed_avg.cnt = 0; 205 #endif 206 207 if(!main_cluster) { 208 __kernel_io_finish_start( this ); 209 } 210 } 211 212 void __kernel_io_finish_start( cluster & this ) { 213 #if defined(__CFA_IO_POLLING_USER__) 214 __cfadbg_print_safe(io, "Kernel I/O : Creating fast poller for cluter %p\n", &this); 215 (this.io.poller.fast){ "Fast IO Poller", this }; 216 __thrd_start( this.io.poller.fast, main ); 217 #endif 218 162 219 // Create the poller thread 163 this.io.stack = __create_pthread( &this.io.poller, __io_poller, &this ); 164 } 165 166 void __kernel_io_shutdown( cluster & this ) { 167 // Stop the IO Poller 220 __cfadbg_print_safe(io, "Kernel I/O : Creating slow poller for cluter %p\n", &this); 221 this.io.poller.slow.stack = __create_pthread( &this.io.poller.slow.kthrd, __io_poller_slow, &this ); 222 } 223 224 void __kernel_io_prepare_stop( cluster & this ) { 225 __cfadbg_print_safe(io, "Kernel I/O : Stopping pollers for cluster\n", &this); 168 226 // Notify the poller thread of the shutdown 169 227 __atomic_store_n(&this.io.done, true, __ATOMIC_SEQ_CST); 228 229 // Stop the IO Poller 170 230 sigval val = { 1 }; 171 pthread_sigqueue( this.io.poller, SIGUSR1, val ); 231 pthread_sigqueue( this.io.poller.slow.kthrd, SIGUSR1, val ); 232 #if defined(__CFA_IO_POLLING_USER__) 233 post( this.io.poller.sem ); 234 #endif 172 235 173 236 // Wait for the poller thread to finish 174 pthread_join( this.io.poller, 0p ); 175 free( this.io.stack ); 237 pthread_join( this.io.poller.slow.kthrd, 0p ); 238 free( this.io.poller.slow.stack ); 239 240 __cfadbg_print_safe(io, "Kernel I/O : Slow poller stopped for cluster\n", &this); 241 242 #if defined(__CFA_IO_POLLING_USER__) 243 // unpark the fast io_poller 244 unpark( &this.io.poller.fast.thrd __cfaabi_dbg_ctx2 ); 245 246 ^(this.io.poller.fast){}; 247 248 __cfadbg_print_safe(io, "Kernel I/O : Fast poller stopped for cluster\n", &this); 249 #endif 250 } 251 252 void __kernel_io_shutdown( cluster & this, bool main_cluster ) { 253 if(!main_cluster) { 254 __kernel_io_prepare_stop( this ); 255 } 256 257 // print statistics 258 #if !defined(__CFA_NO_STATISTICS__) 259 if(this.print_stats) { 260 __cfaabi_bits_print_safe( STDERR_FILENO, 261 "----- I/O uRing Stats -----\n" 262 "- total submit calls : %llu\n" 263 "- avg submit : %lf\n" 264 "- total wait calls : %llu\n" 265 "- avg completion/wait : %lf\n", 266 this.io.submit_q.stats.submit_avg.cnt, 267 ((double)this.io.submit_q.stats.submit_avg.val) / this.io.submit_q.stats.submit_avg.cnt, 268 this.io.completion_q.stats.completed_avg.cnt, 269 ((double)this.io.completion_q.stats.completed_avg.val) / this.io.completion_q.stats.completed_avg.cnt 270 ); 271 } 272 #endif 176 273 177 274 // Shutdown the io rings … … 204 301 // Process a single completion message from the io_uring 205 302 // This is NOT thread-safe 206 static bool __io_process(struct io_ring & ring) { 303 static int __drain_io( struct io_ring & ring, sigset_t * mask, int waitcnt, bool in_kernel ) { 304 int ret = syscall( __NR_io_uring_enter, ring.fd, 0, waitcnt, IORING_ENTER_GETEVENTS, mask, _NSIG / 8); 305 if( ret < 0 ) { 306 switch((int)errno) { 307 case EAGAIN: 308 case EINTR: 309 return -EAGAIN; 310 default: 311 abort( "KERNEL ERROR: IO_URING WAIT - %s\n", strerror(errno) ); 312 } 313 } 314 315 // Drain the queue 207 316 unsigned head = *ring.completion_q.head; 208 317 unsigned tail = __atomic_load_n(ring.completion_q.tail, __ATOMIC_ACQUIRE); 209 318 210 if (head == tail) return false; 211 212 unsigned idx = head & (*ring.completion_q.mask); 213 struct io_uring_cqe & cqe = ring.completion_q.cqes[idx]; 214 215 /* paranoid */ verify(&cqe); 216 217 struct io_user_data * data = (struct io_user_data *)cqe.user_data; 218 // __cfaabi_bits_print_safe( STDERR_FILENO, "Performed reading io cqe %p, result %d for %p\n", data, cqe.res, data->thrd ); 219 220 data->result = cqe.res; 221 __unpark( data->thrd __cfaabi_dbg_ctx2 ); 319 // Nothing was new return 0 320 if (head == tail) { 321 #if !defined(__CFA_NO_STATISTICS__) 322 ring.completion_q.stats.completed_avg.cnt += 1; 323 #endif 324 return 0; 325 } 326 327 uint32_t count = tail - head; 328 for(i; count) { 329 unsigned idx = (head + i) & (*ring.completion_q.mask); 330 struct io_uring_cqe & cqe = ring.completion_q.cqes[idx]; 331 332 /* paranoid */ verify(&cqe); 333 334 struct io_user_data * data = (struct io_user_data *)cqe.user_data; 335 __cfadbg_print_safe( io, "Kernel I/O : Performed reading io cqe %p, result %d for %p\n", data, cqe.res, data->thrd ); 336 337 data->result = cqe.res; 338 if(!in_kernel) { unpark( data->thrd __cfaabi_dbg_ctx2 ); } 339 else { __unpark( data->thrd __cfaabi_dbg_ctx2 ); } 340 } 222 341 223 342 // Allow new submissions to happen 224 V(ring.submit );343 V(ring.submit, count); 225 344 226 345 // Mark to the kernel that the cqe has been seen 227 346 // Ensure that the kernel only sees the new value of the head index after the CQEs have been read. 228 __atomic_fetch_add( ring.completion_q.head, 1, __ATOMIC_RELAXED ); 229 230 return true; 231 } 232 233 static void * __io_poller( void * arg ) { 347 __atomic_fetch_add( ring.completion_q.head, count, __ATOMIC_RELAXED ); 348 349 // Update statistics 350 #if !defined(__CFA_NO_STATISTICS__) 351 ring.completion_q.stats.completed_avg.val += count; 352 ring.completion_q.stats.completed_avg.cnt += 1; 353 #endif 354 355 return count; 356 } 357 358 static void * __io_poller_slow( void * arg ) { 234 359 cluster * cltr = (cluster *)arg; 235 360 struct io_ring & ring = cltr->io; … … 246 371 verify( (*ring.completion_q.head) == (*ring.completion_q.tail) ); 247 372 248 LOOP: while(!__atomic_load_n(&ring.done, __ATOMIC_SEQ_CST)) { 249 int ret = syscall( __NR_io_uring_enter, ring.fd, 0, 1, IORING_ENTER_GETEVENTS, &mask, _NSIG / 8); 250 if( ret < 0 ) { 251 switch((int)errno) { 252 case EAGAIN: 253 case EINTR: 254 continue LOOP; 255 default: 256 abort( "KERNEL ERROR: IO_URING WAIT - %s\n", strerror(errno) ); 373 while(!__atomic_load_n(&ring.done, __ATOMIC_SEQ_CST)) { 374 #if defined(__CFA_IO_POLLING_USER__) 375 376 // In the user-thread approach drain and if anything was drained, 377 // batton pass to the user-thread 378 int count = __drain_io( ring, &mask, 1, true ); 379 if(count > 0) { 380 __cfadbg_print_safe(io, "Kernel I/O : Moving to ring %p to fast poller\n", &ring); 381 __unpark( &ring.poller.fast.thrd __cfaabi_dbg_ctx2 ); 382 wait( ring.poller.sem ); 383 } 384 385 #else 386 387 //In the naive approach, just poll the io completion queue directly 388 __drain_io( ring, &mask, 1, true ); 389 390 #endif 391 } 392 393 return 0p; 394 } 395 396 #if defined(__CFA_IO_POLLING_USER__) 397 void main( __io_poller_fast & this ) { 398 // Start parked 399 park( __cfaabi_dbg_ctx ); 400 401 // Then loop until we need to start 402 while(!__atomic_load_n(&this.ring->done, __ATOMIC_SEQ_CST)) { 403 // Drain the io 404 if(0 > __drain_io( *this.ring, 0p, 0, false )) { 405 // If we got something, just yield and check again 406 yield(); 407 } 408 else { 409 // We didn't get anything baton pass to the slow poller 410 __cfadbg_print_safe(io, "Kernel I/O : Moving to ring %p to slow poller\n", &this.ring); 411 post( this.ring->poller.sem ); 412 park( __cfaabi_dbg_ctx ); 257 413 } 258 414 } 259 260 // Drain the queue 261 while(__io_process(ring)) {} 262 } 263 264 return 0p; 265 } 415 } 416 #endif 266 417 267 418 //============================================================================================= … … 293 444 // 294 445 295 static inline [* struct io_uring_sqe, uint32_t] __submit_alloc( struct io_ring & ring ) { 296 // Wait for a spot to be available 297 P(ring.submit); 298 299 // Allocate the sqe 300 uint32_t idx = __atomic_fetch_add(&ring.submit_q.alloc, 1ul32, __ATOMIC_SEQ_CST); 301 302 // Validate that we didn't overflow anything 303 // Check that nothing overflowed 304 /* paranoid */ verify( true ); 305 306 // Check that it goes head -> tail -> alloc and never head -> alloc -> tail 307 /* paranoid */ verify( true ); 308 309 // Return the sqe 310 return [&ring.submit_q.sqes[ idx & (*ring.submit_q.mask)], idx]; 311 } 312 313 static inline void __submit( struct io_ring & ring, uint32_t idx ) { 314 // get mutual exclusion 315 lock(ring.submit_q.lock __cfaabi_dbg_ctx2); 316 317 // Append to the list of ready entries 318 uint32_t * tail = ring.submit_q.tail; 319 const uint32_t mask = *ring.submit_q.mask; 320 321 ring.submit_q.array[ (*tail) & mask ] = idx & mask; 322 __atomic_fetch_add(tail, 1ul32, __ATOMIC_SEQ_CST); 323 324 // Submit however, many entries need to be submitted 325 int ret = syscall( __NR_io_uring_enter, ring.fd, 1, 0, 0, 0p, 0); 326 // __cfaabi_bits_print_safe( STDERR_FILENO, "Performed io_submit, returned %d\n", ret ); 327 if( ret < 0 ) { 328 switch((int)errno) { 329 default: 330 abort( "KERNEL ERROR: IO_URING SUBMIT - %s\n", strerror(errno) ); 331 } 332 } 333 334 unlock(ring.submit_q.lock); 335 // Make sure that idx was submitted 336 // Be careful to not get false positive if we cycled the entire list or that someone else submitted for us 337 } 338 339 static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd) { 340 this.opcode = opcode; 341 #if !defined(IOSQE_ASYNC) 342 this.flags = 0; 343 #else 344 this.flags = IOSQE_ASYNC; 345 #endif 346 this.ioprio = 0; 347 this.fd = fd; 348 this.off = 0; 349 this.addr = 0; 350 this.len = 0; 351 this.rw_flags = 0; 352 this.__pad2[0] = this.__pad2[1] = this.__pad2[2] = 0; 353 } 354 355 static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd, void * addr, uint32_t len, uint64_t off ) { 356 (this){ opcode, fd }; 357 this.off = off; 358 this.addr = (uint64_t)addr; 359 this.len = len; 360 } 446 static inline [* struct io_uring_sqe, uint32_t] __submit_alloc( struct io_ring & ring ) { 447 // Wait for a spot to be available 448 P(ring.submit); 449 450 // Allocate the sqe 451 uint32_t idx = __atomic_fetch_add(&ring.submit_q.alloc, 1ul32, __ATOMIC_SEQ_CST); 452 453 // Validate that we didn't overflow anything 454 // Check that nothing overflowed 455 /* paranoid */ verify( true ); 456 457 // Check that it goes head -> tail -> alloc and never head -> alloc -> tail 458 /* paranoid */ verify( true ); 459 460 // Return the sqe 461 return [&ring.submit_q.sqes[ idx & (*ring.submit_q.mask)], idx]; 462 } 463 464 static inline void __submit( struct io_ring & ring, uint32_t idx ) { 465 // get mutual exclusion 466 lock(ring.submit_q.lock __cfaabi_dbg_ctx2); 467 468 // Append to the list of ready entries 469 uint32_t * tail = ring.submit_q.tail; 470 const uint32_t mask = *ring.submit_q.mask; 471 472 ring.submit_q.array[ (*tail) & mask ] = idx & mask; 473 __atomic_fetch_add(tail, 1ul32, __ATOMIC_SEQ_CST); 474 475 // Submit however, many entries need to be submitted 476 int ret = syscall( __NR_io_uring_enter, ring.fd, 1, 0, 0, 0p, 0); 477 if( ret < 0 ) { 478 switch((int)errno) { 479 default: 480 abort( "KERNEL ERROR: IO_URING SUBMIT - %s\n", strerror(errno) ); 481 } 482 } 483 484 // update statistics 485 #if !defined(__CFA_NO_STATISTICS__) 486 ring.submit_q.stats.submit_avg.val += 1; 487 ring.submit_q.stats.submit_avg.cnt += 1; 488 #endif 489 490 unlock(ring.submit_q.lock); 491 // Make sure that idx was submitted 492 // Be careful to not get false positive if we cycled the entire list or that someone else submitted for us 493 __cfadbg_print_safe( io, "Kernel I/O : Performed io_submit for %p, returned %d\n", active_thread(), ret ); 494 } 495 496 static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd) { 497 this.opcode = opcode; 498 #if !defined(IOSQE_ASYNC) 499 this.flags = 0; 500 #else 501 this.flags = IOSQE_ASYNC; 502 #endif 503 this.ioprio = 0; 504 this.fd = fd; 505 this.off = 0; 506 this.addr = 0; 507 this.len = 0; 508 this.rw_flags = 0; 509 this.__pad2[0] = this.__pad2[1] = this.__pad2[2] = 0; 510 } 511 512 static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd, void * addr, uint32_t len, uint64_t off ) { 513 (this){ opcode, fd }; 514 this.off = off; 515 this.addr = (uint64_t)addr; 516 this.len = len; 517 } 518 361 519 362 520 //============================================================================================= 363 521 // I/O Interface 364 522 //============================================================================================= 365 extern "C" {366 #define __USE_GNU367 #define _GNU_SOURCE368 #include <fcntl.h>369 #include <sys/uio.h>370 #include <sys/socket.h>371 #include <sys/stat.h>372 }373 523 374 524 #define __submit_prelude \ … … 385 535 park( __cfaabi_dbg_ctx ); \ 386 536 return data.result; 537 #endif 538 539 // Some forward declarations 540 extern "C" { 541 #include <sys/types.h> 542 struct iovec; 543 extern ssize_t preadv2 (int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags); 544 extern ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags); 545 546 extern int fsync(int fd); 547 extern int sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags); 548 549 struct msghdr; 550 struct sockaddr; 551 extern ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); 552 extern ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); 553 extern ssize_t send(int sockfd, const void *buf, size_t len, int flags); 554 extern ssize_t recv(int sockfd, void *buf, size_t len, int flags); 555 extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); 556 extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 557 558 extern int fallocate(int fd, int mode, uint64_t offset, uint64_t len); 559 extern int posix_fadvise(int fd, uint64_t offset, uint64_t len, int advice); 560 extern int madvise(void *addr, size_t length, int advice); 561 562 extern int openat(int dirfd, const char *pathname, int flags, mode_t mode); 563 extern int close(int fd); 564 565 struct statx; 566 extern int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf); 567 568 extern ssize_t read (int fd, void *buf, size_t count); 569 } 387 570 388 571 //----------------------------------------------------------------------------- 389 572 // Asynchronous operations 390 ssize_t async_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags) { 391 #if !defined(IORING_OP_READV) 392 return preadv2(fd, iov, iovcnt, offset, flags); 393 #else 394 __submit_prelude 395 396 (*sqe){ IORING_OP_READV, fd, iov, iovcnt, offset }; 397 398 __submit_wait 399 #endif 400 } 401 402 ssize_t async_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags) { 403 #if !defined(IORING_OP_WRITEV) 404 return pwritev2(fd, iov, iovcnt, offset, flags); 405 #else 406 __submit_prelude 407 408 (*sqe){ IORING_OP_WRITEV, fd, iov, iovcnt, offset }; 409 410 __submit_wait 411 #endif 412 } 413 414 int async_fsync(int fd) { 415 #if !defined(IORING_OP_FSYNC) 416 return fsync(fd); 417 #else 418 __submit_prelude 419 420 (*sqe){ IORING_OP_FSYNC, fd }; 421 422 __submit_wait 423 #endif 424 } 425 426 int async_sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags) { 427 #if !defined(IORING_OP_SYNC_FILE_RANGE) 428 return sync_file_range(fd, offset, nbytes, flags); 429 #else 430 __submit_prelude 431 432 (*sqe){ IORING_OP_SYNC_FILE_RANGE, fd }; 433 sqe->off = offset; 434 sqe->len = nbytes; 435 sqe->sync_range_flags = flags; 436 437 __submit_wait 438 #endif 439 } 440 441 442 ssize_t async_sendmsg(int sockfd, const struct msghdr *msg, int flags) { 443 #if !defined(IORING_OP_SENDMSG) 444 return recv(sockfd, msg, flags); 445 #else 446 __submit_prelude 447 448 (*sqe){ IORING_OP_SENDMSG, sockfd, msg, 1, 0 }; 449 sqe->msg_flags = flags; 450 451 __submit_wait 452 #endif 453 } 454 455 ssize_t async_recvmsg(int sockfd, struct msghdr *msg, int flags) { 456 #if !defined(IORING_OP_RECVMSG) 457 return recv(sockfd, msg, flags); 458 #else 459 __submit_prelude 460 461 (*sqe){ IORING_OP_RECVMSG, sockfd, msg, 1, 0 }; 462 sqe->msg_flags = flags; 463 464 __submit_wait 465 #endif 466 } 467 468 ssize_t async_send(int sockfd, const void *buf, size_t len, int flags) { 469 #if !defined(IORING_OP_SEND) 470 return send( sockfd, buf, len, flags ); 471 #else 472 __submit_prelude 473 474 (*sqe){ IORING_OP_SEND, sockfd }; 475 sqe->addr = (uint64_t)buf; 476 sqe->len = len; 477 sqe->msg_flags = flags; 478 479 __submit_wait 480 #endif 481 } 482 483 ssize_t async_recv(int sockfd, void *buf, size_t len, int flags) { 484 #if !defined(IORING_OP_RECV) 485 return recv( sockfd, buf, len, flags ); 486 #else 487 __submit_prelude 488 489 (*sqe){ IORING_OP_RECV, sockfd }; 490 sqe->addr = (uint64_t)buf; 491 sqe->len = len; 492 sqe->msg_flags = flags; 493 494 __submit_wait 495 #endif 496 } 497 498 int async_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) { 499 #if !defined(IORING_OP_ACCEPT) 500 __SOCKADDR_ARG _addr; 501 _addr.__sockaddr__ = addr; 502 return accept4( sockfd, _addr, addrlen, flags ); 503 #else 504 __submit_prelude 505 506 (*sqe){ IORING_OP_ACCEPT, sockfd }; 507 sqe->addr = addr; 508 sqe->addr2 = addrlen; 509 sqe->accept_flags = flags; 510 511 __submit_wait 512 #endif 513 } 514 515 int async_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { 516 #if !defined(IORING_OP_CONNECT) 517 __CONST_SOCKADDR_ARG _addr; 518 _addr.__sockaddr__ = addr; 519 return connect( sockfd, _addr, addrlen ); 520 #else 521 __submit_prelude 522 523 (*sqe){ IORING_OP_CONNECT, sockfd }; 524 sqe->addr = (uint64_t)addr; 525 sqe->off = addrlen; 526 527 __submit_wait 528 #endif 529 } 530 531 int async_fallocate(int fd, int mode, uint64_t offset, uint64_t len) { 532 #if !defined(IORING_OP_FALLOCATE) 533 return fallocate( fd, mode, offset, len ); 534 #else 535 __submit_prelude 536 537 (*sqe){ IORING_OP_FALLOCATE, fd }; 538 sqe->off = offset; 539 sqe->len = length; 540 sqe->mode = mode; 541 542 __submit_wait 543 #endif 544 } 545 546 int async_fadvise(int fd, uint64_t offset, uint64_t len, int advice) { 547 #if !defined(IORING_OP_FADVISE) 548 return posix_fadvise( fd, offset, len, advice ); 549 #else 550 __submit_prelude 551 552 (*sqe){ IORING_OP_FADVISE, fd }; 553 sqe->off = (uint64_t)offset; 554 sqe->len = length; 555 sqe->fadvise_advice = advice; 556 557 __submit_wait 558 #endif 559 } 560 561 int async_madvise(void *addr, size_t length, int advice) { 562 #if !defined(IORING_OP_MADVISE) 563 return madvise( addr, length, advice ); 564 #else 565 __submit_prelude 566 567 (*sqe){ IORING_OP_MADVISE, 0 }; 568 sqe->addr = (uint64_t)addr; 569 sqe->len = length; 570 sqe->fadvise_advice = advice; 571 572 __submit_wait 573 #endif 574 } 575 576 int async_openat(int dirfd, const char *pathname, int flags, mode_t mode) { 577 #if !defined(IORING_OP_OPENAT) 578 return openat( dirfd, pathname, flags, mode ); 579 #else 580 __submit_prelude 581 582 (*sqe){ IORING_OP_OPENAT, dirfd }; 583 sqe->addr = (uint64_t)pathname; 584 sqe->open_flags = flags; 585 sqe->mode = mode; 586 587 __submit_wait 588 #endif 589 } 590 591 int async_close(int fd) { 592 #if !defined(IORING_OP_CLOSE) 593 return close( fd ); 594 #else 595 __submit_prelude 596 597 (*sqe){ IORING_OP_CLOSE, fd }; 598 599 __submit_wait 600 #endif 601 } 602 603 int async_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf) { 604 #if !defined(IORING_OP_STATX) 605 //return statx( dirfd, pathname, flags, mask, statxbuf ); 606 return syscall( __NR_io_uring_setup, dirfd, pathname, flags, mask, statxbuf ); 607 #else 608 __submit_prelude 609 610 (*sqe){ IORING_OP_STATX, dirfd }; 611 sqe->addr = (uint64_t)pathname; 612 sqe->statx_flags = flags; 613 sqe->len = mask; 614 sqe->off = (uint64_t)statxbuf; 615 616 __submit_wait 617 #endif 618 } 619 620 621 ssize_t async_read(int fd, void *buf, size_t count) { 622 #if !defined(IORING_OP_READ) 623 return read( fd, buf, count ); 624 #else 625 __submit_prelude 626 627 (*sqe){ IORING_OP_READ, fd, buf, count, 0 }; 628 629 __submit_wait 630 #endif 631 } 632 633 ssize_t async_write(int fd, void *buf, size_t count) { 634 #if !defined(IORING_OP_WRITE) 635 return read( fd, buf, count ); 636 #else 637 __submit_prelude 638 639 (*sqe){ IORING_OP_WRITE, fd, buf, count, 0 }; 640 641 __submit_wait 642 #endif 643 } 573 ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags) { 574 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_READV) 575 return preadv2(fd, iov, iovcnt, offset, flags); 576 #else 577 __submit_prelude 578 579 (*sqe){ IORING_OP_READV, fd, iov, iovcnt, offset }; 580 581 __submit_wait 582 #endif 583 } 584 585 ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags) { 586 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_WRITEV) 587 return pwritev2(fd, iov, iovcnt, offset, flags); 588 #else 589 __submit_prelude 590 591 (*sqe){ IORING_OP_WRITEV, fd, iov, iovcnt, offset }; 592 593 __submit_wait 594 #endif 595 } 596 597 int cfa_fsync(int fd) { 598 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_FSYNC) 599 return fsync(fd); 600 #else 601 __submit_prelude 602 603 (*sqe){ IORING_OP_FSYNC, fd }; 604 605 __submit_wait 606 #endif 607 } 608 609 int cfa_sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags) { 610 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_SYNC_FILE_RANGE) 611 return sync_file_range(fd, offset, nbytes, flags); 612 #else 613 __submit_prelude 614 615 (*sqe){ IORING_OP_SYNC_FILE_RANGE, fd }; 616 sqe->off = offset; 617 sqe->len = nbytes; 618 sqe->sync_range_flags = flags; 619 620 __submit_wait 621 #endif 622 } 623 624 625 ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags) { 626 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_SENDMSG) 627 return recv(sockfd, msg, flags); 628 #else 629 __submit_prelude 630 631 (*sqe){ IORING_OP_SENDMSG, sockfd, msg, 1, 0 }; 632 sqe->msg_flags = flags; 633 634 __submit_wait 635 #endif 636 } 637 638 ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags) { 639 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_RECVMSG) 640 return recv(sockfd, msg, flags); 641 #else 642 __submit_prelude 643 644 (*sqe){ IORING_OP_RECVMSG, sockfd, msg, 1, 0 }; 645 sqe->msg_flags = flags; 646 647 __submit_wait 648 #endif 649 } 650 651 ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags) { 652 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_SEND) 653 return send( sockfd, buf, len, flags ); 654 #else 655 __submit_prelude 656 657 (*sqe){ IORING_OP_SEND, sockfd }; 658 sqe->addr = (uint64_t)buf; 659 sqe->len = len; 660 sqe->msg_flags = flags; 661 662 __submit_wait 663 #endif 664 } 665 666 ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags) { 667 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_RECV) 668 return recv( sockfd, buf, len, flags ); 669 #else 670 __submit_prelude 671 672 (*sqe){ IORING_OP_RECV, sockfd }; 673 sqe->addr = (uint64_t)buf; 674 sqe->len = len; 675 sqe->msg_flags = flags; 676 677 __submit_wait 678 #endif 679 } 680 681 int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) { 682 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_ACCEPT) 683 return accept4( sockfd, addr, addrlen, flags ); 684 #else 685 __submit_prelude 686 687 (*sqe){ IORING_OP_ACCEPT, sockfd }; 688 sqe->addr = addr; 689 sqe->addr2 = addrlen; 690 sqe->accept_flags = flags; 691 692 __submit_wait 693 #endif 694 } 695 696 int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { 697 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_CONNECT) 698 return connect( sockfd, addr, addrlen ); 699 #else 700 __submit_prelude 701 702 (*sqe){ IORING_OP_CONNECT, sockfd }; 703 sqe->addr = (uint64_t)addr; 704 sqe->off = addrlen; 705 706 __submit_wait 707 #endif 708 } 709 710 int cfa_fallocate(int fd, int mode, uint64_t offset, uint64_t len) { 711 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_FALLOCATE) 712 return fallocate( fd, mode, offset, len ); 713 #else 714 __submit_prelude 715 716 (*sqe){ IORING_OP_FALLOCATE, fd }; 717 sqe->off = offset; 718 sqe->len = length; 719 sqe->mode = mode; 720 721 __submit_wait 722 #endif 723 } 724 725 int cfa_fadvise(int fd, uint64_t offset, uint64_t len, int advice) { 726 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_FADVISE) 727 return posix_fadvise( fd, offset, len, advice ); 728 #else 729 __submit_prelude 730 731 (*sqe){ IORING_OP_FADVISE, fd }; 732 sqe->off = (uint64_t)offset; 733 sqe->len = length; 734 sqe->fadvise_advice = advice; 735 736 __submit_wait 737 #endif 738 } 739 740 int cfa_madvise(void *addr, size_t length, int advice) { 741 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_MADVISE) 742 return madvise( addr, length, advice ); 743 #else 744 __submit_prelude 745 746 (*sqe){ IORING_OP_MADVISE, 0 }; 747 sqe->addr = (uint64_t)addr; 748 sqe->len = length; 749 sqe->fadvise_advice = advice; 750 751 __submit_wait 752 #endif 753 } 754 755 int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode) { 756 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_OPENAT) 757 return openat( dirfd, pathname, flags, mode ); 758 #else 759 __submit_prelude 760 761 (*sqe){ IORING_OP_OPENAT, dirfd }; 762 sqe->addr = (uint64_t)pathname; 763 sqe->open_flags = flags; 764 sqe->mode = mode; 765 766 __submit_wait 767 #endif 768 } 769 770 int cfa_close(int fd) { 771 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_CLOSE) 772 return close( fd ); 773 #else 774 __submit_prelude 775 776 (*sqe){ IORING_OP_CLOSE, fd }; 777 778 __submit_wait 779 #endif 780 } 781 782 int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf) { 783 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_STATX) 784 //return statx( dirfd, pathname, flags, mask, statxbuf ); 785 return syscall( __NR_io_uring_setup, dirfd, pathname, flags, mask, statxbuf ); 786 #else 787 __submit_prelude 788 789 (*sqe){ IORING_OP_STATX, dirfd }; 790 sqe->addr = (uint64_t)pathname; 791 sqe->statx_flags = flags; 792 sqe->len = mask; 793 sqe->off = (uint64_t)statxbuf; 794 795 __submit_wait 796 #endif 797 } 798 799 800 ssize_t cfa_read(int fd, void *buf, size_t count) { 801 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_READ) 802 return read( fd, buf, count ); 803 #else 804 __submit_prelude 805 806 (*sqe){ IORING_OP_READ, fd, buf, count, 0 }; 807 808 __submit_wait 809 #endif 810 } 811 812 ssize_t cfa_write(int fd, void *buf, size_t count) { 813 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_WRITE) 814 return read( fd, buf, count ); 815 #else 816 __submit_prelude 817 818 (*sqe){ IORING_OP_WRITE, fd, buf, count, 0 }; 819 820 __submit_wait 821 #endif 822 } 644 823 645 824 //----------------------------------------------------------------------------- … … 647 826 648 827 // Macro magic to reduce the size of the following switch case 649 #define IS_DEFINED_APPLY(f, ...) f(__VA_ARGS__)650 #define IS_DEFINED_SECOND(first, second, ...) second651 #define IS_DEFINED_TEST(expansion) _CFA_IO_FEATURE_##expansion652 #define IS_DEFINED(macro) IS_DEFINED_APPLY( IS_DEFINED_SECOND,IS_DEFINED_TEST(macro) false, true)653 654 bool is_async( fptr_t func ) {655 828 #define IS_DEFINED_APPLY(f, ...) f(__VA_ARGS__) 829 #define IS_DEFINED_SECOND(first, second, ...) second 830 #define IS_DEFINED_TEST(expansion) _CFA_IO_FEATURE_##expansion 831 #define IS_DEFINED(macro) IS_DEFINED_APPLY( IS_DEFINED_SECOND,IS_DEFINED_TEST(macro) false, true) 832 833 bool has_user_level_blocking( fptr_t func ) { 834 #if defined(HAVE_LINUX_IO_URING_H) 656 835 if( /*func == (fptr_t)preadv2 || */ 657 func == (fptr_t) async_preadv2 )836 func == (fptr_t)cfa_preadv2 ) 658 837 #define _CFA_IO_FEATURE_IORING_OP_READV , 659 838 return IS_DEFINED(IORING_OP_READV); 660 839 661 840 if( /*func == (fptr_t)pwritev2 || */ 662 func == (fptr_t)async_pwritev2 )841 func == (fptr_t)cfa_pwritev2 ) 663 842 #define _CFA_IO_FEATURE_IORING_OP_WRITEV , 664 843 return IS_DEFINED(IORING_OP_WRITEV); 665 844 666 845 if( /*func == (fptr_t)fsync || */ 667 func == (fptr_t)async_fsync )846 func == (fptr_t)cfa_fsync ) 668 847 #define _CFA_IO_FEATURE_IORING_OP_FSYNC , 669 848 return IS_DEFINED(IORING_OP_FSYNC); 670 849 671 850 if( /*func == (fptr_t)ync_file_range || */ 672 func == (fptr_t)async_sync_file_range )851 func == (fptr_t)cfa_sync_file_range ) 673 852 #define _CFA_IO_FEATURE_IORING_OP_SYNC_FILE_RANGE , 674 853 return IS_DEFINED(IORING_OP_SYNC_FILE_RANGE); 675 854 676 855 if( /*func == (fptr_t)sendmsg || */ 677 func == (fptr_t)async_sendmsg )856 func == (fptr_t)cfa_sendmsg ) 678 857 #define _CFA_IO_FEATURE_IORING_OP_SENDMSG , 679 858 return IS_DEFINED(IORING_OP_SENDMSG); 680 859 681 860 if( /*func == (fptr_t)recvmsg || */ 682 func == (fptr_t)async_recvmsg )861 func == (fptr_t)cfa_recvmsg ) 683 862 #define _CFA_IO_FEATURE_IORING_OP_RECVMSG , 684 863 return IS_DEFINED(IORING_OP_RECVMSG); 685 864 686 865 if( /*func == (fptr_t)send || */ 687 func == (fptr_t) async_send )866 func == (fptr_t)cfa_send ) 688 867 #define _CFA_IO_FEATURE_IORING_OP_SEND , 689 868 return IS_DEFINED(IORING_OP_SEND); 690 869 691 870 if( /*func == (fptr_t)recv || */ 692 func == (fptr_t) async_recv )871 func == (fptr_t)cfa_recv ) 693 872 #define _CFA_IO_FEATURE_IORING_OP_RECV , 694 873 return IS_DEFINED(IORING_OP_RECV); 695 874 696 875 if( /*func == (fptr_t)accept4 || */ 697 func == (fptr_t) async_accept4 )876 func == (fptr_t)cfa_accept4 ) 698 877 #define _CFA_IO_FEATURE_IORING_OP_ACCEPT , 699 878 return IS_DEFINED(IORING_OP_ACCEPT); 700 879 701 880 if( /*func == (fptr_t)connect || */ 702 func == (fptr_t) async_connect )881 func == (fptr_t)cfa_connect ) 703 882 #define _CFA_IO_FEATURE_IORING_OP_CONNECT , 704 883 return IS_DEFINED(IORING_OP_CONNECT); 705 884 706 885 if( /*func == (fptr_t)fallocate || */ 707 func == (fptr_t) async_fallocate )886 func == (fptr_t)cfa_fallocate ) 708 887 #define _CFA_IO_FEATURE_IORING_OP_FALLOCATE , 709 888 return IS_DEFINED(IORING_OP_FALLOCATE); 710 889 711 if( /*func == (fptr_t) fadvise || */712 func == (fptr_t) async_fadvise )890 if( /*func == (fptr_t)posix_fadvise || */ 891 func == (fptr_t)cfa_fadvise ) 713 892 #define _CFA_IO_FEATURE_IORING_OP_FADVISE , 714 893 return IS_DEFINED(IORING_OP_FADVISE); 715 894 716 895 if( /*func == (fptr_t)madvise || */ 717 func == (fptr_t) async_madvise )896 func == (fptr_t)cfa_madvise ) 718 897 #define _CFA_IO_FEATURE_IORING_OP_MADVISE , 719 898 return IS_DEFINED(IORING_OP_MADVISE); 720 899 721 900 if( /*func == (fptr_t)openat || */ 722 func == (fptr_t) async_openat )901 func == (fptr_t)cfa_openat ) 723 902 #define _CFA_IO_FEATURE_IORING_OP_OPENAT , 724 903 return IS_DEFINED(IORING_OP_OPENAT); 725 904 726 905 if( /*func == (fptr_t)close || */ 727 func == (fptr_t) async_close )906 func == (fptr_t)cfa_close ) 728 907 #define _CFA_IO_FEATURE_IORING_OP_CLOSE , 729 908 return IS_DEFINED(IORING_OP_CLOSE); 730 909 731 910 if( /*func == (fptr_t)statx || */ 732 func == (fptr_t) async_statx )911 func == (fptr_t)cfa_statx ) 733 912 #define _CFA_IO_FEATURE_IORING_OP_STATX , 734 913 return IS_DEFINED(IORING_OP_STATX); 735 914 736 915 if( /*func == (fptr_t)read || */ 737 func == (fptr_t)async_read )916 func == (fptr_t)cfa_read ) 738 917 #define _CFA_IO_FEATURE_IORING_OP_READ , 739 918 return IS_DEFINED(IORING_OP_READ); 740 919 741 920 if( /*func == (fptr_t)write || */ 742 func == (fptr_t)async_write )921 func == (fptr_t)cfa_write ) 743 922 #define _CFA_IO_FEATURE_IORING_OP_WRITE , 744 923 return IS_DEFINED(IORING_OP_WRITE); 745 746 return false; 747 } 748 749 #endif 924 #endif 925 926 return false; 927 } -
libcfa/src/concurrency/kernel.cfa
r6091b88a rd45ed83 15 15 16 16 #define __cforall_thread__ 17 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__ 17 18 18 19 //C Includes … … 40 41 #include "invoke.h" 41 42 43 42 44 //----------------------------------------------------------------------------- 43 45 // Some assembly required … … 230 232 idle{}; 231 233 232 __cfa abi_dbg_print_safe("Kernel : Starting core %p\n", &this);234 __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this); 233 235 234 236 this.stack = __create_pthread( &this.kernel_thread, __invoke_processor, (void *)&this ); 235 237 236 __cfa abi_dbg_print_safe("Kernel : core %p started\n", &this);238 __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this); 237 239 } 238 240 239 241 void ^?{}(processor & this) with( this ){ 240 242 if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) { 241 __cfa abi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);243 __cfadbg_print_safe(runtime_core, "Kernel : core %p signaling termination\n", &this); 242 244 243 245 __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED); … … 258 260 ready_queue_lock{}; 259 261 262 #if !defined(__CFA_NO_STATISTICS__) 263 print_stats = false; 264 #endif 265 260 266 procs{ __get }; 261 267 idles{ __get }; 262 268 threads{ __get }; 263 269 264 __kernel_io_startup( this );270 __kernel_io_startup( this, &this == mainCluster ); 265 271 266 272 doregister(this); … … 268 274 269 275 void ^?{}(cluster & this) { 270 __kernel_io_shutdown( this );276 __kernel_io_shutdown( this, &this == mainCluster ); 271 277 272 278 unregister(this); … … 285 291 verify(this); 286 292 287 __cfa abi_dbg_print_safe("Kernel : core %p starting\n", this);293 __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this); 288 294 289 295 doregister(this->cltr, this); … … 293 299 preemption_scope scope = { this }; 294 300 295 __cfa abi_dbg_print_safe("Kernel : core %p started\n", this);301 __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this); 296 302 297 303 $thread * readyThread = 0p; … … 319 325 } 320 326 321 __cfa abi_dbg_print_safe("Kernel : core %p stopping\n", this);327 __cfadbg_print_safe(runtime_core, "Kernel : core %p stopping\n", this); 322 328 } 323 329 … … 326 332 V( this->terminated ); 327 333 328 __cfa abi_dbg_print_safe("Kernel : core %p terminated\n", this);334 __cfadbg_print_safe(runtime_core, "Kernel : core %p terminated\n", this); 329 335 330 336 // HACK : the coroutine context switch expects this_thread to be set … … 471 477 472 478 //We now have a proper context from which to schedule threads 473 __cfa abi_dbg_print_safe("Kernel : core %p created (%p, %p)\n", proc, &proc->runner, &ctx);479 __cfadbg_print_safe(runtime_core, "Kernel : core %p created (%p, %p)\n", proc, &proc->runner, &ctx); 474 480 475 481 // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't … … 482 488 483 489 // Main routine of the core returned, the core is now fully terminated 484 __cfa abi_dbg_print_safe("Kernel : core %p main ended (%p)\n", proc, &proc->runner);490 __cfadbg_print_safe(runtime_core, "Kernel : core %p main ended (%p)\n", proc, &proc->runner); 485 491 486 492 return 0p; … … 713 719 static void __kernel_startup(void) { 714 720 verify( ! kernelTLS.preemption_state.enabled ); 715 __cfa abi_dbg_print_safe("Kernel : Starting\n");721 __cfadbg_print_safe(runtime_core, "Kernel : Starting\n"); 716 722 717 723 __page_size = sysconf( _SC_PAGESIZE ); … … 724 730 (*mainCluster){"Main Cluster"}; 725 731 726 __cfa abi_dbg_print_safe("Kernel : Main cluster ready\n");732 __cfadbg_print_safe(runtime_core, "Kernel : Main cluster ready\n"); 727 733 728 734 // Start by initializing the main thread … … 734 740 (*mainThread){ &info }; 735 741 736 __cfa abi_dbg_print_safe("Kernel : Main thread ready\n");742 __cfadbg_print_safe(runtime_core, "Kernel : Main thread ready\n"); 737 743 738 744 … … 755 761 756 762 runner{ &this }; 757 __cfa abi_dbg_print_safe("Kernel : constructed main processor context %p\n", &runner);763 __cfadbg_print_safe(runtime_core, "Kernel : constructed main processor context %p\n", &runner); 758 764 } 759 765 … … 780 786 781 787 782 783 788 // THE SYSTEM IS NOW COMPLETELY RUNNING 784 __cfaabi_dbg_print_safe("Kernel : Started\n--------------------------------------------------\n\n"); 789 790 791 // Now that the system is up, finish creating systems that need threading 792 __kernel_io_finish_start( *mainCluster ); 793 794 795 __cfadbg_print_safe(runtime_core, "Kernel : Started\n--------------------------------------------------\n\n"); 785 796 786 797 verify( ! kernelTLS.preemption_state.enabled ); … … 790 801 791 802 static void __kernel_shutdown(void) { 792 __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n"); 803 //Before we start shutting things down, wait for systems that need threading to shutdown 804 __kernel_io_prepare_stop( *mainCluster ); 793 805 794 806 /* paranoid */ verify( TL_GET( preemption_state.enabled ) ); 795 807 disable_interrupts(); 796 808 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 809 810 __cfadbg_print_safe(runtime_core, "\n--------------------------------------------------\nKernel : Shutting down\n"); 797 811 798 812 // SKULLDUGGERY: Notify the mainProcessor it needs to terminates. … … 822 836 ^(__cfa_dbg_global_clusters.lock){}; 823 837 824 __cfa abi_dbg_print_safe("Kernel : Shutdown complete\n");838 __cfadbg_print_safe(runtime_core, "Kernel : Shutdown complete\n"); 825 839 } 826 840 … … 847 861 848 862 // We are ready to sleep 849 __cfa abi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);863 __cfadbg_print_safe(runtime_core, "Kernel : Processor %p ready to sleep\n", this); 850 864 wait( idle ); 851 865 852 866 // We have woken up 853 __cfa abi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);867 __cfadbg_print_safe(runtime_core, "Kernel : Processor %p woke up and ready to run\n", this); 854 868 855 869 // Get ourself off the idle list … … 867 881 static bool __wake_one(cluster * this, __attribute__((unused)) bool force) { 868 882 // if we don't want to force check if we know it's false 869 if( !this->idles.head && !force ) return false;883 // if( !this->idles.head && !force ) return false; 870 884 871 885 // First, lock the cluster idle … … 880 894 881 895 // Wake them up 896 __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this->idles.head); 882 897 post( this->idles.head->idle ); 883 898 … … 889 904 // Unconditionnaly wake a thread 890 905 static bool __wake_proc(processor * this) { 906 __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this); 891 907 return post( this->idle ); 892 908 } … … 1000 1016 // make new owner 1001 1017 unpark( thrd __cfaabi_dbg_ctx2 ); 1018 1019 return thrd != 0p; 1020 } 1021 1022 bool V(semaphore & this, unsigned diff) with( this ) { 1023 $thread * thrd = 0p; 1024 lock( lock __cfaabi_dbg_ctx2 ); 1025 int release = max(-count, (int)diff); 1026 count += diff; 1027 for(release) { 1028 unpark( pop_head( waiting ) __cfaabi_dbg_ctx2 ); 1029 } 1030 1031 unlock( lock ); 1002 1032 1003 1033 return thrd != 0p; -
libcfa/src/concurrency/kernel.hfa
r6091b88a rd45ed83 40 40 void P (semaphore & this); 41 41 bool V (semaphore & this); 42 bool V (semaphore & this, unsigned count); 42 43 43 44 … … 135 136 // Like head/tail but not seen by the kernel 136 137 volatile uint32_t alloc; 138 volatile uint32_t ready; 137 139 138 140 __spinlock_t lock; … … 144 146 void * ring_ptr; 145 147 size_t ring_sz; 148 149 // Statistics 150 #if !defined(__CFA_NO_STATISTICS__) 151 struct { 152 struct { 153 unsigned long long int val; 154 unsigned long long int cnt; 155 } submit_avg; 156 } stats; 157 #endif 146 158 }; 147 159 … … 164 176 void * ring_ptr; 165 177 size_t ring_sz; 166 }; 178 179 // Statistics 180 #if !defined(__CFA_NO_STATISTICS__) 181 struct { 182 struct { 183 unsigned long long int val; 184 unsigned long long int cnt; 185 } completed_avg; 186 } stats; 187 #endif 188 }; 189 190 #if defined(__CFA_IO_POLLING_USER__) 191 struct __io_poller_fast { 192 struct io_ring * ring; 193 $thread thrd; 194 }; 195 #endif 167 196 168 197 struct io_ring { … … 171 200 uint32_t flags; 172 201 int fd; 173 pthread_t poller; 174 void * stack; 202 semaphore submit; 175 203 volatile bool done; 176 semaphore submit; 204 struct { 205 struct { 206 void * stack; 207 pthread_t kthrd; 208 } slow; 209 #if defined(__CFA_IO_POLLING_USER__) 210 __io_poller_fast fast; 211 __bin_sem_t sem; 212 #endif 213 } poller; 177 214 }; 178 215 #endif … … 213 250 struct io_ring io; 214 251 #endif 252 253 #if !defined(__CFA_NO_STATISTICS__) 254 bool print_stats; 255 #endif 215 256 }; 216 257 extern Duration default_preemption(); … … 227 268 static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE 228 269 static inline struct cluster * active_cluster () { return TL_GET( this_processor )->cltr; } 270 271 #if !defined(__CFA_NO_STATISTICS__) 272 static inline void print_stats_at_exit( cluster & this ) { 273 this.print_stats = true; 274 } 275 #endif 229 276 230 277 // Local Variables: // -
libcfa/src/concurrency/kernel_private.hfa
r6091b88a rd45ed83 75 75 //----------------------------------------------------------------------------- 76 76 // I/O 77 void __kernel_io_startup ( cluster & ); 78 void __kernel_io_shutdown( cluster & ); 77 void __kernel_io_startup ( cluster &, bool ); 78 void __kernel_io_finish_start( cluster & ); 79 void __kernel_io_prepare_stop( cluster & ); 80 void __kernel_io_shutdown ( cluster &, bool ); 79 81 80 82 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/preemption.cfa
r6091b88a rd45ed83 43 43 // FwdDeclarations : Signal handlers 44 44 static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ ); 45 static void sigHandler_alarm ( __CFA_SIGPARMS__ ); 45 46 static void sigHandler_segv ( __CFA_SIGPARMS__ ); 46 47 static void sigHandler_ill ( __CFA_SIGPARMS__ ); … … 256 257 257 258 if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) { 258 abort( "internal error, pthread_sigmask" );259 abort( "internal error, pthread_sigmask" ); 259 260 } 260 261 } … … 303 304 // Setup proper signal handlers 304 305 __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler 306 __cfaabi_sigaction( SIGALRM, sigHandler_alarm , SA_SIGINFO | SA_RESTART ); // debug handler 305 307 306 308 signal_block( SIGALRM ); … … 394 396 395 397 force_yield( __ALARM_PREEMPTION ); // Do the actual __cfactx_switch 398 } 399 400 static void sigHandler_alarm( __CFA_SIGPARMS__ ) { 401 abort("SIGALRM should never reach the signal handler"); 396 402 } 397 403 -
tools/gdb/utils-gdb.py
r6091b88a rd45ed83 26 26 27 27 class ThreadInfo: 28 tid = 029 cluster = None30 value = None31 32 def __init__(self, cluster, value):33 self.cluster = cluster34 self.value = value35 36 def is_system(self):37 return False28 tid = 0 29 cluster = None 30 value = None 31 32 def __init__(self, cluster, value): 33 self.cluster = cluster 34 self.value = value 35 36 def is_system(self): 37 return False 38 38 39 39 # A named tuple representing information about a stack … … 51 51 52 52 def is_cforall(): 53 return True53 return True 54 54 55 55 def get_cfa_types(): 56 # GDB types for various structures/types in CFA57 return CfaTypes(cluster_ptr = gdb.lookup_type('struct cluster').pointer(),58 processor_ptr = gdb.lookup_type('struct processor').pointer(),59 thread_ptr = gdb.lookup_type('struct $thread').pointer(),60 int_ptr = gdb.lookup_type('int').pointer(),61 thread_state = gdb.lookup_type('enum coroutine_state'))56 # GDB types for various structures/types in CFA 57 return CfaTypes(cluster_ptr = gdb.lookup_type('struct cluster').pointer(), 58 processor_ptr = gdb.lookup_type('struct processor').pointer(), 59 thread_ptr = gdb.lookup_type('struct $thread').pointer(), 60 int_ptr = gdb.lookup_type('int').pointer(), 61 thread_state = gdb.lookup_type('enum coroutine_state')) 62 62 63 63 def get_addr(addr): 64 """65 NOTE: sketchy solution to retrieve address. There is a better solution...66 @addr: str of an address that can be in a format 0xfffff <type of the object67 at this address>68 Return: str of just the address69 """70 str_addr = str(addr)71 ending_addr_index = str_addr.find('<')72 if ending_addr_index == -1:73 return str(addr)74 return str_addr[:ending_addr_index].strip()64 """ 65 NOTE: sketchy solution to retrieve address. There is a better solution... 66 @addr: str of an address that can be in a format 0xfffff <type of the object 67 at this address> 68 Return: str of just the address 69 """ 70 str_addr = str(addr) 71 ending_addr_index = str_addr.find('<') 72 if ending_addr_index == -1: 73 return str(addr) 74 return str_addr[:ending_addr_index].strip() 75 75 76 76 def print_usage(obj): 77 print(obj.__doc__)77 print(obj.__doc__) 78 78 79 79 def parse(args): 80 """81 Split the argument list in string format, where each argument is separated82 by whitespace delimiter, to a list of arguments like argv83 @args: str of arguments84 Return:85 [] if args is an empty string86 list if args is not empty87 """88 # parse the string format of arguments and return a list of arguments89 argv = args.split(' ')90 if len(argv) == 1 and argv[0] == '':91 return []92 return argv80 """ 81 Split the argument list in string format, where each argument is separated 82 by whitespace delimiter, to a list of arguments like argv 83 @args: str of arguments 84 Return: 85 [] if args is an empty string 86 list if args is not empty 87 """ 88 # parse the string format of arguments and return a list of arguments 89 argv = args.split(' ') 90 if len(argv) == 1 and argv[0] == '': 91 return [] 92 return argv 93 93 94 94 def get_cluster_root(): 95 """96 Return: gdb.Value of globalClusters.root (is an address)97 """98 cluster_root = gdb.parse_and_eval('_X11mainClusterPS7cluster_1')99 if cluster_root.address == 0x0:100 print('No clusters, program terminated')101 return cluster_root95 """ 96 Return: gdb.Value of globalClusters.root (is an address) 97 """ 98 cluster_root = gdb.parse_and_eval('_X11mainClusterPS7cluster_1') 99 if cluster_root.address == 0x0: 100 print('No clusters, program terminated') 101 return cluster_root 102 102 103 103 def find_curr_thread(): 104 # btstr = gdb.execute('bt', to_string = True).splitlines() 105 # if len(btstr) == 0: 106 # print('error') 107 # return None 108 # return btstr[0].split('this=',1)[1].split(',')[0].split(')')[0] 109 return None 104 # btstr = gdb.execute('bt', to_string = True).splitlines() 105 # if len(btstr) == 0: 106 # print('error') 107 # return None 108 # return btstr[0].split('this=',1)[1].split(',')[0].split(')')[0] 109 return None 110 111 def all_clusters(): 112 if not is_cforall(): 113 return None 114 115 cluster_root = get_cluster_root() 116 if cluster_root.address == 0x0: 117 return 118 119 curr = cluster_root 120 ret = [curr] 121 122 while True: 123 curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1'] 124 if curr == cluster_root: 125 break 126 127 ret.append(curr) 128 129 return ret 130 110 131 111 132 def lookup_cluster(name = None): 112 """113 Look up a cluster given its ID114 @name: str115 Return: gdb.Value116 """117 if not is_cforall():118 return None119 120 root = get_cluster_root()121 if root.address == 0x0:122 return None123 124 if not name:125 return root126 127 # lookup for the task associated with the id128 cluster = None129 curr = root130 while True:131 if curr['_X4namePKc_1'].string() == name:132 cluster = curr.address133 break134 curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1']135 if curr == root or curr == 0x0:136 break137 138 if not cluster:139 print("Cannot find a cluster with the name: {}.".format(name))140 return None141 142 return cluster133 """ 134 Look up a cluster given its ID 135 @name: str 136 Return: gdb.Value 137 """ 138 if not is_cforall(): 139 return None 140 141 root = get_cluster_root() 142 if root.address == 0x0: 143 return None 144 145 if not name: 146 return root 147 148 # lookup for the task associated with the id 149 cluster = None 150 curr = root 151 while True: 152 if curr['_X4namePKc_1'].string() == name: 153 cluster = curr.address 154 break 155 curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1'] 156 if curr == root or curr == 0x0: 157 break 158 159 if not cluster: 160 print("Cannot find a cluster with the name: {}.".format(name)) 161 return None 162 163 return cluster 143 164 144 165 def lookup_threads_by_cluster(cluster): 145 # Iterate through a circular linked list of threads and accumulate them in an array146 threads = []147 148 cfa_t = get_cfa_types()149 root = cluster['_X7threadsS8__dllist_S7$thread__1']['_X4headPY15__TYPE_generic__1'].cast(cfa_t.thread_ptr)150 151 if root == 0x0 or root.address == 0x0:152 print('There are no tasks for cluster: {}'.format(cluster))153 return threads154 155 curr = root156 tid = 0157 sid = -1158 159 while True:160 t = ThreadInfo(cluster, curr)161 if t.is_system():162 t.tid = sid163 sid -= 1164 else:165 t.tid = tid166 tid += 1167 168 threads.append(t)169 170 curr = curr['node']['next']171 if curr == root or curr == 0x0:172 break173 174 return threads166 # Iterate through a circular linked list of threads and accumulate them in an array 167 threads = [] 168 169 cfa_t = get_cfa_types() 170 root = cluster['_X7threadsS8__dllist_S7$thread__1']['_X4headPY15__TYPE_generic__1'].cast(cfa_t.thread_ptr) 171 172 if root == 0x0 or root.address == 0x0: 173 print('There are no tasks for cluster: {}'.format(cluster)) 174 return threads 175 176 curr = root 177 tid = 0 178 sid = -1 179 180 while True: 181 t = ThreadInfo(cluster, curr) 182 if t.is_system(): 183 t.tid = sid 184 sid -= 1 185 else: 186 t.tid = tid 187 tid += 1 188 189 threads.append(t) 190 191 curr = curr['node']['next'] 192 if curr == root or curr == 0x0: 193 break 194 195 return threads 175 196 176 197 def system_thread(thread): 177 return False198 return False 178 199 179 200 def adjust_stack(pc, fp, sp): 180 # pop sp, fp, pc from global stack181 gdb.execute('set $pc = {}'.format(pc))182 gdb.execute('set $rbp = {}'.format(fp))183 gdb.execute('set $sp = {}'.format(sp))201 # pop sp, fp, pc from global stack 202 gdb.execute('set $pc = {}'.format(pc)) 203 gdb.execute('set $rbp = {}'.format(fp)) 204 gdb.execute('set $sp = {}'.format(sp)) 184 205 185 206 ############################ COMMAND IMPLEMENTATION ######################### 186 207 187 208 class Clusters(gdb.Command): 188 """Cforall: Display currently known clusters209 """Cforall: Display currently known clusters 189 210 Usage: 190 info clusters : print out all the clusters211 info clusters : print out all the clusters 191 212 """ 192 213 193 def __init__(self): 194 super(Clusters, self).__init__('info clusters', gdb.COMMAND_USER) 195 196 def print_cluster(self, cluster_name, cluster_address): 197 print('{:>20} {:>20}'.format(cluster_name, cluster_address)) 198 199 #entry point from gdb 200 def invoke(self, arg, from_tty): 201 if not is_cforall(): 202 return 203 204 if arg: 205 print("info clusters does not take arguments") 206 print_usage(self) 207 return 208 209 cluster_root = get_cluster_root() 210 if cluster_root.address == 0x0: 211 return 212 213 curr = cluster_root 214 self.print_cluster('Name', 'Address') 215 216 while True: 217 self.print_cluster(curr['_X4namePKc_1'].string(), str(curr)) 218 curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1'] 219 if curr == cluster_root: 220 break 221 222 print("") 214 def __init__(self): 215 super(Clusters, self).__init__('info clusters', gdb.COMMAND_USER) 216 217 def print_cluster(self, cluster_name, cluster_address): 218 print('{:>20} {:>20}'.format(cluster_name, cluster_address)) 219 220 #entry point from gdb 221 def invoke(self, arg, from_tty): 222 if not is_cforall(): 223 return 224 225 if arg: 226 print("info clusters does not take arguments") 227 print_usage(self) 228 return 229 230 self.print_cluster('Name', 'Address') 231 232 for c in all_clusters(): 233 self.print_cluster(c['_X4namePKc_1'].string(), str(c)) 234 235 print("") 223 236 224 237 ############ 225 238 class Processors(gdb.Command): 226 """Cforall: Display currently known processors239 """Cforall: Display currently known processors 227 240 Usage: 228 info processors : print out all the processors in the Main Cluster 229 info processors <cluster_name> : print out all processors in a given cluster 241 info processors : print out all the processors in the Main Cluster 242 info processors all : print out all processors in all clusters 243 info processors <cluster_name> : print out all processors in a given cluster 230 244 """ 231 245 232 def __init__(self): 233 super(Processors, self).__init__('info processors', gdb.COMMAND_USER) 234 235 def print_processor(self, name, status, pending, address): 236 print('{:>20} {:>11} {:>13} {:>20}'.format(name, status, pending, address)) 237 238 def iterate_procs(self, root, active): 239 if root == 0x0: 240 return 241 242 cfa_t = get_cfa_types() 243 curr = root 244 245 while True: 246 processor = curr 247 should_stop = processor['_X12do_terminateVb_1'] 248 stop_count = processor['_X10terminatedS9semaphore_1']['_X5counti_1'] 249 if not should_stop: 250 status = 'Active' if active else 'Idle' 251 else: 252 status_str = 'Last Thread' if stop_count >= 0 else 'Terminating' 253 status = '{}({},{})'.format(status_str, should_stop, stop_count) 254 255 self.print_processor(processor['_X4namePKc_1'].string(), 256 status, str(processor['_X18pending_preemptionb_1']), str(processor) 257 ) 258 259 curr = curr['_X4nodeS28__processor____dbg_node_proc_1']['_X4nextPS9processor_1'] 260 261 if curr == root or curr == 0x0: 262 break 263 264 #entry point from gdb 265 def invoke(self, arg, from_tty): 266 if not is_cforall(): 267 return 268 269 cluster = lookup_cluster(arg if arg else None) 270 271 if not cluster: 272 print("No Cluster matching arguments found") 273 return 274 275 cfa_t = get_cfa_types() 276 print('Cluster: "{}"({})'.format(cluster['_X4namePKc_1'].string(), cluster.cast(cfa_t.cluster_ptr))) 277 278 active_root = cluster.cast(cfa_t.cluster_ptr) \ 279 ['_X5procsS8__dllist_S9processor__1'] \ 280 ['_X4headPY15__TYPE_generic__1'] \ 281 .cast(cfa_t.processor_ptr) 282 283 idle_root = cluster.cast(cfa_t.cluster_ptr) \ 284 ['_X5idlesS8__dllist_S9processor__1'] \ 285 ['_X4headPY15__TYPE_generic__1'] \ 286 .cast(cfa_t.processor_ptr) 287 288 if idle_root != 0x0 or active_root != 0x0: 289 self.print_processor('Name', 'Status', 'Pending Yield', 'Address') 290 self.iterate_procs(active_root, True) 291 self.iterate_procs(idle_root, False) 292 else: 293 print("No processors on cluster") 294 295 print() 246 def __init__(self): 247 super(Processors, self).__init__('info processors', gdb.COMMAND_USER) 248 249 def print_processor(self, name, status, pending, address): 250 print('{:>20} {:>11} {:>13} {:>20}'.format(name, status, pending, address)) 251 252 def iterate_procs(self, root, active): 253 if root == 0x0: 254 return 255 256 cfa_t = get_cfa_types() 257 curr = root 258 259 while True: 260 processor = curr 261 should_stop = processor['_X12do_terminateVb_1'] 262 stop_count = processor['_X10terminatedS9semaphore_1']['_X5counti_1'] 263 if not should_stop: 264 status = 'Active' if active else 'Idle' 265 else: 266 status_str = 'Last Thread' if stop_count >= 0 else 'Terminating' 267 status = '{}({},{})'.format(status_str, should_stop, stop_count) 268 269 self.print_processor(processor['_X4namePKc_1'].string(), 270 status, str(processor['_X18pending_preemptionb_1']), str(processor) 271 ) 272 273 curr = curr['_X4nodeS28__processor____dbg_node_proc_1']['_X4nextPS9processor_1'] 274 275 if curr == root or curr == 0x0: 276 break 277 278 #entry point from gdb 279 def invoke(self, arg, from_tty): 280 if not is_cforall(): 281 return 282 283 if not arg: 284 clusters = [lookup_cluster(None)] 285 elif arg == "all": 286 clusters = all_clusters() 287 else: 288 clusters = [lookup_cluster(arg)] 289 290 if not clusters: 291 print("No Cluster matching arguments found") 292 return 293 294 cfa_t = get_cfa_types() 295 for cluster in clusters: 296 print('Cluster: "{}"({})'.format(cluster['_X4namePKc_1'].string(), cluster.cast(cfa_t.cluster_ptr))) 297 298 active_root = cluster.cast(cfa_t.cluster_ptr) \ 299 ['_X5procsS8__dllist_S9processor__1'] \ 300 ['_X4headPY15__TYPE_generic__1'] \ 301 .cast(cfa_t.processor_ptr) 302 303 idle_root = cluster.cast(cfa_t.cluster_ptr) \ 304 ['_X5idlesS8__dllist_S9processor__1'] \ 305 ['_X4headPY15__TYPE_generic__1'] \ 306 .cast(cfa_t.processor_ptr) 307 308 if idle_root != 0x0 or active_root != 0x0: 309 self.print_processor('Name', 'Status', 'Pending Yield', 'Address') 310 self.iterate_procs(active_root, True) 311 self.iterate_procs(idle_root, False) 312 else: 313 print("No processors on cluster") 314 315 print() 296 316 297 317 ############ 298 318 class Threads(gdb.Command): 299 """Cforall: Display currently known threads319 """Cforall: Display currently known threads 300 320 Usage: 301 cfathreads : print Main Cluster threads, application threads only 302 cfathreads all : print all clusters, all threads 303 cfathreads <clusterName> : print cluster threads, application threads only 304 """ 305 def __init__(self): 306 # The first parameter of the line below is the name of the command. You 307 # can call it 'uc++ task' 308 super(Threads, self).__init__('info cfathreads', gdb.COMMAND_USER) 309 310 def print_formatted(self, marked, tid, name, state, address): 311 print('{:>1} {:>4} {:>20} {:>10} {:>20}'.format('*' if marked else ' ', tid, name, state, address)) 312 313 def print_thread(self, thread, tid, marked): 314 cfa_t = get_cfa_types() 315 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread)) 316 317 def print_formatted_cluster(self, str_format, cluster_name, cluster_addr): 318 print(str_format.format(cluster_name, cluster_addr)) 319 320 def print_threads_by_cluster(self, cluster, print_system = False): 321 # Iterate through a circular linked list of tasks and print out its 322 # name along with address associated to each cluster 323 threads = lookup_threads_by_cluster(cluster) 324 if not threads: 325 return 326 327 running_thread = find_curr_thread() 328 if running_thread is None: 329 print('Could not identify current thread') 330 331 self.print_formatted(False, '', 'Name', 'State', 'Address') 332 333 for t in threads: 334 if not t.is_system() or print_system: 335 self.print_thread(t.value, t.tid, t.value == running_thread if running_thread else False) 336 337 print() 338 339 def print_all_threads(self): 340 print("Not implemented") 341 342 def invoke(self, arg, from_tty): 343 """ 344 @arg: str 345 @from_tty: bool 346 """ 347 if not is_cforall(): 348 return 349 350 if not arg: 351 cluster = lookup_cluster() 352 if not cluster: 353 print("Could not find Main Cluster") 354 return 355 356 # only tasks and main 357 self.print_threads_by_cluster(cluster, False) 358 359 elif arg == 'all': 360 # all threads, all clusters 361 self.print_all_threads() 362 363 else: 364 cluster = lookup_cluster(arg) 365 if not cluster: 366 print("Could not find cluster '{}'".format(arg)) 367 return 368 369 # all tasks, specified cluster 370 self.print_threads_by_cluster(cluster, True) 321 cfathreads : print Main Cluster threads, application threads only 322 cfathreads all : print all clusters, all threads 323 cfathreads <clusterName> : print cluster threads, application threads only 324 """ 325 def __init__(self): 326 # The first parameter of the line below is the name of the command. You 327 # can call it 'uc++ task' 328 super(Threads, self).__init__('info cfathreads', gdb.COMMAND_USER) 329 330 def print_formatted(self, marked, tid, name, state, address): 331 print('{:>1} {:>4} {:>20} {:>10} {:>20}'.format('*' if marked else ' ', tid, name, state, address)) 332 333 def print_thread(self, thread, tid, marked): 334 cfa_t = get_cfa_types() 335 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread)) 336 337 def print_threads_by_cluster(self, cluster, print_system = False): 338 # Iterate through a circular linked list of tasks and print out its 339 # name along with address associated to each cluster 340 threads = lookup_threads_by_cluster(cluster) 341 if not threads: 342 return 343 344 running_thread = find_curr_thread() 345 if running_thread is None: 346 print('Could not identify current thread') 347 348 self.print_formatted(False, '', 'Name', 'State', 'Address') 349 350 for t in threads: 351 if not t.is_system() or print_system: 352 self.print_thread(t.value, t.tid, t.value == running_thread if running_thread else False) 353 354 print() 355 356 def print_all_threads(self): 357 for c in all_clusters(): 358 self.print_threads_by_cluster(c, False) 359 360 def invoke(self, arg, from_tty): 361 """ 362 @arg: str 363 @from_tty: bool 364 """ 365 if not is_cforall(): 366 return 367 368 if not arg: 369 cluster = lookup_cluster() 370 if not cluster: 371 print("Could not find Main Cluster") 372 return 373 374 # only tasks and main 375 self.print_threads_by_cluster(cluster, False) 376 377 elif arg == 'all': 378 # all threads, all clusters 379 self.print_all_threads() 380 381 else: 382 cluster = lookup_cluster(arg) 383 if not cluster: 384 print("Could not find cluster '{}'".format(arg)) 385 return 386 387 # all tasks, specified cluster 388 self.print_threads_by_cluster(cluster, True) 371 389 372 390 373 391 ############ 374 392 class Thread(gdb.Command): 375 def __init__(self): 376 # The first parameter of the line below is the name of the command. You 377 # can call it 'uc++ task' 378 super(Threads, self).__init__('cfathread', gdb.COMMAND_USER) 379 380 def print_usage(self): 381 print_usage(""" 382 cfathread : print userCluster tasks, application tasks only 383 cfathread <clusterName> : print cluster tasks, application tasks only 384 cfathread all : print all clusters, all tasks 385 cfathread <id> : switch stack to thread id on userCluster 386 cfathread 0x<address> : switch stack to thread on any cluster 387 cfathread <id> <clusterName> : switch stack to thread on specified cluster 388 """) 389 390 ############################ AUXILIARY FUNCTIONS ######################### 391 392 def print_formatted(self, marked, tid, name, state, address): 393 print('{:>1} {:>4} {:>20} {:>10} {:>20}'.format('*' if marked else ' ', tid, name, state, address)) 394 395 def print_thread(self, thread, tid, marked): 396 cfa_t = get_cfa_types() 397 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread)) 398 399 def print_formatted_cluster(self, str_format, cluster_name, cluster_addr): 400 print(str_format.format(cluster_name, cluster_addr)) 401 402 def print_tasks_by_cluster_all(self, cluster_address): 403 """ 404 Display a list of all info about all available tasks on a particular cluster 405 @cluster_address: gdb.Value 406 """ 407 cluster_address = cluster_address.cast(uCPPTypes.ucluster_ptr) 408 task_root = cluster_address['tasksOnCluster']['root'] 409 410 if task_root == 0x0 or task_root.address == 0x0: 411 print('There are no tasks for cluster at address: {}'.format(cluster_address)) 412 return 413 414 self.print_formatted_task('', 'Task Name', 'Address', 'State') 415 curr = task_root 416 task_id = 0 417 systask_id = -1 418 419 breakpoint_addr = self.find_curr_breakpoint_addr() 420 if breakpoint_addr is None: 421 return 422 423 while True: 424 global SysTask_Name 425 if (curr['task_']['name'].string() in SysTask_Name): 426 self.print_formatted_tasks(systask_id, breakpoint_addr, curr) 427 systask_id -= 1 428 else: 429 self.print_formatted_tasks(task_id, breakpoint_addr, curr) 430 task_id += 1 431 432 curr = curr['next'].cast(uCPPTypes.uBaseTaskDL_ptr_type) 433 if curr == task_root: 434 break 435 436 def print_tasks_by_cluster_address_all(self, cluster_address): 437 """ 438 Display a list of all info about all available tasks on a particular cluster 439 @cluster_address: str 440 """ 441 # Iterate through a circular linked list of tasks and print out its 442 # name along with address associated to each cluster 443 444 # convert hex string to hex number 445 try: 446 hex_addr = int(cluster_address, 16) 447 except: 448 self.print_usage() 449 return 450 451 cluster_address = gdb.Value(hex_addr) 452 if not self.print_tasks_by_cluster_all(cluster_address): 453 return 454 455 def print_threads_by_cluster(self, cluster, print_system = False): 456 """ 457 Display a list of limited info about all available threads on a particular cluster 458 @cluster: str 459 @print_system: bool 460 """ 461 # Iterate through a circular linked list of tasks and print out its 462 # name along with address associated to each cluster 463 464 threads = self.threads_by_cluster(cluster) 465 if not threads: 466 return 467 468 running_thread = self.find_curr_thread() 469 if running_thread is None: 470 print('Could not identify current thread') 471 472 self.print_formatted(False, '', 'Name', 'State', 'Address') 473 474 for t in threads: 475 if not t.is_system() or print_system: 476 self.print_thread(t.value, t.tid, t.value == running_thread if running_thread else False) 477 478 print() 479 480 ############################ COMMAND FUNCTIONS ######################### 481 482 def print_all_threads(self): 483 """Iterate through each cluster, iterate through all tasks and print out info about all the tasks 484 in those clusters""" 485 uCPPTypes = None 486 try: 487 uCPPTypes = get_uCPP_types() 488 except gdb.error: 489 print(not_supported_error_msg) 490 print(gdb.error) 491 return 492 493 cluster_root = get_cluster_root() 494 if cluster_root.address == 0x0: 495 return 496 497 curr = cluster_root 498 self.print_formatted_cluster(self.cluster_str_format, 'Cluster Name', 'Address') 499 500 while True: 501 addr = str(curr['cluster_'].reference_value())[1:] 502 self.print_formatted_cluster(self.cluster_str_format, curr['cluster_']['name'].string(), addr) 503 504 self.print_tasks_by_cluster_address_all(addr) 505 curr = curr['next'].cast(uCPPTypes.uClusterDL_ptr_type) 506 if curr == cluster_root: 507 break 508 509 def switchto(self, thread): 510 """Change to a new task by switching to a different stack and manually 511 adjusting sp, fp and pc 512 @task_address: str 513 2 supported format: 514 in hex format 515 <hex_address>: literal hexadecimal address 516 Ex: 0xffffff 517 in name of the pointer to the task 518 "task_name": pointer of the variable name of the cluster 519 Ex: T* s -> task_name = s 520 Return: gdb.value of the cluster's address 521 """ 522 # uCPPTypes = None 523 # try: 524 # uCPPTypes = get_uCPP_types() 525 # except gdb.error: 526 # print(not_supported_error_msg) 527 # print(gdb.error) 528 # return 529 530 # # Task address has a format "task_address", which implies that it is the 531 # # name of the variable, and it needs to be evaluated 532 # if task_address.startswith('"') and task_address.endswith('"'): 533 # task = gdb.parse_and_eval(task_address.replace('"', '')) 534 # else: 535 # # Task address format does not include the quotation marks, which implies 536 # # that it is a hex address 537 # # convert hex string to hex number 538 # try: 539 # hex_addr = int(task_address, 16) 540 # except: 541 # self.print_usage() 542 # return 543 # task_address = gdb.Value(hex_addr) 544 # task = task_address.cast(uCPPTypes.uBaseTask_ptr_type) 545 try: 546 if not gdb.lookup_symbol('__cfactx_switch'): 547 print('__cfactx_switch symbol is unavailable') 548 return 549 except: 550 print('here 3') 551 552 cfa_t = get_cfa_types() 553 554 state = thread['state'].cast(cfa_t.thread_state) 555 try: 556 if state == gdb.parse_and_eval('Halted'): 557 print('Cannot switch to a terminated thread') 558 return 559 560 if state == gdb.parse_and_eval('Start'): 561 print('Cannjot switch to a thread not yet run') 562 return 563 except: 564 print("here 2") 565 return 566 567 568 context = thread['context'] 569 570 # lookup for sp,fp and uSwitch 571 xsp = context['SP'] + 48 572 xfp = context['FP'] 573 574 # convert string so we can strip out the address 575 try: 576 xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address + 28) 577 except: 578 print("here") 579 return 580 581 # must be at frame 0 to set pc register 582 gdb.execute('select-frame 0') 583 584 # push sp, fp, pc into a global stack 585 global STACK 586 sp = gdb.parse_and_eval('$sp') 587 fp = gdb.parse_and_eval('$fp') 588 pc = gdb.parse_and_eval('$pc') 589 stack_info = StackInfo(sp = sp, fp = fp, pc = pc) 590 STACK.append(stack_info) 591 592 # update registers for new task 593 print('switching to ') 594 gdb.execute('set $rsp={}'.format(xsp)) 595 gdb.execute('set $rbp={}'.format(xfp)) 596 gdb.execute('set $pc={}'.format(xpc)) 597 598 def find_matching_gdb_thread_id(): 599 """ 600 Parse the str from info thread to get the number 601 """ 602 info_thread_str = gdb.execute('info thread', to_string=True).splitlines() 603 for thread_str in info_thread_str: 604 if thread_str.find('this={}'.format(task)) != -1: 605 thread_id_pattern = r'^\*?\s+(\d+)\s+Thread' 606 # retrive gdb thread id 607 return re.match(thread_id_pattern, thread_str).group(1) 608 609 # check if the task is running or not 610 if task_state == gdb.parse_and_eval('uBaseTask::Running'): 611 # find the equivalent thread from info thread 612 gdb_thread_id = find_matching_gdb_thread_id() 613 if gdb_thread_id is None: 614 print('cannot find the thread id to switch to') 615 return 616 # switch to that thread based using thread command 617 gdb.execute('thread {}'.format(gdb_thread_id)) 618 619 def switchto_id(self, tid, cluster): 620 """ 621 @cluster: cluster object 622 @tid: int 623 """ 624 threads = self.threads_by_cluster( cluster ) 625 626 for t in threads: 627 if t.tid == tid: 628 self.switchto(t.value) 629 return 630 631 print("Cound not find thread by id '{}'".format(tid)) 632 633 def invoke(self, arg, from_tty): 634 """ 635 @arg: str 636 @from_tty: bool 637 """ 638 if not is_cforall(): 639 return 640 641 argv = parse(arg) 642 print(argv) 643 if len(argv) == 0: 644 """ 645 Iterate only Main Thread, print only tasks and main 646 """ 647 cluster = lookup_cluster() 648 if not cluster: 649 print("Could not find Main Cluster") 650 return 651 652 # only tasks and main 653 self.print_threads_by_cluster(cluster, False) 654 655 elif len(argv) == 1: 656 if argv[0] == 'help': 657 self.print_usage() 658 # push task 659 elif argv[0].isdigit(): 660 cluster = lookup_cluster() 661 if not cluster: 662 print("Could not find Main Cluster") 663 return 664 665 try: 666 tid = int(argv[0]) 667 except: 668 print("'{}' not a valid thread id".format(argv[0])) 669 self.print_usage() 670 return 671 672 # by id, userCluster 673 self.switchto_id(tid, cluster) 674 675 elif argv[0].startswith('0x') or argv[0].startswith('0X'): 676 self.switchto(argv[0]) # by address, any cluster 677 # print tasks 678 elif argv[0] == 'all': 679 self.print_all_threads() # all tasks, all clusters 680 else: 681 """ 682 Print out all the tasks available in the specified cluster 683 @cluster_name: str 684 """ 685 print("cfathread by name") 686 cluster = lookup_cluster(argv[0]) 687 if not cluster: 688 return 689 690 # all tasks, specified cluster 691 self.print_threads_by_cluster(cluster, True) 692 693 elif len(argv) == 2: 694 # push task 695 self.pushtask_by_id(argv[0], argv[1]) # by id, specified cluster 696 else: 697 print('Invalid arguments') 698 self.print_usage() 393 """Cforall: Switch to specified user threads 394 Usage: 395 cfathread <id> : switch stack to thread id on main cluster 396 cfathread 0x<address> : switch stack to thread on any cluster 397 cfathread <id> <clusterName> : switch stack to thread on specified cluster 398 """ 399 def __init__(self): 400 # The first parameter of the line below is the name of the command. You 401 # can call it 'uc++ task' 402 super(Thread, self).__init__('cfathread', gdb.COMMAND_USER) 403 404 ############################ AUXILIARY FUNCTIONS ######################### 405 406 def switchto(self, thread): 407 """Change to a new task by switching to a different stack and manually 408 adjusting sp, fp and pc 409 @task_address: str 410 2 supported format: 411 in hex format 412 <hex_address>: literal hexadecimal address 413 Ex: 0xffffff 414 in name of the pointer to the task 415 "task_name": pointer of the variable name of the cluster 416 Ex: T* s -> task_name = s 417 Return: gdb.value of the cluster's address 418 """ 419 try: 420 if not gdb.lookup_symbol('__cfactx_switch'): 421 print('__cfactx_switch symbol is unavailable') 422 return 423 except: 424 print('here 3') 425 426 cfa_t = get_cfa_types() 427 428 state = thread['state'].cast(cfa_t.thread_state) 429 try: 430 if state == gdb.parse_and_eval('Halted'): 431 print('Cannot switch to a terminated thread') 432 return 433 434 if state == gdb.parse_and_eval('Start'): 435 print('Cannjot switch to a thread not yet run') 436 return 437 except: 438 print("here 2") 439 return 440 441 442 context = thread['context'] 443 444 # lookup for sp,fp and uSwitch 445 xsp = context['SP'] + 48 446 xfp = context['FP'] 447 448 # convert string so we can strip out the address 449 try: 450 xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address + 28) 451 except: 452 print("here") 453 return 454 455 # must be at frame 0 to set pc register 456 gdb.execute('select-frame 0') 457 458 # push sp, fp, pc into a global stack 459 global STACK 460 sp = gdb.parse_and_eval('$sp') 461 fp = gdb.parse_and_eval('$fp') 462 pc = gdb.parse_and_eval('$pc') 463 stack_info = StackInfo(sp = sp, fp = fp, pc = pc) 464 STACK.append(stack_info) 465 466 # update registers for new task 467 print('switching to ') 468 gdb.execute('set $rsp={}'.format(xsp)) 469 gdb.execute('set $rbp={}'.format(xfp)) 470 gdb.execute('set $pc={}'.format(xpc)) 471 472 def find_matching_gdb_thread_id(): 473 """ 474 Parse the str from info thread to get the number 475 """ 476 info_thread_str = gdb.execute('info thread', to_string=True).splitlines() 477 for thread_str in info_thread_str: 478 if thread_str.find('this={}'.format(task)) != -1: 479 thread_id_pattern = r'^\*?\s+(\d+)\s+Thread' 480 # retrive gdb thread id 481 return re.match(thread_id_pattern, thread_str).group(1) 482 483 # check if the task is running or not 484 if task_state == gdb.parse_and_eval('uBaseTask::Running'): 485 # find the equivalent thread from info thread 486 gdb_thread_id = find_matching_gdb_thread_id() 487 if gdb_thread_id is None: 488 print('cannot find the thread id to switch to') 489 return 490 # switch to that thread based using thread command 491 gdb.execute('thread {}'.format(gdb_thread_id)) 492 493 def switchto_id(self, tid, cluster): 494 """ 495 @cluster: cluster object 496 @tid: int 497 """ 498 threads = lookup_threads_by_cluster( cluster ) 499 500 for t in threads: 501 if t.tid == tid: 502 self.switchto(t.value) 503 return 504 505 print("Cound not find thread by id '{}'".format(tid)) 506 507 def invoke(self, arg, from_tty): 508 """ 509 @arg: str 510 @from_tty: bool 511 """ 512 if not is_cforall(): 513 return 514 515 argv = parse(arg) 516 print(argv) 517 if argv[0].isdigit(): 518 cname = " ".join(argv[1:]) if len(argv) > 1 else None 519 cluster = lookup_cluster(cname) 520 if not cluster: 521 print("Could not find cluster '{}'".format(cname if cname else "Main Cluster")) 522 return 523 524 try: 525 tid = int(argv[0]) 526 except: 527 print("'{}' not a valid thread id".format(argv[0])) 528 print_usage(self) 529 return 530 531 # by id, userCluster 532 self.switchto_id(tid, cluster) 533 534 elif argv[0].startswith('0x') or argv[0].startswith('0X'): 535 self.switchto(argv[0]) # by address, any cluster 699 536 700 537 ############ 701 538 class PrevThread(gdb.Command): 702 """Switch back to previous task on the stack"""703 usage_msg = 'prevtask'704 705 def __init__(self):706 super(PrevThread, self).__init__('prevtask', gdb.COMMAND_USER)707 708 def invoke(self, arg, from_tty):709 """710 @arg: str711 @from_tty: bool712 """713 global STACK714 if len(STACK) != 0:715 # must be at frame 0 to set pc register716 gdb.execute('select-frame 0')717 718 # pop stack719 stack_info = STACK.pop()720 pc = get_addr(stack_info.pc)721 sp = stack_info.sp722 fp = stack_info.fp723 724 # pop sp, fp, pc from global stack725 adjust_stack(pc, fp, sp)726 727 # must be at C++ frame to access C++ vars728 gdb.execute('frame 1')729 else:730 print('empty stack')539 """Switch back to previous task on the stack""" 540 usage_msg = 'prevtask' 541 542 def __init__(self): 543 super(PrevThread, self).__init__('prevtask', gdb.COMMAND_USER) 544 545 def invoke(self, arg, from_tty): 546 """ 547 @arg: str 548 @from_tty: bool 549 """ 550 global STACK 551 if len(STACK) != 0: 552 # must be at frame 0 to set pc register 553 gdb.execute('select-frame 0') 554 555 # pop stack 556 stack_info = STACK.pop() 557 pc = get_addr(stack_info.pc) 558 sp = stack_info.sp 559 fp = stack_info.fp 560 561 # pop sp, fp, pc from global stack 562 adjust_stack(pc, fp, sp) 563 564 # must be at C++ frame to access C++ vars 565 gdb.execute('frame 1') 566 else: 567 print('empty stack') 731 568 732 569 class ResetOriginFrame(gdb.Command): 733 """Reset to the origin frame prior to continue execution again"""734 usage_msg = 'resetOriginFrame'735 def __init__(self):736 super(ResetOriginFrame, self).__init__('reset', gdb.COMMAND_USER)737 738 def invoke(self, arg, from_tty):739 """740 @arg: str741 @from_tty: bool742 """743 global STACK744 if len(STACK) != 0:745 stack_info = STACK.pop(0)746 STACK.clear()747 pc = get_addr(stack_info.pc)748 sp = stack_info.sp749 fp = stack_info.fp750 751 # pop sp, fp, pc from global stack752 adjust_stack(pc, fp, sp)753 754 # must be at C++ frame to access C++ vars755 gdb.execute('frame 1')756 #else:757 #print('reset: empty stack') #probably does not have to print msg570 """Reset to the origin frame prior to continue execution again""" 571 usage_msg = 'resetOriginFrame' 572 def __init__(self): 573 super(ResetOriginFrame, self).__init__('reset', gdb.COMMAND_USER) 574 575 def invoke(self, arg, from_tty): 576 """ 577 @arg: str 578 @from_tty: bool 579 """ 580 global STACK 581 if len(STACK) != 0: 582 stack_info = STACK.pop(0) 583 STACK.clear() 584 pc = get_addr(stack_info.pc) 585 sp = stack_info.sp 586 fp = stack_info.fp 587 588 # pop sp, fp, pc from global stack 589 adjust_stack(pc, fp, sp) 590 591 # must be at C++ frame to access C++ vars 592 gdb.execute('frame 1') 593 #else: 594 #print('reset: empty stack') #probably does not have to print msg 758 595 759 596 Clusters() … … 762 599 PrevThread() 763 600 Threads() 601 Thread() 764 602 765 603 # Local Variables: #
Note:
See TracChangeset
for help on using the changeset viewer.