Repository navigation
Commit 46a1c1a
committed
Fix pager hangs and a startup race in terminal pipelines
Three bugs in the terminal-pipeline job control, found in review and
reproduced on a pseudo-terminal with real less:
1. Output written straight to the pipe's descriptor hung the pager.
cmd2 lent the pager the terminal only during its own writes through
PipelineWriter. A subprocess given self.stdout (for example
subprocess.run(..., stdout=self.stdout) in a custom command, or a `!`
command run by `run_script s.txt | less`) writes to the descriptor
itself, so no lend happened. Once the pipe filled, less stopped with
SIGTTIN reading the keyboard, the watcher waited for a lend that never
came, and the producer blocked on the full pipe forever. On main these
cases worked, because the pager ran in its own session.
PipelineWriter.fileno() now hands out the write end of a relay pipe.
A thread passes that output on to the consumer and lends it the
terminal while a producer is blocked on the relay's full pipe, which
is the only time the consumer needs the terminal to make progress.
Once no producer is waiting, command code gets the terminal back, as
between cmd2's own writes, so a later input() still works. cmd2's own
writes first wait for pending relay output, which keeps output in
order. When the consumer exits, the relay closes its pipe, so
producers still get EPIPE or SIGPIPE.
2. A pipe nested in a piped command took the terminal from the outer
pager.
A pipeline counted as the terminal's job when either its stdout or its
stderr was the foreground terminal. In `run_script s.txt | less` with
`big | cat` in the script, the inner pipeline's stdout is the outer
pipe, but its stderr is the terminal. It became a terminal job and its
lends went to cat's group, so less was never lent the terminal, and
the command hung as in (1).
Only a pipeline whose stdout is the foreground terminal is now the
terminal's job. Others, including nested pipelines and pipelines whose
stdout cmd2 captures, run in their own session, as on main.
3. The pager could start before it owned the terminal.
The consumer could run between Popen() and cmd2's first terminal
lend. A pager such as less sets its terminal modes as it starts, and a
background tcsetattr() stops it with SIGTTOU. On macOS the call then
fails with EINTR once the process continues, and less carries on with
a cooked terminal, so q needs Enter and keys are echoed. This was
reproduced by delaying cmd2 after it starts the pipeline.
A terminal pipeline now starts as
`/bin/sh -c 'read -r _ || exit 1; exec "$SHELL" -c <command>'`. cmd2
sends a single newline down the consumer's stdin pipe only after
making the pipeline's group the foreground one. From a pipe, the read
builtin takes no more than that line, so no extra descriptor is needed.
That matters because dash, /bin/sh on Debian and Ubuntu, cannot
redirect descriptors above 9. Checked with sh, bash, dash and zsh.
If cmd2 fails before sending the newline, it closes the pipe, and the
held pipeline reads EOF and exits rather than waiting forever.
Tests:
- A PTY test covering the three hang cases in (1) and (2): a subprocess
writer, a script's shell command, and a nested pipe. It fails without
this change.
- The pager-startup PTY test gains a variant that delays cmd2 after it
starts the pipeline, which fails without this change.
- Unit tests for the relay: lending only while a producer waits, giving
the terminal back whether or not output is pending, ordering with
cmd2's own writes, and passing the consumer's exit on to producers.1 parent f4c1d67 commit 46a1c1a
5 files changed
Lines changed: 421 additions & 20 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
10 | | - | |
| 9 | + | |
| 10 | + | |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3346 | 3346 | | |
3347 | 3347 | | |
3348 | 3348 | | |
| 3349 | + | |
3349 | 3350 | | |
3350 | | - | |
3351 | | - | |
3352 | | - | |
3353 | | - | |
3354 | | - | |
3355 | | - | |
3356 | | - | |
3357 | | - | |
3358 | | - | |
| 3351 | + | |
| 3352 | + | |
| 3353 | + | |
| 3354 | + | |
| 3355 | + | |
| 3356 | + | |
| 3357 | + | |
| 3358 | + | |
| 3359 | + | |
3359 | 3360 | | |
3360 | 3361 | | |
3361 | 3362 | | |
3362 | 3363 | | |
3363 | 3364 | | |
3364 | | - | |
| 3365 | + | |
| 3366 | + | |
| 3367 | + | |
| 3368 | + | |
| 3369 | + | |
| 3370 | + | |
| 3371 | + | |
| 3372 | + | |
| 3373 | + | |
| 3374 | + | |
| 3375 | + | |
| 3376 | + | |
| 3377 | + | |
| 3378 | + | |
| 3379 | + | |
| 3380 | + | |
| 3381 | + | |
| 3382 | + | |
3365 | 3383 | | |
3366 | 3384 | | |
3367 | 3385 | | |
| |||
3372 | 3390 | | |
3373 | 3391 | | |
3374 | 3392 | | |
3375 | | - | |
| 3393 | + | |
3376 | 3394 | | |
3377 | 3395 | | |
3378 | 3396 | | |
| |||
3394 | 3412 | | |
3395 | 3413 | | |
3396 | 3414 | | |
3397 | | - | |
3398 | | - | |
3399 | | - | |
3400 | | - | |
3401 | | - | |
| 3415 | + | |
3402 | 3416 | | |
| 3417 | + | |
| 3418 | + | |
| 3419 | + | |
3403 | 3420 | | |
3404 | 3421 | | |
3405 | 3422 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
921 | 921 | | |
922 | 922 | | |
923 | 923 | | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
| 930 | + | |
| 931 | + | |
| 932 | + | |
| 933 | + | |
| 934 | + | |
| 935 | + | |
| 936 | + | |
| 937 | + | |
| 938 | + | |
| 939 | + | |
| 940 | + | |
| 941 | + | |
| 942 | + | |
| 943 | + | |
| 944 | + | |
| 945 | + | |
| 946 | + | |
| 947 | + | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
| 953 | + | |
| 954 | + | |
| 955 | + | |
| 956 | + | |
| 957 | + | |
| 958 | + | |
| 959 | + | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
| 1014 | + | |
| 1015 | + | |
| 1016 | + | |
| 1017 | + | |
| 1018 | + | |
| 1019 | + | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
924 | 1047 | | |
925 | 1048 | | |
926 | 1049 | | |
927 | 1050 | | |
928 | 1051 | | |
929 | 1052 | | |
930 | 1053 | | |
| 1054 | + | |
| 1055 | + | |
| 1056 | + | |
| 1057 | + | |
| 1058 | + | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + | |
| 1075 | + | |
931 | 1076 | | |
932 | 1077 | | |
933 | 1078 | | |
| |||
947 | 1092 | | |
948 | 1093 | | |
949 | 1094 | | |
950 | | - | |
| 1095 | + | |
951 | 1096 | | |
952 | 1097 | | |
953 | 1098 | | |
954 | 1099 | | |
| 1100 | + | |
| 1101 | + | |
955 | 1102 | | |
956 | 1103 | | |
957 | 1104 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
461 | 461 | | |
462 | 462 | | |
463 | 463 | | |
464 | | - | |
| 464 | + | |
| 465 | + | |
465 | 466 | | |
466 | 467 | | |
467 | 468 | | |
468 | 469 | | |
469 | 470 | | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
470 | 474 | | |
471 | 475 | | |
472 | 476 | | |
| |||
511 | 515 | | |
512 | 516 | | |
513 | 517 | | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
514 | 525 | | |
515 | 526 | | |
516 | 527 | | |
| |||
731 | 742 | | |
732 | 743 | | |
733 | 744 | | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
0 commit comments