Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/io.cfa

    rdf40a56 r732b406  
    3838
    3939#else
     40        #define _GNU_SOURCE         /* See feature_test_macros(7) */
     41        #include <errno.h>
     42        #include <stdint.h>
     43        #include <string.h>
     44        #include <unistd.h>
     45        #include <sys/mman.h>
     46
    4047        extern "C" {
    41                 #define _GNU_SOURCE         /* See feature_test_macros(7) */
    42                 #include <errno.h>
    43                 #include <stdint.h>
    44                 #include <string.h>
    45                 #include <unistd.h>
    46                 #include <sys/mman.h>
    4748                #include <sys/syscall.h>
    4849
     
    108109                volatile uint32_t * head;
    109110                volatile uint32_t * tail;
     111                volatile uint32_t prev_head;
    110112
    111113                // The actual kernel ring which uses head/tail
     
    128130
    129131                __spinlock_t lock;
     132                __spinlock_t release_lock;
    130133
    131134                // A buffer of sqes (not the actual ring)
     
    181184//=============================================================================================
    182185        void __kernel_io_startup( cluster & this, unsigned io_flags, bool main_cluster ) {
     186                if( (io_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS) && (io_flags & CFA_CLUSTER_IO_EAGER_SUBMITS) ) {
     187                        abort("CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS and CFA_CLUSTER_IO_EAGER_SUBMITS cannot be mixed\n");
     188                }
     189
    183190                this.io = malloc();
    184191
     
    186193                struct io_uring_params params;
    187194                memset(&params, 0, sizeof(params));
     195                if( io_flags & CFA_CLUSTER_IO_KERNEL_POLL_SUBMITS   ) params.flags |= IORING_SETUP_SQPOLL;
     196                if( io_flags & CFA_CLUSTER_IO_KERNEL_POLL_COMPLETES ) params.flags |= IORING_SETUP_IOPOLL;
    188197
    189198                uint32_t nentries = entries_per_cluster();
     
    252261                sq.dropped = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
    253262                sq.array   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
     263                sq.prev_head = *sq.head;
    254264
    255265                {
     
    260270                }
    261271
    262                 if( io_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS ) {
     272                (sq.lock){};
     273                (sq.release_lock){};
     274
     275                if( io_flags & ( CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS | CFA_CLUSTER_IO_EAGER_SUBMITS ) ) {
    263276                        /* paranoid */ verify( is_pow2( io_flags >> CFA_CLUSTER_IO_BUFFLEN_OFFSET ) || ((io_flags >> CFA_CLUSTER_IO_BUFFLEN_OFFSET) < 8)  );
    264277                        sq.ready_cnt = max(io_flags >> CFA_CLUSTER_IO_BUFFLEN_OFFSET, 8);
     
    420433// I/O Polling
    421434//=============================================================================================
    422         struct io_user_data {
    423                 int32_t result;
    424                 $thread * thrd;
    425         };
     435        static unsigned __collect_submitions( struct __io_data & ring );
     436        static uint32_t __release_consumed_submission( struct __io_data & ring );
    426437
    427438        // Process a single completion message from the io_uring
    428439        // This is NOT thread-safe
    429440        static [int, bool] __drain_io( & struct __io_data ring, * sigset_t mask, int waitcnt, bool in_kernel ) {
     441                /* paranoid */ verify( !kernelTLS.preemption_state.enabled );
     442                const uint32_t smask = *ring.submit_q.mask;
     443
    430444                unsigned to_submit = 0;
    431445                if( ring.cltr_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS ) {
    432 
    433446                        // If the poller thread also submits, then we need to aggregate the submissions which are ready
    434                         uint32_t tail = *ring.submit_q.tail;
    435                         const uint32_t mask = *ring.submit_q.mask;
    436 
    437                         // Go through the list of ready submissions
    438                         for( i; ring.submit_q.ready_cnt ) {
    439                                 // replace any submission with the sentinel, to consume it.
    440                                 uint32_t idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED);
    441 
    442                                 // If it was already the sentinel, then we are done
    443                                 if( idx == -1ul32 ) continue;
    444 
    445                                 // If we got a real submission, append it to the list
    446                                 ring.submit_q.array[ (tail + to_submit) & mask ] = idx & mask;
    447                                 to_submit++;
    448                         }
    449 
    450                         // Increment the tail based on how many we are ready to submit
    451                         __atomic_fetch_add(ring.submit_q.tail, to_submit, __ATOMIC_SEQ_CST);
    452                 }
    453 
    454                 const uint32_t smask = *ring.submit_q.mask;
    455                 uint32_t shead = *ring.submit_q.head;
    456                 int ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, waitcnt, IORING_ENTER_GETEVENTS, mask, _NSIG / 8);
    457                 if( ret < 0 ) {
    458                         switch((int)errno) {
    459                         case EAGAIN:
    460                         case EINTR:
    461                                 return -EAGAIN;
    462                         default:
    463                                 abort( "KERNEL ERROR: IO_URING WAIT - %s\n", strerror(errno) );
    464                         }
    465                 }
    466 
    467                 // Release the consumed SQEs
    468                 for( i; ret ) {
    469                         uint32_t idx = ring.submit_q.array[ (i + shead) & smask ];
    470                         ring.submit_q.sqes[ idx ].user_data = 0;
    471                 }
    472 
    473                 uint32_t avail = 0;
    474                 uint32_t sqe_num = *ring.submit_q.num;
    475                 for(i; sqe_num) {
    476                         if( ring.submit_q.sqes[ i ].user_data == 0 ) avail++;
    477                 }
    478 
    479                 // update statistics
    480                 #if !defined(__CFA_NO_STATISTICS__)
    481                         __tls_stats()->io.submit_q.submit_avg.rdy += to_submit;
    482                         __tls_stats()->io.submit_q.submit_avg.csm += ret;
    483                         __tls_stats()->io.submit_q.submit_avg.avl += avail;
    484                         __tls_stats()->io.submit_q.submit_avg.cnt += 1;
    485                 #endif
     447                        to_submit = __collect_submitions( ring );
     448                }
     449
     450                if (to_submit > 0 || waitcnt > 0) {
     451                        int ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, waitcnt, IORING_ENTER_GETEVENTS, mask, _NSIG / 8);
     452                        if( ret < 0 ) {
     453                                switch((int)errno) {
     454                                case EAGAIN:
     455                                case EINTR:
     456                                        return [0, true];
     457                                default:
     458                                        abort( "KERNEL ERROR: IO_URING WAIT - %s\n", strerror(errno) );
     459                                }
     460                        }
     461
     462                        // Release the consumed SQEs
     463                        __release_consumed_submission( ring );
     464
     465                        // update statistics
     466                        __STATS__( true,
     467                                if( to_submit > 0 ) {
     468                                        io.submit_q.submit_avg.rdy += to_submit;
     469                                        io.submit_q.submit_avg.csm += ret;
     470                                        io.submit_q.submit_avg.cnt += 1;
     471                                }
     472                        )
     473                }
     474
     475                // Memory barrier
     476                __atomic_thread_fence( __ATOMIC_SEQ_CST );
    486477
    487478                // Drain the queue
     
    490481                const uint32_t mask = *ring.completion_q.mask;
    491482
    492                 // Memory barrier
    493                 __atomic_thread_fence( __ATOMIC_SEQ_CST );
    494 
    495483                // Nothing was new return 0
    496484                if (head == tail) {
    497                         return 0;
     485                        return [0, to_submit > 0];
    498486                }
    499487
    500488                uint32_t count = tail - head;
     489                /* paranoid */ verify( count != 0 );
    501490                for(i; count) {
    502491                        unsigned idx = (head + i) & mask;
     
    505494                        /* paranoid */ verify(&cqe);
    506495
    507                         struct io_user_data * data = (struct io_user_data *)(uintptr_t)cqe.user_data;
     496                        struct __io_user_data_t * data = (struct __io_user_data_t *)(uintptr_t)cqe.user_data;
    508497                        __cfadbg_print_safe( io, "Kernel I/O : Performed reading io cqe %p, result %d for %p\n", data, cqe.res, data->thrd );
    509498
     
    563552
    564553                                // Update statistics
    565                                 #if !defined(__CFA_NO_STATISTICS__)
    566                                         __tls_stats()->io.complete_q.completed_avg.val += count;
    567                                         __tls_stats()->io.complete_q.completed_avg.slow_cnt += 1;
    568                                 #endif
     554                                __STATS__( true,
     555                                        io.complete_q.completed_avg.val += count;
     556                                        io.complete_q.completed_avg.slow_cnt += 1;
     557                                )
    569558
    570559                                if(again) {
     
    580569                                int count;
    581570                                bool again;
    582                                 [count, again] = __drain_io( ring, &mask, 0, true );
     571                                [count, again] = __drain_io( ring, &mask, 1, true );
    583572
    584573                                // Update statistics
    585                                 #if !defined(__CFA_NO_STATISTICS__)
    586                                         __tls_stats()->io.complete_q.completed_avg.val += count;
    587                                         __tls_stats()->io.complete_q.completed_avg.slow_cnt += 1;
    588                                 #endif
     574                                __STATS__( true,
     575                                        io.complete_q.completed_avg.val += count;
     576                                        io.complete_q.completed_avg.slow_cnt += 1;
     577                                )
    589578                        }
    590579                }
     
    623612
    624613                                // Update statistics
    625                                 #if !defined(__CFA_NO_STATISTICS__)
    626                                         __tls_stats()->io.complete_q.completed_avg.val += count;
    627                                         __tls_stats()->io.complete_q.completed_avg.fast_cnt += 1;
    628                                 #endif
     614                                __STATS__( true,
     615                                        io.complete_q.completed_avg.val += count;
     616                                        io.complete_q.completed_avg.fast_cnt += 1;
     617                                )
    629618                        enable_interrupts( __cfaabi_dbg_ctx );
    630619
     
    662651
    663652// Submition steps :
    664 // 1 - We need to make sure we don't overflow any of the buffer, P(ring.submit) to make sure
    665 //     entries are available. The semaphore make sure that there is no more operations in
    666 //     progress then the number of entries in the buffer. This probably limits concurrency
    667 //     more than necessary since submitted but not completed operations don't need any
    668 //     entries in user space. However, I don't know what happens if we overflow the buffers
    669 //     because too many requests completed at once. This is a safe approach in all cases.
    670 //     Furthermore, with hundreds of entries, this may be okay.
    671 //
    672 // 2 - Allocate a queue entry. The ring already has memory for all entries but only the ones
     653// 1 - Allocate a queue entry. The ring already has memory for all entries but only the ones
    673654//     listed in sq.array are visible by the kernel. For those not listed, the kernel does not
    674655//     offer any assurance that an entry is not being filled by multiple flags. Therefore, we
    675656//     need to write an allocator that allows allocating concurrently.
    676657//
    677 // 3 - Actually fill the submit entry, this is the only simple and straightforward step.
     658// 2 - Actually fill the submit entry, this is the only simple and straightforward step.
    678659//
    679 // 4 - Append the entry index to the array and adjust the tail accordingly. This operation
     660// 3 - Append the entry index to the array and adjust the tail accordingly. This operation
    680661//     needs to arrive to two concensus at the same time:
    681662//     A - The order in which entries are listed in the array: no two threads must pick the
     
    685666//
    686667
    687         // [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) __attribute__((noinline));
    688         static inline [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) {
    689                 verify( data != 0 );
    690 
     668        [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) {
     669                /* paranoid */ verify( data != 0 );
    691670
    692671                // Prepare the data we need
     
    713692                                {
    714693                                        // update statistics
    715                                         #if !defined(__CFA_NO_STATISTICS__)
    716                                                 disable_interrupts();
    717                                                         __tls_stats()->io.submit_q.alloc_avg.val   += len;
    718                                                         __tls_stats()->io.submit_q.alloc_avg.block += block;
    719                                                         __tls_stats()->io.submit_q.alloc_avg.cnt   += 1;
    720                                                 enable_interrupts( __cfaabi_dbg_ctx );
    721                                         #endif
     694                                        __STATS__( false,
     695                                                io.submit_q.alloc_avg.val   += len;
     696                                                io.submit_q.alloc_avg.block += block;
     697                                                io.submit_q.alloc_avg.cnt   += 1;
     698                                        )
    722699
    723700
     
    762739
    763740                        block++;
    764                         yield();
     741                        if( try_lock(ring.submit_q.lock __cfaabi_dbg_ctx2) ) {
     742                                __release_consumed_submission( ring );
     743                                unlock( ring.submit_q.lock );
     744                        }
     745                        else {
     746                                yield();
     747                        }
    765748                }
    766749
    767750                // update statistics
    768                 #if !defined(__CFA_NO_STATISTICS__)
    769                 disable_interrupts();
    770                         __tls_stats()->io.submit_q.look_avg.val   += len;
    771                         __tls_stats()->io.submit_q.look_avg.block += block;
    772                         __tls_stats()->io.submit_q.look_avg.cnt   += 1;
    773                 enable_interrupts( __cfaabi_dbg_ctx );
    774                 #endif
     751                __STATS__( false,
     752                        io.submit_q.look_avg.val   += len;
     753                        io.submit_q.look_avg.block += block;
     754                        io.submit_q.look_avg.cnt   += 1;
     755                )
    775756
    776757                return picked;
    777758        }
    778759
    779         // void __submit( struct __io_data & ring, uint32_t idx ) __attribute__((noinline));
    780         static inline void __submit( struct __io_data & ring, uint32_t idx ) {
     760        void __submit( struct __io_data & ring, uint32_t idx ) {
    781761                // Get now the data we definetely need
    782762                uint32_t * const tail = ring.submit_q.tail;
     
    786766                if( ring.cltr_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS ) {
    787767                        // If the poller thread submits, then we just need to add this to the ready array
    788 
    789768                        __submit_to_ready_array( ring, idx, mask );
    790769
     
    792771
    793772                        __cfadbg_print_safe( io, "Kernel I/O : Added %u to ready for %p\n", idx, active_thread() );
     773                }
     774                else if( ring.cltr_flags & CFA_CLUSTER_IO_EAGER_SUBMITS ) {
     775                        uint32_t picked = __submit_to_ready_array( ring, idx, mask );
     776
     777                        for() {
     778                                yield();
     779
     780                                // If some one else collected our index, we are done
     781                                #warning ABA problem
     782                                if( ring.submit_q.ready[picked] != idx ) {
     783                                        __STATS__( false,
     784                                                io.submit_q.helped += 1;
     785                                        )
     786                                        return;
     787                                }
     788
     789                                if( try_lock(ring.submit_q.lock __cfaabi_dbg_ctx2) ) {
     790                                        __STATS__( false,
     791                                                io.submit_q.leader += 1;
     792                                        )
     793                                        break;
     794                                }
     795
     796                                __STATS__( false,
     797                                        io.submit_q.busy += 1;
     798                                )
     799                        }
     800
     801                        // We got the lock
     802                        unsigned to_submit = __collect_submitions( ring );
     803                        int ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, 0, 0, 0p, _NSIG / 8);
     804                        if( ret < 0 ) {
     805                                switch((int)errno) {
     806                                case EAGAIN:
     807                                case EINTR:
     808                                        unlock(ring.submit_q.lock);
     809                                        return;
     810                                default:
     811                                        abort( "KERNEL ERROR: IO_URING WAIT - %s\n", strerror(errno) );
     812                                }
     813                        }
     814
     815                        /* paranoid */ verify( ret > 0 );
     816
     817                        // Release the consumed SQEs
     818                        __release_consumed_submission( ring );
     819
     820                        // update statistics
     821                        __STATS__( true,
     822                                io.submit_q.submit_avg.rdy += to_submit;
     823                                io.submit_q.submit_avg.csm += ret;
     824                                io.submit_q.submit_avg.cnt += 1;
     825                        )
     826
     827                        unlock(ring.submit_q.lock);
    794828                }
    795829                else {
     
    803837                        ring.submit_q.array[ (*tail) & mask ] = idx & mask;
    804838                        __atomic_fetch_add(tail, 1ul32, __ATOMIC_SEQ_CST);
     839
     840                        /* paranoid */ verify( ring.submit_q.sqes[ idx ].user_data != 0 );
    805841
    806842                        // Submit however, many entries need to be submitted
     
    814850
    815851                        // update statistics
    816                         #if !defined(__CFA_NO_STATISTICS__)
    817                                 __tls_stats()->io.submit_q.submit_avg.csm += 1;
    818                                 __tls_stats()->io.submit_q.submit_avg.cnt += 1;
    819                         #endif
    820 
    821                         ring.submit_q.sqes[ idx & mask ].user_data = 0;
     852                        __STATS__( false,
     853                                io.submit_q.submit_avg.csm += 1;
     854                                io.submit_q.submit_avg.cnt += 1;
     855                        )
     856
     857                        // Release the consumed SQEs
     858                        __release_consumed_submission( ring );
    822859
    823860                        unlock(ring.submit_q.lock);
     
    827864        }
    828865
    829         static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd) {
    830                 this.opcode = opcode;
    831                 #if !defined(IOSQE_ASYNC)
    832                         this.flags = 0;
    833                 #else
    834                         this.flags = IOSQE_ASYNC;
    835                 #endif
    836                 this.ioprio = 0;
    837                 this.fd = fd;
    838                 this.off = 0;
    839                 this.addr = 0;
    840                 this.len = 0;
    841                 this.rw_flags = 0;
    842                 this.__pad2[0] = this.__pad2[1] = this.__pad2[2] = 0;
    843         }
    844 
    845         static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd, void * addr, uint32_t len, uint64_t off ) {
    846                 (this){ opcode, fd };
    847                 this.off = off;
    848                 this.addr = (uint64_t)(uintptr_t)addr;
    849                 this.len = len;
    850         }
    851 
    852 
    853 //=============================================================================================
    854 // I/O Interface
    855 //=============================================================================================
    856 
    857         #define __submit_prelude \
    858                 io_user_data data = { 0, active_thread() }; \
    859                 struct __io_data & ring = *data.thrd->curr_cluster->io; \
    860                 struct io_uring_sqe * sqe; \
    861                 uint32_t idx; \
    862                 [sqe, idx] = __submit_alloc( ring, (uint64_t)(uintptr_t)&data );
    863 
    864         #define __submit_wait \
    865                 /*__cfaabi_bits_print_safe( STDERR_FILENO, "Preparing user data %p for %p\n", &data, data.thrd );*/ \
    866                 verify( sqe->user_data == (uint64_t)(uintptr_t)&data ); \
    867                 __submit( ring, idx ); \
    868                 park( __cfaabi_dbg_ctx ); \
    869                 return data.result;
     866        static unsigned __collect_submitions( struct __io_data & ring ) {
     867                /* paranoid */ verify( ring.submit_q.ready != 0p );
     868                /* paranoid */ verify( ring.submit_q.ready_cnt > 0 );
     869
     870                unsigned to_submit = 0;
     871                uint32_t tail = *ring.submit_q.tail;
     872                const uint32_t mask = *ring.submit_q.mask;
     873
     874                // Go through the list of ready submissions
     875                for( i; ring.submit_q.ready_cnt ) {
     876                        // replace any submission with the sentinel, to consume it.
     877                        uint32_t idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED);
     878
     879                        // If it was already the sentinel, then we are done
     880                        if( idx == -1ul32 ) continue;
     881
     882                        // If we got a real submission, append it to the list
     883                        ring.submit_q.array[ (tail + to_submit) & mask ] = idx & mask;
     884                        to_submit++;
     885                }
     886
     887                // Increment the tail based on how many we are ready to submit
     888                __atomic_fetch_add(ring.submit_q.tail, to_submit, __ATOMIC_SEQ_CST);
     889
     890                return to_submit;
     891        }
     892
     893        static uint32_t __release_consumed_submission( struct __io_data & ring ) {
     894                const uint32_t smask = *ring.submit_q.mask;
     895
     896                if( !try_lock(ring.submit_q.release_lock __cfaabi_dbg_ctx2) ) return 0;
     897                uint32_t chead = *ring.submit_q.head;
     898                uint32_t phead = ring.submit_q.prev_head;
     899                ring.submit_q.prev_head = chead;
     900                unlock(ring.submit_q.release_lock);
     901
     902                uint32_t count = chead - phead;
     903                for( i; count ) {
     904                        uint32_t idx = ring.submit_q.array[ (phead + i) & smask ];
     905                        ring.submit_q.sqes[ idx ].user_data = 0;
     906                }
     907                return count;
     908        }
    870909#endif
    871 
    872 // Some forward declarations
    873 extern "C" {
    874         #include <unistd.h>
    875         #include <sys/types.h>
    876         #include <sys/socket.h>
    877         #include <sys/syscall.h>
    878 
    879 #if defined(HAVE_PREADV2)
    880         struct iovec;
    881         extern ssize_t preadv2 (int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
    882 #endif
    883 #if defined(HAVE_PWRITEV2)
    884         struct iovec;
    885         extern ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags);
    886 #endif
    887 
    888         extern int fsync(int fd);
    889         extern int sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags);
    890 
    891         struct msghdr;
    892         struct sockaddr;
    893         extern ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
    894         extern ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
    895         extern ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    896         extern ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    897         extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
    898         extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    899 
    900         extern int fallocate(int fd, int mode, uint64_t offset, uint64_t len);
    901         extern int posix_fadvise(int fd, uint64_t offset, uint64_t len, int advice);
    902         extern int madvise(void *addr, size_t length, int advice);
    903 
    904         extern int openat(int dirfd, const char *pathname, int flags, mode_t mode);
    905         extern int close(int fd);
    906 
    907         extern ssize_t read (int fd, void *buf, size_t count);
    908 }
    909 
    910 //-----------------------------------------------------------------------------
    911 // Asynchronous operations
    912 #if defined(HAVE_PREADV2)
    913         ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags) {
    914                 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_READV)
    915                         return preadv2(fd, iov, iovcnt, offset, flags);
    916                 #else
    917                         __submit_prelude
    918 
    919                         (*sqe){ IORING_OP_READV, fd, iov, iovcnt, offset };
    920 
    921                         __submit_wait
    922                 #endif
    923         }
    924 #endif
    925 
    926 #if defined(HAVE_PWRITEV2)
    927         ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags) {
    928                 #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_WRITEV)
    929                         return pwritev2(fd, iov, iovcnt, offset, flags);
    930                 #else
    931                         __submit_prelude
    932 
    933                         (*sqe){ IORING_OP_WRITEV, fd, iov, iovcnt, offset };
    934 
    935                         __submit_wait
    936                 #endif
    937         }
    938 #endif
    939 
    940 int cfa_fsync(int fd) {
    941         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_FSYNC)
    942                 return fsync(fd);
    943         #else
    944                 __submit_prelude
    945 
    946                 (*sqe){ IORING_OP_FSYNC, fd };
    947 
    948                 __submit_wait
    949         #endif
    950 }
    951 
    952 int cfa_sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags) {
    953         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_SYNC_FILE_RANGE)
    954                 return sync_file_range(fd, offset, nbytes, flags);
    955         #else
    956                 __submit_prelude
    957 
    958                 (*sqe){ IORING_OP_SYNC_FILE_RANGE, fd };
    959                 sqe->off = offset;
    960                 sqe->len = nbytes;
    961                 sqe->sync_range_flags = flags;
    962 
    963                 __submit_wait
    964         #endif
    965 }
    966 
    967 
    968 ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags) {
    969         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_SENDMSG)
    970                 return sendmsg(sockfd, msg, flags);
    971         #else
    972                 __submit_prelude
    973 
    974                 (*sqe){ IORING_OP_SENDMSG, sockfd, msg, 1, 0 };
    975                 sqe->msg_flags = flags;
    976 
    977                 __submit_wait
    978         #endif
    979 }
    980 
    981 ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags) {
    982         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_RECVMSG)
    983                 return recvmsg(sockfd, msg, flags);
    984         #else
    985                 __submit_prelude
    986 
    987                 (*sqe){ IORING_OP_RECVMSG, sockfd, msg, 1, 0 };
    988                 sqe->msg_flags = flags;
    989 
    990                 __submit_wait
    991         #endif
    992 }
    993 
    994 ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags) {
    995         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_SEND)
    996                 return send( sockfd, buf, len, flags );
    997         #else
    998                 __submit_prelude
    999 
    1000                 (*sqe){ IORING_OP_SEND, sockfd };
    1001                 sqe->addr = (uint64_t)buf;
    1002                 sqe->len = len;
    1003                 sqe->msg_flags = flags;
    1004 
    1005                 __submit_wait
    1006         #endif
    1007 }
    1008 
    1009 ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags) {
    1010         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_RECV)
    1011                 return recv( sockfd, buf, len, flags );
    1012         #else
    1013                 __submit_prelude
    1014 
    1015                 (*sqe){ IORING_OP_RECV, sockfd };
    1016                 sqe->addr = (uint64_t)buf;
    1017                 sqe->len = len;
    1018                 sqe->msg_flags = flags;
    1019 
    1020                 __submit_wait
    1021         #endif
    1022 }
    1023 
    1024 int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) {
    1025         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_ACCEPT)
    1026                 return accept4( sockfd, addr, addrlen, flags );
    1027         #else
    1028                 __submit_prelude
    1029 
    1030                 (*sqe){ IORING_OP_ACCEPT, sockfd };
    1031                 sqe->addr = addr;
    1032                 sqe->addr2 = addrlen;
    1033                 sqe->accept_flags = flags;
    1034 
    1035                 __submit_wait
    1036         #endif
    1037 }
    1038 
    1039 int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
    1040         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_CONNECT)
    1041                 return connect( sockfd, addr, addrlen );
    1042         #else
    1043                 __submit_prelude
    1044 
    1045                 (*sqe){ IORING_OP_CONNECT, sockfd };
    1046                 sqe->addr = (uint64_t)addr;
    1047                 sqe->off = addrlen;
    1048 
    1049                 __submit_wait
    1050         #endif
    1051 }
    1052 
    1053 int cfa_fallocate(int fd, int mode, uint64_t offset, uint64_t len) {
    1054         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_FALLOCATE)
    1055                 return fallocate( fd, mode, offset, len );
    1056         #else
    1057                 __submit_prelude
    1058 
    1059                 (*sqe){ IORING_OP_FALLOCATE, fd };
    1060                 sqe->off = offset;
    1061                 sqe->len = length;
    1062                 sqe->mode = mode;
    1063 
    1064                 __submit_wait
    1065         #endif
    1066 }
    1067 
    1068 int cfa_fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
    1069         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_FADVISE)
    1070                 return posix_fadvise( fd, offset, len, advice );
    1071         #else
    1072                 __submit_prelude
    1073 
    1074                 (*sqe){ IORING_OP_FADVISE, fd };
    1075                 sqe->off = (uint64_t)offset;
    1076                 sqe->len = length;
    1077                 sqe->fadvise_advice = advice;
    1078 
    1079                 __submit_wait
    1080         #endif
    1081 }
    1082 
    1083 int cfa_madvise(void *addr, size_t length, int advice) {
    1084         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_MADVISE)
    1085                 return madvise( addr, length, advice );
    1086         #else
    1087                 __submit_prelude
    1088 
    1089                 (*sqe){ IORING_OP_MADVISE, 0 };
    1090                 sqe->addr = (uint64_t)addr;
    1091                 sqe->len = length;
    1092                 sqe->fadvise_advice = advice;
    1093 
    1094                 __submit_wait
    1095         #endif
    1096 }
    1097 
    1098 int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode) {
    1099         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_OPENAT)
    1100                 return openat( dirfd, pathname, flags, mode );
    1101         #else
    1102                 __submit_prelude
    1103 
    1104                 (*sqe){ IORING_OP_OPENAT, dirfd };
    1105                 sqe->addr = (uint64_t)pathname;
    1106                 sqe->open_flags = flags;
    1107                 sqe->mode = mode;
    1108 
    1109                 __submit_wait
    1110         #endif
    1111 }
    1112 
    1113 int cfa_close(int fd) {
    1114         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_CLOSE)
    1115                 return close( fd );
    1116         #else
    1117                 __submit_prelude
    1118 
    1119                 (*sqe){ IORING_OP_CLOSE, fd };
    1120 
    1121                 __submit_wait
    1122         #endif
    1123 }
    1124 
    1125 
    1126 ssize_t cfa_read(int fd, void *buf, size_t count) {
    1127         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_READ)
    1128                 return read( fd, buf, count );
    1129         #else
    1130                 __submit_prelude
    1131 
    1132                 (*sqe){ IORING_OP_READ, fd, buf, count, 0 };
    1133 
    1134                 __submit_wait
    1135         #endif
    1136 }
    1137 
    1138 ssize_t cfa_write(int fd, void *buf, size_t count) {
    1139         #if !defined(HAVE_LINUX_IO_URING_H) || !defined(IORING_OP_WRITE)
    1140                 return read( fd, buf, count );
    1141         #else
    1142                 __submit_prelude
    1143 
    1144                 (*sqe){ IORING_OP_WRITE, fd, buf, count, 0 };
    1145 
    1146                 __submit_wait
    1147         #endif
    1148 }
    1149 
    1150 //-----------------------------------------------------------------------------
    1151 // Check if a function is asynchronous
    1152 
    1153 // Macro magic to reduce the size of the following switch case
    1154 #define IS_DEFINED_APPLY(f, ...) f(__VA_ARGS__)
    1155 #define IS_DEFINED_SECOND(first, second, ...) second
    1156 #define IS_DEFINED_TEST(expansion) _CFA_IO_FEATURE_##expansion
    1157 #define IS_DEFINED(macro) IS_DEFINED_APPLY( IS_DEFINED_SECOND,IS_DEFINED_TEST(macro) false, true)
    1158 
    1159 bool has_user_level_blocking( fptr_t func ) {
    1160         #if defined(HAVE_LINUX_IO_URING_H)
    1161                 #if defined(HAVE_PREADV2)
    1162                         if( /*func == (fptr_t)preadv2 || */
    1163                                 func == (fptr_t)cfa_preadv2 )
    1164                                 #define _CFA_IO_FEATURE_IORING_OP_READV ,
    1165                                 return IS_DEFINED(IORING_OP_READV);
    1166                 #endif
    1167 
    1168                 #if defined(HAVE_PWRITEV2)
    1169                         if( /*func == (fptr_t)pwritev2 || */
    1170                                 func == (fptr_t)cfa_pwritev2 )
    1171                                 #define _CFA_IO_FEATURE_IORING_OP_WRITEV ,
    1172                                 return IS_DEFINED(IORING_OP_WRITEV);
    1173                 #endif
    1174 
    1175                 if( /*func == (fptr_t)fsync || */
    1176                         func == (fptr_t)cfa_fsync )
    1177                         #define _CFA_IO_FEATURE_IORING_OP_FSYNC ,
    1178                         return IS_DEFINED(IORING_OP_FSYNC);
    1179 
    1180                 if( /*func == (fptr_t)ync_file_range || */
    1181                         func == (fptr_t)cfa_sync_file_range )
    1182                         #define _CFA_IO_FEATURE_IORING_OP_SYNC_FILE_RANGE ,
    1183                         return IS_DEFINED(IORING_OP_SYNC_FILE_RANGE);
    1184 
    1185                 if( /*func == (fptr_t)sendmsg || */
    1186                         func == (fptr_t)cfa_sendmsg )
    1187                         #define _CFA_IO_FEATURE_IORING_OP_SENDMSG ,
    1188                         return IS_DEFINED(IORING_OP_SENDMSG);
    1189 
    1190                 if( /*func == (fptr_t)recvmsg || */
    1191                         func == (fptr_t)cfa_recvmsg )
    1192                         #define _CFA_IO_FEATURE_IORING_OP_RECVMSG ,
    1193                         return IS_DEFINED(IORING_OP_RECVMSG);
    1194 
    1195                 if( /*func == (fptr_t)send || */
    1196                         func == (fptr_t)cfa_send )
    1197                         #define _CFA_IO_FEATURE_IORING_OP_SEND ,
    1198                         return IS_DEFINED(IORING_OP_SEND);
    1199 
    1200                 if( /*func == (fptr_t)recv || */
    1201                         func == (fptr_t)cfa_recv )
    1202                         #define _CFA_IO_FEATURE_IORING_OP_RECV ,
    1203                         return IS_DEFINED(IORING_OP_RECV);
    1204 
    1205                 if( /*func == (fptr_t)accept4 || */
    1206                         func == (fptr_t)cfa_accept4 )
    1207                         #define _CFA_IO_FEATURE_IORING_OP_ACCEPT ,
    1208                         return IS_DEFINED(IORING_OP_ACCEPT);
    1209 
    1210                 if( /*func == (fptr_t)connect || */
    1211                         func == (fptr_t)cfa_connect )
    1212                         #define _CFA_IO_FEATURE_IORING_OP_CONNECT ,
    1213                         return IS_DEFINED(IORING_OP_CONNECT);
    1214 
    1215                 if( /*func == (fptr_t)fallocate || */
    1216                         func == (fptr_t)cfa_fallocate )
    1217                         #define _CFA_IO_FEATURE_IORING_OP_FALLOCATE ,
    1218                         return IS_DEFINED(IORING_OP_FALLOCATE);
    1219 
    1220                 if( /*func == (fptr_t)posix_fadvise || */
    1221                         func == (fptr_t)cfa_fadvise )
    1222                         #define _CFA_IO_FEATURE_IORING_OP_FADVISE ,
    1223                         return IS_DEFINED(IORING_OP_FADVISE);
    1224 
    1225                 if( /*func == (fptr_t)madvise || */
    1226                         func == (fptr_t)cfa_madvise )
    1227                         #define _CFA_IO_FEATURE_IORING_OP_MADVISE ,
    1228                         return IS_DEFINED(IORING_OP_MADVISE);
    1229 
    1230                 if( /*func == (fptr_t)openat || */
    1231                         func == (fptr_t)cfa_openat )
    1232                         #define _CFA_IO_FEATURE_IORING_OP_OPENAT ,
    1233                         return IS_DEFINED(IORING_OP_OPENAT);
    1234 
    1235                 if( /*func == (fptr_t)close || */
    1236                         func == (fptr_t)cfa_close )
    1237                         #define _CFA_IO_FEATURE_IORING_OP_CLOSE ,
    1238                         return IS_DEFINED(IORING_OP_CLOSE);
    1239 
    1240                 if( /*func == (fptr_t)read || */
    1241                         func == (fptr_t)cfa_read )
    1242                         #define _CFA_IO_FEATURE_IORING_OP_READ ,
    1243                         return IS_DEFINED(IORING_OP_READ);
    1244 
    1245                 if( /*func == (fptr_t)write || */
    1246                         func == (fptr_t)cfa_write )
    1247                         #define _CFA_IO_FEATURE_IORING_OP_WRITE ,
    1248                         return IS_DEFINED(IORING_OP_WRITE);
    1249         #endif
    1250 
    1251         return false;
    1252 }
Note: See TracChangeset for help on using the changeset viewer.