Provide a cg_completion_timeout helper function for unreliable functions that takes arbitrary functions and parameters and reliably returns.
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
diff --git a/util.c b/util.c
index 8235b1c..7494b6a 100644
--- a/util.c
+++ b/util.c
@@ -2485,3 +2485,44 @@ void _cgsem_destroy(cgsem_t *cgsem)
sem_destroy(cgsem);
}
#endif
+
+/* Provide a completion_timeout helper function for unreliable functions that
+ * may die due to driver issues etc that time out if the function fails and
+ * can then reliably return. */
+struct cg_completion {
+ cgsem_t cgsem;
+ void (*fn)(void *fnarg);
+ void *fnarg;
+};
+
+void *completion_thread(void *arg)
+{
+ struct cg_completion *cgc = (struct cg_completion *)arg;
+
+ pthread_detach(pthread_self());
+ cgc->fn(cgc->fnarg);
+ cgsem_post(&cgc->cgsem);
+
+ return NULL;
+}
+
+bool _cg_completion_timeout(void *fn, void *fnarg, int timeout, const char *file, const char *func, const int line)
+{
+ struct cg_completion *cgc;
+ pthread_t pthread;
+ bool ret;
+
+ cgc = malloc(sizeof(struct cg_completion));
+ if (unlikely(!cgc))
+ return false;
+ cgsem_init(&cgc->cgsem);
+ cgc->fn = fn;
+ cgc->fnarg = fnarg;
+
+ pthread_create(&pthread, NULL, completion_thread, (void *)cgc);
+
+ ret = cgsem_mswait(&cgc->cgsem, timeout);
+ if (ret)
+ free(cgc);
+ return ret;
+}
diff --git a/util.h b/util.h
index b8a5a39..5d175d7 100644
--- a/util.h
+++ b/util.h
@@ -134,12 +134,14 @@ void _cgsem_post(cgsem_t *cgsem, const char *file, const char *func, const int l
void _cgsem_wait(cgsem_t *cgsem, const char *file, const char *func, const int line);
int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, const int line);
void _cgsem_destroy(cgsem_t *cgsem);
+bool _cg_completion_timeout(void *fn, void *fnarg, int timeout, const char *file, const char *func, const int line);
#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 cgsem_mswait(_sem, _timeout) _cgsem_mswait(_sem, _timeout, __FILE__, __func__, __LINE__)
#define cgsem_destroy(_sem) _cgsem_destroy(_sem)
+#define cg_completion_timeout(fn, fnarg, timeout) _cg_completion_timeout(fn, fnarg, timeout, __FILE__, __func__, __LINE__)
/* Align a size_t to 4 byte boundaries for fussy arches */
static inline void align_len(size_t *len)