From ef467338e4a290b0f8978a0701b404e17c5bb048 Mon Sep 17 00:00:00 2001 From: Jeff Johnston Date: Wed, 19 Jun 2002 22:17:33 +0000 Subject: [PATCH] 2002-06-19 Jeff Johnston * libc/sys/linux/Makefile.am: Add support for message queue routines, ipc routines, and ftok. * libc/sys/linux/Makefile.in: Regenerated. * libc/sys/linux/ftok.c: New file. * libc/sys/linux/ipc.c: Ditto. * libc/sys/linux/mq_close.c: Ditto. * libc/sys/linux/mq_getattr.c: Ditto. * libc/sys/linux/mq_notify.c: Ditto. * libc/sys/linux/mq_open.c: Ditto. * libc/sys/linux/mq_receive.c: Ditto. * libc/sys/linux/mq_send.c: Ditto. * libc/sys/linux/mq_setattr.c: Ditto. * libc/sys/linux/mq_unlink.c: Ditto. * libc/sys/linux/mqlocal.h: Ditto. * libc/sys/linux/include/mqueue.h: Ditto. * libc/sys/linux/sys/types.h: Define __gid_t_defined and __uid_t_defined. --- newlib/ChangeLog | 23 +- newlib/libc/sys/linux/Makefile.am | 10 + newlib/libc/sys/linux/Makefile.in | 51 ++-- newlib/libc/sys/linux/ftok.c | 41 +++ newlib/libc/sys/linux/include/mqueue.h | 34 +++ newlib/libc/sys/linux/ipc.c | 87 +++++++ newlib/libc/sys/linux/mq_close.c | 48 ++++ newlib/libc/sys/linux/mq_getattr.c | 52 ++++ newlib/libc/sys/linux/mq_notify.c | 22 ++ newlib/libc/sys/linux/mq_open.c | 340 +++++++++++++++++++++++++ newlib/libc/sys/linux/mq_receive.c | 67 +++++ newlib/libc/sys/linux/mq_send.c | 72 ++++++ newlib/libc/sys/linux/mq_setattr.c | 59 +++++ newlib/libc/sys/linux/mq_unlink.c | 73 ++++++ newlib/libc/sys/linux/mqlocal.h | 47 ++++ newlib/libc/sys/linux/sys/types.h | 2 + 16 files changed, 1009 insertions(+), 19 deletions(-) create mode 100644 newlib/libc/sys/linux/ftok.c create mode 100644 newlib/libc/sys/linux/include/mqueue.h create mode 100644 newlib/libc/sys/linux/ipc.c create mode 100644 newlib/libc/sys/linux/mq_close.c create mode 100644 newlib/libc/sys/linux/mq_getattr.c create mode 100644 newlib/libc/sys/linux/mq_notify.c create mode 100644 newlib/libc/sys/linux/mq_open.c create mode 100644 newlib/libc/sys/linux/mq_receive.c create mode 100644 newlib/libc/sys/linux/mq_send.c create mode 100644 newlib/libc/sys/linux/mq_setattr.c create mode 100644 newlib/libc/sys/linux/mq_unlink.c create mode 100644 newlib/libc/sys/linux/mqlocal.h diff --git a/newlib/ChangeLog b/newlib/ChangeLog index 8d0b6df0f..e6df2dc6c 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,23 @@ +2002-06-19 Jeff Johnston + + * libc/sys/linux/Makefile.am: Add support for message queue routines, + ipc routines, and ftok. + * libc/sys/linux/Makefile.in: Regenerated. + * libc/sys/linux/ftok.c: New file. + * libc/sys/linux/ipc.c: Ditto. + * libc/sys/linux/mq_close.c: Ditto. + * libc/sys/linux/mq_getattr.c: Ditto. + * libc/sys/linux/mq_notify.c: Ditto. + * libc/sys/linux/mq_open.c: Ditto. + * libc/sys/linux/mq_receive.c: Ditto. + * libc/sys/linux/mq_send.c: Ditto. + * libc/sys/linux/mq_setattr.c: Ditto. + * libc/sys/linux/mq_unlink.c: Ditto. + * libc/sys/linux/mqlocal.h: Ditto. + * libc/sys/linux/include/mqueue.h: Ditto. + * libc/sys/linux/sys/types.h: Define __gid_t_defined and + __uid_t_defined. + 2002-06-19 J"orn Rennecke * libm/common/sf_lround.c (round): Change name to: (lround). @@ -186,9 +206,6 @@ Thu Jun 13 19:23:40 2002 J"orn Rennecke * libc/sys/linux/sigaction.c: New file. * libc/sys/linux/signal.c: Changed to be linux signal() function so as to override regular newlib default signal.c. - * libc/sys/linux/linuxthreads/config.h: Add __ASSUME_REALTIME_SIGNALS - definition. - * libc/sys/linux/linuxthreads/testrtsig.h: New file. * libc/sys/linux/machine/i386/Makefile.am: Remove sigset.c. * libc/sys/linux/machine/i386/Makefile.in: Regenerated. * libc/sys/linux/machine/i386/sigset.c: Moved to linux main directory. diff --git a/newlib/libc/sys/linux/Makefile.am b/newlib/libc/sys/linux/Makefile.am index fccb24dc3..861340d22 100644 --- a/newlib/libc/sys/linux/Makefile.am +++ b/newlib/libc/sys/linux/Makefile.am @@ -13,6 +13,7 @@ LIB_SOURCES = \ brk.c \ cfspeed.c \ flockfile.c \ + ftok.c \ funlockfile.c \ gethostname.c \ getoptlong.c \ @@ -21,8 +22,17 @@ LIB_SOURCES = \ inode.c \ io.c \ io64.c \ + ipc.c \ linux.c \ mmap.c \ + mq_close.c \ + mq_getattr.c \ + mq_notify.c \ + mq_open.c \ + mq_receive.c \ + mq_send.c \ + mq_setattr.c \ + mq_unlink.c \ pread.c \ pread64.c \ process.c \ diff --git a/newlib/libc/sys/linux/Makefile.in b/newlib/libc/sys/linux/Makefile.in index a89736059..9f8459e65 100644 --- a/newlib/libc/sys/linux/Makefile.in +++ b/newlib/libc/sys/linux/Makefile.in @@ -110,6 +110,7 @@ LIB_SOURCES = \ brk.c \ cfspeed.c \ flockfile.c \ + ftok.c \ funlockfile.c \ gethostname.c \ getoptlong.c \ @@ -118,8 +119,17 @@ LIB_SOURCES = \ inode.c \ io.c \ io64.c \ + ipc.c \ linux.c \ mmap.c \ + mq_close.c \ + mq_getattr.c \ + mq_notify.c \ + mq_open.c \ + mq_receive.c \ + mq_send.c \ + mq_setattr.c \ + mq_unlink.c \ pread.c \ pread64.c \ process.c \ @@ -186,12 +196,18 @@ DEFS = @DEFS@ -I. -I$(srcdir) CPPFLAGS = @CPPFLAGS@ LIBS = @LIBS@ @USE_LIBTOOL_FALSE@lib_a_OBJECTS = brk.$(OBJEXT) cfspeed.$(OBJEXT) \ -@USE_LIBTOOL_FALSE@flockfile.$(OBJEXT) funlockfile.$(OBJEXT) \ -@USE_LIBTOOL_FALSE@gethostname.$(OBJEXT) getoptlong.$(OBJEXT) \ -@USE_LIBTOOL_FALSE@getreent.$(OBJEXT) ids.$(OBJEXT) inode.$(OBJEXT) \ -@USE_LIBTOOL_FALSE@io.$(OBJEXT) io64.$(OBJEXT) linux.$(OBJEXT) \ -@USE_LIBTOOL_FALSE@mmap.$(OBJEXT) pread.$(OBJEXT) pread64.$(OBJEXT) \ -@USE_LIBTOOL_FALSE@process.$(OBJEXT) psignal.$(OBJEXT) pwrite.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@flockfile.$(OBJEXT) ftok.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@funlockfile.$(OBJEXT) gethostname.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@getoptlong.$(OBJEXT) getreent.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@ids.$(OBJEXT) inode.$(OBJEXT) io.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@io64.$(OBJEXT) ipc.$(OBJEXT) linux.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@mmap.$(OBJEXT) mq_close.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@mq_getattr.$(OBJEXT) mq_notify.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@mq_open.$(OBJEXT) mq_receive.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@mq_send.$(OBJEXT) mq_setattr.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@mq_unlink.$(OBJEXT) pread.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@pread64.$(OBJEXT) process.$(OBJEXT) \ +@USE_LIBTOOL_FALSE@psignal.$(OBJEXT) pwrite.$(OBJEXT) \ @USE_LIBTOOL_FALSE@pwrite64.$(OBJEXT) raise.$(OBJEXT) \ @USE_LIBTOOL_FALSE@realpath.$(OBJEXT) rename.$(OBJEXT) \ @USE_LIBTOOL_FALSE@resource.$(OBJEXT) sched.$(OBJEXT) select.$(OBJEXT) \ @@ -209,16 +225,19 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) @USE_LIBTOOL_TRUE@liblinux_la_DEPENDENCIES = @USE_LIBTOOL_TRUE@liblinux_la_OBJECTS = brk.lo cfspeed.lo flockfile.lo \ -@USE_LIBTOOL_TRUE@funlockfile.lo gethostname.lo getoptlong.lo \ -@USE_LIBTOOL_TRUE@getreent.lo ids.lo inode.lo io.lo io64.lo linux.lo \ -@USE_LIBTOOL_TRUE@mmap.lo pread.lo pread64.lo process.lo psignal.lo \ -@USE_LIBTOOL_TRUE@pwrite.lo pwrite64.lo raise.lo realpath.lo rename.lo \ -@USE_LIBTOOL_TRUE@resource.lo sched.lo select.lo seteuid.lo shm_open.lo \ -@USE_LIBTOOL_TRUE@shm_unlink.lo sig.lo sigaction.lo sigqueue.lo \ -@USE_LIBTOOL_TRUE@signal.lo siglongjmp.lo sigset.lo sigwait.lo \ -@USE_LIBTOOL_TRUE@socket.lo sleep.lo stack.lo strsignal.lo sysconf.lo \ -@USE_LIBTOOL_TRUE@sysctl.lo systat.lo system.lo tcdrain.lo tcsendbrk.lo \ -@USE_LIBTOOL_TRUE@termios.lo time.lo usleep.lo wait.lo +@USE_LIBTOOL_TRUE@ftok.lo funlockfile.lo gethostname.lo getoptlong.lo \ +@USE_LIBTOOL_TRUE@getreent.lo ids.lo inode.lo io.lo io64.lo ipc.lo \ +@USE_LIBTOOL_TRUE@linux.lo mmap.lo mq_close.lo mq_getattr.lo \ +@USE_LIBTOOL_TRUE@mq_notify.lo mq_open.lo mq_receive.lo mq_send.lo \ +@USE_LIBTOOL_TRUE@mq_setattr.lo mq_unlink.lo pread.lo pread64.lo \ +@USE_LIBTOOL_TRUE@process.lo psignal.lo pwrite.lo pwrite64.lo raise.lo \ +@USE_LIBTOOL_TRUE@realpath.lo rename.lo resource.lo sched.lo select.lo \ +@USE_LIBTOOL_TRUE@seteuid.lo shm_open.lo shm_unlink.lo sig.lo \ +@USE_LIBTOOL_TRUE@sigaction.lo sigqueue.lo signal.lo siglongjmp.lo \ +@USE_LIBTOOL_TRUE@sigset.lo sigwait.lo socket.lo sleep.lo stack.lo \ +@USE_LIBTOOL_TRUE@strsignal.lo sysconf.lo sysctl.lo systat.lo system.lo \ +@USE_LIBTOOL_TRUE@tcdrain.lo tcsendbrk.lo termios.lo time.lo usleep.lo \ +@USE_LIBTOOL_TRUE@wait.lo CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) diff --git a/newlib/libc/sys/linux/ftok.c b/newlib/libc/sys/linux/ftok.c new file mode 100644 index 000000000..497754bdb --- /dev/null +++ b/newlib/libc/sys/linux/ftok.c @@ -0,0 +1,41 @@ +/* Copyright (C) 1995, 1996, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , August 1995. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Modified for newlib by Jeff Johnston, June 10/2002 */ + +#include +#include +#include + +key_t +ftok (pathname, proj_id) + const char *pathname; + int proj_id; +{ + struct stat64 st; + key_t key; + + if (stat64 (pathname, &st) < 0) + return (key_t) -1; + + key = ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) + | ((proj_id & 0xff) << 24)); + + return key; +} diff --git a/newlib/libc/sys/linux/include/mqueue.h b/newlib/libc/sys/linux/include/mqueue.h new file mode 100644 index 000000000..10e81e72f --- /dev/null +++ b/newlib/libc/sys/linux/include/mqueue.h @@ -0,0 +1,34 @@ +/* libc/sys/linux/include/mqueue.h - message queue functions */ + +/* Copyright 2002, Red Hat Inc. - all rights reserved */ + +#ifndef __MQUEUE_H +#define __MQUEUE_H + +#include +#define __need_sigevent_t 1 +#include + +/* message queue types */ +typedef int mqd_t; + +struct mq_attr { + long mq_flags; /* message queue flags */ + long mq_maxmsg; /* maximum number of messages */ + long mq_msgsize; /* maximum message size */ + long mq_curmsgs; /* number of messages currently queued */ +}; + +#define MQ_PRIO_MAX 16 + +/* prototypes */ +mqd_t mq_open (const char *__name, int __oflag, ...); +int mq_close (mqd_t __msgid); +int mq_send (mqd_t __msgid, const char *__msg, size_t __msg_len, unsigned int __msg_prio); +ssize_t mq_receive (mqd_t __msgid, char *__msg, size_t __msg_len, unsigned int *__msg_prio); +int mq_notify (mqd_t __msgid, const struct sigevent *__notification); +int mq_unlink (const char *__name); +int mq_getattr (mqd_t __msgid, struct mq_attr *__mqstat); +int mq_setattr (mqd_t __msgid, const struct mq_attr *__mqstat, struct mq_attr *__omqattr); + +#endif /* __MQUEUE_H */ diff --git a/newlib/libc/sys/linux/ipc.c b/newlib/libc/sys/linux/ipc.c new file mode 100644 index 000000000..31e225255 --- /dev/null +++ b/newlib/libc/sys/linux/ipc.c @@ -0,0 +1,87 @@ +/* libc/sys/linux/ipc.c - IPC semaphore and message queue functions */ + +/* Copyright 2002, Red Hat Inc. */ + +#include +#include +#include +#include + +#include + +#define IPC_64 0x100 + +#define IPCOP_semop 1 +#define IPCOP_semget 2 +#define IPCOP_semctl 3 +#define IPCOP_msgsnd 11 +#define IPCOP_msgrcv 12 +#define IPCOP_msgget 13 +#define IPCOP_msgctl 14 + +static _syscall5(int,ipc,int,op,int,arg1,int,arg2,int,arg3,void *,arg4); + +int +semget (key_t key, int nsems, int semflgs) +{ + return __libc_ipc(IPCOP_semget, (int)key, nsems, semflgs, NULL); +} + +int +semctl (int semid, int semnum, int cmd, ...) +{ + va_list va; + union semun { + int val; + struct semid_ds *buf; + unsigned short *array; + } arg; + + va_start (va, cmd); + + arg = va_arg (va, union semun); + + va_end (va); + + return __libc_ipc(IPCOP_semctl, semid, semnum, cmd | IPC_64, &arg); +} + +int +semop (int semid, struct sembuf *sops, size_t nsems) +{ + return __libc_ipc(IPCOP_semop, semid, (int)nsems, 0, sops); +} + +int +msgget (key_t key, int msgflg) +{ + return __libc_ipc(IPCOP_msgget, (int)key, msgflg, 0, NULL); +} + +int +msgctl (int msqid, int cmd, struct msqid_ds *buf) +{ + return __libc_ipc(IPCOP_msgctl, msqid, cmd | IPC_64, 0, buf); +} + +int +msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg) +{ + return __libc_ipc(IPCOP_msgsnd, msqid, (int)msgsz, msgflg, (void *)msgp); +} + +int +msgrcv (int msqid, void *msgp, size_t msgsz, long int msgtyp, int msgflg) +{ + /* last argument must contain multiple args */ + struct { + void *msgp; + long int msgtyp; + } args; + + args.msgp = msgp; + args.msgtyp = msgtyp; + + return (ssize_t)__libc_ipc(IPCOP_msgrcv, msqid, (int)msgsz, msgflg, &args); +} + diff --git a/newlib/libc/sys/linux/mq_close.c b/newlib/libc/sys/linux/mq_close.c new file mode 100644 index 000000000..f80744327 --- /dev/null +++ b/newlib/libc/sys/linux/mq_close.c @@ -0,0 +1,48 @@ +/* Copyright 2002, Red Hat Inc. */ + +#include +#include +#include +#define _LIBC +#include +#undef _LIBC + +#include "mqlocal.h" + +int +mq_close (mqd_t msgid) +{ + struct libc_mq *info; + struct sembuf sb0 = {0, -1, 0}; + int rc; + int semid; + + info = __find_mq (msgid); + + if (info == NULL) + { + errno = EBADF; + return -1; + } + + /* lock message queue */ + semid = info->semid; + rc = semop (semid, &sb0, 1); + + if (rc == 0) + { + __cleanup_mq (msgid); + + /* unlock message queue */ + sb0.sem_op = 1; + semop (semid, &sb0, 1); + } + + return rc; +} + + + + + + diff --git a/newlib/libc/sys/linux/mq_getattr.c b/newlib/libc/sys/linux/mq_getattr.c new file mode 100644 index 000000000..b82906013 --- /dev/null +++ b/newlib/libc/sys/linux/mq_getattr.c @@ -0,0 +1,52 @@ +/* Copyright 2002, Red Hat Inc. */ + +#include +#include +#include +#include +#define _LIBC +#include +#undef _LIBC + +#include "mqlocal.h" + +int +mq_getattr (mqd_t msgid, struct mq_attr *mqstat) +{ + struct libc_mq *info; + struct sembuf sb0 = {0, -1, 0}; + int num_msgs; + int rc = 0; + + info = __find_mq (msgid); + + if (info == NULL) + { + errno = EBADF; + return -1; + } + + /* temporarily lock message queue */ + semop (info->semid, &sb0, 1); + + num_msgs = semctl (info->semid, 3, GETVAL); + if (num_msgs >= 0) + { + memcpy (mqstat, info->attr, sizeof(struct mq_attr)); + mqstat->mq_curmsgs = num_msgs; + } + else + rc = -1; + + /* release message queue */ + sb0.sem_op = 1; + semop (info->semid, &sb0, 1); + + return rc; +} + + + + + + diff --git a/newlib/libc/sys/linux/mq_notify.c b/newlib/libc/sys/linux/mq_notify.c new file mode 100644 index 000000000..fd4606bd4 --- /dev/null +++ b/newlib/libc/sys/linux/mq_notify.c @@ -0,0 +1,22 @@ +/* Copyright 2002, Red Hat Inc. */ + +#include +#include +#include + +#include "mqlocal.h" + +int +__libc_mq_notify (mqd_t msgid, const struct sigevent *notification) +{ + errno = ENOSYS; + return -1; +} +weak_alias (__libc_mq_notify, mq_notify) + + + + + + + diff --git a/newlib/libc/sys/linux/mq_open.c b/newlib/libc/sys/linux/mq_open.c new file mode 100644 index 000000000..b8da2144d --- /dev/null +++ b/newlib/libc/sys/linux/mq_open.c @@ -0,0 +1,340 @@ +/* Copyright 2002, Red Hat Inc. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define _LIBC +#include +#undef _LIBC + +#include "mqlocal.h" + +#define NHASH 32 /* Num of hash lists, must be a power of 2 */ +#define LOCHASH(i) ((i)&(NHASH-1)) + +static long mq_index; /* Index of next entry */ +static struct libc_mq *mq_hash[NHASH]; /* Hash list heads for mqopen_infos */ + +__LOCK_INIT(static, mq_hash_lock); + +mqd_t +mq_open (const char *name, int oflag, ...) +{ + MSG *wrbuf = NULL; + MSG *rdbuf = NULL; + int msgqid = -1; + int rc = -1; + int fd = -1; + int semid = -1; + int created = 0; + key_t key = (key_t)-1; + struct mq_attr *attr = (struct mq_attr *)MAP_FAILED; + struct sembuf sb = {0, 0, 0}; + mode_t mode = 0; + int size; + int i, index, saved_errno; + char *real_name; + char *ptr; + struct mq_attr *user_attr = NULL; + struct libc_mq *info; + union semun arg; + + /* ignore opening slash if present */ + if (*name == '/') + ++name; + size = strlen(name); + + if ((real_name = (char *)malloc (size + sizeof(MSGQ_PREFIX))) == NULL || + (info = (struct libc_mq *)malloc (sizeof(struct libc_mq))) == NULL) + { + errno = ENOSPC; + if (real_name) + free (real_name); + return (mqd_t)-1; + } + + /* use given name to create shared memory file name - we convert any + slashes to underscores so we don't have to create directories */ + memcpy (real_name, MSGQ_PREFIX, sizeof(MSGQ_PREFIX) - 1); + memcpy (real_name + sizeof(MSGQ_PREFIX) - 1, name, size + 1); + ptr = real_name + sizeof(MSGQ_PREFIX) - 1; + for (i = 0; i < size; ++i) + { + if (*ptr == '/') + *ptr = '_'; + ++ptr; + } + + /* open shared memory file based on msg queue open flags and then use memory + file to create a unique key to use for semaphores, etc.. */ + if (oflag & O_CREAT) + { + va_list list; + va_start (list, oflag); + + saved_errno = errno; + mode = (mode_t)va_arg (list, int); + user_attr = va_arg(list,struct mq_attr *); + va_end (list); + + /* attempt to open the shared memory file for exclusive create so we know + whether we are the owners or not */ + fd = open (real_name, O_RDWR | O_CREAT | O_EXCL, mode); + if (fd < 0 && (oflag & O_EXCL)) + { + /* we failed and the user wanted exclusive create */ + free (real_name); + free (info); + return (mqd_t)-1; + } + errno = saved_errno; + created = 1; + } + + if (fd < 0) + fd = open (real_name, O_RDWR, 0); + + if (fd >= 0) + key = ftok(real_name, 255); + + if (key != (key_t)-1) + /* memory map the shared memory file so we have a global shared data area to use */ + attr = (struct mq_attr *)mmap (0, sizeof(struct mq_attr), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + + if (attr != (struct mq_attr *)MAP_FAILED) + { + /* we need semaphores to prevent multi-process race conditions on the + shared storage which contains a shared structure. The following + are the ones we need. + + 0 = open semaphore + 1 = number of opens + 2 = number of writes left until queue is full + 3 = number of reads available in queue + 4 = notify semaphore + 5 = number of readers */ + arg.val = 0; + /* make sure the creator of the shared memory file also is the creator of the + semaphores...this will ensure that it also creates the message queue */ + if (created) + { + saved_errno = errno; + semid = semget (key, 6, IPC_CREAT | IPC_EXCL | mode); + errno = saved_errno; + /* now that we have created the semaphore, we should initialize it */ + if (semid != -1) + semctl (semid, 0, SETVAL, arg); + } + else + { + /* if we didn't create the shared memory file but have gotten to here, we want + to ensure we haven't gotten ahead of the creator temporarily so we will + loop until the semaphore exists. This ensures that the creator will be the + one to create the message queue with the correct mode and we will be blocked + by the open semaphore 0. We impose a time limit to ensure something terrible + hasn't gone wrong. */ + struct timespec tms; + int i; + + tms.tv_sec = 0; + tms.tv_nsec = 10000; /* 10 microseconds */ + for (i = 0; i < 100; ++i) + { + if ((semid = semget (key, 6, 0)) != -1) + break; + /* sleep in case we our a higher priority process */ + nanosleep (&tms, NULL); + } + } + } + + if (semid != -1) + { + /* acquire main open semaphore if we didn't create it */ + if (!created) + { + sb.sem_op = -1; + rc = semop (semid, &sb, 1); + } + else + rc = 0; /* need this to continue below */ + } + + if (rc == 0) + { + if (created) + { + /* the creator must get here first so the message queue will be created */ + msgqid = msgget (key, IPC_CREAT | mode); + if (msgqid >= 0) + { + /* we have created the message queue so check and set the attributes */ + if ((wrbuf = (MSG *)malloc (user_attr->mq_msgsize + sizeof(int))) == NULL || + (rdbuf = (MSG *)malloc (user_attr->mq_msgsize + sizeof(int))) == NULL || + user_attr == NULL || user_attr->mq_msgsize <= 0 || user_attr->mq_maxmsg <= 0) + { + /* we're out of space and we created the message queue so we should + try to remove it */ + msgctl (msgqid, IPC_RMID, NULL); + msgqid = -1; /* allow clean up to occur below */ + if (wrbuf && rdbuf) + errno = EINVAL; + else + errno = ENOSPC; + } + else /* valid attributes */ + { + write (fd, user_attr, sizeof(struct mq_attr)); + attr->mq_curmsgs = 0; + attr->mq_flags = oflag & O_NONBLOCK; + arg.val = 0; + semctl (semid, 1, SETVAL, arg); /* number of opens starts at 0 */ + semctl (semid, 3, SETVAL, arg); /* number of reads available starts at 0 */ + semctl (semid, 5, SETVAL, arg); /* number of readers starts at 0 */ + arg.val = 1; + semctl (semid, 4, SETVAL, arg); /* notify semaphore */ + arg.val = user_attr->mq_maxmsg; + semctl (semid, 2, SETVAL, arg); /* number of writes left starts at mq_maxmsg */ + } + } + } + else /* just open it */ + msgqid = msgget (key, 0); + + /* release semaphore acquired earlier */ + sb.sem_op = 1; + semop (semid, &sb, 1); + } + + /* if we get here and we haven't got a message queue id, then we need to clean up + our mess and return failure */ + if (msgqid < 0) + { + if (fd >= 0) + close (fd); + if (attr != (struct mq_attr *)MAP_FAILED) + munmap (attr, sizeof(struct mq_attr)); + if (created) + { + unlink (real_name); + if (semid != -1) + semctl (semid, 0, IPC_RMID); + } + free (real_name); + free (info); + if (wrbuf) + free (wrbuf); + if (rdbuf) + free (rdbuf); + return (mqd_t)-1; + } + + /* we are successful so register the message queue */ + + /* up the count of msg queue opens */ + sb.sem_op = 1; + sb.sem_num = 1; + semop (semid, &sb, 1); + + /* success, translate into index into mq_info array */ + __lock_acquire(mq_hash_lock); + index = mq_index++; + info->index = index; + info->msgqid = msgqid; + info->name = real_name; + info->semid = semid; + info->fd = fd; + info->oflag = oflag; + info->wrbuf = wrbuf; + info->rdbuf = rdbuf; + info->cleanup_notify = NULL; + info->next = mq_hash[LOCHASH(index)]; + info->attr = attr; + mq_hash[LOCHASH(index)] = info; + __lock_release(mq_hash_lock); + + return (mqd_t)index; +} + +struct libc_mq * +__find_mq (mqd_t mq) +{ + struct libc_mq *ptr; + + __lock_acquire(mq_hash_lock); + + ptr = mq_hash[LOCHASH((int)mq)]; + + while (ptr) + { + if (ptr->index == (int)mq) + break; + ptr = ptr->next; + } + + __lock_release(mq_hash_lock); + + return ptr; +} + +void +__cleanup_mq (mqd_t mq) +{ + struct libc_mq *ptr; + struct libc_mq *prev; + int semid; + struct sembuf sb = {0, 0, 0}; + + __lock_acquire(mq_hash_lock); + + ptr = mq_hash[LOCHASH((int)mq)]; + prev = NULL; + + while (ptr) + { + if (ptr->index == (int)mq) + break; + prev = ptr; + ptr = ptr->next; + } + + if (ptr != NULL) + { + if (ptr->cleanup_notify != NULL) + ptr->cleanup_notify (ptr); + if (prev != NULL) + prev->next = ptr->next; + else + mq_hash[LOCHASH((int)mq)] = NULL; + munmap (ptr->attr, sizeof(struct mq_attr)); + close (ptr->fd); + free (ptr->name); + free (ptr->wrbuf); + free (ptr->rdbuf); + semid = ptr->semid; + free (ptr); + /* lower the count of msg queue opens */ + sb.sem_op = -1; + sb.sem_num = 1; + sb.sem_flg = IPC_NOWAIT; + semop (semid, &sb, 1); + } + + __lock_release(mq_hash_lock); +} + + + + + diff --git a/newlib/libc/sys/linux/mq_receive.c b/newlib/libc/sys/linux/mq_receive.c new file mode 100644 index 000000000..1aa7b9fb3 --- /dev/null +++ b/newlib/libc/sys/linux/mq_receive.c @@ -0,0 +1,67 @@ +/* Copyright 2002, Red Hat Inc. */ + +#include +#include +#include +#include +#include +#include +#define _LIBC +#include +#undef _LIBC + +#include "mqlocal.h" + +__LOCK_INIT(static, mq_rdbuf_lock); + +ssize_t +mq_receive (mqd_t msgid, char *msg, size_t msg_len, unsigned int *msg_prio) +{ + struct libc_mq *info; + struct sembuf sb2 = {2, 1, 0}; + struct sembuf sb3 = {3, -1, IPC_NOWAIT}; + struct sembuf sb5 = {5, 1, IPC_NOWAIT}; + ssize_t num_bytes; + int ipcflag; + + info = __find_mq (msgid); + + if (info == NULL || (info->oflag & O_ACCMODE) == O_WRONLY) + { + errno = EBADF; + return -1; + } + + if (msg_len < info->attr->mq_msgsize) + { + errno = EMSGSIZE; + return -1; + } + + __lock_acquire (mq_rdbuf_lock); + + ipcflag = (info->attr->mq_flags & O_NONBLOCK) ? IPC_NOWAIT : 0; + + semop (info->semid, &sb5, 1); /* increase number of readers */ + num_bytes = msgrcv (info->msgqid, info->rdbuf, msg_len, -MQ_PRIO_MAX, ipcflag); + sb5.sem_op = -1; + semop (info->semid, &sb5, 1); /* decrease number of readers */ + + if (num_bytes != (ssize_t)-1) + { + semop (info->semid, &sb2, 1); /* add one to messages left to write */ + semop (info->semid, &sb3, 1); /* subtract one from messages to read */ + memcpy (msg, info->rdbuf->text, num_bytes); + if (msg_prio != NULL) + *msg_prio = MQ_PRIO_MAX - info->rdbuf->type; + } + + __lock_release (mq_rdbuf_lock); + return num_bytes; +} + + + + + + diff --git a/newlib/libc/sys/linux/mq_send.c b/newlib/libc/sys/linux/mq_send.c new file mode 100644 index 000000000..92710c2f2 --- /dev/null +++ b/newlib/libc/sys/linux/mq_send.c @@ -0,0 +1,72 @@ +/* Copyright 2002, Red Hat Inc. */ + +#include +#include +#include +#include +#include +#include +#include +#define _LIBC +#include +#undef _LIBC + +#include "mqlocal.h" + +__LOCK_INIT(static, mq_wrbuf_lock); + +int +mq_send (mqd_t msgid, const char *msg, size_t msg_len, unsigned int msg_prio) +{ + struct libc_mq *info; + struct sembuf sb2 = {2, -1, 0}; + struct sembuf sb3 = {3, 1, 0}; + int rc; + int ipcflag; + + info = __find_mq (msgid); + + if (info == NULL || (info->oflag & O_ACCMODE) == O_RDONLY) + { + errno = EBADF; + return -1; + } + + if (msg_len > info->attr->mq_msgsize) + { + errno = EMSGSIZE; + return -1; + } + + if (msg_prio > MQ_PRIO_MAX) + { + errno = EINVAL; + return -1; + } + + __lock_acquire (mq_wrbuf_lock); + + memcpy (info->wrbuf->text, msg, msg_len); + info->wrbuf->type = (MQ_PRIO_MAX - msg_prio); + + ipcflag = (info->attr->mq_flags & O_NONBLOCK) ? IPC_NOWAIT : 0; + sb2.sem_flg = ipcflag; + + /* check to see if max msgs are on queue */ + rc = semop (info->semid, &sb2, 1); + + if (rc == 0) + rc = msgsnd (info->msgqid, info->wrbuf, msg_len, ipcflag); + + if (rc == 0) + semop (info->semid, &sb3, 1); /* increment number of reads */ + + __lock_release (mq_wrbuf_lock); + return rc; +} + + + + + + diff --git a/newlib/libc/sys/linux/mq_setattr.c b/newlib/libc/sys/linux/mq_setattr.c new file mode 100644 index 000000000..ecc32e931 --- /dev/null +++ b/newlib/libc/sys/linux/mq_setattr.c @@ -0,0 +1,59 @@ +/* Copyright 2002, Red Hat Inc. */ + +#include +#include +#include +#include +#define _LIBC +#include +#undef _LIBC + +#include "mqlocal.h" + +int +mq_setattr (mqd_t msgid, const struct mq_attr *mqstat, struct mq_attr *omqstat) +{ + struct libc_mq *info; + struct sembuf sb0 = {0, -1, 0}; + int num_msgs; + int rc = 0; + + info = __find_mq (msgid); + + if (info == NULL) + { + errno = EBADF; + return -1; + } + + /* temporarily lock message queue */ + semop (info->semid, &sb0, 1); + + /* make copy of old structure */ + if (omqstat != NULL) + { + num_msgs = semctl (info->semid, 3, GETVAL); + if (num_msgs >= 0) + { + memcpy (omqstat, info->attr, sizeof(struct mq_attr)); + omqstat->mq_curmsgs = num_msgs; + } + else + rc = -1; + } + + /* only the mq_flags field can be changed */ + info->attr->mq_flags = mqstat->mq_flags; + + /* release message queue */ + sb0.sem_op = 1; + semop (info->semid, &sb0, 1); + + return rc; +} + + + + + + diff --git a/newlib/libc/sys/linux/mq_unlink.c b/newlib/libc/sys/linux/mq_unlink.c new file mode 100644 index 000000000..93902cd59 --- /dev/null +++ b/newlib/libc/sys/linux/mq_unlink.c @@ -0,0 +1,73 @@ +/* Copyright 2002, Red Hat Inc. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define _LIBC +#include +#undef _LIBC + +#include "mqlocal.h" + +int +mq_unlink (const char *name) +{ + int size; + int saved_errno; + char *real_name; + char *ptr; + int i, rc; + int semid, msgqid; + key_t key; + + /* ignore opening slash if present */ + if (*name == '/') + ++name; + size = strlen(name); + + if ((real_name = (char *)malloc (size + sizeof(MSGQ_PREFIX))) == NULL) + { + errno = ENOSPC; + return -1; + } + + /* use given name to create shared memory file name - we convert any + slashes to underscores so we don't have to create directories */ + memcpy (real_name, MSGQ_PREFIX, sizeof(MSGQ_PREFIX) - 1); + memcpy (real_name + sizeof(MSGQ_PREFIX) - 1, name, size + 1); + ptr = real_name + sizeof(MSGQ_PREFIX) - 1; + for (i = 0; i < size; ++i) + { + if (*ptr == '/') + *ptr = '_'; + ++ptr; + } + + /* get key and then unlink shared memory file */ + if ((key = ftok(real_name, 255)) == (key_t)-1) + return -1; + + rc = unlink (real_name); + + if (rc == 0) + { + /* try to remove semaphore and msg queues associated with shared memory file */ + saved_errno = errno; + semid = semget (key, 6, 0); + if (semid != -1) + semctl (semid, 0, IPC_RMID); + msgqid = msgget (key, 0); + if (msgqid != -1) + msgctl (msgqid, IPC_RMID, NULL); + errno = saved_errno; + } + + return rc; +} diff --git a/newlib/libc/sys/linux/mqlocal.h b/newlib/libc/sys/linux/mqlocal.h new file mode 100644 index 000000000..56fd66c2d --- /dev/null +++ b/newlib/libc/sys/linux/mqlocal.h @@ -0,0 +1,47 @@ +/* local definitions needed by mq routines */ + +#include +#include + +/* a message */ +typedef struct +{ + unsigned int type; + char text[1]; +} MSG; + +union semun { + int val; + struct semid_ds *buf; + unsigned short *array; +} arg; + +/* + * One of these structures is malloced to describe any open message queue + * each time mq_open is called. + */ + +struct libc_mq; + +struct libc_mq { + int index; /* index of this message queue */ + int msgqid; /* value returned by msgget */ + int semid; /* semaphore id */ + int fd; /* fd of shared memory file */ + int oflag; /* original open flag used */ + int th; /* thread id for mq_notify */ + char *name; /* name used */ + MSG *wrbuf; /* msg write buffer */ + MSG *rdbuf; /* msg read buffer */ + struct mq_attr *attr; /* pointer to attribute structure */ + struct sigevent *sigevent; /* used for mq_notify */ + void (*cleanup_notify)(struct libc_mq *); /* also used for mq_notify */ + struct libc_mq *next; /* next info struct in hash table */ +}; + +extern struct libc_mq *__find_mq (mqd_t mq); +extern void __cleanup_mq (mqd_t mq); +extern void __cleanup_mq_notify (struct libc_mq *ptr); + +#define MSGQ_PREFIX "/dev/shm/__MSGQ__" + diff --git a/newlib/libc/sys/linux/sys/types.h b/newlib/libc/sys/linux/sys/types.h index 05e313d10..bbc23167e 100644 --- a/newlib/libc/sys/linux/sys/types.h +++ b/newlib/libc/sys/linux/sys/types.h @@ -150,5 +150,7 @@ typedef long fd_mask; #include #include #define __mode_t_defined +#define __gid_t_defined +#define __uid_t_defined #endif