Changes in / [6091b88a:d45ed83]
- Files:
-
- 1 added
- 11 edited
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 650 651 652 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 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 29 30 31 32 33 34 35 36 37 28 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 53 return True 54 54 55 55 def get_cfa_types(): 56 57 58 59 60 61 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 66 67 68 69 70 71 72 73 74 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 77 print(obj.__doc__) 78 78 79 79 def parse(args): 80 81 82 83 84 85 86 87 88 89 90 91 92 80 """ 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 97 98 99 100 101 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_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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 133 """ 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 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 166 # 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 198 return False 178 199 179 200 def adjust_stack(pc, fp, sp): 180 181 182 183 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 209 """Cforall: Display currently known clusters 189 210 Usage: 190 211 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 239 """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 319 """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 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 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 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 570 """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.