]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/posix_ipc.cc
* cygwin.din (sem_unlink): Export.
[newlib-cygwin.git] / winsup / cygwin / posix_ipc.cc
1 /* posix_ipc.cc: POSIX IPC API for Cygwin.
2
3 Copyright 2007 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include "thread.h"
13 #include "path.h"
14 #include "cygerrno.h"
15 #include "cygtls.h"
16 #include "security.h"
17 #include "sigproc.h"
18 #include <sys/stat.h>
19 #include <sys/mman.h>
20 #include <sys/param.h>
21 #include <fcntl.h>
22 #include <pwd.h>
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <unistd.h>
26 #include <stdarg.h>
27 #include <mqueue.h>
28 #include <semaphore.h>
29
30 struct
31 {
32 const char *prefix;
33 const size_t max_len;
34 const char *description;
35 } ipc_names[] = {
36 { "/dev/shm", CYG_MAX_PATH - 10, "POSIX shared memory object" },
37 { "/dev/mqueue", CYG_MAX_PATH - 13, "POSIX message queue" },
38 { "/dev/shm", CYG_MAX_PATH - 14, "POSIX semaphore" }
39 };
40
41 enum ipc_type_t
42 {
43 shmem,
44 mqueue,
45 semaphore
46 };
47
48 static bool
49 check_path (char *res_name, ipc_type_t type, const char *name)
50 {
51 /* Note that we require the existance of the apprpriate /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 ())
58 {
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;
68 }
69 /* Name must start with a single slash. */
70 if (!name || name[0] != '/' || name[1] == '/' || !name[1])
71 {
72 debug_printf ("Invalid %s name '%s'", ipc_names[type].description, name);
73 set_errno (EINVAL);
74 return false;
75 }
76 if (strlen (name) > ipc_names[type].max_len)
77 {
78 debug_printf ("%s name '%s' too long", ipc_names[type].description, name);
79 set_errno (ENAMETOOLONG);
80 return false;
81 }
82 __small_sprintf (res_name, "%s/%s%s", ipc_names[type].prefix,
83 type == semaphore ? "sem." : "",
84 name + 1);
85 return true;
86 }
87
88 static int
89 ipc_mutex_init (HANDLE *pmtx, const char *name)
90 {
91 char buf[CYG_MAX_PATH];
92 __small_sprintf (buf, "%scyg_pmtx/%s",
93 wincap.has_terminal_services () ? "Global\\" : "", name);
94 *pmtx = CreateMutex (&sec_all, FALSE, buf);
95 if (!*pmtx)
96 debug_printf ("failed: %E\n");
97 return *pmtx ? 0 : geterrno_from_win_error ();
98 }
99
100 static int
101 ipc_mutex_lock (HANDLE mtx)
102 {
103 HANDLE h[2] = { mtx, signal_arrived };
104
105 switch (WaitForMultipleObjects (2, h, FALSE, INFINITE))
106 {
107 case WAIT_OBJECT_0:
108 case WAIT_ABANDONED_0:
109 return 0;
110 case WAIT_OBJECT_0 + 1:
111 set_errno (EINTR);
112 return 1;
113 default:
114 break;
115 }
116 return geterrno_from_win_error ();
117 }
118
119 static inline int
120 ipc_mutex_unlock (HANDLE mtx)
121 {
122 return ReleaseMutex (mtx) ? 0 : geterrno_from_win_error ();
123 }
124
125 static inline int
126 ipc_mutex_close (HANDLE mtx)
127 {
128 return CloseHandle (mtx) ? 0 : geterrno_from_win_error ();
129 }
130
131 static int
132 ipc_cond_init (HANDLE *pevt, const char *name)
133 {
134 char buf[CYG_MAX_PATH];
135 __small_sprintf (buf, "%scyg_pevt/%s",
136 wincap.has_terminal_services () ? "Global\\" : "", name);
137 *pevt = CreateEvent (&sec_all, TRUE, FALSE, buf);
138 if (!*pevt)
139 debug_printf ("failed: %E\n");
140 return *pevt ? 0 : geterrno_from_win_error ();
141 }
142
143 static int
144 ipc_cond_timedwait (HANDLE evt, HANDLE mtx, const struct timespec *abstime)
145 {
146 struct timeval tv;
147 DWORD timeout;
148 HANDLE h[2] = { mtx, evt };
149
150 if (!abstime)
151 timeout = INFINITE;
152 else if (abstime->tv_sec < 0
153 || abstime->tv_nsec < 0
154 || abstime->tv_nsec > 999999999)
155 return EINVAL;
156 else
157 {
158 gettimeofday (&tv, NULL);
159 /* Check for immediate timeout. */
160 if (tv.tv_sec > abstime->tv_sec
161 || (tv.tv_sec == abstime->tv_sec
162 && tv.tv_usec > abstime->tv_nsec / 1000))
163 return ETIMEDOUT;
164 timeout = (abstime->tv_sec - tv.tv_sec) * 1000;
165 timeout += (abstime->tv_nsec / 1000 - tv.tv_usec) / 1000;
166 }
167 if (ipc_mutex_unlock (mtx))
168 return -1;
169 switch (WaitForMultipleObjects (2, h, TRUE, timeout))
170 {
171 case WAIT_OBJECT_0:
172 case WAIT_ABANDONED_0:
173 ResetEvent (evt);
174 return 0;
175 case WAIT_TIMEOUT:
176 ipc_mutex_lock (mtx);
177 return ETIMEDOUT;
178 default:
179 break;
180 }
181 return geterrno_from_win_error ();
182 }
183
184 static inline int
185 ipc_cond_signal (HANDLE evt)
186 {
187 return SetEvent (evt) ? 0 : geterrno_from_win_error ();
188 }
189
190 static inline int
191 ipc_cond_close (HANDLE evt)
192 {
193 return CloseHandle (evt) ? 0 : geterrno_from_win_error ();
194 }
195
196 class ipc_flock
197 {
198 struct __flock64 fl;
199
200 public:
201 ipc_flock () { memset (&fl, 0, sizeof fl); }
202
203 int lock (int fd, size_t size)
204 {
205 fl.l_type = F_WRLCK;
206 fl.l_whence = SEEK_SET;
207 fl.l_start = 0;
208 fl.l_len = size;
209 return fcntl (fd, F_SETLKW, &fl);
210 }
211 int unlock (int fd)
212 {
213 if (!fl.l_len)
214 return 0;
215 fl.l_type = F_UNLCK;
216 return fcntl (fd, F_SETLKW, &fl);
217 }
218 };
219
220 /* POSIX shared memory object implementation. */
221
222 extern "C" int
223 shm_open (const char *name, int oflag, mode_t mode)
224 {
225 char shmname[CYG_MAX_PATH];
226
227 if (!check_path (shmname, shmem, name))
228 return -1;
229
230 /* Check for valid flags. */
231 if (((oflag & O_ACCMODE) != O_RDONLY && (oflag & O_ACCMODE) != O_RDWR)
232 || (oflag & ~(O_ACCMODE | O_CREAT | O_EXCL | O_TRUNC)))
233 {
234 debug_printf ("Invalid oflag 0%o", oflag);
235 set_errno (EINVAL);
236 return -1;
237 }
238
239 return open (shmname, oflag, mode & 0777);
240 }
241
242 extern "C" int
243 shm_unlink (const char *name)
244 {
245 char shmname[CYG_MAX_PATH];
246
247 if (!check_path (shmname, shmem, name))
248 return -1;
249
250 return unlink (shmname);
251 }
252
253 /* The POSIX message queue implementation is based on W. Richard STEVENS
254 implementation, just tweaked for Cygwin. The main change is
255 the usage of Windows mutexes and events instead of using the pthread
256 synchronization objects. The pathname is massaged so that the
257 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
258 are implemented additionally. */
259
260 struct mq_hdr
261 {
262 struct mq_attr mqh_attr; /* the queue's attributes */
263 long mqh_head; /* index of first message */
264 long mqh_free; /* index of first free message */
265 long mqh_nwait; /* #threads blocked in mq_receive() */
266 pid_t mqh_pid; /* nonzero PID if mqh_event set */
267 char mqh_uname[36]; /* unique name used to identify synchronization
268 objects connected to this queue */
269 struct sigevent mqh_event; /* for mq_notify() */
270 };
271
272 struct msg_hdr
273 {
274 long msg_next; /* index of next on linked list */
275 ssize_t msg_len; /* actual length */
276 unsigned int msg_prio; /* priority */
277 };
278
279 struct mq_info
280 {
281 struct mq_hdr *mqi_hdr; /* start of mmap'ed region */
282 unsigned long mqi_magic; /* magic number if open */
283 int mqi_flags; /* flags for this process */
284 HANDLE mqi_lock; /* mutex lock */
285 HANDLE mqi_wait; /* and condition variable */
286 };
287
288 #define MQI_MAGIC 0x98765432UL
289
290 #define MSGSIZE(i) roundup((i), sizeof(long))
291
292 #define MAX_TRIES 10 /* for waiting for initialization */
293
294 struct mq_attr defattr = { 0, 10, 8192, 0 }; /* Linux defaults. */
295
296 extern "C" _off64_t lseek64 (int, _off64_t, int);
297 extern "C" void *mmap64 (void *, size_t, int, int, int, _off64_t);
298
299 extern "C" mqd_t
300 mq_open (const char *name, int oflag, ...)
301 {
302 int i, fd, nonblock, created;
303 long msgsize, index;
304 _off64_t filesize = 0;
305 va_list ap;
306 mode_t mode;
307 int8_t *mptr;
308 struct __stat64 statbuff;
309 struct mq_hdr *mqhdr;
310 struct msg_hdr *msghdr;
311 struct mq_attr *attr;
312 struct mq_info *mqinfo;
313 LUID luid;
314 char mqname[CYG_MAX_PATH];
315
316 if (!check_path (mqname, mqueue, name))
317 return (mqd_t) -1;
318
319 myfault efault;
320 if (efault.faulted (EFAULT))
321 return (mqd_t) -1;
322
323 oflag &= (O_CREAT | O_EXCL | O_NONBLOCK);
324 created = 0;
325 nonblock = oflag & O_NONBLOCK;
326 oflag &= ~O_NONBLOCK;
327 mptr = (int8_t *) MAP_FAILED;
328 mqinfo = NULL;
329
330 again:
331 if (oflag & O_CREAT)
332 {
333 va_start (ap, oflag); /* init ap to final named argument */
334 mode = va_arg (ap, mode_t) & ~S_IXUSR;
335 attr = va_arg (ap, struct mq_attr *);
336 va_end (ap);
337
338 /* Open and specify O_EXCL and user-execute */
339 fd = open (mqname, oflag | O_EXCL | O_RDWR, mode | S_IXUSR);
340 if (fd < 0)
341 {
342 if (errno == EEXIST && (oflag & O_EXCL) == 0)
343 goto exists; /* already exists, OK */
344 return (mqd_t) -1;
345 }
346 created = 1;
347 /* First one to create the file initializes it */
348 if (attr == NULL)
349 attr = &defattr;
350 else if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0)
351 {
352 set_errno (EINVAL);
353 goto err;
354 }
355 /* Calculate and set the file size */
356 msgsize = MSGSIZE (attr->mq_msgsize);
357 filesize = sizeof (struct mq_hdr)
358 + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize));
359 if (lseek64 (fd, filesize - 1, SEEK_SET) == -1)
360 goto err;
361 if (write (fd, "", 1) == -1)
362 goto err;
363
364 /* Memory map the file */
365 mptr = (int8_t *) mmap64 (NULL, (size_t) filesize, PROT_READ | PROT_WRITE,
366 MAP_SHARED, fd, 0);
367 if (mptr == (int8_t *) MAP_FAILED)
368 goto err;
369
370 /* Allocate one mq_info{} for the queue */
371 if (!(mqinfo = (struct mq_info *) malloc (sizeof (struct mq_info))))
372 goto err;
373 mqinfo->mqi_hdr = mqhdr = (struct mq_hdr *) mptr;
374 mqinfo->mqi_magic = MQI_MAGIC;
375 mqinfo->mqi_flags = nonblock;
376
377 /* Initialize header at beginning of file */
378 /* Create free list with all messages on it */
379 mqhdr->mqh_attr.mq_flags = 0;
380 mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg;
381 mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize;
382 mqhdr->mqh_attr.mq_curmsgs = 0;
383 mqhdr->mqh_nwait = 0;
384 mqhdr->mqh_pid = 0;
385 if (!AllocateLocallyUniqueId (&luid))
386 {
387 __seterrno ();
388 goto err;
389 }
390 __small_sprintf (mqhdr->mqh_uname, "cyg%016X%08x%08x",
391 hash_path_name (0,mqname),
392 luid.HighPart, luid.LowPart);
393 mqhdr->mqh_head = 0;
394 index = sizeof (struct mq_hdr);
395 mqhdr->mqh_free = index;
396 for (i = 0; i < attr->mq_maxmsg - 1; i++)
397 {
398 msghdr = (struct msg_hdr *) &mptr[index];
399 index += sizeof (struct msg_hdr) + msgsize;
400 msghdr->msg_next = index;
401 }
402 msghdr = (struct msg_hdr *) &mptr[index];
403 msghdr->msg_next = 0; /* end of free list */
404
405 /* Initialize mutex & condition variable */
406 i = ipc_mutex_init (&mqinfo->mqi_lock, mqhdr->mqh_uname);
407 if (i != 0)
408 goto pthreaderr;
409
410 i = ipc_cond_init (&mqinfo->mqi_wait, mqhdr->mqh_uname);
411 if (i != 0)
412 goto pthreaderr;
413
414 /* Initialization complete, turn off user-execute bit */
415 if (fchmod (fd, mode) == -1)
416 goto err;
417 close (fd);
418 return ((mqd_t) mqinfo);
419 }
420
421 exists:
422 /* Open the file then memory map */
423 if ((fd = open (mqname, O_RDWR)) < 0)
424 {
425 if (errno == ENOENT && (oflag & O_CREAT))
426 goto again;
427 goto err;
428 }
429 /* Make certain initialization is complete */
430 for (i = 0; i < MAX_TRIES; i++)
431 {
432 if (stat64 (mqname, &statbuff) == -1)
433 {
434 if (errno == ENOENT && (oflag & O_CREAT))
435 {
436 close (fd);
437 goto again;
438 }
439 goto err;
440 }
441 if ((statbuff.st_mode & S_IXUSR) == 0)
442 break;
443 sleep (1);
444 }
445 if (i == MAX_TRIES)
446 {
447 set_errno (ETIMEDOUT);
448 goto err;
449 }
450
451 filesize = statbuff.st_size;
452 mptr = (int8_t *) mmap64 (NULL, (size_t) filesize, PROT_READ | PROT_WRITE,
453 MAP_SHARED, fd, 0);
454 if (mptr == (int8_t *) MAP_FAILED)
455 goto err;
456 close (fd);
457
458 /* Allocate one mq_info{} for each open */
459 if (!(mqinfo = (struct mq_info *) malloc (sizeof (struct mq_info))))
460 goto err;
461 mqinfo->mqi_hdr = mqhdr = (struct mq_hdr *) mptr;
462 mqinfo->mqi_magic = MQI_MAGIC;
463 mqinfo->mqi_flags = nonblock;
464
465 /* Initialize mutex & condition variable */
466 i = ipc_mutex_init (&mqinfo->mqi_lock, mqhdr->mqh_uname);
467 if (i != 0)
468 goto pthreaderr;
469
470 i = ipc_cond_init (&mqinfo->mqi_wait, mqhdr->mqh_uname);
471 if (i != 0)
472 goto pthreaderr;
473
474 return (mqd_t) mqinfo;
475
476 pthreaderr:
477 errno = i;
478 err:
479 /* Don't let following function calls change errno */
480 save_errno save;
481
482 if (created)
483 unlink (mqname);
484 if (mptr != (int8_t *) MAP_FAILED)
485 munmap((void *) mptr, (size_t) filesize);
486 if (mqinfo)
487 free (mqinfo);
488 close (fd);
489 return (mqd_t) -1;
490 }
491
492 extern "C" int
493 mq_getattr (mqd_t mqd, struct mq_attr *mqstat)
494 {
495 int n;
496 struct mq_hdr *mqhdr;
497 struct mq_attr *attr;
498 struct mq_info *mqinfo;
499
500 myfault efault;
501 if (efault.faulted (EBADF))
502 return -1;
503
504 mqinfo = (struct mq_info *) mqd;
505 if (mqinfo->mqi_magic != MQI_MAGIC)
506 {
507 set_errno (EBADF);
508 return -1;
509 }
510 mqhdr = mqinfo->mqi_hdr;
511 attr = &mqhdr->mqh_attr;
512 if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0)
513 {
514 errno = n;
515 return -1;
516 }
517 mqstat->mq_flags = mqinfo->mqi_flags; /* per-open */
518 mqstat->mq_maxmsg = attr->mq_maxmsg; /* remaining three per-queue */
519 mqstat->mq_msgsize = attr->mq_msgsize;
520 mqstat->mq_curmsgs = attr->mq_curmsgs;
521
522 ipc_mutex_unlock (mqinfo->mqi_lock);
523 return 0;
524 }
525
526 extern "C" int
527 mq_setattr (mqd_t mqd, const struct mq_attr *mqstat, struct mq_attr *omqstat)
528 {
529 int n;
530 struct mq_hdr *mqhdr;
531 struct mq_attr *attr;
532 struct mq_info *mqinfo;
533
534 myfault efault;
535 if (efault.faulted (EBADF))
536 return -1;
537
538 mqinfo = (struct mq_info *) mqd;
539 if (mqinfo->mqi_magic != MQI_MAGIC)
540 {
541 set_errno (EBADF);
542 return -1;
543 }
544 mqhdr = mqinfo->mqi_hdr;
545 attr = &mqhdr->mqh_attr;
546 if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0)
547 {
548 errno = n;
549 return -1;
550 }
551
552 if (omqstat != NULL)
553 {
554 omqstat->mq_flags = mqinfo->mqi_flags; /* previous attributes */
555 omqstat->mq_maxmsg = attr->mq_maxmsg;
556 omqstat->mq_msgsize = attr->mq_msgsize;
557 omqstat->mq_curmsgs = attr->mq_curmsgs; /* and current status */
558 }
559
560 if (mqstat->mq_flags & O_NONBLOCK)
561 mqinfo->mqi_flags |= O_NONBLOCK;
562 else
563 mqinfo->mqi_flags &= ~O_NONBLOCK;
564
565 ipc_mutex_unlock (mqinfo->mqi_lock);
566 return 0;
567 }
568
569 extern "C" int
570 mq_notify (mqd_t mqd, const struct sigevent *notification)
571 {
572 int n;
573 pid_t pid;
574 struct mq_hdr *mqhdr;
575 struct mq_info *mqinfo;
576
577 myfault efault;
578 if (efault.faulted (EBADF))
579 return -1;
580
581 mqinfo = (struct mq_info *) mqd;
582 if (mqinfo->mqi_magic != MQI_MAGIC)
583 {
584 set_errno (EBADF);
585 return -1;
586 }
587 mqhdr = mqinfo->mqi_hdr;
588 if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0)
589 {
590 errno = n;
591 return -1;
592 }
593
594 pid = getpid ();
595 if (!notification)
596 {
597 if (mqhdr->mqh_pid == pid)
598 mqhdr->mqh_pid = 0; /* unregister calling process */
599 }
600 else
601 {
602 if (mqhdr->mqh_pid != 0)
603 {
604 if (kill (mqhdr->mqh_pid, 0) != -1 || errno != ESRCH)
605 {
606 set_errno (EBUSY);
607 ipc_mutex_unlock (mqinfo->mqi_lock);
608 return -1;
609 }
610 }
611 mqhdr->mqh_pid = pid;
612 mqhdr->mqh_event = *notification;
613 }
614 ipc_mutex_unlock (mqinfo->mqi_lock);
615 return 0;
616 }
617
618 static int
619 _mq_send (mqd_t mqd, const char *ptr, size_t len, unsigned int prio,
620 const struct timespec *abstime)
621 {
622 int n;
623 long index, freeindex;
624 int8_t *mptr;
625 struct sigevent *sigev;
626 struct mq_hdr *mqhdr;
627 struct mq_attr *attr;
628 struct msg_hdr *msghdr, *nmsghdr, *pmsghdr;
629 struct mq_info *mqinfo;
630
631 myfault efault;
632 if (efault.faulted (EBADF))
633 return -1;
634
635 mqinfo = (struct mq_info *) mqd;
636 if (mqinfo->mqi_magic != MQI_MAGIC)
637 {
638 set_errno (EBADF);
639 return -1;
640 }
641 if (prio > MQ_PRIO_MAX)
642 {
643 set_errno (EINVAL);
644 return -1;
645 }
646
647 mqhdr = mqinfo->mqi_hdr; /* struct pointer */
648 mptr = (int8_t *) mqhdr; /* byte pointer */
649 attr = &mqhdr->mqh_attr;
650 if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0)
651 {
652 errno = n;
653 return -1;
654 }
655
656 if (len > (size_t) attr->mq_msgsize)
657 {
658 set_errno (EMSGSIZE);
659 goto err;
660 }
661 if (attr->mq_curmsgs == 0)
662 {
663 if (mqhdr->mqh_pid != 0 && mqhdr->mqh_nwait == 0)
664 {
665 sigev = &mqhdr->mqh_event;
666 if (sigev->sigev_notify == SIGEV_SIGNAL)
667 sigqueue (mqhdr->mqh_pid, sigev->sigev_signo, sigev->sigev_value);
668 mqhdr->mqh_pid = 0; /* unregister */
669 }
670 }
671 else if (attr->mq_curmsgs >= attr->mq_maxmsg)
672 {
673 /* Queue is full */
674 if (mqinfo->mqi_flags & O_NONBLOCK)
675 {
676 set_errno (EAGAIN);
677 goto err;
678 }
679 /* Wait for room for one message on the queue */
680 while (attr->mq_curmsgs >= attr->mq_maxmsg)
681 ipc_cond_timedwait (mqinfo->mqi_wait, mqinfo->mqi_lock, abstime);
682 }
683
684 /* nmsghdr will point to new message */
685 if ((freeindex = mqhdr->mqh_free) == 0)
686 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr->mq_curmsgs);
687
688 nmsghdr = (struct msg_hdr *) &mptr[freeindex];
689 nmsghdr->msg_prio = prio;
690 nmsghdr->msg_len = len;
691 memcpy (nmsghdr + 1, ptr, len); /* copy message from caller */
692 mqhdr->mqh_free = nmsghdr->msg_next; /* new freelist head */
693
694 /* Find right place for message in linked list */
695 index = mqhdr->mqh_head;
696 pmsghdr = (struct msg_hdr *) &(mqhdr->mqh_head);
697 while (index)
698 {
699 msghdr = (struct msg_hdr *) &mptr[index];
700 if (prio > msghdr->msg_prio)
701 {
702 nmsghdr->msg_next = index;
703 pmsghdr->msg_next = freeindex;
704 break;
705 }
706 index = msghdr->msg_next;
707 pmsghdr = msghdr;
708 }
709 if (index == 0)
710 {
711 /* Queue was empty or new goes at end of list */
712 pmsghdr->msg_next = freeindex;
713 nmsghdr->msg_next = 0;
714 }
715 /* Wake up anyone blocked in mq_receive waiting for a message */
716 if (attr->mq_curmsgs == 0)
717 ipc_cond_signal (mqinfo->mqi_wait);
718 attr->mq_curmsgs++;
719
720 ipc_mutex_unlock (mqinfo->mqi_lock);
721 return 0;
722
723 err:
724 ipc_mutex_unlock (mqinfo->mqi_lock);
725 return -1;
726 }
727
728 extern "C" int
729 mq_send (mqd_t mqd, const char *ptr, size_t len, unsigned int prio)
730 {
731 return _mq_send (mqd, ptr, len, prio, NULL);
732 }
733
734 extern "C" int
735 mq_timedsend (mqd_t mqd, const char *ptr, size_t len, unsigned int prio,
736 const struct timespec *abstime)
737 {
738 return _mq_send (mqd, ptr, len, prio, abstime);
739 }
740
741 static ssize_t
742 _mq_receive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop,
743 const struct timespec *abstime)
744 {
745 int n;
746 long index;
747 int8_t *mptr;
748 ssize_t len;
749 struct mq_hdr *mqhdr;
750 struct mq_attr *attr;
751 struct msg_hdr *msghdr;
752 struct mq_info *mqinfo;
753
754 myfault efault;
755 if (efault.faulted (EBADF))
756 return -1;
757
758 mqinfo = (struct mq_info *) mqd;
759 if (mqinfo->mqi_magic != MQI_MAGIC)
760 {
761 set_errno (EBADF);
762 return -1;
763 }
764 mqhdr = mqinfo->mqi_hdr; /* struct pointer */
765 mptr = (int8_t *) mqhdr; /* byte pointer */
766 attr = &mqhdr->mqh_attr;
767 if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0)
768 {
769 errno = n;
770 return -1;
771 }
772
773 if (maxlen < (size_t) attr->mq_msgsize)
774 {
775 set_errno (EMSGSIZE);
776 goto err;
777 }
778 if (attr->mq_curmsgs == 0) /* queue is empty */
779 {
780 if (mqinfo->mqi_flags & O_NONBLOCK)
781 {
782 set_errno (EAGAIN);
783 goto err;
784 }
785 /* Wait for a message to be placed onto queue */
786 mqhdr->mqh_nwait++;
787 while (attr->mq_curmsgs == 0)
788 ipc_cond_timedwait (mqinfo->mqi_wait, mqinfo->mqi_lock, abstime);
789 mqhdr->mqh_nwait--;
790 }
791
792 if ((index = mqhdr->mqh_head) == 0)
793 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr->mq_curmsgs);
794
795 msghdr = (struct msg_hdr *) &mptr[index];
796 mqhdr->mqh_head = msghdr->msg_next; /* new head of list */
797 len = msghdr->msg_len;
798 memcpy(ptr, msghdr + 1, len); /* copy the message itself */
799 if (priop != NULL)
800 *priop = msghdr->msg_prio;
801
802 /* Just-read message goes to front of free list */
803 msghdr->msg_next = mqhdr->mqh_free;
804 mqhdr->mqh_free = index;
805
806 /* Wake up anyone blocked in mq_send waiting for room */
807 if (attr->mq_curmsgs == attr->mq_maxmsg)
808 ipc_cond_signal (mqinfo->mqi_wait);
809 attr->mq_curmsgs--;
810
811 ipc_mutex_unlock (mqinfo->mqi_lock);
812 return len;
813
814 err:
815 ipc_mutex_unlock (mqinfo->mqi_lock);
816 return -1;
817 }
818
819 extern "C" ssize_t
820 mq_receive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop)
821 {
822 return _mq_receive (mqd, ptr, maxlen, priop, NULL);
823 }
824
825 extern "C" ssize_t
826 mq_timedreceive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop,
827 const struct timespec *abstime)
828 {
829 return _mq_receive (mqd, ptr, maxlen, priop, abstime);
830 }
831
832 extern "C" int
833 mq_close (mqd_t mqd)
834 {
835 long msgsize, filesize;
836 struct mq_hdr *mqhdr;
837 struct mq_attr *attr;
838 struct mq_info *mqinfo;
839
840 myfault efault;
841 if (efault.faulted (EBADF))
842 return -1;
843
844 mqinfo = (struct mq_info *) mqd;
845 if (mqinfo->mqi_magic != MQI_MAGIC)
846 {
847 set_errno (EBADF);
848 return -1;
849 }
850 mqhdr = mqinfo->mqi_hdr;
851 attr = &mqhdr->mqh_attr;
852
853 if (mq_notify (mqd, NULL)) /* unregister calling process */
854 return -1;
855
856 msgsize = MSGSIZE (attr->mq_msgsize);
857 filesize = sizeof (struct mq_hdr)
858 + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize));
859 if (munmap (mqinfo->mqi_hdr, filesize) == -1)
860 return -1;
861
862 mqinfo->mqi_magic = 0; /* just in case */
863 ipc_cond_close (mqinfo->mqi_wait);
864 ipc_mutex_close (mqinfo->mqi_lock);
865 free (mqinfo);
866 return 0;
867 }
868
869 extern "C" int
870 mq_unlink (const char *name)
871 {
872 char mqname[CYG_MAX_PATH];
873
874 if (!check_path (mqname, mqueue, name))
875 return -1;
876 if (unlink (mqname) == -1)
877 return -1;
878 return 0;
879 }
880
881 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
882 implementation as far as sem_open is concerned, but under the hood using
883 the already existing semaphore class in thread.cc. Using a file backed
884 solution allows to implement kernel persistent named semaphores. */
885
886 struct sem_finfo
887 {
888 unsigned int value;
889 unsigned long long hash;
890 LUID luid;
891 };
892
893 extern "C" sem_t *
894 sem_open (const char *name, int oflag, ...)
895 {
896 int i, fd, created;
897 va_list ap;
898 mode_t mode = 0;
899 unsigned int value = 0;
900 struct __stat64 statbuff;
901 sem_t *sem = SEM_FAILED;
902 sem_finfo sf;
903 char semname[CYG_MAX_PATH];
904 bool wasopen = false;
905 ipc_flock file;
906
907 if (!check_path (semname, semaphore, name))
908 return SEM_FAILED;
909
910 myfault efault;
911 if (efault.faulted (EFAULT))
912 return SEM_FAILED;
913
914 created = 0;
915 oflag &= (O_CREAT | O_EXCL);
916
917 again:
918 if (oflag & O_CREAT)
919 {
920 va_start (ap, oflag); /* init ap to final named argument */
921 mode = va_arg (ap, mode_t) & ~S_IXUSR;
922 value = va_arg (ap, unsigned int);
923 va_end (ap);
924
925 /* Open and specify O_EXCL and user-execute */
926 fd = open (semname, oflag | O_EXCL | O_RDWR, mode | S_IXUSR);
927 if (fd < 0)
928 {
929 if (errno == EEXIST && (oflag & O_EXCL) == 0)
930 goto exists; /* already exists, OK */
931 return SEM_FAILED;
932 }
933 created = 1;
934 /* First one to create the file initializes it. */
935 if (!AllocateLocallyUniqueId (&sf.luid))
936 {
937 __seterrno ();
938 goto err;
939 }
940 sf.value = value;
941 sf.hash = hash_path_name (0, semname);
942 if (write (fd, &sf, sizeof sf) != sizeof sf)
943 goto err;
944 sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, value, wasopen);
945 if (sem == SEM_FAILED)
946 goto err;
947 /* Initialization complete, turn off user-execute bit */
948 if (fchmod (fd, mode) == -1)
949 goto err;
950 /* Don't close (fd); */
951 return sem;
952 }
953
954 exists:
955 /* Open the file and fetch the semaphore name. */
956 if ((fd = open (semname, O_RDWR)) < 0)
957 {
958 if (errno == ENOENT && (oflag & O_CREAT))
959 goto again;
960 goto err;
961 }
962 /* Make certain initialization is complete */
963 for (i = 0; i < MAX_TRIES; i++)
964 {
965 if (stat64 (semname, &statbuff) == -1)
966 {
967 if (errno == ENOENT && (oflag & O_CREAT))
968 {
969 close (fd);
970 goto again;
971 }
972 goto err;
973 }
974 if ((statbuff.st_mode & S_IXUSR) == 0)
975 break;
976 sleep (1);
977 }
978 if (i == MAX_TRIES)
979 {
980 set_errno (ETIMEDOUT);
981 goto err;
982 }
983 if (file.lock (fd, sizeof sf))
984 goto err;
985 if (read (fd, &sf, sizeof sf) != sizeof sf)
986 goto err;
987 sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, sf.value, wasopen);
988 file.unlock (fd);
989 if (sem == SEM_FAILED)
990 goto err;
991 /* If wasopen is set, the semaphore was already opened and we already have
992 an open file descriptor pointing to the file. This means, we have to
993 close the file descriptor created in this call. It won't be stored
994 anywhere anyway. */
995 if (wasopen)
996 close (fd);
997 return sem;
998
999 err:
1000 /* Don't let following function calls change errno */
1001 save_errno save;
1002
1003 file.unlock (fd);
1004 if (created)
1005 unlink (semname);
1006 if (sem != SEM_FAILED)
1007 semaphore::close (sem);
1008 close (fd);
1009 return SEM_FAILED;
1010 }
1011
1012 int
1013 _sem_close (sem_t *sem, bool do_close)
1014 {
1015 sem_finfo sf;
1016 int fd, ret = -1;
1017 ipc_flock file;
1018
1019 if (semaphore::getinternal (sem, &fd, &sf.hash, &sf.luid, &sf.value) == -1)
1020 return -1;
1021 if (!file.lock (fd, sizeof sf)
1022 && lseek64 (fd, 0LL, SEEK_SET) != (_off64_t) -1
1023 && write (fd, &sf, sizeof sf) == sizeof sf)
1024 ret = do_close ? semaphore::close (sem) : 0;
1025
1026 /* Don't let following function calls change errno */
1027 save_errno save;
1028 file.unlock (fd);
1029 close (fd);
1030
1031 return ret;
1032 }
1033
1034 extern "C" int
1035 sem_close (sem_t *sem)
1036 {
1037 return _sem_close (sem, true);
1038 }
1039
1040 extern "C" int
1041 sem_unlink (const char *name)
1042 {
1043 char semname[CYG_MAX_PATH];
1044
1045 if (!check_path (semname, semaphore, name))
1046 return -1;
1047 if (unlink (semname) == -1)
1048 return -1;
1049 return 0;
1050 }
This page took 0.082832 seconds and 6 git commands to generate.