2003-08-13 01:53:07 +00:00
/*
Unix SMB / CIFS implementation .
main select loop and event handling
2005-02-15 10:36:59 +00:00
Copyright ( C ) Andrew Tridgell 2003 - 2005
Copyright ( C ) Stefan Metzmacher 2005
2003-08-13 01:53:07 +00:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/*
2005-02-15 10:36:59 +00:00
This is SAMBA ' s default event loop code
2003-08-13 01:53:07 +00:00
2005-02-15 10:36:59 +00:00
- we try to use epoll if configure detected support for it
otherwise we use select ( )
- if epoll is broken on the system or the kernel doesn ' t support it
at runtime we fallback to select ( )
2003-08-13 01:53:07 +00:00
*/
# include "includes.h"
2005-02-10 05:09:35 +00:00
# include "system/filesys.h"
2004-11-02 06:42:15 +00:00
# include "dlinklist.h"
2005-02-03 11:56:03 +00:00
# include "lib/events/events.h"
2005-02-15 10:36:59 +00:00
# include "lib/events/events_internal.h"
2003-08-13 01:53:07 +00:00
2005-02-03 08:24:08 +00:00
/* use epoll if it is available */
# if defined(HAVE_EPOLL_CREATE) && defined(HAVE_SYS_EPOLL_H)
# define WITH_EPOLL 1
# endif
2005-02-03 02:35:52 +00:00
2005-02-03 08:24:08 +00:00
# if WITH_EPOLL
# include <sys/epoll.h>
# endif
2005-02-03 02:35:52 +00:00
2005-02-15 10:36:59 +00:00
struct std_event_context {
2005-12-09 17:30:14 +00:00
/* a pointer back to the generic event_context */
struct event_context * ev ;
2005-02-03 02:35:52 +00:00
/* list of filedescriptor events */
2005-02-15 10:36:59 +00:00
struct fd_event * fd_events ;
2005-02-03 02:35:52 +00:00
/* list of timed events */
2005-02-15 10:36:59 +00:00
struct timed_event * timed_events ;
2005-02-03 02:35:52 +00:00
/* the maximum file descriptor number in fd_events */
int maxfd ;
/* information for exiting from the event loop */
int exit_code ;
2005-02-03 08:24:08 +00:00
/* this is changed by the destructors for the fd event
type . It is used to detect event destruction by event
handlers , which means the code that is calling the event
handler needs to assume that the linked list is no longer
valid
2005-02-03 02:35:52 +00:00
*/
uint32_t destruction_count ;
2005-02-03 08:24:08 +00:00
/* when using epoll this is the handle from epoll_create */
int epoll_fd ;
2005-02-03 02:35:52 +00:00
} ;
2005-12-09 17:30:14 +00:00
static void std_event_loop_timer ( struct std_event_context * std_ev ) ;
# if WITH_EPOLL
2005-02-10 03:16:33 +00:00
/*
2005-12-09 17:30:14 +00:00
called when a epoll call fails , and we should fallback
to using select
2005-02-10 03:16:33 +00:00
*/
2005-12-09 17:30:14 +00:00
static void epoll_fallback_to_select ( struct std_event_context * std_ev , const char * reason )
2005-02-10 03:16:33 +00:00
{
2005-12-09 17:30:14 +00:00
DEBUG ( 0 , ( " %s (%s) - falling back to select() \n " , reason , strerror ( errno ) ) ) ;
close ( std_ev - > epoll_fd ) ;
std_ev - > epoll_fd = - 1 ;
talloc_set_destructor ( std_ev , NULL ) ;
}
/*
map from EVENT_FD_ * to EPOLLIN / EPOLLOUT
*/
static uint32_t epoll_map_flags ( uint16_t flags )
{
uint32_t ret = 0 ;
if ( flags & EVENT_FD_READ ) ret | = EPOLLIN ;
if ( flags & EVENT_FD_WRITE ) ret | = EPOLLOUT ;
return ret ;
}
/*
free the epoll fd
*/
static int epoll_ctx_destructor ( void * ptr )
{
struct std_event_context * std_ev = talloc_get_type ( ptr ,
2005-02-15 10:36:59 +00:00
struct std_event_context ) ;
2005-12-09 17:30:14 +00:00
close ( std_ev - > epoll_fd ) ;
std_ev - > epoll_fd = - 1 ;
return 0 ;
}
/*
init the epoll fd
*/
static void epoll_init_ctx ( struct std_event_context * std_ev , BOOL try_epoll )
{
if ( ! try_epoll ) return ;
std_ev - > epoll_fd = epoll_create ( 64 ) ;
talloc_set_destructor ( std_ev , epoll_ctx_destructor ) ;
}
/*
add the epoll event to the given fd_event
*/
static void epoll_add_event ( struct std_event_context * std_ev , struct fd_event * fde )
{
struct epoll_event event ;
if ( std_ev - > epoll_fd = = - 1 ) return ;
ZERO_STRUCT ( event ) ;
event . events = epoll_map_flags ( fde - > flags ) ;
event . data . ptr = fde ;
if ( epoll_ctl ( std_ev - > epoll_fd , EPOLL_CTL_ADD , fde - > fd , & event ) ! = 0 ) {
epoll_fallback_to_select ( std_ev , " EPOLL_CTL_ADD failed " ) ;
2005-02-10 03:16:33 +00:00
}
2005-12-09 17:30:14 +00:00
}
/*
remove the epoll event for given fd_event
*/
static void epoll_remove_event ( struct std_event_context * std_ev , struct fd_event * fde )
{
struct epoll_event event ;
if ( std_ev - > epoll_fd = = - 1 ) return ;
ZERO_STRUCT ( event ) ;
event . events = epoll_map_flags ( fde - > flags ) ;
event . data . ptr = fde ;
epoll_ctl ( std_ev - > epoll_fd , EPOLL_CTL_DEL , fde - > fd , & event ) ;
}
/*
change the epoll event to the given fd_event
*/
static void epoll_change_event ( struct std_event_context * std_ev , struct fd_event * fde , uint16_t flags )
{
struct epoll_event event ;
if ( std_ev - > epoll_fd = = - 1 ) return ;
ZERO_STRUCT ( event ) ;
event . events = epoll_map_flags ( flags ) ;
event . data . ptr = fde ;
if ( epoll_ctl ( std_ev - > epoll_fd , EPOLL_CTL_MOD , fde - > fd , & event ) ! = 0 ) {
epoll_fallback_to_select ( std_ev , " EPOLL_CTL_MOD failed " ) ;
}
}
/*
event loop handling using epoll
*/
static int epoll_event_loop ( struct std_event_context * std_ev , struct timeval * tvalp )
{
int ret , i ;
# define MAXEVENTS 8
struct epoll_event events [ MAXEVENTS ] ;
uint32_t destruction_count = std_ev - > destruction_count ;
int timeout = - 1 ;
if ( std_ev - > epoll_fd = = - 1 ) return - 1 ;
if ( tvalp ) {
/* it's better to trigger timed events a bit later than to early */
timeout = ( ( tvalp - > tv_usec + 999 ) / 1000 ) + ( tvalp - > tv_sec * 1000 ) ;
}
ret = epoll_wait ( std_ev - > epoll_fd , events , MAXEVENTS , timeout ) ;
if ( ret = = - 1 & & errno ! = EINTR ) {
epoll_fallback_to_select ( std_ev , " epoll_wait() failed " ) ;
return - 1 ;
}
if ( ret = = 0 & & tvalp ) {
std_event_loop_timer ( std_ev ) ;
return 0 ;
}
for ( i = 0 ; i < ret ; i + + ) {
struct fd_event * fde = talloc_get_type ( events [ i ] . data . ptr ,
struct fd_event ) ;
uint16_t flags = 0 ;
if ( fde = = NULL ) {
epoll_fallback_to_select ( std_ev , " epoll_wait() gave bad data " ) ;
return - 1 ;
}
if ( events [ i ] . events & ( EPOLLHUP | EPOLLERR ) ) flags | = EVENT_FD_READ ;
if ( events [ i ] . events & EPOLLIN ) flags | = EVENT_FD_READ ;
if ( events [ i ] . events & EPOLLOUT ) flags | = EVENT_FD_WRITE ;
if ( flags ) {
fde - > handler ( std_ev - > ev , fde , flags , fde - > private_data ) ;
if ( destruction_count ! = std_ev - > destruction_count ) {
break ;
}
}
}
2005-02-10 03:16:33 +00:00
return 0 ;
}
2005-12-09 17:30:14 +00:00
# else
# define epoll_init_ctx(std_ev,try_epoll) if (try_epoll) { /* fix unused variable warning*/ }
# define epoll_add_event(std_ev,fde)
# define epoll_remove_event(std_ev,fde)
# define epoll_change_event(std_ev,fde,flags)
# define epoll_event_loop(std_ev,tvalp) (-1)
# endif
2005-02-10 03:16:33 +00:00
2003-08-13 01:53:07 +00:00
/*
2005-02-15 10:36:59 +00:00
create a std_event_context structure .
2003-08-13 01:53:07 +00:00
*/
2005-12-09 17:30:14 +00:00
static int std_event_context_init ( struct event_context * ev , void * private_data )
2003-08-13 01:53:07 +00:00
{
2005-02-15 10:36:59 +00:00
struct std_event_context * std_ev ;
2005-12-09 17:30:14 +00:00
BOOL * _try_epoll = private_data ;
BOOL try_epoll = ( _try_epoll = = NULL ? True : * _try_epoll ) ;
2003-08-13 01:53:07 +00:00
2005-02-15 10:36:59 +00:00
std_ev = talloc_zero ( ev , struct std_event_context ) ;
if ( ! std_ev ) return - 1 ;
2005-12-09 17:30:14 +00:00
std_ev - > ev = ev ;
std_ev - > epoll_fd = - 1 ;
2003-08-13 01:53:07 +00:00
2005-12-09 17:30:14 +00:00
epoll_init_ctx ( std_ev , try_epoll ) ;
2005-02-03 08:24:08 +00:00
2005-02-15 10:36:59 +00:00
ev - > additional_data = std_ev ;
return 0 ;
}
2005-02-03 08:24:08 +00:00
2003-08-13 01:53:07 +00:00
/*
recalculate the maxfd
*/
2005-12-09 17:30:14 +00:00
static void calc_maxfd ( struct std_event_context * std_ev )
2003-08-13 01:53:07 +00:00
{
2005-02-15 10:36:59 +00:00
struct fd_event * fde ;
std_ev - > maxfd = 0 ;
for ( fde = std_ev - > fd_events ; fde ; fde = fde - > next ) {
if ( fde - > fd > std_ev - > maxfd ) {
std_ev - > maxfd = fde - > fd ;
2003-08-13 01:53:07 +00:00
}
}
}
2005-02-03 08:24:08 +00:00
2005-01-23 11:49:15 +00:00
/* to mark the ev->maxfd invalid
* this means we need to recalculate it
*/
# define EVENT_INVALID_MAXFD (-1)
2005-02-03 08:24:08 +00:00
/*
destroy an fd_event
*/
2005-02-15 10:36:59 +00:00
static int std_event_fd_destructor ( void * ptr )
2005-01-23 11:49:15 +00:00
{
struct fd_event * fde = talloc_get_type ( ptr , struct fd_event ) ;
2005-02-03 08:24:08 +00:00
struct event_context * ev = fde - > event_ctx ;
2005-02-15 10:36:59 +00:00
struct std_event_context * std_ev = talloc_get_type ( ev - > additional_data ,
struct std_event_context ) ;
2005-02-03 08:24:08 +00:00
2005-02-15 10:36:59 +00:00
if ( std_ev - > maxfd = = fde - > fd ) {
std_ev - > maxfd = EVENT_INVALID_MAXFD ;
2005-01-23 11:49:15 +00:00
}
2005-12-09 17:30:14 +00:00
2005-02-15 10:36:59 +00:00
DLIST_REMOVE ( std_ev - > fd_events , fde ) ;
std_ev - > destruction_count + + ;
2005-12-09 17:30:14 +00:00
epoll_remove_event ( std_ev , fde ) ;
2005-01-23 11:49:15 +00:00
return 0 ;
}
2004-07-23 06:40:49 +00:00
/*
add a fd based event
return NULL on failure ( memory allocation error )
*/
2005-02-15 10:36:59 +00:00
static struct fd_event * std_event_add_fd ( struct event_context * ev , TALLOC_CTX * mem_ctx ,
int fd , uint16_t flags ,
event_fd_handler_t handler ,
void * private_data )
2004-07-23 06:40:49 +00:00
{
2005-02-15 10:36:59 +00:00
struct std_event_context * std_ev = talloc_get_type ( ev - > additional_data ,
struct std_event_context ) ;
struct fd_event * fde ;
2005-02-03 02:35:52 +00:00
2005-02-15 10:36:59 +00:00
fde = talloc ( mem_ctx ? mem_ctx : ev , struct fd_event ) ;
if ( ! fde ) return NULL ;
2005-02-03 02:35:52 +00:00
2005-02-15 10:36:59 +00:00
fde - > event_ctx = ev ;
fde - > fd = fd ;
fde - > flags = flags ;
fde - > handler = handler ;
fde - > private_data = private_data ;
2005-12-09 16:43:19 +00:00
fde - > additional_flags = 0 ;
2005-02-15 10:36:59 +00:00
fde - > additional_data = NULL ;
2005-02-03 02:35:52 +00:00
2005-02-15 10:36:59 +00:00
DLIST_ADD ( std_ev - > fd_events , fde ) ;
if ( fde - > fd > std_ev - > maxfd ) {
std_ev - > maxfd = fde - > fd ;
2005-01-23 12:17:45 +00:00
}
2005-02-15 10:36:59 +00:00
talloc_set_destructor ( fde , std_event_fd_destructor ) ;
2005-12-09 17:30:14 +00:00
epoll_add_event ( std_ev , fde ) ;
2005-02-03 08:24:08 +00:00
2005-02-15 10:36:59 +00:00
return fde ;
2004-07-23 06:40:49 +00:00
}
2005-02-03 02:35:52 +00:00
/*
return the fd event flags
*/
2005-02-15 10:36:59 +00:00
static uint16_t std_event_get_fd_flags ( struct fd_event * fde )
2005-01-23 11:49:15 +00:00
{
2005-12-08 08:31:59 +00:00
return fde - > flags ;
2005-01-23 11:49:15 +00:00
}
2003-08-13 01:53:07 +00:00
/*
2005-02-03 02:35:52 +00:00
set the fd event flags
2003-08-13 01:53:07 +00:00
*/
2005-02-15 10:36:59 +00:00
static void std_event_set_fd_flags ( struct fd_event * fde , uint16_t flags )
2003-08-13 01:53:07 +00:00
{
2005-02-03 08:24:08 +00:00
struct event_context * ev ;
2005-02-15 10:36:59 +00:00
struct std_event_context * std_ev ;
2005-12-09 17:30:14 +00:00
if ( fde - > flags = = flags ) return ;
2005-02-03 08:24:08 +00:00
ev = fde - > event_ctx ;
2005-02-15 10:36:59 +00:00
std_ev = talloc_get_type ( ev - > additional_data , struct std_event_context ) ;
2005-12-09 17:30:14 +00:00
epoll_change_event ( std_ev , fde , flags ) ;
2005-12-08 08:31:59 +00:00
fde - > flags = flags ;
2003-08-13 01:53:07 +00:00
}
2005-02-03 02:35:52 +00:00
/*
destroy a timed event
*/
2005-02-15 10:36:59 +00:00
static int std_event_timed_destructor ( void * ptr )
2005-01-23 11:49:15 +00:00
{
2005-02-03 02:35:52 +00:00
struct timed_event * te = talloc_get_type ( ptr , struct timed_event ) ;
2005-02-15 10:36:59 +00:00
struct std_event_context * std_ev = talloc_get_type ( te - > event_ctx - > additional_data ,
struct std_event_context ) ;
DLIST_REMOVE ( std_ev - > timed_events , te ) ;
2005-01-23 11:49:15 +00:00
return 0 ;
2003-08-13 01:53:07 +00:00
}
2005-09-27 12:54:08 +00:00
static int std_event_timed_deny_destructor ( void * ptr )
{
return - 1 ;
}
2003-08-13 01:53:07 +00:00
/*
2005-02-03 02:35:52 +00:00
add a timed event
2004-01-21 23:19:59 +00:00
return NULL on failure ( memory allocation error )
2003-08-13 01:53:07 +00:00
*/
2005-02-15 10:36:59 +00:00
static struct timed_event * std_event_add_timed ( struct event_context * ev , TALLOC_CTX * mem_ctx ,
struct timeval next_event ,
event_timed_handler_t handler ,
void * private_data )
2003-08-13 01:53:07 +00:00
{
2005-02-15 10:36:59 +00:00
struct std_event_context * std_ev = talloc_get_type ( ev - > additional_data ,
struct std_event_context ) ;
struct timed_event * te , * last_te , * cur_te ;
2005-02-03 04:02:48 +00:00
2005-02-15 10:36:59 +00:00
te = talloc ( mem_ctx ? mem_ctx : ev , struct timed_event ) ;
if ( te = = NULL ) return NULL ;
2005-02-03 02:35:52 +00:00
2005-02-15 10:36:59 +00:00
te - > event_ctx = ev ;
te - > next_event = next_event ;
te - > handler = handler ;
te - > private_data = private_data ;
te - > additional_data = NULL ;
2005-02-03 02:35:52 +00:00
2005-02-03 04:02:48 +00:00
/* keep the list ordered */
2005-02-15 10:36:59 +00:00
last_te = NULL ;
for ( cur_te = std_ev - > timed_events ; cur_te ; cur_te = cur_te - > next ) {
/* if the new event comes before the current one break */
if ( ! timeval_is_zero ( & cur_te - > next_event ) & &
2005-08-01 17:31:40 +00:00
timeval_compare ( & te - > next_event ,
& cur_te - > next_event ) < 0 ) {
2005-02-15 10:36:59 +00:00
break ;
2005-02-03 04:02:48 +00:00
}
2005-02-15 10:36:59 +00:00
last_te = cur_te ;
2005-01-23 12:17:45 +00:00
}
2005-02-03 04:02:48 +00:00
2005-02-15 10:36:59 +00:00
DLIST_ADD_AFTER ( std_ev - > timed_events , te , last_te ) ;
talloc_set_destructor ( te , std_event_timed_destructor ) ;
2005-02-03 04:02:48 +00:00
2005-02-15 10:36:59 +00:00
return te ;
2003-08-13 01:53:07 +00:00
}
/*
2005-02-03 08:24:08 +00:00
a timer has gone off - call it
2003-08-13 01:53:07 +00:00
*/
2005-12-09 17:30:14 +00:00
static void std_event_loop_timer ( struct std_event_context * std_ev )
2005-02-03 08:24:08 +00:00
{
struct timeval t = timeval_current ( ) ;
2005-02-15 10:36:59 +00:00
struct timed_event * te = std_ev - > timed_events ;
2005-02-03 08:24:08 +00:00
2005-07-13 03:55:22 +00:00
if ( te = = NULL ) {
return ;
}
2005-09-27 12:54:08 +00:00
/* deny the handler to free the event */
talloc_set_destructor ( te , std_event_timed_deny_destructor ) ;
2005-10-03 14:24:53 +00:00
/* We need to remove the timer from the list before calling the
* handler because in a semi - async inner event loop called from the
* handler we don ' t want to come across this event again - - vl */
DLIST_REMOVE ( std_ev - > timed_events , te ) ;
2005-12-09 17:30:14 +00:00
te - > handler ( std_ev - > ev , te , t , te - > private_data ) ;
2005-02-03 08:24:08 +00:00
2005-10-03 14:24:53 +00:00
/* The destructor isn't necessary anymore, we've already removed the
* event from the list . */
2005-10-03 17:36:10 +00:00
talloc_set_destructor ( te , NULL ) ;
2005-10-03 14:24:53 +00:00
2005-09-27 12:54:08 +00:00
talloc_free ( te ) ;
2005-02-03 08:24:08 +00:00
}
/*
event loop handling using select ( )
*/
2005-12-09 17:30:14 +00:00
static int std_event_loop_select ( struct std_event_context * std_ev , struct timeval * tvalp )
2003-08-13 01:53:07 +00:00
{
2004-07-23 06:40:49 +00:00
fd_set r_fds , w_fds ;
2005-02-15 10:36:59 +00:00
struct fd_event * fde ;
2004-07-23 06:40:49 +00:00
int selrtn ;
2005-02-15 10:36:59 +00:00
uint32_t destruction_count = std_ev - > destruction_count ;
2003-08-13 01:53:07 +00:00
2005-02-03 08:24:08 +00:00
/* we maybe need to recalculate the maxfd */
2005-02-15 10:36:59 +00:00
if ( std_ev - > maxfd = = EVENT_INVALID_MAXFD ) {
2005-12-09 17:30:14 +00:00
calc_maxfd ( std_ev ) ;
2005-02-03 08:24:08 +00:00
}
2005-02-15 10:36:59 +00:00
2004-07-23 06:40:49 +00:00
FD_ZERO ( & r_fds ) ;
FD_ZERO ( & w_fds ) ;
/* setup any fd events */
2005-02-15 10:36:59 +00:00
for ( fde = std_ev - > fd_events ; fde ; fde = fde - > next ) {
if ( fde - > flags & EVENT_FD_READ ) {
FD_SET ( fde - > fd , & r_fds ) ;
2005-01-23 11:49:15 +00:00
}
2005-02-15 10:36:59 +00:00
if ( fde - > flags & EVENT_FD_WRITE ) {
FD_SET ( fde - > fd , & w_fds ) ;
2003-08-13 01:53:07 +00:00
}
2004-07-23 06:40:49 +00:00
}
2003-08-13 01:53:07 +00:00
2005-02-15 10:36:59 +00:00
selrtn = select ( std_ev - > maxfd + 1 , & r_fds , & w_fds , NULL , tvalp ) ;
2005-02-03 04:02:48 +00:00
if ( selrtn = = - 1 & & errno = = EBADF ) {
/* the socket is dead! this should never
happen as the socket should have first been
made readable and that should have removed
the event , so this must be a bug . This is a
fatal error . */
2005-02-15 10:36:59 +00:00
DEBUG ( 0 , ( " ERROR: EBADF on std_event_loop_once \n " ) ) ;
std_ev - > exit_code = EBADF ;
2005-02-03 04:02:48 +00:00
return - 1 ;
}
2005-02-03 08:24:08 +00:00
if ( selrtn = = 0 & & tvalp ) {
2005-12-09 17:30:14 +00:00
std_event_loop_timer ( std_ev ) ;
2005-02-03 08:24:08 +00:00
return 0 ;
2005-02-03 04:02:48 +00:00
}
2005-02-03 08:24:08 +00:00
2005-02-03 04:02:48 +00:00
if ( selrtn > 0 ) {
/* at least one file descriptor is ready - check
which ones and call the handler , being careful to allow
the handler to remove itself when called */
2005-02-15 10:36:59 +00:00
for ( fde = std_ev - > fd_events ; fde ; fde = fde - > next ) {
2005-02-03 04:02:48 +00:00
uint16_t flags = 0 ;
2005-02-15 10:36:59 +00:00
if ( FD_ISSET ( fde - > fd , & r_fds ) ) flags | = EVENT_FD_READ ;
if ( FD_ISSET ( fde - > fd , & w_fds ) ) flags | = EVENT_FD_WRITE ;
2005-02-03 04:02:48 +00:00
if ( flags ) {
2005-12-09 17:30:14 +00:00
fde - > handler ( std_ev - > ev , fde , flags , fde - > private_data ) ;
2005-02-15 10:36:59 +00:00
if ( destruction_count ! = std_ev - > destruction_count ) {
2005-02-03 04:02:48 +00:00
break ;
2003-08-13 01:53:07 +00:00
}
}
}
2004-07-23 06:40:49 +00:00
}
2003-08-13 01:53:07 +00:00
2004-09-11 15:05:49 +00:00
return 0 ;
2005-02-03 08:24:08 +00:00
}
/*
2005-02-03 11:25:52 +00:00
do a single event loop using the events defined in ev
2005-02-03 08:24:08 +00:00
*/
2005-02-15 10:36:59 +00:00
static int std_event_loop_once ( struct event_context * ev )
2005-02-03 08:24:08 +00:00
{
2005-02-15 10:36:59 +00:00
struct std_event_context * std_ev = talloc_get_type ( ev - > additional_data ,
struct std_event_context ) ;
2005-07-13 03:55:22 +00:00
struct timeval tval ;
2005-02-15 10:36:59 +00:00
2005-02-03 08:24:08 +00:00
/* work out the right timeout for all timed events */
2005-02-15 10:36:59 +00:00
if ( std_ev - > timed_events ) {
2005-02-03 08:24:08 +00:00
struct timeval t = timeval_current ( ) ;
2005-08-01 00:34:39 +00:00
tval = timeval_until ( & t , & std_ev - > timed_events - > next_event ) ;
2005-07-13 03:55:22 +00:00
if ( timeval_is_zero ( & tval ) ) {
2005-12-09 17:30:14 +00:00
std_event_loop_timer ( std_ev ) ;
2005-02-03 08:24:08 +00:00
return 0 ;
}
2005-07-13 03:55:22 +00:00
} else {
/* have a default tick time of 30 seconds. This guarantees
that code that uses its own timeout checking will be
able to proceeed eventually */
tval = timeval_set ( 30 , 0 ) ;
2005-02-03 08:24:08 +00:00
}
2005-12-09 17:30:14 +00:00
if ( epoll_event_loop ( std_ev , & tval ) = = 0 ) {
return 0 ;
2005-02-03 08:24:08 +00:00
}
2005-12-09 17:30:14 +00:00
return std_event_loop_select ( std_ev , & tval ) ;
2004-07-23 06:40:49 +00:00
}
/*
2005-02-15 10:36:59 +00:00
return on failure or ( with 0 ) if all fd events are removed
2004-07-23 06:40:49 +00:00
*/
2005-02-15 10:36:59 +00:00
static int std_event_loop_wait ( struct event_context * ev )
2004-07-23 06:40:49 +00:00
{
2005-02-15 10:36:59 +00:00
struct std_event_context * std_ev = talloc_get_type ( ev - > additional_data ,
struct std_event_context ) ;
std_ev - > exit_code = 0 ;
2004-07-23 06:40:49 +00:00
2005-02-15 10:36:59 +00:00
while ( std_ev - > fd_events & & std_ev - > exit_code = = 0 ) {
if ( std_event_loop_once ( ev ) ! = 0 ) {
2004-09-11 15:05:49 +00:00
break ;
}
2003-08-13 01:53:07 +00:00
}
2005-02-15 10:36:59 +00:00
return std_ev - > exit_code ;
}
static const struct event_ops std_event_ops = {
. context_init = std_event_context_init ,
. add_fd = std_event_add_fd ,
. get_fd_flags = std_event_get_fd_flags ,
. set_fd_flags = std_event_set_fd_flags ,
. add_timed = std_event_add_timed ,
. loop_once = std_event_loop_once ,
. loop_wait = std_event_loop_wait ,
} ;
const struct event_ops * event_standard_get_ops ( void )
{
return & std_event_ops ;
2003-08-13 01:53:07 +00:00
}