]>
sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/posix_ipc.cc
1 /* posix_ipc.cc: POSIX IPC API for Cygwin.
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 #include "shared_info.h"
21 #include <sys/param.h>
25 #include <semaphore.h>
27 extern "C" int ftruncate64 (int fd
, off_t length
);
29 /* The prefix_len is the length of the path prefix ncluding trailing "/"
30 (or "/sem." for semaphores) as well as the trailing NUL. */
34 const size_t prefix_len
;
35 const char *description
;
37 { "/dev/shm", 10, "POSIX shared memory object" },
38 { "/dev/mqueue", 13, "POSIX message queue" },
39 { "/dev/shm", 14, "POSIX semaphore" }
50 check_path (char *res_name
, ipc_type_t type
, const char *name
, size_t len
)
52 /* Note that we require the existance of the appropriate /dev subdirectories
53 for POSIX IPC object support, similar to Linux (which supports the
54 directories, but doesn't require to mount them). We don't create
55 these directory here, that's the task of the installer. But we check
56 for existance and give ample warning. */
57 path_conv
path (ipc_names
[type
].prefix
, PC_SYM_NOFOLLOW
);
58 if (path
.error
|| !path
.exists () || !path
.isdir ())
61 "Warning: '%s' does not exists or is not a directory.\n\n"
62 "%ss require the existance of this directory.\n"
63 "Create the directory '%s' and set the permissions to 01777.\n"
64 "For instance on the command line: mkdir -m 01777 %s\n",
65 ipc_names
[type
].prefix
, ipc_names
[type
].description
,
66 ipc_names
[type
].prefix
, ipc_names
[type
].prefix
);
70 /* Name must not be empty, or just be a single slash, or start with more
71 than one slash. Same for backslash.
72 Apart from handling backslash like slash, the naming rules are identical
73 to Linux, including the names and requirements for subdirectories, if
74 the name contains further slashes. */
75 if (!name
|| (strchr ("/\\", name
[0])
76 && (!name
[1] || strchr ("/\\", name
[1]))))
78 debug_printf ("Invalid %s name '%s'", ipc_names
[type
].description
, name
);
82 /* Skip leading (back-)slash. */
83 if (strchr ("/\\", name
[0]))
85 if (len
> PATH_MAX
- ipc_names
[type
].prefix_len
)
87 debug_printf ("%s name '%s' too long", ipc_names
[type
].description
, name
);
88 set_errno (ENAMETOOLONG
);
91 __small_sprintf (res_name
, "%s/%s%s", ipc_names
[type
].prefix
,
92 type
== semaphore
? "sem." : "",
98 ipc_mutex_init (HANDLE
*pmtx
, const char *name
)
101 UNICODE_STRING uname
;
102 OBJECT_ATTRIBUTES attr
;
105 __small_swprintf (buf
, L
"mqueue/mtx%s", name
);
106 RtlInitUnicodeString (&uname
, buf
);
107 InitializeObjectAttributes (&attr
, &uname
, OBJ_OPENIF
| OBJ_CASE_INSENSITIVE
,
108 get_shared_parent_dir (),
109 everyone_sd (CYG_MUTANT_ACCESS
));
110 status
= NtCreateMutant (pmtx
, CYG_MUTANT_ACCESS
, &attr
, FALSE
);
111 if (!NT_SUCCESS (status
))
113 debug_printf ("NtCreateMutant: %y", status
);
114 return geterrno_from_win_error (RtlNtStatusToDosError (status
));
120 ipc_mutex_lock (HANDLE mtx
, bool eintr
)
122 switch (cygwait (mtx
, cw_infinite
, cw_cancel
| cw_cancel_self
123 | (eintr
? cw_sig_eintr
: cw_sig_restart
)))
126 case WAIT_ABANDONED_0
:
134 return geterrno_from_win_error ();
138 ipc_mutex_unlock (HANDLE mtx
)
140 return ReleaseMutex (mtx
) ? 0 : geterrno_from_win_error ();
144 ipc_cond_init (HANDLE
*pevt
, const char *name
, char sr
)
147 UNICODE_STRING uname
;
148 OBJECT_ATTRIBUTES attr
;
151 __small_swprintf (buf
, L
"mqueue/evt%s%c", name
, sr
);
152 RtlInitUnicodeString (&uname
, buf
);
153 InitializeObjectAttributes (&attr
, &uname
, OBJ_OPENIF
| OBJ_CASE_INSENSITIVE
,
154 get_shared_parent_dir (),
155 everyone_sd (CYG_EVENT_ACCESS
));
156 status
= NtCreateEvent (pevt
, CYG_EVENT_ACCESS
, &attr
,
157 NotificationEvent
, FALSE
);
158 if (!NT_SUCCESS (status
))
160 debug_printf ("NtCreateEvent: %y", status
);
161 return geterrno_from_win_error (RtlNtStatusToDosError (status
));
167 ipc_cond_timedwait (HANDLE evt
, HANDLE mtx
, const struct timespec
*abstime
)
169 HANDLE w4
[4] = { evt
, };
174 wait_signal_arrived
here (w4
[1]);
175 if ((w4
[cnt
] = pthread::get_cancel_event ()) != NULL
)
179 if (!valid_timespec (*abstime
))
182 /* If a timeout is set, we create a waitable timer to wait for.
183 This is the easiest way to handle the absolute timeout value, given
184 that NtSetTimer also takes absolute times and given the double
185 dependency on evt *and* mtx, which requires to call WFMO twice. */
187 LARGE_INTEGER duetime
;
190 status
= NtCreateTimer (&w4
[timer_idx
], TIMER_ALL_ACCESS
, NULL
,
192 if (!NT_SUCCESS (status
))
193 return geterrno_from_nt_status (status
);
194 timespec_to_filetime (abstime
, &duetime
);
195 status
= NtSetTimer (w4
[timer_idx
], &duetime
, NULL
, NULL
, FALSE
, 0, NULL
);
196 if (!NT_SUCCESS (status
))
198 NtClose (w4
[timer_idx
]);
199 return geterrno_from_nt_status (status
);
203 if ((ret
= ipc_mutex_unlock (mtx
)) != 0)
205 /* Everything's set up, so now wait for the event to be signalled. */
207 switch (WaitForMultipleObjects (cnt
, w4
, FALSE
, INFINITE
))
211 case WAIT_OBJECT_0
+ 1:
212 if (_my_tls
.call_signal_handler ())
216 case WAIT_OBJECT_0
+ 2:
218 pthread::static_cancel_self ();
220 case WAIT_OBJECT_0
+ 3:
224 ret
= geterrno_from_win_error ();
229 /* At this point we need to lock the mutex. The wait is practically
230 the same as before, just that we now wait on the mutex instead of the
234 switch (WaitForMultipleObjects (cnt
, w4
, FALSE
, INFINITE
))
237 case WAIT_ABANDONED_0
:
239 case WAIT_OBJECT_0
+ 1:
240 if (_my_tls
.call_signal_handler ())
244 case WAIT_OBJECT_0
+ 2:
246 pthread_testcancel ();
248 case WAIT_OBJECT_0
+ 3:
252 ret
= geterrno_from_win_error ();
258 if (ret
!= ETIMEDOUT
)
259 NtCancelTimer (w4
[timer_idx
], NULL
);
260 NtClose (w4
[timer_idx
]);
266 ipc_cond_signal (HANDLE evt
)
276 ipc_flock () { memset (&fl
, 0, sizeof fl
); }
278 int lock (int fd
, size_t size
)
281 fl
.l_whence
= SEEK_SET
;
284 return fcntl64 (fd
, F_SETLKW
, &fl
);
291 return fcntl64 (fd
, F_SETLKW
, &fl
);
295 /* POSIX shared memory object implementation. */
298 shm_open (const char *name
, int oflag
, mode_t mode
)
300 size_t len
= strlen (name
);
301 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
303 if (!check_path (shmname
, shmem
, name
, len
))
306 /* Check for valid flags. */
307 if (((oflag
& O_ACCMODE
) != O_RDONLY
&& (oflag
& O_ACCMODE
) != O_RDWR
)
308 || (oflag
& ~(O_ACCMODE
| O_CREAT
| O_EXCL
| O_TRUNC
)))
310 debug_printf ("Invalid oflag 0%o", oflag
);
315 return open (shmname
, oflag
| O_CLOEXEC
, mode
& 0777);
319 shm_unlink (const char *name
)
321 size_t len
= strlen (name
);
322 char shmname
[ipc_names
[shmem
].prefix_len
+ len
];
324 if (!check_path (shmname
, shmem
, name
, len
))
327 return unlink (shmname
);
330 /* The POSIX message queue implementation is based on W. Richard STEVENS
331 implementation, just tweaked for Cygwin. The main change is
332 the usage of Windows mutexes and events instead of using the pthread
333 synchronization objects. The pathname is massaged so that the
334 files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
335 are implemented additionally. */
337 #pragma pack (push, 4)
340 int32_t msg_next
; /* index of next on linked list */
341 int32_t msg_len
; /* actual length */
342 unsigned int msg_prio
; /* priority */
346 #define MSGSIZE(i) roundup((i), sizeof(long))
348 #define MAX_TRIES 10 /* for waiting for initialization */
350 struct mq_attr defattr
= { 0, 10, 8192, 0 }; /* Linux defaults. */
352 extern "C" off_t
lseek64 (int, off_t
, int);
353 extern "C" void *mmap64 (void *, size_t, int, int, int, off_t
);
356 _mq_ipc_init (struct mq_info
*mqinfo
, const char *name
)
360 /* Initialize mutex & condition variable */
361 ret
= ipc_mutex_init (&mqinfo
->mqi_lock
, name
);
364 ret
= ipc_cond_init (&mqinfo
->mqi_waitsend
, name
, 'S');
367 NtClose (mqinfo
->mqi_lock
);
370 ret
= ipc_cond_init (&mqinfo
->mqi_waitrecv
, name
, 'R');
373 NtClose (mqinfo
->mqi_waitsend
);
374 NtClose (mqinfo
->mqi_lock
);
381 _map_file (int fd
, SIZE_T filesize
, HANDLE
§h
)
383 OBJECT_ATTRIBUTES oa
;
384 LARGE_INTEGER fsiz
= { QuadPart
: (LONGLONG
) filesize
};
389 InitializeObjectAttributes (&oa
, NULL
, 0, NULL
, NULL
);
390 status
= NtCreateSection (§h
, SECTION_ALL_ACCESS
, &oa
, &fsiz
,
391 PAGE_READWRITE
, SEC_COMMIT
,
392 (HANDLE
) _get_osfhandle (fd
));
393 if (NT_SUCCESS (status
))
395 status
= NtMapViewOfSection (secth
, NtCurrentProcess (), &addr
, 0,
396 filesize
, NULL
, &filesize
,
397 ViewShare
, 0, PAGE_READWRITE
);
398 if (!NT_SUCCESS (status
))
404 if (!NT_SUCCESS (status
))
405 __seterrno_from_nt_status (status
);
406 return (int8_t *) addr
;
410 mq_open (const char *name
, int oflag
, ...)
412 int i
, fd
= -1, nonblock
, created
= 0;
420 struct stat statbuff
;
421 struct mq_hdr
*mqhdr
;
422 struct msg_hdr
*msghdr
;
423 struct mq_attr
*attr
;
424 struct mq_info
*mqinfo
= NULL
;
426 size_t len
= strlen (name
);
427 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
429 if (!check_path (mqname
, mqueue
, name
, len
))
434 oflag
&= (O_CREAT
| O_EXCL
| O_NONBLOCK
);
435 nonblock
= oflag
& O_NONBLOCK
;
436 oflag
&= ~O_NONBLOCK
;
441 va_start (ap
, oflag
); /* init ap to final named argument */
442 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
443 attr
= va_arg (ap
, struct mq_attr
*);
446 /* Open and specify O_EXCL and user-execute */
447 fd
= open (mqname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
,
451 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
452 goto exists
; /* already exists, OK */
456 /* First one to create the file initializes it */
459 /* Check minimum and maximum values. The max values are pretty much
460 arbitrary, taken from the linux mq_overview man page. However,
461 these max values make sure that the internal mq_fattr structure
462 can use 32 bit types. */
463 else if (attr
->mq_maxmsg
<= 0 || attr
->mq_maxmsg
> 32768
464 || attr
->mq_msgsize
<= 0 || attr
->mq_msgsize
> 1048576)
469 /* Calculate and set the file size */
470 msgsize
= MSGSIZE (attr
->mq_msgsize
);
471 filesize
= sizeof (struct mq_hdr
)
472 + (attr
->mq_maxmsg
* (sizeof (struct msg_hdr
) + msgsize
));
473 if (ftruncate64 (fd
, filesize
) == -1)
476 /* Memory map the file */
477 mptr
= _map_file (fd
, filesize
, secth
);
481 /* Create file descriptor for mqueue */
486 fh
= (fhandler_mqueue
*) build_fh_dev (*mqueue_dev
);
491 mqinfo
= fh
->mqinfo (name
, mptr
, secth
, filesize
, mode
, nonblock
);
493 /* Initialize mutex & condition variables */
494 i
= _mq_ipc_init (mqinfo
, fh
->get_name ());
501 /* Initialize header at beginning of file */
502 /* Create free list with all messages on it */
503 mqhdr
= mqinfo
->mqi_hdr
;
504 mqhdr
->mqh_attr
.mq_flags
= 0;
505 mqhdr
->mqh_attr
.mq_maxmsg
= attr
->mq_maxmsg
;
506 mqhdr
->mqh_attr
.mq_msgsize
= attr
->mq_msgsize
;
507 mqhdr
->mqh_attr
.mq_curmsgs
= 0;
508 mqhdr
->mqh_nwait
= 0;
511 mqhdr
->mqh_magic
= MQI_MAGIC
;
512 index
= sizeof (struct mq_hdr
);
513 mqhdr
->mqh_free
= index
;
514 for (i
= 0; i
< attr
->mq_maxmsg
- 1; i
++)
516 msghdr
= (struct msg_hdr
*) &mptr
[index
];
517 index
+= sizeof (struct msg_hdr
) + msgsize
;
518 msghdr
->msg_next
= index
;
520 msghdr
= (struct msg_hdr
*) &mptr
[index
];
521 msghdr
->msg_next
= 0; /* end of free list */
523 /* Initialization complete, turn off user-execute bit */
524 if (fchmod (fd
, mode
) == -1)
531 /* Open the file then memory map */
532 if ((fd
= open (mqname
, O_RDWR
| O_CLOEXEC
)) < 0)
534 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
538 /* Make certain initialization is complete */
539 for (i
= 0; i
< MAX_TRIES
; i
++)
541 if (stat64 (mqname
, &statbuff
) == -1)
543 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
551 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
557 set_errno (ETIMEDOUT
);
561 filesize
= statbuff
.st_size
;
562 mptr
= _map_file (fd
, filesize
, secth
);
569 mqhdr
= (struct mq_hdr
*) mptr
;
570 if (mqhdr
->mqh_magic
!= MQI_MAGIC
)
573 "Old message queue \"%s\" detected!\n"
574 "This file is not usable as message queue anymore due to changes in the "
575 "internal file layout. Please remove the file and try again.", mqname
);
580 /* Create file descriptor for mqueue */
585 fh
= (fhandler_mqueue
*) build_fh_dev (*mqueue_dev
);
590 mqinfo
= fh
->mqinfo (name
, mptr
, secth
, filesize
, statbuff
.st_mode
,
593 /* Initialize mutex & condition variable */
594 i
= _mq_ipc_init (mqinfo
, fh
->get_name ());
605 /* Don't let following function calls change errno */
611 NtUnmapViewOfSection (NtCurrentProcess (), mptr
);
616 if (mqinfo
->mqi_lock
)
617 NtClose (mqinfo
->mqi_lock
);
618 if (mqinfo
->mqi_waitsend
)
619 NtClose (mqinfo
->mqi_waitsend
);
620 if (mqinfo
->mqi_waitrecv
)
621 NtClose (mqinfo
->mqi_waitrecv
);
628 static struct mq_info
*
629 get_mqinfo (cygheap_fdget
&fd
)
633 fhandler_mqueue
*fh
= fd
->is_mqueue ();
637 return fh
->mqinfo ();
643 mq_getattr (mqd_t mqd
, struct mq_attr
*mqstat
)
646 struct mq_hdr
*mqhdr
;
647 struct mq_fattr
*attr
;
648 struct mq_info
*mqinfo
;
652 cygheap_fdget
fd ((int) mqd
, true);
653 mqinfo
= get_mqinfo (fd
);
654 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
659 mqhdr
= mqinfo
->mqi_hdr
;
660 attr
= &mqhdr
->mqh_attr
;
661 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, false)) != 0)
666 mqstat
->mq_flags
= mqinfo
->mqi_flags
; /* per-open */
667 mqstat
->mq_maxmsg
= attr
->mq_maxmsg
; /* remaining three per-queue */
668 mqstat
->mq_msgsize
= attr
->mq_msgsize
;
669 mqstat
->mq_curmsgs
= attr
->mq_curmsgs
;
671 ipc_mutex_unlock (mqinfo
->mqi_lock
);
680 mq_setattr (mqd_t mqd
, const struct mq_attr
*mqstat
, struct mq_attr
*omqstat
)
683 struct mq_hdr
*mqhdr
;
684 struct mq_fattr
*attr
;
685 struct mq_info
*mqinfo
;
689 cygheap_fdget
fd ((int) mqd
, true);
690 mqinfo
= get_mqinfo (fd
);
691 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
696 mqhdr
= mqinfo
->mqi_hdr
;
697 attr
= &mqhdr
->mqh_attr
;
698 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, false)) != 0)
706 omqstat
->mq_flags
= mqinfo
->mqi_flags
; /* previous attributes */
707 omqstat
->mq_maxmsg
= attr
->mq_maxmsg
;
708 omqstat
->mq_msgsize
= attr
->mq_msgsize
;
709 omqstat
->mq_curmsgs
= attr
->mq_curmsgs
; /* and current status */
712 if (mqstat
->mq_flags
& O_NONBLOCK
)
713 mqinfo
->mqi_flags
|= O_NONBLOCK
;
715 mqinfo
->mqi_flags
&= ~O_NONBLOCK
;
717 ipc_mutex_unlock (mqinfo
->mqi_lock
);
726 mq_notify (mqd_t mqd
, const struct sigevent
*notification
)
730 struct mq_hdr
*mqhdr
;
731 struct mq_info
*mqinfo
;
735 cygheap_fdget
fd ((int) mqd
, true);
736 mqinfo
= get_mqinfo (fd
);
737 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
742 mqhdr
= mqinfo
->mqi_hdr
;
743 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, false)) != 0)
752 if (mqhdr
->mqh_pid
== pid
)
753 mqhdr
->mqh_pid
= 0; /* unregister calling process */
757 if (mqhdr
->mqh_pid
!= 0)
759 if (kill (mqhdr
->mqh_pid
, 0) != -1 || errno
!= ESRCH
)
762 ipc_mutex_unlock (mqinfo
->mqi_lock
);
766 mqhdr
->mqh_pid
= pid
;
767 mqhdr
->mqh_event
= *notification
;
769 ipc_mutex_unlock (mqinfo
->mqi_lock
);
778 _mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
779 const struct timespec
*abstime
)
782 long index
, freeindex
;
784 struct sigevent
*sigev
;
785 struct mq_hdr
*mqhdr
;
786 struct mq_fattr
*attr
;
787 struct msg_hdr
*msghdr
, *nmsghdr
, *pmsghdr
;
788 struct mq_info
*mqinfo
= NULL
;
789 bool ipc_mutex_locked
= false;
792 pthread_testcancel ();
796 cygheap_fdget
fd ((int) mqd
);
797 mqinfo
= get_mqinfo (fd
);
798 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
803 if (prio
>= MQ_PRIO_MAX
)
809 mqhdr
= mqinfo
->mqi_hdr
; /* struct pointer */
810 mptr
= (int8_t *) mqhdr
; /* byte pointer */
811 attr
= &mqhdr
->mqh_attr
;
812 if ((n
= ipc_mutex_lock (mqinfo
->mqi_lock
, true)) != 0)
817 ipc_mutex_locked
= true;
818 if (len
> (size_t) attr
->mq_msgsize
)
820 set_errno (EMSGSIZE
);
823 if (attr
->mq_curmsgs
== 0)
825 if (mqhdr
->mqh_pid
!= 0 && mqhdr
->mqh_nwait
== 0)
827 sigev
= &mqhdr
->mqh_event
;
828 if (sigev
->sigev_notify
== SIGEV_SIGNAL
)
829 sigqueue (mqhdr
->mqh_pid
, sigev
->sigev_signo
,
831 mqhdr
->mqh_pid
= 0; /* unregister */
834 else if (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
837 if (mqinfo
->mqi_flags
& O_NONBLOCK
)
842 /* Wait for room for one message on the queue */
843 while (attr
->mq_curmsgs
>= attr
->mq_maxmsg
)
845 int ret
= ipc_cond_timedwait (mqinfo
->mqi_waitsend
,
846 mqinfo
->mqi_lock
, abstime
);
855 /* nmsghdr will point to new message */
856 if ((freeindex
= mqhdr
->mqh_free
) == 0)
857 api_fatal ("mq_send: curmsgs = %ld; free = 0", attr
->mq_curmsgs
);
859 nmsghdr
= (struct msg_hdr
*) &mptr
[freeindex
];
860 nmsghdr
->msg_prio
= prio
;
861 nmsghdr
->msg_len
= len
;
862 memcpy (nmsghdr
+ 1, ptr
, len
); /* copy message from caller */
863 mqhdr
->mqh_free
= nmsghdr
->msg_next
; /* new freelist head */
865 /* Find right place for message in linked list */
866 index
= mqhdr
->mqh_head
;
867 pmsghdr
= (struct msg_hdr
*) &(mqhdr
->mqh_head
);
870 msghdr
= (struct msg_hdr
*) &mptr
[index
];
871 if (prio
> msghdr
->msg_prio
)
873 nmsghdr
->msg_next
= index
;
874 pmsghdr
->msg_next
= freeindex
;
877 index
= msghdr
->msg_next
;
882 /* Queue was empty or new goes at end of list */
883 pmsghdr
->msg_next
= freeindex
;
884 nmsghdr
->msg_next
= 0;
886 /* Wake up anyone blocked in mq_receive waiting for a message */
887 if (attr
->mq_curmsgs
== 0)
888 ipc_cond_signal (mqinfo
->mqi_waitrecv
);
895 if (ipc_mutex_locked
)
896 ipc_mutex_unlock (mqinfo
->mqi_lock
);
901 mq_send (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
)
903 return _mq_send (mqd
, ptr
, len
, prio
, NULL
);
907 mq_timedsend (mqd_t mqd
, const char *ptr
, size_t len
, unsigned int prio
,
908 const struct timespec
*abstime
)
910 return _mq_send (mqd
, ptr
, len
, prio
, abstime
);
914 _mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
915 const struct timespec
*abstime
)
921 struct mq_hdr
*mqhdr
;
922 struct mq_fattr
*attr
;
923 struct msg_hdr
*msghdr
;
924 struct mq_info
*mqinfo
;
925 bool ipc_mutex_locked
= false;
927 pthread_testcancel ();
931 cygheap_fdget
fd ((int) mqd
);
932 mqinfo
= get_mqinfo (fd
);
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
, true)) != 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
);
995 if (ipc_mutex_locked
)
996 ipc_mutex_unlock (mqinfo
->mqi_lock
);
1001 mq_receive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
)
1003 return _mq_receive (mqd
, ptr
, maxlen
, priop
, NULL
);
1007 mq_timedreceive (mqd_t mqd
, char *ptr
, size_t maxlen
, unsigned int *priop
,
1008 const struct timespec
*abstime
)
1010 return _mq_receive (mqd
, ptr
, maxlen
, priop
, abstime
);
1014 mq_close (mqd_t mqd
)
1016 struct mq_info
*mqinfo
;
1020 cygheap_fdget
fd ((int) mqd
, true);
1021 mqinfo
= get_mqinfo (fd
);
1022 if (mqinfo
->mqi_magic
!= MQI_MAGIC
)
1028 if (mq_notify (mqd
, NULL
)) /* unregister calling process */
1031 fd
->isclosed (true);
1042 mq_unlink (const char *name
)
1044 size_t len
= strlen (name
);
1045 char mqname
[ipc_names
[mqueue
].prefix_len
+ len
];
1047 if (!check_path (mqname
, mqueue
, name
, len
))
1049 if (unlink (mqname
) == -1)
1054 /* POSIX named semaphore implementation. Loosely based on Richard W. STEPHENS
1055 implementation as far as sem_open is concerned, but under the hood using
1056 the already existing semaphore class in thread.cc. Using a file backed
1057 solution allows to implement kernel persistent named semaphores. */
1062 unsigned long long hash
;
1067 sem_open (const char *name
, int oflag
, ...)
1069 int i
, fd
= -1, created
= 0;
1072 unsigned int value
= 0;
1073 struct stat statbuff
;
1074 sem_t
*sem
= SEM_FAILED
;
1076 bool wasopen
= false;
1079 size_t len
= strlen (name
);
1080 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1082 if (!check_path (semname
, semaphore
, name
, len
))
1087 oflag
&= (O_CREAT
| O_EXCL
);
1090 if (oflag
& O_CREAT
)
1092 va_start (ap
, oflag
); /* init ap to final named argument */
1093 mode
= va_arg (ap
, mode_t
) & ~S_IXUSR
;
1094 value
= va_arg (ap
, unsigned int);
1097 /* Open and specify O_EXCL and user-execute */
1098 fd
= open (semname
, oflag
| O_EXCL
| O_RDWR
| O_CLOEXEC
,
1102 if (errno
== EEXIST
&& (oflag
& O_EXCL
) == 0)
1103 goto exists
; /* already exists, OK */
1107 /* First one to create the file initializes it. */
1108 NtAllocateLocallyUniqueId (&sf
.luid
);
1110 sf
.hash
= hash_path_name (0, semname
);
1111 if (write (fd
, &sf
, sizeof sf
) != sizeof sf
)
1113 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, value
,
1115 if (sem
== SEM_FAILED
)
1117 /* Initialization complete, turn off user-execute bit */
1118 if (fchmod (fd
, mode
) == -1)
1120 /* Don't close (fd); */
1125 /* Open the file and fetch the semaphore name. */
1126 if ((fd
= open (semname
, O_RDWR
| O_CLOEXEC
)) < 0)
1128 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1132 /* Make certain initialization is complete */
1133 for (i
= 0; i
< MAX_TRIES
; i
++)
1135 if (stat64 (semname
, &statbuff
) == -1)
1137 if (errno
== ENOENT
&& (oflag
& O_CREAT
))
1145 if ((statbuff
.st_mode
& S_IXUSR
) == 0)
1151 set_errno (ETIMEDOUT
);
1154 if (file
.lock (fd
, sizeof sf
))
1156 if (read (fd
, &sf
, sizeof sf
) != sizeof sf
)
1158 sem
= semaphore::open (sf
.hash
, sf
.luid
, fd
, oflag
, mode
, sf
.value
,
1161 if (sem
== SEM_FAILED
)
1163 /* If wasopen is set, the semaphore was already opened and we already have
1164 an open file descriptor pointing to the file. This means, we have to
1165 close the file descriptor created in this call. It won't be stored
1171 __except (EFAULT
) {}
1173 /* Don't let following function calls change errno */
1180 if (sem
!= SEM_FAILED
)
1181 semaphore::close (sem
);
1188 _sem_close (sem_t
*sem
, bool do_close
)
1194 if (semaphore::getinternal (sem
, &fd
, &sf
.hash
, &sf
.luid
, &sf
.value
) == -1)
1196 if (!file
.lock (fd
, sizeof sf
)
1197 && lseek64 (fd
, 0LL, SEEK_SET
) != (off_t
) -1
1198 && write (fd
, &sf
, sizeof sf
) == sizeof sf
)
1199 ret
= do_close
? semaphore::close (sem
) : 0;
1201 /* Don't let following function calls change errno */
1210 sem_close (sem_t
*sem
)
1212 return _sem_close (sem
, true);
1216 sem_unlink (const char *name
)
1218 size_t len
= strlen (name
);
1219 char semname
[ipc_names
[semaphore
].prefix_len
+ len
];
1221 if (!check_path (semname
, semaphore
, name
, len
))
1223 if (unlink (semname
) == -1)
This page took 0.095183 seconds and 6 git commands to generate.