From 729a65f3ab53b900f699e16df7faae7d79d2465f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 26 Aug 2018 07:27:19 -0600 Subject: [PATCH] drivers/serial/pty.c: Add support so that a PTY can poll for both IN/OUT event simultaneously. --- drivers/pipes/pipe_common.c | 10 ++-- drivers/serial/pty.c | 91 +++++++++++++++++++++++++++++++------ 2 files changed, 84 insertions(+), 17 deletions(-) diff --git a/drivers/pipes/pipe_common.c b/drivers/pipes/pipe_common.c index bd5a1a1be5..610a3a1835 100644 --- a/drivers/pipes/pipe_common.c +++ b/drivers/pipes/pipe_common.c @@ -1,7 +1,8 @@ /**************************************************************************** * drivers/pipes/pipe_common.c * - * Copyright (C) 2008-2009, 2011, 2015-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2009, 2011, 2015-2016, 2018 Gregory Nutt. All + * rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -721,17 +722,18 @@ int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds, } /* Notify the POLLOUT event if the pipe is not full, but only if - * there is readers. */ + * there is readers. + */ eventset = 0; - if (nbytes < (dev->d_bufsize - 1)) + if ((filep->f_oflags & O_WROK) && (nbytes < (dev->d_bufsize - 1))) { eventset |= POLLOUT; } /* Notify the POLLIN event if the pipe is not empty */ - if (nbytes > 0) + if ((filep->f_oflags & O_RDOK) && (nbytes > 0)) { eventset |= POLLIN; } diff --git a/drivers/serial/pty.c b/drivers/serial/pty.c index a30e8935a7..35146994ab 100644 --- a/drivers/serial/pty.c +++ b/drivers/serial/pty.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/serial/pty.c * - * Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2016-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -112,10 +112,22 @@ #undef CONFIG_PSEUDOTERM_FULLBLOCKS +/* Maximum number of threads than can be waiting for POLL events */ + +#ifndef CONFIG_DEV_PTY_NPOLLWAITERS +# define CONFIG_DEV_PTY_NPOLLWAITERS 2 +#endif + /**************************************************************************** * Private Types ****************************************************************************/ +struct pty_poll_s +{ + FAR void *src; + FAR void *sink; +}; + /* This device structure describes on memory of the PTY device pair */ struct pty_devpair_s; @@ -132,6 +144,10 @@ struct pty_dev_s tcflag_t pd_iflag; /* Terminal nput modes */ tcflag_t pd_oflag; /* Terminal output modes */ #endif + +#ifndef CONFIG_DISABLE_POLL + struct pty_poll_s pd_poll[CONFIG_DEV_PTY_NPOLLWAITERS]; +#endif }; /* This structure describes the pipe pair */ @@ -160,8 +176,10 @@ static void pty_semtake(FAR struct pty_devpair_s *devpair); static void pty_destroy(FAR struct pty_devpair_s *devpair); #endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS static int pty_open(FAR struct file *filep); static int pty_close(FAR struct file *filep); +#endif static ssize_t pty_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static ssize_t pty_write(FAR struct file *filep, FAR const char *buffer, @@ -922,34 +940,81 @@ static int pty_poll(FAR struct file *filep, FAR struct pollfd *fds, { FAR struct inode *inode; FAR struct pty_dev_s *dev; + FAR struct pty_devpair_s *devpair; + FAR struct pty_poll_s *pollp = NULL; int ret = -ENOSYS; + int i; DEBUGASSERT(filep != NULL && filep->f_inode != NULL); inode = filep->f_inode; dev = inode->i_private; + devpair = dev->pd_devpair; - /* REVISIT: If both POLLIN and POLLOUT are set, might the following logic - * fail? Could we not get POLLIN on the sink file and POLLOUT on the source - * file? - */ + pty_semtake(devpair); + + if (setup) + { + for (i = 0; i < CONFIG_DEV_PTY_NPOLLWAITERS; i++) + { + if (dev->pd_poll[i].src == NULL && dev->pd_poll[i].sink == NULL) + { + pollp = &dev->pd_poll[i]; + break; + } + } + + if (i >= CONFIG_DEV_PTY_NPOLLWAITERS) + { + ret = -EBUSY; + goto errout; + } + } + else + { + pollp = (FAR struct pty_poll_s *)fds->priv; + } /* POLLIN: Data other than high-priority data may be read without blocking. */ if ((fds->events & POLLIN) != 0) { + fds->priv = pollp->src; ret = file_poll(&dev->pd_src, fds, setup); - } - - if (ret >= OK || ret == -ENOTTY) - { - /* POLLOUT: Normal data may be written without blocking. */ - - if ((fds->events & POLLOUT) != 0) + if (ret < 0) { - ret = file_poll(&dev->pd_sink, fds, setup); + goto errout; } + + pollp->src = fds->priv; } + /* POLLOUT: Normal data may be written without blocking. */ + + if ((fds->events & POLLOUT) != 0) + { + fds->priv = pollp->sink; + ret = file_poll(&dev->pd_sink, fds, setup); + if (ret < 0) + { + if (pollp->src) + { + fds->priv = pollp->src; + file_poll(&dev->pd_src, fds, false); + pollp->src = NULL; + } + + goto errout; + } + pollp->sink = fds->priv; + } + + if (setup) + { + fds->priv = pollp; + } + +errout: + pty_semgive(devpair); return ret; } #endif