]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
tevent: Add tevent_context_set_wait_timeout()
authorVolker Lendecke <vl@samba.org>
Mon, 10 Mar 2025 20:12:28 +0000 (21:12 +0100)
committerStefan Metzmacher <metze@samba.org>
Wed, 18 Jun 2025 17:52:37 +0000 (17:52 +0000)
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 <metze@samba.org>

Signed-off-by: Volker Lendecke <vl@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
lib/tevent/ABI/tevent-0.16.2.sigs
lib/tevent/tevent.c
lib/tevent/tevent.h
lib/tevent/tevent_epoll.c
lib/tevent/tevent_internal.h
lib/tevent/tevent_poll.c
lib/tevent/tevent_timed.c

index f7eba5775df3407473727b1176e060aa01e24565..4b129912b6f81eea9c4e79ac95b1dba10cbeacd4 100644 (file)
@@ -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 *)
index 9f4a91953ae3f5f9e1e1017ff2b5ddccc110cdfe..c3e688510e1915ad2d0d310cca460728b0c9f9ee 100644 (file)
@@ -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)
index 0f40b2bed30781357087cdbe5fa5c394c7c87509..b94504981b97ee987f47ad68db3f53e4fba48504 100644 (file)
@@ -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.
index 233533e4d31d2334dad8922ad5efd7b171714975..d13641ec347b6d481fdad917bab4df3f31f52d12 100644 (file)
@@ -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;
index 75ae114e35f8246499d9eedbfa9484b98157f6d1..d43dcbfcccf3951e9ea374751c7b2dae5d76071c 100644 (file)
@@ -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);
index 91a93817a8c91866619dac0013a31ea935c53716..1733516eb0a1493a592159e0c2ef5022a4cf69e5 100644 (file)
@@ -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;
index b4a24980c60ce013ca4d930cca653f02009f9379..3db4a30e295b839ab472ae358e82bd4ef0fe2f09 100644 (file)
@@ -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(&current_time, &te->next_event);
                if (!tevent_timeval_is_zero(&delay)) {
+                       if (tevent_common_no_timeout(&ev->wait_timeout)) {
+                               return ev->wait_timeout;
+                       }
                        return delay;
                }
        }