This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push: new 162870b750 rpmsgdev: support blocked read/write operation 162870b750 is described below commit 162870b7508abc50097b77e8f4b19cb24a78d9af Author: wangbowen6 <wangbow...@xiaomi.com> AuthorDate: Mon Nov 14 16:55:46 2022 +0800 rpmsgdev: support blocked read/write operation Signed-off-by: wangbowen6 <wangbow...@xiaomi.com> --- drivers/misc/rpmsgdev.c | 138 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 132 insertions(+), 6 deletions(-) diff --git a/drivers/misc/rpmsgdev.c b/drivers/misc/rpmsgdev.c index 294f1a3f07..94cefe8c9c 100644 --- a/drivers/misc/rpmsgdev.c +++ b/drivers/misc/rpmsgdev.c @@ -56,7 +56,8 @@ struct rpmsgdev_priv_s { - uint64_t filep; /* store server file pointer */ + uint64_t filep; /* store server file pointer */ + bool nonblock; /* true: open with O_NONBLOCK */ }; struct rpmsgdev_s @@ -87,6 +88,8 @@ struct rpmsgdev_cookie_s static int rpmsgdev_open(FAR struct file *filep); static int rpmsgdev_close(FAR struct file *filep); +static void rpmsgdev_wait_cb(FAR struct pollfd *fds); +static int rpmsgdev_wait(FAR struct file *filep, pollevent_t events); static ssize_t rpmsgdev_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static ssize_t rpmsgdev_write(FAR struct file *filep, FAR const char *buffer, @@ -210,9 +213,12 @@ static int rpmsgdev_open(FAR struct file *filep) return -ENOMEM; } - /* Try to open the device in the remote cpu */ + /* Try to open the device in the remote cpu, open with O_NONBLOCK + * by default to avoid the server rptun thread blocked in read/write + * operations. + */ - msg.flags = filep->f_oflags; + msg.flags = filep->f_oflags | O_NONBLOCK; ret = rpmsgdev_send_recv(dev, RPMSGDEV_OPEN, true, &msg.header, sizeof(msg), NULL); if (ret < 0) @@ -222,7 +228,8 @@ static int rpmsgdev_open(FAR struct file *filep) return ret; } - priv->filep = msg.filep; + priv->filep = msg.filep; + priv->nonblock = (filep->f_oflags & O_NONBLOCK) != 0; /* Attach the private date to the struct file instance */ @@ -279,6 +286,89 @@ static int rpmsgdev_close(FAR struct file *filep) return ret; } +/**************************************************************************** + * Name: rpmsgdev_wait_cb + * + * Description: + * Rpmsg-device read/write operation wait callback function + * + * Parameters: + * fds - The structure describing the events to be monitored. + * + * Returned Values: + * None + * + ****************************************************************************/ + +static void rpmsgdev_wait_cb(FAR struct pollfd *fds) +{ + int semcount = 0; + FAR sem_t *pollsem = (FAR sem_t *)fds->arg; + + nxsem_get_value(pollsem, &semcount); + if (semcount < 1) + { + nxsem_post(pollsem); + } +} + +/**************************************************************************** + * Name: rpmsgdev_wait + * + * Description: + * Rpmsg-device read/write operation wait function, this function will be + * called in the rpmsgdev_read()/rpmsgdev_write() when the open flags is + * not NONBLOCKED to avoid the server rptun thread blocked in file_read() + * or file_write(). By calling this function before sending the READ or + * WRITE command to server, a simulated blocked read/write operation is + * achived. + * + * Parameters: + * filep - the file instance + * events - the events to be monitored + * + * Returned Values: + * OK on success; A negated errno value is returned on any failure. + * + ****************************************************************************/ + +static int rpmsgdev_wait(FAR struct file *filep, pollevent_t events) +{ + int ret; + sem_t sem; + struct pollfd fds; + + nxsem_init(&sem, 0, 0); + + fds.events = events; + fds.arg = &sem; + fds.cb = rpmsgdev_wait_cb; + events |= POLLERR | POLLHUP; + + while (1) + { + ret = rpmsgdev_poll(filep, &fds, true); + if (ret < 0) + { + return ret; + } + + ret = nxsem_wait(&sem); + rpmsgdev_poll(filep, &fds, false); + if (ret < 0) + { + return ret; + } + + if ((fds.revents & events) != 0) + { + break; + } + } + + return ret; +} + /**************************************************************************** * Name: rpmsgdev_read * @@ -320,6 +410,20 @@ static ssize_t rpmsgdev_read(FAR struct file *filep, FAR char *buffer, priv = filep->f_priv; DEBUGASSERT(dev != NULL && priv != NULL); + /* If the open flags is not nonblock, should poll the device for + * read ready first to avoid the server rptun thread blocked in + * device read operation. + */ + + if (priv->nonblock == false) + { + ret = rpmsgdev_wait(filep, POLLIN); + if (ret < 0) + { + return ret; + } + } + /* Call the host to perform the read */ read.iov_base = buffer; @@ -377,6 +481,20 @@ static ssize_t rpmsgdev_write(FAR struct file *filep, const char *buffer, priv = filep->f_priv; DEBUGASSERT(dev != NULL && priv != NULL); + /* If the open flags is not nonblock, should poll the device for + * write ready first to avoid the server rptun thread blocked in + * device write operation. + */ + + if (priv->nonblock == false) + { + ret = rpmsgdev_wait(filep, POLLOUT); + if (ret < 0) + { + return ret; + } + } + /* Perform the rpmsg write */ memset(&cookie, 0, sizeof(cookie)); @@ -532,6 +650,7 @@ static int rpmsgdev_ioctl(FAR struct file *filep, int cmd, unsigned long arg) uint32_t space; size_t arglen; size_t msglen; + int ret; /* Sanity checks */ @@ -564,8 +683,15 @@ static int rpmsgdev_ioctl(FAR struct file *filep, int cmd, unsigned long arg) memcpy(msg->buf, (FAR void *)(uintptr_t)arg, arglen); } - return rpmsgdev_send_recv(dev, RPMSGDEV_IOCTL, false, &msg->header, - msglen, arglen > 0 ? (FAR void *)arg : NULL); + ret = rpmsgdev_send_recv(dev, RPMSGDEV_IOCTL, false, &msg->header, + msglen, arglen > 0 ? (FAR void *)arg : NULL); + if (cmd == FIONBIO && ret >= 0) + { + int *nonblock = (FAR int *)(uintptr_t)arg; + priv->nonblock = *nonblock; + } + + return ret; } /****************************************************************************