第七讲 为用户编程终端控制和_第1页
第七讲 为用户编程终端控制和_第2页
第七讲 为用户编程终端控制和_第3页
第七讲 为用户编程终端控制和_第4页
第七讲 为用户编程终端控制和_第5页
已阅读5页,还剩69页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第七讲为用户编程终端控制和第1页,课件共74页,创作于2023年2月主要内容软件工具与用户程序读取和修改终端驱动程序的设置非阻塞输入用户输入的超时信号fcntl及signal系统调用第2页,课件共74页,创作于2023年2月与终端有关的程序用户常用的程序例如vi、emacs及许多游戏程序经常要有终端进行交互它们设置终端驱动程序的击键和输出处理方式用户经常用到的几种用户终端设置:立即响应击键事件有限的输入集输入的超时屏蔽Ctrl-C第3页,课件共74页,创作于2023年2月终端驱动程序的模式/*rotate.c*/#include<stdio.h>#include<ctype.h>intmain(){intc;while((c=getchar())!=EOF){if(c==‘z’)c=‘a’elseif(islower(c))c++;putchar(c);}第4页,课件共74页,创作于2023年2月规范模式:缓冲和编辑使用默认设置运行该程序(<-退格键)$gccrotate.c-orotate$./rotateabx<-cdbcdeefg^C$第5页,课件共74页,创作于2023年2月输入的内容及程序所得到的内容

rotate程序终端驱动程序显示器及键盘第6页,课件共74页,创作于2023年2月标准输入处理的特征程序未得到输入的x,因为删除了它击键的同时字符显示在屏幕上,但直到按了回车,程序才接收到输入^C键结束输入并终止程序程序rotate并不负责这些事情,对于输入的缓冲、回显、编辑和控制键处理都由驱动程序完成标准输入处理的这些特征被启动时,将终端连接称为规范模式第7页,课件共74页,创作于2023年2月非规范处理$stty-icanon;./rotateabbcxy^?cddeeffggh$sttyicanonstty-icanon命令关闭驱动程序中的规范模式处理非规范模式没有缓冲,输入字母’a’,驱动程序跳过缓冲层,字符直接送到程序,然后程序显示字符’b’用户输入未缓冲可能会带来麻烦,如果用户想修改输入时,此时将无法修改第8页,课件共74页,创作于2023年2月终端模式小结--规范模式

是用户常见的模式输入的字符保存在缓冲区接收到回车键时才将其中内容发送到程序缓冲功能使驱动程序可实现编辑功能,例如删除字符、单词或者行可通过命令stty或者系统调用tcsetattr修改执行上述操作的特定键第9页,课件共74页,创作于2023年2月终端模式小结--非规范模式

缓冲和编辑功能被关闭时,连接被称为处于非规范模式设备驱动器仍然进行特定字符的处理,例如Ctrl-C及换行符及回车符之间的转换删除单词、字符及终止编辑键将不具有特殊含义而是被视作常规的数据输入第10页,课件共74页,创作于2023年2月终端模式小结--raw模式

每个处理步骤都被一个独立的位控制,例如ISIG位控制Ctrl-C是否用于终止一个程序程序可随意关闭所有这些处理步骤当所有处理都被关闭后,驱动程序将输入直接传递给程序。这种模式就称为raw模式sttyraw命令第11页,课件共74页,创作于2023年2月编写一个用户程序:play_again.cplay_again.c的逻辑:对用户显示提示问题接受输入如果是y返回0如果是n返回1第一个play_again0.c程序第12页,课件共74页,创作于2023年2月play_again0.c的不足必须先按回车,程序才能接受到数据当用户按回车键时,程序接收整行的数据对其进行处理,例如Doyouwantanothertransaction(y/n)?surethingsurething第13页,课件共74页,创作于2023年2月改进方法首先关闭规范输入,使得程序能够在用户敲键的同时得到输入的字符set_crmode(){structtermiosttystate;tcgetattr(0,&ttystate); /*readcurr.setting */ttystate.c_lflag&=~ICANON; /*nobuffering */ttystate.c_cc[VMIN]=1; /*get1charatatime */tcsetattr(0,TCSANOW,&ttystate); /*installsettings */}第14页,课件共74页,创作于2023年2月tty_mode(inthow)staticstructtermiosoriginal_mode;if(how==0) tcgetattr(0,&original_mode);elsereturntcsetattr(0,TCSANOW,&original_mode);第15页,课件共74页,创作于2023年2月程序的主要过程首先调用tty_mode(0)函数保存当前终端的设置信息set_crmode()函数首先将终端置于一个字符接一个字符的模式然后调用函数显示一个提示符,并获得一个响应最后调用tty_mode(1)函数还原终端的设置第16页,课件共74页,创作于2023年2月将终端置入字符输入模式包括两部分工作:将ICANON位关闭将控制字符数组中的VMIN下标元素置一,VMIN的值告诉驱动程序一次可以读取多少个字符第17页,课件共74页,创作于2023年2月编译执行play_again1程序此时,程序可以直接接收和处理字符而不用等待回车键但对每个非法字符都提示错误信息,可能比较烦可关闭回显模式,丢掉不需要的字符,直到得到可接收的字符为止在set_crmode函数中加入语句ttystate.c_lflag&=~ECHO;第18页,课件共74页,创作于2023年2月阻塞与非阻塞输入当调用getchar或者read等函数从文件描述符读数据时,这些调用一直等待用户的输入,如果用户不输入,则继续等待,这种行为就术语阻塞输入阻塞不仅仅是终端连接的属性,而且是任何一个打开文件的属性可使用fcntl或者open,通过开启O_NDELAY标志为文件描述符启动非阻塞输入。第19页,课件共74页,创作于2023年2月非阻塞读取文件关闭文件描述符的阻塞状态,然后从中read时,结果如何呢?如果能够获得输入,read返回输入数据及字符个数,如果没有输入字符,read返回0,就像遇到文件末尾一样,有错误,返回-1.每个文件都有一块保存未读取数据的地方,若文件描述符置了O_NDELAY并且该空间为空,则read返回0。第20页,课件共74页,创作于2023年2月play_again3.cget_response(){int input;printf("%s(y/n)?",question); /*ask */fflush(stdout); /*forceoutput */while(1){ sleep(SLEEPTIME); /*waitabit */ input=tolower(get_ok_char()); /*getnextchr*/ if(input=='y') return0; if(input=='n') return1; if(maxtries--==0) /*outatime? */ return2; /*sayso */ BEEP; }}第21页,课件共74页,创作于2023年2月实验结果在输入后,程序会延时一会儿如果长时间不输入,程序也会退出第22页,课件共74页,创作于2023年2月fflush(out)函数终端驱动对于输出也是一行行缓冲的直到它收到一个换行符或者程序试图从终端读取数据时才会进行输出而此时getchar被延迟读入,因此通过该函数将提示信息输出到屏幕上,否则用户将看不到提示信息。第23页,课件共74页,创作于2023年2月Ctrl-C执行上述程序时,如果输入Ctrl-C则程序终止运行,同时,也终止了整个登录会话原因是什么呢?第24页,课件共74页,创作于2023年2月Ctrl-C设置O_NDELAY设置crmode显示提示符等待用户输入用户输入恢复tty设置恢复fcntl标志退出程序流程CtrlC进程被终止进程正常退出时流向第25页,课件共74页,创作于2023年2月Ctrl-C程序接收到Ctrl-C后,会立即退出,此时,无法执行重置启动程序的代码返回shell并从用户获得命令行时,终端仍处于非阻塞模式。shell调用read获取命令行,但是因为处于非阻塞状态,read立即返回0.这时shell程序就退出原因总结:程序结束时,文件描述符处于一个错误的状态。第26页,课件共74页,创作于2023年2月信号Ctrl-C中断当前运行的程。这个中断由内核的信号机制产生Ctrl-C的过程:用户输入Ctrl-C驱动程序收到字符匹配VINTR和ISIG的字符被开启驱动程序调用信号系统信号系统发送SIGINT到进程进程收到SIGINT进程消亡第27页,课件共74页,创作于2023年2月什么是信号信号是由单个词组成的消息,例如红绿灯所发出的信息Ctrl-C时,内核向当前运行的进程发送中断信号每个信号都有一个数字编码。中断信号编码通常是2第28页,课件共74页,创作于2023年2月信号的来源信号来自内核生成信号的请求来自3个地方:用户--通过输入Ctrl-C、Ctrl-\等请求内核产生信号内核--进程执行出错时,内核向进程发送一个信号,例如非法段访问、浮点数溢出等,也可通知进程特定事件的发生。进程--通过系统调用kill给另一个进程发送信号。进程之间可通过信号通信第29页,课件共74页,创作于2023年2月同步与异步信号由进程的某个操作产生的信号称为同步信号,例如被零除用户击键这样的进程外的事件引起的信号称为异步信号第30页,课件共74页,创作于2023年2月信号列表信号编号及其名字可在/usr/include/signal.h文件中找到,例如SIGINT为中断信号,SIGQUIT退出信号,SIGSEGV非法段访问信号可以使用信号消灭一个进程,也有办法保护自己不被杀死第31页,课件共74页,创作于2023年2月进程处理信号的方法进程通过signal系统调用告诉内核如何处理信号进程有3个选择:(1)接受默认处理SIGINT默认处理为消亡,进程通过系统调用signal(SIGINT,SIG_DFL)恢复默认处理(2)忽略信号signal(SIGINT,SIG_IGN)系统调用告诉内核忽略该信号第32页,课件共74页,创作于2023年2月进程处理信号的方法(3)调用一个函数,这是3种方法中最强大的一个。例如在play_again3程序中,当用户输入Ctrl-C时,程序收到信号后执行一个恢复设置的函数就不会发生上述情况了程序能够告诉内核,当信号来时调用哪个函数,signal(SIGINT,function);信号到来时所调用的函数称为信号处理函数第33页,课件共74页,创作于2023年2月signal系统调用目标简单的信号处理头文件#include<signal.h>函数原型result=signal(intsignum,void(*action)(int));参数signum需响应的信号action如何响应返回值-1遇到错误prevaction返回之前的处理函数指针第34页,课件共74页,创作于2023年2月signal系统调用其中action可以是函数名也可以是如下两种特殊值之一:SIG_IGN,忽略信号SIG_DFL将信号恢复为默认处理signal返回前一个处理函数。值为指向该函数的指针第35页,课件共74页,创作于2023年2月信号处理的例子sigdemo1.c

#include <stdio.h>#include <signal.h>main(){ void f(int); /*declarethehandler */ int i; signal(SIGINT,f); /*installthehandler */ for(i=0;i<5;i++){ /*dosomethingelse */ printf("hello\n"); sleep(1); }}voidf(intsignum) /*thisfunctioniscalled*/{ printf("OUCH!\n");}第36页,课件共74页,创作于2023年2月信号处理过程main(){signal(SIGINT,f);for(i=0;i<5;i++){printf(“hello\n”);sleep(1);}}正常控制流信号函数f(){printf(“OUCH”);}第37页,课件共74页,创作于2023年2月sigdemo1.c执行结果hellohellohellohello^COUCH!hello第38页,课件共74页,创作于2023年2月忽略信号sigdemo2.c

#include <stdio.h>#include <signal.h>main(){ signal(SIGINT,SIG_IGN); printf("youcan'tstopme!\n"); while(1) { sleep(1); printf("haha\n"); }}第39页,课件共74页,创作于2023年2月sigdemo2.c程序执行结果youcan'tstopme!hahahaha^Chahahaha^Chahahaha^\退出第40页,课件共74页,创作于2023年2月sigdemo2.c调用signal忽略中断信号,可以随意按Ctrl-C而不会对程序产生影响signal(SIGINT,SIG_IGNT)第41页,课件共74页,创作于2023年2月作业6.10第42页,课件共74页,创作于2023年2月处理多个信号当有多个信号到达进程时,该如何处理?第43页,课件共74页,创作于2023年2月1.捕鼠器问题

信号处理函数有点像捕鼠器早期版本中,在每次捕获之后,都必须重设它们。例如voidhandler(ints){signal(SIGINT,handler);}第44页,课件共74页,创作于2023年2月1.捕鼠器问题即使设置的速度非常快,它还是需要时间触发处理函数及重新设置完成之前,有新的信号或者老鼠溜走这一脆弱的间隙使得原有的信号处理不可靠,因此称为不可靠的信号第45页,课件共74页,创作于2023年2月处理多个信号第二个信号打断第一个信号的处理第二个信号被阻塞返回信号处理的地方是否要重新开始?信号的优先级?第46页,课件共74页,创作于2023年2月进程的多个信号处理函数每次使用之后都要禁用吗?如果SIGY消息在进程处理SIGX消息时到达会发生什么?如果进程还在处理前一个SIGX时,第二个SIGX又到来会发生什么事情呢?第三个呢?如果信号到来时,程序正在处理getchar或者read之类的输入而阻塞,那会如何呢?第47页,课件共74页,创作于2023年2月测试多个信号sigdemo3.c程序signal(SIGINT,inthandler); /*sethandler*/signal(SIGQUIT,quithandler); /*sethandler*/do{ printf("\nTypeamessage\n"); nchars=read(0,input,(INPUTLEN-1)); if(nchars==-1) perror("readreturnedanerror"); else{ input[nchars]='\0'; printf("Youtyped:%s",input); }}while(strncmp(input,"quit",4)!=0);}第48页,课件共74页,创作于2023年2月voidinthandler(ints){ printf("Receivedsignal%d..waiting\n",s); sleep(2); printf("Leavinginthandler\n");}voidquithandler(ints){ printf("Receivedsignal%d..waiting\n",s); sleep(3); printf("Leavingquithandler\n");}第49页,课件共74页,创作于2023年2月执行结果Typeamessagehelloyoutyped:helloTypeamessage^\^CReceivedsignal3....Receivedsignal2....LeavinginthandlerLeavingquithandler第50页,课件共74页,创作于2023年2月各种实验(1)输入^C^C^C^C(2)^\^C^\^C(3)hello^CReturn(4)helloReturn^C(5)^\^\hello^C第51页,课件共74页,创作于2023年2月第一种情况不可靠的信号若两个SIGINT信号杀死了进程,则系统是不可靠的信号若未杀死进程,则处理函数在被调用后还有作用现代信号处理机制允许在两者之间选择默认情况下,为后者第一次实验的结果为:信号函数执行了两次,后面的两次函数丢失第52页,课件共74页,创作于2023年2月第二种情况:SIGY打断SIGX的处理

函数接连按下^C和^\时程序先跳到inthandler,然后跳到quithandler,然后再回到inthandler,最后回到主循环第二种情况的实验:接收到^\后,程序进入quithandler程序,接收到^C后,进入inthandler程序,最后返回到quithandler程序说明信号^C打断信号^\第53页,课件共74页,创作于2023年2月第三种情况:SIGX打断SIGX的处理函数有三种可能:递归,调用同一个处理函数忽略第二个信号阻塞第二个信号直到第一个处理完毕第三种方法最好,第54页,课件共74页,创作于2023年2月系统调用被中断例如当调用read或者getchar函数时,程序接收到^C的信号然后程序执行信号处理函数,执行完后,程序重新返回主循环程序是重新执行read还是从read返回同时设置errno为EINTR呢?第55页,课件共74页,创作于2023年2月实验结果:hello^CReturn时,程序无法接收到hello输入helloReturn^C时,程序可接收到hellohel^CloReturn时,程序只接收到lo^\^\hello^C时,无法得到hello输入,同时信号处理执行完后,重新开始read第56页,课件共74页,创作于2023年2月信号机制其他的弱点无法确定信号产生的原因---早期的模型只是告诉了信号的类型处理函数中无法安全阻塞其他消息voidinthandler(ints){intrv;void(*prev_qhandler)();prev_qhandler=signal(SIGQUIT,SIG_IGN);

….signal(SIGQUIT,prev_qhandler);}第57页,课件共74页,创作于2023年2月无法同时调用inthandler以及忽略SIGQUIT无法阻塞SIGQUIT信号第58页,课件共74页,创作于2023年2月sigaction可以处理多个信号目标指定信号的处理函数头文件#include<signal.h>函数原型result=signaction(intsignum,conststructsigaction*actionstructsigaction*prevaction));参数signum需处理的信号action指向描述操作的结构的指针prevaction指向描述被替换操作的结构指针返回值-1遇到错误0成功第59页,课件共74页,创作于2023年2月定制信号处理structsigactionstructsigaction{void(*sa_handler)();void(*sa_sigaction)(int,siginfo_t*,void*);sigset_tsa_mask;intsa_flags;}其中sa_handler可以为SIG_DFL,SIG_IGN或者函数名称,它是老的信号处理方式第60页,课件共74页,创作于2023年2月sa_sigaction为新的信号处理机制它可获得信号编号及被调用的原因及产生问题的上下文的相关信息使用旧的处理机制:structsigactionaction;action.sa_handler=handler_old;使用新的处理机制:structsigactionaction;action.sa_sigaction=handler_new;将sigaction中的标志位sa_flags置为:SA_SIGINFO第61页,课件共74页,创作于2023年2月sa_flags标志标记含义SA_RESETHAND当处理函数被调用时重置,即捕鼠器模式SA_NODEFER处理信号时关闭信号自动阻塞,因此允许递归调用信号处理函数SA_RESTART当系统调用是针对一些慢速的设备或类似的系统调用,重新开始而不是返回SA_SIGINFO指明使用sa_sigaction的处理函数值。如果它未设置,则使用旧处理机制,若设置,则传给处理函数的包括信号编号、信号产生的原因和条件等信息第62页,课件共74页,创作于2023年2月sigaction的例子 structsigactionnewhandler;/*newsettings*/ sigset_tblocked;/*setofblockedsigs*/ void inthandler();/*thehandler*/ char x[INPUTLEN]; /*loadthesetwomembersfirst*/ newhandler.sa_handler=inthandler;/*handlerfunction*/ newhandler.sa_flags=SA_RESETHAND|SA_RESTART;/*options*/ /*thenbuildthelistofblockedsignals*/ sigemptyset(&blocked);/*clearallbits*/ sigaddset(&blocked,SIGQUIT); /*addSIGQUITtolist*/ newhandler.sa_mask=blocked;/*storeblockmask*/ if(sigaction(SIGINT,&newhandler,NULL)==-1) perror("sigaction");第63页,课件共74页,创作于2023年2月防止数据损毁临界区修改一个数据结构的代码若在运行时被打断,将导致数据的不完整或损毁该代码称为临界区临界区不一定就在信号处理函数中保护它的最简单的办法就是忽略或阻塞处理函数将要使用或修改特定数据的信号第64页,课件共74页,创作于2023年2月阻塞信号:sigprocmask和sigsetop

在信号处理一级或者进程一级阻塞信号在处理一个信号时阻塞另一个信号,设置structsigaction中的sa_mask成员位sa_mask指定哪些信号要被阻塞sa_mask类型为sigset_t,它定义了信号集合第65页,课件共74页,创作于2023年2月进程的阻塞信号任何时候进程都有一些信号被阻塞,这个信号的集合被称为信号挡板。系统调用sigprocmask可修改这个被阻塞的信号集sigprocmask是一个原子操作,根据所给的信号集来修改当前被阻塞的信号集第66页,课件共74页,创作于2023年2月sigprocmask目标修改当前的信号挡板头文件#include<signal.h>函数原型intresult=sigprocmask(inthow,constsigs

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论