Skip to content

Commit 95063bd

Browse files
xiaoxiang781216acassis
authored andcommitted
drivers/serial: add job-control TTY ioctls and libc wrappers
NuttX has no real session/process-group abstraction, so the TTY layer collapses the foreground process group onto the single dev->pid field (pgrp == pid, one member per group). Extend the controlling-terminal support so portable software (e.g. dropbear, socat) that relies on job-control primitives works without losing the existing NuttX-specific behaviour. Driver (serial.c, pty.c): - TIOCSCTTY now accepts a flag: arg > 0 keeps the historical "target PID in arg" semantics (NSH registers the foreground command it just spawned), while arg == 0 selects the calling task via nxsched_getpid(), matching the POSIX flag convention used by dropbear/socat/apue. This preserves all existing callers and makes the previously-dead arg==0 path deliver SIGINT correctly. - Add TIOCGPGRP/TIOCGSID (return dev->pid) and TIOCSPGRP (set it). - pty.c gains the same handlers against pd_pid and includes nuttx/sched.h for nxsched_getpid(). ioctl numbers (tioctl.h): TIOCGPGRP/TIOCSPGRP/TIOCGSID at 0x37-0x39. libc wrappers: - termios: tcgetpgrp(), tcsetpgrp(), tcgetsid() over the new ioctls. - unistd: setsid()/getsid()/setpgid() stubs consistent with the existing getpgrp()/getpgid() single-session model (sid == pgid == pid; setpgid only succeeds for pgid == pid). Declare the new prototypes in unistd.h (tcgetsid was already in termios.h) and register all sources in the Make.defs/CMakeLists. Group-broadcast signalling (kill(-pgrp)) remains unsupported, so tty signals still target the single dev->pid; a real session/process group model is left as a follow-up. Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
1 parent 970f2f2 commit 95063bd

16 files changed

Lines changed: 523 additions & 9 deletions

File tree

Documentation/components/drivers/character/serial.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,34 @@ Serial Device Drivers
3535
Also, you can customize:
3636
``TTY_LAUNCH_ARGS`` ``TTY_LAUNCH_PRIORITY`` ``TTY_LAUNCH_STACKSIZE``
3737

38+
- **Job control / controlling terminal**. When ``CONFIG_TTY_SIGINT``
39+
or ``CONFIG_TTY_SIGTSTP`` is enabled, the TTY layer can generate
40+
``SIGINT`` (Ctrl-C) and ``SIGTSTP`` (Ctrl-Z) for a foreground task.
41+
NuttX does not implement POSIX sessions or process groups, so the
42+
foreground process group is collapsed onto a single PID stored in
43+
the driver (``pgrp == pid``, one member per group); the signal is
44+
delivered with ``nxsig_kill(pid, signo)``.
45+
46+
The following terminal ``ioctl`` commands manage this PID:
47+
48+
- ``TIOCSCTTY`` makes the terminal the controlling terminal. The
49+
``arg`` is treated as a flag: a value of ``0`` selects the
50+
calling task (the POSIX convention used by, e.g., dropbear and
51+
socat), while a positive value is honored as the target PID (the
52+
NuttX convention used by NSH to register a foreground command it
53+
has just spawned).
54+
- ``TIOCNOTTY`` gives up the controlling terminal.
55+
- ``TIOCGPGRP`` / ``TIOCGSID`` return the foreground process group /
56+
session leader PID.
57+
- ``TIOCSPGRP`` sets the foreground process group PID (a value of
58+
``0`` selects the calling task).
59+
60+
The C library exposes these through ``tcgetpgrp()``, ``tcsetpgrp()``,
61+
``tcgetsid()``, ``setsid()``, ``getsid()`` and ``setpgid()``. Because
62+
sending a signal to a process group (``kill(-pgrp, signo)``) is not
63+
supported, TTY signals always target the single foreground PID rather
64+
than an entire group.
65+
3866
- **User Access**. Serial drivers are, ultimately, normal
3967
`character drivers <#chardrivers>`__ and are accessed as other
4068
character drivers.

drivers/serial/pty.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include <nuttx/ascii.h>
4444
#include <nuttx/kmalloc.h>
4545
#include <nuttx/mutex.h>
46+
#include <nuttx/sched.h>
4647
#include <nuttx/semaphore.h>
4748
#include <nuttx/fs/fs.h>
4849
#include <nuttx/serial/pty.h>
@@ -838,16 +839,21 @@ static int pty_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
838839
/* Make the controlling terminal of the calling process */
839840

840841
case TIOCSCTTY:
842+
case TIOCSPGRP:
841843
{
842-
/* Save the PID of the recipient of the SIGINT signal. */
844+
/* Save the PID of the foreground process group that is to receive
845+
* tty-generated signals. A zero 'arg' selects the calling task
846+
* (POSIX flag semantics); a positive 'arg' is honored as the
847+
* target PID (NuttX historical semantics).
848+
*/
843849

844-
if ((int)arg < 0 || dev->pd_pid >= 0)
850+
if ((int)arg < 0)
845851
{
846852
ret = -EINVAL;
847853
}
848854
else
849855
{
850-
dev->pd_pid = (pid_t)arg;
856+
dev->pd_pid = arg > 0 ? (pid_t)arg : nxsched_getpid();
851857
ret = 0;
852858
}
853859
}
@@ -859,6 +865,23 @@ static int pty_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
859865
ret = 0;
860866
}
861867
break;
868+
869+
/* Get the foreground process group / session leader. pgrp == pid. */
870+
871+
case TIOCGPGRP:
872+
case TIOCGSID:
873+
{
874+
if (dev->pd_pid < 0)
875+
{
876+
ret = -ENOTTY;
877+
}
878+
else
879+
{
880+
*(FAR pid_t *)((uintptr_t)arg) = dev->pd_pid;
881+
ret = 0;
882+
}
883+
}
884+
break;
862885
#endif
863886

864887
/* Any unrecognized IOCTL commands will be passed to the contained

drivers/serial/serial.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1749,16 +1749,25 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
17491749
/* Make the controlling terminal of the calling process */
17501750

17511751
case TIOCSCTTY:
1752+
case TIOCSPGRP:
17521753
{
1753-
/* Save the PID of the recipient of the SIGINT signal. */
1754+
/* Save the PID of the foreground process group that is to
1755+
* receive tty-generated signals (SIGINT/SIGTSTP).
1756+
*
1757+
* POSIX passes a flag in 'arg' and uses the caller's PID, so
1758+
* a zero 'arg' selects the calling task. NuttX historically
1759+
* passes the target PID directly in 'arg' (e.g. NSH registers
1760+
* the foreground command it just spawned), so a positive
1761+
* 'arg' is honored as the target PID.
1762+
*/
17541763

1755-
if ((int)arg < 0 || dev->pid >= 0)
1764+
if ((int)arg < 0)
17561765
{
17571766
ret = -EINVAL;
17581767
}
17591768
else
17601769
{
1761-
dev->pid = (pid_t)arg;
1770+
dev->pid = arg > 0 ? (pid_t)arg : nxsched_getpid();
17621771
ret = 0;
17631772
}
17641773
}
@@ -1770,6 +1779,26 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
17701779
ret = 0;
17711780
}
17721781
break;
1782+
1783+
/* Get the foreground process group. Since NuttX has no real
1784+
* process-group abstraction, the controlling task's PID doubles
1785+
* as the (single-member) foreground process group.
1786+
*/
1787+
1788+
case TIOCGPGRP:
1789+
case TIOCGSID:
1790+
{
1791+
if (dev->pid < 0)
1792+
{
1793+
ret = -ENOTTY;
1794+
}
1795+
else
1796+
{
1797+
*(FAR pid_t *)((uintptr_t)arg) = dev->pid;
1798+
ret = 0;
1799+
}
1800+
}
1801+
break;
17731802
#endif
17741803
}
17751804
}

include/nuttx/serial/serial.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,10 @@ struct uart_dev_s
335335

336336
#if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP) || \
337337
defined(CONFIG_TTY_FORCE_PANIC) || defined(CONFIG_TTY_LAUNCH)
338-
pid_t pid; /* Thread PID to receive signals (-1 if none) */
338+
pid_t pid; /* Foreground process group / controlling-tty
339+
* owner that receives tty signals. With no
340+
* process-group support, pgrp == pid.
341+
* (-1 if none) */
339342
#endif
340343

341344
#ifdef CONFIG_TTY_FORCE_PANIC

include/nuttx/serial/tioctl.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787

8888
/* Controlling TTY */
8989

90-
#define TIOCSCTTY _TIOC(0x0018) /* Make controlling TTY: int */
90+
#define TIOCSCTTY _TIOC(0x0018) /* Make controlling TTY: int (0 == caller) */
9191
#define TIOCNOTTY _TIOC(0x0019) /* Give up controllinog TTY: void */
9292

9393
/* Exclusive mode */
@@ -200,6 +200,12 @@
200200

201201
#define SER_SWAP_ENABLED (1 << 0) /* Enable/disable RX/TX swap */
202202

203+
/* Process group / session (job control) */
204+
205+
#define TIOCGPGRP _TIOC(0x0037) /* Get foreground process group: FAR pid_t* */
206+
#define TIOCSPGRP _TIOC(0x0038) /* Set foreground process group: FAR const pid_t* */
207+
#define TIOCGSID _TIOC(0x0039) /* Get session leader: FAR pid_t* */
208+
203209
/****************************************************************************
204210
* Public Type Definitions
205211
****************************************************************************/

include/unistd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,11 @@ pid_t getpgid(pid_t pid);
354354
pid_t getpgrp(void);
355355
pid_t gettid(void);
356356
pid_t getppid(void);
357+
pid_t getsid(pid_t pid);
358+
int setpgid(pid_t pid, pid_t pgid);
359+
pid_t setsid(void);
360+
pid_t tcgetpgrp(int fd);
361+
int tcsetpgrp(int fd, pid_t pgrp);
357362
void _exit(int status) noreturn_function;
358363
unsigned int sleep(unsigned int seconds);
359364
int usleep(useconds_t usec);

libs/libc/termios/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,7 @@ target_sources(
3232
lib_tcsetattr.c
3333
lib_tcsendbreak.c
3434
lib_ttyname.c
35-
lib_ttynamer.c)
35+
lib_ttynamer.c
36+
lib_tcgetpgrp.c
37+
lib_tcsetpgrp.c
38+
lib_tcgetsid.c)

libs/libc/termios/Make.defs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
CSRCS += lib_cfspeed.c lib_cfmakeraw.c lib_isatty.c lib_tcflush.c
2626
CSRCS += lib_tcdrain.c lib_tcflow.c lib_tcgetattr.c lib_tcsetattr.c
2727
CSRCS += lib_tcsendbreak.c lib_ttyname.c lib_ttynamer.c
28+
CSRCS += lib_tcgetpgrp.c lib_tcsetpgrp.c lib_tcgetsid.c
2829

2930
# Add the termios directory to the build
3031

libs/libc/termios/lib_tcgetpgrp.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/****************************************************************************
2+
* libs/libc/termios/lib_tcgetpgrp.c
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Licensed to the Apache Software Foundation (ASF) under one or more
7+
* contributor license agreements. See the NOTICE file distributed with
8+
* this work for additional information regarding copyright ownership. The
9+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
10+
* "License"); you may not use this file except in compliance with the
11+
* License. You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18+
* License for the specific language governing permissions and limitations
19+
* under the License.
20+
*
21+
****************************************************************************/
22+
23+
/****************************************************************************
24+
* Included Files
25+
****************************************************************************/
26+
27+
#include <nuttx/config.h>
28+
29+
#include <sys/ioctl.h>
30+
31+
#include <unistd.h>
32+
33+
#include <nuttx/serial/tioctl.h>
34+
35+
/****************************************************************************
36+
* Public Functions
37+
****************************************************************************/
38+
39+
/****************************************************************************
40+
* Name: tcgetpgrp
41+
*
42+
* Description:
43+
* Return the value of the process group ID of the foreground process
44+
* group associated with the terminal.
45+
*
46+
* Input Parameters:
47+
* fd - The 'fd' argument is an open file descriptor associated with a
48+
* terminal.
49+
*
50+
* Returned Value:
51+
* Upon successful completion, the process group ID of the foreground
52+
* process group is returned. Otherwise, (pid_t)-1 is returned and errno
53+
* is set to indicate the error.
54+
*
55+
****************************************************************************/
56+
57+
pid_t tcgetpgrp(int fd)
58+
{
59+
pid_t pgrp;
60+
61+
if (ioctl(fd, TIOCGPGRP, &pgrp) < 0)
62+
{
63+
return (pid_t)-1;
64+
}
65+
66+
return pgrp;
67+
}

libs/libc/termios/lib_tcgetsid.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/****************************************************************************
2+
* libs/libc/termios/lib_tcgetsid.c
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Licensed to the Apache Software Foundation (ASF) under one or more
7+
* contributor license agreements. See the NOTICE file distributed with
8+
* this work for additional information regarding copyright ownership. The
9+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
10+
* "License"); you may not use this file except in compliance with the
11+
* License. You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18+
* License for the specific language governing permissions and limitations
19+
* under the License.
20+
*
21+
****************************************************************************/
22+
23+
/****************************************************************************
24+
* Included Files
25+
****************************************************************************/
26+
27+
#include <nuttx/config.h>
28+
29+
#include <sys/ioctl.h>
30+
31+
#include <termios.h>
32+
33+
#include <nuttx/serial/tioctl.h>
34+
35+
/****************************************************************************
36+
* Public Functions
37+
****************************************************************************/
38+
39+
/****************************************************************************
40+
* Name: tcgetsid
41+
*
42+
* Description:
43+
* Obtain the process group ID of the session for which the terminal is
44+
* the controlling terminal.
45+
*
46+
* Input Parameters:
47+
* fd - The 'fd' argument is an open file descriptor associated with a
48+
* terminal.
49+
*
50+
* Returned Value:
51+
* Upon successful completion, the session leader's process group ID is
52+
* returned. Otherwise, (pid_t)-1 is returned and errno is set to
53+
* indicate the error.
54+
*
55+
****************************************************************************/
56+
57+
pid_t tcgetsid(int fd)
58+
{
59+
pid_t sid;
60+
61+
if (ioctl(fd, TIOCGSID, &sid) < 0)
62+
{
63+
return (pid_t)-1;
64+
}
65+
66+
return sid;
67+
}

0 commit comments

Comments
 (0)