]>
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 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
)
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: %y", 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
, &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. */
351 /* The mq_attr structure is defined using long datatypes per POSIX.
352 For interoperability reasons between 32 and 64 bit processes, we have
353 to make sure to use a unified structure layout in the message queue file.
354 That's what the mq_fattr is, the in-file representation of the mq_attr
356 #pragma pack (push, 4)
367 struct mq_fattr mqh_attr
; /* the queue's attributes */
368 int32_t mqh_head
; /* index of first message */
369 int32_t mqh_free
; /* index of first free message */
370 int32_t mqh_nwait
; /* #threads blocked in mq_receive() */
371 pid_t mqh_pid
; /* nonzero PID if mqh_event set */
372 char mqh_uname
[36]; /* unique name used to identify synchronization
373 objects connected to this queue */
375 struct sigevent mqh_event
; /* for mq_notify() */
376 /* Make sure sigevent takes the same space on 32 and 64 bit systems.
377 Other than that, it doesn't need to be compatible since only
378 one process can be notified at a time. */
379 uint64_t mqh_placeholder
[8];
381 uint32_t mqh_magic
; /* Expect MQI_MAGIC here, otherwise it's
382 an old-style message queue. */
387 int32_t msg_next
; /* index of next on linked list */
388 int32_t msg_len
; /* actual length */
389 unsigned int msg_prio
; /* priority */
395 struct mq_hdr
*mqi_hdr
; /* start of mmap'ed region */
396 uint32_t mqi_magic
; /* magic number if open */
397 int mqi_flags
; /* flags for this process */
398 HANDLE mqi_lock
; /* mutex lock */
399 HANDLE mqi_waitsend
; /* and condition variable for full queue */
400 HANDLE mqi_waitrecv
; /* and condition variable for empty queue */
403 #define MQI_MAGIC 0x98765432UL
405 #define MSGSIZE(i) roundup((i), sizeof(long))
407 #define MAX_TRIES 10 /* for waiting for initialization */
409 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
411 extern "C" off_t
lseek64 (int, off_t
, int);
412 extern "C" void *mmap64 (void *, size_t, int, int, int, off_t
);
415 mq_open (const char *name
, int oflag
, ...)
417 int i
, fd
= -1, nonblock
, created
= 0;
422 int8_t *mptr
= (int8_t *) MAP_FAILED
;
423 struct stat statbuff
;
424 struct mq_hdr
*mqhdr
;
425 struct msg_hdr
*msghdr
;
426 struct mq_attr
*attr
;
427 struct mq_info
*mqinfo
= NULL
;
430 size_t len
= strlen (name
);
431 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
433 if (!check_path (mqname
, mqueue
, name
, len
))
438 oflag
&= (O_CREAT
| O_EXCL
| O_NONBLOCK
);
439 nonblock
= oflag
& O_NONBLOCK
;
440 oflag
&= ~O_NONBLOCK
;
445 va_start (ap
, oflag
); /* init ap to final named argument */
446 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
447 attr
= va_arg (ap
, struct mq_attr
*);
450 /* Open and specify O_EXCL and user-execute */
451 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
,
455 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
456 goto exists
; /* already exists, OK */
460 /* First one to create the file initializes it */
463 /* Check minimum and maximum values. The max values are pretty much
464 arbitrary, taken from the linux mq_overview man page. However,
465 these max values make sure that the internal mq_fattr structure
466 can use 32 bit types. */
467 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_maxmsg
> 32768
468 || attr
->mq_msgsize
<= 0 || attr
->mq_msgsize
> 1048576)
473 /* Calculate and set the file size */
474 msgsize
= MSGSIZE (attr
->mq_msgsize
);
475 filesize
= sizeof (struct mq_hdr
)
476 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
477 if (lseek64 (fd
, filesize
- 1, SEEK_SET
) == -1)
479 if (write (fd
, "", 1) == -1)
482 /* Memory map the file */
483 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
,
484 PROT_READ
| PROT_WRITE
,
486 if (mptr
== (int8_t *) MAP_FAILED
)
489 /* Allocate one mq_info{} for the queue */
490 if (!(mqinfo
= (struct mq_info
*)
491 calloc (1, sizeof (struct mq_info
))))
493 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
494 mqinfo
->mqi_magic
= MQI_MAGIC
;
495 mqinfo
->mqi_flags
= nonblock
;
497 /* Initialize header at beginning of file */
498 /* Create free list with all messages on it */
499 mqhdr
->mqh_attr
.mq_flags
= 0;
500 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
501 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
502 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
503 mqhdr
->mqh_nwait
= 0;
505 NtAllocateLocallyUniqueId (&luid
);
506 __small_sprintf (mqhdr
->mqh_uname
, "%016X%08x%08x",
507 hash_path_name (0,mqname
),
508 luid
.HighPart
, luid
.LowPart
);
510 mqhdr
->mqh_magic
= MQI_MAGIC
;
511 index
= sizeof (struct mq_hdr
);
512 mqhdr
->mqh_free
= index
;
513 for (i
= 0; i
< attr
->mq_maxmsg
- 1; i
++)
515 msghdr
= (struct msg_hdr
*) &mptr
[index
];
516 index
+= sizeof (struct msg_hdr
) + msgsize
;
517 msghdr
->msg_next
= index
;
519 msghdr
= (struct msg_hdr
*) &mptr
[index
];
520 msghdr
->msg_next
= 0; /* end of free list */
522 /* Initialize mutex & condition variables */
523 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
529 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
535 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
541 /* Initialization complete, turn off user-execute bit */
542 if (fchmod (fd
, mode
) == -1)
545 return ((mqd_t
) mqinfo
);
549 /* Open the file then memory map */
550 if ((fd
= open (mqname
, O_RDWR
| O_CLOEXEC
)) < 0)
552 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
556 /* Make certain initialization is complete */
557 for (i
= 0; i
< MAX_TRIES
; i
++)
559 if (stat64 (mqname
, &statbuff
) == -1)
561 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
569 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
575 set_errno (ETIMEDOUT
);
579 filesize
= statbuff
.st_size
;
580 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
582 if (mptr
== (int8_t *) MAP_FAILED
)
587 /* Allocate one mq_info{} for each open */
588 if (!(mqinfo
= (struct mq_info
*) calloc (1, sizeof (struct mq_info
))))
590 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
591 if (mqhdr
->mqh_magic
!= MQI_MAGIC
)
594 "Old message queue \"%s\" detected!\n"
595 "This file is not usable as message queue anymore due to changes in the "
596 "internal file layout. Please remove the file and try again.", mqname
);
600 mqinfo
->mqi_magic
= MQI_MAGIC
;
601 mqinfo
->mqi_flags
= nonblock
;
603 /* Initialize mutex & condition variable */
604 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
610 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
616 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
622 return (mqd_t
) mqinfo
;
626 /* Don't let following function calls change errno */
630 if (mptr
!= (int8_t *) MAP_FAILED
)
631 munmap((void *) mptr
, (size_t) filesize
);
634 if (mqinfo
->mqi_lock
)
635 ipc_mutex_close (mqinfo
->mqi_lock
);
636 if (mqinfo
->mqi_waitsend
)
637 ipc_cond_close (mqinfo
->mqi_waitsend
);
638 if (mqinfo
->mqi_waitrecv
)
639 ipc_cond_close (mqinfo
->mqi_waitrecv
);
648 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
651 struct mq_hdr
*mqhdr
;
652 struct mq_fattr
*attr
;
653 struct mq_info
*mqinfo
;
657 mqinfo
= (struct mq_info
*) mqd
;
658 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
663 mqhdr
= mqinfo
->mqi_hdr
;
664 attr
= &mqhdr
->mqh_attr
;
665 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
670 mqstat
->mq_flags
= mqinfo
->mqi_flags
; /* per-open */
671 mqstat
->mq_maxmsg
= attr
->mq_maxmsg
; /* remaining three per-queue */
672 mqstat
->mq_msgsize
= attr
->mq_msgsize
;
673 mqstat
->mq_curmsgs
= attr
->mq_curmsgs
;
675 ipc_mutex_unlock (mqinfo
->mqi_lock
);
684 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
687 struct mq_hdr
*mqhdr
;
688 struct mq_fattr
*attr
;
689 struct mq_info
*mqinfo
;
693 mqinfo
= (struct mq_info
*) mqd
;
694 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
699 mqhdr
= mqinfo
->mqi_hdr
;
700 attr
= &mqhdr
->mqh_attr
;
701 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
709 omqstat
->mq_flags
= mqinfo
->mqi_flags
; /* previous attributes */
710 omqstat
->mq_maxmsg
= attr
->mq_maxmsg
;
711 omqstat
->mq_msgsize
= attr
->mq_msgsize
;
712 omqstat
->mq_curmsgs
= attr
->mq_curmsgs
; /* and current status */
715 if (mqstat
->mq_flags
& O_NONBLOCK
)
716 mqinfo
->mqi_flags
|= O_NONBLOCK
;
718 mqinfo
->mqi_flags
&= ~O_NONBLOCK
;
720 ipc_mutex_unlock (mqinfo
->mqi_lock
);
729 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
733 struct mq_hdr
*mqhdr
;
734 struct mq_info
*mqinfo
;
738 mqinfo
= (struct mq_info
*) mqd
;
739 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
744 mqhdr
= mqinfo
->mqi_hdr
;
745 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
754 if (mqhdr
->mqh_pid
== pid
)
755 mqhdr
->mqh_pid
= 0; /* unregister calling process */
759 if (mqhdr
->mqh_pid
!= 0)
761 if (kill (mqhdr
->mqh_pid
, 0) != -1 || errno
!= ESRCH
)
764 ipc_mutex_unlock (mqinfo
->mqi_lock
);
768 mqhdr
->mqh_pid
= pid
;
769 mqhdr
->mqh_event
= *notification
;
771 ipc_mutex_unlock (mqinfo
->mqi_lock
);
780 _mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
781 const struct timespec
*abstime
)
784 long index
, freeindex
;
786 struct sigevent
*sigev
;
787 struct mq_hdr
*mqhdr
;
788 struct mq_fattr
*attr
;
789 struct msg_hdr
*msghdr
, *nmsghdr
, *pmsghdr
;
790 struct mq_info
*mqinfo
= NULL
;
791 bool ipc_mutex_locked
= false;
794 pthread_testcancel ();
798 mqinfo
= (struct mq_info
*) mqd
;
799 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
804 if (prio
> MQ_PRIO_MAX
)
810 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
811 mptr
= (int8_t *) mqhdr
; /* byte pointer */
812 attr
= &mqhdr
->mqh_attr
;
813 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
818 ipc_mutex_locked
= true;
819 if (len
> (size_t) attr
->mq_msgsize
)
821 set_errno (EMSGSIZE
);
824 if (attr
->mq_curmsgs
== 0)
826 if (mqhdr
->mqh_pid
!= 0 && mqhdr
->mqh_nwait
== 0)
828 sigev
= &mqhdr
->mqh_event
;
829 if (sigev
->sigev_notify
== SIGEV_SIGNAL
)
830 sigqueue (mqhdr
->mqh_pid
, sigev
->sigev_signo
,
832 mqhdr
->mqh_pid
= 0; /* unregister */
835 else if (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
838 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
843 /* Wait for room for one message on the queue */
844 while (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
846 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitsend
,
847 mqinfo
->mqi_lock
, abstime
);
856 /* nmsghdr will point to new message */
857 if ((freeindex
= mqhdr
->mqh_free
) == 0)
858 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr
->mq_curmsgs
);
860 nmsghdr
= (struct msg_hdr
*) &mptr
[freeindex
];
861 nmsghdr
->msg_prio
= prio
;
862 nmsghdr
->msg_len
= len
;
863 memcpy (nmsghdr
+ 1, ptr
, len
); /* copy message from caller */
864 mqhdr
->mqh_free
= nmsghdr
->msg_next
; /* new freelist head */
866 /* Find right place for message in linked list */
867 index
= mqhdr
->mqh_head
;
868 pmsghdr
= (struct msg_hdr
*) &(mqhdr
->mqh_head
);
871 msghdr
= (struct msg_hdr
*) &mptr
[index
];
872 if (prio
> msghdr
->msg_prio
)
874 nmsghdr
->msg_next
= index
;
875 pmsghdr
->msg_next
= freeindex
;
878 index
= msghdr
->msg_next
;
883 /* Queue was empty or new goes at end of list */
884 pmsghdr
->msg_next
= freeindex
;
885 nmsghdr
->msg_next
= 0;
887 /* Wake up anyone blocked in mq_receive waiting for a message */
888 if (attr
->mq_curmsgs
== 0)
889 ipc_cond_signal (mqinfo
->mqi_waitrecv
);
892 ipc_mutex_unlock (mqinfo
->mqi_lock
);
897 if (ipc_mutex_locked
)
898 ipc_mutex_unlock (mqinfo
->mqi_lock
);
903 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
905 return _mq_send (mqd
, ptr
, len
, prio
, NULL
);
909 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
910 const struct timespec
*abstime
)
912 return _mq_send (mqd
, ptr
, len
, prio
, abstime
);
916 _mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
917 const struct timespec
*abstime
)
923 struct mq_hdr
*mqhdr
;
924 struct mq_fattr
*attr
;
925 struct msg_hdr
*msghdr
;
926 struct mq_info
*mqinfo
= (struct mq_info
*) mqd
;
927 bool ipc_mutex_locked
= false;
929 pthread_testcancel ();
933 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
938 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
939 mptr
= (int8_t *) mqhdr
; /* byte pointer */
940 attr
= &mqhdr
->mqh_attr
;
941 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
946 ipc_mutex_locked
= true;
947 if (maxlen
< (size_t) attr
->mq_msgsize
)
949 set_errno (EMSGSIZE
);
952 if (attr
->mq_curmsgs
== 0) /* queue is empty */
954 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
959 /* Wait for a message to be placed onto queue */
961 while (attr
->mq_curmsgs
== 0)
963 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitrecv
,
964 mqinfo
->mqi_lock
, abstime
);
974 if ((index
= mqhdr
->mqh_head
) == 0)
975 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr
->mq_curmsgs
);
977 msghdr
= (struct msg_hdr
*) &mptr
[index
];
978 mqhdr
->mqh_head
= msghdr
->msg_next
; /* new head of list */
979 len
= msghdr
->msg_len
;
980 memcpy(ptr
, msghdr
+ 1, len
); /* copy the message itself */
982 *priop
= msghdr
->msg_prio
;
984 /* Just-read message goes to front of free list */
985 msghdr
->msg_next
= mqhdr
->mqh_free
;
986 mqhdr
->mqh_free
= index
;
988 /* Wake up anyone blocked in mq_send waiting for room */
989 if (attr
->mq_curmsgs
== attr
->mq_maxmsg
)
990 ipc_cond_signal (mqinfo
->mqi_waitsend
);
993 ipc_mutex_unlock (mqinfo
->mqi_lock
);
997 if (ipc_mutex_locked
)
998 ipc_mutex_unlock (mqinfo
->mqi_lock
);
1003 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
1005 return _mq_receive (mqd
, ptr
, maxlen
, priop
, NULL
);
1009 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
1010 const struct timespec
*abstime
)
1012 return _mq_receive (mqd
, ptr
, maxlen
, priop
, abstime
);
1016 mq_close (mqd_t mqd
)
1018 long msgsize
, filesize
;
1019 struct mq_hdr
*mqhdr
;
1020 struct mq_fattr
*attr
;
1021 struct mq_info
*mqinfo
;
1025 mqinfo
= (struct mq_info
*) mqd
;
1026 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
1031 mqhdr
= mqinfo
->mqi_hdr
;
1032 attr
= &mqhdr
->mqh_attr
;
1034 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
1037 msgsize
= MSGSIZE (attr
->mq_msgsize
);
1038 filesize
= sizeof (struct mq_hdr
)
1039 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
1040 if (munmap (mqinfo
->mqi_hdr
, filesize
) == -1)
1043 mqinfo
->mqi_magic
= 0; /* just in case */
1044 ipc_cond_close (mqinfo
->mqi_waitsend
);
1045 ipc_cond_close (mqinfo
->mqi_waitrecv
);
1046 ipc_mutex_close (mqinfo
->mqi_lock
);
1056 mq_unlink (const char *name
)
1058 size_t len
= strlen (name
);
1059 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
1061 if (!check_path (mqname
, mqueue
, name
, len
))
1063 if (unlink (mqname
) == -1)
1068 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
1069 implementation as far as sem_open is concerned, but under the hood using
1070 the already existing semaphore class in thread.cc. Using a file backed
1071 solution allows to implement kernel persistent named semaphores. */
1076 unsigned long long hash
;
1081 sem_open (const char *name
, int oflag
, ...)
1083 int i
, fd
= -1, created
= 0;
1086 unsigned int value
= 0;
1087 struct stat statbuff
;
1088 sem_t
*sem
= SEM_FAILED
;
1090 bool wasopen
= false;
1093 size_t len
= strlen (name
);
1094 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1096 if (!check_path (semname
, semaphore
, name
, len
))
1101 oflag
&= (O_CREAT
| O_EXCL
);
1104 if (oflag
& O_CREAT
)
1106 va_start (ap
, oflag
); /* init ap to final named argument */
1107 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
1108 value
= va_arg (ap
, unsigned int);
1111 /* Open and specify O_EXCL and user-execute */
1112 fd
= open (semname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
,
1116 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
1117 goto exists
; /* already exists, OK */
1121 /* First one to create the file initializes it. */
1122 NtAllocateLocallyUniqueId (&sf
.luid
);
1124 sf
.hash
= hash_path_name (0, semname
);
1125 if (write (fd
, &sf
, sizeof sf
) != sizeof sf
)
1127 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, value
,
1129 if (sem
== SEM_FAILED
)
1131 /* Initialization complete, turn off user-execute bit */
1132 if (fchmod (fd
, mode
) == -1)
1134 /* Don't close (fd); */
1139 /* Open the file and fetch the semaphore name. */
1140 if ((fd
= open (semname
, O_RDWR
| O_CLOEXEC
)) < 0)
1142 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1146 /* Make certain initialization is complete */
1147 for (i
= 0; i
< MAX_TRIES
; i
++)
1149 if (stat64 (semname
, &statbuff
) == -1)
1151 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1159 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
1165 set_errno (ETIMEDOUT
);
1168 if (file
.lock (fd
, sizeof sf
))
1170 if (read (fd
, &sf
, sizeof sf
) != sizeof sf
)
1172 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, sf
.value
,
1175 if (sem
== SEM_FAILED
)
1177 /* If wasopen is set, the semaphore was already opened and we already have
1178 an open file descriptor pointing to the file. This means, we have to
1179 close the file descriptor created in this call. It won't be stored
1185 __except (EFAULT
) {}
1187 /* Don't let following function calls change errno */
1194 if (sem
!= SEM_FAILED
)
1195 semaphore::close (sem
);
1202 _sem_close (sem_t
*sem
, bool do_close
)
1208 if (semaphore::getinternal (sem
, &fd
, &sf
.hash
, &sf
.luid
, &sf
.value
) == -1)
1210 if (!file
.lock (fd
, sizeof sf
)
1211 && lseek64 (fd
, 0LL, SEEK_SET
) != (off_t
) -1
1212 && write (fd
, &sf
, sizeof sf
) == sizeof sf
)
1213 ret
= do_close
? semaphore::close (sem
) : 0;
1215 /* Don't let following function calls change errno */
1224 sem_close (sem_t
*sem
)
1226 return _sem_close (sem
, true);
1230 sem_unlink (const char *name
)
1232 size_t len
= strlen (name
);
1233 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1235 if (!check_path (semname
, semaphore
, name
, len
))
1237 if (unlink (semname
) == -1)
This page took 0.092536 seconds and 6 git commands to generate.