Purpose: determine why USE $P:PASTHRU doesn't put YDB into tty raw mode
YottaDB needs to tell the terminal system how to operate so regularly talks back and forth to it via two key calls:
tcsetattr()
tcgetattr()
Other calls are listed as part of the library, but they do not seem key to my investigation
int tcgetattr(int fd, struct termios* termios_p);
int tcsetattr(int fd, int optional_actions, const struct termios* termios_p);
int tcsendbreak(int fd, int duration);
int tcdrain(int fd);
int tcflush(int fd, int queue_selector);
int tcflow(int fd, int action);
void cfmakeraw(struct termios* termios_p);
speed_t cfgetispeed(const struct termios* termios_p);
speed_t cfgetospeed(const struct termios* termios_p);
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
int cfsetspeed(struct termios *termios_p, speed_t speed);
The key part of information passed into and out of the get/set attr calls is a pointer to struct termios
While debugging, if I dump out the termios record (stored in variable t), I see:
(gdb) print -pretty -- t
$9 = {
c_iflag = 1280,
c_oflag = 5,
c_cflag = 191
c_lflag = 35387,
c_line = 0 '\000'
c_cc = ....
c_ispeed = 15,
c_ospeed = 15
}
Each of these flag variables is a bit record, where each bit specifies a different tty setting
I did a search through all the source code for all instances of tcsetattr or tcgetattr (and Tcsetattr, Tcgetattr which is a wrapper macro)
Here are hits for tcgetattr
sr_unix/iott_open.c
sr_unix/iott_use.c
sr_unix/cli_lex.c
sr_unix/mu_term_setup.c
and for tcsetattr
sr_unix/iott_use.c
sr_unix/setterm.c
sr_unix/resetterm.c:
sr_unix/mu_term_setup.c:
The key file for setting device parameters seems to be iott_use (which Sam also previously pointed out). The source code for this file is
here.
I set breakpoints in gdb in the various routines above and the entered mumps command
USE $P:PASTHRU
This leads to breakpoint in iott_use.c
124: status = tcgetattr(tt_ptr->fildes, &t);
this loads t with the current tty state.
I the asked gdb to display the some of elements of t as binary numbers:
display/t t.c_iflag
display/t t.c_cflag
display/t t.c_iflag
which gives this output:
/t t.c_iflag = 10100000000
/t t.c_cflag = 10111111
/t t.c_lflat = 1000101000111011
The meaning of each bit is defined, and I tracked them all down, but that doesn't matter here.
Next we come to lined 361-2
361 case iop_pasthru:
362 mask_in |= TRM_PASTHRU; //kt 000010000
So here we are doing some bit masking to set the parameter.
It is storing this in mask_in, which is a simple int in local scope of the function.
mask_in is copied from a larger structure. It will be put back later... more on this to come
The code then goes through the various settings, and sets flags. Not all options result in flags set
Below is a simplified (edited) listing of flag elements changed:
-------------------------
case iop_canonical: tt_ptr->canonical = TRUE;
t.c_lflag |= ICANON; //kt binary 00000010.
case iop_nocanonical: tt_ptr->canonical = FALSE;
t.c_lflag &= ~(ICANON); //kt binary 11111101.
case iop_empterm: tt_ptr->ext_cap |= TT_EMPTERM; //kt binary 0100 0000 0000 0000.
case iop_noempterm: tt_ptr->ext_cap &= ~TT_EMPTERM; //kt binary 1011 1111 1111 11111
case iop_cenable: (doesn't set flags)
case iop_nocenable: (doesn't set flags)
case iop_clearscreen: (doesn't set flags)
case iop_convert: mask_in |= TRM_CONVERT; //kt binary 100000000
case iop_noconvert: mask_in &= ~TRM_CONVERT; //kt binary 011111111
case iop_ctrap: (doesn't set flags)
case iop_echo: mask_in &= (~TRM_NOECHO); //kt binary 101111111
case iop_noecho: mask_in |= TRM_NOECHO; //kt binary 010000000
case iop_editing: tt_ptr->ext_cap |= TT_EDITING;
case iop_noediting: tt_ptr->ext_cap &= ~TT_EDITING;
case iop_escape: mask_in |= TRM_ESCAPE; //kt binary 010000000
case iop_noescape: mask_in &= (~TRM_ESCAPE); //kt binary 101111111
case iop_eraseline: (doesn't set flags)
case iop_exception: (doesn't set flags)
case iop_filter: (doesn't set flags)
switch (fil_type) {
case 0: iod->write_filter |= CHAR_FILTER; //kt binary 10000000
case 1: iod->write_filter |= ESC1; //kt binary 00000001
case 2: iod->write_filter &= ~CHAR_FILTER; //kt binary 101111111
case 3: iod->write_filter &= ~ESC1; //kt binary 11111110
}
case iop_nofilter: iod->write_filter = 0; //kt binary 00000000
case iop_flush: (doesn't set flags)
case iop_hostsync: t.c_iflag |= IXOFF; //kt binary: 0001 0000 0000 0000
case iop_nohostsync: t.c_iflag &= ~IXOFF; //kt binary: 1110 1111 1111 1111
case iop_hupenable: (doesn't set flags)
case iop_nohupenable: (doesn't set flags)
case iop_insert: tt_ptr->ext_cap &= ~TT_NOINSERT; //kt binary 1101 1111 1111 1111
case iop_noinsert: tt_ptr->ext_cap |= TT_NOINSERT; //kt binary 0010 0000 0000 0000
case iop_length: (doesn't set flags)
case iop_pasthru: mask_in |= TRM_PASTHRU; //kt binary 000010000
case iop_nopasthru: mask_in &= (~TRM_PASTHRU); //kt binary 111101111
case iop_readsync: mask_in |= TRM_READSYNC; '/kt binary 000000100
case iop_noreadsync: mask_in &= (~TRM_READSYNC); //kt binary 111111011
case iop_terminator: (doesn't set flags)
case iop_noterminator: (doesn't set flags)
case iop_ttsync: t.c_iflag |= IXON; //kt Binary: 0000 0100 0000 0000
case iop_nottsync: t.c_iflag &= ~IXON; //kt Binary: 1111 1011 1111 1111
case iop_typeahead: mask_in &= (~TRM_NOTYPEAHD); //kt 111111101
case iop_notypeahead: mask_in |= TRM_NOTYPEAHD; //kt 000000010
case iop_upscroll: (doesn't set flags)
case iop_wrap: (doesn't set flags)
case iop_nowrap: (doesn't set flags)
case iop_x: (doesn't set flags)
case iop_y: (doesn't set flags)
case iop_ipchset: (doesn't set flags)
case iop_opchset: (doesn't set flags)
case iop_chset: (doesn't set flags)
Below I am going to list them again, sorted by elements modified.
Items that modify tt_ptr-><element>
-------------------------
case iop_canonical: tt_ptr->canonical = TRUE;
case iop_nocanonical: tt_ptr->canonical = FALSE;
case iop_empterm: tt_ptr->ext_cap |= TT_EMPTERM; //kt binary 0100 0000 0000 0000.
case iop_noempterm: tt_ptr->ext_cap &= ~TT_EMPTERM; //kt binary 1011 1111 1111 11111
case iop_editing: tt_ptr->ext_cap |= TT_EDITING;
case iop_noediting: tt_ptr->ext_cap &= ~TT_EDITING;
case iop_insert: tt_ptr->ext_cap &= ~TT_NOINSERT; //kt binary 1101 1111 1111 1111
case iop_noinsert: tt_ptr->ext_cap |= TT_NOINSERT; //kt binary 0010 0000 0000 0000
Items that directly modify t.<element>
case iop_canonical: t.c_lflag |= ICANON; //kt binary 00000010.
case iop_nocanonical: t.c_lflag &= ~(ICANON); //kt binary 11111101.
case iop_hostsync: t.c_iflag |= IXOFF; //kt binary: 0001 0000 0000 0000
case iop_nohostsync: t.c_iflag &= ~IXOFF; //kt binary: 1110 1111 1111 1111
case iop_ttsync: t.c_iflag |= IXON; //kt binary: 0000 0100 0000 0000
case iop_nottsync: t.c_iflag &= ~IXON; //kt binary: 1111 1011 1111 1111
Items that modify mask_in
-------------------------
case iop_convert: mask_in |= TRM_CONVERT; //kt binary 100000000
case iop_noecho: mask_in |= TRM_NOECHO; //kt binary 010000000
case iop_escape: mask_in |= TRM_ESCAPE; //kt binary 001000000
case iop_pasthru: mask_in |= TRM_PASTHRU; //kt binary 000010000
case iop_readsync: mask_in |= TRM_READSYNC; //kt binary 000000100
case iop_notypeahead: mask_in |= TRM_NOTYPEAHD; //kt binary 000000010
case iop_noconvert: mask_in &= ~TRM_CONVERT; //kt binary 011111111
case iop_echo: mask_in &= (~TRM_NOECHO); //kt binary 101111111
case iop_noescape: mask_in &= (~TRM_ESCAPE); //kt binary 110111111
case iop_nopasthru: mask_in &= (~TRM_PASTHRU); //kt binary 111101111
case iop_noreadsync: mask_in &= (~TRM_READSYNC); //kt binary 111111011
case iop_typeahead: mask_in &= (~TRM_NOTYPEAHD); //kt binary 111111101
Continuing with code:
temp_ptr = (d_tt_struct *)d_in->dev_sp;
Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status, save_errno, CHANGE_TERM_TRUE);
/* Store both t.c_lflag and t.c_iflag back in tt_ptr after calling Tcsetattr */
/* t.c_iflag used for show TTSYNC and NOTTSYNC when using ZSHOW "D" */
/* we may not need t.c_lflag because tt_ptr->canonical is currently responsible for CANONICAL output */
/* in sr_unix/zshow_devices.c but we might need it later so just store it both just in case */
tt_ptr->ttio_struct->c_iflag = t.c_lflag;
tt_ptr->ttio_struct->c_iflag = t.c_iflag;
if (tt == d_in->type) {
temp_ptr->term_ctrl = mask_in;
/* reset the mask to default if chset was changed without specifying new terminators or Default */
}
Above we see that d_in->dev_sp->term_ctrl = mask_in is the only way that canges to mask_in leave the function
**But note that the changes to mask_in are NOT written to tcsetattr**
I will repeat from above, then continue.
USE $P:PASTHRU
This leads to breakpoint in iott_use.c
124: status = tcgetattr(tt_ptr->fildes, &t); <--- I break AFTER this line. Note this is state BEFORE any changes are made
this loads t with the current tty state.
I the asked gdb to display the some of elements of t as binary numbers:
display/t t.c_iflag
display/t t.c_cflag
display/t t.c_iflag
which gives this output:
/t t.c_iflag = 10100000000
/t t.c_cflag = 10111111
/t t.c_lflat = 1000101000111011
If I then type at the mumps prompt:
USE $P:PASTHRU
And again break at
124: status = tcgetattr(tt_ptr->fildes, &t); <--- I break AFTER this line. Note this is state BEFORE any changes are made
which gives this output:
/t t.c_iflag = 10100000000
/t t.c_cflag = 10111111
/t t.c_lflat = 1000101000111011
NOTICE that there is no change to the t structure which gets state from tty system.
Conclusion
PASTHRU / NOPASTHRU Does not changes any settings in the TTY system. It must only change internal YDB behavior
Below are the only params that seem to change TTY settings
iop_canonical
iop_nocanonical
iop_hostsync
iop_nohostsync
iop_ttsync
iop_nottsync
Now I am confused, because i thought PASTHRU was going to change the TTY system.
KT