Skip to content

Commit 24de78c

Browse files
committed
UART PTY: Add exit wait on readers
When set, --uartX_pty_wait_for_readers will wait for all available bytes to be read from the slave PTY before exiting. This prevents truncating the UART output. Signed-off-by: Scott Shawcroft <scott@tannewt.org>
1 parent 26ed181 commit 24de78c

1 file changed

Lines changed: 56 additions & 6 deletions

File tree

src/HW_models/NHW_UART_backend_pty.c

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
*/
2323

2424
#include <unistd.h>
25+
#include <stdlib.h>
26+
#include <fcntl.h>
27+
#include <time.h>
28+
#include <sys/ioctl.h>
29+
30+
int tcdrain(int fd);
31+
2532
#include "bs_types.h"
2633
#include "bs_tracing.h"
2734
#include "bs_oswrap.h"
@@ -47,6 +54,7 @@ struct upty_st_t {
4754
bool auto_attach;
4855
char *attach_cmd;
4956
bool respect_RTS;
57+
bool wait_for_readers;
5058

5159
int out_fd; /* File descriptor used for output */
5260
int in_fd; /* File descriptor used for input */
@@ -206,18 +214,51 @@ static void nhw_upty_timer_triggered(void) {
206214

207215
NSI_HW_EVENT(Timer_UPTY, nhw_upty_timer_triggered, 900); /* Let's let as many timers as possible evaluate before this one */
208216

217+
static void nhw_upty_wait_for_fionread_empty(int fd) {
218+
int bytes_left = 0;
219+
const struct timespec sleep_time = { .tv_sec = 0, .tv_nsec = 1000000 }; // 1ms
220+
221+
while (1) {
222+
if (ioctl(fd, FIONREAD, &bytes_left) != 0) {
223+
return;
224+
}
225+
226+
if (bytes_left == 0) {
227+
return;
228+
}
229+
230+
(void)nanosleep(&sleep_time, NULL);
231+
}
232+
}
233+
209234
static void nhw_upty_cleanup(void) {
210235
for (int i = 0; i < NHW_UARTE_TOTAL_INST; i++) {
211236
struct upty_st_t *u_el = &upty_st[i];
212237

213-
if (u_el->in_fd != -1) {
214-
close(u_el->in_fd);
215-
u_el->in_fd = -1;
216-
}
217238
if (u_el->out_fd != -1) {
239+
if (u_el->wait_for_readers) {
240+
(void)tcdrain(u_el->out_fd);
241+
242+
char *slave_name = ptsname(u_el->out_fd);
243+
if (slave_name != NULL) {
244+
int slave_fd = open(slave_name, O_RDWR | O_NOCTTY);
245+
if (slave_fd != -1) {
246+
nhw_upty_wait_for_fionread_empty(slave_fd);
247+
close(slave_fd);
248+
}
249+
}
250+
}
251+
218252
close(u_el->out_fd);
253+
if (u_el->in_fd == u_el->out_fd) {
254+
u_el->in_fd = -1;
255+
}
219256
u_el->out_fd = -1;
220257
}
258+
if (u_el->in_fd != -1) {
259+
close(u_el->in_fd);
260+
u_el->in_fd = -1;
261+
}
221262
}
222263
}
223264

@@ -234,15 +275,17 @@ static void parse_poll_period(char *argv, int offset) {
234275
}
235276

236277
static void nhw_upty_backend_register_cmdline(void) {
237-
#define OPT_PER_UART 4
278+
#define OPT_PER_UART 5
238279
static bs_args_struct_t args[OPT_PER_UART*NHW_UARTE_TOTAL_INST + 1 /* End marker */];
239280
static char descr_connect[] = "Connect this UART to a pseudoterminal";
240281
static char descr_auto[] = "Automatically attach to the UART terminal (implies uartx_pty)";
241282
static char descr_cmd[] = "Command used to automatically attach to the terminal (implies "
242283
"uartx_pty_attach), by default: '" DEFAULT_CMD "'";
243284
static char descr_ignoreRTS[] = "Hold feeding data from the PTY if RTS is high (note: "
244285
"If HW flow control is disabled the UART never lowers RTS)";
245-
#define OPTION_LEN (4 + 2 + 15 + 1)
286+
static char descr_wait_readers[] = "At exit, wait for this UART's PTY slave FIONREAD counter "
287+
"to reach 0 before closing";
288+
#define OPTION_LEN (4 + 2 + 21 + 1)
246289
static char options[NHW_UARTE_TOTAL_INST][OPT_PER_UART][OPTION_LEN];
247290
static char opt_cmd[]= "cmd";
248291

@@ -251,6 +294,7 @@ static void nhw_upty_backend_register_cmdline(void) {
251294
snprintf(options[i][1], OPTION_LEN, "uart%i_pty_attach", i);
252295
snprintf(options[i][2], OPTION_LEN, "uart%i_pty_attach_cmd", i);
253296
snprintf(options[i][3], OPTION_LEN, "uart%i_pty_respect_RTS", i);
297+
snprintf(options[i][4], OPTION_LEN, "uart%i_pty_wait_for_readers", i);
254298

255299
args[OPT_PER_UART*i].option = options[i][0];
256300
args[OPT_PER_UART*i].is_switch = true;
@@ -275,6 +319,12 @@ static void nhw_upty_backend_register_cmdline(void) {
275319
args[OPT_PER_UART*i + 3].type = 'b';
276320
args[OPT_PER_UART*i + 3].dest = &upty_st[i].respect_RTS;
277321
args[OPT_PER_UART*i + 3].descript = descr_ignoreRTS;
322+
323+
args[OPT_PER_UART*i + 4].option = options[i][4];
324+
args[OPT_PER_UART*i + 4].is_switch = true;
325+
args[OPT_PER_UART*i + 4].type = 'b';
326+
args[OPT_PER_UART*i + 4].dest = &upty_st[i].wait_for_readers;
327+
args[OPT_PER_UART*i + 4].descript = descr_wait_readers;
278328
}
279329

280330
bs_add_extra_dynargs(args);

0 commit comments

Comments
 (0)