drivers/serial/pty.c: Add support so that a PTY can poll for both IN/OUT event simultaneously.

This commit is contained in:
Gregory Nutt 2018-08-26 07:27:19 -06:00
parent 38cd556af8
commit 729a65f3ab
2 changed files with 84 additions and 17 deletions

View File

@ -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 <gnutt@nuttx.org>
*
* 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;
}

View File

@ -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 <gnutt@nuttx.org>
*
* 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