pre_read fixes
[fio.git] / mutex.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <fcntl.h>
6 #include <pthread.h>
7 #include <sys/mman.h>
8
9 #include "log.h"
10 #include "mutex.h"
11 #include "arch/arch.h"
12 #include "os/os.h"
13
14 void fio_mutex_remove(struct fio_mutex *mutex)
15 {
16         close(mutex->mutex_fd);
17         munmap((void *) mutex, sizeof(*mutex));
18 }
19
20 struct fio_mutex *fio_mutex_init(int value)
21 {
22         char mutex_name[] = "/tmp/.fio_mutex.XXXXXX";
23         struct fio_mutex *mutex = NULL;
24         pthread_mutexattr_t attr;
25         pthread_condattr_t cond;
26         int fd, ret, mflag;
27
28         fd = mkstemp(mutex_name);
29         if (fd < 0) {
30                 perror("open mutex");
31                 return NULL;
32         }
33
34         if (ftruncate(fd, sizeof(struct fio_mutex)) < 0) {
35                 perror("ftruncate mutex");
36                 goto err;
37         }
38
39         mutex = (void *) mmap(NULL, sizeof(struct fio_mutex),
40                                 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
41         if (mutex == MAP_FAILED) {
42                 perror("mmap mutex");
43                 close(fd);
44                 mutex = NULL;
45                 goto err;
46         }
47
48         unlink(mutex_name);
49         mutex->mutex_fd = fd;
50         mutex->value = value;
51
52         /*
53          * Not all platforms support process shared mutexes (FreeBSD)
54          */
55 #ifdef FIO_HAVE_PSHARED_MUTEX
56         mflag = PTHREAD_PROCESS_SHARED;
57 #else
58         mflag = PTHREAD_PROCESS_PRIVATE;
59 #endif
60
61         ret = pthread_mutexattr_init(&attr);
62         if (ret) {
63                 log_err("pthread_mutexattr_init: %s\n", strerror(ret));
64                 goto err;
65         }
66         ret = pthread_mutexattr_setpshared(&attr, mflag);
67         if (ret) {
68                 log_err("pthread_mutexattr_setpshared: %s\n", strerror(ret));
69                 goto err;
70         }
71
72         pthread_condattr_init(&cond);
73         pthread_condattr_setpshared(&cond, mflag);
74         pthread_cond_init(&mutex->cond, &cond);
75
76         ret = pthread_mutex_init(&mutex->lock, &attr);
77         if (ret) {
78                 log_err("pthread_mutex_init: %s\n", strerror(ret));
79                 goto err;
80         }
81
82         return mutex;
83 err:
84         if (mutex)
85                 fio_mutex_remove(mutex);
86
87         unlink(mutex_name);
88         return NULL;
89 }
90
91 void fio_mutex_down(struct fio_mutex *mutex)
92 {
93         pthread_mutex_lock(&mutex->lock);
94
95         while (!mutex->value) {
96                 mutex->waiters++;
97                 pthread_cond_wait(&mutex->cond, &mutex->lock);
98                 mutex->waiters--;
99         }
100
101         mutex->value--;
102         pthread_mutex_unlock(&mutex->lock);
103 }
104
105 void fio_mutex_up(struct fio_mutex *mutex)
106 {
107         pthread_mutex_lock(&mutex->lock);
108         read_barrier();
109         if (!mutex->value && mutex->waiters)
110                 pthread_cond_signal(&mutex->cond);
111         mutex->value++;
112         pthread_mutex_unlock(&mutex->lock);
113 }
114
115 void fio_mutex_down_write(struct fio_mutex *mutex)
116 {
117         pthread_mutex_lock(&mutex->lock);
118
119         while (mutex->value != 0) {
120                 mutex->waiters++;
121                 pthread_cond_wait(&mutex->cond, &mutex->lock);
122                 mutex->waiters--;
123         }
124
125         mutex->value--;
126         pthread_mutex_unlock(&mutex->lock);
127 }
128
129 void fio_mutex_down_read(struct fio_mutex *mutex)
130 {
131         pthread_mutex_lock(&mutex->lock);
132
133         while (mutex->value < 0) {
134                 mutex->waiters++;
135                 pthread_cond_wait(&mutex->cond, &mutex->lock);
136                 mutex->waiters--;
137         }
138
139         mutex->value++;
140         pthread_mutex_unlock(&mutex->lock);
141 }
142
143 void fio_mutex_up_read(struct fio_mutex *mutex)
144 {
145         pthread_mutex_lock(&mutex->lock);
146         mutex->value--;
147         read_barrier();
148         if (mutex->value >= 0 && mutex->waiters)
149                 pthread_cond_signal(&mutex->cond);
150         pthread_mutex_unlock(&mutex->lock);
151 }
152
153 void fio_mutex_up_write(struct fio_mutex *mutex)
154 {
155         pthread_mutex_lock(&mutex->lock);
156         mutex->value++;
157         read_barrier();
158         if (mutex->value >= 0 && mutex->waiters)
159                 pthread_cond_signal(&mutex->cond);
160         pthread_mutex_unlock(&mutex->lock);
161 }