21 static volatile int lock
[1];
23 #define FLAGS (O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NONBLOCK)
25 sem_t
*sem_open(const char *name
, int flags
, ...)
30 int fd
, i
, e
, slot
, first
=1, cnt
, cs
;
36 char buf
[NAME_MAX
+10];
38 if (!(name
= __shm_mapname(name
, buf
)))
42 /* Allocate table if we don't have one yet */
43 if (!semtab
&& !(semtab
= calloc(sizeof *semtab
, SEM_NSEMS_MAX
))) {
48 /* Reserve a slot in case this semaphore is not mapped yet;
49 * this is necessary because there is no way to handle
50 * failures after creation of the file. */
52 for (cnt
=i
=0; i
<SEM_NSEMS_MAX
; i
++) {
53 cnt
+= semtab
[i
].refcnt
;
54 if (!semtab
[i
].sem
&& slot
< 0) slot
= i
;
56 /* Avoid possibility of overflow later */
57 if (cnt
== INT_MAX
|| slot
< 0) {
62 /* Dummy pointer to make a reservation */
63 semtab
[slot
].sem
= (sem_t
*)-1;
66 flags
&= (O_CREAT
|O_EXCL
);
68 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
70 /* Early failure check for exclusive open; otherwise the case
71 * where the semaphore already exists is expensive. */
72 if (flags
== (O_CREAT
|O_EXCL
) && access(name
, F_OK
) == 0) {
78 /* If exclusive mode is not requested, try opening an
79 * existing file first and fall back to creation. */
80 if (flags
!= (O_CREAT
|O_EXCL
)) {
81 fd
= open(name
, FLAGS
);
83 if (fstat(fd
, &st
) < 0 ||
84 (map
= mmap(0, sizeof(sem_t
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
94 if (!(flags
& O_CREAT
))
99 mode
= va_arg(ap
, mode_t
) & 0666;
100 value
= va_arg(ap
, unsigned);
102 if (value
> SEM_VALUE_MAX
) {
106 sem_init(&newsem
, 1, value
);
108 /* Create a temp file with the new semaphore contents
109 * and attempt to atomically link it as the new name */
110 clock_gettime(CLOCK_REALTIME
, &ts
);
111 snprintf(tmp
, sizeof(tmp
), "/dev/shm/tmp-%d", (int)ts
.tv_nsec
);
112 fd
= open(tmp
, O_CREAT
|O_EXCL
|FLAGS
, mode
);
114 if (errno
== EEXIST
) continue;
117 if (write(fd
, &newsem
, sizeof newsem
) != sizeof newsem
|| fstat(fd
, &st
) < 0 ||
118 (map
= mmap(0, sizeof(sem_t
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
124 e
= link(tmp
, name
) ? errno
: 0;
127 munmap(map
, sizeof(sem_t
));
128 /* Failure is only fatal when doing an exclusive open;
129 * otherwise, next iteration will try to open the
131 if (e
!= EEXIST
|| flags
== (O_CREAT
|O_EXCL
))
135 /* See if the newly mapped semaphore is already mapped. If
136 * so, unmap the new mapping and use the existing one. Otherwise,
137 * add it to the table of mapped semaphores. */
139 for (i
=0; i
<SEM_NSEMS_MAX
&& semtab
[i
].ino
!= st
.st_ino
; i
++);
140 if (i
<SEM_NSEMS_MAX
) {
141 munmap(map
, sizeof(sem_t
));
142 semtab
[slot
].sem
= 0;
146 semtab
[slot
].refcnt
++;
147 semtab
[slot
].sem
= map
;
148 semtab
[slot
].ino
= st
.st_ino
;
150 pthread_setcancelstate(cs
, 0);
154 pthread_setcancelstate(cs
, 0);
156 semtab
[slot
].sem
= 0;
161 int sem_close(sem_t
*sem
)
165 for (i
=0; i
<SEM_NSEMS_MAX
&& semtab
[i
].sem
!= sem
; i
++);
166 if (!--semtab
[i
].refcnt
) {
171 munmap(sem
, sizeof *sem
);