Implement a generic cgsem_mswait similar to sem_timedwait
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
diff --git a/util.c b/util.c
index 8e03281..2de5c1c 100644
--- a/util.c
+++ b/util.c
@@ -881,6 +881,14 @@ void ms_to_timespec(struct timespec *spec, int64_t ms)
spec->tv_nsec = tvdiv.rem * 1000000;
}
+void ms_to_timeval(struct timeval *val, int64_t ms)
+{
+ lldiv_t tvdiv = lldiv(ms, 1000);
+
+ val->tv_sec = tvdiv.quot;
+ val->tv_usec = tvdiv.rem * 1000;
+}
+
void timeraddspec(struct timespec *a, const struct timespec *b)
{
a->tv_sec += b->tv_sec;
@@ -2407,6 +2415,31 @@ void _cgsem_destroy(cgsem_t *cgsem)
close(cgsem->pipefd[1]);
close(cgsem->pipefd[0]);
}
+
+/* This is similar to sem_timedwait but takes a millisecond value */
+int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, const int line)
+{
+ struct timeval timeout;
+ int ret, fd;
+ fd_set rd;
+ char buf;
+
+ fd = cgsem->pipefd[0];
+ FD_ZERO(&rd);
+ FD_SET(fd, &rd);
+ ms_to_timeval(&timeout, ms);
+ ret = select(fd + 1, &rd, NULL, NULL, &timeout);
+
+ if (ret > 0) {
+ ret = read(fd, &buf, 1);
+ return 0;
+ }
+ if (likely(!ret))
+ return ETIMEDOUT;
+ quitfrom(1, file, func, line, "Failed to sem_timedwait errno=%d cgsem=0x%p", errno, cgsem);
+ /* We don't reach here */
+ return 0;
+}
#else
void _cgsem_init(cgsem_t *cgsem, const char *file, const char *func, const int line)
{
@@ -2427,6 +2460,23 @@ void _cgsem_wait(cgsem_t *cgsem, const char *file, const char *func, const int l
quitfrom(1, file, func, line, "Failed to sem_wait errno=%d cgsem=0x%p", errno, cgsem);
}
+int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, const int line)
+{
+ struct timespec abs_timeout, ts_now;
+ struct timeval tv_now;
+ int ret;
+
+ cgtime(&tv_now);
+ timeval_to_spec(&ts_now, &tv_now);
+ ms_to_timespec(&abs_timeout, ms);
+ timeraddspec(&abs_timeout, &ts_now);
+ ret = sem_timedwait(cgsem, &abs_timeout);
+
+ if (unlikely(ret && ret != ETIMEDOUT))
+ quitfrom(1, file, func, line, "Failed to sem_timedwait errno=%d cgsem=0x%p", errno, cgsem);
+ return ret;
+}
+
void _cgsem_destroy(cgsem_t *cgsem)
{
sem_destroy(cgsem);
diff --git a/util.h b/util.h
index e318f77..b1dfc3b 100644
--- a/util.h
+++ b/util.h
@@ -129,6 +129,7 @@ void _cgsem_destroy(cgsem_t *cgsem);
#define cgsem_init(_sem) _cgsem_init(_sem, __FILE__, __func__, __LINE__)
#define cgsem_post(_sem) _cgsem_post(_sem, __FILE__, __func__, __LINE__)
#define cgsem_wait(_sem) _cgsem_wait(_sem, __FILE__, __func__, __LINE__)
+#define cgmsem_mswait(_sem, _timeout) _cgsem_mswait(_sem, _timeout, __FILE__, __func__, __LINE__)
#define cgsem_destroy(_sem) _cgsem_destroy(_sem)
/* Align a size_t to 4 byte boundaries for fussy arches */