2006-02-04 01:19:41 +03:00
/*
Unix SMB / CIFS implementation .
Timed event library .
Copyright ( C ) Andrew Tridgell 1992 - 1998
Copyright ( C ) Volker Lendecke 2005
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-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-02-04 01:19:41 +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 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-02-04 01:19:41 +03:00
*/
# include "includes.h"
2007-01-17 15:59:14 +03:00
struct timed_event {
struct timed_event * next , * prev ;
struct event_context * event_ctx ;
struct timeval when ;
const char * event_name ;
void ( * handler ) ( struct event_context * event_ctx ,
struct timed_event * te ,
const struct timeval * now ,
void * private_data ) ;
void * private_data ;
} ;
struct fd_event {
struct fd_event * prev , * next ;
struct event_context * event_ctx ;
int fd ;
uint16_t flags ; /* see EVENT_FD_* flags */
void ( * handler ) ( struct event_context * event_ctx ,
struct fd_event * event ,
uint16 flags ,
void * private_data ) ;
void * private_data ;
} ;
# define EVENT_FD_WRITEABLE(fde) \
event_set_fd_flags ( fde , event_get_fd_flags ( fde ) | EVENT_FD_WRITE )
# define EVENT_FD_READABLE(fde) \
event_set_fd_flags ( fde , event_get_fd_flags ( fde ) | EVENT_FD_READ )
# define EVENT_FD_NOT_WRITEABLE(fde) \
event_set_fd_flags ( fde , event_get_fd_flags ( fde ) & ~ EVENT_FD_WRITE )
# define EVENT_FD_NOT_READABLE(fde) \
event_set_fd_flags ( fde , event_get_fd_flags ( fde ) & ~ EVENT_FD_READ )
struct event_context {
struct timed_event * timed_events ;
struct fd_event * fd_events ;
} ;
2006-02-04 01:19:41 +03:00
2006-08-29 23:14:25 +04:00
static int timed_event_destructor ( struct timed_event * te )
2006-02-04 01:19:41 +03:00
{
DEBUG ( 10 , ( " Destroying timed event %lx \" %s \" \n " , ( unsigned long ) te ,
te - > event_name ) ) ;
2007-01-17 15:59:14 +03:00
DLIST_REMOVE ( te - > event_ctx - > timed_events , te ) ;
2006-02-04 01:19:41 +03:00
return 0 ;
}
2007-01-19 22:41:34 +03:00
/****************************************************************************
Add te by time .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void add_event_by_time ( struct timed_event * te )
{
2007-01-19 23:00:44 +03:00
struct event_context * ctx = te - > event_ctx ;
2007-01-19 22:41:34 +03:00
struct timed_event * last_te , * cur_te ;
/* Keep the list ordered by time. We must preserve this. */
last_te = NULL ;
2007-01-19 23:00:44 +03:00
for ( cur_te = ctx - > timed_events ; cur_te ; cur_te = cur_te - > next ) {
2007-01-19 22:41:34 +03:00
/* if the new event comes before the current one break */
if ( ! timeval_is_zero ( & cur_te - > when ) & &
timeval_compare ( & te - > when , & cur_te - > when ) < 0 ) {
break ;
}
last_te = cur_te ;
}
2007-01-19 23:00:44 +03:00
DLIST_ADD_AFTER ( ctx - > timed_events , te , last_te ) ;
2007-01-19 22:41:34 +03:00
}
2006-02-04 01:19:41 +03:00
/****************************************************************************
2006-02-20 20:59:58 +03:00
Schedule a function for future calling , cancel with TALLOC_FREE ( ) .
It ' s the responsibility of the handler to call TALLOC_FREE ( ) on the event
2006-02-04 01:19:41 +03:00
handed to it .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-01-17 15:59:14 +03:00
struct timed_event * event_add_timed ( struct event_context * event_ctx ,
2007-01-19 22:41:34 +03:00
TALLOC_CTX * mem_ctx ,
2006-02-04 01:19:41 +03:00
struct timeval when ,
const char * event_name ,
2007-01-17 15:59:14 +03:00
void ( * handler ) ( struct event_context * event_ctx ,
struct timed_event * te ,
2006-02-04 01:19:41 +03:00
const struct timeval * now ,
void * private_data ) ,
void * private_data )
{
2007-01-19 22:41:34 +03:00
struct timed_event * te ;
2006-02-04 01:19:41 +03:00
te = TALLOC_P ( mem_ctx , struct timed_event ) ;
if ( te = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
return NULL ;
}
2007-01-17 15:59:14 +03:00
te - > event_ctx = event_ctx ;
2006-02-04 01:19:41 +03:00
te - > when = when ;
te - > event_name = event_name ;
te - > handler = handler ;
te - > private_data = private_data ;
2007-01-19 22:41:34 +03:00
add_event_by_time ( te ) ;
2006-02-04 01:19:41 +03:00
talloc_set_destructor ( te , timed_event_destructor ) ;
DEBUG ( 10 , ( " Added timed event \" %s \" : %lx \n " , event_name ,
( unsigned long ) te ) ) ;
return te ;
}
2007-01-17 15:59:14 +03:00
static int fd_event_destructor ( struct fd_event * fde )
{
struct event_context * event_ctx = fde - > event_ctx ;
DLIST_REMOVE ( event_ctx - > fd_events , fde ) ;
return 0 ;
}
struct fd_event * event_add_fd ( struct event_context * event_ctx ,
TALLOC_CTX * mem_ctx ,
int fd , uint16_t flags ,
void ( * handler ) ( struct event_context * event_ctx ,
struct fd_event * event ,
uint16 flags ,
void * private_data ) ,
void * private_data )
{
struct fd_event * fde ;
if ( ! ( fde = TALLOC_P ( mem_ctx , struct fd_event ) ) ) {
return NULL ;
}
fde - > event_ctx = event_ctx ;
fde - > fd = fd ;
fde - > flags = flags ;
fde - > handler = handler ;
fde - > private_data = private_data ;
DLIST_ADD ( event_ctx - > fd_events , fde ) ;
talloc_set_destructor ( fde , fd_event_destructor ) ;
return fde ;
}
void event_fd_set_writeable ( struct fd_event * fde )
{
fde - > flags | = EVENT_FD_WRITE ;
}
void event_fd_set_not_writeable ( struct fd_event * fde )
{
fde - > flags & = ~ EVENT_FD_WRITE ;
}
void event_fd_set_readable ( struct fd_event * fde )
{
fde - > flags | = EVENT_FD_READ ;
}
void event_fd_set_not_readable ( struct fd_event * fde )
{
fde - > flags & = ~ EVENT_FD_READ ;
}
2007-05-16 17:02:53 +04:00
/*
* Return if there ' s something in the queue
*/
2007-10-19 04:40:25 +04:00
bool event_add_to_select_args ( struct event_context * event_ctx ,
2007-01-17 15:59:14 +03:00
const struct timeval * now ,
fd_set * read_fds , fd_set * write_fds ,
struct timeval * timeout , int * maxfd )
2006-02-04 01:19:41 +03:00
{
2007-01-17 15:59:14 +03:00
struct fd_event * fde ;
struct timeval diff ;
2007-10-19 04:40:25 +04:00
bool ret = False ;
2007-01-17 15:59:14 +03:00
for ( fde = event_ctx - > fd_events ; fde ; fde = fde - > next ) {
if ( fde - > flags & EVENT_FD_READ ) {
FD_SET ( fde - > fd , read_fds ) ;
2007-05-16 17:02:53 +04:00
ret = True ;
2007-01-17 15:59:14 +03:00
}
if ( fde - > flags & EVENT_FD_WRITE ) {
FD_SET ( fde - > fd , write_fds ) ;
2007-05-16 17:02:53 +04:00
ret = True ;
2007-01-17 15:59:14 +03:00
}
if ( ( fde - > flags & ( EVENT_FD_READ | EVENT_FD_WRITE ) )
& & ( fde - > fd > * maxfd ) ) {
* maxfd = fde - > fd ;
}
}
if ( event_ctx - > timed_events = = NULL ) {
2007-05-16 17:02:53 +04:00
return ret ;
2007-01-17 15:59:14 +03:00
}
diff = timeval_until ( now , & event_ctx - > timed_events - > when ) ;
* timeout = timeval_min ( timeout , & diff ) ;
2007-05-16 17:02:53 +04:00
return True ;
2007-01-17 15:59:14 +03:00
}
2007-10-19 04:40:25 +04:00
bool events_pending ( struct event_context * event_ctx )
2007-05-20 01:53:28 +04:00
{
struct fd_event * fde ;
if ( event_ctx - > timed_events ! = NULL ) {
return True ;
}
for ( fde = event_ctx - > fd_events ; fde ; fde = fde - > next ) {
if ( fde - > flags & ( EVENT_FD_READ | EVENT_FD_WRITE ) ) {
return True ;
}
}
return False ;
}
2007-10-19 04:40:25 +04:00
bool run_events ( struct event_context * event_ctx ,
2007-01-17 15:59:14 +03:00
int selrtn , fd_set * read_fds , fd_set * write_fds )
{
2007-10-19 04:40:25 +04:00
bool fired = False ;
2007-01-17 15:59:14 +03:00
struct fd_event * fde , * next ;
2006-09-07 01:43:31 +04:00
/* Run all events that are pending, not just one (as we
did previously . */
2006-02-04 01:19:41 +03:00
2007-01-17 15:59:14 +03:00
while ( event_ctx - > timed_events ) {
2006-09-07 01:43:31 +04:00
struct timeval now ;
GetTimeOfDay ( & now ) ;
2006-02-04 01:19:41 +03:00
2007-01-17 15:59:14 +03:00
if ( timeval_compare (
& now , & event_ctx - > timed_events - > when ) < 0 ) {
2006-09-07 01:43:31 +04:00
/* Nothing to do yet */
DEBUG ( 11 , ( " run_events: Nothing to do \n " ) ) ;
2007-01-17 15:59:14 +03:00
break ;
2006-09-07 01:43:31 +04:00
}
2006-02-04 01:19:41 +03:00
2007-01-17 15:59:14 +03:00
DEBUG ( 10 , ( " Running event \" %s \" %lx \n " ,
event_ctx - > timed_events - > event_name ,
( unsigned long ) event_ctx - > timed_events ) ) ;
event_ctx - > timed_events - > handler (
event_ctx ,
event_ctx - > timed_events , & now ,
event_ctx - > timed_events - > private_data ) ;
2006-02-04 01:19:41 +03:00
2007-01-17 15:59:14 +03:00
fired = True ;
2006-09-07 01:43:31 +04:00
}
2007-01-17 15:59:14 +03:00
if ( fired ) {
/*
* We might have changed the socket status during the timed
* events , return to run select again .
*/
return True ;
}
if ( selrtn = = 0 ) {
/*
* No fd ready
*/
return fired ;
}
for ( fde = event_ctx - > fd_events ; fde ; fde = next ) {
uint16 flags = 0 ;
next = fde - > next ;
if ( FD_ISSET ( fde - > fd , read_fds ) ) flags | = EVENT_FD_READ ;
if ( FD_ISSET ( fde - > fd , write_fds ) ) flags | = EVENT_FD_WRITE ;
2008-04-01 17:29:59 +04:00
if ( flags & fde - > flags ) {
2007-01-17 15:59:14 +03:00
fde - > handler ( event_ctx , fde , flags , fde - > private_data ) ;
fired = True ;
}
}
return fired ;
2006-02-04 01:19:41 +03:00
}
2007-01-17 15:59:14 +03:00
struct timeval * get_timed_events_timeout ( struct event_context * event_ctx ,
struct timeval * to_ret )
2006-02-04 01:19:41 +03:00
{
struct timeval now ;
2007-01-17 15:59:14 +03:00
if ( event_ctx - > timed_events = = NULL ) {
2006-04-14 07:55:42 +04:00
return NULL ;
2006-02-04 01:19:41 +03:00
}
now = timeval_current ( ) ;
2007-01-17 15:59:14 +03:00
* to_ret = timeval_until ( & now , & event_ctx - > timed_events - > when ) ;
2006-02-04 01:19:41 +03:00
DEBUG ( 10 , ( " timed_events_timeout: %d/%d \n " , ( int ) to_ret - > tv_sec ,
( int ) to_ret - > tv_usec ) ) ;
return to_ret ;
}
2006-09-13 17:55:19 +04:00
2007-05-16 17:02:53 +04:00
int event_loop_once ( struct event_context * ev )
{
struct timeval now , to ;
fd_set r_fds , w_fds ;
int maxfd = 0 ;
int ret ;
FD_ZERO ( & r_fds ) ;
FD_ZERO ( & w_fds ) ;
to . tv_sec = 9999 ; /* Max timeout */
to . tv_usec = 0 ;
GetTimeOfDay ( & now ) ;
if ( ! event_add_to_select_args ( ev , & now , & r_fds , & w_fds , & to , & maxfd ) ) {
return - 1 ;
}
if ( timeval_is_zero ( & to ) ) {
run_events ( ev , 0 , NULL , NULL ) ;
return 0 ;
}
ret = sys_select ( maxfd , & r_fds , & w_fds , NULL , & to ) ;
if ( ret = = - 1 & & errno ! = EINTR ) {
return - 1 ;
}
run_events ( ev , ret , & r_fds , & w_fds ) ;
return 0 ;
}
2007-01-17 15:59:14 +03:00
struct event_context * event_context_init ( TALLOC_CTX * mem_ctx )
{
return TALLOC_ZERO_P ( NULL , struct event_context ) ;
}
int set_event_dispatch_time ( struct event_context * event_ctx ,
const char * event_name , struct timeval when )
2006-09-13 17:55:19 +04:00
{
struct timed_event * te ;
2007-01-17 15:59:14 +03:00
for ( te = event_ctx - > timed_events ; te ; te = te - > next ) {
2006-09-13 17:55:19 +04:00
if ( strcmp ( event_name , te - > event_name ) = = 0 ) {
2007-01-19 23:00:44 +03:00
DLIST_REMOVE ( event_ctx - > timed_events , te ) ;
2006-09-13 17:55:19 +04:00
te - > when = when ;
2007-01-19 22:41:34 +03:00
add_event_by_time ( te ) ;
return 1 ;
2006-09-13 17:55:19 +04:00
}
}
2007-01-19 22:41:34 +03:00
return 0 ;
2006-09-13 17:55:19 +04:00
}
2006-12-08 21:40:13 +03:00
/* Returns 1 if event was found and cancelled, 0 otherwise. */
2007-01-17 15:59:14 +03:00
int cancel_named_event ( struct event_context * event_ctx ,
const char * event_name )
2006-12-08 21:40:13 +03:00
{
struct timed_event * te ;
2007-01-17 15:59:14 +03:00
for ( te = event_ctx - > timed_events ; te ; te = te - > next ) {
2006-12-08 21:40:13 +03:00
if ( strcmp ( event_name , te - > event_name ) = = 0 ) {
TALLOC_FREE ( te ) ;
return 1 ;
}
}
return 0 ;
}
2007-06-21 17:03:27 +04:00
void dump_event_list ( struct event_context * event_ctx )
{
struct timed_event * te ;
2007-06-21 19:12:51 +04:00
struct fd_event * fe ;
2007-06-21 17:03:27 +04:00
struct timeval evt , now ;
if ( ! event_ctx ) {
return ;
}
now = timeval_current ( ) ;
DEBUG ( 10 , ( " dump_event_list: \n " ) ) ;
for ( te = event_ctx - > timed_events ; te ; te = te - > next ) {
evt = timeval_until ( & now , & te - > when ) ;
2007-09-20 15:02:27 +04:00
DEBUGADD ( 10 , ( " Timed Event \" %s \" %lx handled in %d seconds (at %s) \n " ,
2007-06-21 17:03:27 +04:00
te - > event_name ,
( unsigned long ) te ,
2007-09-20 15:02:27 +04:00
( int ) evt . tv_sec ,
http_timestring ( te - > when . tv_sec ) ) ) ;
2007-06-21 17:03:27 +04:00
}
2007-06-21 19:12:51 +04:00
for ( fe = event_ctx - > fd_events ; fe ; fe = fe - > next ) {
DEBUGADD ( 10 , ( " FD Event %d %lx, flags: 0x%04x \n " ,
fe - > fd ,
( unsigned long ) fe ,
fe - > flags ) ) ;
}
2007-06-21 17:03:27 +04:00
}