X-Git-Url: https://sourceware.org/git/?a=blobdiff_plain;f=winsup%2Fcygwin%2Fposix_ipc.cc;h=772072d938ad71d4b2d03b861fa531ecff1b4508;hb=b62450cf172971c7805143a39c6c491a7a3c9785;hp=c7b2bc0fed3fdee1709c5528ad2b10edc66453b5;hpb=41e9c14558ea32ce550e285d2b2b8d195b288b3d;p=newlib-cygwin.git diff --git a/winsup/cygwin/posix_ipc.cc b/winsup/cygwin/posix_ipc.cc index c7b2bc0fe..772072d93 100644 --- a/winsup/cygwin/posix_ipc.cc +++ b/winsup/cygwin/posix_ipc.cc @@ -1,7 +1,5 @@ /* posix_ipc.cc: POSIX IPC API for Cygwin. - Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. - This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the @@ -18,6 +16,8 @@ details. */ #include "cygheap.h" #include "sigproc.h" #include "ntdll.h" +#include "tls_pbuf.h" +#include #include #include #include @@ -25,7 +25,7 @@ details. */ #include #include -/* 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 { @@ -66,22 +66,33 @@ check_path (char *res_name, ipc_type_t type, const char *name, size_t len) 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); @@ -89,44 +100,20 @@ check_path (char *res_name, ipc_type_t type, const char *name, size_t len) } __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: %p", status); - return geterrno_from_win_error (RtlNtStatusToDosError (status)); - } - return 0; -} - -static int -ipc_mutex_lock (HANDLE mtx) -{ - HANDLE h[2] = { mtx, signal_arrived }; - - switch (WaitForMultipleObjects (2, h, FALSE, INFINITE)) + 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 0; - case WAIT_OBJECT_0 + 1: + case WAIT_SIGNALED: set_errno (EINTR); return 1; default: @@ -141,93 +128,114 @@ ipc_mutex_unlock (HANDLE mtx) 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: %p", status); - return geterrno_from_win_error (RtlNtStatusToDosError (status)); - } - return 0; -} - static int ipc_cond_timedwait (HANDLE evt, HANDLE mtx, const struct timespec *abstime) { - struct timeval tv; - DWORD timeout; - HANDLE h[2] = { mtx, evt }; - int err; - - if (!abstime) - timeout = INFINITE; - else if (abstime->tv_sec < 0 - || abstime->tv_nsec < 0 - || abstime->tv_nsec > 999999999) - return EINVAL; - else - { - gettimeofday (&tv, NULL); - /* Check for immediate timeout. */ - if (tv.tv_sec > abstime->tv_sec - || (tv.tv_sec == abstime->tv_sec - && tv.tv_usec > abstime->tv_nsec / 1000)) - return ETIMEDOUT; - timeout = (abstime->tv_sec - tv.tv_sec) * 1000; - timeout += (abstime->tv_nsec / 1000 - tv.tv_usec) / 1000; + HANDLE w4[4] = { evt, }; + DWORD cnt = 2; + DWORD timer_idx = 0; + int ret = 0; + + wait_signal_arrived here (w4[1]); + if ((w4[cnt] = pthread::get_cancel_event ()) != NULL) + ++cnt; + if (abstime) + { + if (!valid_timespec (*abstime)) + return EINVAL; + + /* If a timeout is set, we create a waitable timer to wait for. + This is the easiest way to handle the absolute timeout value, given + that NtSetTimer also takes absolute times and given the double + dependency on evt *and* mtx, which requires to call WFMO twice. */ + NTSTATUS status; + LARGE_INTEGER duetime; + + timer_idx = cnt++; + status = NtCreateTimer (&w4[timer_idx], TIMER_ALL_ACCESS, NULL, + NotificationTimer); + if (!NT_SUCCESS (status)) + return geterrno_from_nt_status (status); + timespec_to_filetime (abstime, &duetime); + status = NtSetTimer (w4[timer_idx], &duetime, NULL, NULL, FALSE, 0, NULL); + if (!NT_SUCCESS (status)) + { + NtClose (w4[timer_idx]); + return geterrno_from_nt_status (status); + } } ResetEvent (evt); - if ((err = ipc_mutex_unlock (mtx)) != 0) - return err; - switch (WaitForMultipleObjects (2, h, TRUE, timeout)) + if ((ret = ipc_mutex_unlock (mtx)) != 0) + return ret; + /* Everything's set up, so now wait for the event to be signalled. */ +restart1: + switch (WaitForMultipleObjects (cnt, w4, FALSE, INFINITE)) { case WAIT_OBJECT_0: - case WAIT_ABANDONED_0: - return 0; - case WAIT_TIMEOUT: - ipc_mutex_lock (mtx); - return ETIMEDOUT; + break; + case WAIT_OBJECT_0 + 1: + if (_my_tls.call_signal_handler ()) + goto restart1; + ret = EINTR; + break; + case WAIT_OBJECT_0 + 2: + if (timer_idx != 2) + pthread::static_cancel_self (); + fallthrough; + case WAIT_OBJECT_0 + 3: + ret = ETIMEDOUT; + break; default: + ret = geterrno_from_win_error (); break; } - return geterrno_from_win_error (); + if (ret == 0) + { + /* At this point we need to lock the mutex. The wait is practically + the same as before, just that we now wait on the mutex instead of the + event. */ + restart2: + w4[0] = mtx; + switch (WaitForMultipleObjects (cnt, w4, FALSE, INFINITE)) + { + case WAIT_OBJECT_0: + case WAIT_ABANDONED_0: + break; + case WAIT_OBJECT_0 + 1: + if (_my_tls.call_signal_handler ()) + goto restart2; + ret = EINTR; + break; + case WAIT_OBJECT_0 + 2: + if (timer_idx != 2) + pthread_testcancel (); + fallthrough; + case WAIT_OBJECT_0 + 3: + ret = ETIMEDOUT; + break; + default: + ret = geterrno_from_win_error (); + break; + } + } + if (timer_idx) + { + if (ret != ETIMEDOUT) + NtCancelTimer (w4[timer_idx], NULL); + NtClose (w4[timer_idx]); + } + return ret; } -static inline int +static inline void ipc_cond_signal (HANDLE evt) { - return SetEvent (evt) ? 0 : geterrno_from_win_error (); -} - -static inline int -ipc_cond_close (HANDLE evt) -{ - return CloseHandle (evt) ? 0 : geterrno_from_win_error (); + SetEvent (evt); } class ipc_flock { - struct __flock64 fl; + struct flock fl; public: ipc_flock () { memset (&fl, 0, sizeof fl); } @@ -291,61 +299,13 @@ shm_unlink (const char *name) files are created under /dev/mqueue. mq_timedsend and mq_timedreceive are implemented additionally. */ -struct mq_hdr -{ - struct mq_attr mqh_attr; /* the queue's attributes */ - long mqh_head; /* index of first message */ - long mqh_free; /* index of first free message */ - long 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 */ - struct sigevent mqh_event; /* for mq_notify() */ -}; - -struct msg_hdr -{ - long msg_next; /* index of next on linked list */ - ssize_t msg_len; /* actual length */ - unsigned int msg_prio; /* priority */ -}; - -struct mq_info -{ - struct mq_hdr *mqi_hdr; /* start of mmap'ed region */ - unsigned long 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" _off64_t lseek64 (int, _off64_t, int); -extern "C" void *mmap64 (void *, size_t, int, int, int, _off64_t); - extern "C" mqd_t mq_open (const char *name, int oflag, ...) { - int i, fd = -1, nonblock, created; - long msgsize, index; - _off64_t filesize = 0; va_list ap; - mode_t mode; - int8_t *mptr; - struct __stat64 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]; @@ -353,192 +313,52 @@ mq_open (const char *name, int oflag, ...) 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 (oflag & O_CREAT) { - if (errno == EEXIST && (oflag & O_EXCL) == 0) - goto exists; /* already exists, OK */ - return (mqd_t) -1; + 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); } - created = 1; - /* First one to create the file initializes it */ - if (attr == NULL) - attr = &defattr; - else if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) - { - 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; - index = sizeof (struct mq_hdr); - mqhdr->mqh_free = index; - for (i = 0; i < attr->mq_maxmsg - 1; i++) - { - msghdr = (struct msg_hdr *) &mptr[index]; - index += sizeof (struct msg_hdr) + msgsize; - msghdr->msg_next = index; - } - 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; } + __except (EFAULT) {} + __endtry + if (fh) + delete fh; + return (mqd_t) -1; +} - 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; - 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; - - 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 @@ -546,33 +366,36 @@ mq_getattr (mqd_t mqd, struct mq_attr *mqstat) { int n; struct mq_hdr *mqhdr; - struct mq_attr *attr; + 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; - } - 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 @@ -580,42 +403,45 @@ mq_setattr (mqd_t mqd, const struct mq_attr *mqstat, struct mq_attr *omqstat) { int n; struct mq_hdr *mqhdr; - struct mq_attr *attr; + 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; - } + 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 @@ -626,45 +452,48 @@ mq_notify (mqd_t mqd, const struct sigevent *notification) 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) + __try { - set_errno (EBADF); - return -1; - } - mqhdr = mqinfo->mqi_hdr; - 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; + 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 @@ -676,113 +505,118 @@ _mq_send (mqd_t mqd, const char *ptr, size_t len, unsigned int prio, int8_t *mptr; struct sigevent *sigev; struct mq_hdr *mqhdr; - struct mq_attr *attr; + 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; - myfault efault; - if (efault.faulted (EBADF)) - return -1; + pthread_testcancel (); - 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); - goto err; + 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++; - - ipc_mutex_unlock (mqinfo->mqi_lock); - return 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++; -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 @@ -805,83 +639,84 @@ _mq_receive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop, int n; long index; int8_t *mptr; - ssize_t len; + ssize_t len = -1; struct mq_hdr *mqhdr; - struct mq_attr *attr; + struct mq_fattr *attr; struct msg_hdr *msghdr; struct mq_info *mqinfo; + bool ipc_mutex_locked = false; - 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; - } + pthread_testcancel (); - if (maxlen < (size_t) attr->mq_msgsize) + __try { - set_errno (EMSGSIZE); - goto err; - } - if (attr->mq_curmsgs == 0) /* queue is empty */ - { - 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); - goto err; + 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; + if ((index = mqhdr->mqh_head) == 0) + api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr->mq_curmsgs); - /* Just-read message goes to front of free list */ - msghdr->msg_next = mqhdr->mqh_free; - mqhdr->mqh_free = index; - - /* 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 @@ -900,39 +735,26 @@ mq_timedreceive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop, extern "C" int mq_close (mqd_t mqd) { - long msgsize, filesize; - struct mq_hdr *mqhdr; - struct mq_attr *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 @@ -953,6 +775,8 @@ mq_unlink (const char *name) 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; @@ -963,11 +787,11 @@ struct sem_finfo 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; - struct __stat64 statbuff; + struct stat statbuff; sem_t *sem = SEM_FAILED; sem_finfo sf; bool wasopen = false; @@ -979,97 +803,99 @@ sem_open (const char *name, int oflag, ...) 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) @@ -1079,6 +905,8 @@ err: return SEM_FAILED; } +extern "C" off_t lseek64 (int, off_t, int); + int _sem_close (sem_t *sem, bool do_close) { @@ -1089,7 +917,7 @@ _sem_close (sem_t *sem, bool do_close) if (semaphore::getinternal (sem, &fd, &sf.hash, &sf.luid, &sf.value) == -1) return -1; if (!file.lock (fd, sizeof sf) - && lseek64 (fd, 0LL, SEEK_SET) != (_off64_t) -1 + && lseek64 (fd, 0LL, SEEK_SET) != (off_t) -1 && write (fd, &sf, sizeof sf) == sizeof sf) ret = do_close ? semaphore::close (sem) : 0;