Improve dedupe/compression buffer filling for mixed block sizes
[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 <errno.h>
8 #include <pthread.h>
9 #include <sys/mman.h>
10 #include <assert.h>
11
12 #include "fio.h"
13 #include "log.h"
14 #include "mutex.h"
15 #include "arch/arch.h"
16 #include "os/os.h"
17 #include "helpers.h"
18 #include "fio_time.h"
19 #include "gettime.h"
20
21 void fio_mutex_remove(struct fio_mutex *mutex)
22 {
23         assert(mutex->magic == FIO_MUTEX_MAGIC);
24         pthread_cond_destroy(&mutex->cond);
25         munmap((void *) mutex, sizeof(*mutex));
26 }
27
28 int __fio_mutex_init(struct fio_mutex *mutex, int value)
29 {
30         pthread_mutexattr_t attr;
31         pthread_condattr_t cond;
32         int ret;
33
34         mutex->value = value;
35         mutex->magic = FIO_MUTEX_MAGIC;
36
37         ret = pthread_mutexattr_init(&attr);
38         if (ret) {
39                 log_err("pthread_mutexattr_init: %s\n", strerror(ret));
40                 return ret;
41         }
42
43         /*
44          * Not all platforms support process shared mutexes (FreeBSD)
45          */
46 #ifdef FIO_HAVE_PSHARED_MUTEX
47         ret = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
48         if (ret) {
49                 log_err("pthread_mutexattr_setpshared: %s\n", strerror(ret));
50                 return ret;
51         }
52 #endif
53
54         pthread_condattr_init(&cond);
55 #ifdef FIO_HAVE_PSHARED_MUTEX
56         pthread_condattr_setpshared(&cond, PTHREAD_PROCESS_SHARED);
57 #endif
58         pthread_cond_init(&mutex->cond, &cond);
59
60         ret = pthread_mutex_init(&mutex->lock, &attr);
61         if (ret) {
62                 log_err("pthread_mutex_init: %s\n", strerror(ret));
63                 return ret;
64         }
65
66         pthread_condattr_destroy(&cond);
67         pthread_mutexattr_destroy(&attr);
68         return 0;
69 }
70
71 struct fio_mutex *fio_mutex_init(int value)
72 {
73         struct fio_mutex *mutex = NULL;
74
75         mutex = (void *) mmap(NULL, sizeof(struct fio_mutex),
76                                 PROT_READ | PROT_WRITE,
77                                 OS_MAP_ANON | MAP_SHARED, -1, 0);
78         if (mutex == MAP_FAILED) {
79                 perror("mmap mutex");
80                 return NULL;
81         }
82
83         if (!__fio_mutex_init(mutex, value))
84                 return mutex;
85
86         fio_mutex_remove(mutex);
87         return NULL;
88 }
89
90 static int mutex_timed_out(struct timeval *t, unsigned int seconds)
91 {
92         return mtime_since_now(t) >= seconds * 1000;
93 }
94
95 int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int seconds)
96 {
97         struct timeval tv_s;
98         struct timespec t;
99         int ret = 0;
100
101         assert(mutex->magic == FIO_MUTEX_MAGIC);
102
103         gettimeofday(&tv_s, NULL);
104         t.tv_sec = tv_s.tv_sec + seconds;
105         t.tv_nsec = tv_s.tv_usec * 1000;
106
107         pthread_mutex_lock(&mutex->lock);
108
109         while (!mutex->value && !ret) {
110                 mutex->waiters++;
111
112                 /*
113                  * Some platforms (FreeBSD 9?) seems to return timed out
114                  * way too early, double check.
115                  */
116                 ret = pthread_cond_timedwait(&mutex->cond, &mutex->lock, &t);
117                 if (ret == ETIMEDOUT && !mutex_timed_out(&tv_s, seconds))
118                         ret = 0;
119
120                 mutex->waiters--;
121         }
122
123         if (!ret) {
124                 mutex->value--;
125                 pthread_mutex_unlock(&mutex->lock);
126         }
127
128         return ret;
129 }
130
131 int fio_mutex_down_trylock(struct fio_mutex *mutex)
132 {
133         int ret = 1;
134
135         assert(mutex->magic == FIO_MUTEX_MAGIC);
136
137         pthread_mutex_lock(&mutex->lock);
138         if (mutex->value) {
139                 mutex->value--;
140                 ret = 0;
141         }
142         pthread_mutex_unlock(&mutex->lock);
143
144         return ret;
145 }
146
147 void fio_mutex_down(struct fio_mutex *mutex)
148 {
149         assert(mutex->magic == FIO_MUTEX_MAGIC);
150
151         pthread_mutex_lock(&mutex->lock);
152
153         while (!mutex->value) {
154                 mutex->waiters++;
155                 pthread_cond_wait(&mutex->cond, &mutex->lock);
156                 mutex->waiters--;
157         }
158
159         mutex->value--;
160         pthread_mutex_unlock(&mutex->lock);
161 }
162
163 void fio_mutex_up(struct fio_mutex *mutex)
164 {
165         int do_wake = 0;
166
167         assert(mutex->magic == FIO_MUTEX_MAGIC);
168
169         pthread_mutex_lock(&mutex->lock);
170         read_barrier();
171         if (!mutex->value && mutex->waiters)
172                 do_wake = 1;
173         mutex->value++;
174         pthread_mutex_unlock(&mutex->lock);
175
176         if (do_wake)
177                 pthread_cond_signal(&mutex->cond);
178 }
179
180 void fio_rwlock_write(struct fio_rwlock *lock)
181 {
182         assert(lock->magic == FIO_RWLOCK_MAGIC);
183         pthread_rwlock_wrlock(&lock->lock);
184 }
185
186 void fio_rwlock_read(struct fio_rwlock *lock)
187 {
188         assert(lock->magic == FIO_RWLOCK_MAGIC);
189         pthread_rwlock_rdlock(&lock->lock);
190 }
191
192 void fio_rwlock_unlock(struct fio_rwlock *lock)
193 {
194         assert(lock->magic == FIO_RWLOCK_MAGIC);
195         pthread_rwlock_unlock(&lock->lock);
196 }
197
198 void fio_rwlock_remove(struct fio_rwlock *lock)
199 {
200         assert(lock->magic == FIO_RWLOCK_MAGIC);
201         munmap((void *) lock, sizeof(*lock));
202 }
203
204 struct fio_rwlock *fio_rwlock_init(void)
205 {
206         struct fio_rwlock *lock;
207         pthread_rwlockattr_t attr;
208         int ret;
209
210         lock = (void *) mmap(NULL, sizeof(struct fio_rwlock),
211                                 PROT_READ | PROT_WRITE,
212                                 OS_MAP_ANON | MAP_SHARED, -1, 0);
213         if (lock == MAP_FAILED) {
214                 perror("mmap rwlock");
215                 lock = NULL;
216                 goto err;
217         }
218
219         lock->magic = FIO_RWLOCK_MAGIC;
220
221         ret = pthread_rwlockattr_init(&attr);
222         if (ret) {
223                 log_err("pthread_rwlockattr_init: %s\n", strerror(ret));
224                 goto err;
225         }
226 #ifdef FIO_HAVE_PSHARED_MUTEX
227         ret = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
228         if (ret) {
229                 log_err("pthread_rwlockattr_setpshared: %s\n", strerror(ret));
230                 goto destroy_attr;
231         }
232
233         ret = pthread_rwlock_init(&lock->lock, &attr);
234 #else
235         ret = pthread_rwlock_init(&lock->lock, NULL);
236 #endif
237
238         if (ret) {
239                 log_err("pthread_rwlock_init: %s\n", strerror(ret));
240                 goto destroy_attr;
241         }
242
243         pthread_rwlockattr_destroy(&attr);
244
245         return lock;
246 destroy_attr:
247         pthread_rwlockattr_destroy(&attr);
248 err:
249         if (lock)
250                 fio_rwlock_remove(lock);
251         return NULL;
252 }