From 584d0fe4ad2915ac4ee91bb537e6b46f7bd1d0c0 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 29 Sep 2014 14:59:31 -0600 Subject: [PATCH] Complete re-implementation of mq_open() --- fs/mqueue/mq_open.c | 190 ++++++++++++++++++++++++------------ fs/mqueue/mqueue.h | 77 +++++++++++++++ fs/semaphore/sem_open.c | 2 +- include/nuttx/mqueue.h | 25 ++++- sched/mqueue/mq_descreate.c | 23 +++-- sched/mqueue/mq_msgqalloc.c | 131 +++++++++++++++++++++++++ sched/mqueue/mqueue.h | 2 - 7 files changed, 376 insertions(+), 74 deletions(-) create mode 100644 fs/mqueue/mqueue.h create mode 100644 sched/mqueue/mq_msgqalloc.c diff --git a/fs/mqueue/mq_open.c b/fs/mqueue/mq_open.c index e0d47aa465..299afc4fde 100644 --- a/fs/mqueue/mq_open.c +++ b/fs/mqueue/mq_open.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/mqueue/mq_open.c * - * Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -39,24 +39,36 @@ #include -#include -#include #include +#include +#include #include #include -#include -#include #include + +#include +#include + +#include "inode/inode.h" +#include "mqueue/mqueue.h" + +#if 0 +#include +#include #include -#include #include "sched/sched.h" -#include "mqueue/mqueue.h" +#endif /**************************************************************************** * Pre-procesor Definitions ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_FS_MQUEUE_MPATH +# define CONFIG_FS_MQUEUE_MPATH "/var/mqueue" +#endif /**************************************************************************** * Private Type Declarations @@ -109,83 +121,135 @@ mqd_t mq_open(const char *mq_name, int oflags, ...) { - FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; + FAR struct inode *inode; + FAR const char *relpath = NULL; FAR struct mqueue_inode_s *msgq; - mqd_t mqdes = NULL; - va_list arg; + char fullpath[MAX_MQUEUE_PATH]; + va_list ap; struct mq_attr *attr; + mqd_t mqdes; mode_t mode; - int namelen; + int errcode; + int ret; /* Make sure that a non-NULL name is supplied */ if (mq_name) { + /* Make sure that the check for the existence of the message queue + * and the creation of the message queue are atomic with respect to + * other processes executing mq_open(). A simple sched_lock() should + * be sufficientt. + */ + sched_lock(); - namelen = strlen(mq_name); - if (namelen > 0) + + /* Get the full path to the message queue */ + + snprintf(fullpath, MAX_MQUEUE_PATH, CONFIG_FS_MQUEUE_MPATH "/%s", mq_name); + + /* Get the inode for this mqueue. This should succeed if the message + * queue has already been created. + */ + + inode = inode_find(fullpath, &relpath); + if (inode) { - /* See if the message queue already exists */ + /* It exists. Verify that the inode is a message queue */ - msgq = mq_findnamed(mq_name); - if (msgq) + if (!INODE_IS_MQUEUE(inode)) { - /* It does. Check if the caller wanted to create a new - * message queue with this name (i.e., O_CREAT|O_EXCL) - */ - - if ((oflags & O_CREAT) == 0 || (oflags & O_EXCL) == 0) - { - /* Create a message queue descriptor for the TCB */ - - mqdes = mq_descreate(rtcb, msgq, oflags); - if (mqdes) - { - /* Allow a new connection to the message queue */ - - msgq->nconnect++; - } - } + errcode = ENXIO; + goto errout_with_inode; } - /* It doesn't exist. Should we create one? */ + /* It exists and is a message queue. Check if the caller wanted to + * create a new mqueue with this name. + */ - else if ((oflags & O_CREAT) != 0) + if ((oflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) { - /* Yes.. Get the optional arguments needed to create a message - * queue. - */ + errcode = EEXIST; + goto errout_with_inode; + } - va_start(arg, oflags); - mode = va_arg(arg, mode_t); - attr = va_arg(arg, struct mq_attr*); + /* Create a message queue descriptor for the current thread */ - /* Allocate memory for the new message queue. The size to - * allocate is the size of the struct mqueue_inode_s header - * plus the size of the message queue name+1. - */ - - msgq = (FAR struct mqueue_inode_s*)mq_msgqalloc(oflags, mode, attr); - if (msgq) - { -#warning Missing logic - } - - /* Clean-up variable argument stuff */ - - va_end(arg); + msgq = inode->u.i_mqueue; + mqdes = mq_descreate(NULL, msgq, oflags); + if (!mqdes) + { + errcode = ENOMEM; + goto errout_with_inode; } } + else + { + /* The mqueue does not exists. Were we asked to create it? */ - sched_unlock(); + if ((oflags & O_CREAT) == 0) + { + /* The mqueue does not exist and O_CREAT is not set */ + + errcode = ENOENT; + goto errout_with_lock; + } + + /* Create the mqueue. First we have to extract the additional + * parameters from the variable argument list. + */ + + va_start(ap, oflags); + mode = va_arg(ap, mode_t); + attr = va_arg(ap, FAR struct mq_attr*); + va_end(ap); + + /* Create an inode in the pseudo-filesystem at this path */ + + inode_semtake(); + ret = inode_reserve(fullpath, &inode); + inode_semgive(); + + if (ret < 0) + { + errcode = -ret; + goto errout_with_lock; + } + + /* Allocate memory for the new message queue. */ + + msgq = (FAR struct mqueue_inode_s*)mq_msgqalloc(mode, attr); + if (!msgq) + { + errcode = ENOMEM; + goto errout_with_inode; + } + + /* Create a message queue descriptor for the TCB */ + + mqdes = mq_descreate(NULL, msgq, oflags); + if (!mqdes) + { + errcode = ENOMEM; + goto errout_with_msgq; + } + + /* Save the message queue in the inode structure */ + + inode->u.i_mqueue = msgq; + } } - if (mqdes == NULL) - { - return (mqd_t)ERROR; - } - else - { - return mqdes; - } + sched_unlock(); + return mqdes; + +errout_with_msgq: + mq_msgqfree(msgq); + inode->u.i_mqueue = NULL; +errout_with_inode: + inode_release(inode); +errout_with_lock: + sched_unlock(); + set_errno(errcode); + return (mqd_t)ERROR; } diff --git a/fs/mqueue/mqueue.h b/fs/mqueue/mqueue.h new file mode 100644 index 0000000000..e183021886 --- /dev/null +++ b/fs/mqueue/mqueue.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * fs/mqueue/mqueue.h + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __FS_MQUEUE_MQUEUE_H +#define __FS_MQUEUE_MQUEUE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MAX_MQUEUE_PATH 64 + +/**************************************************************************** + * Public Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __FS_MQUEUE_MQUEUE_H */ + diff --git a/fs/semaphore/sem_open.c b/fs/semaphore/sem_open.c index e4a7da4172..579a94455a 100644 --- a/fs/semaphore/sem_open.c +++ b/fs/semaphore/sem_open.c @@ -234,7 +234,7 @@ FAR sem_t *sem_open (FAR const char *name, int oflags, ...) if (!nsem) { errcode = ENOMEM; - goto errout_with_lock; + goto errout_with_inode; } /* Link to the inode */ diff --git a/include/nuttx/mqueue.h b/include/nuttx/mqueue.h index e3c3de32c2..748e4a6a6f 100644 --- a/include/nuttx/mqueue.h +++ b/include/nuttx/mqueue.h @@ -139,7 +139,6 @@ void mq_msgqfree(FAR struct mqueue_inode_s *msgq); * It allocates and initializes a structu mqueue_inode_s structure. * * Parameters: - * oflags - open flags * mode - mode_t value is ignored * attr - The mq_maxmsg attribute is used at the time that the message * queue is created to determine the maximum number of @@ -151,9 +150,31 @@ void mq_msgqfree(FAR struct mqueue_inode_s *msgq); * ****************************************************************************/ -FAR struct mqueue_inode_s *mq_msgqalloc(int oflags, mode_t mode, +struct mq_attr; +FAR struct mqueue_inode_s *mq_msgqalloc(mode_t mode, FAR struct mq_attr *attr); +/**************************************************************************** + * Name: mq_descreate + * + * Description: + * Create a message queue descriptor for the specified TCB + * + * Inputs: + * TCB - task that needs the descriptor. + * msgq - Named message queue containing the message + * oflags - access rights for the descriptor + * + * Return Value: + * On success, the message queue descriptor is returned. NULL is returned + * on a failure to allocate. + * + ****************************************************************************/ + +struct tcb_s; +mqd_t mq_descreate(FAR struct tcb_s* mtcb, FAR struct mqueue_inode_s* msgq, + int oflags); + #undef EXTERN #ifdef __cplusplus } diff --git a/sched/mqueue/mq_descreate.c b/sched/mqueue/mq_descreate.c index 237085d71a..1320fb1652 100644 --- a/sched/mqueue/mq_descreate.c +++ b/sched/mqueue/mq_descreate.c @@ -50,6 +50,7 @@ #include #include +#include #include "signal/signal.h" @@ -124,8 +125,8 @@ static mqd_t mq_desalloc(void) * Create a message queue descriptor for the specified TCB * * Inputs: - * TCB - task that needs the descriptor. - * msgq - Named message queue containing the message + * mtcb - task that needs the descriptor. + * msgq - Named message queue containing the message * oflags - access rights for the descriptor * * Return Value: @@ -134,12 +135,22 @@ static mqd_t mq_desalloc(void) * ****************************************************************************/ -mqd_t mq_descreate(FAR struct tcb_s* mtcb, FAR struct mqueue_inode_s* msgq, +mqd_t mq_descreate(FAR struct tcb_s *mtcb, FAR struct mqueue_inode_s *msgq, int oflags) { - FAR struct task_group_s *group = mtcb->group; + FAR struct task_group_s *group; mqd_t mqdes; + /* A NULL TCB pointer means to use the TCB of the currently executing + * task/thread. + */ + + if (!mtcb) + { + mtcb = sched_self(); + } + + group = mtcb->group; DEBUGASSERT(group); /* Create a message queue descriptor for the TCB */ @@ -147,13 +158,13 @@ mqd_t mq_descreate(FAR struct tcb_s* mtcb, FAR struct mqueue_inode_s* msgq, mqdes = mq_desalloc(); if (mqdes) { - /* Initialize the MQ descriptor */ + /* Initialize the message queue descriptor */ memset(mqdes, 0, sizeof(struct mq_des)); mqdes->msgq = msgq; mqdes->oflags = oflags; - /* And add it to the specified tasks's TCB */ + /* And add it to the specified task's TCB */ sq_addlast((FAR sq_entry_t*)mqdes, &group->tg_msgdesq); } diff --git a/sched/mqueue/mq_msgqalloc.c b/sched/mqueue/mq_msgqalloc.c new file mode 100644 index 0000000000..f0ddd15dc4 --- /dev/null +++ b/sched/mqueue/mq_msgqalloc.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * sched/mqueue/mq_msgqalloc.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include + +#include "sched/sched.h" +#include "mqueue/mqueue.h" + +/**************************************************************************** + * Pre-procesor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Global Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mq_msgqalloc + * + * Description: + * This function implements a part of the POSIX message queue open logic. + * It allocates and initializes a structu mqueue_inode_s structure. + * + * Parameters: + * mode - mode_t value is ignored + * attr - The mq_maxmsg attribute is used at the time that the message + * queue is created to determine the maximum number of + * messages that may be placed in the message queue. + * + * Return Value: + * The allocated and initalized message queue structure or NULL in the + * event of a failure. + * + ****************************************************************************/ + +FAR struct mqueue_inode_s *mq_msgqalloc(mode_t mode, + FAR struct mq_attr *attr) +{ + FAR struct mqueue_inode_s *msgq; + + /* Allocate memory for the new message queue. */ + + msgq = (FAR struct mqueue_inode_s*)kmm_zalloc(sizeof(struct mqueue_inode_s)); + if (msgq) + { + /* Initialize the new named message queue */ + + sq_init(&msgq->msglist); + if (attr) + { + msgq->maxmsgs = (int16_t)attr->mq_maxmsg; + if (attr->mq_msgsize <= MQ_MAX_BYTES) + { + msgq->maxmsgsize = (int16_t)attr->mq_msgsize; + } + else + { + msgq->maxmsgsize = MQ_MAX_BYTES; + } + } + else + { + msgq->maxmsgs = MQ_MAX_MSGS; + msgq->maxmsgsize = MQ_MAX_BYTES; + } + +#ifndef CONFIG_DISABLE_SIGNALS + msgq->ntpid = INVALID_PROCESS_ID; +#endif + } + + return msgq; +} diff --git a/sched/mqueue/mqueue.h b/sched/mqueue/mqueue.h index 4b382b8b0e..f44d7654d2 100644 --- a/sched/mqueue/mqueue.h +++ b/sched/mqueue/mqueue.h @@ -141,8 +141,6 @@ EXTERN sq_queue_t g_desfree; void weak_function mq_initialize(void); void mq_desblockalloc(void); -mqd_t mq_descreate(FAR struct tcb_s* mtcb, FAR struct mqueue_inode_s* msgq, - int oflags); FAR struct mqueue_inode_s *mq_findnamed(FAR const char *mq_name); void mq_msgfree(FAR struct mqueue_msg_s *mqmsg);