Merge branch 'master' of ssh://brick.kernel.dk/data/git/fio
[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 <pthread.h>
8 #include <sys/mman.h>
9
10 #include "log.h"
11 #include "mutex.h"
12 #include "arch/arch.h"
13 #include "os/os.h"
14
15 void fio_mutex_remove(struct fio_mutex *mutex)
16 {
17         close(mutex->mutex_fd);
18         munmap((void *) mutex, sizeof(*mutex));
19 }
20
21 struct fio_mutex *fio_mutex_init(int value)
22 {
23         char mutex_name[] = "/tmp/.fio_mutex.XXXXXX";
24         struct fio_mutex *mutex = NULL;
25         pthread_mutexattr_t attr;
26         pthread_condattr_t cond;
27         int fd, ret, mflag;
28
29         fd = mkstemp(mutex_name);
30         if (fd < 0) {
31                 perror("open mutex");
32                 return NULL;
33         }
34
35         if (ftruncate(fd, sizeof(struct fio_mutex)) < 0) {
36                 perror("ftruncate mutex");
37                 goto err;
38         }
39
40         mutex = (void *) mmap(NULL, sizeof(struct fio_mutex),
41                                 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
42         if (mutex == MAP_FAILED) {
43                 perror("mmap mutex");
44                 close(fd);
45                 mutex = NULL;
46                 goto err;
47         }
48
49         unlink(mutex_name);
50         mutex->mutex_fd = fd;
51         mutex->value = value;
52
53         /*
54          * Not all platforms support process shared mutexes (FreeBSD)
55          */
56 #ifdef FIO_HAVE_PSHARED_MUTEX
57         mflag = PTHREAD_PROCESS_SHARED;
58 #else
59         mflag = PTHREAD_PROCESS_PRIVATE;
60 #endif
61
62         ret = pthread_mutexattr_init(&attr);
63         if (ret) {
64                 log_err("pthread_mutexattr_init: %s\n", strerror(ret));
65                 goto err;
66         }
67         ret = pthread_mutexattr_setpshared(&attr, mflag);
68         if (ret) {
69                 log_err("pthread_mutexattr_setpshared: %s\n", strerror(ret));
70                 goto err;
71         }
72
73         pthread_condattr_init(&cond);
74         pthread_condattr_setpshared(&cond, mflag);
75         pthread_cond_init(&mutex->cond, &cond);
76
77         ret = pthread_mutex_init(&mutex->lock, &attr);
78         if (ret) {
79                 log_err("pthread_mutex_init: %s\n", strerror(ret));
80                 goto err;
81         }
82
83         return mutex;
84 err:
85         if (mutex)
86                 fio_mutex_remove(mutex);
87
88         unlink(mutex_name);
89         return NULL;
90 }
91
92 int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int seconds)
93 {
94         struct timespec t;
95         int ret = 0;
96
97         clock_gettime(CLOCK_REALTIME, &t);
98         t.tv_sec += seconds;
99
100         pthread_mutex_lock(&mutex->lock);
101
102         while (!mutex->value && !ret) {
103                 mutex->waiters++;
104                 ret = pthread_cond_timedwait(&mutex->cond, &mutex->lock, &t);
105                 mutex->waiters--;
106         }
107
108         if (!ret) {
109                 mutex->value--;
110                 pthread_mutex_unlock(&mutex->lock);
111         }
112
113         return ret;
114 }
115
116 void fio_mutex_down(struct fio_mutex *mutex)
117 {
118         pthread_mutex_lock(&mutex->lock);
119
120         while (!mutex->value) {
121                 mutex->waiters++;
122                 pthread_cond_wait(&mutex->cond, &mutex->lock);
123                 mutex->waiters--;
124         }
125
126         mutex->value--;
127         pthread_mutex_unlock(&mutex->lock);
128 }
129
130 void fio_mutex_up(struct fio_mutex *mutex)
131 {
132         pthread_mutex_lock(&mutex->lock);
133         read_barrier();
134         if (!mutex->value && mutex->waiters)
135                 pthread_cond_signal(&mutex->cond);
136         mutex->value++;
137         pthread_mutex_unlock(&mutex->lock);
138 }
139
140 void fio_mutex_down_write(struct fio_mutex *mutex)
141 {
142         pthread_mutex_lock(&mutex->lock);
143
144         while (mutex->value != 0) {
145                 mutex->waiters++;
146                 pthread_cond_wait(&mutex->cond, &mutex->lock);
147                 mutex->waiters--;
148         }
149
150         mutex->value--;
151         pthread_mutex_unlock(&mutex->lock);
152 }
153
154 void fio_mutex_down_read(struct fio_mutex *mutex)
155 {
156         pthread_mutex_lock(&mutex->lock);
157
158         while (mutex->value < 0) {
159                 mutex->waiters++;
160                 pthread_cond_wait(&mutex->cond, &mutex->lock);
161                 mutex->waiters--;
162         }
163
164         mutex->value++;
165         pthread_mutex_unlock(&mutex->lock);
166 }
167
168 void fio_mutex_up_read(struct fio_mutex *mutex)
169 {
170         pthread_mutex_lock(&mutex->lock);
171         mutex->value--;
172         read_barrier();
173         if (mutex->value >= 0 && mutex->waiters)
174                 pthread_cond_signal(&mutex->cond);
175         pthread_mutex_unlock(&mutex->lock);
176 }
177
178 void fio_mutex_up_write(struct fio_mutex *mutex)
179 {
180         pthread_mutex_lock(&mutex->lock);
181         mutex->value++;
182         read_barrier();
183         if (mutex->value >= 0 && mutex->waiters)
184                 pthread_cond_signal(&mutex->cond);
185         pthread_mutex_unlock(&mutex->lock);
186 }