Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(355)

Side by Side Diff: fusl/src/thread/sem_open.c

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

Powered by Google App Engine
This is Rietveld 408576698