serial/pty: Close the internal pipe when reference count drop to zero

so the other side can get the hang up notification

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
Xiang Xiao 2022-02-06 22:46:54 +08:00 committed by Xiang Xiao
parent 6166dd5833
commit 8e64db45c7
1 changed files with 65 additions and 63 deletions

View File

@ -149,14 +149,10 @@ struct pty_devpair_s
****************************************************************************/
static int pty_semtake(FAR struct pty_devpair_s *devpair);
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static void pty_destroy(FAR struct pty_devpair_s *devpair);
#endif
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static int pty_pipe(FAR struct pty_devpair_s *devpair);
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,
@ -174,13 +170,8 @@ static int pty_unlink(FAR struct inode *inode);
static const struct file_operations g_pty_fops =
{
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
pty_open, /* open */
pty_close, /* close */
#else
NULL, /* open */
NULL, /* close */
#endif
pty_read, /* read */
pty_write, /* write */
NULL, /* seek */
@ -214,7 +205,6 @@ static int pty_semtake(FAR struct pty_devpair_s *devpair)
* Name: pty_destroy
****************************************************************************/
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static void pty_destroy(FAR struct pty_devpair_s *devpair)
{
char devname[16];
@ -235,13 +225,6 @@ static void pty_destroy(FAR struct pty_devpair_s *devpair)
#endif
unregister_driver(devname);
/* Close the contained file structures */
file_close(&devpair->pp_master.pd_src);
file_close(&devpair->pp_master.pd_sink);
file_close(&devpair->pp_slave.pd_src);
file_close(&devpair->pp_slave.pd_sink);
#ifdef CONFIG_PSEUDOTERM_SUSV1
/* Free this minor number so that it can be reused */
@ -254,19 +237,55 @@ static void pty_destroy(FAR struct pty_devpair_s *devpair)
nxsem_destroy(&devpair->pp_slavesem);
kmm_free(devpair);
}
#endif
/****************************************************************************
* Name: pty_pipe
****************************************************************************/
static int pty_pipe(FAR struct pty_devpair_s *devpair)
{
FAR struct file *pipe_a[2];
FAR struct file *pipe_b[2];
int ret;
/* Create two pipes:
*
* pipe_a: Master source, slave sink (TX, slave-to-master)
* pipe_b: Master sink, slave source (RX, master-to-slave)
*/
pipe_a[0] = &devpair->pp_master.pd_src;
pipe_a[1] = &devpair->pp_slave.pd_sink;
ret = file_pipe(pipe_a, CONFIG_PSEUDOTERM_TXBUFSIZE, 0);
if (ret < 0)
{
return ret;
}
pipe_b[0] = &devpair->pp_slave.pd_src;
pipe_b[1] = &devpair->pp_master.pd_sink;
ret = file_pipe(pipe_b, CONFIG_PSEUDOTERM_RXBUFSIZE, 0);
if (ret < 0)
{
file_close(pipe_a[0]);
file_close(pipe_a[1]);
}
return ret;
}
/****************************************************************************
* Name: pty_open
****************************************************************************/
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static int pty_open(FAR struct file *filep)
{
FAR struct inode *inode;
FAR struct pty_dev_s *dev;
FAR struct pty_devpair_s *devpair;
int ret;
int ret = OK;
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
inode = filep->f_inode;
@ -337,24 +356,32 @@ static int pty_open(FAR struct file *filep)
else
#endif
{
/* First open? */
if (devpair->pp_nopen == 0)
{
/* Yes, create the internal pipe */
ret = pty_pipe(devpair);
}
/* Increment the count of open references on the driver */
devpair->pp_nopen++;
DEBUGASSERT(devpair->pp_nopen > 0);
ret = OK;
if (ret >= 0)
{
devpair->pp_nopen++;
DEBUGASSERT(devpair->pp_nopen > 0);
}
}
pty_semgive(devpair);
return ret;
}
#endif
/****************************************************************************
* Name: pty_open
****************************************************************************/
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static int pty_close(FAR struct file *filep)
{
FAR struct inode *inode;
@ -390,6 +417,16 @@ static int pty_close(FAR struct file *filep)
}
#endif
/* Check if the decremented inode reference count would go to zero */
if (inode->i_crefs == 1)
{
/* Close the contained file structures */
file_close(&dev->pd_src);
file_close(&dev->pd_sink);
}
/* Is this the last open reference? If so, was the driver previously
* unlinked?
*/
@ -412,7 +449,6 @@ static int pty_close(FAR struct file *filep)
pty_semgive(devpair);
return OK;
}
#endif
/****************************************************************************
* Name: pty_read
@ -1047,8 +1083,6 @@ static int pty_unlink(FAR struct inode *inode)
int pty_register(int minor)
{
FAR struct pty_devpair_s *devpair;
FAR struct file *pipe_a[2];
FAR struct file *pipe_b[2];
char devname[16];
int ret;
@ -1080,30 +1114,6 @@ int pty_register(int minor)
devpair->pp_slave.pd_devpair = devpair;
devpair->pp_slave.pd_oflag = OPOST | ONLCR;
/* Create two pipes:
*
* pipe_a: Master source, slave sink (TX, slave-to-master)
* pipe_b: Master sink, slave source (RX, master-to-slave)
*/
pipe_a[0] = &devpair->pp_master.pd_src;
pipe_a[1] = &devpair->pp_slave.pd_sink;
ret = file_pipe(pipe_a, CONFIG_PSEUDOTERM_TXBUFSIZE, 0);
if (ret < 0)
{
goto errout_with_devpair;
}
pipe_b[0] = &devpair->pp_slave.pd_src;
pipe_b[1] = &devpair->pp_master.pd_sink;
ret = file_pipe(pipe_b, CONFIG_PSEUDOTERM_RXBUFSIZE, 0);
if (ret < 0)
{
goto errout_with_pipea;
}
/* Register the master device
*
* BSD style (deprecated): /dev/ptyN
@ -1117,7 +1127,7 @@ int pty_register(int minor)
ret = register_driver(devname, &g_pty_fops, 0666, &devpair->pp_master);
if (ret < 0)
{
goto errout_with_pipeb;
goto errout_with_devpair;
}
/* Register the slave device
@ -1146,14 +1156,6 @@ errout_with_master:
snprintf(devname, 16, "/dev/pty%d", minor);
unregister_driver(devname);
errout_with_pipeb:
file_close(pipe_b[0]);
file_close(pipe_b[1]);
errout_with_pipea:
file_close(pipe_a[0]);
file_close(pipe_a[1]);
errout_with_devpair:
nxsem_destroy(&devpair->pp_exclsem);
nxsem_destroy(&devpair->pp_slavesem);