2005-02-15 13:36:59 +03:00
/*
Unix SMB / CIFS implementation .
main select loop and event handling
Copyright ( C ) Andrew Tridgell 2003
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-02-15 13:36:59 +03:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-02-15 13:36:59 +03:00
*/
/*
PLEASE READ THIS BEFORE MODIFYING !
This module is a general abstraction for the main select loop and
event handling . Do not ever put any localised hacks in here , instead
register one of the possible event types and implement that event
somewhere else .
There are 2 types of event handling that are handled in this module :
1 ) a file descriptor becoming readable or writeable . This is mostly
used for network sockets , but can be used for any type of file
descriptor . You may only register one handler for each file
descriptor / io combination or you will get unpredictable results
( this means that you can have a handler for read events , and a
separate handler for write events , but not two handlers that are
both handling read events )
2 ) a timed event . You can register an event that happens at a
specific time . You can register as many of these as you
like . They are single shot - add a new timed event in the event
handler to get another event .
To setup a set of events you first need to create a event_context
structure using the function event_context_init ( ) ; This returns a
2008-12-29 22:24:57 +03:00
' struct tevent_context ' that you use in all subsequent calls .
2005-02-15 13:36:59 +03:00
After that you can add / remove events that you are interested in
using event_add_ * ( ) and talloc_free ( )
2009-01-02 13:32:29 +03:00
Finally , you call tevent_loop_wait_once ( ) to block waiting for one of the
events to occor or tevent_loop_wait ( ) which will loop
2005-02-15 13:36:59 +03:00
forever .
*/
2008-04-25 01:28:30 +04:00
# include "replace.h"
2008-12-16 21:57:09 +03:00
# include "tevent.h"
# include "tevent_internal.h"
# include "tevent_util.h"
2007-01-05 12:35:49 +03:00
struct event_ops_list {
struct event_ops_list * next , * prev ;
const char * name ;
const struct event_ops * ops ;
} ;
/* list of registered event backends */
2008-06-14 19:23:31 +04:00
static struct event_ops_list * event_backends = NULL ;
2009-01-02 13:17:00 +03:00
static char * tevent_default_backend = NULL ;
2007-05-14 04:57:48 +04:00
2007-01-05 12:35:49 +03:00
/*
register an events backend
*/
2007-05-02 01:29:42 +04:00
bool event_register_backend ( const char * name , const struct event_ops * ops )
2007-01-05 12:35:49 +03:00
{
struct event_ops_list * e ;
2008-06-14 19:23:31 +04:00
for ( e = event_backends ; e ! = NULL ; e = e - > next ) {
if ( 0 = = strcmp ( e - > name , name ) ) {
/* already registered, skip it */
return true ;
}
}
2007-01-05 12:35:49 +03:00
e = talloc ( talloc_autofree_context ( ) , struct event_ops_list ) ;
2007-10-05 22:03:01 +04:00
if ( e = = NULL ) return false ;
2008-06-14 19:23:31 +04:00
2007-01-05 12:35:49 +03:00
e - > name = name ;
e - > ops = ops ;
DLIST_ADD ( event_backends , e ) ;
2008-06-14 19:23:31 +04:00
2007-10-05 22:03:01 +04:00
return true ;
2007-01-05 12:35:49 +03:00
}
2007-05-14 04:57:48 +04:00
/*
set the default event backend
*/
2009-01-02 13:17:00 +03:00
void tevent_set_default_backend ( const char * backend )
2007-05-14 04:57:48 +04:00
{
2009-01-02 13:17:00 +03:00
talloc_free ( tevent_default_backend ) ;
tevent_default_backend = talloc_strdup ( talloc_autofree_context ( ) ,
backend ) ;
2007-05-14 04:57:48 +04:00
}
2007-01-05 12:35:49 +03:00
/*
initialise backends if not already done
*/
static void event_backend_init ( void )
{
2007-05-14 04:57:48 +04:00
events_select_init ( ) ;
2007-05-02 01:29:42 +04:00
events_standard_init ( ) ;
2007-05-14 04:57:48 +04:00
# if HAVE_EVENTS_EPOLL
2008-06-14 19:23:31 +04:00
events_epoll_init ( ) ;
2007-05-14 04:57:48 +04:00
# endif
2008-06-14 19:23:31 +04:00
# if HAVE_LINUX_AIO
events_aio_init ( ) ;
2007-05-02 01:29:42 +04:00
# endif
2007-01-05 12:35:49 +03:00
}
/*
list available backends
*/
const char * * event_backend_list ( TALLOC_CTX * mem_ctx )
{
const char * * list = NULL ;
struct event_ops_list * e ;
event_backend_init ( ) ;
for ( e = event_backends ; e ; e = e - > next ) {
2008-06-14 19:23:31 +04:00
list = ev_str_list_add ( list , e - > name ) ;
2007-01-05 12:35:49 +03:00
}
talloc_steal ( mem_ctx , list ) ;
return list ;
}
2005-02-15 13:36:59 +03:00
/*
create a event_context structure for a specific implemementation .
This must be the first events call , and all subsequent calls pass
this event_context as the first element . Event handlers also
receive this as their first argument .
This function is for allowing third - party - applications to hook in gluecode
to their own event loop code , so that they can make async usage of our client libs
NOTE : use event_context_init ( ) inside of samba !
*/
2008-12-29 22:24:57 +03:00
static struct tevent_context * event_context_init_ops ( TALLOC_CTX * mem_ctx ,
2007-01-05 12:35:49 +03:00
const struct event_ops * ops )
2005-02-15 13:36:59 +03:00
{
2008-12-29 22:24:57 +03:00
struct tevent_context * ev ;
2005-02-15 13:36:59 +03:00
int ret ;
2008-12-29 22:24:57 +03:00
ev = talloc_zero ( mem_ctx , struct tevent_context ) ;
2005-02-15 13:36:59 +03:00
if ( ! ev ) return NULL ;
ev - > ops = ops ;
2007-01-05 12:35:49 +03:00
ret = ev - > ops - > context_init ( ev ) ;
2005-02-15 13:36:59 +03:00
if ( ret ! = 0 ) {
talloc_free ( ev ) ;
return NULL ;
}
return ev ;
}
2007-01-05 12:35:49 +03:00
/*
create a event_context structure . This must be the first events
call , and all subsequent calls pass this event_context as the first
element . Event handlers also receive this as their first argument .
*/
2008-12-29 22:24:57 +03:00
struct tevent_context * event_context_init_byname ( TALLOC_CTX * mem_ctx , const char * name )
2007-01-05 12:35:49 +03:00
{
struct event_ops_list * e ;
event_backend_init ( ) ;
2007-05-14 04:57:48 +04:00
if ( name = = NULL ) {
2009-01-02 13:17:00 +03:00
name = tevent_default_backend ;
2007-05-14 04:57:48 +04:00
}
2007-01-09 03:00:30 +03:00
if ( name = = NULL ) {
name = " standard " ;
}
2007-01-05 12:35:49 +03:00
for ( e = event_backends ; e ; e = e - > next ) {
if ( strcmp ( name , e - > name ) = = 0 ) {
return event_context_init_ops ( mem_ctx , e - > ops ) ;
}
}
return NULL ;
}
2005-02-15 13:36:59 +03:00
/*
create a event_context structure . This must be the first events
call , and all subsequent calls pass this event_context as the first
element . Event handlers also receive this as their first argument .
*/
2008-12-29 22:24:57 +03:00
struct tevent_context * event_context_init ( TALLOC_CTX * mem_ctx )
2005-02-15 13:36:59 +03:00
{
2007-01-09 03:00:30 +03:00
return event_context_init_byname ( mem_ctx , NULL ) ;
2005-02-15 13:36:59 +03:00
}
/*
add a fd based event
return NULL on failure ( memory allocation error )
2007-05-14 04:57:48 +04:00
if flags contains EVENT_FD_AUTOCLOSE then the fd will be closed when
the returned fd_event context is freed
2005-02-15 13:36:59 +03:00
*/
2008-12-29 22:24:57 +03:00
struct tevent_fd * event_add_fd ( struct tevent_context * ev , TALLOC_CTX * mem_ctx ,
2005-02-15 13:36:59 +03:00
int fd , uint16_t flags , event_fd_handler_t handler ,
void * private_data )
{
return ev - > ops - > add_fd ( ev , mem_ctx , fd , flags , handler , private_data ) ;
}
2007-01-05 12:35:49 +03:00
/*
add a disk aio event
*/
2008-12-29 22:24:57 +03:00
struct aio_event * event_add_aio ( struct tevent_context * ev ,
2007-01-05 12:35:49 +03:00
TALLOC_CTX * mem_ctx ,
struct iocb * iocb ,
event_aio_handler_t handler ,
void * private_data )
{
if ( ev - > ops - > add_aio = = NULL ) return NULL ;
return ev - > ops - > add_aio ( ev , mem_ctx , iocb , handler , private_data ) ;
}
2005-02-15 13:36:59 +03:00
/*
return the fd event flags
*/
2009-01-02 13:36:52 +03:00
uint16_t tevent_fd_get_flags ( struct tevent_fd * fde )
2005-02-15 13:36:59 +03:00
{
2005-12-08 11:31:59 +03:00
if ( ! fde ) return 0 ;
2005-02-15 13:36:59 +03:00
return fde - > event_ctx - > ops - > get_fd_flags ( fde ) ;
}
/*
set the fd event flags
*/
2009-01-02 13:36:52 +03:00
void tevent_fd_set_flags ( struct tevent_fd * fde , uint16_t flags )
2005-02-15 13:36:59 +03:00
{
2005-12-08 11:31:59 +03:00
if ( ! fde ) return ;
2005-02-15 13:36:59 +03:00
fde - > event_ctx - > ops - > set_fd_flags ( fde , flags ) ;
}
/*
add a timed event
return NULL on failure
*/
2008-12-29 22:24:57 +03:00
struct tevent_timer * event_add_timed ( struct tevent_context * ev , TALLOC_CTX * mem_ctx ,
2005-02-15 13:36:59 +03:00
struct timeval next_event ,
event_timed_handler_t handler ,
void * private_data )
{
2008-12-24 15:52:57 +03:00
return ev - > ops - > add_timer ( ev , mem_ctx , next_event , handler , private_data ) ;
2005-02-15 13:36:59 +03:00
}
2007-01-21 11:23:14 +03:00
/*
add a signal event
2007-01-21 13:32:39 +03:00
sa_flags are flags to sigaction ( 2 )
2007-01-21 11:23:14 +03:00
return NULL on failure
*/
2008-12-29 22:24:57 +03:00
struct signal_event * event_add_signal ( struct tevent_context * ev , TALLOC_CTX * mem_ctx ,
2007-01-21 12:25:21 +03:00
int signum ,
2007-01-21 13:32:39 +03:00
int sa_flags ,
2007-01-21 12:25:21 +03:00
event_signal_handler_t handler ,
void * private_data )
2007-01-21 11:23:14 +03:00
{
2007-01-21 13:32:39 +03:00
return ev - > ops - > add_signal ( ev , mem_ctx , signum , sa_flags , handler , private_data ) ;
2007-01-21 11:23:14 +03:00
}
2005-02-15 13:36:59 +03:00
/*
do a single event loop using the events defined in ev
*/
2009-01-02 13:32:29 +03:00
int tevent_loop_once ( struct tevent_context * ev )
2005-02-15 13:36:59 +03:00
{
return ev - > ops - > loop_once ( ev ) ;
}
/*
return on failure or ( with 0 ) if all fd events are removed
*/
2009-01-02 13:32:29 +03:00
int tevent_loop_wait ( struct tevent_context * ev )
2005-02-15 13:36:59 +03:00
{
return ev - > ops - > loop_wait ( ev ) ;
}