]>
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
)
178 HANDLE w4
[4] = { evt
, signal_arrived
, NULL
, NULL
};
183 thread
= pthread::self ();
184 if (thread
&& thread
->cancel_event
)
185 w4
[cnt
++] = thread
->cancel_event
;
188 if (abstime
->tv_sec
< 0
189 || abstime
->tv_nsec
< 0
190 || abstime
->tv_nsec
> 999999999)
193 /* If a timeout is set, we create a waitable timer to wait for.
194 This is the easiest way to handle the absolute timeout value, given
195 that NtSetTimer also takes absolute times and given the double
196 dependency on evt *and* mtx, which requires to call WFMO twice. */
198 LARGE_INTEGER duetime
;
201 status
= NtCreateTimer (&w4
[timer_idx
], TIMER_ALL_ACCESS
, NULL
,
203 if (!NT_SUCCESS (status
))
204 return geterrno_from_nt_status (status
);
205 timespec_to_filetime (abstime
, (FILETIME
*) &duetime
);
206 status
= NtSetTimer (w4
[timer_idx
], &duetime
, NULL
, NULL
, FALSE
, 0, NULL
);
207 if (!NT_SUCCESS (status
))
209 NtClose (w4
[timer_idx
]);
210 return geterrno_from_nt_status (status
);
214 if ((ret
= ipc_mutex_unlock (mtx
)) != 0)
216 /* Everything's set up, so now wait for the event to be signalled. */
218 switch (WaitForMultipleObjects (cnt
, w4
, FALSE
, INFINITE
))
222 case WAIT_OBJECT_0
+ 1:
223 if (_my_tls
.call_signal_handler ())
227 case WAIT_OBJECT_0
+ 2:
229 pthread_testcancel ();
231 case WAIT_OBJECT_0
+ 3:
235 ret
= geterrno_from_win_error ();
240 /* At this point we need to lock the mutex. The wait is practically
241 the same as before, just that we now wait on the mutex instead of the
245 switch (WaitForMultipleObjects (cnt
, w4
, FALSE
, INFINITE
))
248 case WAIT_ABANDONED_0
:
250 case WAIT_OBJECT_0
+ 1:
251 if (_my_tls
.call_signal_handler ())
255 case WAIT_OBJECT_0
+ 2:
257 pthread_testcancel ();
259 case WAIT_OBJECT_0
+ 3:
263 ret
= geterrno_from_win_error ();
269 if (ret
!= ETIMEDOUT
)
270 NtCancelTimer (w4
[timer_idx
], NULL
);
271 NtClose (w4
[timer_idx
]);
277 ipc_cond_signal (HANDLE evt
)
283 ipc_cond_close (HANDLE evt
)
293 ipc_flock () { memset (&fl
, 0, sizeof fl
); }
295 int lock (int fd
, size_t size
)
298 fl
.l_whence
= SEEK_SET
;
301 return fcntl64 (fd
, F_SETLKW
, &fl
);
308 return fcntl64 (fd
, F_SETLKW
, &fl
);
312 /* POSIX shared memory object implementation. */
315 shm_open (const char *name
, int oflag
, mode_t mode
)
317 size_t len
= strlen (name
);
318 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
320 if (!check_path (shmname
, shmem
, name
, len
))
323 /* Check for valid flags. */
324 if (((oflag
& O_ACCMODE
) != O_RDONLY
&& (oflag
& O_ACCMODE
) != O_RDWR
)
325 || (oflag
& ~(O_ACCMODE
| O_CREAT
| O_EXCL
| O_TRUNC
)))
327 debug_printf ("Invalid oflag 0%o", oflag
);
332 return open (shmname
, oflag
| O_CLOEXEC
, mode
& 0777);
336 shm_unlink (const char *name
)
338 size_t len
= strlen (name
);
339 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
341 if (!check_path (shmname
, shmem
, name
, len
))
344 return unlink (shmname
);
347 /* The POSIX message queue implementation is based on W. Richard STEVENS
348 implementation, just tweaked for Cygwin. The main change is
349 the usage of Windows mutexes and events instead of using the pthread
350 synchronization objects. The pathname is massaged so that the
351 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
352 are implemented additionally. */
356 struct mq_attr mqh_attr
; /* the queue's attributes */
357 long mqh_head
; /* index of first message */
358 long mqh_free
; /* index of first free message */
359 long mqh_nwait
; /* #threads blocked in mq_receive() */
360 pid_t mqh_pid
; /* nonzero PID if mqh_event set */
361 char mqh_uname
[36]; /* unique name used to identify synchronization
362 objects connected to this queue */
363 struct sigevent mqh_event
; /* for mq_notify() */
368 long msg_next
; /* index of next on linked list */
369 ssize_t msg_len
; /* actual length */
370 unsigned int msg_prio
; /* priority */
375 struct mq_hdr
*mqi_hdr
; /* start of mmap'ed region */
376 unsigned long mqi_magic
; /* magic number if open */
377 int mqi_flags
; /* flags for this process */
378 HANDLE mqi_lock
; /* mutex lock */
379 HANDLE mqi_waitsend
; /* and condition variable for full queue */
380 HANDLE mqi_waitrecv
; /* and condition variable for empty queue */
383 #define MQI_MAGIC 0x98765432UL
385 #define MSGSIZE(i) roundup((i), sizeof(long))
387 #define MAX_TRIES 10 /* for waiting for initialization */
389 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
391 extern "C" _off64_t
lseek64 (int, _off64_t
, int);
392 extern "C" void *mmap64 (void *, size_t, int, int, int, _off64_t
);
395 mq_open (const char *name
, int oflag
, ...)
397 int i
, fd
= -1, nonblock
, created
;
399 _off64_t filesize
= 0;
403 struct __stat64 statbuff
;
404 struct mq_hdr
*mqhdr
;
405 struct msg_hdr
*msghdr
;
406 struct mq_attr
*attr
;
407 struct mq_info
*mqinfo
;
410 size_t len
= strlen (name
);
411 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
413 if (!check_path (mqname
, mqueue
, name
, len
))
417 if (efault
.faulted (EFAULT
))
420 oflag
&= (O_CREAT
| O_EXCL
| O_NONBLOCK
);
422 nonblock
= oflag
& O_NONBLOCK
;
423 oflag
&= ~O_NONBLOCK
;
424 mptr
= (int8_t *) MAP_FAILED
;
430 va_start (ap
, oflag
); /* init ap to final named argument */
431 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
432 attr
= va_arg (ap
, struct mq_attr
*);
435 /* Open and specify O_EXCL and user-execute */
436 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
, mode
| S_IXUSR
);
439 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
440 goto exists
; /* already exists, OK */
444 /* First one to create the file initializes it */
447 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_msgsize
<= 0)
452 /* Calculate and set the file size */
453 msgsize
= MSGSIZE (attr
->mq_msgsize
);
454 filesize
= sizeof (struct mq_hdr
)
455 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
456 if (lseek64 (fd
, filesize
- 1, SEEK_SET
) == -1)
458 if (write (fd
, "", 1) == -1)
461 /* Memory map the file */
462 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
464 if (mptr
== (int8_t *) MAP_FAILED
)
467 /* Allocate one mq_info{} for the queue */
468 if (!(mqinfo
= (struct mq_info
*) calloc (1, sizeof (struct mq_info
))))
470 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
471 mqinfo
->mqi_magic
= MQI_MAGIC
;
472 mqinfo
->mqi_flags
= nonblock
;
474 /* Initialize header at beginning of file */
475 /* Create free list with all messages on it */
476 mqhdr
->mqh_attr
.mq_flags
= 0;
477 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
478 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
479 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
480 mqhdr
->mqh_nwait
= 0;
482 NtAllocateLocallyUniqueId (&luid
);
483 __small_sprintf (mqhdr
->mqh_uname
, "%016X%08x%08x",
484 hash_path_name (0,mqname
),
485 luid
.HighPart
, luid
.LowPart
);
487 index
= sizeof (struct mq_hdr
);
488 mqhdr
->mqh_free
= index
;
489 for (i
= 0; i
< attr
->mq_maxmsg
- 1; i
++)
491 msghdr
= (struct msg_hdr
*) &mptr
[index
];
492 index
+= sizeof (struct msg_hdr
) + msgsize
;
493 msghdr
->msg_next
= index
;
495 msghdr
= (struct msg_hdr
*) &mptr
[index
];
496 msghdr
->msg_next
= 0; /* end of free list */
498 /* Initialize mutex & condition variables */
499 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
503 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
507 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
511 /* Initialization complete, turn off user-execute bit */
512 if (fchmod (fd
, mode
) == -1)
515 return ((mqd_t
) mqinfo
);
519 /* Open the file then memory map */
520 if ((fd
= open (mqname
, O_RDWR
| O_CLOEXEC
)) < 0)
522 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
526 /* Make certain initialization is complete */
527 for (i
= 0; i
< MAX_TRIES
; i
++)
529 if (stat64 (mqname
, &statbuff
) == -1)
531 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
539 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
545 set_errno (ETIMEDOUT
);
549 filesize
= statbuff
.st_size
;
550 mptr
= (int8_t *) mmap64 (NULL
, (size_t) filesize
, PROT_READ
| PROT_WRITE
,
552 if (mptr
== (int8_t *) MAP_FAILED
)
557 /* Allocate one mq_info{} for each open */
558 if (!(mqinfo
= (struct mq_info
*) calloc (1, sizeof (struct mq_info
))))
560 mqinfo
->mqi_hdr
= mqhdr
= (struct mq_hdr
*) mptr
;
561 mqinfo
->mqi_magic
= MQI_MAGIC
;
562 mqinfo
->mqi_flags
= nonblock
;
564 /* Initialize mutex & condition variable */
565 i
= ipc_mutex_init (&mqinfo
->mqi_lock
, mqhdr
->mqh_uname
);
569 i
= ipc_cond_init (&mqinfo
->mqi_waitsend
, mqhdr
->mqh_uname
, 'S');
573 i
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, mqhdr
->mqh_uname
, 'R');
577 return (mqd_t
) mqinfo
;
582 /* Don't let following function calls change errno */
587 if (mptr
!= (int8_t *) MAP_FAILED
)
588 munmap((void *) mptr
, (size_t) filesize
);
591 if (mqinfo
->mqi_lock
)
592 ipc_mutex_close (mqinfo
->mqi_lock
);
593 if (mqinfo
->mqi_waitsend
)
594 ipc_cond_close (mqinfo
->mqi_waitsend
);
595 if (mqinfo
->mqi_waitrecv
)
596 ipc_cond_close (mqinfo
->mqi_waitrecv
);
605 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
608 struct mq_hdr
*mqhdr
;
609 struct mq_attr
*attr
;
610 struct mq_info
*mqinfo
;
613 if (efault
.faulted (EBADF
))
616 mqinfo
= (struct mq_info
*) mqd
;
617 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
622 mqhdr
= mqinfo
->mqi_hdr
;
623 attr
= &mqhdr
->mqh_attr
;
624 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
629 mqstat
->mq_flags
= mqinfo
->mqi_flags
; /* per-open */
630 mqstat
->mq_maxmsg
= attr
->mq_maxmsg
; /* remaining three per-queue */
631 mqstat
->mq_msgsize
= attr
->mq_msgsize
;
632 mqstat
->mq_curmsgs
= attr
->mq_curmsgs
;
634 ipc_mutex_unlock (mqinfo
->mqi_lock
);
639 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
642 struct mq_hdr
*mqhdr
;
643 struct mq_attr
*attr
;
644 struct mq_info
*mqinfo
;
647 if (efault
.faulted (EBADF
))
650 mqinfo
= (struct mq_info
*) mqd
;
651 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
656 mqhdr
= mqinfo
->mqi_hdr
;
657 attr
= &mqhdr
->mqh_attr
;
658 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
666 omqstat
->mq_flags
= mqinfo
->mqi_flags
; /* previous attributes */
667 omqstat
->mq_maxmsg
= attr
->mq_maxmsg
;
668 omqstat
->mq_msgsize
= attr
->mq_msgsize
;
669 omqstat
->mq_curmsgs
= attr
->mq_curmsgs
; /* and current status */
672 if (mqstat
->mq_flags
& O_NONBLOCK
)
673 mqinfo
->mqi_flags
|= O_NONBLOCK
;
675 mqinfo
->mqi_flags
&= ~O_NONBLOCK
;
677 ipc_mutex_unlock (mqinfo
->mqi_lock
);
682 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
686 struct mq_hdr
*mqhdr
;
687 struct mq_info
*mqinfo
;
690 if (efault
.faulted (EBADF
))
693 mqinfo
= (struct mq_info
*) mqd
;
694 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
699 mqhdr
= mqinfo
->mqi_hdr
;
700 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
709 if (mqhdr
->mqh_pid
== pid
)
710 mqhdr
->mqh_pid
= 0; /* unregister calling process */
714 if (mqhdr
->mqh_pid
!= 0)
716 if (kill (mqhdr
->mqh_pid
, 0) != -1 || errno
!= ESRCH
)
719 ipc_mutex_unlock (mqinfo
->mqi_lock
);
723 mqhdr
->mqh_pid
= pid
;
724 mqhdr
->mqh_event
= *notification
;
726 ipc_mutex_unlock (mqinfo
->mqi_lock
);
731 _mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
732 const struct timespec
*abstime
)
735 long index
, freeindex
;
737 struct sigevent
*sigev
;
738 struct mq_hdr
*mqhdr
;
739 struct mq_attr
*attr
;
740 struct msg_hdr
*msghdr
, *nmsghdr
, *pmsghdr
;
741 struct mq_info
*mqinfo
;
743 pthread_testcancel ();
746 if (efault
.faulted (EBADF
))
749 mqinfo
= (struct mq_info
*) mqd
;
750 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
755 if (prio
> MQ_PRIO_MAX
)
761 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
762 mptr
= (int8_t *) mqhdr
; /* byte pointer */
763 attr
= &mqhdr
->mqh_attr
;
764 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
770 if (len
> (size_t) attr
->mq_msgsize
)
772 set_errno (EMSGSIZE
);
775 if (attr
->mq_curmsgs
== 0)
777 if (mqhdr
->mqh_pid
!= 0 && mqhdr
->mqh_nwait
== 0)
779 sigev
= &mqhdr
->mqh_event
;
780 if (sigev
->sigev_notify
== SIGEV_SIGNAL
)
781 sigqueue (mqhdr
->mqh_pid
, sigev
->sigev_signo
, sigev
->sigev_value
);
782 mqhdr
->mqh_pid
= 0; /* unregister */
785 else if (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
788 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
793 /* Wait for room for one message on the queue */
794 while (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
796 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitsend
, mqinfo
->mqi_lock
,
806 /* nmsghdr will point to new message */
807 if ((freeindex
= mqhdr
->mqh_free
) == 0)
808 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr
->mq_curmsgs
);
810 nmsghdr
= (struct msg_hdr
*) &mptr
[freeindex
];
811 nmsghdr
->msg_prio
= prio
;
812 nmsghdr
->msg_len
= len
;
813 memcpy (nmsghdr
+ 1, ptr
, len
); /* copy message from caller */
814 mqhdr
->mqh_free
= nmsghdr
->msg_next
; /* new freelist head */
816 /* Find right place for message in linked list */
817 index
= mqhdr
->mqh_head
;
818 pmsghdr
= (struct msg_hdr
*) &(mqhdr
->mqh_head
);
821 msghdr
= (struct msg_hdr
*) &mptr
[index
];
822 if (prio
> msghdr
->msg_prio
)
824 nmsghdr
->msg_next
= index
;
825 pmsghdr
->msg_next
= freeindex
;
828 index
= msghdr
->msg_next
;
833 /* Queue was empty or new goes at end of list */
834 pmsghdr
->msg_next
= freeindex
;
835 nmsghdr
->msg_next
= 0;
837 /* Wake up anyone blocked in mq_receive waiting for a message */
838 if (attr
->mq_curmsgs
== 0)
839 ipc_cond_signal (mqinfo
->mqi_waitrecv
);
842 ipc_mutex_unlock (mqinfo
->mqi_lock
);
846 ipc_mutex_unlock (mqinfo
->mqi_lock
);
851 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
853 return _mq_send (mqd
, ptr
, len
, prio
, NULL
);
857 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
858 const struct timespec
*abstime
)
860 return _mq_send (mqd
, ptr
, len
, prio
, abstime
);
864 _mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
865 const struct timespec
*abstime
)
871 struct mq_hdr
*mqhdr
;
872 struct mq_attr
*attr
;
873 struct msg_hdr
*msghdr
;
874 struct mq_info
*mqinfo
;
876 pthread_testcancel ();
879 if (efault
.faulted (EBADF
))
882 mqinfo
= (struct mq_info
*) mqd
;
883 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
888 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
889 mptr
= (int8_t *) mqhdr
; /* byte pointer */
890 attr
= &mqhdr
->mqh_attr
;
891 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
)) != 0)
897 if (maxlen
< (size_t) attr
->mq_msgsize
)
899 set_errno (EMSGSIZE
);
902 if (attr
->mq_curmsgs
== 0) /* queue is empty */
904 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
909 /* Wait for a message to be placed onto queue */
911 while (attr
->mq_curmsgs
== 0)
913 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitrecv
, mqinfo
->mqi_lock
,
924 if ((index
= mqhdr
->mqh_head
) == 0)
925 api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr
->mq_curmsgs
);
927 msghdr
= (struct msg_hdr
*) &mptr
[index
];
928 mqhdr
->mqh_head
= msghdr
->msg_next
; /* new head of list */
929 len
= msghdr
->msg_len
;
930 memcpy(ptr
, msghdr
+ 1, len
); /* copy the message itself */
932 *priop
= msghdr
->msg_prio
;
934 /* Just-read message goes to front of free list */
935 msghdr
->msg_next
= mqhdr
->mqh_free
;
936 mqhdr
->mqh_free
= index
;
938 /* Wake up anyone blocked in mq_send waiting for room */
939 if (attr
->mq_curmsgs
== attr
->mq_maxmsg
)
940 ipc_cond_signal (mqinfo
->mqi_waitsend
);
943 ipc_mutex_unlock (mqinfo
->mqi_lock
);
947 ipc_mutex_unlock (mqinfo
->mqi_lock
);
952 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
954 return _mq_receive (mqd
, ptr
, maxlen
, priop
, NULL
);
958 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
959 const struct timespec
*abstime
)
961 return _mq_receive (mqd
, ptr
, maxlen
, priop
, abstime
);
967 long msgsize
, filesize
;
968 struct mq_hdr
*mqhdr
;
969 struct mq_attr
*attr
;
970 struct mq_info
*mqinfo
;
973 if (efault
.faulted (EBADF
))
976 mqinfo
= (struct mq_info
*) mqd
;
977 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
982 mqhdr
= mqinfo
->mqi_hdr
;
983 attr
= &mqhdr
->mqh_attr
;
985 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
988 msgsize
= MSGSIZE (attr
->mq_msgsize
);
989 filesize
= sizeof (struct mq_hdr
)
990 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
991 if (munmap (mqinfo
->mqi_hdr
, filesize
) == -1)
994 mqinfo
->mqi_magic
= 0; /* just in case */
995 ipc_cond_close (mqinfo
->mqi_waitsend
);
996 ipc_cond_close (mqinfo
->mqi_waitrecv
);
997 ipc_mutex_close (mqinfo
->mqi_lock
);
1003 mq_unlink (const char *name
)
1005 size_t len
= strlen (name
);
1006 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
1008 if (!check_path (mqname
, mqueue
, name
, len
))
1010 if (unlink (mqname
) == -1)
1015 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
1016 implementation as far as sem_open is concerned, but under the hood using
1017 the already existing semaphore class in thread.cc. Using a file backed
1018 solution allows to implement kernel persistent named semaphores. */
1023 unsigned long long hash
;
1028 sem_open (const char *name
, int oflag
, ...)
1030 int i
, fd
= -1, created
;
1033 unsigned int value
= 0;
1034 struct __stat64 statbuff
;
1035 sem_t
*sem
= SEM_FAILED
;
1037 bool wasopen
= false;
1040 size_t len
= strlen (name
);
1041 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1043 if (!check_path (semname
, semaphore
, name
, len
))
1047 if (efault
.faulted (EFAULT
))
1051 oflag
&= (O_CREAT
| O_EXCL
);
1054 if (oflag
& O_CREAT
)
1056 va_start (ap
, oflag
); /* init ap to final named argument */
1057 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
1058 value
= va_arg (ap
, unsigned int);
1061 /* Open and specify O_EXCL and user-execute */
1062 fd
= open (semname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
, mode
| S_IXUSR
);
1065 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
1066 goto exists
; /* already exists, OK */
1070 /* First one to create the file initializes it. */
1071 NtAllocateLocallyUniqueId (&sf
.luid
);
1073 sf
.hash
= hash_path_name (0, semname
);
1074 if (write (fd
, &sf
, sizeof sf
) != sizeof sf
)
1076 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, value
, wasopen
);
1077 if (sem
== SEM_FAILED
)
1079 /* Initialization complete, turn off user-execute bit */
1080 if (fchmod (fd
, mode
) == -1)
1082 /* Don't close (fd); */
1087 /* Open the file and fetch the semaphore name. */
1088 if ((fd
= open (semname
, O_RDWR
| O_CLOEXEC
)) < 0)
1090 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1094 /* Make certain initialization is complete */
1095 for (i
= 0; i
< MAX_TRIES
; i
++)
1097 if (stat64 (semname
, &statbuff
) == -1)
1099 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1107 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
1113 set_errno (ETIMEDOUT
);
1116 if (file
.lock (fd
, sizeof sf
))
1118 if (read (fd
, &sf
, sizeof sf
) != sizeof sf
)
1120 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, sf
.value
, wasopen
);
1122 if (sem
== SEM_FAILED
)
1124 /* If wasopen is set, the semaphore was already opened and we already have
1125 an open file descriptor pointing to the file. This means, we have to
1126 close the file descriptor created in this call. It won't be stored
1133 /* Don't let following function calls change errno */
1139 if (sem
!= SEM_FAILED
)
1140 semaphore::close (sem
);
1147 _sem_close (sem_t
*sem
, bool do_close
)
1153 if (semaphore::getinternal (sem
, &fd
, &sf
.hash
, &sf
.luid
, &sf
.value
) == -1)
1155 if (!file
.lock (fd
, sizeof sf
)
1156 && lseek64 (fd
, 0LL, SEEK_SET
) != (_off64_t
) -1
1157 && write (fd
, &sf
, sizeof sf
) == sizeof sf
)
1158 ret
= do_close
? semaphore::close (sem
) : 0;
1160 /* Don't let following function calls change errno */
1169 sem_close (sem_t
*sem
)
1171 return _sem_close (sem
, true);
1175 sem_unlink (const char *name
)
1177 size_t len
= strlen (name
);
1178 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1180 if (!check_path (semname
, semaphore
, name
, len
))
1182 if (unlink (semname
) == -1)
This page took 0.089378 seconds and 6 git commands to generate.