终端控制和和信号——《Unix/Linux编程实践教程》读书笔记(第6章)
1、有些程序处理从特定设备来的数据。这些与特定设备相关的程序必须控制与设备的连接。Unix系统中最常见的设备是终端。
2、终端驱动程序有很多设置。各个设置的特定值决定了终端驱动程序的模式。为用户编写的程序通常需要设置终端驱动程序为特定的模式。
3、键盘输入分为3类,终端驱动程序对这些输入做不同的处理。大多数建代表常规数据,它们从驱动程序传输到程序。有些键调用驱动程序中的编辑函数。如果按下删除键,驱动程序将前一个字符从它的行缓冲中删除,并将命令发送到终端屏幕,使之从显示器中删除字符。最后,有些键调用处理控制函数。Ctrl-C键告诉驱动程序调用内核中某个函数,这个函数给进程发送一个信号。终端驱动程序支持若干种处理控制函数,它们都通过发送信号到进程来实现控制。
man 2 signal
4、信号是从内核发送给进程的一种简短消息。信号可能来自用户、其他进程或内核本身。进程可以告诉内涵,在它收到信号时需要做出怎样的响应。
5、
man 2 fcntl
#include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */);
man 2 signal
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); /* * signal() returns the previous value of the signal handler, * or SIG_ERR on error. In the event of an error, * errno is set to indicate the cause. */
/* * play_aganin04.c * purpose: ask if user wants another transaction * method: set tty into char-by-char mode and no echo mode, * set tty into no-delay mode * read char, return result * resets terminal modes on SIGINT, ignores SIGQUIT * returns: 0->yes, 1->no, 2->timeout * better: reset terminal mode on Interrupt */ #include <stdio.h> #include <stdlib.h> #include <termios.h> #include <fcntl.h> #include <string.h> #include <signal.h> #define ASK "Do you want another transaction" #define TRIES (3) /* max tries */ #define SLEEPTIME (2) /* time per try */ #define BEEP putchar(‘\a‘) /* alert user */ int get_response(char *, int); char get_ok_char(void); void tty_mode(int); //void set_crmode(void); void set_cr_noecho_mode(void); void set_nodelay_mode(void); int main(void) { int response; void ctrl_c_handler(int); tty_mode(0); /* save tty mode */ //set_crmode(); /* set char-by-char mode */ set_cr_noecho_mode(); set_nodelay_mode(); signal(SIGINT, ctrl_c_handler); /* handle INT */ signal(SIGQUIT, SIG_IGN); /* ignore QUIT signals */ response = get_response(ASK, TRIES); tty_mode(1); /* restore tty mode */ printf("\n"); return response; } int get_response(char *question, int maxtries) /* * purpose: ask a question and wait for a y/n answer or maxtries * method: use a getchar and ignore non y/n answers * returns: 0->yes, 1->no */ { int input; printf("%s (y/n)?", question); fflush(stdout); while (1) { sleep(SLEEPTIME); input = tolower(get_ok_char()); if (input == ‘y‘) return 0; if (input == ‘n‘) return 1; if (maxtries-- == 0) return 2; BEEP; } } /* * skip over non-legal chars and return y, Y, n, N or EOF */ char get_ok_char(void) { char c; while ((c = getchar()) != EOF && strchr("yYnN", c) == NULL) ; return c; } void set_cr_noecho_mode(void) /* * purpose: put file descriptor 0 into char-by-char and noecho mode * method: use bits in termios */ { struct termios ttystate; tcgetattr(0, &ttystate); ttystate.c_lflag &= ~ICANON; /* no buffering */ ttystate.c_lflag &= ~ECHO; /* no echo either */ ttystate.c_cc[VMIN] = 1; /* get 1 char at a time */ tcsetattr(0, TCSANOW, &ttystate); /* install settings */ } void set_nodelay_mode(void) /* * purpose: put file descriptor 0 into no_delay mode * method: use fcntl to set bits * notes: tcsetattr() will do something similar, but it is complicated */ { int termflags; termflags = fcntl(0, F_GETFL); /* read curr settings */ termflags |= O_NDELAY; /* flip on nodelay bit */ fcntl(0, F_SETFL, termflags); /* and install them */ } /* how == 0 -> save current mode, how == 1 -> restore mode */ /* this version handles termios and fcntl flags */ void tty_mode(int how) { static struct termios original_mode; static int original_flags; static int stored = 0; if (how == 0) { tcgetattr(0, &original_mode); original_flags = fcntl(0, F_GETFL); stored = 1; } else { tcsetattr(0, TCSANOW, &original_mode); fcntl(0, F_SETFL, original_flags); } } void ctrl_c_handler(int signum) /* * purpose: called if SIGINT is detected * action: reset tty and scram */ { tty_mode(1); printf("\nCtrl-C pressed.\n"); exit(1); }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。