blob: cc4e353d1f508e492eae65d052c4af65b9f08d5d [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 Axboe4fa6d0f2009-01-05 09:45:13 +010011#include "log.h"
Jens Axboe07739b52007-03-08 20:25:46 +010012#include "mutex.h"
Jens Axboe4d4e80f2008-03-04 10:18:56 +010013#include "arch/arch.h"
Jens Axboe3c2d93e2009-01-05 19:04:15 +010014#include "os/os.h"
Jens Axboe3b2e1462009-12-15 08:58:10 +010015#include "helpers.h"
Jens Axboeef635052012-02-15 22:24:19 +010016#include "time.h"
17#include "gettime.h"
Jens Axboe07739b52007-03-08 20:25:46 +010018
Jens Axboecdd18ad2008-02-27 18:58:00 +010019void fio_mutex_remove(struct fio_mutex *mutex)
Jens Axboe07739b52007-03-08 20:25:46 +010020{
Jens Axboe58a157d2012-02-15 22:20:26 +010021 pthread_cond_destroy(&mutex->cond);
Jens Axboe5921e802008-05-30 15:02:38 +020022 munmap((void *) mutex, sizeof(*mutex));
Jens Axboe07739b52007-03-08 20:25:46 +010023}
24
Jens Axboecdd18ad2008-02-27 18:58:00 +010025struct fio_mutex *fio_mutex_init(int value)
Jens Axboe07739b52007-03-08 20:25:46 +010026{
Jens Axboecdd18ad2008-02-27 18:58:00 +010027 struct fio_mutex *mutex = NULL;
Jens Axboe07739b52007-03-08 20:25:46 +010028 pthread_mutexattr_t attr;
Zhang, Yanmin108fcc12008-02-04 09:17:52 +010029 pthread_condattr_t cond;
Jens Axboee721c572012-02-09 20:55:29 +010030 int ret;
Jens Axboe07739b52007-03-08 20:25:46 +010031
Jens Axboe5921e802008-05-30 15:02:38 +020032 mutex = (void *) mmap(NULL, sizeof(struct fio_mutex),
Jens Axboeb6f6abc2011-05-02 10:10:56 -060033 PROT_READ | PROT_WRITE,
34 OS_MAP_ANON | MAP_SHARED, -1, 0);
Jens Axboecdd18ad2008-02-27 18:58:00 +010035 if (mutex == MAP_FAILED) {
36 perror("mmap mutex");
Jens Axboecdd18ad2008-02-27 18:58:00 +010037 mutex = NULL;
Jens Axboee53bd0b2007-03-08 20:29:11 +010038 goto err;
Jens Axboe07739b52007-03-08 20:25:46 +010039 }
40
Jens Axboecdd18ad2008-02-27 18:58:00 +010041 mutex->value = value;
Jens Axboe07739b52007-03-08 20:25:46 +010042
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010043 ret = pthread_mutexattr_init(&attr);
44 if (ret) {
45 log_err("pthread_mutexattr_init: %s\n", strerror(ret));
Jens Axboe07739b52007-03-08 20:25:46 +010046 goto err;
47 }
Jens Axboee721c572012-02-09 20:55:29 +010048
49 /*
50 * Not all platforms support process shared mutexes (FreeBSD)
51 */
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020052#ifdef FIO_HAVE_PSHARED_MUTEX
Jens Axboee721c572012-02-09 20:55:29 +010053 ret = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010054 if (ret) {
55 log_err("pthread_mutexattr_setpshared: %s\n", strerror(ret));
Jens Axboe07739b52007-03-08 20:25:46 +010056 goto err;
57 }
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020058#endif
Zhang, Yanmin108fcc12008-02-04 09:17:52 +010059
60 pthread_condattr_init(&cond);
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020061#ifdef FIO_HAVE_PSHARED_MUTEX
Jens Axboee721c572012-02-09 20:55:29 +010062 pthread_condattr_setpshared(&cond, PTHREAD_PROCESS_SHARED);
YAMAMOTO Takashi74524402010-05-12 15:06:46 +020063#endif
Jens Axboeceab2ea2012-02-15 09:56:51 +010064#ifdef FIO_HAVE_CLOCK_MONOTONIC
65 pthread_condattr_setclock(&cond, CLOCK_MONOTONIC);
66#else
67 pthread_condattr_setclock(&cond, CLOCK_REALTIME);
68#endif
Jens Axboe58a157d2012-02-15 22:20:26 +010069 pthread_cond_init(&mutex->cond, &cond);
Zhang, Yanmin108fcc12008-02-04 09:17:52 +010070
Jens Axboe4fa6d0f2009-01-05 09:45:13 +010071 ret = pthread_mutex_init(&mutex->lock, &attr);
72 if (ret) {
73 log_err("pthread_mutex_init: %s\n", strerror(ret));
Jens Axboe07739b52007-03-08 20:25:46 +010074 goto err;
75 }
76
Bruce Cran03e20d62011-01-02 20:14:54 +010077 pthread_condattr_destroy(&cond);
78 pthread_mutexattr_destroy(&attr);
79
Jens Axboecdd18ad2008-02-27 18:58:00 +010080 return mutex;
Jens Axboe07739b52007-03-08 20:25:46 +010081err:
Jens Axboecdd18ad2008-02-27 18:58:00 +010082 if (mutex)
83 fio_mutex_remove(mutex);
Jens Axboef7c9e002007-03-09 12:40:02 +010084
Jens Axboe07739b52007-03-08 20:25:46 +010085 return NULL;
86}
87
Jens Axboeef635052012-02-15 22:24:19 +010088static int mutex_timed_out(struct timeval *t, unsigned int seconds)
89{
90 return mtime_since_now(t) >= seconds * 1000;
91}
92
Jens Axboe656b1392009-07-01 23:02:10 +020093int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int seconds)
94{
Jens Axboeef635052012-02-15 22:24:19 +010095 struct timeval tv_s;
Jens Axboe656b1392009-07-01 23:02:10 +020096 struct timespec t;
97 int ret = 0;
98
Jens Axboeef635052012-02-15 22:24:19 +010099 fio_gettime(&tv_s, NULL);
100
Jens Axboeceab2ea2012-02-15 09:56:51 +0100101#ifdef FIO_HAVE_CLOCK_MONOTONIC
102 clock_gettime(CLOCK_MONOTONIC, &t);
103#else
Jens Axboed481e002009-12-04 09:56:32 +0100104 clock_gettime(CLOCK_REALTIME, &t);
Jens Axboeceab2ea2012-02-15 09:56:51 +0100105#endif
Jens Axboe656b1392009-07-01 23:02:10 +0200106 t.tv_sec += seconds;
107
108 pthread_mutex_lock(&mutex->lock);
109
110 while (!mutex->value && !ret) {
111 mutex->waiters++;
Jens Axboeef635052012-02-15 22:24:19 +0100112
113 /*
114 * Some platforms (FreeBSD 9?) seems to return timed out
115 * way too early, double check.
116 */
Jens Axboe656b1392009-07-01 23:02:10 +0200117 ret = pthread_cond_timedwait(&mutex->cond, &mutex->lock, &t);
Jens Axboeef635052012-02-15 22:24:19 +0100118 if (ret == ETIMEDOUT && !mutex_timed_out(&tv_s, seconds)) {
119 pthread_mutex_lock(&mutex->lock);
120 ret = 0;
121 }
122
Jens Axboe656b1392009-07-01 23:02:10 +0200123 mutex->waiters--;
124 }
125
126 if (!ret) {
127 mutex->value--;
128 pthread_mutex_unlock(&mutex->lock);
129 }
130
131 return ret;
132}
133
Jens Axboecdd18ad2008-02-27 18:58:00 +0100134void fio_mutex_down(struct fio_mutex *mutex)
Jens Axboe07739b52007-03-08 20:25:46 +0100135{
Jens Axboecdd18ad2008-02-27 18:58:00 +0100136 pthread_mutex_lock(&mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100137
138 while (!mutex->value) {
139 mutex->waiters++;
Jens Axboecdd18ad2008-02-27 18:58:00 +0100140 pthread_cond_wait(&mutex->cond, &mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100141 mutex->waiters--;
142 }
143
Jens Axboecdd18ad2008-02-27 18:58:00 +0100144 mutex->value--;
145 pthread_mutex_unlock(&mutex->lock);
Jens Axboe07739b52007-03-08 20:25:46 +0100146}
147
Jens Axboecdd18ad2008-02-27 18:58:00 +0100148void fio_mutex_up(struct fio_mutex *mutex)
Jens Axboe07739b52007-03-08 20:25:46 +0100149{
Jens Axboecdd18ad2008-02-27 18:58:00 +0100150 pthread_mutex_lock(&mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100151 read_barrier();
152 if (!mutex->value && mutex->waiters)
Jens Axboecdd18ad2008-02-27 18:58:00 +0100153 pthread_cond_signal(&mutex->cond);
154 mutex->value++;
155 pthread_mutex_unlock(&mutex->lock);
Jens Axboe07739b52007-03-08 20:25:46 +0100156}
Jens Axboe64d4d312008-03-03 10:36:27 +0100157
158void fio_mutex_down_write(struct fio_mutex *mutex)
159{
160 pthread_mutex_lock(&mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100161
162 while (mutex->value != 0) {
163 mutex->waiters++;
Jens Axboe64d4d312008-03-03 10:36:27 +0100164 pthread_cond_wait(&mutex->cond, &mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100165 mutex->waiters--;
166 }
167
Jens Axboe64d4d312008-03-03 10:36:27 +0100168 mutex->value--;
169 pthread_mutex_unlock(&mutex->lock);
170}
171
172void fio_mutex_down_read(struct fio_mutex *mutex)
173{
174 pthread_mutex_lock(&mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100175
176 while (mutex->value < 0) {
177 mutex->waiters++;
Jens Axboe64d4d312008-03-03 10:36:27 +0100178 pthread_cond_wait(&mutex->cond, &mutex->lock);
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100179 mutex->waiters--;
180 }
181
Jens Axboe64d4d312008-03-03 10:36:27 +0100182 mutex->value++;
183 pthread_mutex_unlock(&mutex->lock);
184}
185
186void fio_mutex_up_read(struct fio_mutex *mutex)
187{
188 pthread_mutex_lock(&mutex->lock);
189 mutex->value--;
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100190 read_barrier();
191 if (mutex->value >= 0 && mutex->waiters)
Jens Axboe64d4d312008-03-03 10:36:27 +0100192 pthread_cond_signal(&mutex->cond);
193 pthread_mutex_unlock(&mutex->lock);
194}
195
196void fio_mutex_up_write(struct fio_mutex *mutex)
197{
198 pthread_mutex_lock(&mutex->lock);
199 mutex->value++;
Jens Axboe4d4e80f2008-03-04 10:18:56 +0100200 read_barrier();
201 if (mutex->value >= 0 && mutex->waiters)
Jens Axboe64d4d312008-03-03 10:36:27 +0100202 pthread_cond_signal(&mutex->cond);
203 pthread_mutex_unlock(&mutex->lock);
204}