OLD | NEW |
1 #include <semaphore.h> | 1 #include <semaphore.h> |
2 #include <sys/mman.h> | 2 #include <sys/mman.h> |
3 #include <limits.h> | 3 #include <limits.h> |
4 #include <fcntl.h> | 4 #include <fcntl.h> |
5 #include <unistd.h> | 5 #include <unistd.h> |
6 #include <string.h> | 6 #include <string.h> |
7 #include <stdarg.h> | 7 #include <stdarg.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 #include <time.h> | 9 #include <time.h> |
10 #include <stdio.h> | 10 #include <stdio.h> |
11 #include <sys/stat.h> | 11 #include <sys/stat.h> |
12 #include <stdlib.h> | 12 #include <stdlib.h> |
13 #include <pthread.h> | 13 #include <pthread.h> |
14 #include "libc.h" | 14 #include "libc.h" |
15 | 15 |
16 char *__shm_mapname(const char *, char *); | 16 char* __shm_mapname(const char*, char*); |
17 | 17 |
18 static struct { | 18 static struct { |
19 » ino_t ino; | 19 ino_t ino; |
20 » sem_t *sem; | 20 sem_t* sem; |
21 » int refcnt; | 21 int refcnt; |
22 } *semtab; | 22 } * semtab; |
23 static volatile int lock[2]; | 23 static volatile int lock[2]; |
24 | 24 |
25 #define FLAGS (O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NONBLOCK) | 25 #define FLAGS (O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) |
26 | 26 |
27 sem_t *sem_open(const char *name, int flags, ...) | 27 sem_t* sem_open(const char* name, int flags, ...) { |
28 { | 28 va_list ap; |
29 » va_list ap; | 29 mode_t mode; |
30 » mode_t mode; | 30 unsigned value; |
31 » unsigned value; | 31 int fd, i, e, slot, first = 1, cnt, cs; |
32 » int fd, i, e, slot, first=1, cnt, cs; | 32 sem_t newsem; |
33 » sem_t newsem; | 33 void* map; |
34 » void *map; | 34 char tmp[64]; |
35 » char tmp[64]; | 35 struct timespec ts; |
36 » struct timespec ts; | 36 struct stat st; |
37 » struct stat st; | 37 char buf[NAME_MAX + 10]; |
38 » char buf[NAME_MAX+10]; | |
39 | 38 |
40 » if (!(name = __shm_mapname(name, buf))) | 39 if (!(name = __shm_mapname(name, buf))) |
41 » » return SEM_FAILED; | 40 return SEM_FAILED; |
42 | 41 |
43 » LOCK(lock); | 42 LOCK(lock); |
44 » /* Allocate table if we don't have one yet */ | 43 /* Allocate table if we don't have one yet */ |
45 » if (!semtab && !(semtab = calloc(sizeof *semtab, SEM_NSEMS_MAX))) { | 44 if (!semtab && !(semtab = calloc(sizeof *semtab, SEM_NSEMS_MAX))) { |
46 » » UNLOCK(lock); | 45 UNLOCK(lock); |
47 » » return SEM_FAILED; | 46 return SEM_FAILED; |
48 » } | 47 } |
49 | 48 |
50 » /* Reserve a slot in case this semaphore is not mapped yet; | 49 /* Reserve a slot in case this semaphore is not mapped yet; |
51 » * this is necessary because there is no way to handle | 50 * this is necessary because there is no way to handle |
52 » * failures after creation of the file. */ | 51 * failures after creation of the file. */ |
53 » slot = -1; | 52 slot = -1; |
54 » for (cnt=i=0; i<SEM_NSEMS_MAX; i++) { | 53 for (cnt = i = 0; i < SEM_NSEMS_MAX; i++) { |
55 » » cnt += semtab[i].refcnt; | 54 cnt += semtab[i].refcnt; |
56 » » if (!semtab[i].sem && slot < 0) slot = i; | 55 if (!semtab[i].sem && slot < 0) |
57 » } | 56 slot = i; |
58 » /* Avoid possibility of overflow later */ | 57 } |
59 » if (cnt == INT_MAX || slot < 0) { | 58 /* Avoid possibility of overflow later */ |
60 » » errno = EMFILE; | 59 if (cnt == INT_MAX || slot < 0) { |
61 » » UNLOCK(lock); | 60 errno = EMFILE; |
62 » » return SEM_FAILED; | 61 UNLOCK(lock); |
63 » } | 62 return SEM_FAILED; |
64 » /* Dummy pointer to make a reservation */ | 63 } |
65 » semtab[slot].sem = (sem_t *)-1; | 64 /* Dummy pointer to make a reservation */ |
66 » UNLOCK(lock); | 65 semtab[slot].sem = (sem_t*)-1; |
| 66 UNLOCK(lock); |
67 | 67 |
68 » flags &= (O_CREAT|O_EXCL); | 68 flags &= (O_CREAT | O_EXCL); |
69 | 69 |
70 » pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); | 70 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); |
71 | 71 |
72 » /* Early failure check for exclusive open; otherwise the case | 72 /* Early failure check for exclusive open; otherwise the case |
73 » * where the semaphore already exists is expensive. */ | 73 * where the semaphore already exists is expensive. */ |
74 » if (flags == (O_CREAT|O_EXCL) && access(name, F_OK) == 0) { | 74 if (flags == (O_CREAT | O_EXCL) && access(name, F_OK) == 0) { |
75 » » errno = EEXIST; | 75 errno = EEXIST; |
76 » » goto fail; | 76 goto fail; |
77 » } | 77 } |
78 | 78 |
79 » for (;;) { | 79 for (;;) { |
80 » » /* If exclusive mode is not requested, try opening an | 80 /* If exclusive mode is not requested, try opening an |
81 » » * existing file first and fall back to creation. */ | 81 * existing file first and fall back to creation. */ |
82 » » if (flags != (O_CREAT|O_EXCL)) { | 82 if (flags != (O_CREAT | O_EXCL)) { |
83 » » » fd = open(name, FLAGS); | 83 fd = open(name, FLAGS); |
84 » » » if (fd >= 0) { | 84 if (fd >= 0) { |
85 » » » » if (fstat(fd, &st) < 0 || | 85 if (fstat(fd, &st) < 0 || |
86 » » » » (map = mmap(0, sizeof(sem_t), PROT_READ|PROT
_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { | 86 (map = mmap(0, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, |
87 » » » » » close(fd); | 87 fd, 0)) == MAP_FAILED) { |
88 » » » » » goto fail; | 88 close(fd); |
89 » » » » } | 89 goto fail; |
90 » » » » close(fd); | 90 } |
91 » » » » break; | 91 close(fd); |
92 » » » } | 92 break; |
93 » » » if (errno != ENOENT) | 93 } |
94 » » » » goto fail; | 94 if (errno != ENOENT) |
95 » » } | 95 goto fail; |
96 » » if (!(flags & O_CREAT)) | 96 } |
97 » » » goto fail; | 97 if (!(flags & O_CREAT)) |
98 » » if (first) { | 98 goto fail; |
99 » » » first = 0; | 99 if (first) { |
100 » » » va_start(ap, flags); | 100 first = 0; |
101 » » » mode = va_arg(ap, mode_t) & 0666; | 101 va_start(ap, flags); |
102 » » » value = va_arg(ap, unsigned); | 102 mode = va_arg(ap, mode_t) & 0666; |
103 » » » va_end(ap); | 103 value = va_arg(ap, unsigned); |
104 » » » if (value > SEM_VALUE_MAX) { | 104 va_end(ap); |
105 » » » » errno = EINVAL; | 105 if (value > SEM_VALUE_MAX) { |
106 » » » » goto fail; | 106 errno = EINVAL; |
107 » » » } | 107 goto fail; |
108 » » » sem_init(&newsem, 1, value); | 108 } |
109 » » } | 109 sem_init(&newsem, 1, value); |
110 » » /* Create a temp file with the new semaphore contents | 110 } |
111 » » * and attempt to atomically link it as the new name */ | 111 /* Create a temp file with the new semaphore contents |
112 » » clock_gettime(CLOCK_REALTIME, &ts); | 112 * and attempt to atomically link it as the new name */ |
113 » » snprintf(tmp, sizeof(tmp), "/dev/shm/tmp-%d", (int)ts.tv_nsec); | 113 clock_gettime(CLOCK_REALTIME, &ts); |
114 » » fd = open(tmp, O_CREAT|O_EXCL|FLAGS, mode); | 114 snprintf(tmp, sizeof(tmp), "/dev/shm/tmp-%d", (int)ts.tv_nsec); |
115 » » if (fd < 0) { | 115 fd = open(tmp, O_CREAT | O_EXCL | FLAGS, mode); |
116 » » » if (errno == EEXIST) continue; | 116 if (fd < 0) { |
117 » » » goto fail; | 117 if (errno == EEXIST) |
118 » » } | 118 continue; |
119 » » if (write(fd, &newsem, sizeof newsem) != sizeof newsem || fstat(
fd, &st) < 0 || | 119 goto fail; |
120 » » (map = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE, MAP_SHAR
ED, fd, 0)) == MAP_FAILED) { | 120 } |
121 » » » close(fd); | 121 if (write(fd, &newsem, sizeof newsem) != sizeof newsem || |
122 » » » unlink(tmp); | 122 fstat(fd, &st) < 0 || |
123 » » » goto fail; | 123 (map = mmap(0, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, |
124 » » } | 124 0)) == MAP_FAILED) { |
125 » » close(fd); | 125 close(fd); |
126 » » e = link(tmp, name) ? errno : 0; | 126 unlink(tmp); |
127 » » unlink(tmp); | 127 goto fail; |
128 » » if (!e) break; | 128 } |
129 » » munmap(map, sizeof(sem_t)); | 129 close(fd); |
130 » » /* Failure is only fatal when doing an exclusive open; | 130 e = link(tmp, name) ? errno : 0; |
131 » » * otherwise, next iteration will try to open the | 131 unlink(tmp); |
132 » » * existing file. */ | 132 if (!e) |
133 » » if (e != EEXIST || flags == (O_CREAT|O_EXCL)) | 133 break; |
134 » » » goto fail; | 134 munmap(map, sizeof(sem_t)); |
135 » } | 135 /* Failure is only fatal when doing an exclusive open; |
| 136 * otherwise, next iteration will try to open the |
| 137 * existing file. */ |
| 138 if (e != EEXIST || flags == (O_CREAT | O_EXCL)) |
| 139 goto fail; |
| 140 } |
136 | 141 |
137 » /* See if the newly mapped semaphore is already mapped. If | 142 /* See if the newly mapped semaphore is already mapped. If |
138 » * so, unmap the new mapping and use the existing one. Otherwise, | 143 * so, unmap the new mapping and use the existing one. Otherwise, |
139 » * add it to the table of mapped semaphores. */ | 144 * add it to the table of mapped semaphores. */ |
140 » LOCK(lock); | 145 LOCK(lock); |
141 » for (i=0; i<SEM_NSEMS_MAX && semtab[i].ino != st.st_ino; i++); | 146 for (i = 0; i < SEM_NSEMS_MAX && semtab[i].ino != st.st_ino; i++) |
142 » if (i<SEM_NSEMS_MAX) { | 147 ; |
143 » » munmap(map, sizeof(sem_t)); | 148 if (i < SEM_NSEMS_MAX) { |
144 » » semtab[slot].sem = 0; | 149 munmap(map, sizeof(sem_t)); |
145 » » slot = i; | 150 semtab[slot].sem = 0; |
146 » » map = semtab[i].sem; | 151 slot = i; |
147 » } | 152 map = semtab[i].sem; |
148 » semtab[slot].refcnt++; | 153 } |
149 » semtab[slot].sem = map; | 154 semtab[slot].refcnt++; |
150 » semtab[slot].ino = st.st_ino; | 155 semtab[slot].sem = map; |
151 » UNLOCK(lock); | 156 semtab[slot].ino = st.st_ino; |
152 » pthread_setcancelstate(cs, 0); | 157 UNLOCK(lock); |
153 » return map; | 158 pthread_setcancelstate(cs, 0); |
| 159 return map; |
154 | 160 |
155 fail: | 161 fail: |
156 » pthread_setcancelstate(cs, 0); | 162 pthread_setcancelstate(cs, 0); |
157 » LOCK(lock); | 163 LOCK(lock); |
158 » semtab[slot].sem = 0; | 164 semtab[slot].sem = 0; |
159 » UNLOCK(lock); | 165 UNLOCK(lock); |
160 » return SEM_FAILED; | 166 return SEM_FAILED; |
161 } | 167 } |
162 | 168 |
163 int sem_close(sem_t *sem) | 169 int sem_close(sem_t* sem) { |
164 { | 170 int i; |
165 » int i; | 171 LOCK(lock); |
166 » LOCK(lock); | 172 for (i = 0; i < SEM_NSEMS_MAX && semtab[i].sem != sem; i++) |
167 » for (i=0; i<SEM_NSEMS_MAX && semtab[i].sem != sem; i++); | 173 ; |
168 » if (!--semtab[i].refcnt) { | 174 if (!--semtab[i].refcnt) { |
169 » » semtab[i].sem = 0; | 175 semtab[i].sem = 0; |
170 » » semtab[i].ino = 0; | 176 semtab[i].ino = 0; |
171 » } | 177 } |
172 » UNLOCK(lock); | 178 UNLOCK(lock); |
173 » munmap(sem, sizeof *sem); | 179 munmap(sem, sizeof *sem); |
174 » return 0; | 180 return 0; |
175 } | 181 } |
OLD | NEW |