16 #define malloc __libc_malloc
17 #define calloc __libc_calloc
26 static volatile int lock[1];
28 #define FLAGS (O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NONBLOCK)
30 sem_t *sem_open(const char *name, int flags, ...)
35 int fd, i, e, slot, first=1, cnt, cs;
41 char buf[NAME_MAX+10];
43 if (!(name = __shm_mapname(name, buf)))
47 /* Allocate table if we don't have one yet */
48 if (!semtab && !(semtab = calloc(sizeof *semtab, SEM_NSEMS_MAX))) {
53 /* Reserve a slot in case this semaphore is not mapped yet;
54 * this is necessary because there is no way to handle
55 * failures after creation of the file. */
57 for (cnt=i=0; i<SEM_NSEMS_MAX; i++) {
58 cnt += semtab[i].refcnt;
59 if (!semtab[i].sem && slot < 0) slot = i;
61 /* Avoid possibility of overflow later */
62 if (cnt == INT_MAX || slot < 0) {
67 /* Dummy pointer to make a reservation */
68 semtab[slot].sem = (sem_t *)-1;
71 flags &= (O_CREAT|O_EXCL);
73 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
75 /* Early failure check for exclusive open; otherwise the case
76 * where the semaphore already exists is expensive. */
77 if (flags == (O_CREAT|O_EXCL) && access(name, F_OK) == 0) {
83 /* If exclusive mode is not requested, try opening an
84 * existing file first and fall back to creation. */
85 if (flags != (O_CREAT|O_EXCL)) {
86 fd = open(name, FLAGS);
88 if (fstat(fd, &st) < 0 ||
89 (map = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
99 if (!(flags & O_CREAT))
104 mode = va_arg(ap, mode_t) & 0666;
105 value = va_arg(ap, unsigned);
107 if (value > SEM_VALUE_MAX) {
111 sem_init(&newsem, 1, value);
113 /* Create a temp file with the new semaphore contents
114 * and attempt to atomically link it as the new name */
115 clock_gettime(CLOCK_REALTIME, &ts);
116 snprintf(tmp, sizeof(tmp), "/dev/shm/tmp-%d", (int)ts.tv_nsec);
117 fd = open(tmp, O_CREAT|O_EXCL|FLAGS, mode);
119 if (errno == EEXIST) continue;
122 if (write(fd, &newsem, sizeof newsem) != sizeof newsem || fstat(fd, &st) < 0 ||
123 (map = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
129 e = link(tmp, name) ? errno : 0;
132 munmap(map, sizeof(sem_t));
133 /* Failure is only fatal when doing an exclusive open;
134 * otherwise, next iteration will try to open the
136 if (e != EEXIST || flags == (O_CREAT|O_EXCL))
140 /* See if the newly mapped semaphore is already mapped. If
141 * so, unmap the new mapping and use the existing one. Otherwise,
142 * add it to the table of mapped semaphores. */
144 for (i=0; i<SEM_NSEMS_MAX && semtab[i].ino != st.st_ino; i++);
145 if (i<SEM_NSEMS_MAX) {
146 munmap(map, sizeof(sem_t));
147 semtab[slot].sem = 0;
151 semtab[slot].refcnt++;
152 semtab[slot].sem = map;
153 semtab[slot].ino = st.st_ino;
155 pthread_setcancelstate(cs, 0);
159 pthread_setcancelstate(cs, 0);
161 semtab[slot].sem = 0;
166 int sem_close(sem_t *sem)
170 for (i=0; i<SEM_NSEMS_MAX && semtab[i].sem != sem; i++);
171 if (--semtab[i].refcnt) {
178 munmap(sem, sizeof *sem);