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
10 #include "shared_info.h"
22 #include <sys/param.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. */
33 const size_t prefix_len
;
34 const char *description
;
36 { "/dev/shm", 10, "POSIX shared memory object" },
37 { "/dev/mqueue", 13, "POSIX message queue" },
38 { "/dev/shm", 14, "POSIX semaphore" }
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 ())
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
);
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
);
79 /* Name must not consist of just a single slash (or backslash) */
82 debug_printf ("Invalid %s name '%s'", ipc_names
[type
].description
, name
);
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
);
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
);
101 __small_sprintf (res_name
, "%s/%s%s", ipc_names
[type
].prefix
,
102 type
== semaphore
? "sem." : "",
112 ipc_flock () { memset (&fl
, 0, sizeof fl
); }
114 int lock (int fd
, size_t size
)
117 fl
.l_whence
= SEEK_SET
;
120 return fcntl (fd
, F_SETLKW
, &fl
);
127 return fcntl (fd
, F_SETLKW
, &fl
);
131 /* POSIX shared memory object implementation. */
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
))
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
);
151 return open (shmname
, oflag
| O_CLOEXEC
, mode
& 0777);
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
))
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. */
174 mq_open (const char *name
, int oflag
, ...)
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
))
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
*);
197 /* Create file descriptor for mqueue */
202 fh
= (fhandler_mqueue
*) build_fh_name (mqname
,
204 | PC_SYM_NOFOLLOW
| PC_NULLEMPTY
,
209 if (fh
->mq_open (oflag
, mode
, attr
))
223 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
227 cygheap_fdget
fd ((int) mqd
, true);
228 fhandler_mqueue
*fh
= fd
->is_mqueue ();
232 ret
= fh
->mq_getattr (mqstat
);
237 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
241 cygheap_fdget
fd ((int) mqd
, true);
242 fhandler_mqueue
*fh
= fd
->is_mqueue ();
246 ret
= fh
->mq_setattr (mqstat
, omqstat
);
251 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
255 cygheap_fdget
fd ((int) mqd
, true);
256 fhandler_mqueue
*fh
= fd
->is_mqueue ();
260 ret
= fh
->mq_notify (notification
);
265 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
266 const struct timespec
*abstime
)
270 cygheap_fdget
fd ((int) mqd
, true);
271 fhandler_mqueue
*fh
= fd
->is_mqueue ();
275 ret
= fh
->mq_timedsend (ptr
, len
, prio
, abstime
);
280 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
282 return mq_timedsend (mqd
, ptr
, len
, prio
, NULL
);
286 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
287 const struct timespec
*abstime
)
291 cygheap_fdget
fd ((int) mqd
, true);
292 fhandler_mqueue
*fh
= fd
->is_mqueue ();
296 ret
= fh
->mq_timedrecv (ptr
, maxlen
, priop
, abstime
);
301 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
303 return mq_timedreceive (mqd
, ptr
, maxlen
, priop
, NULL
);
311 cygheap_fdget
fd ((int) mqd
, true);
312 if (!fd
->is_mqueue ())
318 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
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
))
339 if (unlink (mqname
) == -1)
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 */
354 unsigned long long hash
;
359 sem_open (const char *name
, int oflag
, ...)
361 int i
, fd
= -1, created
= 0;
364 unsigned int value
= 0;
365 struct stat statbuff
;
366 sem_t
*sem
= SEM_FAILED
;
368 bool wasopen
= false;
371 size_t len
= strlen (name
);
372 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
374 if (!check_path (semname
, semaphore
, name
, len
))
379 oflag
&= (O_CREAT
| O_EXCL
);
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);
389 /* Open and specify O_EXCL and user-execute */
390 fd
= open (semname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
,
394 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
395 goto exists
; /* already exists, OK */
399 /* First one to create the file initializes it. */
400 NtAllocateLocallyUniqueId (&sf
.luid
);
402 sf
.hash
= hash_path_name (0, semname
);
403 if (write (fd
, &sf
, sizeof sf
) != sizeof sf
)
405 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, value
,
407 if (sem
== SEM_FAILED
)
409 /* Initialization complete, turn off user-execute bit */
410 if (fchmod (fd
, mode
) == -1)
412 /* Don't close (fd); */
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
))
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
))
437 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
443 set_errno (ETIMEDOUT
);
446 if (file
.lock (fd
, sizeof sf
))
448 if (read (fd
, &sf
, sizeof sf
) != sizeof sf
)
450 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, sf
.value
,
453 if (sem
== SEM_FAILED
)
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
465 /* Don't let following function calls change errno */
472 if (sem
!= SEM_FAILED
)
473 semaphore::close (sem
);
479 extern "C" off_t
lseek (int, off_t
, int);
482 _sem_close (sem_t
*sem
, bool do_close
)
488 if (semaphore::getinternal (sem
, &fd
, &sf
.hash
, &sf
.luid
, &sf
.value
) == -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 */
504 sem_close (sem_t
*sem
)
506 return _sem_close (sem
, true);
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
))
517 if (unlink (semname
) == -1)
523 sem_init (sem_t
* sem
, int pshared
, unsigned int value
)
525 return semaphore::init (sem
, pshared
, value
);
529 sem_destroy (sem_t
* sem
)
531 return semaphore::destroy (sem
);
535 sem_wait (sem_t
* sem
)
537 return semaphore::wait (sem
);
541 sem_trywait (sem_t
* sem
)
543 return semaphore::trywait (sem
);
547 sem_clockwait (sem_t
* sem
, clockid_t clock_id
, const struct timespec
*abstime
)
549 return semaphore::clockwait (sem
, clock_id
, abstime
);
553 sem_timedwait (sem_t
* sem
, const struct timespec
*abstime
)
555 return semaphore::clockwait (sem
, CLOCK_REALTIME
, abstime
);
559 sem_post (sem_t
*sem
)
561 return semaphore::post (sem
);
565 sem_getvalue (sem_t
* sem
, int *sval
)
567 return semaphore::getvalue (sem
, sval
);