From: Volker Lendecke Date: Mon, 10 Mar 2025 20:12:28 +0000 (+0100) Subject: tevent: Add tevent_context_set_wait_timeout() X-Git-Tag: tevent-0.17.0~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d23142643bf7f1d13b1f2996a68b131675eeac16;p=thirdparty%2Fsamba.git tevent: Add tevent_context_set_wait_timeout() Mainly to make tevent_loop_once() return immediately with -1/errno=EAGAIN for polling behaviour. Note the tevent-0.16.2.sigs changes will be reverted in the 'tevent 0.17.0' commit. Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Volker Lendecke Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke --- diff --git a/lib/tevent/ABI/tevent-0.16.2.sigs b/lib/tevent/ABI/tevent-0.16.2.sigs index f7eba5775df..4b129912b6f 100644 --- a/lib/tevent/ABI/tevent-0.16.2.sigs +++ b/lib/tevent/ABI/tevent-0.16.2.sigs @@ -61,6 +61,7 @@ tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *) tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *) tevent_context_is_wrapper: bool (struct tevent_context *) tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *) +tevent_context_set_wait_timeout: uint32_t (struct tevent_context *, uint32_t) tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...) tevent_fd_get_flags: uint16_t (struct tevent_fd *) tevent_fd_get_tag: uint64_t (const struct tevent_fd *) diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c index 9f4a91953ae..c3e688510e1 100644 --- a/lib/tevent/tevent.c +++ b/lib/tevent/tevent.c @@ -544,6 +544,13 @@ struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx, ev->ops = ops; ev->additional_data = additional_data; + /* + * have a default tick time of 30 seconds. This guarantees + * that code that uses its own timeout checking will be + * able to proceed eventually + */ + tevent_context_set_wait_timeout(ev, 30); + ret = ev->ops->context_init(ev); if (ret != 0) { talloc_free(ev); @@ -582,6 +589,31 @@ struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx) return tevent_context_init_byname(mem_ctx, NULL); } +uint32_t tevent_context_set_wait_timeout(struct tevent_context *ev, + uint32_t secs) +{ + time_t ret = ev->wait_timeout.tv_sec; + + /* + * Cut to signed 32-bit time_t. This is the maximum that we + * can reasonably expect to fit into time_t. Use that as magic + * value for "wait forever". Nobody wants to wait 68 years.... + */ + secs = MIN(secs, INT32_MAX); + + /* + * "secs == 0" and thus wait_timeout==tevent_timeval_zero() + * might have a special meaning for custom tevent loop_once + * backend functions. Make this an invalid value, our + * internal poll and epoll backends deal with this properly, + * see tevent_common_no_timeout() + */ + ev->wait_timeout = tevent_timeval_set((time_t)secs, + (secs == 0) ? INT32_MAX: 0); + + return ret; +} + /* add a fd based event return NULL on failure (memory allocation error) diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h index 0f40b2bed30..b94504981b9 100644 --- a/lib/tevent/tevent.h +++ b/lib/tevent/tevent.h @@ -174,6 +174,25 @@ const char **tevent_backend_list(TALLOC_CTX *mem_ctx); */ void tevent_set_default_backend(const char *backend); +/** + * @brief Set the default time to wait without tevent_timers pending + * + * Setting the wait timeout to 0 means polling behaviour, e.g. + * tevent_loop_once will return -1/errno=EAGAIN, when all + * currently available events were processes. + * + * Setting it to UINT32_MAX makes tevent_loop_once wait forever. + * The default is 30 seconds. + * + * @param[in] ev The tevent context to set this on + * + * @param[in] secs The number of seconds to wait without timers + * + * @return secs The previous wait_timeout value + */ +uint32_t tevent_context_set_wait_timeout(struct tevent_context *ev, + uint32_t secs); + #ifdef DOXYGEN /** * @brief Add a file descriptor based event. diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c index 233533e4d31..d13641ec347 100644 --- a/lib/tevent/tevent_epoll.c +++ b/lib/tevent/tevent_epoll.c @@ -590,14 +590,9 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval int ret, i; #define MAXEVENTS 1 struct epoll_event events[MAXEVENTS]; - int timeout = -1; + int timeout = tevent_common_timeout_msec(tvalp); int wait_errno; - if (tvalp) { - /* it's better to trigger timed events a bit later than too early */ - timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000); - } - if (epoll_ev->ev->signal_events && tevent_common_check_signal(epoll_ev->ev)) { return 0; @@ -620,6 +615,14 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval } if (ret == 0 && tvalp) { + /* + * tevent_context_set_wait_timeout(0) was used. + */ + if (tevent_common_no_timeout(tvalp)) { + errno = EAGAIN; + return -1; + } + /* we don't care about a possible delay here */ tevent_common_loop_timer_delay(epoll_ev->ev); return 0; diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h index 75ae114e35f..d43dcbfcccf 100644 --- a/lib/tevent/tevent_internal.h +++ b/lib/tevent/tevent_internal.h @@ -417,6 +417,7 @@ struct tevent_context { * tevent_common_add_timer_v2() */ struct tevent_timer *last_zero_timer; + struct timeval wait_timeout; #ifdef HAVE_PTHREAD struct tevent_context *prev, *next; @@ -466,6 +467,34 @@ struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev, const char *handler_name, const char *location); struct timeval tevent_common_loop_timer_delay(struct tevent_context *); + +/* timeout values for poll(2) / epoll_wait(2) */ +static inline bool tevent_common_no_timeout(const struct timeval *tv) +{ + if ((tv->tv_sec == 0) && (tv->tv_usec == INT32_MAX)) { + /* + * This is special from + * tevent_context_set_wait_timeout(0) + */ + return true; + } + return false; +} +static inline int tevent_common_timeout_msec(const struct timeval *tv) +{ + if (tv->tv_sec == INT32_MAX) { + return -1; + } + if (tevent_common_no_timeout(tv)) { + /* + * This is special from + * tevent_context_set_wait_timeout(0) + */ + return 0; + } + return ((tv->tv_usec + 999) / 1000) + (tv->tv_sec * 1000); +} + int tevent_common_invoke_timer_handler(struct tevent_timer *te, struct timeval current_time, bool *removed); diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c index 91a93817a8c..1733516eb0a 100644 --- a/lib/tevent/tevent_poll.c +++ b/lib/tevent/tevent_poll.c @@ -480,7 +480,7 @@ static int poll_event_loop_poll(struct tevent_context *ev, struct poll_event_context *poll_ev = talloc_get_type_abort( ev->additional_data, struct poll_event_context); int pollrtn; - int timeout = -1; + int timeout = tevent_common_timeout_msec(tvalp); int poll_errno; struct tevent_fd *fde = NULL; struct tevent_fd *next = NULL; @@ -491,11 +491,6 @@ static int poll_event_loop_poll(struct tevent_context *ev, return 0; } - if (tvalp != NULL) { - timeout = tvalp->tv_sec * 1000; - timeout += (tvalp->tv_usec + 999) / 1000; - } - ok = poll_event_sync_arrays(ev, poll_ev); if (!ok) { return -1; @@ -512,6 +507,14 @@ static int poll_event_loop_poll(struct tevent_context *ev, } if (pollrtn == 0 && tvalp) { + /* + * tevent_context_set_wait_timeout(0) was used. + */ + if (tevent_common_no_timeout(tvalp)) { + errno = EAGAIN; + return -1; + } + /* we don't care about a possible delay here */ tevent_common_loop_timer_delay(ev); return 0; diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c index b4a24980c60..3db4a30e295 100644 --- a/lib/tevent/tevent_timed.c +++ b/lib/tevent/tevent_timed.c @@ -421,10 +421,7 @@ struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev) int ret; if (!te) { - /* have a default tick time of 30 seconds. This guarantees - that code that uses its own timeout checking will be - able to proceed eventually */ - return tevent_timeval_set(30, 0); + return ev->wait_timeout; } /* @@ -443,6 +440,9 @@ struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev) delay = tevent_timeval_until(¤t_time, &te->next_event); if (!tevent_timeval_is_zero(&delay)) { + if (tevent_common_no_timeout(&ev->wait_timeout)) { + return ev->wait_timeout; + } return delay; } }