@@ -18,7 +18,7 @@ use crate::event::port::Event;
1818use crate :: event:: EventfdFlags ;
1919#[ cfg( any( bsd, linux_kernel, target_os = "wasi" ) ) ]
2020use crate :: event:: FdSetElement ;
21- use crate :: event:: PollFd ;
21+ use crate :: event:: { PollFd , Timespec } ;
2222use crate :: io;
2323#[ cfg( solarish) ]
2424use crate :: utils:: as_mut_ptr;
@@ -30,7 +30,15 @@ use crate::utils::as_ptr;
3030 all( feature = "alloc" , any( linux_kernel, target_os = "redox" ) ) ,
3131) ) ]
3232use core:: mem:: MaybeUninit ;
33- #[ cfg( any( bsd, linux_kernel, target_os = "wasi" ) ) ]
33+ #[ cfg( any(
34+ bsd,
35+ linux_kernel,
36+ target_os = "fuchsia" ,
37+ target_os = "haiku" ,
38+ target_os = "hurd" ,
39+ target_os = "netbsd" ,
40+ target_os = "wasi"
41+ ) ) ]
3442use core:: ptr:: null;
3543#[ cfg( any( bsd, linux_kernel, solarish, target_os = "redox" , target_os = "wasi" ) ) ]
3644use core:: ptr:: null_mut;
@@ -119,14 +127,98 @@ pub(crate) unsafe fn kevent(
119127}
120128
121129#[ inline]
122- pub ( crate ) fn poll ( fds : & mut [ PollFd < ' _ > ] , timeout : c :: c_int ) -> io:: Result < usize > {
130+ pub ( crate ) fn poll ( fds : & mut [ PollFd < ' _ > ] , timeout : Option < & Timespec > ) -> io:: Result < usize > {
123131 let nfds = fds
124132 . len ( )
125133 . try_into ( )
126134 . map_err ( |_convert_err| io:: Errno :: INVAL ) ?;
127135
128- ret_c_int ( unsafe { c:: poll ( fds. as_mut_ptr ( ) . cast ( ) , nfds, timeout) } )
129- . map ( |nready| nready as usize )
136+ // If we have `ppoll`, it supports a `timespec` timeout, so use it.
137+ #[ cfg( any(
138+ linux_kernel,
139+ freebsdlike,
140+ target_os = "fuchsia" ,
141+ target_os = "haiku" ,
142+ target_os = "hurd" ,
143+ target_os = "netbsd"
144+ ) ) ]
145+ {
146+ // If we don't have to fix y2038 on this platform, `Timespec` is
147+ // the same as `c::timespec` and it's easy.
148+ #[ cfg( not( fix_y2038) ) ]
149+ let timeout = crate :: timespec:: option_as_libc_timespec_ptr ( timeout) ;
150+
151+ // If we do have to fix y2038 on this platform, convert to
152+ // `c::timespec`.
153+ #[ cfg( fix_y2038) ]
154+ let converted_timeout;
155+ #[ cfg( fix_y2038) ]
156+ let timeout = match timeout {
157+ None => null ( ) ,
158+ Some ( timeout) => {
159+ converted_timeout = c:: timespec {
160+ tv_sec : timeout. tv_sec . try_into ( ) . map_err ( |_| io:: Errno :: OVERFLOW ) ?,
161+ tv_nsec : timeout. tv_nsec as _ ,
162+ } ;
163+ & converted_timeout
164+ }
165+ } ;
166+
167+ #[ cfg( not( target_os = "netbsd" ) ) ]
168+ {
169+ ret_c_int ( unsafe { c:: ppoll ( fds. as_mut_ptr ( ) . cast ( ) , nfds, timeout, null ( ) ) } )
170+ . map ( |nready| nready as usize )
171+ }
172+
173+ // NetBSD 9.x lacks `ppoll`, so use a weak symbol and fall back to
174+ // plain `poll` if needed.
175+ #[ cfg( target_os = "netbsd" ) ]
176+ {
177+ weak ! {
178+ fn ppoll(
179+ * mut c:: pollfd,
180+ c:: nfds_t,
181+ * const c:: timespec,
182+ * const c:: sigset_t
183+ ) -> c:: c_int
184+ }
185+ if let Some ( func) = ppoll. get ( ) {
186+ return ret_c_int ( unsafe { func ( fds. as_mut_ptr ( ) . cast ( ) , nfds, timeout, null ( ) ) } )
187+ . map ( |nready| nready as usize ) ;
188+ }
189+ }
190+ }
191+
192+ // If we don't have `ppoll`, convert the timeout to `c_int` and use `poll`.
193+ #[ cfg( not( any(
194+ linux_kernel,
195+ freebsdlike,
196+ target_os = "fuchsia" ,
197+ target_os = "haiku" ,
198+ target_os = "hurd"
199+ ) ) ) ]
200+ {
201+ let timeout = match timeout {
202+ None => -1 ,
203+ Some ( timeout) => {
204+ // Convert from `Timespec` to `c_int` milliseconds.
205+ let secs = timeout. tv_sec ;
206+ if secs < 0 {
207+ return Err ( io:: Errno :: INVAL ) ;
208+ }
209+ secs. checked_mul ( 1000 )
210+ . and_then ( |millis| {
211+ // Add the nanoseconds, converted to millis, rounding
212+ // up. With Rust 1.73.0 this can use `div_ceil`.
213+ millis. checked_add ( ( i64:: from ( timeout. tv_nsec ) + 999_999 ) / 1_000_000 )
214+ } )
215+ . and_then ( |millis| c:: c_int:: try_from ( millis) . ok ( ) )
216+ . ok_or ( io:: Errno :: INVAL ) ?
217+ }
218+ } ;
219+ ret_c_int ( unsafe { c:: poll ( fds. as_mut_ptr ( ) . cast ( ) , nfds, timeout) } )
220+ . map ( |nready| nready as usize )
221+ }
130222}
131223
132224#[ cfg( any( bsd, linux_kernel) ) ]
@@ -135,7 +227,7 @@ pub(crate) unsafe fn select(
135227 readfds : Option < & mut [ FdSetElement ] > ,
136228 writefds : Option < & mut [ FdSetElement ] > ,
137229 exceptfds : Option < & mut [ FdSetElement ] > ,
138- timeout : Option < & crate :: timespec :: Timespec > ,
230+ timeout : Option < & Timespec > ,
139231) -> io:: Result < i32 > {
140232 let len = crate :: event:: fd_set_num_elements_for_bitvector ( nfds) ;
141233
@@ -212,7 +304,7 @@ pub(crate) unsafe fn select(
212304 readfds : Option < & mut [ FdSetElement ] > ,
213305 writefds : Option < & mut [ FdSetElement ] > ,
214306 exceptfds : Option < & mut [ FdSetElement ] > ,
215- timeout : Option < & crate :: timespec :: Timespec > ,
307+ timeout : Option < & Timespec > ,
216308) -> io:: Result < i32 > {
217309 let len = crate :: event:: fd_set_num_elements_for_fd_array ( nfds as usize ) ;
218310
0 commit comments