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