Completes the re-implementation of mq_unlink()

This commit is contained in:
Gregory Nutt 2014-09-29 15:48:52 -06:00
parent 1f2cc9f4fe
commit 419b074b15
5 changed files with 161 additions and 97 deletions

View File

@ -1,7 +1,7 @@
/****************************************************************************
* sched/mqueue/mq_close.c
* fs/mqueue/mq_close.c
*
* Copyright (C) 2007, 2009, 2013 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2009, 2013-2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -107,7 +107,7 @@ int mq_close(mqd_t mqdes)
FAR struct tcb_s *rtcb = sched_self();
FAR struct task_group_s *group = rtcb->group;
FAR struct mqueue_inode_s *msgq;
struct inode *inode ;
FAR struct inode *inode;
DEBUGASSERT(group);
@ -128,11 +128,6 @@ int mq_close(mqd_t mqdes)
msgq = mqdes->msgq;
DEBUGASSERT(msgq && msgq->inode);
/* Get the inode from the message queue structure */
inode = msgq->inode;
DEBUGASSERT(inode->u.i_mqueue == msgq);
/* Check if the calling task has a notification attached to
* the message queue via this mqdes.
*/
@ -147,6 +142,35 @@ int mq_close(mqd_t mqdes)
}
#endif
/* Get the inode from the message queue structure */
inode = msgq->inode;
DEBUGASSERT(inode->u.i_mqueue == msgq);
/* Decrement the reference count on the inode */
mq_release(inode);
}
return OK;
}
/****************************************************************************
* Name: mq_close
*
* Description:
* Release a reference count on a message queue inode.
*
* Parameters:
* inode - The message queue inode
*
* Return Value:
* None
*
****************************************************************************/
void mq_release(FAR struct inode *inode)
{
/* Decrement the reference count on the inode */
inode_semtake();
@ -155,32 +179,28 @@ int mq_close(mqd_t mqdes)
inode->i_crefs--;
}
/* If the message queue was previously unlinked and the reference
* count has decremented to zero, then release the message queue and
* delete the inode now.
/* If the message queue was previously unlinked and the reference count
* has decremented to zero, then release the message queue and delete
* the inode now.
*/
if (inode->i_crefs <= 0 && (inode->i_flags & FSNODEFLAG_DELETED) != 0)
{
FAR struct mqueue_inode_s *msgq = inode->u.i_mqueue;
DEBUGASSERT(msgq);
/* Free the message queue (and any messages left in it) */
mq_msgqfree(msgq);
inode->u.i_mqueue = NULL;
/* Release and free the inode container */
inode_semgive();
inode_free(inode->i_child);
kmm_free(inode);
return OK;
return;
}
/* Deallocate the message descriptor */
mq_desfree(mqdes);
sched_unlock();
inode_semgive();
}
return OK;
}

View File

@ -1,5 +1,5 @@
/****************************************************************************
* sched/mqueue/mq_open.c
* fs/mqueue/mq_open.c
*
* Copyright (C) 2007-2009, 2011, 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
@ -64,11 +64,6 @@
/****************************************************************************
* Pre-procesor Definitions
****************************************************************************/
/* Configuration ************************************************************/
#ifndef CONFIG_FS_MQUEUE_MPATH
# define CONFIG_FS_MQUEUE_MPATH "/var/mqueue"
#endif
/****************************************************************************
* Private Type Declarations

View File

@ -1,7 +1,7 @@
/************************************************************************
* sched/mqueue/mq_unlink.c
* fs/mqueue/mq_unlink.c
*
* Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2009, 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -39,10 +39,14 @@
#include <nuttx/config.h>
#include <stdbool.h>
#include <stdio.h>
#include <mqueue.h>
#include <sched.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/mqueue.h>
#include "inode/inode.h"
#include "mqueue/mqueue.h"
/************************************************************************
@ -88,58 +92,80 @@
*
************************************************************************/
int mq_unlink(const char *mq_name)
int mq_unlink(FAR const char *mq_name)
{
FAR struct mqueue_inode_s *msgq;
irqstate_t saved_state;
int ret = ERROR;
FAR struct inode *inode;
FAR const char *relpath = NULL;
char fullpath[MAX_MQUEUE_PATH];
int errcode;
int ret;
/* Verify the input values */
/* 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 message queue. */
if (mq_name)
{
sched_lock();
/* Find the named message queue */
msgq = mq_findnamed(mq_name);
if (msgq)
inode = inode_find(fullpath, &relpath);
if (!inode)
{
/* If it is no longer connected, then we can just
* discard the message queue now.
/* There is no inode that includes in this path */
errcode = ENOENT;
goto errout;
}
/* Verify that what we found is, indeed, a message queue */
if (!INODE_IS_MQUEUE(inode))
{
errcode = ENXIO;
goto errout_with_inode;
}
/* Refuse to unlink the inode if it has children. I.e., if it is
* functioning as a directory and the directory is not empty.
*/
if (!msgq->nconnect)
inode_semtake();
if (inode->i_child != NULL)
{
/* Remove the message queue from the list of all
* message queues
errcode = ENOTEMPTY;
goto errout_with_semaphore;
}
/* Remove the old inode from the tree. Because we hold a reference count
* on the inode, it will not be deleted now. This will set the
* FSNODEFLAG_DELETED bit in the inode flags.
*/
saved_state = irqsave();
(void)sq_rem((FAR sq_entry_t*)msgq, &g_msgqueues);
irqrestore(saved_state);
ret = inode_remove(fullpath);
/* Then deallocate it (and any messages left in it) */
mq_msgqfree(msgq);
}
/* If the message queue is still connected to a message descriptor,
* then mark it for deletion when the last message descriptor is
* closed
/* inode_remove() should always fail with -EBUSY because we hae a reference
* on the inode. -EBUSY means taht the inode was, indeed, unlinked but
* thatis could not be freed because there are refrences.
*/
else
{
msgq->unlinked = true;
}
DEBUGASSERT(ret >= 0 || ret == -EBUSY);
UNUSED(ret);
ret = OK;
}
/* Now we do not release the reference count in the normal way (by calling
* inode release. Rather, we call sem_close(). sem_close will decrement
* the reference count on the inode. But it will also free the message queue
* if that reference count decrements to zero. Since we hold one reference,
* that can only occur if the message queue is not in-use.
*/
sched_unlock();
}
inode_semgive();
mq_release(inode);
return OK;
return ret;
errout_with_semaphore:
inode_semgive();
errout_with_inode:
inode_release(inode);
errout:
set_errno(errcode);
return ERROR;
}

View File

@ -45,6 +45,13 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
#ifndef CONFIG_FS_MQUEUE_MPATH
# define CONFIG_FS_MQUEUE_MPATH "/var/mqueue"
#endif
/* Sizes of things */
#define MAX_MQUEUE_PATH 64
@ -68,6 +75,22 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: mq_close
*
* Description:
* Release a reference count on a message queue inode.
*
* Parameters:
* inode - The message queue inode
*
* Return Value:
* None
*
****************************************************************************/
void mq_release(FAR struct inode *inode);
#undef EXTERN
#ifdef __cplusplus
}