c1ce2a3e8740de808e70076a141b642646f9087f
[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 <time.h>
7 #include <pthread.h>
8 #include <sys/mman.h>
9
10 #include "log.h"
11 #include "mutex.h"
12 #include "arch/arch.h"
13 #include "os/os.h"
14 #include "helpers.h"
15
16 void fio_mutex_remove(struct fio_mutex *mutex)
17 {
18         close(mutex->mutex_fd);
19         munmap((void *) mutex, sizeof(*mutex));
20 }
21
22 struct fio_mutex *fio_mutex_init(int value)
23 {
24         char mutex_name[] = "/tmp/.fio_mutex.XXXXXX";
25         struct fio_mutex *mutex = NULL;
26         pthread_mutexattr_t attr;
27         pthread_condattr_t cond;
28         int fd, ret, mflag;
29
30         fd = mkstemp(mutex_name);
31         if (fd < 0) {
32                 perror("open mutex");
33                 return NULL;
34         }
35
36 #ifdef FIO_HAVE_FALLOCATE
37         ret = posix_fallocate(fd, 0, sizeof(struct fio_mutex));
38         if (ret > 0) {
39                 fprintf(stderr, "posix_fallocate mutex failed: %s\n", strerror(ret));
40                 goto err;
41         }
42 #endif
43
44         if (ftruncate(fd, sizeof(struct fio_mutex)) < 0) {
45                 perror("ftruncate mutex");
46                 goto err;
47         }
48
49         mutex = (void *) mmap(NULL, sizeof(struct fio_mutex),
50                                 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
51         if (mutex == MAP_FAILED) {
52                 perror("mmap mutex");
53                 close(fd);
54                 mutex = NULL;
55                 goto err;
56         }
57
58         unlink(mutex_name);
59         mutex->mutex_fd = fd;
60         mutex->value = value;
61
62         /*
63          * Not all platforms support process shared mutexes (FreeBSD)
64          */
65 #ifdef FIO_HAVE_PSHARED_MUTEX
66         mflag = PTHREAD_PROCESS_SHARED;
67 #else
68         mflag = PTHREAD_PROCESS_PRIVATE;
69 #endif
70
71         ret = pthread_mutexattr_init(&attr);
72         if (ret) {
73                 log_err("pthread_mutexattr_init: %s\n", strerror(ret));
74                 goto err;
75         }
76 #ifdef FIO_HAVE_PSHARED_MUTEX
77         ret = pthread_mutexattr_setpshared(&attr, mflag);
78         if (ret) {
79                 log_err("pthread_mutexattr_setpshared: %s\n", strerror(ret));
80                 goto err;
81         }
82 #endif
83
84         pthread_condattr_init(&cond);
85 #ifdef FIO_HAVE_PSHARED_MUTEX
86         pthread_condattr_setpshared(&cond, mflag);
87 #endif
88         pthread_cond_init(&mutex->cond, &cond);
89
90         ret = pthread_mutex_init(&mutex->lock, &attr);
91         if (ret) {
92                 log_err("pthread_mutex_init: %s\n", strerror(ret));
93                 goto err;
94         }
95
96         pthread_condattr_destroy(&cond);
97         pthread_mutexattr_destroy(&attr);
98
99         return mutex;
100 err:
101         if (mutex)
102                 fio_mutex_remove(mutex);
103
104         unlink(mutex_name);
105         return NULL;
106 }
107
108 int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int seconds)
109 {
110         struct timespec t;
111         int ret = 0;
112
113         clock_gettime(CLOCK_REALTIME, &t);
114         t.tv_sec += seconds;
115
116         pthread_mutex_lock(&mutex->lock);
117
118         while (!mutex->value && !ret) {
119                 mutex->waiters++;
120                 ret = pthread_cond_timedwait(&mutex->cond, &mutex->lock, &t);
121                 mutex->waiters--;
122         }
123
124         if (!ret) {
125                 mutex->value--;
126                 pthread_mutex_unlock(&mutex->lock);
127         }
128
129         return ret;
130 }
131
132 void fio_mutex_down(struct fio_mutex *mutex)
133 {
134         pthread_mutex_lock(&mutex->lock);
135
136         while (!mutex->value) {
137                 mutex->waiters++;
138                 pthread_cond_wait(&mutex->cond, &mutex->lock);
139                 mutex->waiters--;
140         }
141
142         mutex->value--;
143         pthread_mutex_unlock(&mutex->lock);
144 }
145
146 void fio_mutex_up(struct fio_mutex *mutex)
147 {
148         pthread_mutex_lock(&mutex->lock);
149         read_barrier();
150         if (!mutex->value && mutex->waiters)
151                 pthread_cond_signal(&mutex->cond);
152         mutex->value++;
153         pthread_mutex_unlock(&mutex->lock);
154 }
155
156 void fio_mutex_down_write(struct fio_mutex *mutex)
157 {
158         pthread_mutex_lock(&mutex->lock);
159
160         while (mutex->value != 0) {
161                 mutex->waiters++;
162                 pthread_cond_wait(&mutex->cond, &mutex->lock);
163                 mutex->waiters--;
164         }
165
166         mutex->value--;
167         pthread_mutex_unlock(&mutex->lock);
168 }
169
170 void fio_mutex_down_read(struct fio_mutex *mutex)
171 {
172         pthread_mutex_lock(&mutex->lock);
173
174         while (mutex->value < 0) {
175                 mutex->waiters++;
176                 pthread_cond_wait(&mutex->cond, &mutex->lock);
177                 mutex->waiters--;
178         }
179
180         mutex->value++;
181         pthread_mutex_unlock(&mutex->lock);
182 }
183
184 void fio_mutex_up_read(struct fio_mutex *mutex)
185 {
186         pthread_mutex_lock(&mutex->lock);
187         mutex->value--;
188         read_barrier();
189         if (mutex->value >= 0 && mutex->waiters)
190                 pthread_cond_signal(&mutex->cond);
191         pthread_mutex_unlock(&mutex->lock);
192 }
193
194 void fio_mutex_up_write(struct fio_mutex *mutex)
195 {
196         pthread_mutex_lock(&mutex->lock);
197         mutex->value++;
198         read_barrier();
199         if (mutex->value >= 0 && mutex->waiters)
200                 pthread_cond_signal(&mutex->cond);
201         pthread_mutex_unlock(&mutex->lock);
202 }