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