Ignore:
File:
1 edited

Legend:

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

    r732b406 rdf40a56  
    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 
    4740        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>
    4847                #include <sys/syscall.h>
    4948
     
    109108                volatile uint32_t * head;
    110109                volatile uint32_t * tail;
    111                 volatile uint32_t prev_head;
    112110
    113111                // The actual kernel ring which uses head/tail
     
    130128
    131129                __spinlock_t lock;
    132                 __spinlock_t release_lock;
    133130
    134131                // A buffer of sqes (not the actual ring)
     
    184181//=============================================================================================
    185182        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 
    190183                this.io = malloc();
    191184
     
    193186                struct io_uring_params params;
    194187                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;
    197188
    198189                uint32_t nentries = entries_per_cluster();
     
    261252                sq.dropped = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
    262253                sq.array   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
    263                 sq.prev_head = *sq.head;
    264254
    265255                {
     
    270260                }
    271261
    272                 (sq.lock){};
    273                 (sq.release_lock){};
    274 
    275                 if( io_flags & ( CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS | CFA_CLUSTER_IO_EAGER_SUBMITS ) ) {
     262                if( io_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS ) {
    276263                        /* paranoid */ verify( is_pow2( io_flags >> CFA_CLUSTER_IO_BUFFLEN_OFFSET ) || ((io_flags >> CFA_CLUSTER_IO_BUFFLEN_OFFSET) < 8)  );
    277264                        sq.ready_cnt = max(io_flags >> CFA_CLUSTER_IO_BUFFLEN_OFFSET, 8);
     
    433420// I/O Polling
    434421//=============================================================================================
    435         static unsigned __collect_submitions( struct __io_data & ring );
    436         static uint32_t __release_consumed_submission( struct __io_data & ring );
     422        struct io_user_data {
     423                int32_t result;
     424                $thread * thrd;
     425        };
    437426
    438427        // Process a single completion message from the io_uring
    439428        // This is NOT thread-safe
    440429        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 
    444430                unsigned to_submit = 0;
    445431                if( ring.cltr_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS ) {
     432
    446433                        // If the poller thread also submits, then we need to aggregate the submissions which are ready
    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 );
     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
    477486
    478487                // Drain the queue
     
    481490                const uint32_t mask = *ring.completion_q.mask;
    482491
     492                // Memory barrier
     493                __atomic_thread_fence( __ATOMIC_SEQ_CST );
     494
    483495                // Nothing was new return 0
    484496                if (head == tail) {
    485                         return [0, to_submit > 0];
     497                        return 0;
    486498                }
    487499
    488500                uint32_t count = tail - head;
    489                 /* paranoid */ verify( count != 0 );
    490501                for(i; count) {
    491502                        unsigned idx = (head + i) & mask;
     
    494505                        /* paranoid */ verify(&cqe);
    495506
    496                         struct __io_user_data_t * data = (struct __io_user_data_t *)(uintptr_t)cqe.user_data;
     507                        struct io_user_data * data = (struct io_user_data *)(uintptr_t)cqe.user_data;
    497508                        __cfadbg_print_safe( io, "Kernel I/O : Performed reading io cqe %p, result %d for %p\n", data, cqe.res, data->thrd );
    498509
     
    552563
    553564                                // Update statistics
    554                                 __STATS__( true,
    555                                         io.complete_q.completed_avg.val += count;
    556                                         io.complete_q.completed_avg.slow_cnt += 1;
    557                                 )
     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
    558569
    559570                                if(again) {
     
    569580                                int count;
    570581                                bool again;
    571                                 [count, again] = __drain_io( ring, &mask, 1, true );
     582                                [count, again] = __drain_io( ring, &mask, 0, true );
    572583
    573584                                // Update statistics
    574                                 __STATS__( true,
    575                                         io.complete_q.completed_avg.val += count;
    576                                         io.complete_q.completed_avg.slow_cnt += 1;
    577                                 )
     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
    578589                        }
    579590                }
     
    612623
    613624                                // Update statistics
    614                                 __STATS__( true,
    615                                         io.complete_q.completed_avg.val += count;
    616                                         io.complete_q.completed_avg.fast_cnt += 1;
    617                                 )
     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
    618629                        enable_interrupts( __cfaabi_dbg_ctx );
    619630
     
    651662
    652663// Submition steps :
    653 // 1 - Allocate a queue entry. The ring already has memory for all entries but only the ones
     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
    654673//     listed in sq.array are visible by the kernel. For those not listed, the kernel does not
    655674//     offer any assurance that an entry is not being filled by multiple flags. Therefore, we
    656675//     need to write an allocator that allows allocating concurrently.
    657676//
    658 // 2 - Actually fill the submit entry, this is the only simple and straightforward step.
     677// 3 - Actually fill the submit entry, this is the only simple and straightforward step.
    659678//
    660 // 3 - Append the entry index to the array and adjust the tail accordingly. This operation
     679// 4 - Append the entry index to the array and adjust the tail accordingly. This operation
    661680//     needs to arrive to two concensus at the same time:
    662681//     A - The order in which entries are listed in the array: no two threads must pick the
     
    666685//
    667686
    668         [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) {
    669                 /* paranoid */ verify( data != 0 );
     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
    670691
    671692                // Prepare the data we need
     
    692713                                {
    693714                                        // update statistics
    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                                         )
     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
    699722
    700723
     
    739762
    740763                        block++;
    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                         }
     764                        yield();
    748765                }
    749766
    750767                // update statistics
    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                 )
     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
    756775
    757776                return picked;
    758777        }
    759778
    760         void __submit( struct __io_data & ring, uint32_t idx ) {
     779        // void __submit( struct __io_data & ring, uint32_t idx ) __attribute__((noinline));
     780        static inline void __submit( struct __io_data & ring, uint32_t idx ) {
    761781                // Get now the data we definetely need
    762782                uint32_t * const tail = ring.submit_q.tail;
     
    766786                if( ring.cltr_flags & CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS ) {
    767787                        // If the poller thread submits, then we just need to add this to the ready array
     788
    768789                        __submit_to_ready_array( ring, idx, mask );
    769790
     
    771792
    772793                        __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);
    828794                }
    829795                else {
     
    837803                        ring.submit_q.array[ (*tail) & mask ] = idx & mask;
    838804                        __atomic_fetch_add(tail, 1ul32, __ATOMIC_SEQ_CST);
    839 
    840                         /* paranoid */ verify( ring.submit_q.sqes[ idx ].user_data != 0 );
    841805
    842806                        // Submit however, many entries need to be submitted
     
    850814
    851815                        // update statistics
    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 );
     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;
    859822
    860823                        unlock(ring.submit_q.lock);
     
    864827        }
    865828
    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         }
     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;
    909870#endif
     871
     872// Some forward declarations
     873extern "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
     940int 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
     952int 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
     968ssize_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
     981ssize_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
     994ssize_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
     1009ssize_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
     1024int 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
     1039int 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
     1053int 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
     1068int 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
     1083int 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
     1098int 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
     1113int 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
     1126ssize_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
     1138ssize_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
     1159bool 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.