15 #include "fork_impl.h"
17 #define malloc __libc_malloc
18 #define calloc __libc_calloc
27 static volatile int lock
[1];
28 volatile int *const __sem_open_lockptr
= lock
;
30 #define FLAGS (O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NONBLOCK)
32 sem_t
*sem_open(const char *name
, int flags
, ...)
37 int fd
, i
, e
, slot
, first
=1, cnt
, cs
;
43 char buf
[NAME_MAX
+10];
45 if (!(name
= __shm_mapname(name
, buf
)))
49 /* Allocate table if we don't have one yet */
50 if (!semtab
&& !(semtab
= calloc(sizeof *semtab
, SEM_NSEMS_MAX
))) {
55 /* Reserve a slot in case this semaphore is not mapped yet;
56 * this is necessary because there is no way to handle
57 * failures after creation of the file. */
59 for (cnt
=i
=0; i
<SEM_NSEMS_MAX
; i
++) {
60 cnt
+= semtab
[i
].refcnt
;
61 if (!semtab
[i
].sem
&& slot
< 0) slot
= i
;
63 /* Avoid possibility of overflow later */
64 if (cnt
== INT_MAX
|| slot
< 0) {
69 /* Dummy pointer to make a reservation */
70 semtab
[slot
].sem
= (sem_t
*)-1;
73 flags
&= (O_CREAT
|O_EXCL
);
75 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
77 /* Early failure check for exclusive open; otherwise the case
78 * where the semaphore already exists is expensive. */
79 if (flags
== (O_CREAT
|O_EXCL
) && access(name
, F_OK
) == 0) {
85 /* If exclusive mode is not requested, try opening an
86 * existing file first and fall back to creation. */
87 if (flags
!= (O_CREAT
|O_EXCL
)) {
88 fd
= open(name
, FLAGS
);
90 if (fstat(fd
, &st
) < 0 ||
91 (map
= mmap(0, sizeof(sem_t
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
101 if (!(flags
& O_CREAT
))
106 mode
= va_arg(ap
, mode_t
) & 0666;
107 value
= va_arg(ap
, unsigned);
109 if (value
> SEM_VALUE_MAX
) {
113 sem_init(&newsem
, 1, value
);
115 /* Create a temp file with the new semaphore contents
116 * and attempt to atomically link it as the new name */
117 clock_gettime(CLOCK_REALTIME
, &ts
);
118 snprintf(tmp
, sizeof(tmp
), "/dev/shm/tmp-%d", (int)ts
.tv_nsec
);
119 fd
= open(tmp
, O_CREAT
|O_EXCL
|FLAGS
, mode
);
121 if (errno
== EEXIST
) continue;
124 if (write(fd
, &newsem
, sizeof newsem
) != sizeof newsem
|| fstat(fd
, &st
) < 0 ||
125 (map
= mmap(0, sizeof(sem_t
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
131 e
= link(tmp
, name
) ? errno
: 0;
134 munmap(map
, sizeof(sem_t
));
135 /* Failure is only fatal when doing an exclusive open;
136 * otherwise, next iteration will try to open the
138 if (e
!= EEXIST
|| flags
== (O_CREAT
|O_EXCL
))
142 /* See if the newly mapped semaphore is already mapped. If
143 * so, unmap the new mapping and use the existing one. Otherwise,
144 * add it to the table of mapped semaphores. */
146 for (i
=0; i
<SEM_NSEMS_MAX
&& semtab
[i
].ino
!= st
.st_ino
; i
++);
147 if (i
<SEM_NSEMS_MAX
) {
148 munmap(map
, sizeof(sem_t
));
149 semtab
[slot
].sem
= 0;
153 semtab
[slot
].refcnt
++;
154 semtab
[slot
].sem
= map
;
155 semtab
[slot
].ino
= st
.st_ino
;
157 pthread_setcancelstate(cs
, 0);
161 pthread_setcancelstate(cs
, 0);
163 semtab
[slot
].sem
= 0;
168 int sem_close(sem_t
*sem
)
172 for (i
=0; i
<SEM_NSEMS_MAX
&& semtab
[i
].sem
!= sem
; i
++);
173 if (--semtab
[i
].refcnt
) {
180 munmap(sem
, sizeof *sem
);