Changes in / [d45ed83:6091b88a]


Ignore:
Files:
1 deleted
11 edited

Legend:

Unmodified
Added
Removed
  • benchmark/io/readv.cfa

    rd45ed83 r6091b88a  
    1717#include <time.hfa>
    1818
    19 #if !defined(HAVE_LINUX_IO_URING_H)
    20 #warning no io uring
    21 #endif
    22 
    2319extern bool traceHeapOn();
    24 extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
     20extern ssize_t async_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
    2521
    2622int fd;
     
    3026unsigned long int buflen = 50;
    3127
    32 cluster * the_cluster;
    33 
    3428thread 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 
    4729void main( Reader & ) {
    4830        while(!__atomic_load_n(&run, __ATOMIC_RELAXED)) yield();
     
    5234
    5335        while(__atomic_load_n(&run, __ATOMIC_RELAXED)) {
    54                 int r = cfa_preadv2(fd, &iov, 1, 0, 0);
    55                 if(r < 0) abort(strerror(-r));
    56 
     36                async_preadv2(fd, &iov, 1, 0, 0);
    5737                __atomic_fetch_add( &count, 1, __ATOMIC_SEQ_CST );
    5838        }
     
    6646        printf("Setting local\n");
    6747        setlocale(LC_NUMERIC, "");
     48
    6849
    6950        arg_loop:
     
    129110        }
    130111
    131         fd = open(__FILE__, 0);
     112        int fd = open(__FILE__, 0);
    132113        if(fd < 0) {
    133114                fprintf(stderr, "Could not open source file\n");
     
    137118        printf("Running %lu threads over %lu processors for %lf seconds\n", nthreads, nprocs, duration);
    138119
     120        Time start, end;
    139121        {
    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
     122                processor procs[nprocs - 1];
    146123                {
    147                         my_processor procs[nprocs];
    148                         {
    149                                 Reader threads[nthreads];
     124                        Reader threads[nthreads];
    150125
    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;
     126                        printf("Starting\n");
     127                        start = getTime();
     128                        run = true;
     129                        do {
     130                                sleep(500`ms);
    159131                                end = getTime();
    160                                 printf("Done\n");
    161                         }
     132                        } while( (end - start) < duration`s );
     133                        run = false;
     134                        end = getTime();
    162135                }
    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);
    166136        }
     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);
    167140
    168141        close(fd);
     142        printf("Done\n");
    169143}
  • examples/io/simple/server.cfa

    rd45ed83 r6091b88a  
    5151
    5252//----------
    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);
     53extern ssize_t async_recvmsg(int sockfd, struct msghdr *msg, int flags);
     54extern int async_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
     55extern int async_close(int fd);
    5656
    5757//----------
     
    8888        struct sockaddr_in cli_addr;
    8989        __socklen_t clilen = sizeof(cli_addr);
    90         int newsock = cfa_accept4(sock, (struct sockaddr *) &cli_addr, &clilen, 0);
     90        int newsock = async_accept4(sock, (struct sockaddr *) &cli_addr, &clilen, 0);
    9191        if (newsock < 0) {
    9292                error( printer, "accept", -newsock);
     
    9797
    9898        while(1) {
    99                 int res = cfa_recvmsg(newsock, &msg, 0);
     99                int res = async_recvmsg(newsock, &msg, 0);
    100100                if(res == 0) break;
    101101                if(res < 0) {
     
    107107        }
    108108
    109         ret = cfa_close(newsock);
     109        ret = async_close(newsock);
    110110      if(ret < 0) {
    111111            error( printer, "close new", -ret);
     
    113113      }
    114114
    115         ret = cfa_close(sock);
     115        ret = async_close(sock);
    116116      if(ret < 0) {
    117117            error( printer, "close old", -ret);
  • libcfa/prelude/defines.hfa.in

    rd45ed83 r6091b88a  
    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 //
    151
    162#undef HAVE_LINUX_IO_URING_H
    17 
    18 // #define __CFA_IO_POLLING_USER__
    19 // #define __CFA_IO_POLLING_KERNEL__
  • libcfa/src/bits/locks.hfa

    rd45ed83 r6091b88a  
    113113
    114114        struct __bin_sem_t {
     115                bool                    signaled;
    115116                pthread_mutex_t         lock;
    116117                pthread_cond_t          cond;
    117                 int                     val;
    118118        };
    119119
    120120        static inline void ?{}(__bin_sem_t & this) with( this ) {
     121                signaled = false;
    121122                pthread_mutex_init(&lock, NULL);
    122123                pthread_cond_init (&cond, NULL);
    123                 val = 0;
    124124        }
    125125
     
    132132                verify(__cfaabi_dbg_in_kernel());
    133133                pthread_mutex_lock(&lock);
    134                         while(val < 1) {
     134                        if(!signaled) {   // this must be a loop, not if!
    135135                                pthread_cond_wait(&cond, &lock);
    136136                        }
    137                         val -= 1;
     137                        signaled = false;
    138138                pthread_mutex_unlock(&lock);
    139139        }
    140140
    141141        static inline bool post(__bin_sem_t & this) with( this ) {
    142                 bool needs_signal = false;
     142                pthread_mutex_lock(&lock);
     143                        bool needs_signal = !signaled;
     144                        signaled = true;
     145                pthread_mutex_unlock(&lock);
    143146
    144                 pthread_mutex_lock(&lock);
    145                         if(val < 1) {
    146                                 val += 1;
    147                                 pthread_cond_signal(&cond);
    148                                 needs_signal = true;
    149                         }
    150                 pthread_mutex_unlock(&lock);
     147                if (needs_signal) pthread_cond_signal(&cond);
    151148
    152149                return needs_signal;
  • libcfa/src/bits/signal.hfa

    rd45ed83 r6091b88a  
    5454                        sig, handler, flags, errno, strerror( errno )
    5555                );
    56                 _Exit( EXIT_FAILURE );
     56                _exit( EXIT_FAILURE );
    5757        } // if
    5858}
  • libcfa/src/concurrency/io.cfa

    rd45ed83 r6091b88a  
    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 
    181#include "kernel.hfa"
    192
    203#if !defined(HAVE_LINUX_IO_URING_H)
    21         void __kernel_io_startup( cluster & ) {
     4        void __kernel_io_startup( cluster & this ) {
    225                // Nothing to do without io_uring
    236        }
    247
    25         void __kernel_io_start_thrd( cluster & ) {
     8        void __kernel_io_shutdown( cluster & this ) {
    269                // Nothing to do without io_uring
    2710        }
    2811
    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
     12        bool is_async( void (*)() ) {
     13                return false;
    3514        }
    3615
     
    5635        }
    5736
    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
     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
    9766
    9867//=============================================================================================
    9968// I/O Startup / Shutdown logic
    10069//=============================================================================================
    101         void __kernel_io_startup( cluster & this, bool main_cluster ) {
     70        void __kernel_io_startup( cluster & this ) {
    10271                // Step 1 : call to setup
    10372                struct io_uring_params params;
     
    12190
    12291                // Requires features
    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
     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                // }
    12996
    13097                // mmap the Submit Queue into existence
     
    134101                }
    135102
     103                // mmap the Completion Queue into existence (may or may not be needed)
    136104                // Requires features
    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                 {
     105                // if ((params.features & IORING_FEAT_SINGLE_MMAP) != 0) {
     106                //      cq->ring_ptr = sq->ring_ptr;
     107                // }
     108                // else {
    145109                        // We need multiple call to MMAP
    146110                        cq.ring_ptr = mmap(0, cq.ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_CQ_RING);
     
    149113                                abort("KERNEL ERROR: IO_URING MMAP2 - %s\n", strerror(errno));
    150114                        }
    151                 }
     115                // }
    152116
    153117                // mmap the submit queue entries
     
    170134                sq.array   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
    171135                sq.alloc = *sq.tail;
    172                 sq.ready = *sq.tail;
    173136
    174137                // completion queue
     
    197160                (this.io.submit){ min(*sq.num, *cq.num) };
    198161
    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 
    219162                // Create the poller thread
    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);
     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
    226168                // Notify the poller thread of the shutdown
    227169                __atomic_store_n(&this.io.done, true, __ATOMIC_SEQ_CST);
    228 
    229                 // Stop the IO Poller
    230170                sigval val = { 1 };
    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
     171                pthread_sigqueue( this.io.poller, SIGUSR1, val );
    235172
    236173                // Wait for the poller thread to finish
    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
     174                pthread_join( this.io.poller, 0p );
     175                free( this.io.stack );
    273176
    274177                // Shutdown the io rings
     
    301204        // Process a single completion message from the io_uring
    302205        // This is NOT thread-safe
    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
     206        static bool __io_process(struct io_ring & ring) {
    316207                unsigned head = *ring.completion_q.head;
    317208                unsigned tail = __atomic_load_n(ring.completion_q.tail, __ATOMIC_ACQUIRE);
    318209
    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                 }
     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 );
    341222
    342223                // Allow new submissions to happen
    343                 V(ring.submit, count);
     224                V(ring.submit);
    344225
    345226                // Mark to the kernel that the cqe has been seen
    346227                // Ensure that the kernel only sees the new value of the head index after the CQEs have been read.
    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 ) {
     228                __atomic_fetch_add( ring.completion_q.head, 1, __ATOMIC_RELAXED );
     229
     230                return true;
     231        }
     232
     233        static void * __io_poller( void * arg ) {
    359234                cluster * cltr = (cluster *)arg;
    360235                struct io_ring & ring = cltr->io;
     
    371246                verify( (*ring.completion_q.head) == (*ring.completion_q.tail) );
    372247
    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 );
     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) );
    413257                                }
    414258                        }
     259
     260                        // Drain the queue
     261                        while(__io_process(ring)) {}
    415262                }
    416         #endif
     263
     264                return 0p;
     265        }
    417266
    418267//=============================================================================================
     
    444293//
    445294
    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                         }
     295static 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
     313static 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) );
    482331                }
    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 
     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
     339static 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
     355static 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}
    519361
    520362//=============================================================================================
    521363// I/O Interface
    522364//=============================================================================================
     365        extern "C" {
     366                #define __USE_GNU
     367                #define _GNU_SOURCE
     368                #include <fcntl.h>
     369                #include <sys/uio.h>
     370                #include <sys/socket.h>
     371                #include <sys/stat.h>
     372        }
    523373
    524374        #define __submit_prelude \
     
    535385                park( __cfaabi_dbg_ctx ); \
    536386                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 }
    570387
    571388//-----------------------------------------------------------------------------
    572389// Asynchronous operations
    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 }
     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        }
    823644
    824645//-----------------------------------------------------------------------------
     
    826647
    827648// Macro magic to reduce the size of the following switch case
    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)
     649        #define IS_DEFINED_APPLY(f, ...) f(__VA_ARGS__)
     650        #define IS_DEFINED_SECOND(first, second, ...) second
     651        #define IS_DEFINED_TEST(expansion) _CFA_IO_FEATURE_##expansion
     652        #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
    835656                if( /*func == (fptr_t)preadv2 || */
    836                         func == (fptr_t)cfa_preadv2 )
     657                        func == (fptr_t)async_preadv2 )
    837658                        #define _CFA_IO_FEATURE_IORING_OP_READV ,
    838659                        return IS_DEFINED(IORING_OP_READV);
    839660
    840661                if( /*func == (fptr_t)pwritev2 || */
    841                         func == (fptr_t)cfa_pwritev2 )
     662                      func == (fptr_t)async_pwritev2 )
    842663                        #define _CFA_IO_FEATURE_IORING_OP_WRITEV ,
    843664                        return IS_DEFINED(IORING_OP_WRITEV);
    844665
    845666                if( /*func == (fptr_t)fsync || */
    846                         func == (fptr_t)cfa_fsync )
     667                      func == (fptr_t)async_fsync )
    847668                        #define _CFA_IO_FEATURE_IORING_OP_FSYNC ,
    848669                        return IS_DEFINED(IORING_OP_FSYNC);
    849670
    850671                if( /*func == (fptr_t)ync_file_range || */
    851                         func == (fptr_t)cfa_sync_file_range )
     672                      func == (fptr_t)async_sync_file_range )
    852673                        #define _CFA_IO_FEATURE_IORING_OP_SYNC_FILE_RANGE ,
    853674                        return IS_DEFINED(IORING_OP_SYNC_FILE_RANGE);
    854675
    855676                if( /*func == (fptr_t)sendmsg || */
    856                         func == (fptr_t)cfa_sendmsg )
     677                      func == (fptr_t)async_sendmsg )
    857678                        #define _CFA_IO_FEATURE_IORING_OP_SENDMSG ,
    858679                        return IS_DEFINED(IORING_OP_SENDMSG);
    859680
    860681                if( /*func == (fptr_t)recvmsg || */
    861                         func == (fptr_t)cfa_recvmsg )
     682                      func == (fptr_t)async_recvmsg )
    862683                        #define _CFA_IO_FEATURE_IORING_OP_RECVMSG ,
    863684                        return IS_DEFINED(IORING_OP_RECVMSG);
    864685
    865686                if( /*func == (fptr_t)send || */
    866                         func == (fptr_t)cfa_send )
     687                        func == (fptr_t)async_send )
    867688                        #define _CFA_IO_FEATURE_IORING_OP_SEND ,
    868689                        return IS_DEFINED(IORING_OP_SEND);
    869690
    870691                if( /*func == (fptr_t)recv || */
    871                         func == (fptr_t)cfa_recv )
     692                        func == (fptr_t)async_recv )
    872693                        #define _CFA_IO_FEATURE_IORING_OP_RECV ,
    873694                        return IS_DEFINED(IORING_OP_RECV);
    874695
    875696                if( /*func == (fptr_t)accept4 || */
    876                         func == (fptr_t)cfa_accept4 )
     697                        func == (fptr_t)async_accept4 )
    877698                        #define _CFA_IO_FEATURE_IORING_OP_ACCEPT ,
    878699                        return IS_DEFINED(IORING_OP_ACCEPT);
    879700
    880701                if( /*func == (fptr_t)connect || */
    881                         func == (fptr_t)cfa_connect )
     702                        func == (fptr_t)async_connect )
    882703                        #define _CFA_IO_FEATURE_IORING_OP_CONNECT ,
    883704                        return IS_DEFINED(IORING_OP_CONNECT);
    884705
    885706                if( /*func == (fptr_t)fallocate || */
    886                         func == (fptr_t)cfa_fallocate )
     707                        func == (fptr_t)async_fallocate )
    887708                        #define _CFA_IO_FEATURE_IORING_OP_FALLOCATE ,
    888709                        return IS_DEFINED(IORING_OP_FALLOCATE);
    889710
    890                 if( /*func == (fptr_t)posix_fadvise || */
    891                         func == (fptr_t)cfa_fadvise )
     711                if( /*func == (fptr_t)fadvise || */
     712                        func == (fptr_t)async_fadvise )
    892713                        #define _CFA_IO_FEATURE_IORING_OP_FADVISE ,
    893714                        return IS_DEFINED(IORING_OP_FADVISE);
    894715
    895716                if( /*func == (fptr_t)madvise || */
    896                         func == (fptr_t)cfa_madvise )
     717                        func == (fptr_t)async_madvise )
    897718                        #define _CFA_IO_FEATURE_IORING_OP_MADVISE ,
    898719                        return IS_DEFINED(IORING_OP_MADVISE);
    899720
    900721                if( /*func == (fptr_t)openat || */
    901                         func == (fptr_t)cfa_openat )
     722                        func == (fptr_t)async_openat )
    902723                        #define _CFA_IO_FEATURE_IORING_OP_OPENAT ,
    903724                        return IS_DEFINED(IORING_OP_OPENAT);
    904725
    905726                if( /*func == (fptr_t)close || */
    906                         func == (fptr_t)cfa_close )
     727                        func == (fptr_t)async_close )
    907728                        #define _CFA_IO_FEATURE_IORING_OP_CLOSE ,
    908729                        return IS_DEFINED(IORING_OP_CLOSE);
    909730
    910731                if( /*func == (fptr_t)statx || */
    911                         func == (fptr_t)cfa_statx )
     732                        func == (fptr_t)async_statx )
    912733                        #define _CFA_IO_FEATURE_IORING_OP_STATX ,
    913734                        return IS_DEFINED(IORING_OP_STATX);
    914735
    915736                if( /*func == (fptr_t)read || */
    916                         func == (fptr_t)cfa_read )
     737                      func == (fptr_t)async_read )
    917738                        #define _CFA_IO_FEATURE_IORING_OP_READ ,
    918739                        return IS_DEFINED(IORING_OP_READ);
    919740
    920741                if( /*func == (fptr_t)write || */
    921                         func == (fptr_t)cfa_write )
     742                      func == (fptr_t)async_write )
    922743                        #define _CFA_IO_FEATURE_IORING_OP_WRITE ,
    923744                        return IS_DEFINED(IORING_OP_WRITE);
    924         #endif
    925 
    926         return false;
    927 }
     745
     746                return false;
     747        }
     748
     749#endif
  • libcfa/src/concurrency/kernel.cfa

    rd45ed83 r6091b88a  
    1515
    1616#define __cforall_thread__
    17 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
    1817
    1918//C Includes
     
    4140#include "invoke.h"
    4241
    43 
    4442//-----------------------------------------------------------------------------
    4543// Some assembly required
     
    232230        idle{};
    233231
    234         __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this);
     232        __cfaabi_dbg_print_safe("Kernel : Starting core %p\n", &this);
    235233
    236234        this.stack = __create_pthread( &this.kernel_thread, __invoke_processor, (void *)&this );
    237235
    238         __cfadbg_print_safe(runtime_core, "Kernel : core %p created\n", &this);
     236        __cfaabi_dbg_print_safe("Kernel : core %p started\n", &this);
    239237}
    240238
    241239void ^?{}(processor & this) with( this ){
    242240        if( ! __atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ) {
    243                 __cfadbg_print_safe(runtime_core, "Kernel : core %p signaling termination\n", &this);
     241                __cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);
    244242
    245243                __atomic_store_n(&do_terminate, true, __ATOMIC_RELAXED);
     
    260258        ready_queue_lock{};
    261259
    262         #if !defined(__CFA_NO_STATISTICS__)
    263                 print_stats = false;
    264         #endif
    265 
    266260        procs{ __get };
    267261        idles{ __get };
    268262        threads{ __get };
    269263
    270         __kernel_io_startup( this, &this == mainCluster );
     264        __kernel_io_startup( this );
    271265
    272266        doregister(this);
     
    274268
    275269void ^?{}(cluster & this) {
    276         __kernel_io_shutdown( this, &this == mainCluster );
     270        __kernel_io_shutdown( this );
    277271
    278272        unregister(this);
     
    291285        verify(this);
    292286
    293         __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this);
     287        __cfaabi_dbg_print_safe("Kernel : core %p starting\n", this);
    294288
    295289        doregister(this->cltr, this);
     
    299293                preemption_scope scope = { this };
    300294
    301                 __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this);
     295                __cfaabi_dbg_print_safe("Kernel : core %p started\n", this);
    302296
    303297                $thread * readyThread = 0p;
     
    325319                }
    326320
    327                 __cfadbg_print_safe(runtime_core, "Kernel : core %p stopping\n", this);
     321                __cfaabi_dbg_print_safe("Kernel : core %p stopping\n", this);
    328322        }
    329323
     
    332326        V( this->terminated );
    333327
    334         __cfadbg_print_safe(runtime_core, "Kernel : core %p terminated\n", this);
     328        __cfaabi_dbg_print_safe("Kernel : core %p terminated\n", this);
    335329
    336330        // HACK : the coroutine context switch expects this_thread to be set
     
    477471
    478472        //We now have a proper context from which to schedule threads
    479         __cfadbg_print_safe(runtime_core, "Kernel : core %p created (%p, %p)\n", proc, &proc->runner, &ctx);
     473        __cfaabi_dbg_print_safe("Kernel : core %p created (%p, %p)\n", proc, &proc->runner, &ctx);
    480474
    481475        // SKULLDUGGERY: Since the coroutine doesn't have its own stack, we can't
     
    488482
    489483        // Main routine of the core returned, the core is now fully terminated
    490         __cfadbg_print_safe(runtime_core, "Kernel : core %p main ended (%p)\n", proc, &proc->runner);
     484        __cfaabi_dbg_print_safe("Kernel : core %p main ended (%p)\n", proc, &proc->runner);
    491485
    492486        return 0p;
     
    719713static void __kernel_startup(void) {
    720714        verify( ! kernelTLS.preemption_state.enabled );
    721         __cfadbg_print_safe(runtime_core, "Kernel : Starting\n");
     715        __cfaabi_dbg_print_safe("Kernel : Starting\n");
    722716
    723717        __page_size = sysconf( _SC_PAGESIZE );
     
    730724        (*mainCluster){"Main Cluster"};
    731725
    732         __cfadbg_print_safe(runtime_core, "Kernel : Main cluster ready\n");
     726        __cfaabi_dbg_print_safe("Kernel : Main cluster ready\n");
    733727
    734728        // Start by initializing the main thread
     
    740734        (*mainThread){ &info };
    741735
    742         __cfadbg_print_safe(runtime_core, "Kernel : Main thread ready\n");
     736        __cfaabi_dbg_print_safe("Kernel : Main thread ready\n");
    743737
    744738
     
    761755
    762756                runner{ &this };
    763                 __cfadbg_print_safe(runtime_core, "Kernel : constructed main processor context %p\n", &runner);
     757                __cfaabi_dbg_print_safe("Kernel : constructed main processor context %p\n", &runner);
    764758        }
    765759
     
    786780
    787781
     782
    788783        // THE SYSTEM IS NOW COMPLETELY RUNNING
    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");
     784        __cfaabi_dbg_print_safe("Kernel : Started\n--------------------------------------------------\n\n");
    796785
    797786        verify( ! kernelTLS.preemption_state.enabled );
     
    801790
    802791static void __kernel_shutdown(void) {
    803         //Before we start shutting things down, wait for systems that need threading to shutdown
    804         __kernel_io_prepare_stop( *mainCluster );
     792        __cfaabi_dbg_print_safe("\n--------------------------------------------------\nKernel : Shutting down\n");
    805793
    806794        /* paranoid */ verify( TL_GET( preemption_state.enabled ) );
    807795        disable_interrupts();
    808796        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    809 
    810         __cfadbg_print_safe(runtime_core, "\n--------------------------------------------------\nKernel : Shutting down\n");
    811797
    812798        // SKULLDUGGERY: Notify the mainProcessor it needs to terminates.
     
    836822        ^(__cfa_dbg_global_clusters.lock){};
    837823
    838         __cfadbg_print_safe(runtime_core, "Kernel : Shutdown complete\n");
     824        __cfaabi_dbg_print_safe("Kernel : Shutdown complete\n");
    839825}
    840826
     
    861847
    862848        // We are ready to sleep
    863         __cfadbg_print_safe(runtime_core, "Kernel : Processor %p ready to sleep\n", this);
     849        __cfaabi_dbg_print_safe("Kernel : Processor %p ready to sleep\n", this);
    864850        wait( idle );
    865851
    866852        // We have woken up
    867         __cfadbg_print_safe(runtime_core, "Kernel : Processor %p woke up and ready to run\n", this);
     853        __cfaabi_dbg_print_safe("Kernel : Processor %p woke up and ready to run\n", this);
    868854
    869855        // Get ourself off the idle list
     
    881867static bool __wake_one(cluster * this, __attribute__((unused)) bool force) {
    882868        // if we don't want to force check if we know it's false
    883         // if( !this->idles.head && !force ) return false;
     869        if( !this->idles.head && !force ) return false;
    884870
    885871        // First, lock the cluster idle
     
    894880
    895881        // Wake them up
    896         __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this->idles.head);
    897882        post( this->idles.head->idle );
    898883
     
    904889// Unconditionnaly wake a thread
    905890static bool __wake_proc(processor * this) {
    906         __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
    907891        return post( this->idle );
    908892}
     
    10161000        // make new owner
    10171001        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 );
    10321002
    10331003        return thrd != 0p;
  • libcfa/src/concurrency/kernel.hfa

    rd45ed83 r6091b88a  
    4040void   P (semaphore & this);
    4141bool   V (semaphore & this);
    42 bool   V (semaphore & this, unsigned count);
    4342
    4443
     
    136135        // Like head/tail but not seen by the kernel
    137136        volatile uint32_t alloc;
    138         volatile uint32_t ready;
    139137
    140138        __spinlock_t lock;
     
    146144        void * ring_ptr;
    147145        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
    158146};
    159147
     
    176164        void * ring_ptr;
    177165        size_t ring_sz;
    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
     166};
    196167
    197168struct io_ring {
     
    200171        uint32_t flags;
    201172        int fd;
     173        pthread_t poller;
     174        void * stack;
     175        volatile bool done;
    202176        semaphore submit;
    203         volatile bool done;
    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;
    214177};
    215178#endif
     
    250213                struct io_ring io;
    251214        #endif
    252 
    253         #if !defined(__CFA_NO_STATISTICS__)
    254                 bool print_stats;
    255         #endif
    256215};
    257216extern Duration default_preemption();
     
    268227static inline struct processor * active_processor() { return TL_GET( this_processor ); } // UNSAFE
    269228static 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
    276229
    277230// Local Variables: //
  • libcfa/src/concurrency/kernel_private.hfa

    rd45ed83 r6091b88a  
    7575//-----------------------------------------------------------------------------
    7676// I/O
    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 );
     77void __kernel_io_startup ( cluster & );
     78void __kernel_io_shutdown( cluster & );
    8179
    8280//-----------------------------------------------------------------------------
  • libcfa/src/concurrency/preemption.cfa

    rd45ed83 r6091b88a  
    4343// FwdDeclarations : Signal handlers
    4444static void sigHandler_ctxSwitch( __CFA_SIGPARMS__ );
    45 static void sigHandler_alarm    ( __CFA_SIGPARMS__ );
    4645static void sigHandler_segv     ( __CFA_SIGPARMS__ );
    4746static void sigHandler_ill      ( __CFA_SIGPARMS__ );
     
    257256
    258257        if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
    259                 abort( "internal error, pthread_sigmask" );
     258            abort( "internal error, pthread_sigmask" );
    260259        }
    261260}
     
    304303        // Setup proper signal handlers
    305304        __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler
    306         __cfaabi_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO | SA_RESTART ); // debug handler
    307305
    308306        signal_block( SIGALRM );
     
    396394
    397395        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");
    402396}
    403397
  • tools/gdb/utils-gdb.py

    rd45ed83 r6091b88a  
    2626
    2727class ThreadInfo:
    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
     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
    3838
    3939# A named tuple representing information about a stack
     
    5151
    5252def is_cforall():
    53         return True
     53    return True
    5454
    5555def get_cfa_types():
    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'))
     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'))
    6262
    6363def 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 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()
     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()
    7575
    7676def print_usage(obj):
    77         print(obj.__doc__)
     77    print(obj.__doc__)
    7878
    7979def parse(args):
    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
     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
    9393
    9494def 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_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_root
    102102
    103103def 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
    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 
     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
    131110
    132111def lookup_cluster(name = None):
    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
     112    """
     113    Look up a cluster given its ID
     114    @name: str
     115    Return: gdb.Value
     116    """
     117    if not is_cforall():
     118        return None
     119
     120    root = get_cluster_root()
     121    if root.address == 0x0:
     122        return None
     123
     124    if not name:
     125        return root
     126
     127    # lookup for the task associated with the id
     128    cluster = None
     129    curr = root
     130    while True:
     131        if curr['_X4namePKc_1'].string() == name:
     132            cluster = curr.address
     133            break
     134        curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1']
     135        if curr == root or curr == 0x0:
     136            break
     137
     138    if not cluster:
     139        print("Cannot find a cluster with the name: {}.".format(name))
     140        return None
     141
     142    return cluster
    164143
    165144def lookup_threads_by_cluster(cluster):
    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
     145        # Iterate through a circular linked list of threads and accumulate them in an array
     146        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 threads
     154
     155        curr = root
     156        tid = 0
     157        sid = -1
     158
     159        while True:
     160            t = ThreadInfo(cluster, curr)
     161            if t.is_system():
     162                t.tid = sid
     163                sid -= 1
     164            else:
     165                t.tid = tid
     166                tid += 1
     167
     168            threads.append(t)
     169
     170            curr = curr['node']['next']
     171            if curr == root or curr == 0x0:
     172                break
     173
     174        return threads
    196175
    197176def system_thread(thread):
    198         return False
     177    return False
    199178
    200179def adjust_stack(pc, fp, 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))
     180    # pop sp, fp, pc from global stack
     181    gdb.execute('set $pc = {}'.format(pc))
     182    gdb.execute('set $rbp = {}'.format(fp))
     183    gdb.execute('set $sp = {}'.format(sp))
    205184
    206185############################ COMMAND IMPLEMENTATION #########################
    207186
    208187class Clusters(gdb.Command):
    209         """Cforall: Display currently known clusters
     188    """Cforall: Display currently known clusters
    210189Usage:
    211         info clusters                 : print out all the clusters
     190    info clusters                 : print out all the clusters
    212191"""
    213192
    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("")
     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("")
    236223
    237224############
    238225class Processors(gdb.Command):
    239         """Cforall: Display currently known processors
     226    """Cforall: Display currently known processors
    240227Usage:
    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
     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
    244230"""
    245231
    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()
     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()
    316296
    317297############
    318298class Threads(gdb.Command):
    319         """Cforall: Display currently known threads
     299    """Cforall: Display currently known threads
    320300Usage:
    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)
     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)
    389371
    390372
    391373############
    392374class Thread(gdb.Command):
    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
     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()
    536699
    537700############
    538701class PrevThread(gdb.Command):
    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')
     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: str
     711        @from_tty: bool
     712        """
     713        global STACK
     714        if len(STACK) != 0:
     715            # must be at frame 0 to set pc register
     716            gdb.execute('select-frame 0')
     717
     718            # pop stack
     719            stack_info = STACK.pop()
     720            pc = get_addr(stack_info.pc)
     721            sp = stack_info.sp
     722            fp = stack_info.fp
     723
     724            # pop sp, fp, pc from global stack
     725            adjust_stack(pc, fp, sp)
     726
     727            # must be at C++ frame to access C++ vars
     728            gdb.execute('frame 1')
     729        else:
     730            print('empty stack')
    568731
    569732class ResetOriginFrame(gdb.Command):
    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
     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: str
     741        @from_tty: bool
     742        """
     743        global STACK
     744        if len(STACK) != 0:
     745            stack_info = STACK.pop(0)
     746            STACK.clear()
     747            pc = get_addr(stack_info.pc)
     748            sp = stack_info.sp
     749            fp = stack_info.fp
     750
     751            # pop sp, fp, pc from global stack
     752            adjust_stack(pc, fp, sp)
     753
     754            # must be at C++ frame to access C++ vars
     755            gdb.execute('frame 1')
     756        #else:
     757            #print('reset: empty stack') #probably does not have to print msg
    595758
    596759Clusters()
     
    599762PrevThread()
    600763Threads()
    601 Thread()
    602764
    603765# Local Variables: #
Note: See TracChangeset for help on using the changeset viewer.