@@ -241,6 +241,8 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
241241 io_uring_sqe_set_data (sqe, &timer_ctx);
242242 }
243243
244+ if (try_submit () < 0 ) return -1 ;
245+
244246 SCOPED_PAUSE_WORK_STEALING ;
245247 photon::thread_sleep (-1 );
246248
@@ -268,6 +270,15 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
268270 }
269271 }
270272
273+ int try_submit () {
274+ if (m_args.eager_submit ) {
275+ int ret = io_uring_submit (m_ring);
276+ if (ret < 0 )
277+ LOG_ERROR_RETURN (-ret, -1 , " iouring: failed to io_uring_submit(), " , ERRNO (-ret));
278+ }
279+ return 0 ;
280+ }
281+
271282 int wait_for_fd (int fd, uint32_t interests, Timeout timeout) override {
272283 if (unlikely (interests == 0 ))
273284 return 0 ;
@@ -289,9 +300,8 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
289300
290301 bool one_shot = e.interests & ONE_SHOT ;
291302 fdInterest fd_interest{e.fd , (uint32_t )evmap.translate_bitwisely (e.interests )};
292- ioCtx io_ctx (false , true );
293- eventCtx event_ctx{e, one_shot, io_ctx};
294- auto pair = m_event_contexts.insert ({fd_interest, event_ctx});
303+ eventCtx event_ctx{e, one_shot, {false , true }};
304+ auto pair = m_event_contexts.emplace (fd_interest, event_ctx);
295305 if (!pair.second ) {
296306 LOG_ERROR_RETURN (0 , -1 , " iouring: event has already been added" );
297307 }
@@ -302,10 +312,7 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
302312 io_uring_prep_poll_multishot (sqe, fd_interest.fd , fd_interest.interest );
303313 }
304314 io_uring_sqe_set_data (sqe, &pair.first ->second .io_ctx );
305- int ret = io_uring_submit (m_ring);
306- if (ret < 0 )
307- LOG_ERROR_RETURN (-ret, -1 , " iouring: fail to submit when adding interest, " , ERRNO (-ret));
308- return 0 ;
315+ return try_submit ();
309316 }
310317
311318 int rm_interest (Event e) override {
@@ -321,74 +328,29 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
321328
322329 io_uring_prep_poll_remove (sqe, (__u64) &iter->second .io_ctx );
323330 io_uring_sqe_set_data (sqe, nullptr );
324- int ret = io_uring_submit (m_ring);
325- if (ret < 0 )
326- LOG_ERROR_RETURN (-ret, -1 , " iouring: fail to submit when removing interest, " , ERRNO (-ret));
327- return 0 ;
331+ return try_submit ();
328332 }
329333
330334 ssize_t wait_for_events (void ** data, size_t count, Timeout timeout) override {
335+ if (!(m_ring->flags & IORING_SETUP_SQPOLL ) &&
336+ m_ring->sq .sqe_tail != *m_ring->sq .khead )
337+ io_uring_submit (m_ring);
338+
331339 // Use master engine to wait for self event fd
332340 int ret = ::photon::wait_for_fd_readable (m_eventfd, timeout);
333341 if (ret < 0 ) {
334342 return errno == ETIMEDOUT ? 0 : -1 ;
335343 }
336344 uint64_t value;
337345 eventfd_read (m_eventfd, &value);
338-
339- // Reap events
340- size_t num = 0 ;
341- io_uring_cqe* cqe = nullptr ;
342- uint32_t head = 0 ;
343- unsigned i = 0 ;
344- io_uring_for_each_cqe (m_ring, head, cqe) {
345- ++i;
346- auto ctx = (ioCtx*) io_uring_cqe_get_data (cqe);
347- if (!ctx) {
348- // rm_interest didn't set user data
349- continue ;
350- }
351- ctx->res = cqe->res ;
352- if (cqe->flags & IORING_CQE_F_MORE && cqe->res & POLLERR ) {
353- LOG_ERROR_RETURN (0 , -1 , " iouring: multi-shot poll got POLLERR" );
354- }
355- if (!ctx->is_event ) {
356- LOG_ERROR_RETURN (0 , -1 , " iouring: cascading engine only needs to handle event. Must be a bug..." )
357- }
358- eventCtx* event_ctx = container_of (ctx, eventCtx, io_ctx);
359- fdInterest fd_interest{event_ctx->event .fd , (uint32_t )evmap.translate_bitwisely (event_ctx->event .interests )};
360- if (ctx->res == -ECANCELED ) {
361- m_event_contexts.erase (fd_interest);
362- } else if (event_ctx->one_shot ) {
363- data[num++] = event_ctx->event .data ;
364- m_event_contexts.erase (fd_interest);
365- } else {
366- data[num++] = event_ctx->event .data ;
367- }
368- if (num >= count) {
369- break ;
370- }
371- }
372- io_uring_cq_advance (m_ring, i);
373- return num;
346+ return reap_events (data, count);
374347 }
375-
376- ssize_t wait_and_fire_events (uint64_t timeout) override {
377- // Prepare own timeout
378- if (timeout > (uint64_t ) std::numeric_limits<int64_t >::max ()) {
379- timeout = std::numeric_limits<int64_t >::max ();
380- }
381-
382- auto ts = usec_to_timespec (timeout);
383- if (m_submit_wait_func (m_ring, &ts) != 0 ) {
384- return -1 ;
385- }
386-
387- uint32_t head = 0 ;
388- unsigned i = 0 ;
348+ ssize_t reap_events (void ** data = 0 , size_t count = 0 ) {
389349 io_uring_cqe* cqe;
350+ uint32_t head = 0 , num = 0 , n = 0 ;
351+ DEFER ( io_uring_cq_advance (m_ring, n) );
390352 io_uring_for_each_cqe (m_ring, head, cqe) {
391- i ++;
353+ n ++;
392354 auto ctx = (ioCtx*) io_uring_cqe_get_data (cqe);
393355 if (!ctx) {
394356 // Own timeout doesn't have user data
@@ -406,31 +368,65 @@ class iouringEngine : public MasterEventEngine, public CascadingEventEngine, pub
406368 // The cqe for notify, corresponding to IORING_CQE_F_MORE
407369 if (unlikely (cqe->res != 0 ))
408370 LOG_WARN (" iouring: send_zc fall back to copying" );
371+ assert (!ctx->is_event );
409372 photon::thread_interrupt (ctx->th_id , EOK );
410373 continue ;
411374 }
412375
413376 ctx->res = cqe->res ;
414- if (!ctx->is_canceller && ctx->res == -ECANCELED ) {
415- // An I/O was canceled because of:
416- // 1. IORING_OP_LINK_TIMEOUT. Leave the interrupt job to the linked timer later.
417- // 2. IORING_OP_POLL_REMOVE. The I/O is actually a polling.
418- // 3. IORING_OP_ASYNC_CANCEL. This OP is the superset of case 2.
419- ctx->res = -ETIMEDOUT ;
420- continue ;
421- } else if (ctx->is_canceller && ctx->res == -ECANCELED ) {
422- // The linked timer itself is also a canceller. The reasons it got cancelled could be:
423- // 1. I/O finished in time
424- // 2. I/O was cancelled by IORING_OP_ASYNC_CANCEL
425- continue ;
426- } else if (cqe->flags & IORING_CQE_F_MORE ) {
427- continue ;
377+ if (cqe->flags & IORING_CQE_F_MORE ) {
378+ if (cqe->res & POLLERR ) {
379+ assert (ctx->is_event );
380+ assert (num == 0 );
381+ LOG_ERROR_RETURN (0 , -1 , " iouring: multi-shot poll got POLLERR" );
382+ } else { continue ; }
383+ }
384+ if (!ctx->is_event ) {
385+ if (!ctx->is_canceller && ctx->res == -ECANCELED ) {
386+ // An I/O was canceled because of:
387+ // 1. IORING_OP_LINK_TIMEOUT. Leave the interrupt job to the linked timer later.
388+ // 2. IORING_OP_POLL_REMOVE. The I/O is actually a polling.
389+ // 3. IORING_OP_ASYNC_CANCEL. This OP is the superset of case 2.
390+ ctx->res = -ETIMEDOUT ;
391+ continue ;
392+ } else if (ctx->is_canceller && ctx->res == -ECANCELED ) {
393+ // The linked timer itself is also a canceller. The reasons it got cancelled could be:
394+ // 1. I/O finished in time
395+ // 2. I/O was cancelled by IORING_OP_ASYNC_CANCEL
396+ continue ;
397+ }
398+ photon::thread_interrupt (ctx->th_id , EOK );
399+
400+ } else /* if (ctx->is_event) */ {
401+
402+ if (num >= count) { --n; break ; }
403+ eventCtx* event_ctx = container_of (ctx, eventCtx, io_ctx);
404+ fdInterest fd_interest{event_ctx->event .fd , (uint32_t )evmap.translate_bitwisely (event_ctx->event .interests )};
405+ if (ctx->res == -ECANCELED ) {
406+ m_event_contexts.erase (fd_interest);
407+ } else if (event_ctx->one_shot ) {
408+ data[num++] = event_ctx->event .data ;
409+ m_event_contexts.erase (fd_interest);
410+ } else {
411+ data[num++] = event_ctx->event .data ;
412+ }
428413 }
414+ }
415+ return num;
416+ }
417+
418+ ssize_t wait_and_fire_events (uint64_t timeout) override {
419+ // Prepare own timeout
420+ if (timeout > (uint64_t ) std::numeric_limits<int64_t >::max ()) {
421+ timeout = std::numeric_limits<int64_t >::max ();
422+ }
429423
430- photon::thread_interrupt (ctx->th_id , EOK );
424+ auto ts = usec_to_timespec (timeout);
425+ if (m_submit_wait_func (m_ring, &ts) != 0 ) {
426+ return -1 ;
431427 }
432428
433- io_uring_cq_advance (m_ring, i );
429+ reap_events ( );
434430 return 0 ;
435431 }
436432
@@ -594,108 +590,105 @@ int iouringEngine::m_cooperative_task_flag = -1;
594590
595591iouringEngine::SubmitWaitFunc iouringEngine::m_submit_wait_func = nullptr ;
596592
597- template <typename ...Ts >
598- inline size_t do_async_io (Ts...xs ) {
599- auto mee = (iouringEngine*) get_vcpu ()->master_event_engine ;
600- return mee->async_io (xs...);
593+ inline iouringEngine* get_ring (CascadingEventEngine* cee) {
594+ return cee ? static_cast <iouringEngine*>(cee) :
595+ static_cast <iouringEngine*>(get_vcpu ()->master_event_engine );
601596}
602597
603- ssize_t iouring_pread (int fd, void * buf, size_t count, off_t offset, uint64_t flags, Timeout timeout) {
598+ ssize_t iouring_pread (int fd, void * buf, size_t count, off_t offset, uint64_t flags, Timeout timeout, CascadingEventEngine* cee ) {
604599 uint32_t ring_flags = flags >> 32 ;
605- return do_async_io (&io_uring_prep_read, timeout, ring_flags, fd, buf, count, offset);
600+ return get_ring (cee)-> async_io (&io_uring_prep_read, timeout, ring_flags, fd, buf, count, offset);
606601}
607602
608- ssize_t iouring_pwrite (int fd, const void * buf, size_t count, off_t offset, uint64_t flags, Timeout timeout) {
603+ ssize_t iouring_pwrite (int fd, const void * buf, size_t count, off_t offset, uint64_t flags, Timeout timeout, CascadingEventEngine* cee ) {
609604 uint32_t ring_flags = flags >> 32 ;
610- return do_async_io (&io_uring_prep_write, timeout, ring_flags, fd, buf, count, offset);
605+ return get_ring (cee)-> async_io (&io_uring_prep_write, timeout, ring_flags, fd, buf, count, offset);
611606}
612607
613- ssize_t iouring_preadv (int fd, const iovec* iov, int iovcnt, off_t offset, uint64_t flags, Timeout timeout) {
608+ ssize_t iouring_preadv (int fd, const iovec* iov, int iovcnt, off_t offset, uint64_t flags, Timeout timeout, CascadingEventEngine* cee ) {
614609 uint32_t ring_flags = flags >> 32 ;
615- return do_async_io (&io_uring_prep_readv, timeout, ring_flags, fd, iov, iovcnt, offset);
610+ return get_ring (cee)-> async_io (&io_uring_prep_readv, timeout, ring_flags, fd, iov, iovcnt, offset);
616611}
617612
618- ssize_t iouring_pwritev (int fd, const iovec* iov, int iovcnt, off_t offset, uint64_t flags, Timeout timeout) {
613+ ssize_t iouring_pwritev (int fd, const iovec* iov, int iovcnt, off_t offset, uint64_t flags, Timeout timeout, CascadingEventEngine* cee ) {
619614 uint32_t ring_flags = flags >> 32 ;
620- return do_async_io (&io_uring_prep_writev, timeout, ring_flags, fd, iov, iovcnt, offset);
615+ return get_ring (cee)-> async_io (&io_uring_prep_writev, timeout, ring_flags, fd, iov, iovcnt, offset);
621616}
622617
623- ssize_t iouring_send (int fd, const void * buf, size_t len, uint64_t flags, Timeout timeout) {
618+ ssize_t iouring_send (int fd, const void * buf, size_t len, uint64_t flags, Timeout timeout, CascadingEventEngine* cee ) {
624619 uint32_t io_flags = flags & 0xffffffff ;
625620 uint32_t ring_flags = flags >> 32 ;
626- return do_async_io (&io_uring_prep_send, timeout, ring_flags, fd, buf, len, io_flags);
621+ return get_ring (cee)-> async_io (&io_uring_prep_send, timeout, ring_flags, fd, buf, len, io_flags);
627622}
628623
629- ssize_t iouring_send_zc (int fd, const void * buf, size_t len, uint64_t flags, Timeout timeout) {
624+ ssize_t iouring_send_zc (int fd, const void * buf, size_t len, uint64_t flags, Timeout timeout, CascadingEventEngine* cee ) {
630625 uint32_t io_flags = flags & 0xffffffff ;
631626 uint32_t ring_flags = flags >> 32 ;
632- return do_async_io (&io_uring_prep_send_zc, timeout, ring_flags, fd, buf, len, io_flags, 0 );
627+ return get_ring (cee)-> async_io (&io_uring_prep_send_zc, timeout, ring_flags, fd, buf, len, io_flags, 0 );
633628}
634629
635- ssize_t iouring_sendmsg (int fd, const msghdr* msg, uint64_t flags, Timeout timeout) {
630+ ssize_t iouring_sendmsg (int fd, const msghdr* msg, uint64_t flags, Timeout timeout, CascadingEventEngine* cee ) {
636631 uint32_t io_flags = flags & 0xffffffff ;
637632 uint32_t ring_flags = flags >> 32 ;
638- return do_async_io (&io_uring_prep_sendmsg, timeout, ring_flags, fd, msg, io_flags);
633+ return get_ring (cee)-> async_io (&io_uring_prep_sendmsg, timeout, ring_flags, fd, msg, io_flags);
639634}
640635
641- ssize_t iouring_sendmsg_zc (int fd, const msghdr* msg, uint64_t flags, Timeout timeout) {
636+ ssize_t iouring_sendmsg_zc (int fd, const msghdr* msg, uint64_t flags, Timeout timeout, CascadingEventEngine* cee ) {
642637 uint32_t io_flags = flags & 0xffffffff ;
643638 uint32_t ring_flags = flags >> 32 ;
644- return do_async_io (&io_uring_prep_sendmsg_zc, timeout, ring_flags, fd, msg, io_flags);
639+ return get_ring (cee)-> async_io (&io_uring_prep_sendmsg_zc, timeout, ring_flags, fd, msg, io_flags);
645640}
646641
647- ssize_t iouring_recv (int fd, void * buf, size_t len, uint64_t flags, Timeout timeout) {
642+ ssize_t iouring_recv (int fd, void * buf, size_t len, uint64_t flags, Timeout timeout, CascadingEventEngine* cee ) {
648643 uint32_t io_flags = flags & 0xffffffff ;
649644 uint32_t ring_flags = flags >> 32 ;
650- return do_async_io (&io_uring_prep_recv, timeout, ring_flags, fd, buf, len, io_flags);
645+ return get_ring (cee)-> async_io (&io_uring_prep_recv, timeout, ring_flags, fd, buf, len, io_flags);
651646}
652647
653- ssize_t iouring_recvmsg (int fd, msghdr* msg, uint64_t flags, Timeout timeout) {
648+ ssize_t iouring_recvmsg (int fd, msghdr* msg, uint64_t flags, Timeout timeout, CascadingEventEngine* cee ) {
654649 uint32_t io_flags = flags & 0xffffffff ;
655650 uint32_t ring_flags = flags >> 32 ;
656- return do_async_io (&io_uring_prep_recvmsg, timeout, ring_flags, fd, msg, io_flags);
651+ return get_ring (cee)-> async_io (&io_uring_prep_recvmsg, timeout, ring_flags, fd, msg, io_flags);
657652}
658653
659- int iouring_connect (int fd, const sockaddr* addr, socklen_t addrlen, Timeout timeout) {
660- return do_async_io (&io_uring_prep_connect, timeout, 0 , fd, addr, addrlen);
654+ int iouring_connect (int fd, const sockaddr* addr, socklen_t addrlen, Timeout timeout, CascadingEventEngine* cee ) {
655+ return get_ring (cee)-> async_io (&io_uring_prep_connect, timeout, 0 , fd, addr, addrlen);
661656}
662657
663- int iouring_accept (int fd, sockaddr* addr, socklen_t * addrlen, Timeout timeout) {
664- return do_async_io (&io_uring_prep_accept, timeout, 0 , fd, addr, addrlen, 0 );
658+ int iouring_accept (int fd, sockaddr* addr, socklen_t * addrlen, Timeout timeout, CascadingEventEngine* cee ) {
659+ return get_ring (cee)-> async_io (&io_uring_prep_accept, timeout, 0 , fd, addr, addrlen, 0 );
665660}
666661
667- int iouring_fsync (int fd) {
668- return do_async_io ( &io_uring_prep_fsync, - 1 , 0 , fd, 0 );
662+ int iouring_fsync (int fd, Timeout timeout, CascadingEventEngine* cee ) {
663+ return get_ring (cee)-> async_io ( &io_uring_prep_fsync, timeout , 0 , fd, 0 );
669664}
670665
671- int iouring_fdatasync (int fd) {
672- return do_async_io ( &io_uring_prep_fsync, - 1 , 0 , fd, IORING_FSYNC_DATASYNC );
666+ int iouring_fdatasync (int fd, Timeout timeout, CascadingEventEngine* cee ) {
667+ return get_ring (cee)-> async_io ( &io_uring_prep_fsync, timeout , 0 , fd, IORING_FSYNC_DATASYNC );
673668}
674669
675- int iouring_open (const char * path, int flags, mode_t mode) {
676- return do_async_io ( &io_uring_prep_openat, - 1 , 0 , AT_FDCWD , path, flags, mode);
670+ int iouring_open (const char * path, int flags, mode_t mode, Timeout timeout, CascadingEventEngine* cee ) {
671+ return get_ring (cee)-> async_io ( &io_uring_prep_openat, timeout , 0 , AT_FDCWD , path, flags, mode);
677672}
678673
679- int iouring_mkdir (const char * path, mode_t mode) {
680- return do_async_io ( &io_uring_prep_mkdirat, - 1 , 0 , AT_FDCWD , path, mode);
674+ int iouring_mkdir (const char * path, mode_t mode, Timeout timeout, CascadingEventEngine* cee ) {
675+ return get_ring (cee)-> async_io ( &io_uring_prep_mkdirat, timeout , 0 , AT_FDCWD , path, mode);
681676}
682677
683- int iouring_close (int fd) {
684- return do_async_io ( &io_uring_prep_close, - 1 , 0 , fd);
678+ int iouring_close (int fd, Timeout timeout, CascadingEventEngine* cee ) {
679+ return get_ring (cee)-> async_io ( &io_uring_prep_close, timeout , 0 , fd);
685680}
686681
687682bool iouring_register_files_enabled () {
688683 return iouringEngine::register_files_enabled ();
689684}
690685
691- int iouring_register_files (int fd) {
692- auto ee = (iouringEngine*) get_vcpu ()->master_event_engine ;
693- return ee->register_unregister_files (fd, true );
686+ int iouring_register_files (int fd, CascadingEventEngine* cee) {
687+ return get_ring (cee)->register_unregister_files (fd, true );
694688}
695689
696- int iouring_unregister_files (int fd) {
697- auto ee = (iouringEngine*) get_vcpu ()->master_event_engine ;
698- return ee->register_unregister_files (fd, false );
690+ int iouring_unregister_files (int fd, CascadingEventEngine* cee) {
691+ return get_ring (cee)->register_unregister_files (fd, false );
699692}
700693
701694void * new_iouring_event_engine (iouring_args args) {
0 commit comments