Signed-off-by: rean <[email protected]>
---
core/semaphore.cc | 23 +++++++++++++++++++++
modules/tests/Makefile | 2 +-
tests/tst-sem-timed-wait.cc | 50 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+), 1 deletion(-)
create mode 100644 tests/tst-sem-timed-wait.cc
diff --git a/core/semaphore.cc b/core/semaphore.cc
index 73732b8..6081a87 100644
--- a/core/semaphore.cc
+++ b/core/semaphore.cc
@@ -46,6 +46,29 @@ bool semaphore::wait(unsigned units, sched::timer* tmr)
sched::thread::wait_until(_mtx,
[&] { return (tmr && tmr->expired()) || !wr.owner; });
+ // If wr.owner is not nullptr then there was a timeout (post() did not
+ // wake us). In that case, just remove the wait_record (local variable)
+ // that we just pushed onto _waiters (via push_back)
+ if (wr.owner) {
+ auto i = _waiters.begin();
+ // _val can be 0 right now, so we can't use the same condition that
+ // post_unlocked uses "_val > 0 && i != _waiters.end()"
+ while (i != _waiters.end()) {
+ auto wait_rec = i++;
+ if (wait_rec->owner == sched::thread::current()) {
+ // We found our wait record so remove it from the list.
+ // There is no need to wake ourselves or set wr.owner = nullptr
+ // we want to remember that we timed out (if post happened then
+ // wr.owner would have been set to nullptr)
+ if (wait_rec->units <= _val) {
+ _val -= wait_rec->units;
+ }
+ // Remove our wait_record
+ _waiters.erase(wait_rec);
+ }
+ }
+ }
+
// if wr.owner, it's a timeout - post() didn't wake us and didn't decrease
// the semaphore's value for us. Note we are holding the mutex, so there
// can be no race with post().
diff --git a/modules/tests/Makefile b/modules/tests/Makefile
index fb8d001..6e3aea7 100644
--- a/modules/tests/Makefile
+++ b/modules/tests/Makefile
@@ -84,7 +84,7 @@ tests := tst-pthread.so misc-ramdisk.so tst-vblk.so
tst-bsd-evh.so \
tst-namespace.so tst-without-namespace.so payload-env.so \
payload-merge-env.so misc-execve.so misc-execve-payload.so
misc-mutex2.so \
tst-pthread-setcancelstate.so tst-syscall.so tst-pin.so tst-run.so \
- tst-ifaddrs.so tst-pthread-affinity-inherit.so
+ tst-ifaddrs.so tst-pthread-affinity-inherit.so tst-sem-timed-wait.so
# libstatic-thread-variable.so tst-static-thread-variable.so \
diff --git a/tests/tst-sem-timed-wait.cc b/tests/tst-sem-timed-wait.cc
new file mode 100644
index 0000000..f401ed0
--- /dev/null
+++ b/tests/tst-sem-timed-wait.cc
@@ -0,0 +1,50 @@
+#include <osv/semaphore.hh>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+
+unsigned int tests_total = 0, tests_failed = 0;
+
+void report(const char* name, bool passed)
+{
+ static const char* status[] = {"FAIL", "PASS"};
+ printf("%s: %s\n", status[passed], name);
+ tests_total += 1;
+ tests_failed += !passed;
+}
+
+int main(void)
+{
+ printf("Starting sem_timed_wait test\n");
+
+ // Basic flow for test
+ // 1) Create a semaphore (initialized to 0)
+ // 2) Do a timed-wait on it
+ // 3) We're never signaled/woken so our stack-allocated wait_record remains
+ // on the semaphore's waiters list
+ //
+ // In the failure case the end result is a stacktrace that looks like:
+ // Assertion failed: !hook.is_linked()
+ //(/usr/include/boost/intrusive/detail/generic_hook.hpp: destructor_impl:
47)
+
+ //[backtrace]
+ //0x0000000000225a48 <__assert_fail+24>
+ //0x00000000003c40e9 <???+3948777>
+ //0x00000000003c4242 <semaphore::wait(unsigned int, sched::timer*)+98>
+ //0x0000100000c01057 <???+12587095>
+
+ semaphore sem(0);
+ timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ sched::timer tmr(*sched::thread::current());
+ osv::clock::wall::time_point time(std::chrono::seconds(ts.tv_sec) +
+ std::chrono::nanoseconds(ts.tv_nsec));
+ tmr.set(time);
+ bool ret_val = sem.wait(1, &tmr);
+ report("sem_timedwait\0", ret_val == false);
+ printf("SUMMARY: %u tests / %u failures\n", tests_total, tests_failed);
+ return tests_failed == 0 ? 0 : 1;
+}
--
2.7.4
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.