/* posix_ipc.cc: POSIX IPC API for Cygwin.
- Copyright 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
-
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
#include "cygheap.h"
#include "sigproc.h"
#include "ntdll.h"
+#include "tls_pbuf.h"
+#include <io.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <stdlib.h>
#include <mqueue.h>
#include <semaphore.h>
-/* The prefix_len is the length of the path prefix ncluding trailing "/"
+/* The prefix_len is the length of the path prefix including trailing "/"
(or "/sem." for semaphores) as well as the trailing NUL. */
static struct
{
set_errno (EINVAL);
return false;
}
- /* Name must not be empty, or just be a single slash, or start with more
- than one slash. Same for backslash.
- Apart from handling backslash like slash, the naming rules are identical
+ /* Apart from handling backslash like slash, the naming rules are identical
to Linux, including the names and requirements for subdirectories, if
the name contains further slashes. */
- if (!name || (strchr ("/\\", name[0])
- && (!name[1] || strchr ("/\\", name[1]))))
+ /* Name must not be empty and has to start with a slash (or backslash) */
+ if (!name || !strchr ("/\\", name[0]))
{
debug_printf ("Invalid %s name '%s'", ipc_names[type].description, name);
set_errno (EINVAL);
return false;
}
- /* Skip leading (back-)slash. */
- if (strchr ("/\\", name[0]))
- ++name;
- if (len > PATH_MAX - ipc_names[type].prefix_len)
+ /* Name must not consist of just a single slash (or backslash) */
+ if (!name[1])
+ {
+ debug_printf ("Invalid %s name '%s'", ipc_names[type].description, name);
+ set_errno (ENOENT);
+ return false;
+ }
+ /* Name must not contain slashes after the leading one */
+ if (strpbrk (name + 1, "/\\"))
+ {
+ debug_printf ("Invalid %s name '%s'", ipc_names[type].description, name);
+ set_errno (EACCES);
+ return false;
+ }
+ /* Length must be less than or equal to NAME_MAX, or NAME_MAX - 4 in
+ case of semaphores, due to the leading "sem." prefix */
+ if (len > NAME_MAX - (type == semaphore ? strlen ("sem.") : 0))
{
debug_printf ("%s name '%s' too long", ipc_names[type].description, name);
set_errno (ENAMETOOLONG);
}
__small_sprintf (res_name, "%s/%s%s", ipc_names[type].prefix,
type == semaphore ? "sem." : "",
- name);
+ name + 1);
return true;
}
static int
-ipc_mutex_init (HANDLE *pmtx, const char *name)
+ipc_mutex_lock (HANDLE mtx, bool eintr)
{
- WCHAR buf[MAX_PATH];
- UNICODE_STRING uname;
- OBJECT_ATTRIBUTES attr;
- NTSTATUS status;
-
- __small_swprintf (buf, L"mqueue/mtx_%s", name);
- RtlInitUnicodeString (&uname, buf);
- InitializeObjectAttributes (&attr, &uname,
- OBJ_INHERIT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
- get_shared_parent_dir (),
- everyone_sd (CYG_MUTANT_ACCESS));
- status = NtCreateMutant (pmtx, CYG_MUTANT_ACCESS, &attr, FALSE);
- if (!NT_SUCCESS (status))
- {
- debug_printf ("NtCreateMutant: %y", status);
- return geterrno_from_win_error (RtlNtStatusToDosError (status));
- }
- return 0;
-}
-
-static int
-ipc_mutex_lock (HANDLE mtx)
-{
- switch (cygwait (mtx, cw_infinite, cw_sig_eintr | cw_cancel | cw_cancel_self))
+ switch (cygwait (mtx, cw_infinite, cw_cancel | cw_cancel_self
+ | (eintr ? cw_sig_eintr : cw_sig_restart)))
{
case WAIT_OBJECT_0:
case WAIT_ABANDONED_0:
return ReleaseMutex (mtx) ? 0 : geterrno_from_win_error ();
}
-static inline int
-ipc_mutex_close (HANDLE mtx)
-{
- return CloseHandle (mtx) ? 0 : geterrno_from_win_error ();
-}
-
-static int
-ipc_cond_init (HANDLE *pevt, const char *name, char sr)
-{
- WCHAR buf[MAX_PATH];
- UNICODE_STRING uname;
- OBJECT_ATTRIBUTES attr;
- NTSTATUS status;
-
- __small_swprintf (buf, L"mqueue/evt_%s%c", name, sr);
- RtlInitUnicodeString (&uname, buf);
- InitializeObjectAttributes (&attr, &uname,
- OBJ_INHERIT | OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
- get_shared_parent_dir (),
- everyone_sd (CYG_EVENT_ACCESS));
- status = NtCreateEvent (pevt, CYG_EVENT_ACCESS, &attr,
- NotificationEvent, FALSE);
- if (!NT_SUCCESS (status))
- {
- debug_printf ("NtCreateEvent: %y", status);
- return geterrno_from_win_error (RtlNtStatusToDosError (status));
- }
- return 0;
-}
-
static int
ipc_cond_timedwait (HANDLE evt, HANDLE mtx, const struct timespec *abstime)
{
DWORD timer_idx = 0;
int ret = 0;
- set_signal_arrived here (w4[1]);
+ wait_signal_arrived here (w4[1]);
if ((w4[cnt] = pthread::get_cancel_event ()) != NULL)
++cnt;
if (abstime)
{
- if (abstime->tv_sec < 0
- || abstime->tv_nsec < 0
- || abstime->tv_nsec > 999999999)
+ if (!valid_timespec (*abstime))
return EINVAL;
/* If a timeout is set, we create a waitable timer to wait for.
case WAIT_OBJECT_0 + 2:
if (timer_idx != 2)
pthread::static_cancel_self ();
- /*FALLTHRU*/
+ fallthrough;
case WAIT_OBJECT_0 + 3:
ret = ETIMEDOUT;
break;
case WAIT_OBJECT_0 + 2:
if (timer_idx != 2)
pthread_testcancel ();
- /*FALLTHRU*/
+ fallthrough;
case WAIT_OBJECT_0 + 3:
ret = ETIMEDOUT;
break;
SetEvent (evt);
}
-static inline void
-ipc_cond_close (HANDLE evt)
-{
- CloseHandle (evt);
-}
-
class ipc_flock
{
struct flock fl;
files are created under /dev/mqueue. mq_timedsend and mq_timedreceive
are implemented additionally. */
-/* The mq_attr structure is defined using long datatypes per POSIX.
- For interoperability reasons between 32 and 64 bit processes, we have
- to make sure to use a unified structure layout in the message queue file.
- That's what the mq_fattr is, the in-file representation of the mq_attr
- struct. */
-#pragma pack (push, 4)
-struct mq_fattr
-{
- uint32_t mq_flags;
- uint32_t mq_maxmsg;
- uint32_t mq_msgsize;
- uint32_t mq_curmsgs;
-};
-
-struct mq_hdr
-{
- struct mq_fattr mqh_attr; /* the queue's attributes */
- int32_t mqh_head; /* index of first message */
- int32_t mqh_free; /* index of first free message */
- int32_t mqh_nwait; /* #threads blocked in mq_receive() */
- pid_t mqh_pid; /* nonzero PID if mqh_event set */
- char mqh_uname[36]; /* unique name used to identify synchronization
- objects connected to this queue */
- union {
- struct sigevent mqh_event; /* for mq_notify() */
- /* Make sure sigevent takes the same space on 32 and 64 bit systems.
- Other than that, it doesn't need to be compatible since only
- one process can be notified at a time. */
- uint64_t mqh_placeholder[8];
- };
- uint32_t mqh_magic; /* Expect MQI_MAGIC here, otherwise it's
- an old-style message queue. */
-};
-
-struct msg_hdr
-{
- int32_t msg_next; /* index of next on linked list */
- int32_t msg_len; /* actual length */
- unsigned int msg_prio; /* priority */
-};
-#pragma pack (pop)
-
-struct mq_info
-{
- struct mq_hdr *mqi_hdr; /* start of mmap'ed region */
- uint32_t mqi_magic; /* magic number if open */
- int mqi_flags; /* flags for this process */
- HANDLE mqi_lock; /* mutex lock */
- HANDLE mqi_waitsend; /* and condition variable for full queue */
- HANDLE mqi_waitrecv; /* and condition variable for empty queue */
-};
-
-#define MQI_MAGIC 0x98765432UL
-
-#define MSGSIZE(i) roundup((i), sizeof(long))
-
-#define MAX_TRIES 10 /* for waiting for initialization */
-
-struct mq_attr defattr = { 0, 10, 8192, 0 }; /* Linux defaults. */
-
-extern "C" off_t lseek64 (int, off_t, int);
-extern "C" void *mmap64 (void *, size_t, int, int, int, off_t);
-
extern "C" mqd_t
mq_open (const char *name, int oflag, ...)
{
- int i, fd = -1, nonblock, created;
- long msgsize, index;
- off_t filesize = 0;
va_list ap;
- mode_t mode;
- int8_t *mptr;
- struct stat statbuff;
- struct mq_hdr *mqhdr;
- struct msg_hdr *msghdr;
- struct mq_attr *attr;
- struct mq_info *mqinfo;
- LUID luid;
+ mode_t mode = 0;
+ fhandler_mqueue *fh = NULL;
+ struct mq_attr *attr = NULL;
size_t len = strlen (name);
char mqname[ipc_names[mqueue].prefix_len + len];
if (!check_path (mqname, mqueue, name, len))
return (mqd_t) -1;
- myfault efault;
- if (efault.faulted (EFAULT))
- return (mqd_t) -1;
-
- oflag &= (O_CREAT | O_EXCL | O_NONBLOCK);
- created = 0;
- nonblock = oflag & O_NONBLOCK;
- oflag &= ~O_NONBLOCK;
- mptr = (int8_t *) MAP_FAILED;
- mqinfo = NULL;
-
-again:
- if (oflag & O_CREAT)
+ __try
{
- va_start (ap, oflag); /* init ap to final named argument */
- mode = va_arg (ap, mode_t) & ~S_IXUSR;
- attr = va_arg (ap, struct mq_attr *);
- va_end (ap);
-
- /* Open and specify O_EXCL and user-execute */
- fd = open (mqname, oflag | O_EXCL | O_RDWR | O_CLOEXEC, mode | S_IXUSR);
- if (fd < 0)
- {
- if (errno == EEXIST && (oflag & O_EXCL) == 0)
- goto exists; /* already exists, OK */
- return (mqd_t) -1;
- }
- created = 1;
- /* First one to create the file initializes it */
- if (attr == NULL)
- attr = &defattr;
- /* Check minimum and maximum values. The max values are pretty much
- arbitrary, taken from the linux mq_overview man page. However,
- these max values make sure that the internal mq_fattr structure
- can use 32 bit types. */
- else if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > 32768
- || attr->mq_msgsize <= 0 || attr->mq_msgsize > 1048576)
- {
- set_errno (EINVAL);
- goto err;
- }
- /* Calculate and set the file size */
- msgsize = MSGSIZE (attr->mq_msgsize);
- filesize = sizeof (struct mq_hdr)
- + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize));
- if (lseek64 (fd, filesize - 1, SEEK_SET) == -1)
- goto err;
- if (write (fd, "", 1) == -1)
- goto err;
-
- /* Memory map the file */
- mptr = (int8_t *) mmap64 (NULL, (size_t) filesize, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0);
- if (mptr == (int8_t *) MAP_FAILED)
- goto err;
-
- /* Allocate one mq_info{} for the queue */
- if (!(mqinfo = (struct mq_info *) calloc (1, sizeof (struct mq_info))))
- goto err;
- mqinfo->mqi_hdr = mqhdr = (struct mq_hdr *) mptr;
- mqinfo->mqi_magic = MQI_MAGIC;
- mqinfo->mqi_flags = nonblock;
-
- /* Initialize header at beginning of file */
- /* Create free list with all messages on it */
- mqhdr->mqh_attr.mq_flags = 0;
- mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg;
- mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize;
- mqhdr->mqh_attr.mq_curmsgs = 0;
- mqhdr->mqh_nwait = 0;
- mqhdr->mqh_pid = 0;
- NtAllocateLocallyUniqueId (&luid);
- __small_sprintf (mqhdr->mqh_uname, "%016X%08x%08x",
- hash_path_name (0,mqname),
- luid.HighPart, luid.LowPart);
- mqhdr->mqh_head = 0;
- mqhdr->mqh_magic = MQI_MAGIC;
- index = sizeof (struct mq_hdr);
- mqhdr->mqh_free = index;
- for (i = 0; i < attr->mq_maxmsg - 1; i++)
+ if (oflag & O_CREAT)
{
- msghdr = (struct msg_hdr *) &mptr[index];
- index += sizeof (struct msg_hdr) + msgsize;
- msghdr->msg_next = index;
+ va_start (ap, oflag); /* init ap to final named argument */
+ mode = va_arg (ap, mode_t) & ~S_IXUSR;
+ attr = va_arg (ap, struct mq_attr *);
+ va_end (ap);
}
- msghdr = (struct msg_hdr *) &mptr[index];
- msghdr->msg_next = 0; /* end of free list */
-
- /* Initialize mutex & condition variables */
- i = ipc_mutex_init (&mqinfo->mqi_lock, mqhdr->mqh_uname);
- if (i != 0)
- goto pthreaderr;
-
- i = ipc_cond_init (&mqinfo->mqi_waitsend, mqhdr->mqh_uname, 'S');
- if (i != 0)
- goto pthreaderr;
-
- i = ipc_cond_init (&mqinfo->mqi_waitrecv, mqhdr->mqh_uname, 'R');
- if (i != 0)
- goto pthreaderr;
-
- /* Initialization complete, turn off user-execute bit */
- if (fchmod (fd, mode) == -1)
- goto err;
- close (fd);
- return ((mqd_t) mqinfo);
- }
-exists:
- /* Open the file then memory map */
- if ((fd = open (mqname, O_RDWR | O_CLOEXEC)) < 0)
- {
- if (errno == ENOENT && (oflag & O_CREAT))
- goto again;
- goto err;
- }
- /* Make certain initialization is complete */
- for (i = 0; i < MAX_TRIES; i++)
- {
- if (stat64 (mqname, &statbuff) == -1)
+ /* Create file descriptor for mqueue */
+ cygheap_fdnew fd;
+
+ if (fd < 0)
+ __leave;
+ fh = (fhandler_mqueue *) build_fh_name (mqname,
+ PC_OPEN | PC_POSIX
+ | PC_SYM_NOFOLLOW | PC_NULLEMPTY,
+ NULL);
+ if (!fh)
+ __leave;
+
+ if (fh->mq_open (oflag, mode, attr))
{
- if (errno == ENOENT && (oflag & O_CREAT))
- {
- close (fd);
- fd = -1;
- goto again;
- }
- goto err;
+ fd = fh;
+ return (mqd_t) fd;
}
- if ((statbuff.st_mode & S_IXUSR) == 0)
- break;
- sleep (1);
- }
- if (i == MAX_TRIES)
- {
- set_errno (ETIMEDOUT);
- goto err;
- }
-
- filesize = statbuff.st_size;
- mptr = (int8_t *) mmap64 (NULL, (size_t) filesize, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0);
- if (mptr == (int8_t *) MAP_FAILED)
- goto err;
- close (fd);
- fd = -1;
-
- /* Allocate one mq_info{} for each open */
- if (!(mqinfo = (struct mq_info *) calloc (1, sizeof (struct mq_info))))
- goto err;
- mqinfo->mqi_hdr = mqhdr = (struct mq_hdr *) mptr;
- if (mqhdr->mqh_magic != MQI_MAGIC)
- {
- system_printf (
-"Old message queue \"%s\" detected!\n"
-"This file is not usable as message queue anymore due to changes in the "
-"internal file layout. Please remove the file and try again.", mqname);
- set_errno (EACCES);
- goto err;
}
- mqinfo->mqi_magic = MQI_MAGIC;
- mqinfo->mqi_flags = nonblock;
-
- /* Initialize mutex & condition variable */
- i = ipc_mutex_init (&mqinfo->mqi_lock, mqhdr->mqh_uname);
- if (i != 0)
- goto pthreaderr;
-
- i = ipc_cond_init (&mqinfo->mqi_waitsend, mqhdr->mqh_uname, 'S');
- if (i != 0)
- goto pthreaderr;
-
- i = ipc_cond_init (&mqinfo->mqi_waitrecv, mqhdr->mqh_uname, 'R');
- if (i != 0)
- goto pthreaderr;
-
- return (mqd_t) mqinfo;
-
-pthreaderr:
- errno = i;
-err:
- /* Don't let following function calls change errno */
- save_errno save;
+ __except (EFAULT) {}
+ __endtry
+ if (fh)
+ delete fh;
+ return (mqd_t) -1;
+}
- if (created)
- unlink (mqname);
- if (mptr != (int8_t *) MAP_FAILED)
- munmap((void *) mptr, (size_t) filesize);
- if (mqinfo)
+static struct mq_info *
+get_mqinfo (cygheap_fdget &fd)
+{
+ if (fd >= 0)
{
- if (mqinfo->mqi_lock)
- ipc_mutex_close (mqinfo->mqi_lock);
- if (mqinfo->mqi_waitsend)
- ipc_cond_close (mqinfo->mqi_waitsend);
- if (mqinfo->mqi_waitrecv)
- ipc_cond_close (mqinfo->mqi_waitrecv);
- free (mqinfo);
+ fhandler_mqueue *fh = fd->is_mqueue ();
+ if (fh)
+ return fh->mqinfo ();
+ set_errno (EINVAL);
}
- if (fd >= 0)
- close (fd);
- return (mqd_t) -1;
+ return NULL;
}
extern "C" int
struct mq_fattr *attr;
struct mq_info *mqinfo;
- myfault efault;
- if (efault.faulted (EBADF))
- return -1;
-
- mqinfo = (struct mq_info *) mqd;
- if (mqinfo->mqi_magic != MQI_MAGIC)
- {
- set_errno (EBADF);
- return -1;
- }
- mqhdr = mqinfo->mqi_hdr;
- attr = &mqhdr->mqh_attr;
- if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0)
+ __try
{
- errno = n;
- return -1;
- }
- mqstat->mq_flags = mqinfo->mqi_flags; /* per-open */
- mqstat->mq_maxmsg = attr->mq_maxmsg; /* remaining three per-queue */
- mqstat->mq_msgsize = attr->mq_msgsize;
- mqstat->mq_curmsgs = attr->mq_curmsgs;
+ cygheap_fdget fd ((int) mqd, true);
+ mqinfo = get_mqinfo (fd);
+ if (mqinfo->mqi_magic != MQI_MAGIC)
+ {
+ set_errno (EBADF);
+ __leave;
+ }
+ mqhdr = mqinfo->mqi_hdr;
+ attr = &mqhdr->mqh_attr;
+ if ((n = ipc_mutex_lock (mqinfo->mqi_lock, false)) != 0)
+ {
+ errno = n;
+ __leave;
+ }
+ mqstat->mq_flags = mqinfo->mqi_flags; /* per-open */
+ mqstat->mq_maxmsg = attr->mq_maxmsg; /* remaining three per-queue */
+ mqstat->mq_msgsize = attr->mq_msgsize;
+ mqstat->mq_curmsgs = attr->mq_curmsgs;
- ipc_mutex_unlock (mqinfo->mqi_lock);
- return 0;
+ ipc_mutex_unlock (mqinfo->mqi_lock);
+ return 0;
+ }
+ __except (EBADF) {}
+ __endtry
+ return -1;
}
extern "C" int
struct mq_fattr *attr;
struct mq_info *mqinfo;
- myfault efault;
- if (efault.faulted (EBADF))
- return -1;
-
- mqinfo = (struct mq_info *) mqd;
- if (mqinfo->mqi_magic != MQI_MAGIC)
+ __try
{
- set_errno (EBADF);
- return -1;
- }
- mqhdr = mqinfo->mqi_hdr;
- attr = &mqhdr->mqh_attr;
- if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0)
- {
- errno = n;
- return -1;
- }
+ cygheap_fdget fd ((int) mqd, true);
+ mqinfo = get_mqinfo (fd);
+ if (mqinfo->mqi_magic != MQI_MAGIC)
+ {
+ set_errno (EBADF);
+ __leave;
+ }
+ mqhdr = mqinfo->mqi_hdr;
+ attr = &mqhdr->mqh_attr;
+ if ((n = ipc_mutex_lock (mqinfo->mqi_lock, false)) != 0)
+ {
+ errno = n;
+ __leave;
+ }
- if (omqstat != NULL)
- {
- omqstat->mq_flags = mqinfo->mqi_flags; /* previous attributes */
- omqstat->mq_maxmsg = attr->mq_maxmsg;
- omqstat->mq_msgsize = attr->mq_msgsize;
- omqstat->mq_curmsgs = attr->mq_curmsgs; /* and current status */
- }
+ if (omqstat != NULL)
+ {
+ omqstat->mq_flags = mqinfo->mqi_flags; /* previous attributes */
+ omqstat->mq_maxmsg = attr->mq_maxmsg;
+ omqstat->mq_msgsize = attr->mq_msgsize;
+ omqstat->mq_curmsgs = attr->mq_curmsgs; /* and current status */
+ }
- if (mqstat->mq_flags & O_NONBLOCK)
- mqinfo->mqi_flags |= O_NONBLOCK;
- else
- mqinfo->mqi_flags &= ~O_NONBLOCK;
+ if (mqstat->mq_flags & O_NONBLOCK)
+ mqinfo->mqi_flags |= O_NONBLOCK;
+ else
+ mqinfo->mqi_flags &= ~O_NONBLOCK;
- ipc_mutex_unlock (mqinfo->mqi_lock);
- return 0;
+ ipc_mutex_unlock (mqinfo->mqi_lock);
+ return 0;
+ }
+ __except (EBADF) {}
+ __endtry
+ return -1;
}
extern "C" int
struct mq_hdr *mqhdr;
struct mq_info *mqinfo;
- myfault efault;
- if (efault.faulted (EBADF))
- return -1;
-
- mqinfo = (struct mq_info *) mqd;
- if (mqinfo->mqi_magic != MQI_MAGIC)
- {
- set_errno (EBADF);
- return -1;
- }
- mqhdr = mqinfo->mqi_hdr;
- if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0)
+ __try
{
- errno = n;
- return -1;
- }
+ cygheap_fdget fd ((int) mqd, true);
+ mqinfo = get_mqinfo (fd);
+ if (mqinfo->mqi_magic != MQI_MAGIC)
+ {
+ set_errno (EBADF);
+ __leave;
+ }
+ mqhdr = mqinfo->mqi_hdr;
+ if ((n = ipc_mutex_lock (mqinfo->mqi_lock, false)) != 0)
+ {
+ errno = n;
+ __leave;
+ }
- pid = getpid ();
- if (!notification)
- {
- if (mqhdr->mqh_pid == pid)
- mqhdr->mqh_pid = 0; /* unregister calling process */
- }
- else
- {
- if (mqhdr->mqh_pid != 0)
+ pid = getpid ();
+ if (!notification)
+ {
+ if (mqhdr->mqh_pid == pid)
+ mqhdr->mqh_pid = 0; /* unregister calling process */
+ }
+ else
{
- if (kill (mqhdr->mqh_pid, 0) != -1 || errno != ESRCH)
+ if (mqhdr->mqh_pid != 0)
{
- set_errno (EBUSY);
- ipc_mutex_unlock (mqinfo->mqi_lock);
- return -1;
+ if (kill (mqhdr->mqh_pid, 0) != -1 || errno != ESRCH)
+ {
+ set_errno (EBUSY);
+ ipc_mutex_unlock (mqinfo->mqi_lock);
+ __leave;
+ }
}
+ mqhdr->mqh_pid = pid;
+ mqhdr->mqh_event = *notification;
}
- mqhdr->mqh_pid = pid;
- mqhdr->mqh_event = *notification;
+ ipc_mutex_unlock (mqinfo->mqi_lock);
+ return 0;
}
- ipc_mutex_unlock (mqinfo->mqi_lock);
- return 0;
+ __except (EBADF) {}
+ __endtry
+ return -1;
}
static int
struct mq_hdr *mqhdr;
struct mq_fattr *attr;
struct msg_hdr *msghdr, *nmsghdr, *pmsghdr;
- struct mq_info *mqinfo;
+ struct mq_info *mqinfo = NULL;
+ bool ipc_mutex_locked = false;
+ int ret = -1;
pthread_testcancel ();
- myfault efault;
- if (efault.faulted (EBADF))
- return -1;
-
- mqinfo = (struct mq_info *) mqd;
- if (mqinfo->mqi_magic != MQI_MAGIC)
+ __try
{
- set_errno (EBADF);
- return -1;
- }
- if (prio > MQ_PRIO_MAX)
- {
- set_errno (EINVAL);
- return -1;
- }
-
- mqhdr = mqinfo->mqi_hdr; /* struct pointer */
- mptr = (int8_t *) mqhdr; /* byte pointer */
- attr = &mqhdr->mqh_attr;
- if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0)
- {
- errno = n;
- return -1;
- }
+ cygheap_fdget fd ((int) mqd);
+ mqinfo = get_mqinfo (fd);
+ if (mqinfo->mqi_magic != MQI_MAGIC)
+ {
+ set_errno (EBADF);
+ __leave;
+ }
+ if (prio >= MQ_PRIO_MAX)
+ {
+ set_errno (EINVAL);
+ __leave;
+ }
- if (len > (size_t) attr->mq_msgsize)
- {
- set_errno (EMSGSIZE);
- goto err;
- }
- if (attr->mq_curmsgs == 0)
- {
- if (mqhdr->mqh_pid != 0 && mqhdr->mqh_nwait == 0)
+ mqhdr = mqinfo->mqi_hdr; /* struct pointer */
+ mptr = (int8_t *) mqhdr; /* byte pointer */
+ attr = &mqhdr->mqh_attr;
+ if ((n = ipc_mutex_lock (mqinfo->mqi_lock, true)) != 0)
{
- sigev = &mqhdr->mqh_event;
- if (sigev->sigev_notify == SIGEV_SIGNAL)
- sigqueue (mqhdr->mqh_pid, sigev->sigev_signo, sigev->sigev_value);
- mqhdr->mqh_pid = 0; /* unregister */
+ errno = n;
+ __leave;
}
- }
- else if (attr->mq_curmsgs >= attr->mq_maxmsg)
- {
- /* Queue is full */
- if (mqinfo->mqi_flags & O_NONBLOCK)
+ ipc_mutex_locked = true;
+ if (len > (size_t) attr->mq_msgsize)
{
- set_errno (EAGAIN);
- goto err;
+ set_errno (EMSGSIZE);
+ __leave;
}
- /* Wait for room for one message on the queue */
- while (attr->mq_curmsgs >= attr->mq_maxmsg)
+ if (attr->mq_curmsgs == 0)
{
- int ret = ipc_cond_timedwait (mqinfo->mqi_waitsend, mqinfo->mqi_lock,
- abstime);
- if (ret != 0)
+ if (mqhdr->mqh_pid != 0 && mqhdr->mqh_nwait == 0)
{
- set_errno (ret);
- return -1;
+ sigev = &mqhdr->mqh_event;
+ if (sigev->sigev_notify == SIGEV_SIGNAL)
+ sigqueue (mqhdr->mqh_pid, sigev->sigev_signo,
+ sigev->sigev_value);
+ mqhdr->mqh_pid = 0; /* unregister */
+ }
+ }
+ else if (attr->mq_curmsgs >= attr->mq_maxmsg)
+ {
+ /* Queue is full */
+ if (mqinfo->mqi_flags & O_NONBLOCK)
+ {
+ set_errno (EAGAIN);
+ __leave;
+ }
+ /* Wait for room for one message on the queue */
+ while (attr->mq_curmsgs >= attr->mq_maxmsg)
+ {
+ int ret = ipc_cond_timedwait (mqinfo->mqi_waitsend,
+ mqinfo->mqi_lock, abstime);
+ if (ret != 0)
+ {
+ set_errno (ret);
+ __leave;
+ }
}
}
- }
- /* nmsghdr will point to new message */
- if ((freeindex = mqhdr->mqh_free) == 0)
- api_fatal ("mq_send: curmsgs = %ld; free = 0", attr->mq_curmsgs);
+ /* nmsghdr will point to new message */
+ if ((freeindex = mqhdr->mqh_free) == 0)
+ api_fatal ("mq_send: curmsgs = %ld; free = 0", attr->mq_curmsgs);
- nmsghdr = (struct msg_hdr *) &mptr[freeindex];
- nmsghdr->msg_prio = prio;
- nmsghdr->msg_len = len;
- memcpy (nmsghdr + 1, ptr, len); /* copy message from caller */
- mqhdr->mqh_free = nmsghdr->msg_next; /* new freelist head */
+ nmsghdr = (struct msg_hdr *) &mptr[freeindex];
+ nmsghdr->msg_prio = prio;
+ nmsghdr->msg_len = len;
+ memcpy (nmsghdr + 1, ptr, len); /* copy message from caller */
+ mqhdr->mqh_free = nmsghdr->msg_next; /* new freelist head */
- /* Find right place for message in linked list */
- index = mqhdr->mqh_head;
- pmsghdr = (struct msg_hdr *) &(mqhdr->mqh_head);
- while (index)
- {
- msghdr = (struct msg_hdr *) &mptr[index];
- if (prio > msghdr->msg_prio)
+ /* Find right place for message in linked list */
+ index = mqhdr->mqh_head;
+ pmsghdr = (struct msg_hdr *) &(mqhdr->mqh_head);
+ while (index)
{
- nmsghdr->msg_next = index;
+ msghdr = (struct msg_hdr *) &mptr[index];
+ if (prio > msghdr->msg_prio)
+ {
+ nmsghdr->msg_next = index;
+ pmsghdr->msg_next = freeindex;
+ break;
+ }
+ index = msghdr->msg_next;
+ pmsghdr = msghdr;
+ }
+ if (index == 0)
+ {
+ /* Queue was empty or new goes at end of list */
pmsghdr->msg_next = freeindex;
- break;
+ nmsghdr->msg_next = 0;
}
- index = msghdr->msg_next;
- pmsghdr = msghdr;
- }
- if (index == 0)
- {
- /* Queue was empty or new goes at end of list */
- pmsghdr->msg_next = freeindex;
- nmsghdr->msg_next = 0;
- }
- /* Wake up anyone blocked in mq_receive waiting for a message */
- if (attr->mq_curmsgs == 0)
- ipc_cond_signal (mqinfo->mqi_waitrecv);
- attr->mq_curmsgs++;
+ /* Wake up anyone blocked in mq_receive waiting for a message */
+ if (attr->mq_curmsgs == 0)
+ ipc_cond_signal (mqinfo->mqi_waitrecv);
+ attr->mq_curmsgs++;
- ipc_mutex_unlock (mqinfo->mqi_lock);
- return 0;
-
-err:
- ipc_mutex_unlock (mqinfo->mqi_lock);
- return -1;
+ ret = 0;
+ }
+ __except (EBADF) {}
+ __endtry
+ if (ipc_mutex_locked)
+ ipc_mutex_unlock (mqinfo->mqi_lock);
+ return ret;
}
extern "C" int
int n;
long index;
int8_t *mptr;
- ssize_t len;
+ ssize_t len = -1;
struct mq_hdr *mqhdr;
struct mq_fattr *attr;
struct msg_hdr *msghdr;
struct mq_info *mqinfo;
+ bool ipc_mutex_locked = false;
pthread_testcancel ();
- myfault efault;
- if (efault.faulted (EBADF))
- return -1;
-
- mqinfo = (struct mq_info *) mqd;
- if (mqinfo->mqi_magic != MQI_MAGIC)
- {
- set_errno (EBADF);
- return -1;
- }
- mqhdr = mqinfo->mqi_hdr; /* struct pointer */
- mptr = (int8_t *) mqhdr; /* byte pointer */
- attr = &mqhdr->mqh_attr;
- if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0)
- {
- errno = n;
- return -1;
- }
-
- if (maxlen < (size_t) attr->mq_msgsize)
- {
- set_errno (EMSGSIZE);
- goto err;
- }
- if (attr->mq_curmsgs == 0) /* queue is empty */
+ __try
{
- if (mqinfo->mqi_flags & O_NONBLOCK)
+ cygheap_fdget fd ((int) mqd);
+ mqinfo = get_mqinfo (fd);
+ if (mqinfo->mqi_magic != MQI_MAGIC)
{
- set_errno (EAGAIN);
- goto err;
+ set_errno (EBADF);
+ __leave;
}
- /* Wait for a message to be placed onto queue */
- mqhdr->mqh_nwait++;
- while (attr->mq_curmsgs == 0)
+ mqhdr = mqinfo->mqi_hdr; /* struct pointer */
+ mptr = (int8_t *) mqhdr; /* byte pointer */
+ attr = &mqhdr->mqh_attr;
+ if ((n = ipc_mutex_lock (mqinfo->mqi_lock, true)) != 0)
{
- int ret = ipc_cond_timedwait (mqinfo->mqi_waitrecv, mqinfo->mqi_lock,
- abstime);
- if (ret != 0)
+ errno = n;
+ __leave;
+ }
+ ipc_mutex_locked = true;
+ if (maxlen < (size_t) attr->mq_msgsize)
+ {
+ set_errno (EMSGSIZE);
+ __leave;
+ }
+ if (attr->mq_curmsgs == 0) /* queue is empty */
+ {
+ if (mqinfo->mqi_flags & O_NONBLOCK)
+ {
+ set_errno (EAGAIN);
+ __leave;
+ }
+ /* Wait for a message to be placed onto queue */
+ mqhdr->mqh_nwait++;
+ while (attr->mq_curmsgs == 0)
{
- set_errno (ret);
- return -1;
+ int ret = ipc_cond_timedwait (mqinfo->mqi_waitrecv,
+ mqinfo->mqi_lock, abstime);
+ if (ret != 0)
+ {
+ set_errno (ret);
+ __leave;
+ }
}
+ mqhdr->mqh_nwait--;
}
- mqhdr->mqh_nwait--;
- }
-
- if ((index = mqhdr->mqh_head) == 0)
- api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr->mq_curmsgs);
-
- msghdr = (struct msg_hdr *) &mptr[index];
- mqhdr->mqh_head = msghdr->msg_next; /* new head of list */
- len = msghdr->msg_len;
- memcpy(ptr, msghdr + 1, len); /* copy the message itself */
- if (priop != NULL)
- *priop = msghdr->msg_prio;
- /* Just-read message goes to front of free list */
- msghdr->msg_next = mqhdr->mqh_free;
- mqhdr->mqh_free = index;
+ if ((index = mqhdr->mqh_head) == 0)
+ api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr->mq_curmsgs);
- /* Wake up anyone blocked in mq_send waiting for room */
- if (attr->mq_curmsgs == attr->mq_maxmsg)
- ipc_cond_signal (mqinfo->mqi_waitsend);
- attr->mq_curmsgs--;
+ msghdr = (struct msg_hdr *) &mptr[index];
+ mqhdr->mqh_head = msghdr->msg_next; /* new head of list */
+ len = msghdr->msg_len;
+ memcpy(ptr, msghdr + 1, len); /* copy the message itself */
+ if (priop != NULL)
+ *priop = msghdr->msg_prio;
+
+ /* Just-read message goes to front of free list */
+ msghdr->msg_next = mqhdr->mqh_free;
+ mqhdr->mqh_free = index;
- ipc_mutex_unlock (mqinfo->mqi_lock);
+ /* Wake up anyone blocked in mq_send waiting for room */
+ if (attr->mq_curmsgs == attr->mq_maxmsg)
+ ipc_cond_signal (mqinfo->mqi_waitsend);
+ attr->mq_curmsgs--;
+ }
+ __except (EBADF) {}
+ __endtry
+ if (ipc_mutex_locked)
+ ipc_mutex_unlock (mqinfo->mqi_lock);
return len;
-
-err:
- ipc_mutex_unlock (mqinfo->mqi_lock);
- return -1;
}
extern "C" ssize_t
extern "C" int
mq_close (mqd_t mqd)
{
- long msgsize, filesize;
- struct mq_hdr *mqhdr;
- struct mq_fattr *attr;
- struct mq_info *mqinfo;
-
- myfault efault;
- if (efault.faulted (EBADF))
- return -1;
-
- mqinfo = (struct mq_info *) mqd;
- if (mqinfo->mqi_magic != MQI_MAGIC)
+ __try
{
- set_errno (EBADF);
- return -1;
- }
- mqhdr = mqinfo->mqi_hdr;
- attr = &mqhdr->mqh_attr;
-
- if (mq_notify (mqd, NULL)) /* unregister calling process */
- return -1;
+ cygheap_fdget fd ((int) mqd, true);
+ if (!fd->is_mqueue ())
+ {
+ set_errno (EBADF);
+ __leave;
+ }
- msgsize = MSGSIZE (attr->mq_msgsize);
- filesize = sizeof (struct mq_hdr)
- + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize));
- if (munmap (mqinfo->mqi_hdr, filesize) == -1)
- return -1;
+ if (mq_notify (mqd, NULL)) /* unregister calling process */
+ __leave;
- mqinfo->mqi_magic = 0; /* just in case */
- ipc_cond_close (mqinfo->mqi_waitsend);
- ipc_cond_close (mqinfo->mqi_waitrecv);
- ipc_mutex_close (mqinfo->mqi_lock);
- free (mqinfo);
- return 0;
+ fd->isclosed (true);
+ fd->close ();
+ fd.release ();
+ return 0;
+ }
+ __except (EBADF) {}
+ __endtry
+ return -1;
}
extern "C" int
the already existing semaphore class in thread.cc. Using a file backed
solution allows to implement kernel persistent named semaphores. */
+#define MAX_TRIES 10 /* for waiting for initialization */
+
struct sem_finfo
{
unsigned int value;
extern "C" sem_t *
sem_open (const char *name, int oflag, ...)
{
- int i, fd = -1, created;
+ int i, fd = -1, created = 0;
va_list ap;
mode_t mode = 0;
unsigned int value = 0;
if (!check_path (semname, semaphore, name, len))
return SEM_FAILED;
- myfault efault;
- if (efault.faulted (EFAULT))
- return SEM_FAILED;
-
- created = 0;
- oflag &= (O_CREAT | O_EXCL);
-
-again:
- if (oflag & O_CREAT)
+ __try
{
- va_start (ap, oflag); /* init ap to final named argument */
- mode = va_arg (ap, mode_t) & ~S_IXUSR;
- value = va_arg (ap, unsigned int);
- va_end (ap);
+ oflag &= (O_CREAT | O_EXCL);
- /* Open and specify O_EXCL and user-execute */
- fd = open (semname, oflag | O_EXCL | O_RDWR | O_CLOEXEC, mode | S_IXUSR);
- if (fd < 0)
+ again:
+ if (oflag & O_CREAT)
{
- if (errno == EEXIST && (oflag & O_EXCL) == 0)
- goto exists; /* already exists, OK */
- return SEM_FAILED;
+ va_start (ap, oflag); /* init ap to final named argument */
+ mode = va_arg (ap, mode_t) & ~S_IXUSR;
+ value = va_arg (ap, unsigned int);
+ va_end (ap);
+
+ /* Open and specify O_EXCL and user-execute */
+ fd = open (semname, oflag | O_EXCL | O_RDWR | O_CLOEXEC,
+ mode | S_IXUSR);
+ if (fd < 0)
+ {
+ if (errno == EEXIST && (oflag & O_EXCL) == 0)
+ goto exists; /* already exists, OK */
+ return SEM_FAILED;
+ }
+ created = 1;
+ /* First one to create the file initializes it. */
+ NtAllocateLocallyUniqueId (&sf.luid);
+ sf.value = value;
+ sf.hash = hash_path_name (0, semname);
+ if (write (fd, &sf, sizeof sf) != sizeof sf)
+ __leave;
+ sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, value,
+ wasopen);
+ if (sem == SEM_FAILED)
+ __leave;
+ /* Initialization complete, turn off user-execute bit */
+ if (fchmod (fd, mode) == -1)
+ __leave;
+ /* Don't close (fd); */
+ return sem;
}
- created = 1;
- /* First one to create the file initializes it. */
- NtAllocateLocallyUniqueId (&sf.luid);
- sf.value = value;
- sf.hash = hash_path_name (0, semname);
- if (write (fd, &sf, sizeof sf) != sizeof sf)
- goto err;
- sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, value, wasopen);
- if (sem == SEM_FAILED)
- goto err;
- /* Initialization complete, turn off user-execute bit */
- if (fchmod (fd, mode) == -1)
- goto err;
- /* Don't close (fd); */
- return sem;
- }
-exists:
- /* Open the file and fetch the semaphore name. */
- if ((fd = open (semname, O_RDWR | O_CLOEXEC)) < 0)
- {
- if (errno == ENOENT && (oflag & O_CREAT))
- goto again;
- goto err;
- }
- /* Make certain initialization is complete */
- for (i = 0; i < MAX_TRIES; i++)
- {
- if (stat64 (semname, &statbuff) == -1)
+ exists:
+ /* Open the file and fetch the semaphore name. */
+ if ((fd = open (semname, O_RDWR | O_CLOEXEC)) < 0)
{
if (errno == ENOENT && (oflag & O_CREAT))
+ goto again;
+ __leave;
+ }
+ /* Make certain initialization is complete */
+ for (i = 0; i < MAX_TRIES; i++)
+ {
+ if (stat64 (semname, &statbuff) == -1)
{
- close (fd);
- fd = -1;
- goto again;
+ if (errno == ENOENT && (oflag & O_CREAT))
+ {
+ close (fd);
+ fd = -1;
+ goto again;
+ }
+ __leave;
}
- goto err;
+ if ((statbuff.st_mode & S_IXUSR) == 0)
+ break;
+ sleep (1);
}
- if ((statbuff.st_mode & S_IXUSR) == 0)
- break;
- sleep (1);
- }
- if (i == MAX_TRIES)
- {
- set_errno (ETIMEDOUT);
- goto err;
+ if (i == MAX_TRIES)
+ {
+ set_errno (ETIMEDOUT);
+ __leave;
+ }
+ if (file.lock (fd, sizeof sf))
+ __leave;
+ if (read (fd, &sf, sizeof sf) != sizeof sf)
+ __leave;
+ sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, sf.value,
+ wasopen);
+ file.unlock (fd);
+ if (sem == SEM_FAILED)
+ __leave;
+ /* If wasopen is set, the semaphore was already opened and we already have
+ an open file descriptor pointing to the file. This means, we have to
+ close the file descriptor created in this call. It won't be stored
+ anywhere anyway. */
+ if (wasopen)
+ close (fd);
+ return sem;
}
- if (file.lock (fd, sizeof sf))
- goto err;
- if (read (fd, &sf, sizeof sf) != sizeof sf)
- goto err;
- sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, sf.value, wasopen);
- file.unlock (fd);
- if (sem == SEM_FAILED)
- goto err;
- /* If wasopen is set, the semaphore was already opened and we already have
- an open file descriptor pointing to the file. This means, we have to
- close the file descriptor created in this call. It won't be stored
- anywhere anyway. */
- if (wasopen)
- close (fd);
- return sem;
-
-err:
+ __except (EFAULT) {}
+ __endtry
/* Don't let following function calls change errno */
save_errno save;
- file.unlock (fd);
+ if (fd >= 0)
+ file.unlock (fd);
if (created)
unlink (semname);
if (sem != SEM_FAILED)
return SEM_FAILED;
}
+extern "C" off_t lseek64 (int, off_t, int);
+
int
_sem_close (sem_t *sem, bool do_close)
{