summaryrefslogtreecommitdiff
path: root/src/wg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wg.c')
-rw-r--r--src/wg.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/src/wg.c b/src/wg.c
new file mode 100644
index 0000000..4f60765
--- /dev/null
+++ b/src/wg.c
@@ -0,0 +1,45 @@
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h> /* for EXIT_FAILURE */
+#include <unistd.h>
+
+#include "wg.h"
+
+/* Thread management tools modeled on https://golang.org/pkg/sync/#WaitGroup */
+
+/* pthread_cond_t is overly complicated. Just use a self-pipe. */
+
+void wg_init(struct wg *wg) {
+ wg->count = 0;
+ pthread_mutex_init(&wg->lock, NULL);
+ int fds[2];
+ if (pipe(fds) != 0)
+ error(EXIT_FAILURE, errno, "pipe");
+ wg->fd_wait = fds[0];
+ wg->fd_signal = fds[1];
+}
+
+void wg_add(struct wg *wg, unsigned int n) {
+ pthread_mutex_lock(&wg->lock);
+ wg->count += n;
+ pthread_mutex_unlock(&wg->lock);
+}
+
+void wg_sub(struct wg *wg, unsigned int n) {
+ pthread_mutex_lock(&wg->lock);
+ wg->count -= n;
+ if (wg->count == 0)
+ if (write(wg->fd_signal, " ", 1) < 1)
+ error(EXIT_FAILURE, errno, "write");
+ pthread_mutex_unlock(&wg->lock);
+}
+
+void wg_wait(struct wg *wg) {
+ char b;
+ retry:
+ if (read(wg->fd_wait, &b, 1) == -1) {
+ if (errno == EINTR)
+ goto retry;
+ error(EXIT_FAILURE, errno, "wg_wait");
+ }
+}