Add a real semaphore implemtation
I've seen races where job N+1 got started before N, this breaks
for dependent jobs. So give up and implement a real semaphore
in mmap'ed shared storage.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/mutex.c b/mutex.c
new file mode 100644
index 0000000..bb417c2
--- /dev/null
+++ b/mutex.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/mman.h>
+
+#include "mutex.h"
+
+void fio_sem_remove(struct fio_sem *sem)
+{
+ unlink(sem->sem_name);
+ munmap(sem, sizeof(*sem));
+}
+
+struct fio_sem *fio_sem_init(int value)
+{
+ pthread_mutexattr_t attr;
+ struct fio_sem *sem;
+ char sem_name[32];
+ int fd;
+
+ sprintf(sem_name, "/tmp/.fio_lock.XXXXXX");
+ fd = mkstemp(sem_name);
+ if (fd < 0) {
+ perror("open sem");
+ return NULL;
+ }
+
+ if (ftruncate(fd, sizeof(struct fio_sem)) < 0) {
+ perror("ftruncate sem");
+ return NULL;
+ }
+
+ sem = mmap(NULL, sizeof(struct fio_sem), PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (sem == MAP_FAILED) {
+ perror("mmap sem");
+ close(fd);
+ unlink(sem_name);
+ return NULL;
+ }
+
+ close(fd);
+ sem->value = value;
+ strcpy(sem->sem_name, sem_name);
+
+ if (pthread_mutexattr_init(&attr)) {
+ perror("pthread_mutexattr_init");
+ goto err;
+ }
+ if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
+ perror("pthread_mutexattr_setpshared");
+ goto err;
+ }
+ if (pthread_mutex_init(&sem->lock, &attr)) {
+ perror("pthread_mutex_init");
+ goto err;
+ }
+
+ return sem;
+err:
+ munmap(sem, sizeof(*sem));
+ unlink(sem_name);
+ return NULL;
+}
+
+void fio_sem_down(struct fio_sem *sem)
+{
+ pthread_mutex_lock(&sem->lock);
+ while (sem->value == 0)
+ pthread_cond_wait(&sem->cond, &sem->lock);
+ sem->value--;
+ pthread_mutex_unlock(&sem->lock);
+}
+
+void fio_sem_up(struct fio_sem *sem)
+{
+ pthread_mutex_lock(&sem->lock);
+ if (!sem->value)
+ pthread_cond_signal(&sem->cond);
+ sem->value++;
+ pthread_mutex_unlock(&sem->lock);
+}