Rename fio_mutex into fio_sem
[fio.git] / fio_sem.c
CommitLineData
971caeb1
BVA
1#include <string.h>
2#include <sys/mman.h>
3#include <assert.h>
4
5#include "log.h"
6#include "fio_sem.h"
7#include "pshared.h"
8#include "os/os.h"
9#include "fio_time.h"
10#include "gettime.h"
11
12void __fio_sem_remove(struct fio_sem *sem)
13{
14 assert(sem->magic == FIO_SEM_MAGIC);
15 pthread_cond_destroy(&sem->cond);
16
17 /*
18 * Ensure any subsequent attempt to grab this semaphore will fail
19 * with an assert, instead of just silently hanging.
20 */
21 memset(sem, 0, sizeof(*sem));
22}
23
24void fio_sem_remove(struct fio_sem *sem)
25{
26 __fio_sem_remove(sem);
27 munmap((void *) sem, sizeof(*sem));
28}
29
30int __fio_sem_init(struct fio_sem *sem, int value)
31{
32 int ret;
33
34 sem->value = value;
35 sem->magic = FIO_SEM_MAGIC;
36
37 ret = mutex_cond_init_pshared(&sem->lock, &sem->cond);
38 if (ret)
39 return ret;
40
41 return 0;
42}
43
44struct fio_sem *fio_sem_init(int value)
45{
46 struct fio_sem *sem = NULL;
47
48 sem = (void *) mmap(NULL, sizeof(struct fio_sem),
49 PROT_READ | PROT_WRITE,
50 OS_MAP_ANON | MAP_SHARED, -1, 0);
51 if (sem == MAP_FAILED) {
52 perror("mmap semaphore");
53 return NULL;
54 }
55
56 if (!__fio_sem_init(sem, value))
57 return sem;
58
59 fio_sem_remove(sem);
60 return NULL;
61}
62
63static bool sem_timed_out(struct timespec *t, unsigned int msecs)
64{
65 struct timeval tv;
66 struct timespec now;
67
68 gettimeofday(&tv, NULL);
69 now.tv_sec = tv.tv_sec;
70 now.tv_nsec = tv.tv_usec * 1000;
71
72 return mtime_since(t, &now) >= msecs;
73}
74
75int fio_sem_down_timeout(struct fio_sem *sem, unsigned int msecs)
76{
77 struct timeval tv_s;
78 struct timespec base;
79 struct timespec t;
80 int ret = 0;
81
82 assert(sem->magic == FIO_SEM_MAGIC);
83
84 gettimeofday(&tv_s, NULL);
85 base.tv_sec = t.tv_sec = tv_s.tv_sec;
86 base.tv_nsec = t.tv_nsec = tv_s.tv_usec * 1000;
87
88 t.tv_sec += msecs / 1000;
89 t.tv_nsec += ((msecs * 1000000ULL) % 1000000000);
90 if (t.tv_nsec >= 1000000000) {
91 t.tv_nsec -= 1000000000;
92 t.tv_sec++;
93 }
94
95 pthread_mutex_lock(&sem->lock);
96
97 sem->waiters++;
98 while (!sem->value && !ret) {
99 /*
100 * Some platforms (FreeBSD 9?) seems to return timed out
101 * way too early, double check.
102 */
103 ret = pthread_cond_timedwait(&sem->cond, &sem->lock, &t);
104 if (ret == ETIMEDOUT && !sem_timed_out(&base, msecs))
105 ret = 0;
106 }
107 sem->waiters--;
108
109 if (!ret) {
110 sem->value--;
111 pthread_mutex_unlock(&sem->lock);
112 return 0;
113 }
114
115 pthread_mutex_unlock(&sem->lock);
116 return ret;
117}
118
119bool fio_sem_down_trylock(struct fio_sem *sem)
120{
121 bool ret = true;
122
123 assert(sem->magic == FIO_SEM_MAGIC);
124
125 pthread_mutex_lock(&sem->lock);
126 if (sem->value) {
127 sem->value--;
128 ret = false;
129 }
130 pthread_mutex_unlock(&sem->lock);
131
132 return ret;
133}
134
135void fio_sem_down(struct fio_sem *sem)
136{
137 assert(sem->magic == FIO_SEM_MAGIC);
138
139 pthread_mutex_lock(&sem->lock);
140
141 while (!sem->value) {
142 sem->waiters++;
143 pthread_cond_wait(&sem->cond, &sem->lock);
144 sem->waiters--;
145 }
146
147 sem->value--;
148 pthread_mutex_unlock(&sem->lock);
149}
150
151void fio_sem_up(struct fio_sem *sem)
152{
153 int do_wake = 0;
154
155 assert(sem->magic == FIO_SEM_MAGIC);
156
157 pthread_mutex_lock(&sem->lock);
158 read_barrier();
159 if (!sem->value && sem->waiters)
160 do_wake = 1;
161 sem->value++;
162
163 if (do_wake)
164 pthread_cond_signal(&sem->cond);
165
166 pthread_mutex_unlock(&sem->lock);
167}