Bug #12470

raw mode should default to minimum reads of just one byte

Added by Joshua M. Clulow 8 months ago. Updated 8 months ago.

Start date:
Due date:
% Done:


Estimated time:
Gerrit CR:


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" 

Note that these raw byte values are unpacked into the default struct termios, so:

                                       ^ ^
                                       | `--- 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

Related to illumos gate - Feature #1060: termios missing cfmakeraw In ProgressAndrew Stormont2011-05-23


Updated by Joshua M. Clulow 8 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.



Updated by Joshua M. Clulow 8 months ago

Also available in: Atom PDF