void mq_inode_release(FAR struct inode *inode) { /* Decrement the reference count on the inode */ inode_semtake(); if (inode->i_crefs > 0) { 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 (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; } inode_semgive(); }
mqd_t mq_open(FAR const char *mq_name, int oflags, ...) { FAR struct inode *inode; FAR const char *relpath = NULL; FAR struct mqueue_inode_s *msgq; char fullpath[MAX_MQUEUE_PATH]; va_list ap; struct mq_attr *attr; mqd_t mqdes; mode_t mode; int errcode; int ret; /* Make sure that a non-NULL name is supplied */ if (!mq_name) { errcode = EINVAL; goto errout; } /* Get the full path to the message queue */ snprintf(fullpath, MAX_MQUEUE_PATH, CONFIG_FS_MQUEUE_MPATH "/%s", 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 sufficient. */ sched_lock(); /* Get the inode for this mqueue. This should succeed if the message * queue has already been created. */ inode = inode_find(fullpath, &relpath); if (inode) { /* It exists. Verify that the inode is a message queue */ if (!INODE_IS_MQUEUE(inode)) { errcode = ENXIO; goto errout_with_inode; } /* It exists and is a message queue. Check if the caller wanted to * create a new mqueue with this name. */ if ((oflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) { errcode = EEXIST; goto errout_with_inode; } /* Create a message queue descriptor for the current thread */ 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? */ 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 = ENOSPC; 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; } /* Bind the message queue and the inode structure */ INODE_SET_MQUEUE(inode); inode->u.i_mqueue = msgq; msgq->inode = inode; } 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(); errout: set_errno(errcode); return (mqd_t)ERROR; }
int mq_close(mqd_t mqdes) { FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; FAR msgq_t *msgq; irqstate_t saved_state; int ret = ERROR; /* Verify the inputs */ if (mqdes) { sched_lock(); /* Remove the message descriptor from the current task's * list of message descriptors. */ sq_rem((FAR sq_entry_t*)mqdes, &rtcb->msgdesq); /* Find the message queue associated with the message descriptor */ msgq = mqdes->msgq; /* Check if the calling task has a notification attached to * the message queue via this mqdes. */ #ifndef CONFIG_DISABLE_SIGNALS if (msgq->ntmqdes == mqdes) { msgq->ntpid = INVALID_PROCESS_ID; msgq->ntsigno = 0; msgq->ntvalue.sival_int = 0; msgq->ntmqdes = NULL; } #endif /* Decrement the connection count on the message queue. */ if (msgq->nconnect) { msgq->nconnect--; } /* If it is no longer connected to any message descriptor and if the * message queue has already been unlinked, then we can discard the * message queue. */ if (!msgq->nconnect && msgq->unlinked) { /* Remove the message queue from the list of all * message queues */ saved_state = irqsave(); (void)sq_rem((FAR sq_entry_t*)msgq, &g_msgqueues); irqrestore(saved_state); /* Then deallocate it (and any messages left in it) */ mq_msgqfree(msgq); } /* Deallocate the message descriptor */ mq_desfree(mqdes); sched_unlock(); ret = OK; } return ret; }