@@ -559,7 +559,7 @@ conn_flags_to_epoll_events(enum lwan_connection_flags flags)
559
559
return EPOLL_EVENTS (flags );
560
560
}
561
561
562
- static void update_epoll_flags (const struct timeout_queue * tq ,
562
+ static void update_epoll_flags (const struct lwan * lwan ,
563
563
struct lwan_connection * conn ,
564
564
int epoll_fd ,
565
565
enum lwan_connection_coro_yield yield_result )
@@ -609,7 +609,7 @@ static void update_epoll_flags(const struct timeout_queue *tq,
609
609
610
610
struct epoll_event event = {.events = conn_flags_to_epoll_events (conn -> flags ),
611
611
.data .ptr = conn };
612
- int fd = lwan_connection_get_fd (tq -> lwan , conn );
612
+ int fd = lwan_connection_get_fd (lwan , conn );
613
613
614
614
if (UNLIKELY (epoll_ctl (epoll_fd , EPOLL_CTL_MOD , fd , & event ) < 0 ))
615
615
lwan_status_perror ("epoll_ctl" );
@@ -619,7 +619,11 @@ static void unasync_await_conn(void *data1, void *data2)
619
619
{
620
620
struct lwan_connection * async_fd_conn = data1 ;
621
621
622
- async_fd_conn -> flags &= ~(CONN_ASYNC_AWAIT | CONN_HUNG_UP );
622
+ async_fd_conn -> flags &=
623
+ ~(CONN_ASYNC_AWAIT | CONN_HUNG_UP | CONN_ASYNC_AWAIT_MULTIPLE );
624
+ assert (async_fd_conn -> parent );
625
+ async_fd_conn -> parent -> flags &= ~CONN_ASYNC_AWAIT_MULTIPLE ;
626
+
623
627
async_fd_conn -> thread = data2 ;
624
628
625
629
/* If this file descriptor number is used again in the future as an HTTP
@@ -635,9 +639,9 @@ static void unasync_await_conn(void *data1, void *data2)
635
639
}
636
640
637
641
static enum lwan_connection_coro_yield
638
- resume_async (const struct timeout_queue * tq ,
642
+ resume_async (const struct lwan * l ,
639
643
enum lwan_connection_coro_yield yield_result ,
640
- int64_t from_coro ,
644
+ int await_fd ,
641
645
struct lwan_connection * conn ,
642
646
int epoll_fd )
643
647
{
@@ -646,7 +650,6 @@ resume_async(const struct timeout_queue *tq,
646
650
[CONN_CORO_ASYNC_AWAIT_WRITE ] = CONN_EVENTS_WRITE ,
647
651
[CONN_CORO_ASYNC_AWAIT_READ_WRITE ] = CONN_EVENTS_READ_WRITE ,
648
652
};
649
- int await_fd = (int )((uint64_t )from_coro >> 32 );
650
653
enum lwan_connection_flags flags ;
651
654
int op ;
652
655
@@ -656,7 +659,7 @@ resume_async(const struct timeout_queue *tq,
656
659
657
660
flags = to_connection_flags [yield_result ];
658
661
659
- struct lwan_connection * await_fd_conn = & tq -> lwan -> conns [await_fd ];
662
+ struct lwan_connection * await_fd_conn = & l -> conns [await_fd ];
660
663
if (LIKELY (await_fd_conn -> flags & CONN_ASYNC_AWAIT )) {
661
664
if (LIKELY ((await_fd_conn -> flags & CONN_EVENTS_MASK ) == flags ))
662
665
return CONN_CORO_SUSPEND ;
@@ -697,6 +700,168 @@ resume_async(const struct timeout_queue *tq,
697
700
return CONN_CORO_ABORT ;
698
701
}
699
702
703
+ struct flag_update {
704
+ unsigned int num_awaiting ;
705
+ enum lwan_connection_coro_yield request_conn_yield ;
706
+ };
707
+
708
+ static struct flag_update
709
+ update_flags_for_async_awaitv (struct lwan_request * r , struct lwan * l , va_list ap )
710
+ {
711
+ int epoll_fd = r -> conn -> thread -> epoll_fd ;
712
+ struct flag_update update = {.num_awaiting = 0 ,
713
+ .request_conn_yield = CONN_CORO_YIELD };
714
+
715
+ while (true) {
716
+ int await_fd = va_arg (ap , int );
717
+ if (await_fd < 0 ) {
718
+ return update ;
719
+ }
720
+
721
+ enum lwan_connection_coro_yield events =
722
+ va_arg (ap , enum lwan_connection_coro_yield );
723
+ if (UNLIKELY (events < CONN_CORO_ASYNC_AWAIT_READ ||
724
+ events > CONN_CORO_ASYNC_AWAIT_READ_WRITE )) {
725
+ lwan_status_error ("awaitv() called with invalid events" );
726
+ coro_yield (r -> conn -> coro , CONN_CORO_ABORT );
727
+ __builtin_unreachable ();
728
+ }
729
+
730
+ struct lwan_connection * conn = & l -> conns [await_fd ];
731
+
732
+ if (UNLIKELY (conn -> flags & CONN_ASYNC_AWAIT_MULTIPLE )) {
733
+ lwan_status_debug ("ignoring second awaitv call on same fd: %d" ,
734
+ await_fd );
735
+ continue ;
736
+ }
737
+
738
+ conn -> flags |= CONN_ASYNC_AWAIT_MULTIPLE ;
739
+ update .num_awaiting ++ ;
740
+
741
+ if (await_fd == r -> fd ) {
742
+ static const enum lwan_connection_coro_yield to_request_yield [] = {
743
+ [CONN_CORO_ASYNC_AWAIT_READ ] = CONN_CORO_WANT_READ ,
744
+ [CONN_CORO_ASYNC_AWAIT_WRITE ] = CONN_CORO_WANT_WRITE ,
745
+ [CONN_CORO_ASYNC_AWAIT_READ_WRITE ] = CONN_CORO_WANT_READ_WRITE ,
746
+ };
747
+
748
+ update .request_conn_yield = to_request_yield [events ];
749
+ continue ;
750
+ }
751
+
752
+ events = resume_async (l , events , await_fd , r -> conn , epoll_fd );
753
+ if (UNLIKELY (events == CONN_CORO_ABORT )) {
754
+ lwan_status_error ("could not register fd for async operation" );
755
+ coro_yield (r -> conn -> coro , CONN_CORO_ABORT );
756
+ __builtin_unreachable ();
757
+ }
758
+ }
759
+ }
760
+
761
+ static void reset_conn_async_await_multiple_flag (struct lwan_connection * conns ,
762
+ va_list ap )
763
+ {
764
+ while (true) {
765
+ int await_fd = va_arg (ap , int );
766
+ if (await_fd < 0 )
767
+ return ;
768
+
769
+ struct lwan_connection * conn = & conns [await_fd ];
770
+ conn -> flags &= ~CONN_ASYNC_AWAIT_MULTIPLE ;
771
+
772
+ LWAN_NO_DISCARD (va_arg (ap , enum lwan_connection_coro_yield ));
773
+ }
774
+ }
775
+
776
+ int lwan_request_awaitv_any (struct lwan_request * r , ...)
777
+ {
778
+ struct lwan * l = r -> conn -> thread -> lwan ;
779
+ va_list ap ;
780
+
781
+ va_start (ap , r );
782
+ reset_conn_async_await_multiple_flag (l -> conns , ap );
783
+ va_end (ap );
784
+
785
+ va_start (ap , r );
786
+ struct flag_update update = update_flags_for_async_awaitv (r , l , ap );
787
+ va_end (ap );
788
+
789
+ while (true) {
790
+ int64_t v = coro_yield (r -> conn -> coro , update .request_conn_yield );
791
+ struct lwan_connection * conn = (struct lwan_connection * )(uintptr_t )v ;
792
+
793
+ if (conn -> flags & CONN_ASYNC_AWAIT_MULTIPLE ) {
794
+ va_start (ap , r );
795
+ reset_conn_async_await_multiple_flag (l -> conns , ap );
796
+ va_end (ap );
797
+
798
+ return lwan_connection_get_fd (l , conn );
799
+ }
800
+ }
801
+ }
802
+
803
+ void lwan_request_awaitv_all (struct lwan_request * r , ...)
804
+ {
805
+ struct lwan * l = r -> conn -> thread -> lwan ;
806
+ va_list ap ;
807
+
808
+ va_start (ap , r );
809
+ reset_conn_async_await_multiple_flag (l -> conns , ap );
810
+ va_end (ap );
811
+
812
+ va_start (ap , r );
813
+ struct flag_update update = update_flags_for_async_awaitv (r , l , ap );
814
+ va_end (ap );
815
+
816
+ while (update .num_awaiting ) {
817
+ int64_t v = coro_yield (r -> conn -> coro , update .request_conn_yield );
818
+ struct lwan_connection * conn = (struct lwan_connection * )(uintptr_t )v ;
819
+
820
+ if (conn -> flags & CONN_ASYNC_AWAIT_MULTIPLE ) {
821
+ conn -> flags &= ~CONN_ASYNC_AWAIT_MULTIPLE ;
822
+ update .num_awaiting -- ;
823
+ }
824
+ }
825
+ }
826
+
827
+ static inline int64_t
828
+ make_async_yield_value (int fd , enum lwan_connection_coro_yield event )
829
+ {
830
+ assert (event >= CONN_CORO_ASYNC_AWAIT_READ &&
831
+ event <= CONN_CORO_ASYNC_AWAIT_READ_WRITE );
832
+
833
+ return (int64_t )(((uint64_t )fd << 32 | event ));
834
+ }
835
+
836
+ static inline int async_await_fd (struct lwan_connection * conn ,
837
+ int fd ,
838
+ enum lwan_connection_coro_yield events )
839
+ {
840
+ int64_t yield_value = make_async_yield_value (fd , events );
841
+ int64_t from_coro = coro_yield (conn -> coro , yield_value );
842
+ struct lwan_connection * conn_from_coro =
843
+ (struct lwan_connection * )(intptr_t )from_coro ;
844
+
845
+ assert (conn_from_coro -> flags & CONN_ASYNC_AWAIT );
846
+
847
+ return lwan_connection_get_fd (conn -> thread -> lwan , conn_from_coro );
848
+ }
849
+
850
+ inline int lwan_request_await_read (struct lwan_request * r , int fd )
851
+ {
852
+ return async_await_fd (r -> conn , fd , CONN_CORO_ASYNC_AWAIT_READ );
853
+ }
854
+
855
+ inline int lwan_request_await_write (struct lwan_request * r , int fd )
856
+ {
857
+ return async_await_fd (r -> conn , fd , CONN_CORO_ASYNC_AWAIT_WRITE );
858
+ }
859
+
860
+ inline int lwan_request_await_read_write (struct lwan_request * r , int fd )
861
+ {
862
+ return async_await_fd (r -> conn , fd , CONN_CORO_ASYNC_AWAIT_READ_WRITE );
863
+ }
864
+
700
865
static ALWAYS_INLINE void resume_coro (struct timeout_queue * tq ,
701
866
struct lwan_connection * conn_to_resume ,
702
867
struct lwan_connection * conn_to_yield ,
@@ -710,14 +875,15 @@ static ALWAYS_INLINE void resume_coro(struct timeout_queue *tq,
710
875
enum lwan_connection_coro_yield yield_result = from_coro & 0xffffffff ;
711
876
712
877
if (UNLIKELY (yield_result >= CONN_CORO_ASYNC )) {
713
- yield_result =
714
- resume_async (tq , yield_result , from_coro , conn_to_resume , epoll_fd );
878
+ int await_fd = (int )((uint64_t )from_coro >> 32 );
879
+ yield_result = resume_async (tq -> lwan , yield_result , await_fd ,
880
+ conn_to_resume , epoll_fd );
715
881
}
716
882
717
883
if (UNLIKELY (yield_result == CONN_CORO_ABORT )) {
718
884
timeout_queue_expire (tq , conn_to_resume );
719
885
} else {
720
- update_epoll_flags (tq , conn_to_resume , epoll_fd , yield_result );
886
+ update_epoll_flags (tq -> lwan , conn_to_resume , epoll_fd , yield_result );
721
887
timeout_queue_move_to_last (tq , conn_to_resume );
722
888
}
723
889
}
@@ -787,7 +953,7 @@ static bool process_pending_timers(struct timeout_queue *tq,
787
953
}
788
954
789
955
request = container_of (timeout , struct lwan_request , timeout );
790
- update_epoll_flags (tq , request -> conn , epoll_fd , CONN_CORO_RESUME );
956
+ update_epoll_flags (tq -> lwan , request -> conn , epoll_fd , CONN_CORO_RESUME );
791
957
}
792
958
793
959
if (should_expire_timers ) {
@@ -1452,7 +1618,7 @@ void lwan_thread_init(struct lwan *l)
1452
1618
1453
1619
for (unsigned int i = 0 ; i < l -> thread .count ; i ++ ) {
1454
1620
struct lwan_thread * thread ;
1455
-
1621
+
1456
1622
if (schedtbl ) {
1457
1623
/* For SO_ATTACH_REUSEPORT_CBPF to work with the program
1458
1624
* we provide the kernel, sockets have to be added to the
0 commit comments