Commit f826e35765b44cdb7d3df435093569561577b58e

ckolivas 2013-10-18T10:14:51

Provide a cg_completion_timeout helper function for unreliable functions that takes arbitrary functions and parameters and reliably returns.

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)