blob: ff6ec73062efb4bed4c4a880c0276a263a9a722d [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>
10
Jens Axboeb4c1fb32012-02-16 22:22:46 +010011#include "fio.h"
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010012#include "log.h"
Jens Axboe07739b52007-03-08 20:25:46 +010013#include "mutex.h"
Jens Axboe4d4e80f2008-03-04 10:18:56 +010014#include "arch/arch.h"
Jens Axboe3c2d93e2009-01-05 19:04:15 +010015#include "os/os.h"
Jens Axboe3b2e1462009-12-15 08:58:10 +010016#include "helpers.h"
Jens Axboeef635052012-02-15 22:24:19 +010017#include "time.h"
18#include "gettime.h"
Jens Axboe07739b52007-03-08 20:25:46 +010019
Jens Axboeb4c1fb32012-02-16 22:22:46 +010020static clockid_t fio_clk_id = CLOCK_REALTIME;
21
Jens Axboecdd18ad2008-02-27 18:58:00 +010022void fio_mutex_remove(struct fio_mutex *mutex)
Jens Axboe07739b52007-03-08 20:25:46 +010023{
Jens Axboe58a157d2012-02-15 22:20:26 +010024 pthread_cond_destroy(&mutex->cond);
Jens Axboe5921e802008-05-30 15:02:38 +020025 munmap((void *) mutex, sizeof(*mutex));
Jens Axboe07739b52007-03-08 20:25:46 +010026}
27
Jens Axboecdd18ad2008-02-27 18:58:00 +010028struct fio_mutex *fio_mutex_init(int value)
Jens Axboe07739b52007-03-08 20:25:46 +010029{
Jens Axboecdd18ad2008-02-27 18:58:00 +010030 struct fio_mutex *mutex = NULL;
Jens Axboe07739b52007-03-08 20:25:46 +010031 pthread_mutexattr_t attr;
Zhang, Yanmin108fcc12008-02-04 09:17:52 +010032 pthread_condattr_t cond;
Jens Axboee721c572012-02-09 20:55:29 +010033 int ret;
Jens Axboe07739b52007-03-08 20:25:46 +010034
Jens Axboe5921e802008-05-30 15:02:38 +020035 mutex = (void *) mmap(NULL, sizeof(struct fio_mutex),
Jens Axboeb6f6abc2011-05-02 10:10:56 -060036 PROT_READ | PROT_WRITE,
37 OS_MAP_ANON | MAP_SHARED, -1, 0);
Jens Axboecdd18ad2008-02-27 18:58:00 +010038 if (mutex == MAP_FAILED) {
39 perror("mmap mutex");
Jens Axboecdd18ad2008-02-27 18:58:00 +010040 mutex = NULL;
Jens Axboee53bd0b2007-03-08 20:29:11 +010041 goto err;
Jens Axboe07739b52007-03-08 20:25:46 +010042 }
43
Jens Axboecdd18ad2008-02-27 18:58:00 +010044 mutex->value = value;
Jens Axboe07739b52007-03-08 20:25:46 +010045
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010046 ret = pthread_mutexattr_init(&attr);
47 if (ret) {
48 log_err("pthread_mutexattr_init: %s\n", strerror(ret));
Jens Axboe07739b52007-03-08 20:25:46 +010049 goto err;
50 }
Jens Axboee721c572012-02-09 20:55:29 +010051
52 /*
53 * Not all platforms support process shared mutexes (FreeBSD)
54 */
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020055#ifdef FIO_HAVE_PSHARED_MUTEX
Jens Axboee721c572012-02-09 20:55:29 +010056 ret = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010057 if (ret) {
58 log_err("pthread_mutexattr_setpshared: %s\n", strerror(ret));
Jens Axboe07739b52007-03-08 20:25:46 +010059 goto err;
60 }
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020061#endif
Zhang, Yanmin108fcc12008-02-04 09:17:52 +010062
63 pthread_condattr_init(&cond);
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020064#ifdef FIO_HAVE_PSHARED_MUTEX
Jens Axboee721c572012-02-09 20:55:29 +010065 pthread_condattr_setpshared(&cond, PTHREAD_PROCESS_SHARED);
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020066#endif
Jens Axboeceab2ea2012-02-15 09:56:51 +010067#ifdef FIO_HAVE_CLOCK_MONOTONIC
Jens Axboeb4c1fb32012-02-16 22:22:46 +010068 pthread_condattr_setclock(&cond, fio_clk_id);
Jens Axboeceab2ea2012-02-15 09:56:51 +010069#endif
Jens Axboe58a157d2012-02-15 22:20:26 +010070 pthread_cond_init(&mutex->cond, &cond);
Zhang, Yanmin108fcc12008-02-04 09:17:52 +010071
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010072 ret = pthread_mutex_init(&mutex->lock, &attr);
73 if (ret) {
74 log_err("pthread_mutex_init: %s\n", strerror(ret));
Jens Axboe07739b52007-03-08 20:25:46 +010075 goto err;
76 }
77
Bruce Cran03e20d62011-01-02 20:14:54 +010078 pthread_condattr_destroy(&cond);
79 pthread_mutexattr_destroy(&attr);
80
Jens Axboecdd18ad2008-02-27 18:58:00 +010081 return mutex;
Jens Axboe07739b52007-03-08 20:25:46 +010082err:
Jens Axboecdd18ad2008-02-27 18:58:00 +010083 if (mutex)
84 fio_mutex_remove(mutex);
Jens Axboef7c9e002007-03-09 12:40:02 +010085
Jens Axboe07739b52007-03-08 20:25:46 +010086 return NULL;
87}
88
Jens Axboeef635052012-02-15 22:24:19 +010089static int mutex_timed_out(struct timeval *t, unsigned int seconds)
90{
91 return mtime_since_now(t) >= seconds * 1000;
92}
93
Jens Axboe656b1392009-07-01 23:02:10 +020094int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int seconds)
95{
Jens Axboeef635052012-02-15 22:24:19 +010096 struct timeval tv_s;
Jens Axboe656b1392009-07-01 23:02:10 +020097 struct timespec t;
98 int ret = 0;
99
Jens Axboeef635052012-02-15 22:24:19 +0100100 fio_gettime(&tv_s, NULL);
101
Jens Axboeb4c1fb32012-02-16 22:22:46 +0100102 clock_gettime(fio_clk_id, &t);
Jens Axboe656b1392009-07-01 23:02:10 +0200103 t.tv_sec += seconds;
104
105 pthread_mutex_lock(&mutex->lock);
106
107 while (!mutex->value && !ret) {
108 mutex->waiters++;
Jens Axboeef635052012-02-15 22:24:19 +0100109
110 /*
111 * Some platforms (FreeBSD 9?) seems to return timed out
112 * way too early, double check.
113 */
Jens Axboe656b1392009-07-01 23:02:10 +0200114 ret = pthread_cond_timedwait(&mutex->cond, &mutex->lock, &t);
Jens Axboeef635052012-02-15 22:24:19 +0100115 if (ret == ETIMEDOUT && !mutex_timed_out(&tv_s, seconds)) {
116 pthread_mutex_lock(&mutex->lock);
117 ret = 0;
118 }
119
Jens Axboe656b1392009-07-01 23:02:10 +0200120 mutex->waiters--;
121 }
122
123 if (!ret) {
124 mutex->value--;
125 pthread_mutex_unlock(&mutex->lock);
126 }
127
128 return ret;
129}
130
Jens Axboecdd18ad2008-02-27 18:58:00 +0100131void fio_mutex_down(struct fio_mutex *mutex)
Jens Axboe07739b52007-03-08 20:25:46 +0100132{
Jens Axboecdd18ad2008-02-27 18:58:00 +0100133 pthread_mutex_lock(&mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100134
135 while (!mutex->value) {
136 mutex->waiters++;
Jens Axboecdd18ad2008-02-27 18:58:00 +0100137 pthread_cond_wait(&mutex->cond, &mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100138 mutex->waiters--;
139 }
140
Jens Axboecdd18ad2008-02-27 18:58:00 +0100141 mutex->value--;
142 pthread_mutex_unlock(&mutex->lock);
Jens Axboe07739b52007-03-08 20:25:46 +0100143}
144
Jens Axboecdd18ad2008-02-27 18:58:00 +0100145void fio_mutex_up(struct fio_mutex *mutex)
Jens Axboe07739b52007-03-08 20:25:46 +0100146{
Jens Axboecdd18ad2008-02-27 18:58:00 +0100147 pthread_mutex_lock(&mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100148 read_barrier();
149 if (!mutex->value && mutex->waiters)
Jens Axboecdd18ad2008-02-27 18:58:00 +0100150 pthread_cond_signal(&mutex->cond);
151 mutex->value++;
152 pthread_mutex_unlock(&mutex->lock);
Jens Axboe07739b52007-03-08 20:25:46 +0100153}
Jens Axboe64d4d312008-03-03 10:36:27 +0100154
155void fio_mutex_down_write(struct fio_mutex *mutex)
156{
157 pthread_mutex_lock(&mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100158
159 while (mutex->value != 0) {
160 mutex->waiters++;
Jens Axboe64d4d312008-03-03 10:36:27 +0100161 pthread_cond_wait(&mutex->cond, &mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100162 mutex->waiters--;
163 }
164
Jens Axboe64d4d312008-03-03 10:36:27 +0100165 mutex->value--;
166 pthread_mutex_unlock(&mutex->lock);
167}
168
169void fio_mutex_down_read(struct fio_mutex *mutex)
170{
171 pthread_mutex_lock(&mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100172
173 while (mutex->value < 0) {
174 mutex->waiters++;
Jens Axboe64d4d312008-03-03 10:36:27 +0100175 pthread_cond_wait(&mutex->cond, &mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100176 mutex->waiters--;
177 }
178
Jens Axboe64d4d312008-03-03 10:36:27 +0100179 mutex->value++;
180 pthread_mutex_unlock(&mutex->lock);
181}
182
183void fio_mutex_up_read(struct fio_mutex *mutex)
184{
185 pthread_mutex_lock(&mutex->lock);
186 mutex->value--;
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100187 read_barrier();
188 if (mutex->value >= 0 && mutex->waiters)
Jens Axboe64d4d312008-03-03 10:36:27 +0100189 pthread_cond_signal(&mutex->cond);
190 pthread_mutex_unlock(&mutex->lock);
191}
192
193void fio_mutex_up_write(struct fio_mutex *mutex)
194{
195 pthread_mutex_lock(&mutex->lock);
196 mutex->value++;
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100197 read_barrier();
198 if (mutex->value >= 0 && mutex->waiters)
Jens Axboe64d4d312008-03-03 10:36:27 +0100199 pthread_cond_signal(&mutex->cond);
200 pthread_mutex_unlock(&mutex->lock);
201}
Jens Axboeb4c1fb32012-02-16 22:22:46 +0100202
203static void fio_init fio_mutex_global_init(void)
204{
205#ifdef FIO_HAVE_PTHREAD_CONDATTR_SETCLOCK
206#ifdef FIO_HAVE_CLOCK_MONOTONIC
207 pthread_condattr_t cond;
208
209 pthread_condattr_init(&cond);
210
211 if (!pthread_condattr_setclock(&cond, CLOCK_MONOTONIC))
212 fio_clk_id = CLOCK_MONOTONIC;
213
214 pthread_condattr_destroy(&cond);
215#endif
216#endif
217}