| /* SPDX-License-Identifier: MIT */ | |
| #ifndef LIBURING_PROXY_H | |
| #define LIBURING_PROXY_H | |
| #include <sys/time.h> | |
| /* | |
| * Generic opcode agnostic encoding to sqe/cqe->user_data | |
| */ | |
| struct userdata { | |
| union { | |
| struct { | |
| uint16_t op_tid; /* 4 bits op, 12 bits tid */ | |
| uint16_t bid; | |
| uint16_t fd; | |
| }; | |
| uint64_t val; | |
| }; | |
| }; | |
| #define OP_SHIFT (12) | |
| #define TID_MASK ((1U << 12) - 1) | |
| /* | |
| * Packs the information that we will need at completion time into the | |
| * sqe->user_data field, which is passed back in the completion in | |
| * cqe->user_data. Some apps would need more space than this, and in fact | |
| * I'd love to pack the requested IO size in here, and it's not uncommon to | |
| * see apps use this field as just a cookie to either index a data structure | |
| * at completion time, or even just put the pointer to the associated | |
| * structure into this field. | |
| */ | |
| static inline void __encode_userdata(struct io_uring_sqe *sqe, int tid, int op, | |
| int bid, int fd) | |
| { | |
| struct userdata ud = { | |
| .op_tid = (op << OP_SHIFT) | tid, | |
| .bid = bid, | |
| .fd = fd | |
| }; | |
| io_uring_sqe_set_data64(sqe, ud.val); | |
| } | |
| static inline uint64_t __raw_encode(int tid, int op, int bid, int fd) | |
| { | |
| struct userdata ud = { | |
| .op_tid = (op << OP_SHIFT) | tid, | |
| .bid = bid, | |
| .fd = fd | |
| }; | |
| return ud.val; | |
| } | |
| static inline int cqe_to_op(struct io_uring_cqe *cqe) | |
| { | |
| struct userdata ud = { .val = cqe->user_data }; | |
| return ud.op_tid >> OP_SHIFT; | |
| } | |
| static inline int cqe_to_bid(struct io_uring_cqe *cqe) | |
| { | |
| struct userdata ud = { .val = cqe->user_data }; | |
| return ud.bid; | |
| } | |
| static inline int cqe_to_fd(struct io_uring_cqe *cqe) | |
| { | |
| struct userdata ud = { .val = cqe->user_data }; | |
| return ud.fd; | |
| } | |
| static unsigned long long mtime_since(const struct timeval *s, | |
| const struct timeval *e) | |
| { | |
| long long sec, usec; | |
| sec = e->tv_sec - s->tv_sec; | |
| usec = (e->tv_usec - s->tv_usec); | |
| if (sec > 0 && usec < 0) { | |
| sec--; | |
| usec += 1000000; | |
| } | |
| sec *= 1000; | |
| usec /= 1000; | |
| return sec + usec; | |
| } | |
| static unsigned long long mtime_since_now(struct timeval *tv) | |
| { | |
| struct timeval end; | |
| gettimeofday(&end, NULL); | |
| return mtime_since(tv, &end); | |
| } | |
| #endif |