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