Bug #12470
raw mode should default to minimum reads of just one byte
0%
Description
From the termio(7I) page:
Non-canonical Mode Input Processing In non-canonical mode input processing, input characters are not assembled into lines, and erase and kill processing does not occur. The MIN and TIME values are used to determine how to process the characters received. MIN represents the minimum number of characters that should be received when the read is satisfied (that is, when the characters are returned to the user). TIME is a timer of 0.10-second granularity that is used to timeout bursty and short-term data transmissions. The four possible values for MIN and TIME and their interactions are described below.
Non-canonical Mode, often colloquially referred to as raw mode, allows the application to directly read bytes from the tty without being chunked into lines by the kernel. Our default values for these parameters are MIN
of 4 and TIME
of 0, which puts us in Case B as described in the page:
Case B: MIN > 0, TIME = 0 In this case, since the value of TIME is zero, the timer plays no role and only MIN is significant. A pending read is not satisfied until MIN characters are received (the pending read sleeps until MIN characters are received). A program that uses this case to read record based terminal I/O may block indefinitely in the read operation.
Essentially, a blocking read will block and wait for 4 input characters to be available before returning. If 4 input characters do not emerge, the read will block forever.
Other platforms, such as FreeBSD and Linux, appear to default to a MIN
value of just 1 byte. Many applications in the wild expect this behaviour, and thus do not work correctly without patches on illumos.
Our default value appears to be specified in /kernel/drv/options.conf
in the ttymodes
property:
# # The property "ttymodes" defines the default termios modes # (upon driver open) for ttys. # # ttymodes=<string> # # The format of <string> is the same format as the output of # the "-g" option to /usr/bin/stty. Some standard termios modes # have been included for reference: # # For SVID compliance, use these modes, # "522:1805:4b7:2b:7f:1c:23:40:4:0:0:0:11:13:1a:19:12:f:17:16" # # For SunOS 4.x defaults (7-bit/evenp/istrip), use these modes, # "2522:1805:1ad:8a3b:3:1c:7f:15:4:0:0:0:11:13:1a:19:12:f:17:16" # # For SunOS 4.x defaults that are 8-bit clean for # internationalization, use these modes, # "2502:1805:bd:8a3b:3:1c:7f:15:4:0:0:0:11:13:1a:19:12:f:17:16" # name="options" class="root" ttymodes="2502:1805:bd:8a3b:3:1c:7f:15:4:0:0:0:11:13:1a:19:12:f:17:16:14:8";
Note that these raw byte values are unpacked into the default struct termios
, so:
ttymodes="2502:1805:bd:8a3b:3:1c:7f:15:4:0:0:0:11:13:1a:19:12:f:17:16:14:8"; ^ ^ | `--- TIME `----- MIN
While this change is, on some level, breaking, I suspect it's unlikely to have any lasting impact beyond merely sanding down another bump of differing expectations with other platforms. Critically, any correct application must always allow for any number of bytes to be returned, regardless of our default read coalescing size here.
Related issues
Updated by Joshua M. Clulow 10 months ago
This turns out to be more complicated than I had initially anticipated, due to what appears to have been an extremely poor decision to save two bytes in a structure:
The MIN values is stored in the VMIN element of the c_cc array; the TIME value is stored in the VTIME element of the c_cc array. The VMIN element is the same element as the VEOF element; the VTIME element is the same element as the VEOL element.
This appears to be the real reason that MIN defaults to a value of 4: that's the value of the ASCII EOT character, which people often associate with ^D.
These offsets (and their ridiculous overlap) appear to form a part of our ABI. If we were to change the offsets in the headers, we'd effectively need some way to version the structure; e.g., using a bit in c_lflag
. It would seem difficult to cover all bases here, given a struct termios
can come from either a raw ioctl(TCGETS)
or the tcgetattr()
wrapper.
Sigh.
Updated by Joshua M. Clulow 10 months ago
- Related to Feature #1060: termios missing cfmakeraw added