]>
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 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
};
183 else if (abstime
->tv_sec
< 0
184 || abstime
->tv_nsec
< 0
185 || abstime
->tv_nsec
> 999999999)
189 gettimeofday (&tv
, NULL
);
190 /* Check for immediate timeout. */
191 if (tv
.tv_sec
> abstime
->tv_sec
192 || (tv
.tv_sec
== abstime
->tv_sec
193 && tv
.tv_usec
> abstime
->tv_nsec
/ 1000))
195 timeout
= (abstime
->tv_sec
- tv
.tv_sec
) * 1000;
196 timeout
+= (abstime
->tv_nsec
/ 1000 - tv
.tv_usec
) / 1000;
199 if (ipc_mutex_unlock (mtx
))
201 switch (WaitForMultipleObjects (2, h
, TRUE
, timeout
))
204 case WAIT_ABANDONED_0
:
207 ipc_mutex_lock (mtx
);
212 return geterrno_from_win_error ();
216 ipc_cond_signal (HANDLE evt
)
218 return SetEvent (evt
) ? 0 : geterrno_from_win_error ();
222 ipc_cond_close (HANDLE evt
)
224 return CloseHandle (evt
) ? 0 : geterrno_from_win_error ();
232 ipc_flock () { memset (&fl
, 0, sizeof fl
); }
234 int lock (int fd
, size_t size
)
237 fl
.l_whence
= SEEK_SET
;
240 return fcntl64 (fd
, F_SETLKW
, &fl
);
247 return fcntl64 (fd
, F_SETLKW
, &fl
);
251 /* POSIX shared memory object implementation. */
254 shm_open (const char *name
, int oflag
, mode_t mode
)
256 size_t len
= strlen (name
);
257 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
259 if (!check_path (shmname
, shmem
, name
, len
))
262 /* Check for valid flags. */
263 if (((oflag
& O_ACCMODE
) != O_RDONLY
&& (oflag
& O_ACCMODE
) != O_RDWR
)
264 || (oflag
& ~(O_ACCMODE
| O_CREAT
| O_EXCL
| O_TRUNC
)))
266 debug_printf ("Invalid oflag 0%o", oflag
);
271 return open (shmname
, oflag
| O_CLOEXEC
, mode
& 0777);
275 shm_unlink (const char *name
)
277 size_t len
= strlen (name
);
278 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
280 if (!check_path (shmname
, shmem
, name
, len
))
283 return unlink (shmname
);
286 /* The POSIX message queue implementation is based on W. Richard STEVENS
287 implementation, just tweaked for Cygwin. The main change is
288 the usage of Windows mutexes and events instead of using the pthread
289 synchronization objects. The pathname is massaged so that the
290 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
291 are implemented additionally. */
295 struct mq_attr mqh_attr
; /* the queue's attributes */
296 long mqh_head
; /* index of first message */
297 long mqh_free
; /* index of first free message */
298 long mqh_nwait
; /* #threads blocked in mq_receive() */
299 pid_t mqh_pid
; /* nonzero PID if mqh_event set */
300 char mqh_uname
[36]; /* unique name used to identify synchronization
301 objects connected to this queue */
302 struct sigevent mqh_event
; /* for mq_notify() */
307 long msg_next
; /* index of next on linked list */
308 ssize_t msg_len
; /* actual length */
309 unsigned int msg_prio
; /* priority */
314 struct mq_hdr
*mqi_hdr
; /* start of mmap'ed region */
315 unsigned long mqi_magic
; /* magic number if open */
316 int mqi_flags
; /* flags for this process */
317 HANDLE mqi_lock
; /* mutex lock */
318 HANDLE mqi_waitsend
; /* and condition variable for full queue */
319 HANDLE mqi_waitrecv
; /* and condition variable for empty queue */
322 #define MQI_MAGIC 0x98765432UL
324 #define MSGSIZE(i) roundup((i), sizeof(long))
326 #define MAX_TRIES 10 /* for waiting for initialization */
328 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
330 extern "C" _off64_t
lseek64 (int, _off64_t
, int);
331 extern "C" void *mmap64 (void *, size_t, int, int, int, _off64_t
);
334 mq_open (const char *name
, int oflag
, ...)
336 int i
, fd
= -1, nonblock
, created
;
338 _off64_t filesize
= 0;
342 struct __stat64 statbuff
;
343 struct mq_hdr
*mqhdr
;
344 struct msg_hdr
*msghdr
;
345 struct mq_attr
*attr
;
346 struct mq_info
*mqinfo
;
349 size_t len
= strlen (name
);
350 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
352 if (!check_path (mqname
, mqueue
, name
, len
))
356 if (efault
.faulted (EFAULT
))
359 oflag
&= (O_CREAT
| O_EXCL
| O_NONBLOCK
);
361 nonblock
= oflag
& O_NONBLOCK
;
362 oflag
&= ~O_NONBLOCK
;
363 mptr
= (int8_t *) MAP_FAILED
;
369 va_start (ap
, oflag
); /* init ap to final named argument */
370 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
371 attr
= va_arg (ap
, struct mq_attr
*);
374 /* Open and specify O_EXCL and user-execute */
375 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
, mode
| S_IXUSR
);
378 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
379 goto exists
; /* already exists, OK */
383 /* First one to create the file initializes it */
386 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_msgsize
<= 0)
391 /* Calculate and set the file size */
392 msgsize
= MSGSIZE (attr
->mq_msgsize
);
393 filesize
= sizeof (struct mq_hdr
)
394 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
395 if (lseek64 (fd
, filesize
- 1, SEEK_SET
) == -1)
397 if (write (fd
, "", 1) == -1)
400 /* Memory map the file */
401 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
403 if (mptr
== (int8_t *) MAP_FAILED
)
406 /* Allocate one mq_info{} for the queue */
407 if (!(mqinfo
= (struct mq_info
*) calloc (1, sizeof (struct mq_info
))))
409 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
410 mqinfo
->mqi_magic
= MQI_MAGIC
;
411 mqinfo
->mqi_flags
= nonblock
;
413 /* Initialize header at beginning of file */
414 /* Create free list with all messages on it */
415 mqhdr
->mqh_attr
.mq_flags
= 0;
416 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
417 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
418 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
419 mqhdr
->mqh_nwait
= 0;
421 if (!AllocateLocallyUniqueId (&luid
))
426 __small_sprintf (mqhdr
->mqh_uname
, "%016X%08x%08x",
427 hash_path_name (0,mqname
),
428 luid
.HighPart
, luid
.LowPart
);
430 index
= sizeof (struct mq_hdr
);
431 mqhdr
->mqh_free
= index
;
432 for (i
= 0; i
< attr
->mq_maxmsg
- 1; i
++)
434 msghdr
= (struct msg_hdr
*) &mptr
[index
];
435 index
+= sizeof (struct msg_hdr
) + msgsize
;
436 msghdr
->msg_next
= index
;
438 msghdr
= (struct msg_hdr
*) &mptr
[index
];
439 msghdr
->msg_next
= 0; /* end of free list */
441 /* Initialize mutex & condition variables */
442 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
446 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
450 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
454 /* Initialization complete, turn off user-execute bit */
455 if (fchmod (fd
, mode
) == -1)
458 return ((mqd_t
) mqinfo
);
462 /* Open the file then memory map */
463 if ((fd
= open (mqname
, O_RDWR
| O_CLOEXEC
)) < 0)
465 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
469 /* Make certain initialization is complete */
470 for (i
= 0; i
< MAX_TRIES
; i
++)
472 if (stat64 (mqname
, &statbuff
) == -1)
474 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
482 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
488 set_errno (ETIMEDOUT
);
492 filesize
= statbuff
.st_size
;
493 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
495 if (mptr
== (int8_t *) MAP_FAILED
)
500 /* Allocate one mq_info{} for each open */
501 if (!(mqinfo
= (struct mq_info
*) calloc (1, sizeof (struct mq_info
))))
503 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
504 mqinfo
->mqi_magic
= MQI_MAGIC
;
505 mqinfo
->mqi_flags
= nonblock
;
507 /* Initialize mutex & condition variable */
508 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
512 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
516 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
520 return (mqd_t
) mqinfo
;
525 /* Don't let following function calls change errno */
530 if (mptr
!= (int8_t *) MAP_FAILED
)
531 munmap((void *) mptr
, (size_t) filesize
);
534 if (mqinfo
->mqi_lock
)
535 ipc_mutex_close (mqinfo
->mqi_lock
);
536 if (mqinfo
->mqi_waitsend
)
537 ipc_cond_close (mqinfo
->mqi_waitsend
);
538 if (mqinfo
->mqi_waitrecv
)
539 ipc_cond_close (mqinfo
->mqi_waitrecv
);
548 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
551 struct mq_hdr
*mqhdr
;
552 struct mq_attr
*attr
;
553 struct mq_info
*mqinfo
;
556 if (efault
.faulted (EBADF
))
559 mqinfo
= (struct mq_info
*) mqd
;
560 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
565 mqhdr
= mqinfo
->mqi_hdr
;
566 attr
= &mqhdr
->mqh_attr
;
567 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
572 mqstat
->mq_flags
= mqinfo
->mqi_flags
; /* per-open */
573 mqstat
->mq_maxmsg
= attr
->mq_maxmsg
; /* remaining three per-queue */
574 mqstat
->mq_msgsize
= attr
->mq_msgsize
;
575 mqstat
->mq_curmsgs
= attr
->mq_curmsgs
;
577 ipc_mutex_unlock (mqinfo
->mqi_lock
);
582 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
585 struct mq_hdr
*mqhdr
;
586 struct mq_attr
*attr
;
587 struct mq_info
*mqinfo
;
590 if (efault
.faulted (EBADF
))
593 mqinfo
= (struct mq_info
*) mqd
;
594 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
599 mqhdr
= mqinfo
->mqi_hdr
;
600 attr
= &mqhdr
->mqh_attr
;
601 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
609 omqstat
->mq_flags
= mqinfo
->mqi_flags
; /* previous attributes */
610 omqstat
->mq_maxmsg
= attr
->mq_maxmsg
;
611 omqstat
->mq_msgsize
= attr
->mq_msgsize
;
612 omqstat
->mq_curmsgs
= attr
->mq_curmsgs
; /* and current status */
615 if (mqstat
->mq_flags
& O_NONBLOCK
)
616 mqinfo
->mqi_flags
|= O_NONBLOCK
;
618 mqinfo
->mqi_flags
&= ~O_NONBLOCK
;
620 ipc_mutex_unlock (mqinfo
->mqi_lock
);
625 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
629 struct mq_hdr
*mqhdr
;
630 struct mq_info
*mqinfo
;
633 if (efault
.faulted (EBADF
))
636 mqinfo
= (struct mq_info
*) mqd
;
637 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
642 mqhdr
= mqinfo
->mqi_hdr
;
643 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
652 if (mqhdr
->mqh_pid
== pid
)
653 mqhdr
->mqh_pid
= 0; /* unregister calling process */
657 if (mqhdr
->mqh_pid
!= 0)
659 if (kill (mqhdr
->mqh_pid
, 0) != -1 || errno
!= ESRCH
)
662 ipc_mutex_unlock (mqinfo
->mqi_lock
);
666 mqhdr
->mqh_pid
= pid
;
667 mqhdr
->mqh_event
= *notification
;
669 ipc_mutex_unlock (mqinfo
->mqi_lock
);
674 _mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
675 const struct timespec
*abstime
)
678 long index
, freeindex
;
680 struct sigevent
*sigev
;
681 struct mq_hdr
*mqhdr
;
682 struct mq_attr
*attr
;
683 struct msg_hdr
*msghdr
, *nmsghdr
, *pmsghdr
;
684 struct mq_info
*mqinfo
;
687 if (efault
.faulted (EBADF
))
690 mqinfo
= (struct mq_info
*) mqd
;
691 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
696 if (prio
> MQ_PRIO_MAX
)
702 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
703 mptr
= (int8_t *) mqhdr
; /* byte pointer */
704 attr
= &mqhdr
->mqh_attr
;
705 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
711 if (len
> (size_t) attr
->mq_msgsize
)
713 set_errno (EMSGSIZE
);
716 if (attr
->mq_curmsgs
== 0)
718 if (mqhdr
->mqh_pid
!= 0 && mqhdr
->mqh_nwait
== 0)
720 sigev
= &mqhdr
->mqh_event
;
721 if (sigev
->sigev_notify
== SIGEV_SIGNAL
)
722 sigqueue (mqhdr
->mqh_pid
, sigev
->sigev_signo
, sigev
->sigev_value
);
723 mqhdr
->mqh_pid
= 0; /* unregister */
726 else if (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
729 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
734 /* Wait for room for one message on the queue */
735 while (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
736 ipc_cond_timedwait (mqinfo
->mqi_waitsend
, mqinfo
->mqi_lock
, abstime
);
739 /* nmsghdr will point to new message */
740 if ((freeindex
= mqhdr
->mqh_free
) == 0)
741 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr
->mq_curmsgs
);
743 nmsghdr
= (struct msg_hdr
*) &mptr
[freeindex
];
744 nmsghdr
->msg_prio
= prio
;
745 nmsghdr
->msg_len
= len
;
746 memcpy (nmsghdr
+ 1, ptr
, len
); /* copy message from caller */
747 mqhdr
->mqh_free
= nmsghdr
->msg_next
; /* new freelist head */
749 /* Find right place for message in linked list */
750 index
= mqhdr
->mqh_head
;
751 pmsghdr
= (struct msg_hdr
*) &(mqhdr
->mqh_head
);
754 msghdr
= (struct msg_hdr
*) &mptr
[index
];
755 if (prio
> msghdr
->msg_prio
)
757 nmsghdr
->msg_next
= index
;
758 pmsghdr
->msg_next
= freeindex
;
761 index
= msghdr
->msg_next
;
766 /* Queue was empty or new goes at end of list */
767 pmsghdr
->msg_next
= freeindex
;
768 nmsghdr
->msg_next
= 0;
770 /* Wake up anyone blocked in mq_receive waiting for a message */
771 if (attr
->mq_curmsgs
== 0)
772 ipc_cond_signal (mqinfo
->mqi_waitrecv
);
775 ipc_mutex_unlock (mqinfo
->mqi_lock
);
779 ipc_mutex_unlock (mqinfo
->mqi_lock
);
784 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
786 return _mq_send (mqd
, ptr
, len
, prio
, NULL
);
790 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
791 const struct timespec
*abstime
)
793 return _mq_send (mqd
, ptr
, len
, prio
, abstime
);
797 _mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
798 const struct timespec
*abstime
)
804 struct mq_hdr
*mqhdr
;
805 struct mq_attr
*attr
;
806 struct msg_hdr
*msghdr
;
807 struct mq_info
*mqinfo
;
810 if (efault
.faulted (EBADF
))
813 mqinfo
= (struct mq_info
*) mqd
;
814 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
819 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
820 mptr
= (int8_t *) mqhdr
; /* byte pointer */
821 attr
= &mqhdr
->mqh_attr
;
822 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
828 if (maxlen
< (size_t) attr
->mq_msgsize
)
830 set_errno (EMSGSIZE
);
833 if (attr
->mq_curmsgs
== 0) /* queue is empty */
835 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
840 /* Wait for a message to be placed onto queue */
842 while (attr
->mq_curmsgs
== 0)
843 ipc_cond_timedwait (mqinfo
->mqi_waitrecv
, mqinfo
->mqi_lock
, abstime
);
847 if ((index
= mqhdr
->mqh_head
) == 0)
848 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr
->mq_curmsgs
);
850 msghdr
= (struct msg_hdr
*) &mptr
[index
];
851 mqhdr
->mqh_head
= msghdr
->msg_next
; /* new head of list */
852 len
= msghdr
->msg_len
;
853 memcpy(ptr
, msghdr
+ 1, len
); /* copy the message itself */
855 *priop
= msghdr
->msg_prio
;
857 /* Just-read message goes to front of free list */
858 msghdr
->msg_next
= mqhdr
->mqh_free
;
859 mqhdr
->mqh_free
= index
;
861 /* Wake up anyone blocked in mq_send waiting for room */
862 if (attr
->mq_curmsgs
== attr
->mq_maxmsg
)
863 ipc_cond_signal (mqinfo
->mqi_waitsend
);
866 ipc_mutex_unlock (mqinfo
->mqi_lock
);
870 ipc_mutex_unlock (mqinfo
->mqi_lock
);
875 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
877 return _mq_receive (mqd
, ptr
, maxlen
, priop
, NULL
);
881 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
882 const struct timespec
*abstime
)
884 return _mq_receive (mqd
, ptr
, maxlen
, priop
, abstime
);
890 long msgsize
, filesize
;
891 struct mq_hdr
*mqhdr
;
892 struct mq_attr
*attr
;
893 struct mq_info
*mqinfo
;
896 if (efault
.faulted (EBADF
))
899 mqinfo
= (struct mq_info
*) mqd
;
900 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
905 mqhdr
= mqinfo
->mqi_hdr
;
906 attr
= &mqhdr
->mqh_attr
;
908 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
911 msgsize
= MSGSIZE (attr
->mq_msgsize
);
912 filesize
= sizeof (struct mq_hdr
)
913 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
914 if (munmap (mqinfo
->mqi_hdr
, filesize
) == -1)
917 mqinfo
->mqi_magic
= 0; /* just in case */
918 ipc_cond_close (mqinfo
->mqi_waitsend
);
919 ipc_cond_close (mqinfo
->mqi_waitrecv
);
920 ipc_mutex_close (mqinfo
->mqi_lock
);
926 mq_unlink (const char *name
)
928 size_t len
= strlen (name
);
929 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
931 if (!check_path (mqname
, mqueue
, name
, len
))
933 if (unlink (mqname
) == -1)
938 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
939 implementation as far as sem_open is concerned, but under the hood using
940 the already existing semaphore class in thread.cc. Using a file backed
941 solution allows to implement kernel persistent named semaphores. */
946 unsigned long long hash
;
951 sem_open (const char *name
, int oflag
, ...)
953 int i
, fd
= -1, created
;
956 unsigned int value
= 0;
957 struct __stat64 statbuff
;
958 sem_t
*sem
= SEM_FAILED
;
960 bool wasopen
= false;
963 size_t len
= strlen (name
);
964 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
966 if (!check_path (semname
, semaphore
, name
, len
))
970 if (efault
.faulted (EFAULT
))
974 oflag
&= (O_CREAT
| O_EXCL
);
979 va_start (ap
, oflag
); /* init ap to final named argument */
980 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
981 value
= va_arg (ap
, unsigned int);
984 /* Open and specify O_EXCL and user-execute */
985 fd
= open (semname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
, mode
| S_IXUSR
);
988 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
989 goto exists
; /* already exists, OK */
993 /* First one to create the file initializes it. */
994 if (!AllocateLocallyUniqueId (&sf
.luid
))
1000 sf
.hash
= hash_path_name (0, semname
);
1001 if (write (fd
, &sf
, sizeof sf
) != sizeof sf
)
1003 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, value
, wasopen
);
1004 if (sem
== SEM_FAILED
)
1006 /* Initialization complete, turn off user-execute bit */
1007 if (fchmod (fd
, mode
) == -1)
1009 /* Don't close (fd); */
1014 /* Open the file and fetch the semaphore name. */
1015 if ((fd
= open (semname
, O_RDWR
| O_CLOEXEC
)) < 0)
1017 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1021 /* Make certain initialization is complete */
1022 for (i
= 0; i
< MAX_TRIES
; i
++)
1024 if (stat64 (semname
, &statbuff
) == -1)
1026 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1034 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
1040 set_errno (ETIMEDOUT
);
1043 if (file
.lock (fd
, sizeof sf
))
1045 if (read (fd
, &sf
, sizeof sf
) != sizeof sf
)
1047 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, sf
.value
, wasopen
);
1049 if (sem
== SEM_FAILED
)
1051 /* If wasopen is set, the semaphore was already opened and we already have
1052 an open file descriptor pointing to the file. This means, we have to
1053 close the file descriptor created in this call. It won't be stored
1060 /* Don't let following function calls change errno */
1066 if (sem
!= SEM_FAILED
)
1067 semaphore::close (sem
);
1074 _sem_close (sem_t
*sem
, bool do_close
)
1080 if (semaphore::getinternal (sem
, &fd
, &sf
.hash
, &sf
.luid
, &sf
.value
) == -1)
1082 if (!file
.lock (fd
, sizeof sf
)
1083 && lseek64 (fd
, 0LL, SEEK_SET
) != (_off64_t
) -1
1084 && write (fd
, &sf
, sizeof sf
) == sizeof sf
)
1085 ret
= do_close
? semaphore::close (sem
) : 0;
1087 /* Don't let following function calls change errno */
1096 sem_close (sem_t
*sem
)
1098 return _sem_close (sem
, true);
1102 sem_unlink (const char *name
)
1104 size_t len
= strlen (name
);
1105 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1107 if (!check_path (semname
, semaphore
, name
, len
))
1109 if (unlink (semname
) == -1)
This page took 0.08828 seconds and 6 git commands to generate.