If canonical mode is not set, will non-blocking read be performed?

The code below is an example of a non-blocking reading of terminal IO, however, when I type in a character on the console, it does not immediately print it. Perpapses, you will say that I have to set stty -icanon , so canonical mode is disabled, which really works, but I think that even if I don’t disable stty icanon , non-blocking terminal reading is a character-oriented , cannonical mode just wakes up the blocking process but my process does not block, if we enter a character, then we read fd, so it should immediately print the character.

 #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <string.h> #include <stdlib.h> #define MSG_TRY "try again\n" int main(void) { char buf[10]; int fd, n; fd = open("/dev/tty", O_RDONLY|O_NONBLOCK); if(fd<0) { perror("open /dev/tty"); exit(1); } tryagain: n = read(fd, buf, 10); if (n < 0) { if (errno == EAGAIN) { sleep(1); write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY)); goto tryagain; } perror("read /dev/tty"); exit(1); } write(STDOUT_FILENO, buf, n); close(fd); return 0; } 
+4
source share
2 answers

O, as I understand it, using the O_NONBLOCK flag at the time of opening, it simply tells open not to wait until the modem is ready if, for example, you try to open the terminal.

This source is very helpful. http://en.wikibooks.org/wiki/Serial_Programming/termios#Opening.2FClosing_a_Serial_Device

Today I worked with tty devices (RS232 port). http://www.gnu.org/software/libc/manual/html_node/Terminal-Modes.html#Terminal-Modes

How do you know if the terminal is canonical or unprocessed? If I understand you correctly, you say that you installed the terminal non-canonical (raw), but later it changed. It's right? In this case, if in your code you configured the device non-canonical?

If you need raw mode, there is a cfmakeraw () function. And don't forget to specify your attributes with tcsetattr (). for example const struct termios yourtermios yourtermios.c_cc [VTIME] = 0; yourtermios.c_cc [VMIN] = 1; Or whatever value you choose.

Here is a great source of information about canonical or not. http://www.gnu.org/software/libc/manual/html_node/Canonical-or-Not.html#Canonical-or-Not

+1
source

If you want a function that takes one unbuffered character is a function that I wrote myself. It will read one character (which is one keystroke in most cases), without waiting for the user to press the enter key.

 #include <unistd.h> #include <termios.h> #include <errno.h> int ugetc(char *c) { if(c == NULL) return EINVAL; struct termios term; //Get the current terminal settings so that only //the settings we want to change are changed if(tcgetattr(STDIN_FILENO, &term) == -1) return errno; //Save the original terminal settings unsigned int c_lflag = term.c_lflag; unsigned int vmin = term.c_cc[VMIN]; unsigned int vtime = term.c_cc[VTIME]; //If line buffering is turned on then turn if off if(term.c_lflag & ICANON) term.c_lflag ^= ICANON; //Make sure that read() will wait for a single character term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; //Apply the changed settings if(tcsetattr(STDIN_FILENO, TCSANOW, &term) == -1) return errno; //Verify that changes were made properly see "man tcgetattr" for more details if(tcgetattr(STDIN_FILENO, &term) == -1) return errno; //Verify that changes were made properly see "man tcgetattr" for more details if ( term.c_lflag & ICANON || term.c_cc[VMIN] != 1 || term.c_cc[VTIME] != 0 ) //The value returned can be change to any valid errno macro return ECANCELED; //Save the read() return value for later processing int ret = read(STDIN_FILENO, c, 1); //Restore the old settings saved from earlier term.c_lflag = c_lflag; term.c_cc[VMIN] = vmin; term.c_cc[VTIME] = vtime; //Apply the restored settings if(tcsetattr(STDIN_FILENO, TCSANOW, &term) == -1) return errno; //Verify the changes were successful see "man tcgetattr" for more details //NOTE: If tcgetattr() fails to restore the original settings the terminal //will stay unbuffered if(tcgetattr(STDIN_FILENO, &term) == -1) return errno; //Verify the changes were successful see "man tcgetattr" for more details if ( term.c_lflag != term.c_lflag || term.c_cc[VMIN] != vmin || term.c_cc[VTIME] != vtime ) return ECANCELED; //If a read error occured return errno //NOTE: If an error occurs we want to restore the old //settings anyway so we save the return value and check //it after the old settings have been restored if(ret == -1) return errno; return 0; } 

The function has not been thoroughly tested yet, so you must test it yourself.

0
source

Source: https://habr.com/ru/post/1479221/


All Articles