]>
sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/posix_ipc.cc
1 /* posix_ipc.cc: POSIX IPC API for Cygwin.
3 Copyright 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 #include "shared_info.h"
22 #include <sys/param.h>
26 #include <semaphore.h>
28 /* The prefix_len is the length of the path prefix ncluding 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 /* Name must not be empty, or just be a single slash, or start with more
70 than one slash. Same for backslash.
71 Apart from handling backslash like slash, the naming rules are identical
72 to Linux, including the names and requirements for subdirectories, if
73 the name contains further slashes. */
74 if (!name
|| (strchr ("/\\", name
[0])
75 && (!name
[1] || strchr ("/\\", name
[1]))))
77 debug_printf ("Invalid %s name '%s'", ipc_names
[type
].description
, name
);
81 /* Skip leading (back-)slash. */
82 if (strchr ("/\\", name
[0]))
84 if (len
> PATH_MAX
- ipc_names
[type
].prefix_len
)
86 debug_printf ("%s name '%s' too long", ipc_names
[type
].description
, name
);
87 set_errno (ENAMETOOLONG
);
90 __small_sprintf (res_name
, "%s/%s%s", ipc_names
[type
].prefix
,
91 type
== semaphore
? "sem." : "",
97 ipc_mutex_init (HANDLE
*pmtx
, const char *name
)
100 UNICODE_STRING uname
;
101 OBJECT_ATTRIBUTES attr
;
104 __small_swprintf (buf
, L
"mqueue/mtx_%s", name
);
105 RtlInitUnicodeString (&uname
, buf
);
106 InitializeObjectAttributes (&attr
, &uname
,
107 OBJ_INHERIT
| OBJ_OPENIF
| OBJ_CASE_INSENSITIVE
,
108 get_shared_parent_dir (),
109 everyone_sd (CYG_MUTANT_ACCESS
));
110 status
= NtCreateMutant (pmtx
, CYG_MUTANT_ACCESS
, &attr
, FALSE
);
111 if (!NT_SUCCESS (status
))
113 debug_printf ("NtCreateMutant: %p", status
);
114 return geterrno_from_win_error (RtlNtStatusToDosError (status
));
120 ipc_mutex_lock (HANDLE mtx
)
122 switch (cygwait (mtx
, cw_infinite
, cw_sig_eintr
| cw_cancel
| cw_cancel_self
))
125 case WAIT_ABANDONED_0
:
133 return geterrno_from_win_error ();
137 ipc_mutex_unlock (HANDLE mtx
)
139 return ReleaseMutex (mtx
) ? 0 : geterrno_from_win_error ();
143 ipc_mutex_close (HANDLE mtx
)
145 return CloseHandle (mtx
) ? 0 : geterrno_from_win_error ();
149 ipc_cond_init (HANDLE
*pevt
, const char *name
, char sr
)
152 UNICODE_STRING uname
;
153 OBJECT_ATTRIBUTES attr
;
156 __small_swprintf (buf
, L
"mqueue/evt_%s%c", name
, sr
);
157 RtlInitUnicodeString (&uname
, buf
);
158 InitializeObjectAttributes (&attr
, &uname
,
159 OBJ_INHERIT
| OBJ_OPENIF
| OBJ_CASE_INSENSITIVE
,
160 get_shared_parent_dir (),
161 everyone_sd (CYG_EVENT_ACCESS
));
162 status
= NtCreateEvent (pevt
, CYG_EVENT_ACCESS
, &attr
,
163 NotificationEvent
, FALSE
);
164 if (!NT_SUCCESS (status
))
166 debug_printf ("NtCreateEvent: %p", status
);
167 return geterrno_from_win_error (RtlNtStatusToDosError (status
));
173 ipc_cond_timedwait (HANDLE evt
, HANDLE mtx
, const struct timespec
*abstime
)
175 HANDLE w4
[4] = { evt
, };
180 set_signal_arrived
here (w4
[1]);
181 if ((w4
[cnt
] = pthread::get_cancel_event ()) != NULL
)
185 if (abstime
->tv_sec
< 0
186 || abstime
->tv_nsec
< 0
187 || abstime
->tv_nsec
> 999999999)
190 /* If a timeout is set, we create a waitable timer to wait for.
191 This is the easiest way to handle the absolute timeout value, given
192 that NtSetTimer also takes absolute times and given the double
193 dependency on evt *and* mtx, which requires to call WFMO twice. */
195 LARGE_INTEGER duetime
;
198 status
= NtCreateTimer (&w4
[timer_idx
], TIMER_ALL_ACCESS
, NULL
,
200 if (!NT_SUCCESS (status
))
201 return geterrno_from_nt_status (status
);
202 timespec_to_filetime (abstime
, (FILETIME
*) &duetime
);
203 status
= NtSetTimer (w4
[timer_idx
], &duetime
, NULL
, NULL
, FALSE
, 0, NULL
);
204 if (!NT_SUCCESS (status
))
206 NtClose (w4
[timer_idx
]);
207 return geterrno_from_nt_status (status
);
211 if ((ret
= ipc_mutex_unlock (mtx
)) != 0)
213 /* Everything's set up, so now wait for the event to be signalled. */
215 switch (WaitForMultipleObjects (cnt
, w4
, FALSE
, INFINITE
))
219 case WAIT_OBJECT_0
+ 1:
220 if (_my_tls
.call_signal_handler ())
224 case WAIT_OBJECT_0
+ 2:
226 pthread::static_cancel_self ();
228 case WAIT_OBJECT_0
+ 3:
232 ret
= geterrno_from_win_error ();
237 /* At this point we need to lock the mutex. The wait is practically
238 the same as before, just that we now wait on the mutex instead of the
242 switch (WaitForMultipleObjects (cnt
, w4
, FALSE
, INFINITE
))
245 case WAIT_ABANDONED_0
:
247 case WAIT_OBJECT_0
+ 1:
248 if (_my_tls
.call_signal_handler ())
252 case WAIT_OBJECT_0
+ 2:
254 pthread_testcancel ();
256 case WAIT_OBJECT_0
+ 3:
260 ret
= geterrno_from_win_error ();
266 if (ret
!= ETIMEDOUT
)
267 NtCancelTimer (w4
[timer_idx
], NULL
);
268 NtClose (w4
[timer_idx
]);
274 ipc_cond_signal (HANDLE evt
)
280 ipc_cond_close (HANDLE evt
)
290 ipc_flock () { memset (&fl
, 0, sizeof fl
); }
292 int lock (int fd
, size_t size
)
295 fl
.l_whence
= SEEK_SET
;
298 return fcntl64 (fd
, F_SETLKW
, &fl
);
305 return fcntl64 (fd
, F_SETLKW
, &fl
);
309 /* POSIX shared memory object implementation. */
312 shm_open (const char *name
, int oflag
, mode_t mode
)
314 size_t len
= strlen (name
);
315 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
317 if (!check_path (shmname
, shmem
, name
, len
))
320 /* Check for valid flags. */
321 if (((oflag
& O_ACCMODE
) != O_RDONLY
&& (oflag
& O_ACCMODE
) != O_RDWR
)
322 || (oflag
& ~(O_ACCMODE
| O_CREAT
| O_EXCL
| O_TRUNC
)))
324 debug_printf ("Invalid oflag 0%o", oflag
);
329 return open (shmname
, oflag
| O_CLOEXEC
, mode
& 0777);
333 shm_unlink (const char *name
)
335 size_t len
= strlen (name
);
336 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
338 if (!check_path (shmname
, shmem
, name
, len
))
341 return unlink (shmname
);
344 /* The POSIX message queue implementation is based on W. Richard STEVENS
345 implementation, just tweaked for Cygwin. The main change is
346 the usage of Windows mutexes and events instead of using the pthread
347 synchronization objects. The pathname is massaged so that the
348 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
349 are implemented additionally. */
353 struct mq_attr mqh_attr
; /* the queue's attributes */
354 long mqh_head
; /* index of first message */
355 long mqh_free
; /* index of first free message */
356 long mqh_nwait
; /* #threads blocked in mq_receive() */
357 pid_t mqh_pid
; /* nonzero PID if mqh_event set */
358 char mqh_uname
[36]; /* unique name used to identify synchronization
359 objects connected to this queue */
360 struct sigevent mqh_event
; /* for mq_notify() */
365 long msg_next
; /* index of next on linked list */
366 ssize_t msg_len
; /* actual length */
367 unsigned int msg_prio
; /* priority */
372 struct mq_hdr
*mqi_hdr
; /* start of mmap'ed region */
373 unsigned long mqi_magic
; /* magic number if open */
374 int mqi_flags
; /* flags for this process */
375 HANDLE mqi_lock
; /* mutex lock */
376 HANDLE mqi_waitsend
; /* and condition variable for full queue */
377 HANDLE mqi_waitrecv
; /* and condition variable for empty queue */
380 #define MQI_MAGIC 0x98765432UL
382 #define MSGSIZE(i) roundup((i), sizeof(long))
384 #define MAX_TRIES 10 /* for waiting for initialization */
386 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
388 extern "C" _off64_t
lseek64 (int, _off64_t
, int);
389 extern "C" void *mmap64 (void *, size_t, int, int, int, _off64_t
);
392 mq_open (const char *name
, int oflag
, ...)
394 int i
, fd
= -1, nonblock
, created
;
396 _off64_t filesize
= 0;
400 struct __stat64 statbuff
;
401 struct mq_hdr
*mqhdr
;
402 struct msg_hdr
*msghdr
;
403 struct mq_attr
*attr
;
404 struct mq_info
*mqinfo
;
407 size_t len
= strlen (name
);
408 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
410 if (!check_path (mqname
, mqueue
, name
, len
))
414 if (efault
.faulted (EFAULT
))
417 oflag
&= (O_CREAT
| O_EXCL
| O_NONBLOCK
);
419 nonblock
= oflag
& O_NONBLOCK
;
420 oflag
&= ~O_NONBLOCK
;
421 mptr
= (int8_t *) MAP_FAILED
;
427 va_start (ap
, oflag
); /* init ap to final named argument */
428 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
429 attr
= va_arg (ap
, struct mq_attr
*);
432 /* Open and specify O_EXCL and user-execute */
433 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
, mode
| S_IXUSR
);
436 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
437 goto exists
; /* already exists, OK */
441 /* First one to create the file initializes it */
444 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_msgsize
<= 0)
449 /* Calculate and set the file size */
450 msgsize
= MSGSIZE (attr
->mq_msgsize
);
451 filesize
= sizeof (struct mq_hdr
)
452 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
453 if (lseek64 (fd
, filesize
- 1, SEEK_SET
) == -1)
455 if (write (fd
, "", 1) == -1)
458 /* Memory map the file */
459 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
461 if (mptr
== (int8_t *) MAP_FAILED
)
464 /* Allocate one mq_info{} for the queue */
465 if (!(mqinfo
= (struct mq_info
*) calloc (1, sizeof (struct mq_info
))))
467 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
468 mqinfo
->mqi_magic
= MQI_MAGIC
;
469 mqinfo
->mqi_flags
= nonblock
;
471 /* Initialize header at beginning of file */
472 /* Create free list with all messages on it */
473 mqhdr
->mqh_attr
.mq_flags
= 0;
474 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
475 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
476 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
477 mqhdr
->mqh_nwait
= 0;
479 NtAllocateLocallyUniqueId (&luid
);
480 __small_sprintf (mqhdr
->mqh_uname
, "%016X%08x%08x",
481 hash_path_name (0,mqname
),
482 luid
.HighPart
, luid
.LowPart
);
484 index
= sizeof (struct mq_hdr
);
485 mqhdr
->mqh_free
= index
;
486 for (i
= 0; i
< attr
->mq_maxmsg
- 1; i
++)
488 msghdr
= (struct msg_hdr
*) &mptr
[index
];
489 index
+= sizeof (struct msg_hdr
) + msgsize
;
490 msghdr
->msg_next
= index
;
492 msghdr
= (struct msg_hdr
*) &mptr
[index
];
493 msghdr
->msg_next
= 0; /* end of free list */
495 /* Initialize mutex & condition variables */
496 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
500 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
504 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
508 /* Initialization complete, turn off user-execute bit */
509 if (fchmod (fd
, mode
) == -1)
512 return ((mqd_t
) mqinfo
);
516 /* Open the file then memory map */
517 if ((fd
= open (mqname
, O_RDWR
| O_CLOEXEC
)) < 0)
519 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
523 /* Make certain initialization is complete */
524 for (i
= 0; i
< MAX_TRIES
; i
++)
526 if (stat64 (mqname
, &statbuff
) == -1)
528 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
536 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
542 set_errno (ETIMEDOUT
);
546 filesize
= statbuff
.st_size
;
547 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
549 if (mptr
== (int8_t *) MAP_FAILED
)
554 /* Allocate one mq_info{} for each open */
555 if (!(mqinfo
= (struct mq_info
*) calloc (1, sizeof (struct mq_info
))))
557 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
558 mqinfo
->mqi_magic
= MQI_MAGIC
;
559 mqinfo
->mqi_flags
= nonblock
;
561 /* Initialize mutex & condition variable */
562 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
566 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
570 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
574 return (mqd_t
) mqinfo
;
579 /* Don't let following function calls change errno */
584 if (mptr
!= (int8_t *) MAP_FAILED
)
585 munmap((void *) mptr
, (size_t) filesize
);
588 if (mqinfo
->mqi_lock
)
589 ipc_mutex_close (mqinfo
->mqi_lock
);
590 if (mqinfo
->mqi_waitsend
)
591 ipc_cond_close (mqinfo
->mqi_waitsend
);
592 if (mqinfo
->mqi_waitrecv
)
593 ipc_cond_close (mqinfo
->mqi_waitrecv
);
602 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
605 struct mq_hdr
*mqhdr
;
606 struct mq_attr
*attr
;
607 struct mq_info
*mqinfo
;
610 if (efault
.faulted (EBADF
))
613 mqinfo
= (struct mq_info
*) mqd
;
614 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
619 mqhdr
= mqinfo
->mqi_hdr
;
620 attr
= &mqhdr
->mqh_attr
;
621 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
626 mqstat
->mq_flags
= mqinfo
->mqi_flags
; /* per-open */
627 mqstat
->mq_maxmsg
= attr
->mq_maxmsg
; /* remaining three per-queue */
628 mqstat
->mq_msgsize
= attr
->mq_msgsize
;
629 mqstat
->mq_curmsgs
= attr
->mq_curmsgs
;
631 ipc_mutex_unlock (mqinfo
->mqi_lock
);
636 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
639 struct mq_hdr
*mqhdr
;
640 struct mq_attr
*attr
;
641 struct mq_info
*mqinfo
;
644 if (efault
.faulted (EBADF
))
647 mqinfo
= (struct mq_info
*) mqd
;
648 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
653 mqhdr
= mqinfo
->mqi_hdr
;
654 attr
= &mqhdr
->mqh_attr
;
655 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
663 omqstat
->mq_flags
= mqinfo
->mqi_flags
; /* previous attributes */
664 omqstat
->mq_maxmsg
= attr
->mq_maxmsg
;
665 omqstat
->mq_msgsize
= attr
->mq_msgsize
;
666 omqstat
->mq_curmsgs
= attr
->mq_curmsgs
; /* and current status */
669 if (mqstat
->mq_flags
& O_NONBLOCK
)
670 mqinfo
->mqi_flags
|= O_NONBLOCK
;
672 mqinfo
->mqi_flags
&= ~O_NONBLOCK
;
674 ipc_mutex_unlock (mqinfo
->mqi_lock
);
679 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
683 struct mq_hdr
*mqhdr
;
684 struct mq_info
*mqinfo
;
687 if (efault
.faulted (EBADF
))
690 mqinfo
= (struct mq_info
*) mqd
;
691 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
696 mqhdr
= mqinfo
->mqi_hdr
;
697 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
706 if (mqhdr
->mqh_pid
== pid
)
707 mqhdr
->mqh_pid
= 0; /* unregister calling process */
711 if (mqhdr
->mqh_pid
!= 0)
713 if (kill (mqhdr
->mqh_pid
, 0) != -1 || errno
!= ESRCH
)
716 ipc_mutex_unlock (mqinfo
->mqi_lock
);
720 mqhdr
->mqh_pid
= pid
;
721 mqhdr
->mqh_event
= *notification
;
723 ipc_mutex_unlock (mqinfo
->mqi_lock
);
728 _mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
729 const struct timespec
*abstime
)
732 long index
, freeindex
;
734 struct sigevent
*sigev
;
735 struct mq_hdr
*mqhdr
;
736 struct mq_attr
*attr
;
737 struct msg_hdr
*msghdr
, *nmsghdr
, *pmsghdr
;
738 struct mq_info
*mqinfo
;
740 pthread_testcancel ();
743 if (efault
.faulted (EBADF
))
746 mqinfo
= (struct mq_info
*) mqd
;
747 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
752 if (prio
> MQ_PRIO_MAX
)
758 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
759 mptr
= (int8_t *) mqhdr
; /* byte pointer */
760 attr
= &mqhdr
->mqh_attr
;
761 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
767 if (len
> (size_t) attr
->mq_msgsize
)
769 set_errno (EMSGSIZE
);
772 if (attr
->mq_curmsgs
== 0)
774 if (mqhdr
->mqh_pid
!= 0 && mqhdr
->mqh_nwait
== 0)
776 sigev
= &mqhdr
->mqh_event
;
777 if (sigev
->sigev_notify
== SIGEV_SIGNAL
)
778 sigqueue (mqhdr
->mqh_pid
, sigev
->sigev_signo
, sigev
->sigev_value
);
779 mqhdr
->mqh_pid
= 0; /* unregister */
782 else if (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
785 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
790 /* Wait for room for one message on the queue */
791 while (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
793 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitsend
, mqinfo
->mqi_lock
,
803 /* nmsghdr will point to new message */
804 if ((freeindex
= mqhdr
->mqh_free
) == 0)
805 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr
->mq_curmsgs
);
807 nmsghdr
= (struct msg_hdr
*) &mptr
[freeindex
];
808 nmsghdr
->msg_prio
= prio
;
809 nmsghdr
->msg_len
= len
;
810 memcpy (nmsghdr
+ 1, ptr
, len
); /* copy message from caller */
811 mqhdr
->mqh_free
= nmsghdr
->msg_next
; /* new freelist head */
813 /* Find right place for message in linked list */
814 index
= mqhdr
->mqh_head
;
815 pmsghdr
= (struct msg_hdr
*) &(mqhdr
->mqh_head
);
818 msghdr
= (struct msg_hdr
*) &mptr
[index
];
819 if (prio
> msghdr
->msg_prio
)
821 nmsghdr
->msg_next
= index
;
822 pmsghdr
->msg_next
= freeindex
;
825 index
= msghdr
->msg_next
;
830 /* Queue was empty or new goes at end of list */
831 pmsghdr
->msg_next
= freeindex
;
832 nmsghdr
->msg_next
= 0;
834 /* Wake up anyone blocked in mq_receive waiting for a message */
835 if (attr
->mq_curmsgs
== 0)
836 ipc_cond_signal (mqinfo
->mqi_waitrecv
);
839 ipc_mutex_unlock (mqinfo
->mqi_lock
);
843 ipc_mutex_unlock (mqinfo
->mqi_lock
);
848 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
850 return _mq_send (mqd
, ptr
, len
, prio
, NULL
);
854 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
855 const struct timespec
*abstime
)
857 return _mq_send (mqd
, ptr
, len
, prio
, abstime
);
861 _mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
862 const struct timespec
*abstime
)
868 struct mq_hdr
*mqhdr
;
869 struct mq_attr
*attr
;
870 struct msg_hdr
*msghdr
;
871 struct mq_info
*mqinfo
;
873 pthread_testcancel ();
876 if (efault
.faulted (EBADF
))
879 mqinfo
= (struct mq_info
*) mqd
;
880 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
885 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
886 mptr
= (int8_t *) mqhdr
; /* byte pointer */
887 attr
= &mqhdr
->mqh_attr
;
888 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
894 if (maxlen
< (size_t) attr
->mq_msgsize
)
896 set_errno (EMSGSIZE
);
899 if (attr
->mq_curmsgs
== 0) /* queue is empty */
901 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
906 /* Wait for a message to be placed onto queue */
908 while (attr
->mq_curmsgs
== 0)
910 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitrecv
, mqinfo
->mqi_lock
,
921 if ((index
= mqhdr
->mqh_head
) == 0)
922 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr
->mq_curmsgs
);
924 msghdr
= (struct msg_hdr
*) &mptr
[index
];
925 mqhdr
->mqh_head
= msghdr
->msg_next
; /* new head of list */
926 len
= msghdr
->msg_len
;
927 memcpy(ptr
, msghdr
+ 1, len
); /* copy the message itself */
929 *priop
= msghdr
->msg_prio
;
931 /* Just-read message goes to front of free list */
932 msghdr
->msg_next
= mqhdr
->mqh_free
;
933 mqhdr
->mqh_free
= index
;
935 /* Wake up anyone blocked in mq_send waiting for room */
936 if (attr
->mq_curmsgs
== attr
->mq_maxmsg
)
937 ipc_cond_signal (mqinfo
->mqi_waitsend
);
940 ipc_mutex_unlock (mqinfo
->mqi_lock
);
944 ipc_mutex_unlock (mqinfo
->mqi_lock
);
949 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
951 return _mq_receive (mqd
, ptr
, maxlen
, priop
, NULL
);
955 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
956 const struct timespec
*abstime
)
958 return _mq_receive (mqd
, ptr
, maxlen
, priop
, abstime
);
964 long msgsize
, filesize
;
965 struct mq_hdr
*mqhdr
;
966 struct mq_attr
*attr
;
967 struct mq_info
*mqinfo
;
970 if (efault
.faulted (EBADF
))
973 mqinfo
= (struct mq_info
*) mqd
;
974 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
979 mqhdr
= mqinfo
->mqi_hdr
;
980 attr
= &mqhdr
->mqh_attr
;
982 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
985 msgsize
= MSGSIZE (attr
->mq_msgsize
);
986 filesize
= sizeof (struct mq_hdr
)
987 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
988 if (munmap (mqinfo
->mqi_hdr
, filesize
) == -1)
991 mqinfo
->mqi_magic
= 0; /* just in case */
992 ipc_cond_close (mqinfo
->mqi_waitsend
);
993 ipc_cond_close (mqinfo
->mqi_waitrecv
);
994 ipc_mutex_close (mqinfo
->mqi_lock
);
1000 mq_unlink (const char *name
)
1002 size_t len
= strlen (name
);
1003 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
1005 if (!check_path (mqname
, mqueue
, name
, len
))
1007 if (unlink (mqname
) == -1)
1012 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
1013 implementation as far as sem_open is concerned, but under the hood using
1014 the already existing semaphore class in thread.cc. Using a file backed
1015 solution allows to implement kernel persistent named semaphores. */
1020 unsigned long long hash
;
1025 sem_open (const char *name
, int oflag
, ...)
1027 int i
, fd
= -1, created
;
1030 unsigned int value
= 0;
1031 struct __stat64 statbuff
;
1032 sem_t
*sem
= SEM_FAILED
;
1034 bool wasopen
= false;
1037 size_t len
= strlen (name
);
1038 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1040 if (!check_path (semname
, semaphore
, name
, len
))
1044 if (efault
.faulted (EFAULT
))
1048 oflag
&= (O_CREAT
| O_EXCL
);
1051 if (oflag
& O_CREAT
)
1053 va_start (ap
, oflag
); /* init ap to final named argument */
1054 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
1055 value
= va_arg (ap
, unsigned int);
1058 /* Open and specify O_EXCL and user-execute */
1059 fd
= open (semname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
, mode
| S_IXUSR
);
1062 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
1063 goto exists
; /* already exists, OK */
1067 /* First one to create the file initializes it. */
1068 NtAllocateLocallyUniqueId (&sf
.luid
);
1070 sf
.hash
= hash_path_name (0, semname
);
1071 if (write (fd
, &sf
, sizeof sf
) != sizeof sf
)
1073 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, value
, wasopen
);
1074 if (sem
== SEM_FAILED
)
1076 /* Initialization complete, turn off user-execute bit */
1077 if (fchmod (fd
, mode
) == -1)
1079 /* Don't close (fd); */
1084 /* Open the file and fetch the semaphore name. */
1085 if ((fd
= open (semname
, O_RDWR
| O_CLOEXEC
)) < 0)
1087 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1091 /* Make certain initialization is complete */
1092 for (i
= 0; i
< MAX_TRIES
; i
++)
1094 if (stat64 (semname
, &statbuff
) == -1)
1096 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1104 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
1110 set_errno (ETIMEDOUT
);
1113 if (file
.lock (fd
, sizeof sf
))
1115 if (read (fd
, &sf
, sizeof sf
) != sizeof sf
)
1117 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, sf
.value
, wasopen
);
1119 if (sem
== SEM_FAILED
)
1121 /* If wasopen is set, the semaphore was already opened and we already have
1122 an open file descriptor pointing to the file. This means, we have to
1123 close the file descriptor created in this call. It won't be stored
1130 /* Don't let following function calls change errno */
1136 if (sem
!= SEM_FAILED
)
1137 semaphore::close (sem
);
1144 _sem_close (sem_t
*sem
, bool do_close
)
1150 if (semaphore::getinternal (sem
, &fd
, &sf
.hash
, &sf
.luid
, &sf
.value
) == -1)
1152 if (!file
.lock (fd
, sizeof sf
)
1153 && lseek64 (fd
, 0LL, SEEK_SET
) != (_off64_t
) -1
1154 && write (fd
, &sf
, sizeof sf
) == sizeof sf
)
1155 ret
= do_close
? semaphore::close (sem
) : 0;
1157 /* Don't let following function calls change errno */
1166 sem_close (sem_t
*sem
)
1168 return _sem_close (sem
, true);
1172 sem_unlink (const char *name
)
1174 size_t len
= strlen (name
);
1175 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1177 if (!check_path (semname
, semaphore
, name
, len
))
1179 if (unlink (semname
) == -1)
This page took 0.088392 seconds and 5 git commands to generate.