2022-06-16 20:09:03 +03:00
/*
2005-02-15 13:36:59 +03:00
Unix SMB / CIFS implementation .
main select loop and event handling
Copyright ( C ) Andrew Tridgell 2003
2009-02-16 10:52:06 +03:00
Copyright ( C ) Stefan Metzmacher 2009
* * NOTE ! The following LGPL license applies to the tevent
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 3 of the License , or ( at your option ) any later version .
This library is distributed in the hope that it will be useful ,
2005-02-15 13:36:59 +03:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2009-02-16 10:52:06 +03:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; 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
2009-01-02 13:30:00 +03:00
structure using the function tevent_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
2009-01-02 13:44:17 +03:00
using tevent_add_ * ( ) and talloc_free ( )
2005-02-15 13:36:59 +03:00
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"
2009-01-03 14:39:11 +03:00
# include "system/filesys.h"
2016-08-08 12:26:37 +03:00
# ifdef HAVE_PTHREAD
# include "system/threads.h"
# endif
2009-03-12 11:51:33 +03:00
# define TEVENT_DEPRECATED 1
2008-12-16 21:57:09 +03:00
# include "tevent.h"
# include "tevent_internal.h"
# include "tevent_util.h"
2016-08-12 17:32:33 +03:00
# ifdef HAVE_EVENTFD
# include <sys/eventfd.h>
# endif
2007-01-05 12:35:49 +03:00
2009-01-02 13:30:00 +03:00
struct tevent_ops_list {
struct tevent_ops_list * next , * prev ;
2007-01-05 12:35:49 +03:00
const char * name ;
2009-01-02 13:30:00 +03:00
const struct tevent_ops * ops ;
2007-01-05 12:35:49 +03:00
} ;
/* list of registered event backends */
2009-01-02 13:30:00 +03:00
static struct tevent_ops_list * tevent_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
*/
2009-01-02 15:35:32 +03:00
bool tevent_register_backend ( const char * name , const struct tevent_ops * ops )
2007-01-05 12:35:49 +03:00
{
2009-01-02 13:30:00 +03:00
struct tevent_ops_list * e ;
2008-06-14 19:23:31 +04:00
2009-01-02 13:30:00 +03:00
for ( e = tevent_backends ; e ! = NULL ; e = e - > next ) {
2008-06-14 19:23:31 +04:00
if ( 0 = = strcmp ( e - > name , name ) ) {
/* already registered, skip it */
return true ;
}
}
2010-09-24 21:13:05 +04:00
e = talloc ( NULL , struct tevent_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 ;
2009-01-02 13:30:00 +03:00
DLIST_ADD ( tevent_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 ) ;
2010-09-24 21:13:05 +04:00
tevent_default_backend = talloc_strdup ( NULL , backend ) ;
2007-05-14 04:57:48 +04:00
}
2007-01-05 12:35:49 +03:00
/*
initialise backends if not already done
*/
2009-01-02 13:30:00 +03:00
static void tevent_backend_init ( void )
2007-01-05 12:35:49 +03:00
{
2013-02-14 12:29:57 +04:00
static bool done ;
if ( done ) {
return ;
}
done = true ;
2011-02-09 17:28:10 +03:00
tevent_poll_init ( ) ;
2012-08-13 18:06:01 +04:00
tevent_poll_mt_init ( ) ;
2013-07-23 01:23:33 +04:00
# if defined(HAVE_EPOLL)
2009-01-02 15:35:32 +03:00
tevent_epoll_init ( ) ;
2007-05-14 04:57:48 +04:00
# endif
2013-07-23 01:23:33 +04:00
2013-02-11 22:36:52 +04:00
tevent_standard_init ( ) ;
2007-01-05 12:35:49 +03:00
}
2022-10-28 15:10:15 +03:00
const struct tevent_ops * tevent_find_ops_byname ( const char * name )
2013-02-11 22:56:58 +04:00
{
struct tevent_ops_list * e ;
tevent_backend_init ( ) ;
if ( name = = NULL ) {
name = tevent_default_backend ;
}
if ( name = = NULL ) {
name = " standard " ;
}
for ( e = tevent_backends ; e ! = NULL ; e = e - > next ) {
if ( 0 = = strcmp ( e - > name , name ) ) {
return e - > ops ;
}
}
return NULL ;
}
2007-01-05 12:35:49 +03:00
/*
list available backends
*/
2009-01-02 13:30:00 +03:00
const char * * tevent_backend_list ( TALLOC_CTX * mem_ctx )
2007-01-05 12:35:49 +03:00
{
const char * * list = NULL ;
2009-01-02 13:30:00 +03:00
struct tevent_ops_list * e ;
2021-05-03 23:03:47 +03:00
size_t idx = 0 ;
2007-01-05 12:35:49 +03:00
2009-01-02 13:30:00 +03:00
tevent_backend_init ( ) ;
2007-01-05 12:35:49 +03:00
2009-01-02 13:30:00 +03:00
for ( e = tevent_backends ; e ; e = e - > next ) {
2021-05-03 23:03:47 +03:00
idx + = 1 ;
2007-01-05 12:35:49 +03:00
}
2021-05-03 23:03:47 +03:00
list = talloc_zero_array ( mem_ctx , const char * , idx + 1 ) ;
if ( list = = NULL ) {
return NULL ;
}
idx = 0 ;
for ( e = tevent_backends ; e ; e = e - > next ) {
list [ idx ] = talloc_strdup ( list , e - > name ) ;
if ( list [ idx ] = = NULL ) {
TALLOC_FREE ( list ) ;
return NULL ;
}
idx + = 1 ;
}
2007-01-05 12:35:49 +03:00
return list ;
}
2005-02-15 13:36:59 +03:00
2016-08-12 17:00:56 +03:00
static void tevent_common_wakeup_fini ( struct tevent_context * ev ) ;
2016-08-08 12:26:37 +03:00
# ifdef HAVE_PTHREAD
static pthread_mutex_t tevent_contexts_mutex = PTHREAD_MUTEX_INITIALIZER ;
static struct tevent_context * tevent_contexts = NULL ;
static pthread_once_t tevent_atfork_initialized = PTHREAD_ONCE_INIT ;
2022-07-13 15:30:47 +03:00
static pid_t tevent_cached_global_pid = 0 ;
2016-08-08 12:26:37 +03:00
static void tevent_atfork_prepare ( void )
{
struct tevent_context * ev ;
int ret ;
ret = pthread_mutex_lock ( & tevent_contexts_mutex ) ;
if ( ret ! = 0 ) {
abort ( ) ;
}
for ( ev = tevent_contexts ; ev ! = NULL ; ev = ev - > next ) {
2016-09-07 21:25:36 +03:00
struct tevent_threaded_context * tctx ;
for ( tctx = ev - > threaded_contexts ; tctx ! = NULL ;
tctx = tctx - > next ) {
ret = pthread_mutex_lock ( & tctx - > event_ctx_mutex ) ;
if ( ret ! = 0 ) {
tevent_abort ( ev , " pthread_mutex_lock failed " ) ;
}
}
2016-08-08 12:26:37 +03:00
ret = pthread_mutex_lock ( & ev - > scheduled_mutex ) ;
if ( ret ! = 0 ) {
tevent_abort ( ev , " pthread_mutex_lock failed " ) ;
}
}
}
static void tevent_atfork_parent ( void )
{
struct tevent_context * ev ;
int ret ;
for ( ev = DLIST_TAIL ( tevent_contexts ) ; ev ! = NULL ;
ev = DLIST_PREV ( ev ) ) {
2016-09-07 21:25:36 +03:00
struct tevent_threaded_context * tctx ;
2016-08-08 12:26:37 +03:00
ret = pthread_mutex_unlock ( & ev - > scheduled_mutex ) ;
if ( ret ! = 0 ) {
tevent_abort ( ev , " pthread_mutex_unlock failed " ) ;
}
2016-09-07 21:25:36 +03:00
for ( tctx = DLIST_TAIL ( ev - > threaded_contexts ) ; tctx ! = NULL ;
tctx = DLIST_PREV ( tctx ) ) {
ret = pthread_mutex_unlock ( & tctx - > event_ctx_mutex ) ;
if ( ret ! = 0 ) {
tevent_abort (
ev , " pthread_mutex_unlock failed " ) ;
}
}
2016-08-08 12:26:37 +03:00
}
ret = pthread_mutex_unlock ( & tevent_contexts_mutex ) ;
if ( ret ! = 0 ) {
abort ( ) ;
}
}
static void tevent_atfork_child ( void )
{
struct tevent_context * ev ;
int ret ;
2022-07-13 15:30:47 +03:00
tevent_cached_global_pid = getpid ( ) ;
2016-08-08 12:26:37 +03:00
for ( ev = DLIST_TAIL ( tevent_contexts ) ; ev ! = NULL ;
ev = DLIST_PREV ( ev ) ) {
struct tevent_threaded_context * tctx ;
2016-09-07 21:25:36 +03:00
for ( tctx = DLIST_TAIL ( ev - > threaded_contexts ) ; tctx ! = NULL ;
tctx = DLIST_PREV ( tctx ) ) {
2016-08-08 12:26:37 +03:00
tctx - > event_ctx = NULL ;
2016-09-07 21:25:36 +03:00
ret = pthread_mutex_unlock ( & tctx - > event_ctx_mutex ) ;
if ( ret ! = 0 ) {
tevent_abort (
ev , " pthread_mutex_unlock failed " ) ;
}
2016-08-08 12:26:37 +03:00
}
ev - > threaded_contexts = NULL ;
ret = pthread_mutex_unlock ( & ev - > scheduled_mutex ) ;
if ( ret ! = 0 ) {
tevent_abort ( ev , " pthread_mutex_unlock failed " ) ;
}
}
ret = pthread_mutex_unlock ( & tevent_contexts_mutex ) ;
if ( ret ! = 0 ) {
abort ( ) ;
}
}
static void tevent_prep_atfork ( void )
{
int ret ;
ret = pthread_atfork ( tevent_atfork_prepare ,
tevent_atfork_parent ,
tevent_atfork_child ) ;
if ( ret ! = 0 ) {
abort ( ) ;
}
2022-07-13 15:30:47 +03:00
tevent_cached_global_pid = getpid ( ) ;
}
# endif
static int tevent_init_globals ( void )
{
# ifdef HAVE_PTHREAD
int ret ;
ret = pthread_once ( & tevent_atfork_initialized , tevent_prep_atfork ) ;
if ( ret ! = 0 ) {
return ret ;
}
# endif
return 0 ;
2016-08-08 12:26:37 +03:00
}
2022-07-13 15:30:47 +03:00
_PUBLIC_ pid_t tevent_cached_getpid ( void )
{
# ifdef HAVE_PTHREAD
tevent_init_globals ( ) ;
# ifdef TEVENT_VERIFY_CACHED_GETPID
if ( tevent_cached_global_pid ! = getpid ( ) ) {
tevent_abort ( NULL , " tevent_cached_global_pid invalid " ) ;
}
# endif
if ( tevent_cached_global_pid ! = 0 ) {
return tevent_cached_global_pid ;
}
2016-08-08 12:26:37 +03:00
# endif
2022-07-13 15:30:47 +03:00
return getpid ( ) ;
}
2016-08-08 12:26:37 +03:00
2009-01-05 21:23:23 +03:00
int tevent_common_context_destructor ( struct tevent_context * ev )
{
2009-01-12 11:20:57 +03:00
struct tevent_fd * fd , * fn ;
struct tevent_timer * te , * tn ;
2009-03-13 17:47:33 +03:00
struct tevent_immediate * ie , * in ;
2009-01-12 11:20:57 +03:00
struct tevent_signal * se , * sn ;
2014-07-22 18:51:38 +04:00
struct tevent_wrapper_glue * gl , * gn ;
2016-08-08 12:26:37 +03:00
# ifdef HAVE_PTHREAD
int ret ;
2014-07-22 18:51:38 +04:00
# endif
if ( ev - > wrapper . glue ! = NULL ) {
tevent_abort ( ev ,
" tevent_common_context_destructor() active on wrapper " ) ;
}
2016-08-08 12:26:37 +03:00
2014-07-22 18:51:38 +04:00
# ifdef HAVE_PTHREAD
2016-08-08 12:26:37 +03:00
ret = pthread_mutex_lock ( & tevent_contexts_mutex ) ;
if ( ret ! = 0 ) {
abort ( ) ;
}
DLIST_REMOVE ( tevent_contexts , ev ) ;
ret = pthread_mutex_unlock ( & tevent_contexts_mutex ) ;
if ( ret ! = 0 ) {
abort ( ) ;
}
2016-09-07 21:25:36 +03:00
while ( ev - > threaded_contexts ! = NULL ) {
struct tevent_threaded_context * tctx = ev - > threaded_contexts ;
ret = pthread_mutex_lock ( & tctx - > event_ctx_mutex ) ;
if ( ret ! = 0 ) {
abort ( ) ;
}
2016-08-08 12:26:37 +03:00
/*
2016-09-07 21:25:36 +03:00
* Indicate to the thread that the tevent_context is
* gone . The counterpart of this is in
* _tevent_threaded_schedule_immediate , there we read
* this under the threaded_context ' s mutex .
2016-08-08 12:26:37 +03:00
*/
2016-09-07 21:25:36 +03:00
tctx - > event_ctx = NULL ;
ret = pthread_mutex_unlock ( & tctx - > event_ctx_mutex ) ;
if ( ret ! = 0 ) {
abort ( ) ;
}
DLIST_REMOVE ( ev - > threaded_contexts , tctx ) ;
2016-08-08 12:26:37 +03:00
}
2017-05-24 17:21:40 +03:00
ret = pthread_mutex_destroy ( & ev - > scheduled_mutex ) ;
if ( ret ! = 0 ) {
abort ( ) ;
}
2016-09-07 21:25:36 +03:00
# endif
2016-08-08 12:26:37 +03:00
2014-07-22 18:51:38 +04:00
for ( gl = ev - > wrapper . list ; gl ; gl = gn ) {
gn = gl - > next ;
gl - > main_ev = NULL ;
DLIST_REMOVE ( ev - > wrapper . list , gl ) ;
}
2016-08-12 17:00:56 +03:00
tevent_common_wakeup_fini ( ev ) ;
2009-01-05 21:23:23 +03:00
2009-01-12 11:20:57 +03:00
for ( fd = ev - > fd_events ; fd ; fd = fn ) {
fn = fd - > next ;
2023-08-31 19:09:28 +03:00
tevent_common_fd_disarm ( fd ) ;
2009-01-05 21:23:23 +03:00
}
2013-02-22 15:45:39 +04:00
ev - > last_zero_timer = NULL ;
2009-01-12 11:20:57 +03:00
for ( te = ev - > timer_events ; te ; te = tn ) {
tn = te - > next ;
2021-06-01 15:10:05 +03:00
tevent_trace_timer_callback ( te - > event_ctx , te , TEVENT_EVENT_TRACE_DETACH ) ;
2014-07-22 18:51:38 +04:00
te - > wrapper = NULL ;
2009-01-05 21:23:23 +03:00
te - > event_ctx = NULL ;
2009-01-11 22:00:50 +03:00
DLIST_REMOVE ( ev - > timer_events , te ) ;
2009-01-05 21:23:23 +03:00
}
2009-03-13 17:47:33 +03:00
for ( ie = ev - > immediate_events ; ie ; ie = in ) {
in = ie - > next ;
2021-06-01 15:10:05 +03:00
tevent_trace_immediate_callback ( ie - > event_ctx , ie , TEVENT_EVENT_TRACE_DETACH ) ;
2014-07-22 18:51:38 +04:00
ie - > wrapper = NULL ;
2009-03-13 17:47:33 +03:00
ie - > event_ctx = NULL ;
ie - > cancel_fn = NULL ;
DLIST_REMOVE ( ev - > immediate_events , ie ) ;
}
2009-01-12 11:20:57 +03:00
for ( se = ev - > signal_events ; se ; se = sn ) {
sn = se - > next ;
2021-06-01 15:10:05 +03:00
tevent_trace_signal_callback ( se - > event_ctx , se , TEVENT_EVENT_TRACE_DETACH ) ;
2014-07-22 18:51:38 +04:00
se - > wrapper = NULL ;
2009-01-05 21:23:23 +03:00
se - > event_ctx = NULL ;
DLIST_REMOVE ( ev - > signal_events , se ) ;
2010-02-09 12:02:20 +03:00
/*
* This is important , Otherwise signals
* are handled twice in child . eg , SIGHUP .
* one added in parent , and another one in
* the child . - - BoYang
*/
tevent_cleanup_pending_signal_handlers ( se ) ;
2009-01-05 21:23:23 +03:00
}
2011-08-12 05:56:28 +04:00
/* removing nesting hook or we get an abort when nesting is
* not allowed . - - SSS
* Note that we need to leave the allowed flag at its current
* value , otherwise the use in tevent_re_initialise ( ) will
* leave the event context with allowed forced to false , which
* will break users that expect nesting to be allowed
*/
2011-04-26 07:40:15 +04:00
ev - > nesting . level = 0 ;
ev - > nesting . hook_fn = NULL ;
ev - > nesting . hook_private = NULL ;
2009-01-05 21:23:23 +03:00
return 0 ;
}
2017-06-05 07:58:37 +03:00
static int tevent_common_context_constructor ( struct tevent_context * ev )
2005-02-15 13:36:59 +03:00
{
int ret ;
2022-07-13 15:30:47 +03:00
ret = tevent_init_globals ( ) ;
2016-08-08 12:26:37 +03:00
if ( ret ! = 0 ) {
2017-06-05 07:58:37 +03:00
return ret ;
2016-08-08 12:26:37 +03:00
}
2022-07-13 15:30:47 +03:00
# ifdef HAVE_PTHREAD
2016-08-08 12:26:37 +03:00
ret = pthread_mutex_init ( & ev - > scheduled_mutex , NULL ) ;
if ( ret ! = 0 ) {
2017-06-05 07:58:37 +03:00
return ret ;
2016-08-08 12:26:37 +03:00
}
ret = pthread_mutex_lock ( & tevent_contexts_mutex ) ;
if ( ret ! = 0 ) {
pthread_mutex_destroy ( & ev - > scheduled_mutex ) ;
2017-06-05 07:58:37 +03:00
return ret ;
2016-08-08 12:26:37 +03:00
}
DLIST_ADD ( tevent_contexts , ev ) ;
ret = pthread_mutex_unlock ( & tevent_contexts_mutex ) ;
if ( ret ! = 0 ) {
abort ( ) ;
}
# endif
2009-01-05 21:23:23 +03:00
talloc_set_destructor ( ev , tevent_common_context_destructor ) ;
2017-06-05 07:58:37 +03:00
return 0 ;
}
2018-04-17 17:33:47 +03:00
void tevent_common_check_double_free ( TALLOC_CTX * ptr , const char * reason )
{
void * parent_ptr = talloc_parent ( ptr ) ;
size_t parent_blocks = talloc_total_blocks ( parent_ptr ) ;
if ( parent_ptr ! = NULL & & parent_blocks = = 0 ) {
/*
* This is an implicit talloc free , as we still have a parent
* but it ' s already being destroyed . Note that
* talloc_total_blocks ( ptr ) also just returns 0 if a
* talloc_free ( ptr ) is still in progress of freeing all
* children .
*/
return ;
}
tevent_abort ( NULL , reason ) ;
}
2017-06-05 07:58:37 +03:00
/*
2023-04-13 14:18:05 +03:00
create a event_context structure for a specific implementation .
2017-06-05 07:58:37 +03:00
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 tevent_context_init ( ) inside of samba !
*/
struct tevent_context * tevent_context_init_ops ( TALLOC_CTX * mem_ctx ,
const struct tevent_ops * ops ,
void * additional_data )
{
struct tevent_context * ev ;
int ret ;
ev = talloc_zero ( mem_ctx , struct tevent_context ) ;
if ( ! ev ) return NULL ;
ret = tevent_common_context_constructor ( ev ) ;
if ( ret ! = 0 ) {
talloc_free ( ev ) ;
return NULL ;
}
2005-02-15 13:36:59 +03:00
ev - > ops = ops ;
2012-05-11 17:19:55 +04:00
ev - > additional_data = additional_data ;
2005-02-15 13:36:59 +03:00
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 .
*/
2009-01-02 13:30:00 +03:00
struct tevent_context * tevent_context_init_byname ( TALLOC_CTX * mem_ctx ,
const char * name )
2007-01-05 12:35:49 +03:00
{
2013-02-17 19:36:25 +04:00
const struct tevent_ops * ops ;
2007-01-05 12:35:49 +03:00
2013-02-14 12:30:31 +04:00
ops = tevent_find_ops_byname ( name ) ;
if ( ops = = NULL ) {
return NULL ;
2007-01-09 03:00:30 +03:00
}
2013-02-14 12:30:31 +04:00
return tevent_context_init_ops ( mem_ctx , ops , NULL ) ;
2007-01-05 12:35:49 +03:00
}
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 .
*/
2009-01-02 13:30:00 +03:00
struct tevent_context * tevent_context_init ( TALLOC_CTX * mem_ctx )
2005-02-15 13:36:59 +03:00
{
2009-01-02 13:30:00 +03:00
return tevent_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 )
*/
2009-01-02 13:44:17 +03:00
struct tevent_fd * _tevent_add_fd ( struct tevent_context * ev ,
TALLOC_CTX * mem_ctx ,
int fd ,
uint16_t flags ,
tevent_fd_handler_t handler ,
void * private_data ,
const char * handler_name ,
const char * location )
2005-02-15 13:36:59 +03:00
{
2009-01-02 15:26:32 +03:00
return ev - > ops - > add_fd ( ev , mem_ctx , fd , flags , handler , private_data ,
handler_name , location ) ;
2005-02-15 13:36:59 +03:00
}
2009-01-03 13:27:00 +03:00
/*
set a close function on the fd event
*/
void tevent_fd_set_close_fn ( struct tevent_fd * fde ,
tevent_fd_close_fn_t close_fn )
{
if ( ! fde ) return ;
2009-01-07 08:30:37 +03:00
if ( ! fde - > event_ctx ) return ;
2009-01-03 13:27:00 +03:00
fde - > event_ctx - > ops - > set_fd_close_fn ( fde , close_fn ) ;
}
2009-01-03 14:39:11 +03:00
static void tevent_fd_auto_close_fn ( struct tevent_context * ev ,
struct tevent_fd * fde ,
int fd ,
void * private_data )
{
close ( fd ) ;
}
void tevent_fd_set_auto_close ( struct tevent_fd * fde )
{
tevent_fd_set_close_fn ( fde , tevent_fd_auto_close_fn ) ;
}
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 ;
2009-01-07 08:30:37 +03:00
if ( ! fde - > event_ctx ) 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 ;
2009-01-07 08:30:37 +03:00
if ( ! fde - > event_ctx ) return ;
2005-02-15 13:36:59 +03:00
fde - > event_ctx - > ops - > set_fd_flags ( fde , flags ) ;
}
2009-03-12 10:48:59 +03:00
bool tevent_signal_support ( struct tevent_context * ev )
{
if ( ev - > ops - > add_signal ) {
return true ;
}
return false ;
}
2009-03-12 11:22:41 +03:00
static void ( * tevent_abort_fn ) ( const char * reason ) ;
void tevent_set_abort_fn ( void ( * abort_fn ) ( const char * reason ) )
{
tevent_abort_fn = abort_fn ;
}
2014-07-22 17:10:00 +04:00
void tevent_abort ( struct tevent_context * ev , const char * reason )
2009-03-12 11:22:41 +03:00
{
2018-03-22 18:51:01 +03:00
if ( ev ! = NULL ) {
tevent_debug ( ev , TEVENT_DEBUG_FATAL ,
" abort: %s \n " , reason ) ;
}
2009-03-12 11:22:41 +03:00
if ( ! tevent_abort_fn ) {
abort ( ) ;
}
tevent_abort_fn ( reason ) ;
}
2005-02-15 13:36:59 +03:00
/*
2009-01-02 13:44:17 +03:00
add a timer event
2005-02-15 13:36:59 +03:00
return NULL on failure
*/
2009-01-02 13:44:17 +03:00
struct tevent_timer * _tevent_add_timer ( struct tevent_context * ev ,
TALLOC_CTX * mem_ctx ,
struct timeval next_event ,
tevent_timer_handler_t handler ,
void * private_data ,
const char * handler_name ,
const char * location )
2005-02-15 13:36:59 +03:00
{
2009-01-02 15:26:32 +03:00
return ev - > ops - > add_timer ( ev , mem_ctx , next_event , handler , private_data ,
handler_name , location ) ;
2005-02-15 13:36:59 +03:00
}
2009-03-13 17:47:33 +03:00
/*
allocate an immediate event
return NULL on failure ( memory allocation error )
*/
struct tevent_immediate * _tevent_create_immediate ( TALLOC_CTX * mem_ctx ,
const char * location )
{
struct tevent_immediate * im ;
im = talloc ( mem_ctx , struct tevent_immediate ) ;
if ( im = = NULL ) return NULL ;
2017-06-17 22:26:27 +03:00
* im = ( struct tevent_immediate ) { . create_location = location } ;
2009-03-13 17:47:33 +03:00
return im ;
}
/*
schedule an immediate event
*/
void _tevent_schedule_immediate ( struct tevent_immediate * im ,
struct tevent_context * ev ,
tevent_immediate_handler_t handler ,
void * private_data ,
const char * handler_name ,
const char * location )
{
ev - > ops - > schedule_immediate ( im , ev , handler , private_data ,
handler_name , location ) ;
}
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
*/
2009-01-02 13:44:17 +03:00
struct tevent_signal * _tevent_add_signal ( struct tevent_context * ev ,
TALLOC_CTX * mem_ctx ,
int signum ,
int sa_flags ,
tevent_signal_handler_t handler ,
void * private_data ,
const char * handler_name ,
const char * location )
2007-01-21 11:23:14 +03:00
{
2009-01-02 15:26:32 +03:00
return ev - > ops - > add_signal ( ev , mem_ctx , signum , sa_flags , handler , private_data ,
handler_name , location ) ;
2007-01-21 11:23:14 +03:00
}
2009-03-12 11:51:33 +03:00
void tevent_loop_allow_nesting ( struct tevent_context * ev )
{
2014-07-22 18:51:38 +04:00
if ( ev - > wrapper . glue ! = NULL ) {
tevent_abort ( ev , " tevent_loop_allow_nesting() on wrapper " ) ;
return ;
}
if ( ev - > wrapper . list ! = NULL ) {
tevent_abort ( ev , " tevent_loop_allow_nesting() with wrapper " ) ;
return ;
}
2009-03-12 11:51:33 +03:00
ev - > nesting . allowed = true ;
}
2009-03-12 12:23:30 +03:00
void tevent_loop_set_nesting_hook ( struct tevent_context * ev ,
tevent_nesting_hook hook ,
void * private_data )
{
2022-06-16 20:09:03 +03:00
if ( ev - > nesting . hook_fn & &
2009-03-19 03:21:36 +03:00
( ev - > nesting . hook_fn ! = hook | |
ev - > nesting . hook_private ! = private_data ) ) {
/* the way the nesting hook code is currently written
we cannot support two different nesting hooks at the
same time . */
tevent_abort ( ev , " tevent: Violation of nesting hook rules \n " ) ;
}
2009-03-12 12:23:30 +03:00
ev - > nesting . hook_fn = hook ;
ev - > nesting . hook_private = private_data ;
}
2009-03-12 11:51:33 +03:00
static void tevent_abort_nesting ( struct tevent_context * ev , const char * location )
{
const char * reason ;
reason = talloc_asprintf ( NULL , " tevent_loop_once() nesting at %s " ,
location ) ;
if ( ! reason ) {
reason = " tevent_loop_once() nesting " ;
}
tevent_abort ( ev , reason ) ;
}
2005-02-15 13:36:59 +03:00
/*
2022-06-16 20:09:03 +03:00
do a single event loop using the events defined in ev
2005-02-15 13:36:59 +03:00
*/
2009-03-12 11:33:26 +03:00
int _tevent_loop_once ( struct tevent_context * ev , const char * location )
2005-02-15 13:36:59 +03:00
{
2009-03-12 11:51:33 +03:00
int ret ;
2009-03-12 12:23:30 +03:00
void * nesting_stack_ptr = NULL ;
2009-03-12 11:51:33 +03:00
ev - > nesting . level + + ;
if ( ev - > nesting . level > 1 ) {
if ( ! ev - > nesting . allowed ) {
tevent_abort_nesting ( ev , location ) ;
errno = ELOOP ;
return - 1 ;
}
2009-03-19 16:31:43 +03:00
}
if ( ev - > nesting . level > 0 ) {
2009-03-12 12:23:30 +03:00
if ( ev - > nesting . hook_fn ) {
int ret2 ;
ret2 = ev - > nesting . hook_fn ( ev ,
ev - > nesting . hook_private ,
ev - > nesting . level ,
true ,
( void * ) & nesting_stack_ptr ,
location ) ;
if ( ret2 ! = 0 ) {
ret = ret2 ;
goto done ;
}
}
2009-03-12 11:51:33 +03:00
}
2013-02-26 18:54:57 +04:00
tevent_trace_point_callback ( ev , TEVENT_TRACE_BEFORE_LOOP_ONCE ) ;
2009-03-12 11:51:33 +03:00
ret = ev - > ops - > loop_once ( ev , location ) ;
2013-02-26 18:54:57 +04:00
tevent_trace_point_callback ( ev , TEVENT_TRACE_AFTER_LOOP_ONCE ) ;
2009-03-12 11:51:33 +03:00
2022-06-16 17:23:22 +03:00
/* New event (and request) will always start with call depth 0. */
2023-05-02 22:57:16 +03:00
tevent_thread_call_depth_notify ( TEVENT_CALL_FLOW_REQ_RESET ,
NULL ,
0 ,
__func__ ) ;
2022-06-16 17:23:22 +03:00
2009-03-19 16:31:43 +03:00
if ( ev - > nesting . level > 0 ) {
2009-03-12 12:23:30 +03:00
if ( ev - > nesting . hook_fn ) {
int ret2 ;
ret2 = ev - > nesting . hook_fn ( ev ,
ev - > nesting . hook_private ,
ev - > nesting . level ,
false ,
( void * ) & nesting_stack_ptr ,
location ) ;
if ( ret2 ! = 0 ) {
ret = ret2 ;
goto done ;
}
}
}
2009-03-12 11:51:33 +03:00
2009-03-12 12:23:30 +03:00
done :
ev - > nesting . level - - ;
2009-03-12 11:51:33 +03:00
return ret ;
2005-02-15 13:36:59 +03:00
}
2009-03-12 12:35:23 +03:00
/*
this is a performance optimization for the samba4 nested event loop problems
*/
int _tevent_loop_until ( struct tevent_context * ev ,
bool ( * finished ) ( void * private_data ) ,
void * private_data ,
const char * location )
{
2009-03-12 20:44:36 +03:00
int ret = 0 ;
2009-03-12 12:35:23 +03:00
void * nesting_stack_ptr = NULL ;
ev - > nesting . level + + ;
if ( ev - > nesting . level > 1 ) {
if ( ! ev - > nesting . allowed ) {
tevent_abort_nesting ( ev , location ) ;
errno = ELOOP ;
return - 1 ;
}
2009-03-19 16:31:43 +03:00
}
if ( ev - > nesting . level > 0 ) {
2009-03-12 12:35:23 +03:00
if ( ev - > nesting . hook_fn ) {
int ret2 ;
ret2 = ev - > nesting . hook_fn ( ev ,
ev - > nesting . hook_private ,
ev - > nesting . level ,
true ,
( void * ) & nesting_stack_ptr ,
location ) ;
if ( ret2 ! = 0 ) {
ret = ret2 ;
goto done ;
}
}
}
while ( ! finished ( private_data ) ) {
2013-02-26 18:54:57 +04:00
tevent_trace_point_callback ( ev , TEVENT_TRACE_BEFORE_LOOP_ONCE ) ;
2009-03-12 12:35:23 +03:00
ret = ev - > ops - > loop_once ( ev , location ) ;
2013-02-26 18:54:57 +04:00
tevent_trace_point_callback ( ev , TEVENT_TRACE_AFTER_LOOP_ONCE ) ;
2009-03-12 12:35:23 +03:00
if ( ret ! = 0 ) {
break ;
}
}
2009-03-19 16:31:43 +03:00
if ( ev - > nesting . level > 0 ) {
2009-03-12 12:35:23 +03:00
if ( ev - > nesting . hook_fn ) {
int ret2 ;
ret2 = ev - > nesting . hook_fn ( ev ,
ev - > nesting . hook_private ,
ev - > nesting . level ,
false ,
( void * ) & nesting_stack_ptr ,
location ) ;
if ( ret2 ! = 0 ) {
ret = ret2 ;
goto done ;
}
}
}
done :
ev - > nesting . level - - ;
return ret ;
}
2016-07-29 09:53:59 +03:00
bool tevent_common_have_events ( struct tevent_context * ev )
{
if ( ev - > fd_events ! = NULL ) {
2016-08-12 17:32:33 +03:00
if ( ev - > fd_events ! = ev - > wakeup_fde ) {
2016-07-29 09:53:59 +03:00
return true ;
}
if ( ev - > fd_events - > next ! = NULL ) {
return true ;
}
/*
* At this point we just have the wakeup pipe event as
* the only fd_event . That one does not count as a
* regular event , so look at the other event types .
*/
}
return ( ( ev - > timer_events ! = NULL ) | |
( ev - > immediate_events ! = NULL ) | |
( ev - > signal_events ! = NULL ) ) ;
}
2009-03-16 16:15:07 +03:00
/*
return on failure or ( with 0 ) if all fd events are removed
*/
int tevent_common_loop_wait ( struct tevent_context * ev ,
const char * location )
{
/*
* loop as long as we have events pending
*/
2016-07-29 09:53:59 +03:00
while ( tevent_common_have_events ( ev ) ) {
2009-03-16 16:15:07 +03:00
int ret ;
ret = _tevent_loop_once ( ev , location ) ;
if ( ret ! = 0 ) {
tevent_debug ( ev , TEVENT_DEBUG_FATAL ,
" _tevent_loop_once() failed: %d - %s \n " ,
ret , strerror ( errno ) ) ;
return ret ;
}
}
tevent_debug ( ev , TEVENT_DEBUG_WARNING ,
" tevent_common_loop_wait() out of events \n " ) ;
return 0 ;
}
2005-02-15 13:36:59 +03:00
/*
return on failure or ( with 0 ) if all fd events are removed
*/
2009-03-12 11:33:26 +03:00
int _tevent_loop_wait ( struct tevent_context * ev , const char * location )
2005-02-15 13:36:59 +03:00
{
2009-03-19 16:31:43 +03:00
return ev - > ops - > loop_wait ( ev , location ) ;
2005-02-15 13:36:59 +03:00
}
2010-03-26 13:13:27 +03:00
/*
re - initialise a tevent context . This leaves you with the same
event context , but all events are wiped and the structure is
2022-06-16 20:09:03 +03:00
re - initialised . This is most useful after a fork ( )
2010-03-26 13:13:27 +03:00
zero is returned on success , non - zero on failure
*/
int tevent_re_initialise ( struct tevent_context * ev )
{
tevent_common_context_destructor ( ev ) ;
2017-06-05 08:16:17 +03:00
tevent_common_context_constructor ( ev ) ;
2010-03-26 13:13:27 +03:00
return ev - > ops - > context_init ( ev ) ;
}
2016-07-29 09:53:59 +03:00
static void wakeup_pipe_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags , void * _private )
{
ssize_t ret ;
do {
2016-08-12 17:32:33 +03:00
/*
* This is the boilerplate for eventfd , but it works
* for pipes too . And as we don ' t care about the data
* we read , we ' re fine .
*/
uint64_t val ;
ret = read ( fde - > fd , & val , sizeof ( val ) ) ;
2016-07-29 09:53:59 +03:00
} while ( ret = = - 1 & & errno = = EINTR ) ;
}
/*
* Initialize the wakeup pipe and pipe fde
*/
int tevent_common_wakeup_init ( struct tevent_context * ev )
{
2016-09-07 20:17:21 +03:00
int ret , read_fd ;
2016-07-29 09:53:59 +03:00
2016-08-12 17:32:33 +03:00
if ( ev - > wakeup_fde ! = NULL ) {
2016-07-29 09:53:59 +03:00
return 0 ;
}
2016-08-12 17:32:33 +03:00
# ifdef HAVE_EVENTFD
ret = eventfd ( 0 , EFD_NONBLOCK ) ;
2016-07-29 09:53:59 +03:00
if ( ret = = - 1 ) {
return errno ;
}
2016-09-07 20:17:21 +03:00
read_fd = ev - > wakeup_fd = ret ;
2016-08-12 17:32:33 +03:00
# else
{
int pipe_fds [ 2 ] ;
ret = pipe ( pipe_fds ) ;
if ( ret = = - 1 ) {
return errno ;
}
2016-09-07 20:17:21 +03:00
ev - > wakeup_fd = pipe_fds [ 1 ] ;
ev - > wakeup_read_fd = pipe_fds [ 0 ] ;
2016-08-12 17:32:33 +03:00
ev_set_blocking ( ev - > wakeup_fd , false ) ;
2016-09-07 20:17:21 +03:00
ev_set_blocking ( ev - > wakeup_read_fd , false ) ;
read_fd = ev - > wakeup_read_fd ;
2016-08-12 17:32:33 +03:00
}
# endif
2016-07-29 09:53:59 +03:00
2016-09-07 20:17:21 +03:00
ev - > wakeup_fde = tevent_add_fd ( ev , ev , read_fd , TEVENT_FD_READ ,
2016-07-29 09:53:59 +03:00
wakeup_pipe_handler , NULL ) ;
2016-08-12 17:32:33 +03:00
if ( ev - > wakeup_fde = = NULL ) {
close ( ev - > wakeup_fd ) ;
# ifndef HAVE_EVENTFD
2016-09-07 20:17:21 +03:00
close ( ev - > wakeup_read_fd ) ;
2016-08-12 17:32:33 +03:00
# endif
2016-07-29 09:53:59 +03:00
return ENOMEM ;
}
return 0 ;
}
2016-09-07 20:47:55 +03:00
int tevent_common_wakeup_fd ( int fd )
2016-07-29 09:53:59 +03:00
{
ssize_t ret ;
do {
2016-08-12 17:32:33 +03:00
# ifdef HAVE_EVENTFD
uint64_t val = 1 ;
2016-09-07 20:47:55 +03:00
ret = write ( fd , & val , sizeof ( val ) ) ;
2016-08-12 17:32:33 +03:00
# else
2016-07-29 09:53:59 +03:00
char c = ' \0 ' ;
2016-09-07 20:47:55 +03:00
ret = write ( fd , & c , 1 ) ;
2016-08-12 17:32:33 +03:00
# endif
2016-07-29 09:53:59 +03:00
} while ( ( ret = = - 1 ) & & ( errno = = EINTR ) ) ;
return 0 ;
}
2016-08-12 17:00:56 +03:00
2016-09-07 20:47:55 +03:00
int tevent_common_wakeup ( struct tevent_context * ev )
{
if ( ev - > wakeup_fde = = NULL ) {
return ENOTCONN ;
}
return tevent_common_wakeup_fd ( ev - > wakeup_fd ) ;
}
2016-08-12 17:00:56 +03:00
static void tevent_common_wakeup_fini ( struct tevent_context * ev )
{
2016-08-12 17:32:33 +03:00
if ( ev - > wakeup_fde = = NULL ) {
2016-08-12 17:00:56 +03:00
return ;
}
2016-08-12 17:32:33 +03:00
TALLOC_FREE ( ev - > wakeup_fde ) ;
2016-08-12 17:00:56 +03:00
2016-08-12 17:32:33 +03:00
close ( ev - > wakeup_fd ) ;
# ifndef HAVE_EVENTFD
2016-09-07 20:17:21 +03:00
close ( ev - > wakeup_read_fd ) ;
2016-08-12 17:32:33 +03:00
# endif
2016-08-12 17:00:56 +03:00
}