11extern crate std;
22
3- use core:: ffi:: c_int;
43use core:: sync:: atomic:: { AtomicI64 , Ordering } ;
5- use core:: { mem, ptr} ;
6- use std:: sync:: OnceLock ;
74
85use core:: future:: Future ;
6+ use std:: sync:: OnceLock ;
97
10- use alloc:: boxed:: Box ;
118pub use async_task:: Task ;
129use async_task:: { Runnable , ScheduleInfo , WithInfo } ;
1310use crossbeam_channel:: { unbounded, Receiver , Sender } ;
14- use nginx_sys:: { kill , ngx_event_t, ngx_post_event , ngx_posted_next_events , ngx_thread_tid, SIGIO } ;
11+ use nginx_sys:: { ngx_event_t, ngx_thread_tid} ;
1512
1613use crate :: log:: ngx_cycle_log;
1714use crate :: ngx_log_debug;
1815
16+ #[ cfg( not( feature = "async_eventfd" ) ) ]
17+ mod default {
18+ extern crate std;
19+
20+ use nginx_sys:: { kill, SIGIO } ;
21+
22+ use crate :: log:: ngx_cycle_log;
23+ use crate :: ngx_log_debug;
24+
25+ pub ( crate ) fn notify ( ) {
26+ let rc = unsafe {
27+ kill (
28+ std:: process:: id ( ) . try_into ( ) . unwrap ( ) ,
29+ SIGIO . try_into ( ) . unwrap ( ) ,
30+ )
31+ } ;
32+ if rc != 0 {
33+ panic ! ( "kill: rc={rc}" ) ;
34+ }
35+
36+ ngx_log_debug ! ( ngx_cycle_log( ) . as_ptr( ) , "async: notified (SIGIO)" ) ;
37+ }
38+ }
39+ #[ cfg( not( feature = "async_eventfd" ) ) ]
40+ use default:: * ;
41+
42+ #[ cfg( feature = "async_eventfd" ) ]
43+ mod eventfd {
44+ extern crate std;
45+
46+ use core:: mem;
47+
48+ use nginx_sys:: {
49+ eventfd, ngx_connection_t, ngx_cycle, ngx_event_actions, ngx_event_t, ngx_int_t, ngx_log_t,
50+ EFD_CLOEXEC , EFD_NONBLOCK , NGX_ERROR , NGX_OK ,
51+ } ;
52+ use std:: { fs:: File , io:: Write , os:: fd:: FromRawFd , sync:: OnceLock } ;
53+
54+ use crate :: log:: ngx_cycle_log;
55+ use crate :: ngx_log_debug;
56+
57+ #[ cfg( not( ngx_feature = "have_eventfd" ) ) ]
58+ compile_error ! ( "feature async_eventfd requires eventfd(), NGX_HAVE_EVENTFD" ) ;
59+
60+ pub ( crate ) fn notify ( ) {
61+ let w = EVENT_FILE
62+ . get ( )
63+ . expect ( "EVENT_FILE" )
64+ . write ( & 1u64 . to_ne_bytes ( ) )
65+ . expect ( "write" ) ;
66+ if w != 8 {
67+ panic ! ( "eventfd: wrote {w}, expected 8" ) ;
68+ }
69+
70+ ngx_log_debug ! ( ngx_cycle_log( ) . as_ptr( ) , "async: notified (eventfd)" ) ;
71+ }
72+
73+ static mut NOTIFY_EVENT : ngx_event_t = unsafe { mem:: zeroed ( ) } ;
74+ static mut NOTIFY_CONN : ngx_connection_t = unsafe { mem:: zeroed ( ) } ;
75+ static EVENT_FILE : OnceLock < File > = OnceLock :: new ( ) ;
76+ static mut DUMMY_WRITE_EVENT : ngx_event_t = unsafe { mem:: zeroed ( ) } ;
77+
78+ extern "C" fn _dummy_write_handler ( _ev : * mut ngx_event_t ) { }
79+
80+ /// intialize async_eventfd, needs to be called once in init_process, before spawn() is used
81+ pub fn async_init ( ) -> ngx_int_t {
82+ let fd = unsafe { eventfd ( 0 , ( EFD_NONBLOCK | EFD_CLOEXEC ) . try_into ( ) . unwrap ( ) ) } ;
83+ if fd == -1 {
84+ return NGX_ERROR as isize ;
85+ }
86+
87+ let log: * mut ngx_log_t = unsafe { ngx_cycle. read ( ) . log } ;
88+
89+ ngx_log_debug ! ( log, "async: eventfd {fd}" ) ;
90+
91+ unsafe {
92+ NOTIFY_EVENT . handler = Some ( super :: async_handler) ;
93+ NOTIFY_EVENT . log = log;
94+ ( & raw mut NOTIFY_EVENT ) . read ( ) . set_active ( 1 ) ;
95+ NOTIFY_EVENT . data = ( & raw mut NOTIFY_CONN ) . cast ( ) ;
96+
97+ DUMMY_WRITE_EVENT . handler = Some ( _dummy_write_handler) ;
98+
99+ NOTIFY_CONN . fd = fd;
100+ NOTIFY_CONN . read = & raw mut NOTIFY_EVENT ;
101+ NOTIFY_CONN . write = & raw mut DUMMY_WRITE_EVENT ;
102+ NOTIFY_CONN . log = log;
103+
104+ ngx_event_actions. add_conn . unwrap ( ) ( & raw mut NOTIFY_CONN ) ;
105+
106+ EVENT_FILE . set ( File :: from_raw_fd ( fd) ) . expect ( "EVENT_FILE" ) ;
107+ }
108+
109+ NGX_OK as ngx_int_t
110+ }
111+ }
112+ #[ cfg( feature = "async_eventfd" ) ]
113+ pub use eventfd:: * ;
114+
19115static MAIN_TID : AtomicI64 = AtomicI64 :: new ( -1 ) ;
20116
21117#[ inline]
@@ -30,29 +126,16 @@ extern "C" fn async_handler(ev: *mut ngx_event_t) {
30126 let tid = unsafe { ngx_thread_tid ( ) . into ( ) } ;
31127 let _ = MAIN_TID . compare_exchange ( -1 , tid, Ordering :: Relaxed , Ordering :: Relaxed ) ;
32128 let scheduler = scheduler ( ) ;
129+
130+ if scheduler. rx . is_empty ( ) {
131+ return ;
132+ }
33133 let mut cnt = 0 ;
34134 while let Ok ( r) = scheduler. rx . try_recv ( ) {
35135 r. run ( ) ;
36136 cnt += 1 ;
37137 }
38- ngx_log_debug ! (
39- unsafe { ( * ev) . log } ,
40- "async: processed {cnt} items"
41- ) ;
42-
43- unsafe {
44- drop ( Box :: from_raw ( ev) ) ;
45- }
46- }
47-
48- fn notify ( ) -> c_int {
49- ngx_log_debug ! ( ngx_cycle_log( ) . as_ptr( ) , "async: notify via SIGIO" ) ;
50- unsafe {
51- kill (
52- std:: process:: id ( ) . try_into ( ) . unwrap ( ) ,
53- SIGIO . try_into ( ) . unwrap ( ) ,
54- )
55- }
138+ ngx_log_debug ! ( unsafe { ev. read( ) . log } , "async: processed {cnt} items" ) ;
56139}
57140
58141struct Scheduler {
@@ -69,28 +152,28 @@ impl Scheduler {
69152 fn schedule ( & self , runnable : Runnable , info : ScheduleInfo ) {
70153 let oet = on_event_thread ( ) ;
71154 // If we are on the event loop thread it's safe to simply run the Runnable, otherwise we
72- // enqueue the Runnable, post our event, and SIGIO to interrupt epoll . The event handler
73- // then runs the Runnable on the event loop thread.
155+ // enqueue the Runnable, post our event, and notify . The event handler then runs the
156+ // Runnable on the event loop thread.
74157 //
75158 // If woken_while_running, it indicates that a task has yielded itself to the Scheduler.
76- // Force round-trip via queue to limit reentrancy (skipping SIGIO) .
159+ // Force round-trip via queue to limit reentrancy.
77160 if oet && !info. woken_while_running {
78161 runnable. run ( ) ;
79162 } else {
80163 self . tx . send ( runnable) . expect ( "send" ) ;
164+
165+ #[ cfg( not( feature = "async_eventfd" ) ) ]
81166 unsafe {
82- let event: * mut ngx_event_t = Box :: into_raw ( Box :: new ( mem:: zeroed ( ) ) ) ;
167+ let event: * mut ngx_event_t =
168+ std:: boxed:: Box :: into_raw ( std:: boxed:: Box :: new ( core:: mem:: zeroed ( ) ) ) ;
83169 ( * event) . handler = Some ( async_handler) ;
84170 ( * event) . log = ngx_cycle_log ( ) . as_ptr ( ) ;
85- ngx_post_event ( event, ptr:: addr_of_mut!( ngx_posted_next_events) ) ;
86- }
87-
88- if !oet {
89- let rc = notify ( ) ;
90- if rc != 0 {
91- panic ! ( "kill: {rc}" )
92- }
171+ nginx_sys:: ngx_post_event (
172+ event,
173+ std:: ptr:: addr_of_mut!( nginx_sys:: ngx_posted_next_events) ,
174+ ) ;
93175 }
176+ notify ( ) ;
94177 }
95178 }
96179}
0 commit comments