Add a typecheck for the endianness conversions
[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         assert(mutex->magic == FIO_MUTEX_MAGIC);
166
167         pthread_mutex_lock(&mutex->lock);
168         read_barrier();
169         if (!mutex->value && mutex->waiters)
170                 pthread_cond_signal(&mutex->cond);
171         mutex->value++;
172         pthread_mutex_unlock(&mutex->lock);
173 }
174
175 void fio_rwlock_write(struct fio_rwlock *lock)
176 {
177         assert(lock->magic == FIO_RWLOCK_MAGIC);
178         pthread_rwlock_wrlock(&lock->lock);
179 }
180
181 void fio_rwlock_read(struct fio_rwlock *lock)
182 {
183         assert(lock->magic == FIO_RWLOCK_MAGIC);
184         pthread_rwlock_rdlock(&lock->lock);
185 }
186
187 void fio_rwlock_unlock(struct fio_rwlock *lock)
188 {
189         assert(lock->magic == FIO_RWLOCK_MAGIC);
190         pthread_rwlock_unlock(&lock->lock);
191 }
192
193 void fio_rwlock_remove(struct fio_rwlock *lock)
194 {
195         assert(lock->magic == FIO_RWLOCK_MAGIC);
196         munmap((void *) lock, sizeof(*lock));
197 }
198
199 struct fio_rwlock *fio_rwlock_init(void)
200 {
201         struct fio_rwlock *lock;
202         pthread_rwlockattr_t attr;
203         int ret;
204
205         lock = (void *) mmap(NULL, sizeof(struct fio_rwlock),
206                                 PROT_READ | PROT_WRITE,
207                                 OS_MAP_ANON | MAP_SHARED, -1, 0);
208         if (lock == MAP_FAILED) {
209                 perror("mmap rwlock");
210                 lock = NULL;
211                 goto err;
212         }
213
214         lock->magic = FIO_RWLOCK_MAGIC;
215
216         ret = pthread_rwlockattr_init(&attr);
217         if (ret) {
218                 log_err("pthread_rwlockattr_init: %s\n", strerror(ret));
219                 goto err;
220         }
221 #ifdef FIO_HAVE_PSHARED_MUTEX
222         ret = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
223         if (ret) {
224                 log_err("pthread_rwlockattr_setpshared: %s\n", strerror(ret));
225                 goto destroy_attr;
226         }
227
228         ret = pthread_rwlock_init(&lock->lock, &attr);
229 #else
230         ret = pthread_rwlock_init(&lock->lock, NULL);
231 #endif
232
233         if (ret) {
234                 log_err("pthread_rwlock_init: %s\n", strerror(ret));
235                 goto destroy_attr;
236         }
237
238         pthread_rwlockattr_destroy(&attr);
239
240         return lock;
241 destroy_attr:
242         pthread_rwlockattr_destroy(&attr);
243 err:
244         if (lock)
245                 fio_rwlock_remove(lock);
246         return NULL;
247 }