From 0e802c8affc3ec03ad4353294e1ef08b13d8e54d Mon Sep 17 00:00:00 2001 From: corinna Date: Wed, 14 Feb 2007 10:06:45 +0000 Subject: [PATCH] * Makefile.in (DLL_OFILES): Add posix_ipc.o. * cygwin.din (mq_close): Export. (mq_getattr): Export. (mq_notify): Export. (mq_open): Export. (mq_receive): Export. (mq_send): Export. (mq_setattr): Export. (mq_timedreceive): Export. (mq_timedsend): Export. (mq_unlink): Export. * posix_ipc.cc: New file implementing the above functions. Move shm_open and shm_unlink from syscalls.cc here. * sysconf.cc (sca): Set value of _SC_MQ_OPEN_MAX to MQ_OPEN_MAX, _SC_MQ_PRIO_MAX to MQ_PRIO_MAX, _SC_MESSAGE_PASSING to _POSIX_MESSAGE_PASSING. * include/limits.h (MQ_OPEN_MAX): Define. (MQ_PRIO_MAX): Define. * include/mqueue.h: New file. * include/cygwin/version.h: Bump API minor number. --- winsup/cygwin/ChangeLog | 23 + winsup/cygwin/Makefile.in | 14 +- winsup/cygwin/cygwin.din | 10 + winsup/cygwin/include/cygwin/version.h | 4 +- winsup/cygwin/include/limits.h | 10 +- winsup/cygwin/include/mqueue.h | 45 ++ winsup/cygwin/posix_ipc.cc | 849 +++++++++++++++++++++++++++++++++ winsup/cygwin/syscalls.cc | 70 --- winsup/cygwin/sysconf.cc | 6 +- 9 files changed, 944 insertions(+), 87 deletions(-) create mode 100644 winsup/cygwin/include/mqueue.h create mode 100644 winsup/cygwin/posix_ipc.cc diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 5c375cbe1f..385b2ffa4f 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,26 @@ +2007-02-14 Corinna Vinschen + + * Makefile.in (DLL_OFILES): Add posix_ipc.o. + * cygwin.din (mq_close): Export. + (mq_getattr): Export. + (mq_notify): Export. + (mq_open): Export. + (mq_receive): Export. + (mq_send): Export. + (mq_setattr): Export. + (mq_timedreceive): Export. + (mq_timedsend): Export. + (mq_unlink): Export. + * posix_ipc.cc: New file implementing the above functions. Move + shm_open and shm_unlink from syscalls.cc here. + * sysconf.cc (sca): Set value of _SC_MQ_OPEN_MAX to MQ_OPEN_MAX, + _SC_MQ_PRIO_MAX to MQ_PRIO_MAX, _SC_MESSAGE_PASSING to + _POSIX_MESSAGE_PASSING. + * include/limits.h (MQ_OPEN_MAX): Define. + (MQ_PRIO_MAX): Define. + * include/mqueue.h: New file. + * include/cygwin/version.h: Bump API minor number. + 2007-02-13 Corinna Vinschen * include/cygwin/stdlib.h (valloc): Declare. diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index 0d1c0c07cf..6aabf5d162 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -137,13 +137,13 @@ DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \ grp.o heap.o hookapi.o inet_addr.o inet_network.o init.o ioctl.o ipc.o \ localtime.o lsearch.o malloc_wrapper.o memmem.o minires-os-if.o \ minires.o miscfuncs.o mktemp.o mmap.o msg.o net.o netdb.o nftw.o ntea.o \ - passwd.o path.o pinfo.o pipe.o poll.o pthread.o regcomp.o regerror.o \ - regexec.o regfree.o registry.o resource.o rexec.o rcmd.o scandir.o \ - sched.o sec_acl.o sec_helper.o security.o select.o sem.o shared.o shm.o \ - sigfe.o signal.o sigproc.o smallprint.o spawn.o strace.o strptime.o \ - strsep.o strsig.o sync.o syscalls.o sysconf.o syslog.o termios.o \ - thread.o timelocal.o timer.o times.o tty.o uinfo.o uname.o v8_regexp.o \ - v8_regerror.o v8_regsub.o wait.o wincap.o window.o winf.o \ + passwd.o path.o pinfo.o pipe.o poll.o posix_ipc.o pthread.o regcomp.o \ + regerror.o regexec.o regfree.o registry.o resource.o rexec.o rcmd.o \ + scandir.o sched.o sec_acl.o sec_helper.o security.o select.o sem.o \ + shared.o shm.o sigfe.o signal.o sigproc.o smallprint.o spawn.o strace.o \ + strptime.o strsep.o strsig.o sync.o syscalls.o sysconf.o syslog.o \ + termios.o thread.o timelocal.o timer.o times.o tty.o uinfo.o uname.o \ + v8_regexp.o v8_regerror.o v8_regsub.o wait.o wincap.o window.o winf.o \ $(EXTRA_DLL_OFILES) $(EXTRA_OFILES) $(MALLOC_OFILES) $(MT_SAFE_OBJECTS) GMON_OFILES:=gmon.o mcount.o profil.o diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index b641a84622..4b016a4659 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -933,6 +933,16 @@ _modff = modff NOSIGFE mount SIGFE _mount = mount SIGFE mprotect SIGFE +mq_close SIGFE +mq_getattr SIGFE +mq_notify SIGFE +mq_open SIGFE +mq_receive SIGFE +mq_send SIGFE +mq_setattr SIGFE +mq_timedreceive SIGFE +mq_timedsend SIGFE +mq_unlink SIGFE mrand48 NOSIGFE msgctl SIGFE msgget SIGFE diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 8ed2f7dff6..fd9cf5aa32 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -303,12 +303,14 @@ details. */ if_nameindex, if_freenameindex. 163: Export posix_madvise, posix_memalign. 164: Export shm_open, shm_unlink. + 165: Export mq_close, mq_getattr, mq_notify, mq_open, mq_receive, + mq_send, mq_setattr, mq_timedreceive, mq_timedsend, mq_unlink. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 164 +#define CYGWIN_VERSION_API_MINOR 165 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/limits.h b/winsup/cygwin/include/limits.h index 260e63a53c..f7ae460e8b 100644 --- a/winsup/cygwin/include/limits.h +++ b/winsup/cygwin/include/limits.h @@ -179,15 +179,13 @@ details. */ #undef LOGIN_NAME_MAX #define LOGIN_NAME_MAX 256 /* equal to UNLEN defined in w32api/lmcons.h */ -/* The maximum number of open message queue descriptors a process may hold. - Not yet implemented. */ +/* The maximum number of open message queue descriptors a process may hold. */ #undef MQ_OPEN_MAX -/* #define MQ_OPEN_MAX >= _POSIX_MQ_OPEN_MAX */ +#define MQ_OPEN_MAX OPEN_MAX -/* The maximum number of message priorities supported by the implementation. - Not yet implemented. */ +/* The maximum number of message priorities supported by the implementation. */ #undef MQ_PRIO_MAX -/* #define MQ_PRIO_MAX >= _POSIX_MQ_PRIO_MAX */ +#define MQ_PRIO_MAX INT_MAX /* # of open files per process. Actually it can be more since Cygwin grows the dtable as necessary. We define a reasonable limit here diff --git a/winsup/cygwin/include/mqueue.h b/winsup/cygwin/include/mqueue.h new file mode 100644 index 0000000000..804a809199 --- /dev/null +++ b/winsup/cygwin/include/mqueue.h @@ -0,0 +1,45 @@ +/* mqueue.h: POSIX message queue interface + + Copyright 2007 Red Hat, Inc. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#include +#include +#include +#include + +#ifndef _MQUEUE_H +#define _MQUEUE_H + +__BEGIN_DECLS + +typedef void *mqd_t; + +struct mq_attr { + long mq_flags; /* Message queue flags */ + long mq_maxmsg; /* Max number of messages in queue */ + long mq_msgsize; /* Max message size */ + long mq_curmsgs; /* Current number of messages in queue */ +}; + +int mq_close (mqd_t); +int mq_getattr (mqd_t, struct mq_attr *); +int mq_notify (mqd_t, const struct sigevent *); +mqd_t mq_open (const char *, int, ...); +ssize_t mq_receive (mqd_t, char *, size_t, unsigned int *); +int mq_send (mqd_t, const char *, size_t, unsigned int); +int mq_setattr (mqd_t, const struct mq_attr *, struct mq_attr *); +ssize_t mq_timedreceive (mqd_t, char *, size_t, unsigned int *, + const struct timespec *); +int mq_timedsend (mqd_t, const char *, size_t, unsigned int, + const struct timespec *); +int mq_unlink (const char *name); + +__END_DECLS + +#endif /* _MQUEUE_H */ diff --git a/winsup/cygwin/posix_ipc.cc b/winsup/cygwin/posix_ipc.cc new file mode 100644 index 0000000000..5ed59bc3f1 --- /dev/null +++ b/winsup/cygwin/posix_ipc.cc @@ -0,0 +1,849 @@ +/* posix_ipc.cc: POSIX IPC API for Cygwin. + + Copyright 2007 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* TODO: POSIX semaphores are implemented in thread.cc right now. The + implementation in thread.cc disallows implementing kernel + persistent semaphores, so in the long run we should move the + implementation here, using file based shared memory instead. */ + +#include "winsup.h" +#include "path.h" +#include "cygerrno.h" +#include "cygtls.h" +#include "security.h" +#include "sigproc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct +{ + const char *prefix; + const char *description; +} ipc_names[] = { + { "/dev/shm", "POSIX shared memory object" }, + { "/dev/mqueue", "POSIX message queue" }, + { "/dev/sem", "POSIX semaphore" } +}; + +enum ipc_type_t +{ + shmem, + mqueue, + sem +}; + +static bool +check_path (char *res_name, ipc_type_t type, const char *name) +{ + /* Note that we require the existance of the apprpriate /dev subdirectories + for POSIX IPC object support, similar to Linux (which supports the + directories, but doesn't require to mount them). We don't create + these directory here, that's the task of the installer. But we check + for existance and give ample warning. */ + path_conv path (ipc_names[type].prefix, PC_SYM_NOFOLLOW); + if (path.error || !path.exists () || !path.isdir ()) + { + small_printf ( + "Warning: '%s' does not exists or is not a directory.\n\n" + "%ss require the existance of this directory.\n" + "Create the directory '%s' and set the permissions to 01777.\n" + "For instance on the command line: mkdir -m 01777 %s\n", + ipc_names[type].prefix, ipc_names[type].description, + ipc_names[type].prefix, ipc_names[type].prefix); + set_errno (EINVAL); + return false; + } + /* Name must start with a single slash. */ + if (!name || name[0] != '/' || name[1] == '/') + { + debug_printf ("Invalid %s name '%s'", ipc_names[type].description, name); + set_errno (EINVAL); + return false; + } + if (strlen (name) > CYG_MAX_PATH - sizeof (ipc_names[type].prefix)) + { + debug_printf ("%s name '%s' too long", ipc_names[type].description, name); + set_errno (ENAMETOOLONG); + return false; + } + strcpy (res_name, ipc_names[type].prefix); + strcat (res_name, name); + return true; +} + +static int +ipc_mutex_init (HANDLE *pmtx, const char *name) +{ + char buf[CYG_MAX_PATH]; + strcpy (buf, "cyg_pmtx"); + strcat (buf, name); + for (char *c = buf; c = strchr (c + 1, '\\'); ++c) + *c = '/'; + *pmtx = CreateMutex (&sec_all, FALSE, buf); + if (!*pmtx) + debug_printf ("failed: %E\n"); + return *pmtx ? 0 : geterrno_from_win_error (); +} + +static int +ipc_mutex_lock (HANDLE mtx) +{ + HANDLE h[2] = { mtx, signal_arrived }; + + switch (WaitForMultipleObjects (2, h, FALSE, INFINITE)) + { + case WAIT_OBJECT_0: + case WAIT_ABANDONED_0: + return 0; + case WAIT_OBJECT_0 + 1: + set_errno (EINTR); + return 1; + default: + break; + } + return geterrno_from_win_error (); +} + +static inline int +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 buf[CYG_MAX_PATH]; + strcpy (buf, "cyg_pevt"); + strcat (buf, name); + for (char *c = buf; c = strchr (c + 1, '\\'); ++c) + *c = '/'; + *pevt = CreateEvent (&sec_all, TRUE, FALSE, buf); + if (!*pevt) + debug_printf ("failed: %E\n"); + return *pevt ? 0 : geterrno_from_win_error (); +} + +static int +ipc_cond_timedwait (HANDLE evt, HANDLE mtx, const struct timespec *abstime) +{ + struct timeval tv; + DWORD timeout; + HANDLE h[2] = { mtx, evt }; + + 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; + } + if (ipc_mutex_unlock (mtx)) + return -1; + switch (WaitForMultipleObjects (2, h, TRUE, timeout)) + { + case WAIT_OBJECT_0: + case WAIT_ABANDONED_0: + ResetEvent (evt); + return 0; + case WAIT_TIMEOUT: + ipc_mutex_lock (mtx); + return ETIMEDOUT; + default: + break; + } + return geterrno_from_win_error (); +} + +static inline int +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 (); +} + +/* POSIX shared memory object implementation. */ + +extern "C" int +shm_open (const char *name, int oflag, mode_t mode) +{ + char shmname[CYG_MAX_PATH]; + + if (!check_path (shmname, shmem, name)) + return -1; + + /* Check for valid flags. */ + if (((oflag & O_ACCMODE) != O_RDONLY && (oflag & O_ACCMODE) != O_RDWR) + || (oflag & ~(O_ACCMODE | O_CREAT | O_EXCL | O_TRUNC))) + { + debug_printf ("Invalid oflag 0%o", oflag); + set_errno (EINVAL); + return -1; + } + + return open (shmname, oflag, mode & 0777); +} + +extern "C" int +shm_unlink (const char *name) +{ + char shmname[CYG_MAX_PATH]; + + if (!check_path (shmname, shmem, name)) + return -1; + + return unlink (shmname); +} + +/* The POSIX message queue implementation is based on W. Richard STEVENS + implementation, just tweaked for Cygwin. The main change is + the usage of Windows mutexes and events instead of using the pthread + synchronization objects. The pathname is massaged so that the + 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 */ + 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_wait; /* and condition variable */ +}; + +#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, nonblock, created; + long msgsize, index; + _off64_t filesize; + 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; + char mqname[CYG_MAX_PATH]; + + if (!check_path (mqname, mqueue, name)) + return (mqd_t) -1; + + myfault efault; + if (efault.faulted (EFAULT)) + return (mqd_t) -1; + + created = 0; + nonblock = oflag & O_NONBLOCK; + oflag &= ~O_NONBLOCK; + mptr = (int8_t *) MAP_FAILED; + mqinfo = NULL; + +again: + if (oflag & O_CREAT) + { + 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, 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; + 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 *) malloc (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; + 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 variable */ + i = ipc_mutex_init (&mqinfo->mqi_lock, mqname); + if (i != 0) + goto pthreaderr; + + i = ipc_cond_init (&mqinfo->mqi_wait, mqname); + 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)) < 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) + { + if (errno == ENOENT && (oflag & O_CREAT)) + { + close(fd); + goto again; + } + goto err; + } + 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); + + /* Allocate one mq_info{} for each open */ + if (!(mqinfo = (struct mq_info *) malloc (sizeof (struct mq_info)))) + goto err; + mqinfo->mqi_hdr = (struct mq_hdr *) mptr; + mqinfo->mqi_magic = MQI_MAGIC; + mqinfo->mqi_flags = nonblock; + + /* Initialize mutex & condition variable */ + i = ipc_mutex_init (&mqinfo->mqi_lock, mqname); + if (i != 0) + goto pthreaderr; + + i = ipc_cond_init (&mqinfo->mqi_wait, mqname); + 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) + free (mqinfo); + close (fd); + return (mqd_t) -1; +} + +extern "C" int +mq_getattr (mqd_t mqd, struct mq_attr *mqstat) +{ + int n; + 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) + { + 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; + + ipc_mutex_unlock (mqinfo->mqi_lock); + return 0; +} + +extern "C" int +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_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) + { + errno = n; + return -1; + } + + 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; + + ipc_mutex_unlock (mqinfo->mqi_lock); + return 0; +} + +extern "C" int +mq_notify (mqd_t mqd, const struct sigevent *notification) +{ + int n; + pid_t pid; + 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) + { + errno = n; + return -1; + } + + pid = getpid (); + if (!notification) + { + if (mqhdr->mqh_pid == pid) + mqhdr->mqh_pid = 0; /* unregister calling process */ + } + else + { + if (mqhdr->mqh_pid != 0) + { + if (kill (mqhdr->mqh_pid, 0) != -1 || errno != ESRCH) + { + set_errno (EBUSY); + ipc_mutex_unlock (mqinfo->mqi_lock); + return -1; + } + } + mqhdr->mqh_pid = pid; + mqhdr->mqh_event = *notification; + } + ipc_mutex_unlock (mqinfo->mqi_lock); + return 0; +} + +static int +_mq_send (mqd_t mqd, const char *ptr, size_t len, unsigned int prio, + const struct timespec *abstime) +{ + int n; + long index, freeindex; + int8_t *mptr; + struct sigevent *sigev; + struct mq_hdr *mqhdr; + struct mq_attr *attr; + struct msg_hdr *msghdr, *nmsghdr, *pmsghdr; + 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; + } + 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; + } + + 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) + { + 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); + goto err; + } + /* Wait for room for one message on the queue */ + while (attr->mq_curmsgs >= attr->mq_maxmsg) + ipc_cond_timedwait (mqinfo->mqi_wait, mqinfo->mqi_lock, abstime); + } + + /* 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 */ + + /* 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) + { + 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; + 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_wait); + attr->mq_curmsgs++; + + ipc_mutex_unlock (mqinfo->mqi_lock); + return 0; + +err: + ipc_mutex_unlock (mqinfo->mqi_lock); + return -1; +} + +extern "C" int +mq_send (mqd_t mqd, const char *ptr, size_t len, unsigned int prio) +{ + return _mq_send (mqd, ptr, len, prio, NULL); +} + +extern "C" int +mq_timedsend (mqd_t mqd, const char *ptr, size_t len, unsigned int prio, + const struct timespec *abstime) +{ + return _mq_send (mqd, ptr, len, prio, abstime); +} + +static ssize_t +_mq_receive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop, + const struct timespec *abstime) +{ + int n; + long index; + int8_t *mptr; + ssize_t len; + struct mq_hdr *mqhdr; + struct mq_attr *attr; + struct msg_hdr *msghdr; + 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; /* 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 */ + { + if (mqinfo->mqi_flags & O_NONBLOCK) + { + set_errno (EAGAIN); + goto err; + } + /* Wait for a message to be placed onto queue */ + mqhdr->mqh_nwait++; + while (attr->mq_curmsgs == 0) + ipc_cond_timedwait (mqinfo->mqi_wait, mqinfo->mqi_lock, abstime); + 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; + + /* Wake up anyone blocked in mq_send waiting for room */ + if (attr->mq_curmsgs == attr->mq_maxmsg) + ipc_cond_signal (mqinfo->mqi_wait); + attr->mq_curmsgs--; + + ipc_mutex_unlock (mqinfo->mqi_lock); + return len; + +err: + ipc_mutex_unlock (mqinfo->mqi_lock); + return -1; +} + +extern "C" ssize_t +mq_receive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop) +{ + return _mq_receive (mqd, ptr, maxlen, priop, NULL); +} + +extern "C" ssize_t +mq_timedreceive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop, + const struct timespec *abstime) +{ + return _mq_receive (mqd, ptr, maxlen, priop, abstime); +} + +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) + { + set_errno (EBADF); + return -1; + } + mqhdr = mqinfo->mqi_hdr; + attr = &mqhdr->mqh_attr; + + if (mq_notify (mqd, NULL)) /* unregister calling process */ + return -1; + + 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; + + mqinfo->mqi_magic = 0; /* just in case */ + ipc_cond_close (mqinfo->mqi_wait); + ipc_mutex_close (mqinfo->mqi_lock); + free (mqinfo); + return 0; +} + +extern "C" int +mq_unlink (const char *name) +{ + char mqname[CYG_MAX_PATH]; + + if (!check_path (mqname, mqueue, name)) + return -1; + if (unlink (mqname) == -1) + return -1; + return 0; +} + diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 855ff43ccb..6a0e45fb58 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -3346,73 +3346,3 @@ pclose (FILE *fp) return status; } - -#define SHM_STORAGE "/dev/shm" - -static bool -check_shm (const char *name) -{ - /* Note that we require the existance of /dev/shm for shared memory - object support, same as on Linux. We don't create this directory - here, that's the task of the installer. But we check for existance - and give ample warning. */ - path_conv dev_shm (SHM_STORAGE, PC_SYM_NOFOLLOW); - if (dev_shm.error || !dev_shm.exists () || !dev_shm.isdir ()) - { - small_printf ( - "Warning: '%s' does not exists or is not a directory.\n\n" - "Shared memory objects require the existance of this directory.\n" - "Create the directory '%s' and set the permissions to 01777.\n" - "For instance on the command line: mkdir -m 01777 %s\n", - SHM_STORAGE, SHM_STORAGE, SHM_STORAGE); - set_errno (EINVAL); - return false; - } - /* Name must start with a single slash. */ - if (!name || name[0] != '/' || name[1] == '/') - { - debug_printf ("Invalid shared memory object name '%s'", name); - set_errno (EINVAL); - return false; - } - if (strlen (name) > CYG_MAX_PATH - sizeof (SHM_STORAGE)) - { - debug_printf ("shared memory object name '%s' too long", name); - set_errno (ENAMETOOLONG); - return false; - } - return true; -} - -extern "C" int -shm_open (const char *name, int oflag, mode_t mode) -{ - if (!check_shm (name)) - return -1; - - /* Check for valid flags. */ - if (((oflag & O_ACCMODE) != O_RDONLY && (oflag & O_ACCMODE) != O_RDWR) - || (oflag & ~(O_ACCMODE | O_CREAT | O_EXCL | O_TRUNC))) - { - debug_printf ("Invalid oflag 0%o", oflag); - set_errno (EINVAL); - return -1; - } - - char shmname[CYG_MAX_PATH]; - strcpy (shmname, SHM_STORAGE); - strcat (shmname, name); - return open (shmname, oflag, mode & 0777); -} - -extern "C" int -shm_unlink (const char *name) -{ - if (!check_shm (name)) - return -1; - - char shmname[CYG_MAX_PATH]; - strcpy (shmname, SHM_STORAGE); - strcat (shmname, name); - return unlink (shmname); -} diff --git a/winsup/cygwin/sysconf.cc b/winsup/cygwin/sysconf.cc index f1f5d391e4..7a4ee9c643 100644 --- a/winsup/cygwin/sysconf.cc +++ b/winsup/cygwin/sysconf.cc @@ -131,8 +131,8 @@ static struct {func, {f:get_nproc_values}}, /* 10, _SC_NPROCESSORS_ONLN */ {func, {f:get_nproc_values}}, /* 11, _SC_PHYS_PAGES */ {func, {f:get_avphys}}, /* 12, _SC_AVPHYS_PAGES */ - {nsup, {c:0}}, /* 13, _SC_MQ_OPEN_MAX */ - {nsup, {c:0}}, /* 14, _SC_MQ_PRIO_MAX */ + {cons, {c:MQ_OPEN_MAX}}, /* 13, _SC_MQ_OPEN_MAX */ + {cons, {c:MQ_PRIO_MAX}}, /* 14, _SC_MQ_PRIO_MAX */ {cons, {c:RTSIG_MAX}}, /* 15, _SC_RTSIG_MAX */ {cons, {c:-1L}}, /* 16, _SC_SEM_NSEMS_MAX */ {cons, {c:SEM_VALUE_MAX}}, /* 17, _SC_SEM_VALUE_MAX */ @@ -145,7 +145,7 @@ static struct {cons, {c:-1L}}, /* 24, _SC_MEMLOCK */ {cons, {c:_POSIX_MEMLOCK_RANGE}}, /* 25, _SC_MEMLOCK_RANGE */ {cons, {c:_POSIX_MEMORY_PROTECTION}}, /* 26, _SC_MEMORY_PROTECTION */ - {cons, {c:-1L}}, /* 27, _SC_MESSAGE_PASSING */ + {cons, {c:_POSIX_MESSAGE_PASSING}}, /* 27, _SC_MESSAGE_PASSING */ {cons, {c:-1L}}, /* 28, _SC_PRIORITIZED_IO */ {cons, {c:_POSIX_REALTIME_SIGNALS}}, /* 29, _SC_REALTIME_SIGNALS */ {cons, {c:_POSIX_SEMAPHORES}}, /* 30, _SC_SEMAPHORES */ -- 2.11.0