blob: 53f9651a9887538be42addc8db55a5969bd7b974 [file] [log] [blame]
Jens Axboe07739b52007-03-08 20:25:46 +01001#include <stdio.h>
2#include <string.h>
3#include <unistd.h>
4#include <stdlib.h>
5#include <fcntl.h>
Jens Axboe656b1392009-07-01 23:02:10 +02006#include <time.h>
Jens Axboeef635052012-02-15 22:24:19 +01007#include <errno.h>
Jens Axboe07739b52007-03-08 20:25:46 +01008#include <pthread.h>
9#include <sys/mman.h>
Jens Axboe8b4e9542013-03-21 10:05:07 -060010#include <assert.h>
Jens Axboe07739b52007-03-08 20:25:46 +010011
Jens Axboeb4c1fb32012-02-16 22:22:46 +010012#include "fio.h"
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010013#include "log.h"
Jens Axboe07739b52007-03-08 20:25:46 +010014#include "mutex.h"
Jens Axboe4d4e80f2008-03-04 10:18:56 +010015#include "arch/arch.h"
Jens Axboe3c2d93e2009-01-05 19:04:15 +010016#include "os/os.h"
Jens Axboe3b2e1462009-12-15 08:58:10 +010017#include "helpers.h"
Daniel Gollubef3c94b2014-04-30 11:25:04 +020018#include "fio_time.h"
Jens Axboeef635052012-02-15 22:24:19 +010019#include "gettime.h"
Jens Axboe07739b52007-03-08 20:25:46 +010020
Jens Axboec1803422014-12-18 19:44:18 -070021void __fio_mutex_remove(struct fio_mutex *mutex)
Jens Axboe07739b52007-03-08 20:25:46 +010022{
Jianpeng Ma8f801ad2013-03-22 07:16:32 -060023 assert(mutex->magic == FIO_MUTEX_MAGIC);
Jens Axboe58a157d2012-02-15 22:20:26 +010024 pthread_cond_destroy(&mutex->cond);
Jens Axboec1803422014-12-18 19:44:18 -070025}
26
27void fio_mutex_remove(struct fio_mutex *mutex)
28{
29 __fio_mutex_remove(mutex);
Jens Axboe5921e802008-05-30 15:02:38 +020030 munmap((void *) mutex, sizeof(*mutex));
Jens Axboe07739b52007-03-08 20:25:46 +010031}
32
Jens Axboe72242052014-04-02 15:45:25 -060033int __fio_mutex_init(struct fio_mutex *mutex, int value)
Jens Axboe07739b52007-03-08 20:25:46 +010034{
35 pthread_mutexattr_t attr;
Zhang, Yanmin108fcc12008-02-04 09:17:52 +010036 pthread_condattr_t cond;
Jens Axboee721c572012-02-09 20:55:29 +010037 int ret;
Jens Axboe07739b52007-03-08 20:25:46 +010038
Jens Axboecdd18ad2008-02-27 18:58:00 +010039 mutex->value = value;
Jens Axboe8b4e9542013-03-21 10:05:07 -060040 mutex->magic = FIO_MUTEX_MAGIC;
Jens Axboe07739b52007-03-08 20:25:46 +010041
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010042 ret = pthread_mutexattr_init(&attr);
43 if (ret) {
44 log_err("pthread_mutexattr_init: %s\n", strerror(ret));
Jens Axboe72242052014-04-02 15:45:25 -060045 return ret;
Jens Axboe07739b52007-03-08 20:25:46 +010046 }
Jens Axboee721c572012-02-09 20:55:29 +010047
48 /*
49 * Not all platforms support process shared mutexes (FreeBSD)
50 */
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020051#ifdef FIO_HAVE_PSHARED_MUTEX
Jens Axboee721c572012-02-09 20:55:29 +010052 ret = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010053 if (ret) {
54 log_err("pthread_mutexattr_setpshared: %s\n", strerror(ret));
Jens Axboe72242052014-04-02 15:45:25 -060055 return ret;
Jens Axboe07739b52007-03-08 20:25:46 +010056 }
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020057#endif
Zhang, Yanmin108fcc12008-02-04 09:17:52 +010058
59 pthread_condattr_init(&cond);
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020060#ifdef FIO_HAVE_PSHARED_MUTEX
Jens Axboee721c572012-02-09 20:55:29 +010061 pthread_condattr_setpshared(&cond, PTHREAD_PROCESS_SHARED);
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020062#endif
Jens Axboe58a157d2012-02-15 22:20:26 +010063 pthread_cond_init(&mutex->cond, &cond);
Zhang, Yanmin108fcc12008-02-04 09:17:52 +010064
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010065 ret = pthread_mutex_init(&mutex->lock, &attr);
66 if (ret) {
67 log_err("pthread_mutex_init: %s\n", strerror(ret));
Jens Axboe72242052014-04-02 15:45:25 -060068 return ret;
Jens Axboe07739b52007-03-08 20:25:46 +010069 }
70
Bruce Cran03e20d62011-01-02 20:14:54 +010071 pthread_condattr_destroy(&cond);
72 pthread_mutexattr_destroy(&attr);
Jens Axboe72242052014-04-02 15:45:25 -060073 return 0;
74}
Bruce Cran03e20d62011-01-02 20:14:54 +010075
Jens Axboe72242052014-04-02 15:45:25 -060076struct fio_mutex *fio_mutex_init(int value)
77{
78 struct fio_mutex *mutex = NULL;
Jens Axboef7c9e002007-03-09 12:40:02 +010079
Jens Axboe72242052014-04-02 15:45:25 -060080 mutex = (void *) mmap(NULL, sizeof(struct fio_mutex),
81 PROT_READ | PROT_WRITE,
82 OS_MAP_ANON | MAP_SHARED, -1, 0);
83 if (mutex == MAP_FAILED) {
84 perror("mmap mutex");
85 return NULL;
86 }
87
88 if (!__fio_mutex_init(mutex, value))
89 return mutex;
90
91 fio_mutex_remove(mutex);
Jens Axboe07739b52007-03-08 20:25:46 +010092 return NULL;
93}
94
Jens Axboeef635052012-02-15 22:24:19 +010095static int mutex_timed_out(struct timeval *t, unsigned int seconds)
96{
97 return mtime_since_now(t) >= seconds * 1000;
98}
99
Jens Axboe656b1392009-07-01 23:02:10 +0200100int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int seconds)
101{
Jens Axboeef635052012-02-15 22:24:19 +0100102 struct timeval tv_s;
Jens Axboe656b1392009-07-01 23:02:10 +0200103 struct timespec t;
104 int ret = 0;
105
Jianpeng Ma8f801ad2013-03-22 07:16:32 -0600106 assert(mutex->magic == FIO_MUTEX_MAGIC);
Jens Axboe8b4e9542013-03-21 10:05:07 -0600107
Jens Axboeb11e4cc2012-02-20 09:18:43 +0100108 gettimeofday(&tv_s, NULL);
109 t.tv_sec = tv_s.tv_sec + seconds;
110 t.tv_nsec = tv_s.tv_usec * 1000;
Jens Axboe656b1392009-07-01 23:02:10 +0200111
112 pthread_mutex_lock(&mutex->lock);
113
114 while (!mutex->value && !ret) {
115 mutex->waiters++;
Jens Axboeef635052012-02-15 22:24:19 +0100116
117 /*
118 * Some platforms (FreeBSD 9?) seems to return timed out
119 * way too early, double check.
120 */
Jens Axboe656b1392009-07-01 23:02:10 +0200121 ret = pthread_cond_timedwait(&mutex->cond, &mutex->lock, &t);
Jens Axboed7df1d12013-03-20 19:57:01 -0600122 if (ret == ETIMEDOUT && !mutex_timed_out(&tv_s, seconds))
Jens Axboeef635052012-02-15 22:24:19 +0100123 ret = 0;
Jens Axboeef635052012-02-15 22:24:19 +0100124
Jens Axboe656b1392009-07-01 23:02:10 +0200125 mutex->waiters--;
126 }
127
128 if (!ret) {
129 mutex->value--;
130 pthread_mutex_unlock(&mutex->lock);
131 }
132
133 return ret;
134}
135
Jens Axboe72242052014-04-02 15:45:25 -0600136int fio_mutex_down_trylock(struct fio_mutex *mutex)
137{
138 int ret = 1;
139
140 assert(mutex->magic == FIO_MUTEX_MAGIC);
141
142 pthread_mutex_lock(&mutex->lock);
143 if (mutex->value) {
144 mutex->value--;
145 ret = 0;
146 }
147 pthread_mutex_unlock(&mutex->lock);
148
149 return ret;
150}
151
Jens Axboecdd18ad2008-02-27 18:58:00 +0100152void fio_mutex_down(struct fio_mutex *mutex)
Jens Axboe07739b52007-03-08 20:25:46 +0100153{
Jianpeng Ma8f801ad2013-03-22 07:16:32 -0600154 assert(mutex->magic == FIO_MUTEX_MAGIC);
Jens Axboe8b4e9542013-03-21 10:05:07 -0600155
Jens Axboecdd18ad2008-02-27 18:58:00 +0100156 pthread_mutex_lock(&mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100157
158 while (!mutex->value) {
159 mutex->waiters++;
Jens Axboecdd18ad2008-02-27 18:58:00 +0100160 pthread_cond_wait(&mutex->cond, &mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100161 mutex->waiters--;
162 }
163
Jens Axboecdd18ad2008-02-27 18:58:00 +0100164 mutex->value--;
165 pthread_mutex_unlock(&mutex->lock);
Jens Axboe07739b52007-03-08 20:25:46 +0100166}
167
Jens Axboecdd18ad2008-02-27 18:58:00 +0100168void fio_mutex_up(struct fio_mutex *mutex)
Jens Axboe07739b52007-03-08 20:25:46 +0100169{
Jens Axboef5fc4b42014-07-08 09:46:37 +0200170 int do_wake = 0;
171
Jianpeng Ma8f801ad2013-03-22 07:16:32 -0600172 assert(mutex->magic == FIO_MUTEX_MAGIC);
Jens Axboe8b4e9542013-03-21 10:05:07 -0600173
Jens Axboecdd18ad2008-02-27 18:58:00 +0100174 pthread_mutex_lock(&mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100175 read_barrier();
176 if (!mutex->value && mutex->waiters)
Jens Axboef5fc4b42014-07-08 09:46:37 +0200177 do_wake = 1;
Jens Axboecdd18ad2008-02-27 18:58:00 +0100178 mutex->value++;
179 pthread_mutex_unlock(&mutex->lock);
Jens Axboef5fc4b42014-07-08 09:46:37 +0200180
181 if (do_wake)
182 pthread_cond_signal(&mutex->cond);
Jens Axboe07739b52007-03-08 20:25:46 +0100183}
Jens Axboe64d4d312008-03-03 10:36:27 +0100184
Jens Axboed7df1d12013-03-20 19:57:01 -0600185void fio_rwlock_write(struct fio_rwlock *lock)
Jens Axboe64d4d312008-03-03 10:36:27 +0100186{
Jianpeng Ma8f801ad2013-03-22 07:16:32 -0600187 assert(lock->magic == FIO_RWLOCK_MAGIC);
Jens Axboed7df1d12013-03-20 19:57:01 -0600188 pthread_rwlock_wrlock(&lock->lock);
189}
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100190
Jens Axboed7df1d12013-03-20 19:57:01 -0600191void fio_rwlock_read(struct fio_rwlock *lock)
192{
Jianpeng Ma8f801ad2013-03-22 07:16:32 -0600193 assert(lock->magic == FIO_RWLOCK_MAGIC);
Jens Axboed7df1d12013-03-20 19:57:01 -0600194 pthread_rwlock_rdlock(&lock->lock);
195}
196
197void fio_rwlock_unlock(struct fio_rwlock *lock)
198{
Jianpeng Ma8f801ad2013-03-22 07:16:32 -0600199 assert(lock->magic == FIO_RWLOCK_MAGIC);
Jens Axboed7df1d12013-03-20 19:57:01 -0600200 pthread_rwlock_unlock(&lock->lock);
201}
202
203void fio_rwlock_remove(struct fio_rwlock *lock)
204{
Jianpeng Ma8f801ad2013-03-22 07:16:32 -0600205 assert(lock->magic == FIO_RWLOCK_MAGIC);
Jens Axboed7df1d12013-03-20 19:57:01 -0600206 munmap((void *) lock, sizeof(*lock));
207}
208
209struct fio_rwlock *fio_rwlock_init(void)
210{
211 struct fio_rwlock *lock;
Shaohua Li33980f52013-03-28 08:28:51 -0600212 pthread_rwlockattr_t attr;
Jens Axboed7df1d12013-03-20 19:57:01 -0600213 int ret;
214
215 lock = (void *) mmap(NULL, sizeof(struct fio_rwlock),
216 PROT_READ | PROT_WRITE,
217 OS_MAP_ANON | MAP_SHARED, -1, 0);
218 if (lock == MAP_FAILED) {
219 perror("mmap rwlock");
220 lock = NULL;
221 goto err;
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100222 }
223
Jens Axboe8b4e9542013-03-21 10:05:07 -0600224 lock->magic = FIO_RWLOCK_MAGIC;
225
Shaohua Li33980f52013-03-28 08:28:51 -0600226 ret = pthread_rwlockattr_init(&attr);
Jens Axboed7df1d12013-03-20 19:57:01 -0600227 if (ret) {
Bruce Crancdb57fe2013-03-29 16:02:53 +0000228 log_err("pthread_rwlockattr_init: %s\n", strerror(ret));
Jens Axboed7df1d12013-03-20 19:57:01 -0600229 goto err;
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100230 }
Shaohua Li33980f52013-03-28 08:28:51 -0600231#ifdef FIO_HAVE_PSHARED_MUTEX
232 ret = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
233 if (ret) {
Bruce Crancdb57fe2013-03-29 16:02:53 +0000234 log_err("pthread_rwlockattr_setpshared: %s\n", strerror(ret));
Shaohua Li33980f52013-03-28 08:28:51 -0600235 goto destroy_attr;
236 }
Shaohua Li33980f52013-03-28 08:28:51 -0600237
238 ret = pthread_rwlock_init(&lock->lock, &attr);
Bruce Cran09f17d62013-03-29 16:17:25 +0000239#else
240 ret = pthread_rwlock_init(&lock->lock, NULL);
241#endif
242
Shaohua Li33980f52013-03-28 08:28:51 -0600243 if (ret) {
244 log_err("pthread_rwlock_init: %s\n", strerror(ret));
245 goto destroy_attr;
246 }
247
248 pthread_rwlockattr_destroy(&attr);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100249
Jens Axboed7df1d12013-03-20 19:57:01 -0600250 return lock;
Shaohua Li33980f52013-03-28 08:28:51 -0600251destroy_attr:
252 pthread_rwlockattr_destroy(&attr);
Jens Axboed7df1d12013-03-20 19:57:01 -0600253err:
254 if (lock)
255 fio_rwlock_remove(lock);
256 return NULL;
Jens Axboe64d4d312008-03-03 10:36:27 +0100257}