]>
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, 2014, 2015 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: %y", status
);
114 return geterrno_from_win_error (RtlNtStatusToDosError (status
));
120 ipc_mutex_lock (HANDLE mtx
, bool eintr
)
122 switch (cygwait (mtx
, cw_infinite
, cw_cancel
| cw_cancel_self
123 | (eintr
? cw_sig_eintr
: cw_sig_restart
)))
126 case WAIT_ABANDONED_0
:
134 return geterrno_from_win_error ();
138 ipc_mutex_unlock (HANDLE mtx
)
140 return ReleaseMutex (mtx
) ? 0 : geterrno_from_win_error ();
144 ipc_mutex_close (HANDLE mtx
)
146 return CloseHandle (mtx
) ? 0 : geterrno_from_win_error ();
150 ipc_cond_init (HANDLE
*pevt
, const char *name
, char sr
)
153 UNICODE_STRING uname
;
154 OBJECT_ATTRIBUTES attr
;
157 __small_swprintf (buf
, L
"mqueue/evt_%s%c", name
, sr
);
158 RtlInitUnicodeString (&uname
, buf
);
159 InitializeObjectAttributes (&attr
, &uname
,
160 OBJ_INHERIT
| OBJ_OPENIF
| OBJ_CASE_INSENSITIVE
,
161 get_shared_parent_dir (),
162 everyone_sd (CYG_EVENT_ACCESS
));
163 status
= NtCreateEvent (pevt
, CYG_EVENT_ACCESS
, &attr
,
164 NotificationEvent
, FALSE
);
165 if (!NT_SUCCESS (status
))
167 debug_printf ("NtCreateEvent: %y", status
);
168 return geterrno_from_win_error (RtlNtStatusToDosError (status
));
174 ipc_cond_timedwait (HANDLE evt
, HANDLE mtx
, const struct timespec
*abstime
)
176 HANDLE w4
[4] = { evt
, };
181 wait_signal_arrived
here (w4
[1]);
182 if ((w4
[cnt
] = pthread::get_cancel_event ()) != NULL
)
186 if (abstime
->tv_sec
< 0
187 || abstime
->tv_nsec
< 0
188 || abstime
->tv_nsec
> 999999999)
191 /* If a timeout is set, we create a waitable timer to wait for.
192 This is the easiest way to handle the absolute timeout value, given
193 that NtSetTimer also takes absolute times and given the double
194 dependency on evt *and* mtx, which requires to call WFMO twice. */
196 LARGE_INTEGER duetime
;
199 status
= NtCreateTimer (&w4
[timer_idx
], TIMER_ALL_ACCESS
, NULL
,
201 if (!NT_SUCCESS (status
))
202 return geterrno_from_nt_status (status
);
203 timespec_to_filetime (abstime
, &duetime
);
204 status
= NtSetTimer (w4
[timer_idx
], &duetime
, NULL
, NULL
, FALSE
, 0, NULL
);
205 if (!NT_SUCCESS (status
))
207 NtClose (w4
[timer_idx
]);
208 return geterrno_from_nt_status (status
);
212 if ((ret
= ipc_mutex_unlock (mtx
)) != 0)
214 /* Everything's set up, so now wait for the event to be signalled. */
216 switch (WaitForMultipleObjects (cnt
, w4
, FALSE
, INFINITE
))
220 case WAIT_OBJECT_0
+ 1:
221 if (_my_tls
.call_signal_handler ())
225 case WAIT_OBJECT_0
+ 2:
227 pthread::static_cancel_self ();
229 case WAIT_OBJECT_0
+ 3:
233 ret
= geterrno_from_win_error ();
238 /* At this point we need to lock the mutex. The wait is practically
239 the same as before, just that we now wait on the mutex instead of the
243 switch (WaitForMultipleObjects (cnt
, w4
, FALSE
, INFINITE
))
246 case WAIT_ABANDONED_0
:
248 case WAIT_OBJECT_0
+ 1:
249 if (_my_tls
.call_signal_handler ())
253 case WAIT_OBJECT_0
+ 2:
255 pthread_testcancel ();
257 case WAIT_OBJECT_0
+ 3:
261 ret
= geterrno_from_win_error ();
267 if (ret
!= ETIMEDOUT
)
268 NtCancelTimer (w4
[timer_idx
], NULL
);
269 NtClose (w4
[timer_idx
]);
275 ipc_cond_signal (HANDLE evt
)
281 ipc_cond_close (HANDLE evt
)
291 ipc_flock () { memset (&fl
, 0, sizeof fl
); }
293 int lock (int fd
, size_t size
)
296 fl
.l_whence
= SEEK_SET
;
299 return fcntl64 (fd
, F_SETLKW
, &fl
);
306 return fcntl64 (fd
, F_SETLKW
, &fl
);
310 /* POSIX shared memory object implementation. */
313 shm_open (const char *name
, int oflag
, mode_t mode
)
315 size_t len
= strlen (name
);
316 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
318 if (!check_path (shmname
, shmem
, name
, len
))
321 /* Check for valid flags. */
322 if (((oflag
& O_ACCMODE
) != O_RDONLY
&& (oflag
& O_ACCMODE
) != O_RDWR
)
323 || (oflag
& ~(O_ACCMODE
| O_CREAT
| O_EXCL
| O_TRUNC
)))
325 debug_printf ("Invalid oflag 0%o", oflag
);
330 return open (shmname
, oflag
| O_CLOEXEC
, mode
& 0777);
334 shm_unlink (const char *name
)
336 size_t len
= strlen (name
);
337 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
339 if (!check_path (shmname
, shmem
, name
, len
))
342 return unlink (shmname
);
345 /* The POSIX message queue implementation is based on W. Richard STEVENS
346 implementation, just tweaked for Cygwin. The main change is
347 the usage of Windows mutexes and events instead of using the pthread
348 synchronization objects. The pathname is massaged so that the
349 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
350 are implemented additionally. */
352 /* The mq_attr structure is defined using long datatypes per POSIX.
353 For interoperability reasons between 32 and 64 bit processes, we have
354 to make sure to use a unified structure layout in the message queue file.
355 That's what the mq_fattr is, the in-file representation of the mq_attr
357 #pragma pack (push, 4)
368 struct mq_fattr mqh_attr
; /* the queue's attributes */
369 int32_t mqh_head
; /* index of first message */
370 int32_t mqh_free
; /* index of first free message */
371 int32_t mqh_nwait
; /* #threads blocked in mq_receive() */
372 pid_t mqh_pid
; /* nonzero PID if mqh_event set */
373 char mqh_uname
[36]; /* unique name used to identify synchronization
374 objects connected to this queue */
376 struct sigevent mqh_event
; /* for mq_notify() */
377 /* Make sure sigevent takes the same space on 32 and 64 bit systems.
378 Other than that, it doesn't need to be compatible since only
379 one process can be notified at a time. */
380 uint64_t mqh_placeholder
[8];
382 uint32_t mqh_magic
; /* Expect MQI_MAGIC here, otherwise it's
383 an old-style message queue. */
388 int32_t msg_next
; /* index of next on linked list */
389 int32_t msg_len
; /* actual length */
390 unsigned int msg_prio
; /* priority */
396 struct mq_hdr
*mqi_hdr
; /* start of mmap'ed region */
397 uint32_t mqi_magic
; /* magic number if open */
398 int mqi_flags
; /* flags for this process */
399 HANDLE mqi_lock
; /* mutex lock */
400 HANDLE mqi_waitsend
; /* and condition variable for full queue */
401 HANDLE mqi_waitrecv
; /* and condition variable for empty queue */
404 #define MQI_MAGIC 0x98765432UL
406 #define MSGSIZE(i) roundup((i), sizeof(long))
408 #define MAX_TRIES 10 /* for waiting for initialization */
410 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
412 extern "C" off_t
lseek64 (int, off_t
, int);
413 extern "C" void *mmap64 (void *, size_t, int, int, int, off_t
);
416 mq_open (const char *name
, int oflag
, ...)
418 int i
, fd
= -1, nonblock
, created
= 0;
423 int8_t *mptr
= (int8_t *) MAP_FAILED
;
424 struct stat statbuff
;
425 struct mq_hdr
*mqhdr
;
426 struct msg_hdr
*msghdr
;
427 struct mq_attr
*attr
;
428 struct mq_info
*mqinfo
= NULL
;
431 size_t len
= strlen (name
);
432 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
434 if (!check_path (mqname
, mqueue
, name
, len
))
439 oflag
&= (O_CREAT
| O_EXCL
| O_NONBLOCK
);
440 nonblock
= oflag
& O_NONBLOCK
;
441 oflag
&= ~O_NONBLOCK
;
446 va_start (ap
, oflag
); /* init ap to final named argument */
447 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
448 attr
= va_arg (ap
, struct mq_attr
*);
451 /* Open and specify O_EXCL and user-execute */
452 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
,
456 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
457 goto exists
; /* already exists, OK */
461 /* First one to create the file initializes it */
464 /* Check minimum and maximum values. The max values are pretty much
465 arbitrary, taken from the linux mq_overview man page. However,
466 these max values make sure that the internal mq_fattr structure
467 can use 32 bit types. */
468 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_maxmsg
> 32768
469 || attr
->mq_msgsize
<= 0 || attr
->mq_msgsize
> 1048576)
474 /* Calculate and set the file size */
475 msgsize
= MSGSIZE (attr
->mq_msgsize
);
476 filesize
= sizeof (struct mq_hdr
)
477 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
478 if (lseek64 (fd
, filesize
- 1, SEEK_SET
) == -1)
480 if (write (fd
, "", 1) == -1)
483 /* Memory map the file */
484 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
,
485 PROT_READ
| PROT_WRITE
,
487 if (mptr
== (int8_t *) MAP_FAILED
)
490 /* Allocate one mq_info{} for the queue */
491 if (!(mqinfo
= (struct mq_info
*)
492 calloc (1, sizeof (struct mq_info
))))
494 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
495 mqinfo
->mqi_magic
= MQI_MAGIC
;
496 mqinfo
->mqi_flags
= nonblock
;
498 /* Initialize header at beginning of file */
499 /* Create free list with all messages on it */
500 mqhdr
->mqh_attr
.mq_flags
= 0;
501 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
502 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
503 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
504 mqhdr
->mqh_nwait
= 0;
506 NtAllocateLocallyUniqueId (&luid
);
507 __small_sprintf (mqhdr
->mqh_uname
, "%016X%08x%08x",
508 hash_path_name (0,mqname
),
509 luid
.HighPart
, luid
.LowPart
);
511 mqhdr
->mqh_magic
= MQI_MAGIC
;
512 index
= sizeof (struct mq_hdr
);
513 mqhdr
->mqh_free
= index
;
514 for (i
= 0; i
< attr
->mq_maxmsg
- 1; i
++)
516 msghdr
= (struct msg_hdr
*) &mptr
[index
];
517 index
+= sizeof (struct msg_hdr
) + msgsize
;
518 msghdr
->msg_next
= index
;
520 msghdr
= (struct msg_hdr
*) &mptr
[index
];
521 msghdr
->msg_next
= 0; /* end of free list */
523 /* Initialize mutex & condition variables */
524 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
530 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
536 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
542 /* Initialization complete, turn off user-execute bit */
543 if (fchmod (fd
, mode
) == -1)
546 return ((mqd_t
) mqinfo
);
550 /* Open the file then memory map */
551 if ((fd
= open (mqname
, O_RDWR
| O_CLOEXEC
)) < 0)
553 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
557 /* Make certain initialization is complete */
558 for (i
= 0; i
< MAX_TRIES
; i
++)
560 if (stat64 (mqname
, &statbuff
) == -1)
562 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
570 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
576 set_errno (ETIMEDOUT
);
580 filesize
= statbuff
.st_size
;
581 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
583 if (mptr
== (int8_t *) MAP_FAILED
)
588 /* Allocate one mq_info{} for each open */
589 if (!(mqinfo
= (struct mq_info
*) calloc (1, sizeof (struct mq_info
))))
591 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
592 if (mqhdr
->mqh_magic
!= MQI_MAGIC
)
595 "Old message queue \"%s\" detected!\n"
596 "This file is not usable as message queue anymore due to changes in the "
597 "internal file layout. Please remove the file and try again.", mqname
);
601 mqinfo
->mqi_magic
= MQI_MAGIC
;
602 mqinfo
->mqi_flags
= nonblock
;
604 /* Initialize mutex & condition variable */
605 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
611 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
617 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
623 return (mqd_t
) mqinfo
;
627 /* Don't let following function calls change errno */
631 if (mptr
!= (int8_t *) MAP_FAILED
)
632 munmap((void *) mptr
, (size_t) filesize
);
635 if (mqinfo
->mqi_lock
)
636 ipc_mutex_close (mqinfo
->mqi_lock
);
637 if (mqinfo
->mqi_waitsend
)
638 ipc_cond_close (mqinfo
->mqi_waitsend
);
639 if (mqinfo
->mqi_waitrecv
)
640 ipc_cond_close (mqinfo
->mqi_waitrecv
);
649 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
652 struct mq_hdr
*mqhdr
;
653 struct mq_fattr
*attr
;
654 struct mq_info
*mqinfo
;
658 mqinfo
= (struct mq_info
*) mqd
;
659 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
664 mqhdr
= mqinfo
->mqi_hdr
;
665 attr
= &mqhdr
->mqh_attr
;
666 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, false)) != 0)
671 mqstat
->mq_flags
= mqinfo
->mqi_flags
; /* per-open */
672 mqstat
->mq_maxmsg
= attr
->mq_maxmsg
; /* remaining three per-queue */
673 mqstat
->mq_msgsize
= attr
->mq_msgsize
;
674 mqstat
->mq_curmsgs
= attr
->mq_curmsgs
;
676 ipc_mutex_unlock (mqinfo
->mqi_lock
);
685 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
688 struct mq_hdr
*mqhdr
;
689 struct mq_fattr
*attr
;
690 struct mq_info
*mqinfo
;
694 mqinfo
= (struct mq_info
*) mqd
;
695 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
700 mqhdr
= mqinfo
->mqi_hdr
;
701 attr
= &mqhdr
->mqh_attr
;
702 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, false)) != 0)
710 omqstat
->mq_flags
= mqinfo
->mqi_flags
; /* previous attributes */
711 omqstat
->mq_maxmsg
= attr
->mq_maxmsg
;
712 omqstat
->mq_msgsize
= attr
->mq_msgsize
;
713 omqstat
->mq_curmsgs
= attr
->mq_curmsgs
; /* and current status */
716 if (mqstat
->mq_flags
& O_NONBLOCK
)
717 mqinfo
->mqi_flags
|= O_NONBLOCK
;
719 mqinfo
->mqi_flags
&= ~O_NONBLOCK
;
721 ipc_mutex_unlock (mqinfo
->mqi_lock
);
730 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
734 struct mq_hdr
*mqhdr
;
735 struct mq_info
*mqinfo
;
739 mqinfo
= (struct mq_info
*) mqd
;
740 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
745 mqhdr
= mqinfo
->mqi_hdr
;
746 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, false)) != 0)
755 if (mqhdr
->mqh_pid
== pid
)
756 mqhdr
->mqh_pid
= 0; /* unregister calling process */
760 if (mqhdr
->mqh_pid
!= 0)
762 if (kill (mqhdr
->mqh_pid
, 0) != -1 || errno
!= ESRCH
)
765 ipc_mutex_unlock (mqinfo
->mqi_lock
);
769 mqhdr
->mqh_pid
= pid
;
770 mqhdr
->mqh_event
= *notification
;
772 ipc_mutex_unlock (mqinfo
->mqi_lock
);
781 _mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
782 const struct timespec
*abstime
)
785 long index
, freeindex
;
787 struct sigevent
*sigev
;
788 struct mq_hdr
*mqhdr
;
789 struct mq_fattr
*attr
;
790 struct msg_hdr
*msghdr
, *nmsghdr
, *pmsghdr
;
791 struct mq_info
*mqinfo
= NULL
;
792 bool ipc_mutex_locked
= false;
795 pthread_testcancel ();
799 mqinfo
= (struct mq_info
*) mqd
;
800 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
805 if (prio
> MQ_PRIO_MAX
)
811 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
812 mptr
= (int8_t *) mqhdr
; /* byte pointer */
813 attr
= &mqhdr
->mqh_attr
;
814 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, true)) != 0)
819 ipc_mutex_locked
= true;
820 if (len
> (size_t) attr
->mq_msgsize
)
822 set_errno (EMSGSIZE
);
825 if (attr
->mq_curmsgs
== 0)
827 if (mqhdr
->mqh_pid
!= 0 && mqhdr
->mqh_nwait
== 0)
829 sigev
= &mqhdr
->mqh_event
;
830 if (sigev
->sigev_notify
== SIGEV_SIGNAL
)
831 sigqueue (mqhdr
->mqh_pid
, sigev
->sigev_signo
,
833 mqhdr
->mqh_pid
= 0; /* unregister */
836 else if (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
839 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
844 /* Wait for room for one message on the queue */
845 while (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
847 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitsend
,
848 mqinfo
->mqi_lock
, abstime
);
857 /* nmsghdr will point to new message */
858 if ((freeindex
= mqhdr
->mqh_free
) == 0)
859 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr
->mq_curmsgs
);
861 nmsghdr
= (struct msg_hdr
*) &mptr
[freeindex
];
862 nmsghdr
->msg_prio
= prio
;
863 nmsghdr
->msg_len
= len
;
864 memcpy (nmsghdr
+ 1, ptr
, len
); /* copy message from caller */
865 mqhdr
->mqh_free
= nmsghdr
->msg_next
; /* new freelist head */
867 /* Find right place for message in linked list */
868 index
= mqhdr
->mqh_head
;
869 pmsghdr
= (struct msg_hdr
*) &(mqhdr
->mqh_head
);
872 msghdr
= (struct msg_hdr
*) &mptr
[index
];
873 if (prio
> msghdr
->msg_prio
)
875 nmsghdr
->msg_next
= index
;
876 pmsghdr
->msg_next
= freeindex
;
879 index
= msghdr
->msg_next
;
884 /* Queue was empty or new goes at end of list */
885 pmsghdr
->msg_next
= freeindex
;
886 nmsghdr
->msg_next
= 0;
888 /* Wake up anyone blocked in mq_receive waiting for a message */
889 if (attr
->mq_curmsgs
== 0)
890 ipc_cond_signal (mqinfo
->mqi_waitrecv
);
893 ipc_mutex_unlock (mqinfo
->mqi_lock
);
898 if (ipc_mutex_locked
)
899 ipc_mutex_unlock (mqinfo
->mqi_lock
);
904 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
906 return _mq_send (mqd
, ptr
, len
, prio
, NULL
);
910 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
911 const struct timespec
*abstime
)
913 return _mq_send (mqd
, ptr
, len
, prio
, abstime
);
917 _mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
918 const struct timespec
*abstime
)
924 struct mq_hdr
*mqhdr
;
925 struct mq_fattr
*attr
;
926 struct msg_hdr
*msghdr
;
927 struct mq_info
*mqinfo
= (struct mq_info
*) mqd
;
928 bool ipc_mutex_locked
= false;
930 pthread_testcancel ();
934 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
939 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
940 mptr
= (int8_t *) mqhdr
; /* byte pointer */
941 attr
= &mqhdr
->mqh_attr
;
942 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, true)) != 0)
947 ipc_mutex_locked
= true;
948 if (maxlen
< (size_t) attr
->mq_msgsize
)
950 set_errno (EMSGSIZE
);
953 if (attr
->mq_curmsgs
== 0) /* queue is empty */
955 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
960 /* Wait for a message to be placed onto queue */
962 while (attr
->mq_curmsgs
== 0)
964 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitrecv
,
965 mqinfo
->mqi_lock
, abstime
);
975 if ((index
= mqhdr
->mqh_head
) == 0)
976 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr
->mq_curmsgs
);
978 msghdr
= (struct msg_hdr
*) &mptr
[index
];
979 mqhdr
->mqh_head
= msghdr
->msg_next
; /* new head of list */
980 len
= msghdr
->msg_len
;
981 memcpy(ptr
, msghdr
+ 1, len
); /* copy the message itself */
983 *priop
= msghdr
->msg_prio
;
985 /* Just-read message goes to front of free list */
986 msghdr
->msg_next
= mqhdr
->mqh_free
;
987 mqhdr
->mqh_free
= index
;
989 /* Wake up anyone blocked in mq_send waiting for room */
990 if (attr
->mq_curmsgs
== attr
->mq_maxmsg
)
991 ipc_cond_signal (mqinfo
->mqi_waitsend
);
994 ipc_mutex_unlock (mqinfo
->mqi_lock
);
998 if (ipc_mutex_locked
)
999 ipc_mutex_unlock (mqinfo
->mqi_lock
);
1004 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
1006 return _mq_receive (mqd
, ptr
, maxlen
, priop
, NULL
);
1010 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
1011 const struct timespec
*abstime
)
1013 return _mq_receive (mqd
, ptr
, maxlen
, priop
, abstime
);
1017 mq_close (mqd_t mqd
)
1019 long msgsize
, filesize
;
1020 struct mq_hdr
*mqhdr
;
1021 struct mq_fattr
*attr
;
1022 struct mq_info
*mqinfo
;
1026 mqinfo
= (struct mq_info
*) mqd
;
1027 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
1032 mqhdr
= mqinfo
->mqi_hdr
;
1033 attr
= &mqhdr
->mqh_attr
;
1035 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
1038 msgsize
= MSGSIZE (attr
->mq_msgsize
);
1039 filesize
= sizeof (struct mq_hdr
)
1040 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
1041 if (munmap (mqinfo
->mqi_hdr
, filesize
) == -1)
1044 mqinfo
->mqi_magic
= 0; /* just in case */
1045 ipc_cond_close (mqinfo
->mqi_waitsend
);
1046 ipc_cond_close (mqinfo
->mqi_waitrecv
);
1047 ipc_mutex_close (mqinfo
->mqi_lock
);
1057 mq_unlink (const char *name
)
1059 size_t len
= strlen (name
);
1060 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
1062 if (!check_path (mqname
, mqueue
, name
, len
))
1064 if (unlink (mqname
) == -1)
1069 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
1070 implementation as far as sem_open is concerned, but under the hood using
1071 the already existing semaphore class in thread.cc. Using a file backed
1072 solution allows to implement kernel persistent named semaphores. */
1077 unsigned long long hash
;
1082 sem_open (const char *name
, int oflag
, ...)
1084 int i
, fd
= -1, created
= 0;
1087 unsigned int value
= 0;
1088 struct stat statbuff
;
1089 sem_t
*sem
= SEM_FAILED
;
1091 bool wasopen
= false;
1094 size_t len
= strlen (name
);
1095 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1097 if (!check_path (semname
, semaphore
, name
, len
))
1102 oflag
&= (O_CREAT
| O_EXCL
);
1105 if (oflag
& O_CREAT
)
1107 va_start (ap
, oflag
); /* init ap to final named argument */
1108 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
1109 value
= va_arg (ap
, unsigned int);
1112 /* Open and specify O_EXCL and user-execute */
1113 fd
= open (semname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
,
1117 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
1118 goto exists
; /* already exists, OK */
1122 /* First one to create the file initializes it. */
1123 NtAllocateLocallyUniqueId (&sf
.luid
);
1125 sf
.hash
= hash_path_name (0, semname
);
1126 if (write (fd
, &sf
, sizeof sf
) != sizeof sf
)
1128 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, value
,
1130 if (sem
== SEM_FAILED
)
1132 /* Initialization complete, turn off user-execute bit */
1133 if (fchmod (fd
, mode
) == -1)
1135 /* Don't close (fd); */
1140 /* Open the file and fetch the semaphore name. */
1141 if ((fd
= open (semname
, O_RDWR
| O_CLOEXEC
)) < 0)
1143 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1147 /* Make certain initialization is complete */
1148 for (i
= 0; i
< MAX_TRIES
; i
++)
1150 if (stat64 (semname
, &statbuff
) == -1)
1152 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1160 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
1166 set_errno (ETIMEDOUT
);
1169 if (file
.lock (fd
, sizeof sf
))
1171 if (read (fd
, &sf
, sizeof sf
) != sizeof sf
)
1173 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, sf
.value
,
1176 if (sem
== SEM_FAILED
)
1178 /* If wasopen is set, the semaphore was already opened and we already have
1179 an open file descriptor pointing to the file. This means, we have to
1180 close the file descriptor created in this call. It won't be stored
1186 __except (EFAULT
) {}
1188 /* Don't let following function calls change errno */
1195 if (sem
!= SEM_FAILED
)
1196 semaphore::close (sem
);
1203 _sem_close (sem_t
*sem
, bool do_close
)
1209 if (semaphore::getinternal (sem
, &fd
, &sf
.hash
, &sf
.luid
, &sf
.value
) == -1)
1211 if (!file
.lock (fd
, sizeof sf
)
1212 && lseek64 (fd
, 0LL, SEEK_SET
) != (off_t
) -1
1213 && write (fd
, &sf
, sizeof sf
) == sizeof sf
)
1214 ret
= do_close
? semaphore::close (sem
) : 0;
1216 /* Don't let following function calls change errno */
1225 sem_close (sem_t
*sem
)
1227 return _sem_close (sem
, true);
1231 sem_unlink (const char *name
)
1233 size_t len
= strlen (name
);
1234 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1236 if (!check_path (semname
, semaphore
, name
, len
))
1238 if (unlink (semname
) == -1)
This page took 0.093736 seconds and 6 git commands to generate.