]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
lib/posix-timerfd: Fix counter on subsequent reads
authorAndrei Tatar <andrei@unikraft.io>
Wed, 22 Jan 2025 22:26:44 +0000 (23:26 +0100)
committerUnikraft Bot <monkey@unikraft.io>
Tue, 25 Feb 2025 08:01:05 +0000 (08:01 +0000)
The internal counter of a timerfd is returned on read() and reset to 0,
and should be increased by 1 for every subsequent expiration.
A logic error in the current code makes every update set the counter to
the total expirations rather than since last read, leading to subsequent
successful reads returning wrong counts.
This change fixes this error.

Signed-off-by: Andrei Tatar <andrei@unikraft.io>
Approved-by: Sergiu Moga <sergiu@unikraft.io>
Reviewed-by: Sergiu Moga <sergiu@unikraft.io>
GitHub-Closes: #1567

lib/posix-timerfd/timerfd.c

index eb1614165fc8a2d0bcdd49c27e986531154e31b0..1e1b3271944f90a2f009877622af1de25c773792 100644 (file)
@@ -32,6 +32,7 @@ static const char TIMERFD_VOLID[] = "timerfd_vol";
 struct timerfd_node {
        struct itimerspec set;
        __u64 val;
+       __u64 total;
        clockid_t clkid;
        struct uk_thread *upthread;
 };
@@ -102,12 +103,11 @@ static __nsec _timerfd_update(const struct uk_file *f)
        deadline = now + st.next;
 
        /* Update val & events */
-       if (st.exp != d->val) {
-               d->val = st.exp;
-               if (st.exp)
-                       uk_file_event_set(f, UKFD_POLLIN);
-               else
-                       uk_file_event_clear(f, UKFD_POLLIN);
+       UK_ASSERT(st.exp >= d->total);
+       if (st.exp > d->total) {
+               d->val += st.exp - d->total;
+               d->total = st.exp;
+               uk_file_event_set(f, UKFD_POLLIN);
        }
        return deadline;
 }
@@ -124,6 +124,7 @@ static void _timerfd_set(struct timerfd_node *d, const struct itimerspec *set)
                /* Arm */
                d->set.it_value = set->it_value;
                d->set.it_interval = set->it_interval;
+               d->total = 0;
                uk_thread_wake(d->upthread);
        }
 }