]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/posix_ipc.cc
Cygwin: FAQ: building-cygwin: accomodate autoconf changes
[newlib-cygwin.git] / winsup / cygwin / posix_ipc.cc
CommitLineData
7b487ba9
CV
1/* posix_ipc.cc: POSIX IPC API for Cygwin.
2
7b487ba9
CV
3This file is part of Cygwin.
4
5This software is a copyrighted work licensed under the terms of the
6Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7details. */
8
7b487ba9 9#include "winsup.h"
3748b3e8 10#include "shared_info.h"
8fbd574e 11#include "thread.h"
7b487ba9 12#include "path.h"
7b487ba9 13#include "cygtls.h"
e6fbf13e
CV
14#include "fhandler.h"
15#include "dtable.h"
16#include "cygheap.h"
7b487ba9 17#include "sigproc.h"
abbde487 18#include "ntdll.h"
7b487ba9
CV
19#include <sys/mman.h>
20#include <sys/param.h>
7b487ba9 21#include <stdlib.h>
7b487ba9 22#include <unistd.h>
7b487ba9 23#include <mqueue.h>
8fbd574e 24#include <semaphore.h>
7b487ba9 25
547ad329
CV
26/* The prefix_len is the length of the path prefix ncluding trailing "/"
27 (or "/sem." for semaphores) as well as the trailing NUL. */
cb7e1879 28static struct
7b487ba9
CV
29{
30 const char *prefix;
547ad329 31 const size_t prefix_len;
7b487ba9
CV
32 const char *description;
33} ipc_names[] = {
547ad329
CV
34 { "/dev/shm", 10, "POSIX shared memory object" },
35 { "/dev/mqueue", 13, "POSIX message queue" },
36 { "/dev/shm", 14, "POSIX semaphore" }
7b487ba9
CV
37};
38
39enum ipc_type_t
40{
41 shmem,
42 mqueue,
8fbd574e 43 semaphore
7b487ba9
CV
44};
45
46static bool
547ad329 47check_path (char *res_name, ipc_type_t type, const char *name, size_t len)
7b487ba9 48{
b32c31d1 49 /* Note that we require the existance of the appropriate /dev subdirectories
7b487ba9
CV
50 for POSIX IPC object support, similar to Linux (which supports the
51 directories, but doesn't require to mount them). We don't create
52 these directory here, that's the task of the installer. But we check
53 for existance and give ample warning. */
54 path_conv path (ipc_names[type].prefix, PC_SYM_NOFOLLOW);
55 if (path.error || !path.exists () || !path.isdir ())
56 {
57 small_printf (
58 "Warning: '%s' does not exists or is not a directory.\n\n"
59 "%ss require the existance of this directory.\n"
60 "Create the directory '%s' and set the permissions to 01777.\n"
61 "For instance on the command line: mkdir -m 01777 %s\n",
62 ipc_names[type].prefix, ipc_names[type].description,
63 ipc_names[type].prefix, ipc_names[type].prefix);
64 set_errno (EINVAL);
65 return false;
66 }
b32c31d1
CV
67 /* Name must not be empty, or just be a single slash, or start with more
68 than one slash. Same for backslash.
69 Apart from handling backslash like slash, the naming rules are identical
70 to Linux, including the names and requirements for subdirectories, if
71 the name contains further slashes. */
72 if (!name || (strchr ("/\\", name[0])
73 && (!name[1] || strchr ("/\\", name[1]))))
7b487ba9
CV
74 {
75 debug_printf ("Invalid %s name '%s'", ipc_names[type].description, name);
76 set_errno (EINVAL);
77 return false;
78 }
b32c31d1
CV
79 /* Skip leading (back-)slash. */
80 if (strchr ("/\\", name[0]))
81 ++name;
547ad329 82 if (len > PATH_MAX - ipc_names[type].prefix_len)
7b487ba9
CV
83 {
84 debug_printf ("%s name '%s' too long", ipc_names[type].description, name);
85 set_errno (ENAMETOOLONG);
86 return false;
87 }
8fbd574e
CV
88 __small_sprintf (res_name, "%s/%s%s", ipc_names[type].prefix,
89 type == semaphore ? "sem." : "",
b32c31d1 90 name);
7b487ba9
CV
91 return true;
92}
93
94static int
95ipc_mutex_init (HANDLE *pmtx, const char *name)
96{
3748b3e8
CV
97 WCHAR buf[MAX_PATH];
98 UNICODE_STRING uname;
99 OBJECT_ATTRIBUTES attr;
100 NTSTATUS status;
101
102 __small_swprintf (buf, L"mqueue/mtx_%s", name);
103 RtlInitUnicodeString (&uname, buf);
104 InitializeObjectAttributes (&attr, &uname,
105 OBJ_INHERIT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
106 get_shared_parent_dir (),
107 everyone_sd (CYG_MUTANT_ACCESS));
108 status = NtCreateMutant (pmtx, CYG_MUTANT_ACCESS, &attr, FALSE);
109 if (!NT_SUCCESS (status))
110 {
61522196 111 debug_printf ("NtCreateMutant: %y", status);
3748b3e8
CV
112 return geterrno_from_win_error (RtlNtStatusToDosError (status));
113 }
114 return 0;
7b487ba9
CV
115}
116
117static int
c6d1382a 118ipc_mutex_lock (HANDLE mtx, bool eintr)
7b487ba9 119{
c6d1382a
CV
120 switch (cygwait (mtx, cw_infinite, cw_cancel | cw_cancel_self
121 | (eintr ? cw_sig_eintr : cw_sig_restart)))
7b44665a 122 {
7b487ba9
CV
123 case WAIT_OBJECT_0:
124 case WAIT_ABANDONED_0:
125 return 0;
962f9a2c 126 case WAIT_SIGNALED:
7b487ba9
CV
127 set_errno (EINTR);
128 return 1;
129 default:
130 break;
7b44665a 131 }
7b487ba9
CV
132 return geterrno_from_win_error ();
133}
134
135static inline int
136ipc_mutex_unlock (HANDLE mtx)
137{
138 return ReleaseMutex (mtx) ? 0 : geterrno_from_win_error ();
139}
140
141static inline int
142ipc_mutex_close (HANDLE mtx)
143{
144 return CloseHandle (mtx) ? 0 : geterrno_from_win_error ();
145}
146
147static int
3748b3e8 148ipc_cond_init (HANDLE *pevt, const char *name, char sr)
7b487ba9 149{
3748b3e8
CV
150 WCHAR buf[MAX_PATH];
151 UNICODE_STRING uname;
152 OBJECT_ATTRIBUTES attr;
153 NTSTATUS status;
154
155 __small_swprintf (buf, L"mqueue/evt_%s%c", name, sr);
156 RtlInitUnicodeString (&uname, buf);
157 InitializeObjectAttributes (&attr, &uname,
158 OBJ_INHERIT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
159 get_shared_parent_dir (),
160 everyone_sd (CYG_EVENT_ACCESS));
161 status = NtCreateEvent (pevt, CYG_EVENT_ACCESS, &attr,
162 NotificationEvent, FALSE);
163 if (!NT_SUCCESS (status))
164 {
61522196 165 debug_printf ("NtCreateEvent: %y", status);
3748b3e8
CV
166 return geterrno_from_win_error (RtlNtStatusToDosError (status));
167 }
168 return 0;
7b487ba9
CV
169}
170
171static int
172ipc_cond_timedwait (HANDLE evt, HANDLE mtx, const struct timespec *abstime)
173{
962f9a2c 174 HANDLE w4[4] = { evt, };
86bf572e 175 DWORD cnt = 2;
206a6ee9 176 DWORD timer_idx = 0;
86bf572e
CV
177 int ret = 0;
178
c43e9340 179 wait_signal_arrived here (w4[1]);
a91ac4dc
CV
180 if ((w4[cnt] = pthread::get_cancel_event ()) != NULL)
181 ++cnt;
86bf572e
CV
182 if (abstime)
183 {
397526de 184 if (!valid_timespec (*abstime))
86bf572e
CV
185 return EINVAL;
186
187 /* If a timeout is set, we create a waitable timer to wait for.
188 This is the easiest way to handle the absolute timeout value, given
189 that NtSetTimer also takes absolute times and given the double
190 dependency on evt *and* mtx, which requires to call WFMO twice. */
191 NTSTATUS status;
192 LARGE_INTEGER duetime;
193
206a6ee9
CV
194 timer_idx = cnt++;
195 status = NtCreateTimer (&w4[timer_idx], TIMER_ALL_ACCESS, NULL,
86bf572e
CV
196 NotificationTimer);
197 if (!NT_SUCCESS (status))
198 return geterrno_from_nt_status (status);
0ff057d5 199 timespec_to_filetime (abstime, &duetime);
206a6ee9 200 status = NtSetTimer (w4[timer_idx], &duetime, NULL, NULL, FALSE, 0, NULL);
86bf572e
CV
201 if (!NT_SUCCESS (status))
202 {
206a6ee9 203 NtClose (w4[timer_idx]);
86bf572e
CV
204 return geterrno_from_nt_status (status);
205 }
7b487ba9 206 }
3748b3e8 207 ResetEvent (evt);
86bf572e
CV
208 if ((ret = ipc_mutex_unlock (mtx)) != 0)
209 return ret;
210 /* Everything's set up, so now wait for the event to be signalled. */
211restart1:
212 switch (WaitForMultipleObjects (cnt, w4, FALSE, INFINITE))
7b44665a 213 {
7b487ba9 214 case WAIT_OBJECT_0:
86bf572e
CV
215 break;
216 case WAIT_OBJECT_0 + 1:
217 if (_my_tls.call_signal_handler ())
218 goto restart1;
219 ret = EINTR;
220 break;
221 case WAIT_OBJECT_0 + 2:
206a6ee9 222 if (timer_idx != 2)
b86f999a 223 pthread::static_cancel_self ();
50ad1980 224 fallthrough;
206a6ee9 225 case WAIT_OBJECT_0 + 3:
86bf572e
CV
226 ret = ETIMEDOUT;
227 break;
7b487ba9 228 default:
86bf572e 229 ret = geterrno_from_win_error ();
7b487ba9 230 break;
7b44665a 231 }
86bf572e
CV
232 if (ret == 0)
233 {
234 /* At this point we need to lock the mutex. The wait is practically
235 the same as before, just that we now wait on the mutex instead of the
236 event. */
237 restart2:
238 w4[0] = mtx;
239 switch (WaitForMultipleObjects (cnt, w4, FALSE, INFINITE))
240 {
241 case WAIT_OBJECT_0:
242 case WAIT_ABANDONED_0:
243 break;
244 case WAIT_OBJECT_0 + 1:
245 if (_my_tls.call_signal_handler ())
246 goto restart2;
247 ret = EINTR;
248 break;
249 case WAIT_OBJECT_0 + 2:
206a6ee9
CV
250 if (timer_idx != 2)
251 pthread_testcancel ();
50ad1980 252 fallthrough;
206a6ee9 253 case WAIT_OBJECT_0 + 3:
86bf572e
CV
254 ret = ETIMEDOUT;
255 break;
256 default:
257 ret = geterrno_from_win_error ();
258 break;
259 }
260 }
206a6ee9 261 if (timer_idx)
86bf572e
CV
262 {
263 if (ret != ETIMEDOUT)
206a6ee9
CV
264 NtCancelTimer (w4[timer_idx], NULL);
265 NtClose (w4[timer_idx]);
86bf572e
CV
266 }
267 return ret;
7b487ba9
CV
268}
269
86bf572e 270static inline void
7b487ba9
CV
271ipc_cond_signal (HANDLE evt)
272{
86bf572e 273 SetEvent (evt);
7b487ba9
CV
274}
275
86bf572e 276static inline void
7b487ba9
CV
277ipc_cond_close (HANDLE evt)
278{
86bf572e 279 CloseHandle (evt);
7b487ba9
CV
280}
281
8fbd574e
CV
282class ipc_flock
283{
61522196 284 struct flock fl;
8fbd574e
CV
285
286public:
287 ipc_flock () { memset (&fl, 0, sizeof fl); }
288
289 int lock (int fd, size_t size)
290 {
291 fl.l_type = F_WRLCK;
292 fl.l_whence = SEEK_SET;
293 fl.l_start = 0;
294 fl.l_len = size;
fabfb1a1 295 return fcntl64 (fd, F_SETLKW, &fl);
8fbd574e
CV
296 }
297 int unlock (int fd)
298 {
299 if (!fl.l_len)
300 return 0;
301 fl.l_type = F_UNLCK;
fabfb1a1 302 return fcntl64 (fd, F_SETLKW, &fl);
8fbd574e
CV
303 }
304};
305
7b487ba9
CV
306/* POSIX shared memory object implementation. */
307
308extern "C" int
309shm_open (const char *name, int oflag, mode_t mode)
310{
547ad329
CV
311 size_t len = strlen (name);
312 char shmname[ipc_names[shmem].prefix_len + len];
7b487ba9 313
547ad329 314 if (!check_path (shmname, shmem, name, len))
7b487ba9
CV
315 return -1;
316
317 /* Check for valid flags. */
318 if (((oflag & O_ACCMODE) != O_RDONLY && (oflag & O_ACCMODE) != O_RDWR)
319 || (oflag & ~(O_ACCMODE | O_CREAT | O_EXCL | O_TRUNC)))
320 {
321 debug_printf ("Invalid oflag 0%o", oflag);
322 set_errno (EINVAL);
323 return -1;
324 }
325
e70fdfb9 326 return open (shmname, oflag | O_CLOEXEC, mode & 0777);
7b487ba9
CV
327}
328
329extern "C" int
330shm_unlink (const char *name)
331{
547ad329
CV
332 size_t len = strlen (name);
333 char shmname[ipc_names[shmem].prefix_len + len];
7b487ba9 334
547ad329 335 if (!check_path (shmname, shmem, name, len))
7b487ba9
CV
336 return -1;
337
338 return unlink (shmname);
339}
340
341/* The POSIX message queue implementation is based on W. Richard STEVENS
342 implementation, just tweaked for Cygwin. The main change is
343 the usage of Windows mutexes and events instead of using the pthread
344 synchronization objects. The pathname is massaged so that the
345 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
346 are implemented additionally. */
347
61522196
CV
348/* The mq_attr structure is defined using long datatypes per POSIX.
349 For interoperability reasons between 32 and 64 bit processes, we have
350 to make sure to use a unified structure layout in the message queue file.
351 That's what the mq_fattr is, the in-file representation of the mq_attr
352 struct. */
353#pragma pack (push, 4)
354struct mq_fattr
355{
356 uint32_t mq_flags;
357 uint32_t mq_maxmsg;
358 uint32_t mq_msgsize;
359 uint32_t mq_curmsgs;
360};
361
7b487ba9
CV
362struct mq_hdr
363{
61522196
CV
364 struct mq_fattr mqh_attr; /* the queue's attributes */
365 int32_t mqh_head; /* index of first message */
366 int32_t mqh_free; /* index of first free message */
367 int32_t mqh_nwait; /* #threads blocked in mq_receive() */
93162be5 368 pid_t mqh_pid; /* nonzero PID if mqh_event set */
8fbd574e 369 char mqh_uname[36]; /* unique name used to identify synchronization
7b44665a 370 objects connected to this queue */
61522196
CV
371 union {
372 struct sigevent mqh_event; /* for mq_notify() */
373 /* Make sure sigevent takes the same space on 32 and 64 bit systems.
374 Other than that, it doesn't need to be compatible since only
375 one process can be notified at a time. */
376 uint64_t mqh_placeholder[8];
377 };
378 uint32_t mqh_magic; /* Expect MQI_MAGIC here, otherwise it's
379 an old-style message queue. */
7b487ba9
CV
380};
381
382struct msg_hdr
383{
61522196
CV
384 int32_t msg_next; /* index of next on linked list */
385 int32_t msg_len; /* actual length */
93162be5 386 unsigned int msg_prio; /* priority */
7b487ba9 387};
61522196 388#pragma pack (pop)
7b487ba9
CV
389
390struct mq_info
391{
93162be5 392 struct mq_hdr *mqi_hdr; /* start of mmap'ed region */
61522196 393 uint32_t mqi_magic; /* magic number if open */
93162be5
CV
394 int mqi_flags; /* flags for this process */
395 HANDLE mqi_lock; /* mutex lock */
3748b3e8
CV
396 HANDLE mqi_waitsend; /* and condition variable for full queue */
397 HANDLE mqi_waitrecv; /* and condition variable for empty queue */
7b487ba9
CV
398};
399
400#define MQI_MAGIC 0x98765432UL
401
402#define MSGSIZE(i) roundup((i), sizeof(long))
403
404#define MAX_TRIES 10 /* for waiting for initialization */
405
406struct mq_attr defattr = { 0, 10, 8192, 0 }; /* Linux defaults. */
407
61522196
CV
408extern "C" off_t lseek64 (int, off_t, int);
409extern "C" void *mmap64 (void *, size_t, int, int, int, off_t);
7b487ba9
CV
410
411extern "C" mqd_t
412mq_open (const char *name, int oflag, ...)
413{
3f3bd101 414 int i, fd = -1, nonblock, created = 0;
7b487ba9 415 long msgsize, index;
61522196 416 off_t filesize = 0;
7b487ba9
CV
417 va_list ap;
418 mode_t mode;
3f3bd101 419 int8_t *mptr = (int8_t *) MAP_FAILED;
61522196 420 struct stat statbuff;
7b487ba9
CV
421 struct mq_hdr *mqhdr;
422 struct msg_hdr *msghdr;
423 struct mq_attr *attr;
3f3bd101 424 struct mq_info *mqinfo = NULL;
8fbd574e 425 LUID luid;
7b487ba9 426
547ad329
CV
427 size_t len = strlen (name);
428 char mqname[ipc_names[mqueue].prefix_len + len];
429
430 if (!check_path (mqname, mqueue, name, len))
7b487ba9
CV
431 return (mqd_t) -1;
432
3f3bd101
CV
433 __try
434 {
435 oflag &= (O_CREAT | O_EXCL | O_NONBLOCK);
436 nonblock = oflag & O_NONBLOCK;
437 oflag &= ~O_NONBLOCK;
7b487ba9 438
3f3bd101
CV
439 again:
440 if (oflag & O_CREAT)
441 {
442 va_start (ap, oflag); /* init ap to final named argument */
443 mode = va_arg (ap, mode_t) & ~S_IXUSR;
444 attr = va_arg (ap, struct mq_attr *);
445 va_end (ap);
446
447 /* Open and specify O_EXCL and user-execute */
448 fd = open (mqname, oflag | O_EXCL | O_RDWR | O_CLOEXEC,
449 mode | S_IXUSR);
450 if (fd < 0)
451 {
452 if (errno == EEXIST && (oflag & O_EXCL) == 0)
453 goto exists; /* already exists, OK */
454 return (mqd_t) -1;
455 }
456 created = 1;
457 /* First one to create the file initializes it */
458 if (attr == NULL)
459 attr = &defattr;
460 /* Check minimum and maximum values. The max values are pretty much
461 arbitrary, taken from the linux mq_overview man page. However,
462 these max values make sure that the internal mq_fattr structure
463 can use 32 bit types. */
464 else if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > 32768
465 || attr->mq_msgsize <= 0 || attr->mq_msgsize > 1048576)
466 {
467 set_errno (EINVAL);
468 __leave;
469 }
470 /* Calculate and set the file size */
471 msgsize = MSGSIZE (attr->mq_msgsize);
472 filesize = sizeof (struct mq_hdr)
473 + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize));
474 if (lseek64 (fd, filesize - 1, SEEK_SET) == -1)
475 __leave;
476 if (write (fd, "", 1) == -1)
477 __leave;
478
479 /* Memory map the file */
480 mptr = (int8_t *) mmap64 (NULL, (size_t) filesize,
481 PROT_READ | PROT_WRITE,
482 MAP_SHARED, fd, 0);
483 if (mptr == (int8_t *) MAP_FAILED)
484 __leave;
485
486 /* Allocate one mq_info{} for the queue */
487 if (!(mqinfo = (struct mq_info *)
488 calloc (1, sizeof (struct mq_info))))
489 __leave;
490 mqinfo->mqi_hdr = mqhdr = (struct mq_hdr *) mptr;
491 mqinfo->mqi_magic = MQI_MAGIC;
492 mqinfo->mqi_flags = nonblock;
493
494 /* Initialize header at beginning of file */
495 /* Create free list with all messages on it */
496 mqhdr->mqh_attr.mq_flags = 0;
497 mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg;
498 mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize;
499 mqhdr->mqh_attr.mq_curmsgs = 0;
500 mqhdr->mqh_nwait = 0;
501 mqhdr->mqh_pid = 0;
502 NtAllocateLocallyUniqueId (&luid);
503 __small_sprintf (mqhdr->mqh_uname, "%016X%08x%08x",
504 hash_path_name (0,mqname),
505 luid.HighPart, luid.LowPart);
506 mqhdr->mqh_head = 0;
507 mqhdr->mqh_magic = MQI_MAGIC;
508 index = sizeof (struct mq_hdr);
509 mqhdr->mqh_free = index;
510 for (i = 0; i < attr->mq_maxmsg - 1; i++)
511 {
512 msghdr = (struct msg_hdr *) &mptr[index];
513 index += sizeof (struct msg_hdr) + msgsize;
514 msghdr->msg_next = index;
515 }
516 msghdr = (struct msg_hdr *) &mptr[index];
517 msghdr->msg_next = 0; /* end of free list */
7b487ba9 518
3f3bd101
CV
519 /* Initialize mutex & condition variables */
520 i = ipc_mutex_init (&mqinfo->mqi_lock, mqhdr->mqh_uname);
521 if (i != 0)
522 {
523 set_errno (i);
524 __leave;
525 }
526 i = ipc_cond_init (&mqinfo->mqi_waitsend, mqhdr->mqh_uname, 'S');
527 if (i != 0)
528 {
529 set_errno (i);
530 __leave;
531 }
532 i = ipc_cond_init (&mqinfo->mqi_waitrecv, mqhdr->mqh_uname, 'R');
533 if (i != 0)
534 {
535 set_errno (i);
536 __leave;
537 }
538 /* Initialization complete, turn off user-execute bit */
539 if (fchmod (fd, mode) == -1)
540 __leave;
541 close (fd);
542 return ((mqd_t) mqinfo);
543 }
544
545 exists:
546 /* Open the file then memory map */
547 if ((fd = open (mqname, O_RDWR | O_CLOEXEC)) < 0)
7b44665a 548 {
3f3bd101
CV
549 if (errno == ENOENT && (oflag & O_CREAT))
550 goto again;
551 __leave;
7b487ba9 552 }
3f3bd101
CV
553 /* Make certain initialization is complete */
554 for (i = 0; i < MAX_TRIES; i++)
7b487ba9 555 {
3f3bd101
CV
556 if (stat64 (mqname, &statbuff) == -1)
557 {
558 if (errno == ENOENT && (oflag & O_CREAT))
559 {
560 close (fd);
561 fd = -1;
562 goto again;
563 }
564 __leave;
565 }
566 if ((statbuff.st_mode & S_IXUSR) == 0)
567 break;
568 sleep (1);
569 }
570 if (i == MAX_TRIES)
571 {
572 set_errno (ETIMEDOUT);
573 __leave;
7b487ba9 574 }
7b487ba9 575
3f3bd101 576 filesize = statbuff.st_size;
7b487ba9
CV
577 mptr = (int8_t *) mmap64 (NULL, (size_t) filesize, PROT_READ | PROT_WRITE,
578 MAP_SHARED, fd, 0);
579 if (mptr == (int8_t *) MAP_FAILED)
3f3bd101
CV
580 __leave;
581 close (fd);
582 fd = -1;
7b487ba9 583
3f3bd101 584 /* Allocate one mq_info{} for each open */
3748b3e8 585 if (!(mqinfo = (struct mq_info *) calloc (1, sizeof (struct mq_info))))
3f3bd101 586 __leave;
7b487ba9 587 mqinfo->mqi_hdr = mqhdr = (struct mq_hdr *) mptr;
3f3bd101 588 if (mqhdr->mqh_magic != MQI_MAGIC)
7b487ba9 589 {
3f3bd101
CV
590 system_printf (
591 "Old message queue \"%s\" detected!\n"
592 "This file is not usable as message queue anymore due to changes in the "
593 "internal file layout. Please remove the file and try again.", mqname);
594 set_errno (EACCES);
595 __leave;
7b487ba9 596 }
3f3bd101
CV
597 mqinfo->mqi_magic = MQI_MAGIC;
598 mqinfo->mqi_flags = nonblock;
7b487ba9 599
3f3bd101 600 /* Initialize mutex & condition variable */
93162be5 601 i = ipc_mutex_init (&mqinfo->mqi_lock, mqhdr->mqh_uname);
7b487ba9 602 if (i != 0)
3f3bd101
CV
603 {
604 set_errno (i);
605 __leave;
606 }
3748b3e8
CV
607 i = ipc_cond_init (&mqinfo->mqi_waitsend, mqhdr->mqh_uname, 'S');
608 if (i != 0)
3f3bd101
CV
609 {
610 set_errno (i);
611 __leave;
612 }
3748b3e8 613 i = ipc_cond_init (&mqinfo->mqi_waitrecv, mqhdr->mqh_uname, 'R');
7b487ba9 614 if (i != 0)
7b487ba9 615 {
3f3bd101
CV
616 set_errno (i);
617 __leave;
7b487ba9 618 }
3f3bd101 619 return (mqd_t) mqinfo;
7b487ba9 620 }
3f3bd101
CV
621 __except (EFAULT) {}
622 __endtry
7b487ba9
CV
623 /* Don't let following function calls change errno */
624 save_errno save;
7b487ba9
CV
625 if (created)
626 unlink (mqname);
627 if (mptr != (int8_t *) MAP_FAILED)
628 munmap((void *) mptr, (size_t) filesize);
629 if (mqinfo)
3748b3e8
CV
630 {
631 if (mqinfo->mqi_lock)
b86f999a 632 ipc_mutex_close (mqinfo->mqi_lock);
3748b3e8
CV
633 if (mqinfo->mqi_waitsend)
634 ipc_cond_close (mqinfo->mqi_waitsend);
635 if (mqinfo->mqi_waitrecv)
636 ipc_cond_close (mqinfo->mqi_waitrecv);
637 free (mqinfo);
638 }
599d462d
CV
639 if (fd >= 0)
640 close (fd);
7b487ba9
CV
641 return (mqd_t) -1;
642}
643
644extern "C" int
645mq_getattr (mqd_t mqd, struct mq_attr *mqstat)
646{
647 int n;
648 struct mq_hdr *mqhdr;
61522196 649 struct mq_fattr *attr;
7b487ba9 650 struct mq_info *mqinfo;
7b44665a 651
3f3bd101 652 __try
7b487ba9 653 {
3f3bd101
CV
654 mqinfo = (struct mq_info *) mqd;
655 if (mqinfo->mqi_magic != MQI_MAGIC)
656 {
657 set_errno (EBADF);
658 __leave;
659 }
660 mqhdr = mqinfo->mqi_hdr;
661 attr = &mqhdr->mqh_attr;
c6d1382a 662 if ((n = ipc_mutex_lock (mqinfo->mqi_lock, false)) != 0)
3f3bd101
CV
663 {
664 errno = n;
665 __leave;
666 }
667 mqstat->mq_flags = mqinfo->mqi_flags; /* per-open */
668 mqstat->mq_maxmsg = attr->mq_maxmsg; /* remaining three per-queue */
669 mqstat->mq_msgsize = attr->mq_msgsize;
670 mqstat->mq_curmsgs = attr->mq_curmsgs;
7b487ba9 671
3f3bd101
CV
672 ipc_mutex_unlock (mqinfo->mqi_lock);
673 return 0;
674 }
675 __except (EBADF) {}
676 __endtry
677 return -1;
7b44665a 678}
7b487ba9
CV
679
680extern "C" int
681mq_setattr (mqd_t mqd, const struct mq_attr *mqstat, struct mq_attr *omqstat)
682{
683 int n;
7b44665a 684 struct mq_hdr *mqhdr;
61522196 685 struct mq_fattr *attr;
7b487ba9
CV
686 struct mq_info *mqinfo;
687
3f3bd101 688 __try
7b487ba9 689 {
3f3bd101
CV
690 mqinfo = (struct mq_info *) mqd;
691 if (mqinfo->mqi_magic != MQI_MAGIC)
692 {
693 set_errno (EBADF);
694 __leave;
695 }
696 mqhdr = mqinfo->mqi_hdr;
697 attr = &mqhdr->mqh_attr;
c6d1382a 698 if ((n = ipc_mutex_lock (mqinfo->mqi_lock, false)) != 0)
3f3bd101
CV
699 {
700 errno = n;
701 __leave;
702 }
7b487ba9 703
3f3bd101
CV
704 if (omqstat != NULL)
705 {
706 omqstat->mq_flags = mqinfo->mqi_flags; /* previous attributes */
707 omqstat->mq_maxmsg = attr->mq_maxmsg;
708 omqstat->mq_msgsize = attr->mq_msgsize;
709 omqstat->mq_curmsgs = attr->mq_curmsgs; /* and current status */
710 }
7b487ba9 711
3f3bd101
CV
712 if (mqstat->mq_flags & O_NONBLOCK)
713 mqinfo->mqi_flags |= O_NONBLOCK;
714 else
715 mqinfo->mqi_flags &= ~O_NONBLOCK;
7b487ba9 716
3f3bd101
CV
717 ipc_mutex_unlock (mqinfo->mqi_lock);
718 return 0;
719 }
720 __except (EBADF) {}
721 __endtry
722 return -1;
7b487ba9
CV
723}
724
725extern "C" int
726mq_notify (mqd_t mqd, const struct sigevent *notification)
727{
728 int n;
729 pid_t pid;
730 struct mq_hdr *mqhdr;
731 struct mq_info *mqinfo;
7b44665a 732
3f3bd101 733 __try
7b487ba9 734 {
3f3bd101
CV
735 mqinfo = (struct mq_info *) mqd;
736 if (mqinfo->mqi_magic != MQI_MAGIC)
737 {
738 set_errno (EBADF);
739 __leave;
740 }
741 mqhdr = mqinfo->mqi_hdr;
c6d1382a 742 if ((n = ipc_mutex_lock (mqinfo->mqi_lock, false)) != 0)
3f3bd101
CV
743 {
744 errno = n;
745 __leave;
746 }
7b44665a 747
3f3bd101
CV
748 pid = getpid ();
749 if (!notification)
7b487ba9 750 {
3f3bd101
CV
751 if (mqhdr->mqh_pid == pid)
752 mqhdr->mqh_pid = 0; /* unregister calling process */
753 }
754 else
755 {
756 if (mqhdr->mqh_pid != 0)
7b487ba9 757 {
3f3bd101
CV
758 if (kill (mqhdr->mqh_pid, 0) != -1 || errno != ESRCH)
759 {
760 set_errno (EBUSY);
761 ipc_mutex_unlock (mqinfo->mqi_lock);
762 __leave;
763 }
7b487ba9 764 }
3f3bd101
CV
765 mqhdr->mqh_pid = pid;
766 mqhdr->mqh_event = *notification;
7b487ba9 767 }
3f3bd101
CV
768 ipc_mutex_unlock (mqinfo->mqi_lock);
769 return 0;
7b44665a 770 }
3f3bd101
CV
771 __except (EBADF) {}
772 __endtry
773 return -1;
7b44665a 774}
7b487ba9
CV
775
776static int
777_mq_send (mqd_t mqd, const char *ptr, size_t len, unsigned int prio,
778 const struct timespec *abstime)
779{
780 int n;
781 long index, freeindex;
782 int8_t *mptr;
783 struct sigevent *sigev;
784 struct mq_hdr *mqhdr;
61522196 785 struct mq_fattr *attr;
7b487ba9 786 struct msg_hdr *msghdr, *nmsghdr, *pmsghdr;
3f3bd101
CV
787 struct mq_info *mqinfo = NULL;
788 bool ipc_mutex_locked = false;
789 int ret = -1;
7b487ba9 790
74f9ac5b
CV
791 pthread_testcancel ();
792
3f3bd101 793 __try
7b487ba9 794 {
3f3bd101
CV
795 mqinfo = (struct mq_info *) mqd;
796 if (mqinfo->mqi_magic != MQI_MAGIC)
797 {
798 set_errno (EBADF);
799 __leave;
800 }
801 if (prio > MQ_PRIO_MAX)
802 {
803 set_errno (EINVAL);
804 __leave;
805 }
7b487ba9 806
3f3bd101
CV
807 mqhdr = mqinfo->mqi_hdr; /* struct pointer */
808 mptr = (int8_t *) mqhdr; /* byte pointer */
809 attr = &mqhdr->mqh_attr;
c6d1382a 810 if ((n = ipc_mutex_lock (mqinfo->mqi_lock, true)) != 0)
7b487ba9 811 {
3f3bd101
CV
812 errno = n;
813 __leave;
7b487ba9 814 }
3f3bd101
CV
815 ipc_mutex_locked = true;
816 if (len > (size_t) attr->mq_msgsize)
7b487ba9 817 {
3f3bd101
CV
818 set_errno (EMSGSIZE);
819 __leave;
7b487ba9 820 }
3f3bd101 821 if (attr->mq_curmsgs == 0)
b994b837 822 {
3f3bd101 823 if (mqhdr->mqh_pid != 0 && mqhdr->mqh_nwait == 0)
b994b837 824 {
3f3bd101
CV
825 sigev = &mqhdr->mqh_event;
826 if (sigev->sigev_notify == SIGEV_SIGNAL)
827 sigqueue (mqhdr->mqh_pid, sigev->sigev_signo,
828 sigev->sigev_value);
829 mqhdr->mqh_pid = 0; /* unregister */
830 }
831 }
832 else if (attr->mq_curmsgs >= attr->mq_maxmsg)
833 {
834 /* Queue is full */
835 if (mqinfo->mqi_flags & O_NONBLOCK)
836 {
837 set_errno (EAGAIN);
838 __leave;
839 }
840 /* Wait for room for one message on the queue */
841 while (attr->mq_curmsgs >= attr->mq_maxmsg)
842 {
843 int ret = ipc_cond_timedwait (mqinfo->mqi_waitsend,
844 mqinfo->mqi_lock, abstime);
845 if (ret != 0)
846 {
847 set_errno (ret);
848 __leave;
849 }
b994b837
CV
850 }
851 }
7b487ba9 852
3f3bd101
CV
853 /* nmsghdr will point to new message */
854 if ((freeindex = mqhdr->mqh_free) == 0)
855 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr->mq_curmsgs);
7b487ba9 856
3f3bd101
CV
857 nmsghdr = (struct msg_hdr *) &mptr[freeindex];
858 nmsghdr->msg_prio = prio;
859 nmsghdr->msg_len = len;
860 memcpy (nmsghdr + 1, ptr, len); /* copy message from caller */
861 mqhdr->mqh_free = nmsghdr->msg_next; /* new freelist head */
7b487ba9 862
3f3bd101
CV
863 /* Find right place for message in linked list */
864 index = mqhdr->mqh_head;
865 pmsghdr = (struct msg_hdr *) &(mqhdr->mqh_head);
866 while (index)
7b487ba9 867 {
3f3bd101
CV
868 msghdr = (struct msg_hdr *) &mptr[index];
869 if (prio > msghdr->msg_prio)
870 {
871 nmsghdr->msg_next = index;
872 pmsghdr->msg_next = freeindex;
873 break;
874 }
875 index = msghdr->msg_next;
876 pmsghdr = msghdr;
877 }
878 if (index == 0)
879 {
880 /* Queue was empty or new goes at end of list */
7b487ba9 881 pmsghdr->msg_next = freeindex;
3f3bd101 882 nmsghdr->msg_next = 0;
7b487ba9 883 }
3f3bd101
CV
884 /* Wake up anyone blocked in mq_receive waiting for a message */
885 if (attr->mq_curmsgs == 0)
886 ipc_cond_signal (mqinfo->mqi_waitrecv);
887 attr->mq_curmsgs++;
7b487ba9 888
3f3bd101
CV
889 ipc_mutex_unlock (mqinfo->mqi_lock);
890 ret = 0;
891 }
892 __except (EBADF) {}
893 __endtry
894 if (ipc_mutex_locked)
895 ipc_mutex_unlock (mqinfo->mqi_lock);
896 return ret;
7b487ba9
CV
897}
898
899extern "C" int
900mq_send (mqd_t mqd, const char *ptr, size_t len, unsigned int prio)
901{
902 return _mq_send (mqd, ptr, len, prio, NULL);
903}
904
905extern "C" int
906mq_timedsend (mqd_t mqd, const char *ptr, size_t len, unsigned int prio,
907 const struct timespec *abstime)
908{
909 return _mq_send (mqd, ptr, len, prio, abstime);
910}
911
912static ssize_t
913_mq_receive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop,
914 const struct timespec *abstime)
915{
916 int n;
917 long index;
918 int8_t *mptr;
3f3bd101 919 ssize_t len = -1;
7b44665a 920 struct mq_hdr *mqhdr;
61522196 921 struct mq_fattr *attr;
7b487ba9 922 struct msg_hdr *msghdr;
3f3bd101
CV
923 struct mq_info *mqinfo = (struct mq_info *) mqd;
924 bool ipc_mutex_locked = false;
7b487ba9 925
74f9ac5b
CV
926 pthread_testcancel ();
927
3f3bd101 928 __try
7b487ba9 929 {
3f3bd101
CV
930 if (mqinfo->mqi_magic != MQI_MAGIC)
931 {
932 set_errno (EBADF);
933 __leave;
934 }
935 mqhdr = mqinfo->mqi_hdr; /* struct pointer */
936 mptr = (int8_t *) mqhdr; /* byte pointer */
937 attr = &mqhdr->mqh_attr;
c6d1382a 938 if ((n = ipc_mutex_lock (mqinfo->mqi_lock, true)) != 0)
3f3bd101
CV
939 {
940 errno = n;
941 __leave;
942 }
943 ipc_mutex_locked = true;
944 if (maxlen < (size_t) attr->mq_msgsize)
7b487ba9 945 {
3f3bd101
CV
946 set_errno (EMSGSIZE);
947 __leave;
7b487ba9 948 }
3f3bd101 949 if (attr->mq_curmsgs == 0) /* queue is empty */
b994b837 950 {
3f3bd101 951 if (mqinfo->mqi_flags & O_NONBLOCK)
b994b837 952 {
3f3bd101
CV
953 set_errno (EAGAIN);
954 __leave;
b994b837 955 }
3f3bd101
CV
956 /* Wait for a message to be placed onto queue */
957 mqhdr->mqh_nwait++;
958 while (attr->mq_curmsgs == 0)
959 {
960 int ret = ipc_cond_timedwait (mqinfo->mqi_waitrecv,
961 mqinfo->mqi_lock, abstime);
962 if (ret != 0)
963 {
964 set_errno (ret);
965 __leave;
966 }
967 }
968 mqhdr->mqh_nwait--;
b994b837 969 }
7b487ba9 970
3f3bd101
CV
971 if ((index = mqhdr->mqh_head) == 0)
972 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr->mq_curmsgs);
7b487ba9 973
3f3bd101
CV
974 msghdr = (struct msg_hdr *) &mptr[index];
975 mqhdr->mqh_head = msghdr->msg_next; /* new head of list */
976 len = msghdr->msg_len;
977 memcpy(ptr, msghdr + 1, len); /* copy the message itself */
978 if (priop != NULL)
979 *priop = msghdr->msg_prio;
980
981 /* Just-read message goes to front of free list */
982 msghdr->msg_next = mqhdr->mqh_free;
983 mqhdr->mqh_free = index;
7b487ba9 984
3f3bd101
CV
985 /* Wake up anyone blocked in mq_send waiting for room */
986 if (attr->mq_curmsgs == attr->mq_maxmsg)
987 ipc_cond_signal (mqinfo->mqi_waitsend);
988 attr->mq_curmsgs--;
7b487ba9 989
3f3bd101
CV
990 ipc_mutex_unlock (mqinfo->mqi_lock);
991 }
992 __except (EBADF) {}
993 __endtry
994 if (ipc_mutex_locked)
995 ipc_mutex_unlock (mqinfo->mqi_lock);
7b487ba9 996 return len;
7b487ba9
CV
997}
998
999extern "C" ssize_t
1000mq_receive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop)
1001{
1002 return _mq_receive (mqd, ptr, maxlen, priop, NULL);
1003}
1004
1005extern "C" ssize_t
1006mq_timedreceive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop,
1007 const struct timespec *abstime)
1008{
1009 return _mq_receive (mqd, ptr, maxlen, priop, abstime);
1010}
1011
1012extern "C" int
1013mq_close (mqd_t mqd)
1014{
1015 long msgsize, filesize;
1016 struct mq_hdr *mqhdr;
61522196 1017 struct mq_fattr *attr;
7b487ba9
CV
1018 struct mq_info *mqinfo;
1019
3f3bd101 1020 __try
7b487ba9 1021 {
3f3bd101
CV
1022 mqinfo = (struct mq_info *) mqd;
1023 if (mqinfo->mqi_magic != MQI_MAGIC)
1024 {
1025 set_errno (EBADF);
1026 __leave;
1027 }
1028 mqhdr = mqinfo->mqi_hdr;
1029 attr = &mqhdr->mqh_attr;
7b487ba9 1030
3f3bd101
CV
1031 if (mq_notify (mqd, NULL)) /* unregister calling process */
1032 __leave;
7b487ba9 1033
3f3bd101
CV
1034 msgsize = MSGSIZE (attr->mq_msgsize);
1035 filesize = sizeof (struct mq_hdr)
1036 + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize));
1037 if (munmap (mqinfo->mqi_hdr, filesize) == -1)
1038 __leave;
7b487ba9 1039
3f3bd101
CV
1040 mqinfo->mqi_magic = 0; /* just in case */
1041 ipc_cond_close (mqinfo->mqi_waitsend);
1042 ipc_cond_close (mqinfo->mqi_waitrecv);
1043 ipc_mutex_close (mqinfo->mqi_lock);
1044 free (mqinfo);
1045 return 0;
1046 }
1047 __except (EBADF) {}
1048 __endtry
1049 return -1;
7b487ba9
CV
1050}
1051
1052extern "C" int
1053mq_unlink (const char *name)
1054{
547ad329
CV
1055 size_t len = strlen (name);
1056 char mqname[ipc_names[mqueue].prefix_len + len];
7b487ba9 1057
547ad329 1058 if (!check_path (mqname, mqueue, name, len))
7b487ba9
CV
1059 return -1;
1060 if (unlink (mqname) == -1)
1061 return -1;
1062 return 0;
1063}
1064
8fbd574e
CV
1065/* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
1066 implementation as far as sem_open is concerned, but under the hood using
1067 the already existing semaphore class in thread.cc. Using a file backed
1068 solution allows to implement kernel persistent named semaphores. */
1069
1070struct sem_finfo
1071{
1072 unsigned int value;
1073 unsigned long long hash;
1074 LUID luid;
1075};
1076
1077extern "C" sem_t *
1078sem_open (const char *name, int oflag, ...)
1079{
3f3bd101 1080 int i, fd = -1, created = 0;
8fbd574e
CV
1081 va_list ap;
1082 mode_t mode = 0;
1083 unsigned int value = 0;
61522196 1084 struct stat statbuff;
8fbd574e
CV
1085 sem_t *sem = SEM_FAILED;
1086 sem_finfo sf;
8fbd574e
CV
1087 bool wasopen = false;
1088 ipc_flock file;
1089
547ad329
CV
1090 size_t len = strlen (name);
1091 char semname[ipc_names[semaphore].prefix_len + len];
1092
1093 if (!check_path (semname, semaphore, name, len))
8fbd574e
CV
1094 return SEM_FAILED;
1095
3f3bd101 1096 __try
8fbd574e 1097 {
3f3bd101
CV
1098 oflag &= (O_CREAT | O_EXCL);
1099
1100 again:
1101 if (oflag & O_CREAT)
7b44665a 1102 {
3f3bd101
CV
1103 va_start (ap, oflag); /* init ap to final named argument */
1104 mode = va_arg (ap, mode_t) & ~S_IXUSR;
1105 value = va_arg (ap, unsigned int);
1106 va_end (ap);
1107
1108 /* Open and specify O_EXCL and user-execute */
1109 fd = open (semname, oflag | O_EXCL | O_RDWR | O_CLOEXEC,
1110 mode | S_IXUSR);
1111 if (fd < 0)
1112 {
1113 if (errno == EEXIST && (oflag & O_EXCL) == 0)
1114 goto exists; /* already exists, OK */
1115 return SEM_FAILED;
1116 }
1117 created = 1;
1118 /* First one to create the file initializes it. */
1119 NtAllocateLocallyUniqueId (&sf.luid);
1120 sf.value = value;
1121 sf.hash = hash_path_name (0, semname);
1122 if (write (fd, &sf, sizeof sf) != sizeof sf)
1123 __leave;
1124 sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, value,
1125 wasopen);
1126 if (sem == SEM_FAILED)
1127 __leave;
1128 /* Initialization complete, turn off user-execute bit */
1129 if (fchmod (fd, mode) == -1)
1130 __leave;
1131 /* Don't close (fd); */
1132 return sem;
8fbd574e 1133 }
8fbd574e 1134
3f3bd101
CV
1135 exists:
1136 /* Open the file and fetch the semaphore name. */
1137 if ((fd = open (semname, O_RDWR | O_CLOEXEC)) < 0)
8fbd574e
CV
1138 {
1139 if (errno == ENOENT && (oflag & O_CREAT))
3f3bd101
CV
1140 goto again;
1141 __leave;
1142 }
1143 /* Make certain initialization is complete */
1144 for (i = 0; i < MAX_TRIES; i++)
1145 {
1146 if (stat64 (semname, &statbuff) == -1)
8fbd574e 1147 {
3f3bd101
CV
1148 if (errno == ENOENT && (oflag & O_CREAT))
1149 {
1150 close (fd);
1151 fd = -1;
1152 goto again;
1153 }
1154 __leave;
8fbd574e 1155 }
3f3bd101
CV
1156 if ((statbuff.st_mode & S_IXUSR) == 0)
1157 break;
1158 sleep (1);
8fbd574e 1159 }
3f3bd101
CV
1160 if (i == MAX_TRIES)
1161 {
1162 set_errno (ETIMEDOUT);
1163 __leave;
1164 }
1165 if (file.lock (fd, sizeof sf))
1166 __leave;
1167 if (read (fd, &sf, sizeof sf) != sizeof sf)
1168 __leave;
1169 sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, sf.value,
1170 wasopen);
1171 file.unlock (fd);
1172 if (sem == SEM_FAILED)
1173 __leave;
1174 /* If wasopen is set, the semaphore was already opened and we already have
1175 an open file descriptor pointing to the file. This means, we have to
1176 close the file descriptor created in this call. It won't be stored
1177 anywhere anyway. */
1178 if (wasopen)
1179 close (fd);
1180 return sem;
8fbd574e 1181 }
3f3bd101
CV
1182 __except (EFAULT) {}
1183 __endtry
8fbd574e
CV
1184 /* Don't let following function calls change errno */
1185 save_errno save;
1186
3f3bd101
CV
1187 if (fd >= 0)
1188 file.unlock (fd);
8fbd574e
CV
1189 if (created)
1190 unlink (semname);
1191 if (sem != SEM_FAILED)
1192 semaphore::close (sem);
599d462d
CV
1193 if (fd >= 0)
1194 close (fd);
8fbd574e
CV
1195 return SEM_FAILED;
1196}
1197
1198int
1199_sem_close (sem_t *sem, bool do_close)
1200{
1201 sem_finfo sf;
1202 int fd, ret = -1;
1203 ipc_flock file;
1204
1205 if (semaphore::getinternal (sem, &fd, &sf.hash, &sf.luid, &sf.value) == -1)
1206 return -1;
1207 if (!file.lock (fd, sizeof sf)
61522196 1208 && lseek64 (fd, 0LL, SEEK_SET) != (off_t) -1
8fbd574e
CV
1209 && write (fd, &sf, sizeof sf) == sizeof sf)
1210 ret = do_close ? semaphore::close (sem) : 0;
1211
1212 /* Don't let following function calls change errno */
1213 save_errno save;
1214 file.unlock (fd);
1215 close (fd);
1216
1217 return ret;
1218}
1219
1220extern "C" int
1221sem_close (sem_t *sem)
1222{
1223 return _sem_close (sem, true);
1224}
1225
1226extern "C" int
1227sem_unlink (const char *name)
1228{
547ad329
CV
1229 size_t len = strlen (name);
1230 char semname[ipc_names[semaphore].prefix_len + len];
8fbd574e 1231
547ad329 1232 if (!check_path (semname, semaphore, name, len))
8fbd574e
CV
1233 return -1;
1234 if (unlink (semname) == -1)
1235 return -1;
1236 return 0;
1237}
This page took 0.434006 seconds and 5 git commands to generate.