Split mutex.c and .h each into three files
[fio.git] / mutex.c
1 #include <string.h>
2 #include <sys/mman.h>
3 #include <assert.h>
4
5 #include "log.h"
6 #include "mutex.h"
7 #include "pshared.h"
8 #include "os/os.h"
9 #include "fio_time.h"
10 #include "gettime.h"
11
12 void __fio_mutex_remove(struct fio_mutex *mutex)
13 {
14         assert(mutex->magic == FIO_MUTEX_MAGIC);
15         pthread_cond_destroy(&mutex->cond);
16
17         /*
18          * Ensure any subsequent attempt to grab this mutex will fail
19          * with an assert, instead of just silently hanging.
20          */
21         memset(mutex, 0, sizeof(*mutex));
22 }
23
24 void fio_mutex_remove(struct fio_mutex *mutex)
25 {
26         __fio_mutex_remove(mutex);
27         munmap((void *) mutex, sizeof(*mutex));
28 }
29
30 int __fio_mutex_init(struct fio_mutex *mutex, int value)
31 {
32         int ret;
33
34         mutex->value = value;
35         mutex->magic = FIO_MUTEX_MAGIC;
36
37         ret = mutex_cond_init_pshared(&mutex->lock, &mutex->cond);
38         if (ret)
39                 return ret;
40
41         return 0;
42 }
43
44 struct fio_mutex *fio_mutex_init(int value)
45 {
46         struct fio_mutex *mutex = NULL;
47
48         mutex = (void *) mmap(NULL, sizeof(struct fio_mutex),
49                                 PROT_READ | PROT_WRITE,
50                                 OS_MAP_ANON | MAP_SHARED, -1, 0);
51         if (mutex == MAP_FAILED) {
52                 perror("mmap mutex");
53                 return NULL;
54         }
55
56         if (!__fio_mutex_init(mutex, value))
57                 return mutex;
58
59         fio_mutex_remove(mutex);
60         return NULL;
61 }
62
63 static bool mutex_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
75 int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int msecs)
76 {
77         struct timeval tv_s;
78         struct timespec base;
79         struct timespec t;
80         int ret = 0;
81
82         assert(mutex->magic == FIO_MUTEX_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(&mutex->lock);
96
97         mutex->waiters++;
98         while (!mutex->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(&mutex->cond, &mutex->lock, &t);
104                 if (ret == ETIMEDOUT && !mutex_timed_out(&base, msecs))
105                         ret = 0;
106         }
107         mutex->waiters--;
108
109         if (!ret) {
110                 mutex->value--;
111                 pthread_mutex_unlock(&mutex->lock);
112                 return 0;
113         }
114
115         pthread_mutex_unlock(&mutex->lock);
116         return ret;
117 }
118
119 bool fio_mutex_down_trylock(struct fio_mutex *mutex)
120 {
121         bool ret = true;
122
123         assert(mutex->magic == FIO_MUTEX_MAGIC);
124
125         pthread_mutex_lock(&mutex->lock);
126         if (mutex->value) {
127                 mutex->value--;
128                 ret = false;
129         }
130         pthread_mutex_unlock(&mutex->lock);
131
132         return ret;
133 }
134
135 void fio_mutex_down(struct fio_mutex *mutex)
136 {
137         assert(mutex->magic == FIO_MUTEX_MAGIC);
138
139         pthread_mutex_lock(&mutex->lock);
140
141         while (!mutex->value) {
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_up(struct fio_mutex *mutex)
152 {
153         int do_wake = 0;
154
155         assert(mutex->magic == FIO_MUTEX_MAGIC);
156
157         pthread_mutex_lock(&mutex->lock);
158         read_barrier();
159         if (!mutex->value && mutex->waiters)
160                 do_wake = 1;
161         mutex->value++;
162
163         if (do_wake)
164                 pthread_cond_signal(&mutex->cond);
165
166         pthread_mutex_unlock(&mutex->lock);
167 }