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