2007-01-05 12:35:49 +03:00
/*
Unix SMB / CIFS implementation .
common events code for timed events
Copyright ( C ) Andrew Tridgell 2003 - 2006
Copyright ( C ) Stefan Metzmacher 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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2007-01-05 12:35:49 +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/>.
2007-01-05 12:35:49 +03:00
*/
2008-06-14 19:23:31 +04:00
# include <sys/time.h>
# include <time.h>
2008-04-25 01:28:30 +04:00
# include "replace.h"
2007-01-05 12:35:49 +03:00
# include "system/filesys.h"
# include "system/select.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
2008-06-14 19:23:31 +04:00
/**
compare two timeval structures .
Return - 1 if tv1 < tv2
Return 0 if tv1 = = tv2
Return 1 if tv1 > tv2
*/
static int ev_timeval_compare ( const struct timeval * tv1 , const struct timeval * tv2 )
{
if ( tv1 - > tv_sec > tv2 - > tv_sec ) return 1 ;
if ( tv1 - > tv_sec < tv2 - > tv_sec ) return - 1 ;
if ( tv1 - > tv_usec > tv2 - > tv_usec ) return 1 ;
if ( tv1 - > tv_usec < tv2 - > tv_usec ) return - 1 ;
return 0 ;
}
/**
return a zero timeval
*/
static struct timeval ev_timeval_zero ( void )
{
struct timeval tv ;
tv . tv_sec = 0 ;
tv . tv_usec = 0 ;
return tv ;
}
/**
return a timeval for the current time
*/
static struct timeval ev_timeval_current ( void )
{
struct timeval tv ;
gettimeofday ( & tv , NULL ) ;
return tv ;
}
/**
return a timeval struct with the given elements
*/
static struct timeval ev_timeval_set ( uint32_t secs , uint32_t usecs )
{
struct timeval tv ;
tv . tv_sec = secs ;
tv . tv_usec = usecs ;
return tv ;
}
/**
return the difference between two timevals as a timeval
if tv1 comes after tv2 , then return a zero timeval
( this is * tv2 - * tv1 )
*/
static struct timeval ev_timeval_until ( const struct timeval * tv1 ,
const struct timeval * tv2 )
{
struct timeval t ;
if ( ev_timeval_compare ( tv1 , tv2 ) > = 0 ) {
return ev_timeval_zero ( ) ;
}
t . tv_sec = tv2 - > tv_sec - tv1 - > tv_sec ;
if ( tv1 - > tv_usec > tv2 - > tv_usec ) {
t . tv_sec - - ;
t . tv_usec = 1000000 - ( tv1 - > tv_usec - tv2 - > tv_usec ) ;
} else {
t . tv_usec = tv2 - > tv_usec - tv1 - > tv_usec ;
}
return t ;
}
/**
return true if a timeval is zero
*/
bool ev_timeval_is_zero ( const struct timeval * tv )
{
return tv - > tv_sec = = 0 & & tv - > tv_usec = = 0 ;
}
2007-01-05 12:35:49 +03:00
/*
destroy a timed event
*/
static int common_event_timed_destructor ( struct timed_event * te )
{
2007-01-05 13:31:54 +03:00
struct event_context * ev = talloc_get_type ( te - > event_ctx ,
struct event_context ) ;
2008-12-24 15:52:57 +03:00
DLIST_REMOVE ( ev - > timer_events , te ) ;
2007-01-05 12:35:49 +03:00
return 0 ;
}
static int common_event_timed_deny_destructor ( struct timed_event * te )
{
return - 1 ;
}
/*
add a timed event
return NULL on failure ( memory allocation error )
*/
struct timed_event * common_event_add_timed ( struct event_context * ev , TALLOC_CTX * mem_ctx ,
struct timeval next_event ,
event_timed_handler_t handler ,
void * private_data )
{
struct timed_event * te , * last_te , * cur_te ;
te = talloc ( mem_ctx ? mem_ctx : ev , struct timed_event ) ;
if ( te = = NULL ) return NULL ;
te - > event_ctx = ev ;
te - > next_event = next_event ;
te - > handler = handler ;
te - > private_data = private_data ;
te - > additional_data = NULL ;
/* keep the list ordered */
last_te = NULL ;
2008-12-24 15:52:57 +03:00
for ( cur_te = ev - > timer_events ; cur_te ; cur_te = cur_te - > next ) {
2007-01-05 12:35:49 +03:00
/* if the new event comes before the current one break */
2008-06-14 19:23:31 +04:00
if ( ev_timeval_compare ( & te - > next_event , & cur_te - > next_event ) < 0 ) {
2007-01-05 12:35:49 +03:00
break ;
}
last_te = cur_te ;
}
2008-12-24 15:52:57 +03:00
DLIST_ADD_AFTER ( ev - > timer_events , te , last_te ) ;
2007-01-05 12:35:49 +03:00
talloc_set_destructor ( te , common_event_timed_destructor ) ;
return te ;
}
/*
r22661: optimize the handling of directly triggered timed events:
- if someone adds a timed_event with a zero timeval
we now avoid serval gettimeofday() calls and the
event handler doesn't get the current time when it's
called, instead we also pass a zero timeval
- this also makes sure multiple timed events with a zero timeval
are processed in the order there're added.
the little benchmark shows that processing 2000000 directly timed events
is now much faster, while avoiding syscalls at all!
> time ./evtest (with the old code)
real 0m6.388s
user 0m1.740s
sys 0m4.632s
> time ./evtest (with the new code)
real 0m1.498s
user 0m1.496s
sys 0m0.004s
metze@SERNOX:~/devel/samba/4.0/samba4-ci/source> cat evtest.c
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <talloc.h>
#include <events.h>
static void dummy_fde_handler(struct event_context *ev_ctx, struct fd_event *fde,
uint16_t flags, void *private_data)
{
}
static void timeout_handler(struct event_context *ev, struct timed_event *te,
struct timeval tval, void *private_data)
{
uint32_t *countp = (uint32_t *)private_data;
(*countp)++;
if (*countp > 2000000) exit(0);
event_add_timed(ev, ev, tval, timeout_handler, countp);
}
int main(void)
{
struct event_context *ev;
struct timeval tval = { 0, 0 };
uint32_t count = 0;
ev = event_context_init(NULL);
event_add_fd(ev, ev, 0, 0, dummy_fde_handler, NULL);
event_add_timed(ev, ev, tval, timeout_handler, &count);
return event_loop_wait(ev);
}
(This used to be commit 4db64b4ce2320b88d648078cbf86385f6fb44f1f)
2007-05-04 13:22:52 +04:00
do a single event loop using the events defined in ev
return the delay untill the next timed event ,
or zero if a timed event was triggered
2007-01-05 12:35:49 +03:00
*/
r22661: optimize the handling of directly triggered timed events:
- if someone adds a timed_event with a zero timeval
we now avoid serval gettimeofday() calls and the
event handler doesn't get the current time when it's
called, instead we also pass a zero timeval
- this also makes sure multiple timed events with a zero timeval
are processed in the order there're added.
the little benchmark shows that processing 2000000 directly timed events
is now much faster, while avoiding syscalls at all!
> time ./evtest (with the old code)
real 0m6.388s
user 0m1.740s
sys 0m4.632s
> time ./evtest (with the new code)
real 0m1.498s
user 0m1.496s
sys 0m0.004s
metze@SERNOX:~/devel/samba/4.0/samba4-ci/source> cat evtest.c
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <talloc.h>
#include <events.h>
static void dummy_fde_handler(struct event_context *ev_ctx, struct fd_event *fde,
uint16_t flags, void *private_data)
{
}
static void timeout_handler(struct event_context *ev, struct timed_event *te,
struct timeval tval, void *private_data)
{
uint32_t *countp = (uint32_t *)private_data;
(*countp)++;
if (*countp > 2000000) exit(0);
event_add_timed(ev, ev, tval, timeout_handler, countp);
}
int main(void)
{
struct event_context *ev;
struct timeval tval = { 0, 0 };
uint32_t count = 0;
ev = event_context_init(NULL);
event_add_fd(ev, ev, 0, 0, dummy_fde_handler, NULL);
event_add_timed(ev, ev, tval, timeout_handler, &count);
return event_loop_wait(ev);
}
(This used to be commit 4db64b4ce2320b88d648078cbf86385f6fb44f1f)
2007-05-04 13:22:52 +04:00
struct timeval common_event_loop_timer_delay ( struct event_context * ev )
2007-01-05 12:35:49 +03:00
{
2008-06-14 19:23:31 +04:00
struct timeval current_time = ev_timeval_zero ( ) ;
2008-12-24 15:52:57 +03:00
struct timed_event * te = ev - > timer_events ;
2007-01-05 12:35:49 +03:00
r22661: optimize the handling of directly triggered timed events:
- if someone adds a timed_event with a zero timeval
we now avoid serval gettimeofday() calls and the
event handler doesn't get the current time when it's
called, instead we also pass a zero timeval
- this also makes sure multiple timed events with a zero timeval
are processed in the order there're added.
the little benchmark shows that processing 2000000 directly timed events
is now much faster, while avoiding syscalls at all!
> time ./evtest (with the old code)
real 0m6.388s
user 0m1.740s
sys 0m4.632s
> time ./evtest (with the new code)
real 0m1.498s
user 0m1.496s
sys 0m0.004s
metze@SERNOX:~/devel/samba/4.0/samba4-ci/source> cat evtest.c
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <talloc.h>
#include <events.h>
static void dummy_fde_handler(struct event_context *ev_ctx, struct fd_event *fde,
uint16_t flags, void *private_data)
{
}
static void timeout_handler(struct event_context *ev, struct timed_event *te,
struct timeval tval, void *private_data)
{
uint32_t *countp = (uint32_t *)private_data;
(*countp)++;
if (*countp > 2000000) exit(0);
event_add_timed(ev, ev, tval, timeout_handler, countp);
}
int main(void)
{
struct event_context *ev;
struct timeval tval = { 0, 0 };
uint32_t count = 0;
ev = event_context_init(NULL);
event_add_fd(ev, ev, 0, 0, dummy_fde_handler, NULL);
event_add_timed(ev, ev, tval, timeout_handler, &count);
return event_loop_wait(ev);
}
(This used to be commit 4db64b4ce2320b88d648078cbf86385f6fb44f1f)
2007-05-04 13:22:52 +04:00
if ( ! te ) {
/* have a default tick time of 30 seconds. This guarantees
that code that uses its own timeout checking will be
able to proceeed eventually */
2008-06-14 19:23:31 +04:00
return ev_timeval_set ( 30 , 0 ) ;
2007-01-05 12:35:49 +03:00
}
r22661: optimize the handling of directly triggered timed events:
- if someone adds a timed_event with a zero timeval
we now avoid serval gettimeofday() calls and the
event handler doesn't get the current time when it's
called, instead we also pass a zero timeval
- this also makes sure multiple timed events with a zero timeval
are processed in the order there're added.
the little benchmark shows that processing 2000000 directly timed events
is now much faster, while avoiding syscalls at all!
> time ./evtest (with the old code)
real 0m6.388s
user 0m1.740s
sys 0m4.632s
> time ./evtest (with the new code)
real 0m1.498s
user 0m1.496s
sys 0m0.004s
metze@SERNOX:~/devel/samba/4.0/samba4-ci/source> cat evtest.c
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <talloc.h>
#include <events.h>
static void dummy_fde_handler(struct event_context *ev_ctx, struct fd_event *fde,
uint16_t flags, void *private_data)
{
}
static void timeout_handler(struct event_context *ev, struct timed_event *te,
struct timeval tval, void *private_data)
{
uint32_t *countp = (uint32_t *)private_data;
(*countp)++;
if (*countp > 2000000) exit(0);
event_add_timed(ev, ev, tval, timeout_handler, countp);
}
int main(void)
{
struct event_context *ev;
struct timeval tval = { 0, 0 };
uint32_t count = 0;
ev = event_context_init(NULL);
event_add_fd(ev, ev, 0, 0, dummy_fde_handler, NULL);
event_add_timed(ev, ev, tval, timeout_handler, &count);
return event_loop_wait(ev);
}
(This used to be commit 4db64b4ce2320b88d648078cbf86385f6fb44f1f)
2007-05-04 13:22:52 +04:00
/*
* work out the right timeout for the next timed event
*
* avoid the syscall to gettimeofday ( ) if the timed event should
* be triggered directly
*
* if there ' s a delay till the next timed event , we ' re done
* with just returning the delay
*/
2008-06-14 19:23:31 +04:00
if ( ! ev_timeval_is_zero ( & te - > next_event ) ) {
r22661: optimize the handling of directly triggered timed events:
- if someone adds a timed_event with a zero timeval
we now avoid serval gettimeofday() calls and the
event handler doesn't get the current time when it's
called, instead we also pass a zero timeval
- this also makes sure multiple timed events with a zero timeval
are processed in the order there're added.
the little benchmark shows that processing 2000000 directly timed events
is now much faster, while avoiding syscalls at all!
> time ./evtest (with the old code)
real 0m6.388s
user 0m1.740s
sys 0m4.632s
> time ./evtest (with the new code)
real 0m1.498s
user 0m1.496s
sys 0m0.004s
metze@SERNOX:~/devel/samba/4.0/samba4-ci/source> cat evtest.c
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <talloc.h>
#include <events.h>
static void dummy_fde_handler(struct event_context *ev_ctx, struct fd_event *fde,
uint16_t flags, void *private_data)
{
}
static void timeout_handler(struct event_context *ev, struct timed_event *te,
struct timeval tval, void *private_data)
{
uint32_t *countp = (uint32_t *)private_data;
(*countp)++;
if (*countp > 2000000) exit(0);
event_add_timed(ev, ev, tval, timeout_handler, countp);
}
int main(void)
{
struct event_context *ev;
struct timeval tval = { 0, 0 };
uint32_t count = 0;
ev = event_context_init(NULL);
event_add_fd(ev, ev, 0, 0, dummy_fde_handler, NULL);
event_add_timed(ev, ev, tval, timeout_handler, &count);
return event_loop_wait(ev);
}
(This used to be commit 4db64b4ce2320b88d648078cbf86385f6fb44f1f)
2007-05-04 13:22:52 +04:00
struct timeval delay ;
2008-06-14 19:23:31 +04:00
current_time = ev_timeval_current ( ) ;
r22661: optimize the handling of directly triggered timed events:
- if someone adds a timed_event with a zero timeval
we now avoid serval gettimeofday() calls and the
event handler doesn't get the current time when it's
called, instead we also pass a zero timeval
- this also makes sure multiple timed events with a zero timeval
are processed in the order there're added.
the little benchmark shows that processing 2000000 directly timed events
is now much faster, while avoiding syscalls at all!
> time ./evtest (with the old code)
real 0m6.388s
user 0m1.740s
sys 0m4.632s
> time ./evtest (with the new code)
real 0m1.498s
user 0m1.496s
sys 0m0.004s
metze@SERNOX:~/devel/samba/4.0/samba4-ci/source> cat evtest.c
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <talloc.h>
#include <events.h>
static void dummy_fde_handler(struct event_context *ev_ctx, struct fd_event *fde,
uint16_t flags, void *private_data)
{
}
static void timeout_handler(struct event_context *ev, struct timed_event *te,
struct timeval tval, void *private_data)
{
uint32_t *countp = (uint32_t *)private_data;
(*countp)++;
if (*countp > 2000000) exit(0);
event_add_timed(ev, ev, tval, timeout_handler, countp);
}
int main(void)
{
struct event_context *ev;
struct timeval tval = { 0, 0 };
uint32_t count = 0;
ev = event_context_init(NULL);
event_add_fd(ev, ev, 0, 0, dummy_fde_handler, NULL);
event_add_timed(ev, ev, tval, timeout_handler, &count);
return event_loop_wait(ev);
}
(This used to be commit 4db64b4ce2320b88d648078cbf86385f6fb44f1f)
2007-05-04 13:22:52 +04:00
2008-06-14 19:23:31 +04:00
delay = ev_timeval_until ( & current_time , & te - > next_event ) ;
if ( ! ev_timeval_is_zero ( & delay ) ) {
r22661: optimize the handling of directly triggered timed events:
- if someone adds a timed_event with a zero timeval
we now avoid serval gettimeofday() calls and the
event handler doesn't get the current time when it's
called, instead we also pass a zero timeval
- this also makes sure multiple timed events with a zero timeval
are processed in the order there're added.
the little benchmark shows that processing 2000000 directly timed events
is now much faster, while avoiding syscalls at all!
> time ./evtest (with the old code)
real 0m6.388s
user 0m1.740s
sys 0m4.632s
> time ./evtest (with the new code)
real 0m1.498s
user 0m1.496s
sys 0m0.004s
metze@SERNOX:~/devel/samba/4.0/samba4-ci/source> cat evtest.c
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <talloc.h>
#include <events.h>
static void dummy_fde_handler(struct event_context *ev_ctx, struct fd_event *fde,
uint16_t flags, void *private_data)
{
}
static void timeout_handler(struct event_context *ev, struct timed_event *te,
struct timeval tval, void *private_data)
{
uint32_t *countp = (uint32_t *)private_data;
(*countp)++;
if (*countp > 2000000) exit(0);
event_add_timed(ev, ev, tval, timeout_handler, countp);
}
int main(void)
{
struct event_context *ev;
struct timeval tval = { 0, 0 };
uint32_t count = 0;
ev = event_context_init(NULL);
event_add_fd(ev, ev, 0, 0, dummy_fde_handler, NULL);
event_add_timed(ev, ev, tval, timeout_handler, &count);
return event_loop_wait(ev);
}
(This used to be commit 4db64b4ce2320b88d648078cbf86385f6fb44f1f)
2007-05-04 13:22:52 +04:00
return delay ;
}
}
/*
* ok , we have a timed event that we ' ll process . . .
*/
2007-01-05 12:35:49 +03:00
/* deny the handler to free the event */
talloc_set_destructor ( te , common_event_timed_deny_destructor ) ;
/* 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 */
2008-12-24 15:52:57 +03:00
DLIST_REMOVE ( ev - > timer_events , te ) ;
2007-01-05 12:35:49 +03:00
r22661: optimize the handling of directly triggered timed events:
- if someone adds a timed_event with a zero timeval
we now avoid serval gettimeofday() calls and the
event handler doesn't get the current time when it's
called, instead we also pass a zero timeval
- this also makes sure multiple timed events with a zero timeval
are processed in the order there're added.
the little benchmark shows that processing 2000000 directly timed events
is now much faster, while avoiding syscalls at all!
> time ./evtest (with the old code)
real 0m6.388s
user 0m1.740s
sys 0m4.632s
> time ./evtest (with the new code)
real 0m1.498s
user 0m1.496s
sys 0m0.004s
metze@SERNOX:~/devel/samba/4.0/samba4-ci/source> cat evtest.c
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <talloc.h>
#include <events.h>
static void dummy_fde_handler(struct event_context *ev_ctx, struct fd_event *fde,
uint16_t flags, void *private_data)
{
}
static void timeout_handler(struct event_context *ev, struct timed_event *te,
struct timeval tval, void *private_data)
{
uint32_t *countp = (uint32_t *)private_data;
(*countp)++;
if (*countp > 2000000) exit(0);
event_add_timed(ev, ev, tval, timeout_handler, countp);
}
int main(void)
{
struct event_context *ev;
struct timeval tval = { 0, 0 };
uint32_t count = 0;
ev = event_context_init(NULL);
event_add_fd(ev, ev, 0, 0, dummy_fde_handler, NULL);
event_add_timed(ev, ev, tval, timeout_handler, &count);
return event_loop_wait(ev);
}
(This used to be commit 4db64b4ce2320b88d648078cbf86385f6fb44f1f)
2007-05-04 13:22:52 +04:00
/*
* If the timed event was registered for a zero current_time ,
* then we pass a zero timeval here too ! To avoid the
* overhead of gettimeofday ( ) calls .
*
* otherwise we pass the current time
*/
te - > handler ( ev , te , current_time , te - > private_data ) ;
2007-01-05 12:35:49 +03:00
/* The destructor isn't necessary anymore, we've already removed the
* event from the list . */
talloc_set_destructor ( te , NULL ) ;
talloc_free ( te ) ;
2008-06-14 19:23:31 +04:00
return ev_timeval_zero ( ) ;
2007-01-05 12:35:49 +03:00
}