]>
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 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 HANDLE h
[2] = { mtx
, signal_arrived
};
124 switch (WaitForMultipleObjects (2, h
, FALSE
, INFINITE
))
127 case WAIT_ABANDONED_0
:
129 case WAIT_OBJECT_0
+ 1:
135 return geterrno_from_win_error ();
139 ipc_mutex_unlock (HANDLE mtx
)
141 return ReleaseMutex (mtx
) ? 0 : geterrno_from_win_error ();
145 ipc_mutex_close (HANDLE mtx
)
147 return CloseHandle (mtx
) ? 0 : geterrno_from_win_error ();
151 ipc_cond_init (HANDLE
*pevt
, const char *name
, char sr
)
154 UNICODE_STRING uname
;
155 OBJECT_ATTRIBUTES attr
;
158 __small_swprintf (buf
, L
"mqueue/evt_%s%c", name
, sr
);
159 RtlInitUnicodeString (&uname
, buf
);
160 InitializeObjectAttributes (&attr
, &uname
,
161 OBJ_INHERIT
| OBJ_OPENIF
| OBJ_CASE_INSENSITIVE
,
162 get_shared_parent_dir (),
163 everyone_sd (CYG_EVENT_ACCESS
));
164 status
= NtCreateEvent (pevt
, CYG_EVENT_ACCESS
, &attr
,
165 NotificationEvent
, FALSE
);
166 if (!NT_SUCCESS (status
))
168 debug_printf ("NtCreateEvent: %p", status
);
169 return geterrno_from_win_error (RtlNtStatusToDosError (status
));
175 ipc_cond_timedwait (HANDLE evt
, HANDLE mtx
, const struct timespec
*abstime
)
179 HANDLE h
[2] = { mtx
, evt
};
184 else if (abstime
->tv_sec
< 0
185 || abstime
->tv_nsec
< 0
186 || abstime
->tv_nsec
> 999999999)
190 gettimeofday (&tv
, NULL
);
191 /* Check for immediate timeout. */
192 if (tv
.tv_sec
> abstime
->tv_sec
193 || (tv
.tv_sec
== abstime
->tv_sec
194 && tv
.tv_usec
> abstime
->tv_nsec
/ 1000))
196 timeout
= (abstime
->tv_sec
- tv
.tv_sec
) * 1000;
197 timeout
+= (abstime
->tv_nsec
/ 1000 - tv
.tv_usec
) / 1000;
200 if ((err
= ipc_mutex_unlock (mtx
)) != 0)
202 switch (WaitForMultipleObjects (2, h
, TRUE
, timeout
))
205 case WAIT_ABANDONED_0
:
208 ipc_mutex_lock (mtx
);
213 return geterrno_from_win_error ();
217 ipc_cond_signal (HANDLE evt
)
219 return SetEvent (evt
) ? 0 : geterrno_from_win_error ();
223 ipc_cond_close (HANDLE evt
)
225 return CloseHandle (evt
) ? 0 : geterrno_from_win_error ();
233 ipc_flock () { memset (&fl
, 0, sizeof fl
); }
235 int lock (int fd
, size_t size
)
238 fl
.l_whence
= SEEK_SET
;
241 return fcntl64 (fd
, F_SETLKW
, &fl
);
248 return fcntl64 (fd
, F_SETLKW
, &fl
);
252 /* POSIX shared memory object implementation. */
255 shm_open (const char *name
, int oflag
, mode_t mode
)
257 size_t len
= strlen (name
);
258 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
260 if (!check_path (shmname
, shmem
, name
, len
))
263 /* Check for valid flags. */
264 if (((oflag
& O_ACCMODE
) != O_RDONLY
&& (oflag
& O_ACCMODE
) != O_RDWR
)
265 || (oflag
& ~(O_ACCMODE
| O_CREAT
| O_EXCL
| O_TRUNC
)))
267 debug_printf ("Invalid oflag 0%o", oflag
);
272 return open (shmname
, oflag
| O_CLOEXEC
, mode
& 0777);
276 shm_unlink (const char *name
)
278 size_t len
= strlen (name
);
279 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
281 if (!check_path (shmname
, shmem
, name
, len
))
284 return unlink (shmname
);
287 /* The POSIX message queue implementation is based on W. Richard STEVENS
288 implementation, just tweaked for Cygwin. The main change is
289 the usage of Windows mutexes and events instead of using the pthread
290 synchronization objects. The pathname is massaged so that the
291 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
292 are implemented additionally. */
296 struct mq_attr mqh_attr
; /* the queue's attributes */
297 long mqh_head
; /* index of first message */
298 long mqh_free
; /* index of first free message */
299 long mqh_nwait
; /* #threads blocked in mq_receive() */
300 pid_t mqh_pid
; /* nonzero PID if mqh_event set */
301 char mqh_uname
[36]; /* unique name used to identify synchronization
302 objects connected to this queue */
303 struct sigevent mqh_event
; /* for mq_notify() */
308 long msg_next
; /* index of next on linked list */
309 ssize_t msg_len
; /* actual length */
310 unsigned int msg_prio
; /* priority */
315 struct mq_hdr
*mqi_hdr
; /* start of mmap'ed region */
316 unsigned long mqi_magic
; /* magic number if open */
317 int mqi_flags
; /* flags for this process */
318 HANDLE mqi_lock
; /* mutex lock */
319 HANDLE mqi_waitsend
; /* and condition variable for full queue */
320 HANDLE mqi_waitrecv
; /* and condition variable for empty queue */
323 #define MQI_MAGIC 0x98765432UL
325 #define MSGSIZE(i) roundup((i), sizeof(long))
327 #define MAX_TRIES 10 /* for waiting for initialization */
329 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
331 extern "C" _off64_t
lseek64 (int, _off64_t
, int);
332 extern "C" void *mmap64 (void *, size_t, int, int, int, _off64_t
);
335 mq_open (const char *name
, int oflag
, ...)
337 int i
, fd
= -1, nonblock
, created
;
339 _off64_t filesize
= 0;
343 struct __stat64 statbuff
;
344 struct mq_hdr
*mqhdr
;
345 struct msg_hdr
*msghdr
;
346 struct mq_attr
*attr
;
347 struct mq_info
*mqinfo
;
350 size_t len
= strlen (name
);
351 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
353 if (!check_path (mqname
, mqueue
, name
, len
))
357 if (efault
.faulted (EFAULT
))
360 oflag
&= (O_CREAT
| O_EXCL
| O_NONBLOCK
);
362 nonblock
= oflag
& O_NONBLOCK
;
363 oflag
&= ~O_NONBLOCK
;
364 mptr
= (int8_t *) MAP_FAILED
;
370 va_start (ap
, oflag
); /* init ap to final named argument */
371 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
372 attr
= va_arg (ap
, struct mq_attr
*);
375 /* Open and specify O_EXCL and user-execute */
376 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
, mode
| S_IXUSR
);
379 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
380 goto exists
; /* already exists, OK */
384 /* First one to create the file initializes it */
387 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_msgsize
<= 0)
392 /* Calculate and set the file size */
393 msgsize
= MSGSIZE (attr
->mq_msgsize
);
394 filesize
= sizeof (struct mq_hdr
)
395 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
396 if (lseek64 (fd
, filesize
- 1, SEEK_SET
) == -1)
398 if (write (fd
, "", 1) == -1)
401 /* Memory map the file */
402 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
404 if (mptr
== (int8_t *) MAP_FAILED
)
407 /* Allocate one mq_info{} for the queue */
408 if (!(mqinfo
= (struct mq_info
*) calloc (1, sizeof (struct mq_info
))))
410 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
411 mqinfo
->mqi_magic
= MQI_MAGIC
;
412 mqinfo
->mqi_flags
= nonblock
;
414 /* Initialize header at beginning of file */
415 /* Create free list with all messages on it */
416 mqhdr
->mqh_attr
.mq_flags
= 0;
417 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
418 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
419 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
420 mqhdr
->mqh_nwait
= 0;
422 if (!AllocateLocallyUniqueId (&luid
))
427 __small_sprintf (mqhdr
->mqh_uname
, "%016X%08x%08x",
428 hash_path_name (0,mqname
),
429 luid
.HighPart
, luid
.LowPart
);
431 index
= sizeof (struct mq_hdr
);
432 mqhdr
->mqh_free
= index
;
433 for (i
= 0; i
< attr
->mq_maxmsg
- 1; i
++)
435 msghdr
= (struct msg_hdr
*) &mptr
[index
];
436 index
+= sizeof (struct msg_hdr
) + msgsize
;
437 msghdr
->msg_next
= index
;
439 msghdr
= (struct msg_hdr
*) &mptr
[index
];
440 msghdr
->msg_next
= 0; /* end of free list */
442 /* Initialize mutex & condition variables */
443 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
447 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
451 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
455 /* Initialization complete, turn off user-execute bit */
456 if (fchmod (fd
, mode
) == -1)
459 return ((mqd_t
) mqinfo
);
463 /* Open the file then memory map */
464 if ((fd
= open (mqname
, O_RDWR
| O_CLOEXEC
)) < 0)
466 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
470 /* Make certain initialization is complete */
471 for (i
= 0; i
< MAX_TRIES
; i
++)
473 if (stat64 (mqname
, &statbuff
) == -1)
475 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
483 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
489 set_errno (ETIMEDOUT
);
493 filesize
= statbuff
.st_size
;
494 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
496 if (mptr
== (int8_t *) MAP_FAILED
)
501 /* Allocate one mq_info{} for each open */
502 if (!(mqinfo
= (struct mq_info
*) calloc (1, sizeof (struct mq_info
))))
504 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
505 mqinfo
->mqi_magic
= MQI_MAGIC
;
506 mqinfo
->mqi_flags
= nonblock
;
508 /* Initialize mutex & condition variable */
509 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
513 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
517 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
521 return (mqd_t
) mqinfo
;
526 /* Don't let following function calls change errno */
531 if (mptr
!= (int8_t *) MAP_FAILED
)
532 munmap((void *) mptr
, (size_t) filesize
);
535 if (mqinfo
->mqi_lock
)
536 ipc_mutex_close (mqinfo
->mqi_lock
);
537 if (mqinfo
->mqi_waitsend
)
538 ipc_cond_close (mqinfo
->mqi_waitsend
);
539 if (mqinfo
->mqi_waitrecv
)
540 ipc_cond_close (mqinfo
->mqi_waitrecv
);
549 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
552 struct mq_hdr
*mqhdr
;
553 struct mq_attr
*attr
;
554 struct mq_info
*mqinfo
;
557 if (efault
.faulted (EBADF
))
560 mqinfo
= (struct mq_info
*) mqd
;
561 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
566 mqhdr
= mqinfo
->mqi_hdr
;
567 attr
= &mqhdr
->mqh_attr
;
568 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
573 mqstat
->mq_flags
= mqinfo
->mqi_flags
; /* per-open */
574 mqstat
->mq_maxmsg
= attr
->mq_maxmsg
; /* remaining three per-queue */
575 mqstat
->mq_msgsize
= attr
->mq_msgsize
;
576 mqstat
->mq_curmsgs
= attr
->mq_curmsgs
;
578 ipc_mutex_unlock (mqinfo
->mqi_lock
);
583 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
586 struct mq_hdr
*mqhdr
;
587 struct mq_attr
*attr
;
588 struct mq_info
*mqinfo
;
591 if (efault
.faulted (EBADF
))
594 mqinfo
= (struct mq_info
*) mqd
;
595 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
600 mqhdr
= mqinfo
->mqi_hdr
;
601 attr
= &mqhdr
->mqh_attr
;
602 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
610 omqstat
->mq_flags
= mqinfo
->mqi_flags
; /* previous attributes */
611 omqstat
->mq_maxmsg
= attr
->mq_maxmsg
;
612 omqstat
->mq_msgsize
= attr
->mq_msgsize
;
613 omqstat
->mq_curmsgs
= attr
->mq_curmsgs
; /* and current status */
616 if (mqstat
->mq_flags
& O_NONBLOCK
)
617 mqinfo
->mqi_flags
|= O_NONBLOCK
;
619 mqinfo
->mqi_flags
&= ~O_NONBLOCK
;
621 ipc_mutex_unlock (mqinfo
->mqi_lock
);
626 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
630 struct mq_hdr
*mqhdr
;
631 struct mq_info
*mqinfo
;
634 if (efault
.faulted (EBADF
))
637 mqinfo
= (struct mq_info
*) mqd
;
638 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
643 mqhdr
= mqinfo
->mqi_hdr
;
644 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
653 if (mqhdr
->mqh_pid
== pid
)
654 mqhdr
->mqh_pid
= 0; /* unregister calling process */
658 if (mqhdr
->mqh_pid
!= 0)
660 if (kill (mqhdr
->mqh_pid
, 0) != -1 || errno
!= ESRCH
)
663 ipc_mutex_unlock (mqinfo
->mqi_lock
);
667 mqhdr
->mqh_pid
= pid
;
668 mqhdr
->mqh_event
= *notification
;
670 ipc_mutex_unlock (mqinfo
->mqi_lock
);
675 _mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
676 const struct timespec
*abstime
)
679 long index
, freeindex
;
681 struct sigevent
*sigev
;
682 struct mq_hdr
*mqhdr
;
683 struct mq_attr
*attr
;
684 struct msg_hdr
*msghdr
, *nmsghdr
, *pmsghdr
;
685 struct mq_info
*mqinfo
;
688 if (efault
.faulted (EBADF
))
691 mqinfo
= (struct mq_info
*) mqd
;
692 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
697 if (prio
> MQ_PRIO_MAX
)
703 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
704 mptr
= (int8_t *) mqhdr
; /* byte pointer */
705 attr
= &mqhdr
->mqh_attr
;
706 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
712 if (len
> (size_t) attr
->mq_msgsize
)
714 set_errno (EMSGSIZE
);
717 if (attr
->mq_curmsgs
== 0)
719 if (mqhdr
->mqh_pid
!= 0 && mqhdr
->mqh_nwait
== 0)
721 sigev
= &mqhdr
->mqh_event
;
722 if (sigev
->sigev_notify
== SIGEV_SIGNAL
)
723 sigqueue (mqhdr
->mqh_pid
, sigev
->sigev_signo
, sigev
->sigev_value
);
724 mqhdr
->mqh_pid
= 0; /* unregister */
727 else if (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
730 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
735 /* Wait for room for one message on the queue */
736 while (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
738 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitsend
, mqinfo
->mqi_lock
,
748 /* nmsghdr will point to new message */
749 if ((freeindex
= mqhdr
->mqh_free
) == 0)
750 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr
->mq_curmsgs
);
752 nmsghdr
= (struct msg_hdr
*) &mptr
[freeindex
];
753 nmsghdr
->msg_prio
= prio
;
754 nmsghdr
->msg_len
= len
;
755 memcpy (nmsghdr
+ 1, ptr
, len
); /* copy message from caller */
756 mqhdr
->mqh_free
= nmsghdr
->msg_next
; /* new freelist head */
758 /* Find right place for message in linked list */
759 index
= mqhdr
->mqh_head
;
760 pmsghdr
= (struct msg_hdr
*) &(mqhdr
->mqh_head
);
763 msghdr
= (struct msg_hdr
*) &mptr
[index
];
764 if (prio
> msghdr
->msg_prio
)
766 nmsghdr
->msg_next
= index
;
767 pmsghdr
->msg_next
= freeindex
;
770 index
= msghdr
->msg_next
;
775 /* Queue was empty or new goes at end of list */
776 pmsghdr
->msg_next
= freeindex
;
777 nmsghdr
->msg_next
= 0;
779 /* Wake up anyone blocked in mq_receive waiting for a message */
780 if (attr
->mq_curmsgs
== 0)
781 ipc_cond_signal (mqinfo
->mqi_waitrecv
);
784 ipc_mutex_unlock (mqinfo
->mqi_lock
);
788 ipc_mutex_unlock (mqinfo
->mqi_lock
);
793 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
795 return _mq_send (mqd
, ptr
, len
, prio
, NULL
);
799 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
800 const struct timespec
*abstime
)
802 return _mq_send (mqd
, ptr
, len
, prio
, abstime
);
806 _mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
807 const struct timespec
*abstime
)
813 struct mq_hdr
*mqhdr
;
814 struct mq_attr
*attr
;
815 struct msg_hdr
*msghdr
;
816 struct mq_info
*mqinfo
;
819 if (efault
.faulted (EBADF
))
822 mqinfo
= (struct mq_info
*) mqd
;
823 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
828 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
829 mptr
= (int8_t *) mqhdr
; /* byte pointer */
830 attr
= &mqhdr
->mqh_attr
;
831 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
837 if (maxlen
< (size_t) attr
->mq_msgsize
)
839 set_errno (EMSGSIZE
);
842 if (attr
->mq_curmsgs
== 0) /* queue is empty */
844 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
849 /* Wait for a message to be placed onto queue */
851 while (attr
->mq_curmsgs
== 0)
853 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitrecv
, mqinfo
->mqi_lock
,
864 if ((index
= mqhdr
->mqh_head
) == 0)
865 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr
->mq_curmsgs
);
867 msghdr
= (struct msg_hdr
*) &mptr
[index
];
868 mqhdr
->mqh_head
= msghdr
->msg_next
; /* new head of list */
869 len
= msghdr
->msg_len
;
870 memcpy(ptr
, msghdr
+ 1, len
); /* copy the message itself */
872 *priop
= msghdr
->msg_prio
;
874 /* Just-read message goes to front of free list */
875 msghdr
->msg_next
= mqhdr
->mqh_free
;
876 mqhdr
->mqh_free
= index
;
878 /* Wake up anyone blocked in mq_send waiting for room */
879 if (attr
->mq_curmsgs
== attr
->mq_maxmsg
)
880 ipc_cond_signal (mqinfo
->mqi_waitsend
);
883 ipc_mutex_unlock (mqinfo
->mqi_lock
);
887 ipc_mutex_unlock (mqinfo
->mqi_lock
);
892 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
894 return _mq_receive (mqd
, ptr
, maxlen
, priop
, NULL
);
898 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
899 const struct timespec
*abstime
)
901 return _mq_receive (mqd
, ptr
, maxlen
, priop
, abstime
);
907 long msgsize
, filesize
;
908 struct mq_hdr
*mqhdr
;
909 struct mq_attr
*attr
;
910 struct mq_info
*mqinfo
;
913 if (efault
.faulted (EBADF
))
916 mqinfo
= (struct mq_info
*) mqd
;
917 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
922 mqhdr
= mqinfo
->mqi_hdr
;
923 attr
= &mqhdr
->mqh_attr
;
925 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
928 msgsize
= MSGSIZE (attr
->mq_msgsize
);
929 filesize
= sizeof (struct mq_hdr
)
930 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
931 if (munmap (mqinfo
->mqi_hdr
, filesize
) == -1)
934 mqinfo
->mqi_magic
= 0; /* just in case */
935 ipc_cond_close (mqinfo
->mqi_waitsend
);
936 ipc_cond_close (mqinfo
->mqi_waitrecv
);
937 ipc_mutex_close (mqinfo
->mqi_lock
);
943 mq_unlink (const char *name
)
945 size_t len
= strlen (name
);
946 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
948 if (!check_path (mqname
, mqueue
, name
, len
))
950 if (unlink (mqname
) == -1)
955 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
956 implementation as far as sem_open is concerned, but under the hood using
957 the already existing semaphore class in thread.cc. Using a file backed
958 solution allows to implement kernel persistent named semaphores. */
963 unsigned long long hash
;
968 sem_open (const char *name
, int oflag
, ...)
970 int i
, fd
= -1, created
;
973 unsigned int value
= 0;
974 struct __stat64 statbuff
;
975 sem_t
*sem
= SEM_FAILED
;
977 bool wasopen
= false;
980 size_t len
= strlen (name
);
981 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
983 if (!check_path (semname
, semaphore
, name
, len
))
987 if (efault
.faulted (EFAULT
))
991 oflag
&= (O_CREAT
| O_EXCL
);
996 va_start (ap
, oflag
); /* init ap to final named argument */
997 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
998 value
= va_arg (ap
, unsigned int);
1001 /* Open and specify O_EXCL and user-execute */
1002 fd
= open (semname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
, mode
| S_IXUSR
);
1005 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
1006 goto exists
; /* already exists, OK */
1010 /* First one to create the file initializes it. */
1011 if (!AllocateLocallyUniqueId (&sf
.luid
))
1017 sf
.hash
= hash_path_name (0, semname
);
1018 if (write (fd
, &sf
, sizeof sf
) != sizeof sf
)
1020 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, value
, wasopen
);
1021 if (sem
== SEM_FAILED
)
1023 /* Initialization complete, turn off user-execute bit */
1024 if (fchmod (fd
, mode
) == -1)
1026 /* Don't close (fd); */
1031 /* Open the file and fetch the semaphore name. */
1032 if ((fd
= open (semname
, O_RDWR
| O_CLOEXEC
)) < 0)
1034 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1038 /* Make certain initialization is complete */
1039 for (i
= 0; i
< MAX_TRIES
; i
++)
1041 if (stat64 (semname
, &statbuff
) == -1)
1043 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1051 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
1057 set_errno (ETIMEDOUT
);
1060 if (file
.lock (fd
, sizeof sf
))
1062 if (read (fd
, &sf
, sizeof sf
) != sizeof sf
)
1064 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, sf
.value
, wasopen
);
1066 if (sem
== SEM_FAILED
)
1068 /* If wasopen is set, the semaphore was already opened and we already have
1069 an open file descriptor pointing to the file. This means, we have to
1070 close the file descriptor created in this call. It won't be stored
1077 /* Don't let following function calls change errno */
1083 if (sem
!= SEM_FAILED
)
1084 semaphore::close (sem
);
1091 _sem_close (sem_t
*sem
, bool do_close
)
1097 if (semaphore::getinternal (sem
, &fd
, &sf
.hash
, &sf
.luid
, &sf
.value
) == -1)
1099 if (!file
.lock (fd
, sizeof sf
)
1100 && lseek64 (fd
, 0LL, SEEK_SET
) != (_off64_t
) -1
1101 && write (fd
, &sf
, sizeof sf
) == sizeof sf
)
1102 ret
= do_close
? semaphore::close (sem
) : 0;
1104 /* Don't let following function calls change errno */
1113 sem_close (sem_t
*sem
)
1115 return _sem_close (sem
, true);
1119 sem_unlink (const char *name
)
1121 size_t len
= strlen (name
);
1122 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1124 if (!check_path (semname
, semaphore
, name
, len
))
1126 if (unlink (semname
) == -1)
This page took 0.094247 seconds and 6 git commands to generate.