Update OS support line
[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         return mutex;
97 err:
98         if (mutex)
99                 fio_mutex_remove(mutex);
100
101         unlink(mutex_name);
102         return NULL;
103 }
104
105 int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int seconds)
106 {
107         struct timespec t;
108         int ret = 0;
109
110         clock_gettime(CLOCK_REALTIME, &t);
111         t.tv_sec += seconds;
112
113         pthread_mutex_lock(&mutex->lock);
114
115         while (!mutex->value && !ret) {
116                 mutex->waiters++;
117                 ret = pthread_cond_timedwait(&mutex->cond, &mutex->lock, &t);
118                 mutex->waiters--;
119         }
120
121         if (!ret) {
122                 mutex->value--;
123                 pthread_mutex_unlock(&mutex->lock);
124         }
125
126         return ret;
127 }
128
129 void fio_mutex_down(struct fio_mutex *mutex)
130 {
131         pthread_mutex_lock(&mutex->lock);
132
133         while (!mutex->value) {
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(struct fio_mutex *mutex)
144 {
145         pthread_mutex_lock(&mutex->lock);
146         read_barrier();
147         if (!mutex->value && mutex->waiters)
148                 pthread_cond_signal(&mutex->cond);
149         mutex->value++;
150         pthread_mutex_unlock(&mutex->lock);
151 }
152
153 void fio_mutex_down_write(struct fio_mutex *mutex)
154 {
155         pthread_mutex_lock(&mutex->lock);
156
157         while (mutex->value != 0) {
158                 mutex->waiters++;
159                 pthread_cond_wait(&mutex->cond, &mutex->lock);
160                 mutex->waiters--;
161         }
162
163         mutex->value--;
164         pthread_mutex_unlock(&mutex->lock);
165 }
166
167 void fio_mutex_down_read(struct fio_mutex *mutex)
168 {
169         pthread_mutex_lock(&mutex->lock);
170
171         while (mutex->value < 0) {
172                 mutex->waiters++;
173                 pthread_cond_wait(&mutex->cond, &mutex->lock);
174                 mutex->waiters--;
175         }
176
177         mutex->value++;
178         pthread_mutex_unlock(&mutex->lock);
179 }
180
181 void fio_mutex_up_read(struct fio_mutex *mutex)
182 {
183         pthread_mutex_lock(&mutex->lock);
184         mutex->value--;
185         read_barrier();
186         if (mutex->value >= 0 && mutex->waiters)
187                 pthread_cond_signal(&mutex->cond);
188         pthread_mutex_unlock(&mutex->lock);
189 }
190
191 void fio_mutex_up_write(struct fio_mutex *mutex)
192 {
193         pthread_mutex_lock(&mutex->lock);
194         mutex->value++;
195         read_barrier();
196         if (mutex->value >= 0 && mutex->waiters)
197                 pthread_cond_signal(&mutex->cond);
198         pthread_mutex_unlock(&mutex->lock);
199 }