@ -28,6 +28,11 @@
# include <sys/devpoll.h>
# endif
# ifdef __dietlibc__
# include <fmt.h>
# include <write12.h>
# endif
# ifdef DEBUG
# include <stdio.h>
# endif
@ -119,97 +124,38 @@ int64 io_waituntil2(int64 milliseconds) {
if ( io_waitmode = = EPOLL ) {
int n ;
struct epoll_event y [ 100 ] ;
io_entry * e ;
if ( alt_firstread > = 0 & & ( e = iarray_get ( & io_fds , alt_firstread ) ) & & e - > canread ) return 1 ;
if ( alt_firstwrite > = 0 & & ( e = iarray_get ( & io_fds , alt_firstwrite ) ) & & e - > canwrite ) return 1 ;
if ( ( n = epoll_wait ( io_master , y , 100 , milliseconds ) ) = = - 1 ) return - 1 ;
for ( i = n - 1 ; i > = 0 ; - - i ) {
io_entry * e = array_get ( & io_fds , sizeof ( io_entry ) , y [ i ] . data . fd ) ;
for ( i = 0 ; i < n ; + + i ) {
e= i array_get( & io_fds , y [ i ] . data . fd ) ;
if ( e ) {
int curevents = 0 , newevents ;
if ( e - > kernelwantread ) curevents | = EPOLLIN ;
if ( e - > kernelwantwrite ) curevents | = EPOLLOUT ;
# ifdef DEBUG
if ( ( y [ i ] . events & ( EPOLLIN | EPOLLPRI | EPOLLRDNORM | EPOLLRDBAND ) ) & & ! e - > kernelwantread )
printf ( " got unexpected read event on fd #%d \n " , y [ i ] . data . fd ) ;
if ( ( y [ i ] . events & EPOLLOUT ) & & ! e - > kernelwantwrite )
printf ( " got unexpected write event on fd #%d \n " , y [ i ] . data . fd ) ;
# endif
if ( y [ i ] . events & ( EPOLLERR | EPOLLHUP ) ) {
if ( y [ i ] . events & ( POLLERR | POLLHUP ) ) {
/* error; signal whatever app is looking for */
if ( e - > wantread ) y [ i ] . events | = EPOLLIN ;
if ( e - > wantwrite ) y [ i ] . events | = EPOLLOUT ;
}
newevents = 0 ;
if ( ! e - > canread | | e - > wantread ) {
newevents | = EPOLLIN ;
e - > kernelwantread = 1 ;
} else
e - > kernelwantread = 0 ;
if ( ! e - > canwrite | | e - > wantwrite ) {
newevents | = EPOLLOUT ;
e - > kernelwantwrite = 1 ;
} else
e - > kernelwantwrite = 0 ;
/* if we think we can not read, but the kernel tells us that we
* can , put this fd in the relevant data structures */
if ( ! e - > canread & & ( y [ i ] . events & ( EPOLLIN | EPOLLPRI | EPOLLRDNORM | EPOLLRDBAND ) ) ) {
if ( e - > canread ) {
newevents & = ~ EPOLLIN ;
} else {
e - > canread = 1 ;
if ( e - > wantread ) {
e - > next_read = first_readable ;
first_readable = y [ i ] . data . fd ;
}
}
if ( e - > wantread ) y [ i ] . events | = POLLIN ;
if ( e - > wantwrite ) y [ i ] . events | = POLLOUT ;
}
/* if the kernel says the fd is writable, ... */
if ( y [ i ] . events & EPOLLOUT ) {
/* Usually, if the kernel says a descriptor is writable, we
* note it and do not tell the kernel not to tell us again .
* The idea is that once we notify the caller that the fd is
* writable , and the caller handles the event , the caller will
* just ask to be notified of future write events again . We
* are trying to save the superfluous epoll_ctl syscalls .
* If e - > canwrite is set , then this gamble did not work out .
* We told the caller , yet after the caller is done we still
* got another write event . Clearly the user is implementing
* some kind of throttling and we can tell the kernel to leave
* us alone for now . */
if ( e - > canwrite ) {
newevents & = ~ EPOLLOUT ;
e - > kernelwantwrite = 0 ;
} else {
/* If !e->wantwrite: The laziness optimization in
* io_dontwantwrite hit . We did not tell the kernel that we
* are no longer interested in writing to save the syscall .
* Now we know we could write if we wanted ; remember that
* and then go on . */
e - > canwrite = 1 ;
if ( e - > wantwrite ) {
e - > next_write = first_writeable ;
first_writeable = y [ i ] . data . fd ;
}
}
if ( y [ i ] . events & POLLIN & & ! e - > canread ) {
debug_printf ( ( " io_waituntil2: enqueueing %ld in normal read queue before %ld \n " , info . si_fd , first_readable ) ) ;
e - > canread = 1 ;
e - > next_read = first_readable ;
first_readable = y [ i ] . data . fd ;
}
if ( newevents ! = curevents ) {
#if 0
printf ( " canread %d, wantread %d, kernelwantread %d, canwrite %d, wantwrite %d, kernelwantwrite %d \n " ,
e - > canread , e - > wantread , e - > kernelwantread , e - > canwrite , e - > wantwrite , e - > kernelwantwrite ) ;
printf ( " newevents: read %d write %d \n " , ! ! ( newevents & EPOLLIN ) , ! ! ( newevents & EPOLLOUT ) ) ;
# endif
y [ i ] . events = newevents ;
if ( newevents ) {
epoll_ctl ( io_master , EPOLL_CTL_MOD , y [ i ] . data . fd , y + i ) ;
} else {
epoll_ctl ( io_master , EPOLL_CTL_DEL , y [ i ] . data . fd , y + i ) ;
- - io_wanted_fds ;
}
if ( y [ i ] . events & POLLOUT & & ! e - > canwrite ) {
debug_printf ( ( " io_waituntil2: enqueueing %ld in normal write queue before %ld \n " , info . si_fd , first_writeable ) ) ;
e - > canwrite = 1 ;
e - > next_write = first_writeable ;
first_writeable = y [ i ] . data . fd ;
}
} else {
# ifdef __dietlibc__
char buf [ FMT_ULONG ] ;
buf [ fmt_ulong ( buf , y [ i ] . data . fd ) ] = 0 ;
__write2 ( " got epoll event on invalid fd " ) ;
__write2 ( buf ) ;
__write2 ( " ! \n " ) ;
# endif
epoll_ctl ( io_master , EPOLL_CTL_DEL , y [ i ] . data . fd , y + i ) ;
}
}
@ -224,7 +170,7 @@ int64 io_waituntil2(int64 milliseconds) {
ts . tv_sec = milliseconds / 1000 ; ts . tv_nsec = ( milliseconds % 1000 ) * 1000000 ;
if ( ( n = kevent ( io_master , 0 , 0 , y , 100 , milliseconds ! = - 1 ? & ts : 0 ) ) = = - 1 ) return - 1 ;
for ( i = n - 1 ; i > = 0 ; - - i ) {
io_entry * e = array_get( & io_fds , sizeof ( io_entry ) , y [ - - n ] . ident ) ;
io_entry * e = i array_get( & io_fds , y [ - - n ] . ident ) ;
if ( e ) {
if ( y [ n ] . flags & EV_ERROR ) {
/* error; signal whatever app is looking for */
@ -260,7 +206,7 @@ int64 io_waituntil2(int64 milliseconds) {
timeout . dp_fds = y ;
if ( ( n = ioctl ( io_master , DP_POLL , & timeout ) ) = = - 1 ) return - 1 ;
for ( i = n - 1 ; i > = 0 ; - - i ) {
io_entry * e = array_get( & io_fds , sizeof ( io_entry ) , y [ - - n ] . fd ) ;
io_entry * e = i array_get( & io_fds , y [ - - n ] . fd ) ;
if ( e ) {
if ( y [ n ] . revents & ( POLLERR | POLLHUP | POLLNVAL ) ) {
/* error; signal whatever app is looking for */
@ -296,8 +242,8 @@ int64 io_waituntil2(int64 milliseconds) {
struct timespec ts ;
int r ;
io_entry * e ;
if ( alt_firstread > = 0 & & ( e = array_get( & io_fds , sizeof ( io_entry ) , alt_firstread ) ) & & e - > canread ) return 1 ;
if ( alt_firstwrite > = 0 & & ( e = array_get( & io_fds , sizeof ( io_entry ) , alt_firstwrite ) ) & & e - > canwrite ) return 1 ;
if ( alt_firstread > = 0 & & ( e = i array_get( & io_fds , alt_firstread ) ) & & e - > canread ) return 1 ;
if ( alt_firstwrite > = 0 & & ( e = i array_get( & io_fds , alt_firstwrite ) ) & & e - > canwrite ) return 1 ;
if ( milliseconds = = - 1 )
r = sigwaitinfo ( & io_ss , & info ) ;
else {
@ -311,7 +257,7 @@ int64 io_waituntil2(int64 milliseconds) {
goto dopoll ;
default :
if ( r = = io_signum ) {
io_entry * e = array_get( & io_fds , sizeof ( io_entry ) , info . si_fd ) ;
io_entry * e = i array_get( & io_fds , info . si_fd ) ;
if ( e ) {
if ( info . si_band & ( POLLERR | POLLHUP ) ) {
/* error; signal whatever app is looking for */
@ -351,7 +297,7 @@ dopoll:
}
fprintf ( stderr , " Calling GetQueuedCompletionStatus %p... " , io_comport ) ;
if ( GetQueuedCompletionStatus ( io_comport , & numberofbytes , & x , & o , milliseconds = = - 1 ? INFINITE : milliseconds ) ) {
io_entry * e = array_get( & io_fds , sizeof ( io_entry ) , x ) ;
io_entry * e = i array_get( & io_fds , x ) ;
fprintf ( stderr , " OK. Got %x, e=%p \n " , x , e ) ;
if ( ! e ) return 0 ;
e - > errorcode = 0 ;
@ -398,7 +344,7 @@ dopoll:
/* we got a completion packet for a failed I/O operation */
err = GetLastError ( ) ;
if ( err = = WAIT_TIMEOUT ) return 0 ; /* or maybe not */
e = array_get( & io_fds , sizeof ( io_entry ) , x ) ;
e = i array_get( & io_fds , x ) ;
if ( ! e ) return 0 ; /* WTF?! */
e - > errorcode = err ;
if ( o = = & e - > or & & ( e - > readqueued | | e - > acceptqueued ) ) {
@ -422,8 +368,8 @@ dopoll:
return 1 ;
}
# else
for ( i = r = 0 ; i < array_length( & io_fds , sizeof ( io_entry ) ) ; + + i ) {
io_entry * e = array_get( & io_fds , sizeof ( io_entry ) , i ) ;
for ( i = r = 0 ; ( size_t ) i < i array_length( & io_fds ) ; + + i ) {
io_entry * e = i array_get( & io_fds , i ) ;
if ( ! e ) return - 1 ;
e - > canread = e - > canwrite = 0 ;
if ( e - > wantread | | e - > wantwrite ) {
@ -439,7 +385,7 @@ dopoll:
p = array_start ( & io_pollfds ) ;
if ( ( i = poll ( array_start ( & io_pollfds ) , r , milliseconds ) ) < 1 ) return - 1 ;
for ( j = r - 1 ; j > = 0 ; - - j ) {
io_entry * e = array_get( & io_fds , sizeof ( io_entry ) , p - > fd ) ;
io_entry * e = i array_get( & io_fds , p - > fd ) ;
if ( p - > revents & ( POLLERR | POLLHUP | POLLNVAL ) ) {
/* error; signal whatever app is looking for */
if ( e - > wantread ) p - > revents | = POLLIN ;