Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / posix_ipc.cc
blob34fd2ba34c7eca04478a5202135d4a4389fd4b34
1 /* posix_ipc.cc: POSIX IPC API for Cygwin.
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include "shared_info.h"
11 #include "thread.h"
12 #include "path.h"
13 #include "cygtls.h"
14 #include "fhandler.h"
15 #include "dtable.h"
16 #include "cygheap.h"
17 #include "sigproc.h"
18 #include "ntdll.h"
19 #include "tls_pbuf.h"
20 #include <io.h>
21 #include <sys/mman.h>
22 #include <sys/param.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <mqueue.h>
26 #include <semaphore.h>
28 /* The prefix_len is the length of the path prefix including trailing "/"
29 (or "/sem." for semaphores) as well as the trailing NUL. */
30 static struct
32 const char *prefix;
33 const size_t prefix_len;
34 const char *description;
35 } ipc_names[] = {
36 { "/dev/shm", 10, "POSIX shared memory object" },
37 { "/dev/mqueue", 13, "POSIX message queue" },
38 { "/dev/shm", 14, "POSIX semaphore" }
41 enum ipc_type_t
43 shmem,
44 mqueue,
45 semaphore
48 static bool
49 check_path (char *res_name, ipc_type_t type, const char *name, size_t len)
51 /* Note that we require the existance of the appropriate /dev subdirectories
52 for POSIX IPC object support, similar to Linux (which supports the
53 directories, but doesn't require to mount them). We don't create
54 these directory here, that's the task of the installer. But we check
55 for existance and give ample warning. */
56 path_conv path (ipc_names[type].prefix, PC_SYM_NOFOLLOW);
57 if (path.error || !path.exists () || !path.isdir ())
59 small_printf (
60 "Warning: '%s' does not exists or is not a directory.\n\n"
61 "%ss require the existance of this directory.\n"
62 "Create the directory '%s' and set the permissions to 01777.\n"
63 "For instance on the command line: mkdir -m 01777 %s\n",
64 ipc_names[type].prefix, ipc_names[type].description,
65 ipc_names[type].prefix, ipc_names[type].prefix);
66 set_errno (EINVAL);
67 return false;
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 /* Name must not be empty and has to start with a slash (or backslash) */
73 if (!name || !strchr ("/\\", name[0]))
75 debug_printf ("Invalid %s name '%s'", ipc_names[type].description, name);
76 set_errno (EINVAL);
77 return false;
79 /* Name must not consist of just a single slash (or backslash) */
80 if (!name[1])
82 debug_printf ("Invalid %s name '%s'", ipc_names[type].description, name);
83 set_errno (ENOENT);
84 return false;
86 /* Name must not contain slashes after the leading one */
87 if (strpbrk (name + 1, "/\\"))
89 debug_printf ("Invalid %s name '%s'", ipc_names[type].description, name);
90 set_errno (EACCES);
91 return false;
93 /* Length must be less than or equal to NAME_MAX, or NAME_MAX - 4 in
94 case of semaphores, due to the leading "sem." prefix */
95 if (len > NAME_MAX - (type == semaphore ? strlen ("sem.") : 0))
97 debug_printf ("%s name '%s' too long", ipc_names[type].description, name);
98 set_errno (ENAMETOOLONG);
99 return false;
101 __small_sprintf (res_name, "%s/%s%s", ipc_names[type].prefix,
102 type == semaphore ? "sem." : "",
103 name + 1);
104 return true;
107 class ipc_flock
109 struct flock fl;
111 public:
112 ipc_flock () { memset (&fl, 0, sizeof fl); }
114 int lock (int fd, size_t size)
116 fl.l_type = F_WRLCK;
117 fl.l_whence = SEEK_SET;
118 fl.l_start = 0;
119 fl.l_len = size;
120 return fcntl (fd, F_SETLKW, &fl);
122 int unlock (int fd)
124 if (!fl.l_len)
125 return 0;
126 fl.l_type = F_UNLCK;
127 return fcntl (fd, F_SETLKW, &fl);
131 /* POSIX shared memory object implementation. */
133 extern "C" int
134 shm_open (const char *name, int oflag, mode_t mode)
136 size_t len = strlen (name);
137 char shmname[ipc_names[shmem].prefix_len + len];
139 if (!check_path (shmname, shmem, name, len))
140 return -1;
142 /* Check for valid flags. */
143 if (((oflag & O_ACCMODE) != O_RDONLY && (oflag & O_ACCMODE) != O_RDWR)
144 || (oflag & ~(O_ACCMODE | O_CREAT | O_EXCL | O_TRUNC)))
146 debug_printf ("Invalid oflag 0%o", oflag);
147 set_errno (EINVAL);
148 return -1;
151 return open (shmname, oflag | O_CLOEXEC, mode & 0777);
154 extern "C" int
155 shm_unlink (const char *name)
157 size_t len = strlen (name);
158 char shmname[ipc_names[shmem].prefix_len + len];
160 if (!check_path (shmname, shmem, name, len))
161 return -1;
163 return unlink (shmname);
166 /* The POSIX message queue implementation is based on W. Richard STEVENS
167 implementation, just tweaked for Cygwin. The main change is
168 the usage of Windows mutexes and events instead of using the pthread
169 synchronization objects. The pathname is massaged so that the
170 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
171 are implemented additionally. */
173 extern "C" mqd_t
174 mq_open (const char *name, int oflag, ...)
176 va_list ap;
177 mode_t mode = 0;
178 fhandler_mqueue *fh = NULL;
179 struct mq_attr *attr = NULL;
181 size_t len = strlen (name);
182 char mqname[ipc_names[mqueue].prefix_len + len];
184 if (!check_path (mqname, mqueue, name, len))
185 return (mqd_t) -1;
187 __try
189 if (oflag & O_CREAT)
191 va_start (ap, oflag); /* init ap to final named argument */
192 mode = va_arg (ap, mode_t) & ~S_IXUSR;
193 attr = va_arg (ap, struct mq_attr *);
194 va_end (ap);
197 /* Create file descriptor for mqueue */
198 cygheap_fdnew fd;
200 if (fd < 0)
201 __leave;
202 fh = (fhandler_mqueue *) build_fh_name (mqname,
203 PC_OPEN | PC_POSIX
204 | PC_SYM_NOFOLLOW | PC_NULLEMPTY,
205 NULL);
206 if (!fh)
207 __leave;
209 if (fh->mq_open (oflag, mode, attr))
211 fd = fh;
212 return (mqd_t) fd;
215 __except (EFAULT) {}
216 __endtry
217 if (fh)
218 delete fh;
219 return (mqd_t) -1;
222 extern "C" int
223 mq_getattr (mqd_t mqd, struct mq_attr *mqstat)
225 int ret = -1;
227 cygheap_fdget fd ((int) mqd, true);
228 fhandler_mqueue *fh = fd->is_mqueue ();
229 if (!fh)
230 set_errno (EBADF);
231 else
232 ret = fh->mq_getattr (mqstat);
233 return ret;
236 extern "C" int
237 mq_setattr (mqd_t mqd, const struct mq_attr *mqstat, struct mq_attr *omqstat)
239 int ret = -1;
241 cygheap_fdget fd ((int) mqd, true);
242 fhandler_mqueue *fh = fd->is_mqueue ();
243 if (!fh)
244 set_errno (EBADF);
245 else
246 ret = fh->mq_setattr (mqstat, omqstat);
247 return ret;
250 extern "C" int
251 mq_notify (mqd_t mqd, const struct sigevent *notification)
253 int ret = -1;
255 cygheap_fdget fd ((int) mqd, true);
256 fhandler_mqueue *fh = fd->is_mqueue ();
257 if (!fh)
258 set_errno (EBADF);
259 else
260 ret = fh->mq_notify (notification);
261 return ret;
264 extern "C" int
265 mq_timedsend (mqd_t mqd, const char *ptr, size_t len, unsigned int prio,
266 const struct timespec *abstime)
268 int ret = -1;
270 cygheap_fdget fd ((int) mqd, true);
271 fhandler_mqueue *fh = fd->is_mqueue ();
272 if (!fh)
273 set_errno (EBADF);
274 else
275 ret = fh->mq_timedsend (ptr, len, prio, abstime);
276 return ret;
279 extern "C" int
280 mq_send (mqd_t mqd, const char *ptr, size_t len, unsigned int prio)
282 return mq_timedsend (mqd, ptr, len, prio, NULL);
285 extern "C" ssize_t
286 mq_timedreceive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop,
287 const struct timespec *abstime)
289 int ret = -1;
291 cygheap_fdget fd ((int) mqd, true);
292 fhandler_mqueue *fh = fd->is_mqueue ();
293 if (!fh)
294 set_errno (EBADF);
295 else
296 ret = fh->mq_timedrecv (ptr, maxlen, priop, abstime);
297 return ret;
300 extern "C" ssize_t
301 mq_receive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop)
303 return mq_timedreceive (mqd, ptr, maxlen, priop, NULL);
306 extern "C" int
307 mq_close (mqd_t mqd)
309 __try
311 cygheap_fdget fd ((int) mqd, true);
312 if (!fd->is_mqueue ())
314 set_errno (EBADF);
315 __leave;
318 if (mq_notify (mqd, NULL)) /* unregister calling process */
319 __leave;
321 fd->isclosed (true);
322 fd->close ();
323 fd.release ();
324 return 0;
326 __except (EBADF) {}
327 __endtry
328 return -1;
331 extern "C" int
332 mq_unlink (const char *name)
334 size_t len = strlen (name);
335 char mqname[ipc_names[mqueue].prefix_len + len];
337 if (!check_path (mqname, mqueue, name, len))
338 return -1;
339 if (unlink (mqname) == -1)
340 return -1;
341 return 0;
344 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
345 implementation as far as sem_open is concerned, but under the hood using
346 the already existing semaphore class in thread.cc. Using a file backed
347 solution allows to implement kernel persistent named semaphores. */
349 #define MAX_TRIES 10 /* for waiting for initialization */
351 struct sem_finfo
353 unsigned int value;
354 unsigned long long hash;
355 LUID luid;
358 extern "C" sem_t *
359 sem_open (const char *name, int oflag, ...)
361 int i, fd = -1, created = 0;
362 va_list ap;
363 mode_t mode = 0;
364 unsigned int value = 0;
365 struct stat statbuff;
366 sem_t *sem = SEM_FAILED;
367 sem_finfo sf;
368 bool wasopen = false;
369 ipc_flock file;
371 size_t len = strlen (name);
372 char semname[ipc_names[semaphore].prefix_len + len];
374 if (!check_path (semname, semaphore, name, len))
375 return SEM_FAILED;
377 __try
379 oflag &= (O_CREAT | O_EXCL);
381 again:
382 if (oflag & O_CREAT)
384 va_start (ap, oflag); /* init ap to final named argument */
385 mode = va_arg (ap, mode_t) & ~S_IXUSR;
386 value = va_arg (ap, unsigned int);
387 va_end (ap);
389 /* Open and specify O_EXCL and user-execute */
390 fd = open (semname, oflag | O_EXCL | O_RDWR | O_CLOEXEC,
391 mode | S_IXUSR);
392 if (fd < 0)
394 if (errno == EEXIST && (oflag & O_EXCL) == 0)
395 goto exists; /* already exists, OK */
396 return SEM_FAILED;
398 created = 1;
399 /* First one to create the file initializes it. */
400 NtAllocateLocallyUniqueId (&sf.luid);
401 sf.value = value;
402 sf.hash = hash_path_name (0, semname);
403 if (write (fd, &sf, sizeof sf) != sizeof sf)
404 __leave;
405 sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, value,
406 wasopen);
407 if (sem == SEM_FAILED)
408 __leave;
409 /* Initialization complete, turn off user-execute bit */
410 if (fchmod (fd, mode) == -1)
411 __leave;
412 /* Don't close (fd); */
413 return sem;
416 exists:
417 /* Open the file and fetch the semaphore name. */
418 if ((fd = open (semname, O_RDWR | O_CLOEXEC)) < 0)
420 if (errno == ENOENT && (oflag & O_CREAT))
421 goto again;
422 __leave;
424 /* Make certain initialization is complete */
425 for (i = 0; i < MAX_TRIES; i++)
427 if (stat (semname, &statbuff) == -1)
429 if (errno == ENOENT && (oflag & O_CREAT))
431 close (fd);
432 fd = -1;
433 goto again;
435 __leave;
437 if ((statbuff.st_mode & S_IXUSR) == 0)
438 break;
439 sleep (1);
441 if (i == MAX_TRIES)
443 set_errno (ETIMEDOUT);
444 __leave;
446 if (file.lock (fd, sizeof sf))
447 __leave;
448 if (read (fd, &sf, sizeof sf) != sizeof sf)
449 __leave;
450 sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, sf.value,
451 wasopen);
452 file.unlock (fd);
453 if (sem == SEM_FAILED)
454 __leave;
455 /* If wasopen is set, the semaphore was already opened and we already have
456 an open file descriptor pointing to the file. This means, we have to
457 close the file descriptor created in this call. It won't be stored
458 anywhere anyway. */
459 if (wasopen)
460 close (fd);
461 return sem;
463 __except (EFAULT) {}
464 __endtry
465 /* Don't let following function calls change errno */
466 save_errno save;
468 if (fd >= 0)
469 file.unlock (fd);
470 if (created)
471 unlink (semname);
472 if (sem != SEM_FAILED)
473 semaphore::close (sem);
474 if (fd >= 0)
475 close (fd);
476 return SEM_FAILED;
479 extern "C" off_t lseek (int, off_t, int);
482 _sem_close (sem_t *sem, bool do_close)
484 sem_finfo sf;
485 int fd, ret = -1;
486 ipc_flock file;
488 if (semaphore::getinternal (sem, &fd, &sf.hash, &sf.luid, &sf.value) == -1)
489 return -1;
490 if (!file.lock (fd, sizeof sf)
491 && lseek (fd, 0LL, SEEK_SET) != (off_t) -1
492 && write (fd, &sf, sizeof sf) == sizeof sf)
493 ret = do_close ? semaphore::close (sem) : 0;
495 /* Don't let following function calls change errno */
496 save_errno save;
497 file.unlock (fd);
498 close (fd);
500 return ret;
503 extern "C" int
504 sem_close (sem_t *sem)
506 return _sem_close (sem, true);
509 extern "C" int
510 sem_unlink (const char *name)
512 size_t len = strlen (name);
513 char semname[ipc_names[semaphore].prefix_len + len];
515 if (!check_path (semname, semaphore, name, len))
516 return -1;
517 if (unlink (semname) == -1)
518 return -1;
519 return 0;
522 extern "C" int
523 sem_init (sem_t * sem, int pshared, unsigned int value)
525 return semaphore::init (sem, pshared, value);
528 extern "C" int
529 sem_destroy (sem_t * sem)
531 return semaphore::destroy (sem);
534 extern "C" int
535 sem_wait (sem_t * sem)
537 return semaphore::wait (sem);
540 extern "C" int
541 sem_trywait (sem_t * sem)
543 return semaphore::trywait (sem);
546 extern "C" int
547 sem_clockwait (sem_t * sem, clockid_t clock_id, const struct timespec *abstime)
549 return semaphore::clockwait (sem, clock_id, abstime);
552 extern "C" int
553 sem_timedwait (sem_t * sem, const struct timespec *abstime)
555 return semaphore::clockwait (sem, CLOCK_REALTIME, abstime);
558 extern "C" int
559 sem_post (sem_t *sem)
561 return semaphore::post (sem);
564 extern "C" int
565 sem_getvalue (sem_t * sem, int *sval)
567 return semaphore::getvalue (sem, sval);