Programmering Sommarkurs 2007 www.hh.se/staff/vero/programmering Verónica Gaspes Utkast Avbrott i mjukvara Larm signaler Avslutnings signaler IDE-sektionen Curses Juli 2 Olika typer av program Signals Hittils har vi skrivit program som styr vad de vill att omgivningen (användaren) skall göra. Men många (de flesta?) program är styrda av omgivningen i form av händelser som sker med de hårdvara som är kopplad till processorn: sensorer, nätverket, tangenter, mus, med mera. Vi skall nu titta på hur man programmerar så att man kan ta hand om avbrott. Dessa avbrott sker på ett för programmet asynkron sätt och kräver att programmet tar hand om de. Vi måste först ta reda på vilka typer av avbrott som kan ske och vilken stöd som erbjuds för att hantera de.
Hårdvarunära programmering OS nära Hårdvarunära När man programmerar datorsystem utan OS måste man kunna addresser i en interrupt vector som beskrivs i dokumentationen. Där kan man lägga var det finns programdelar som kan hantera avbrottet. När ett avbrott sker sparar processorn tillståndet och hoppar till det address som anges i vektorn. Man kan blockera vissa avbrott. I en datorsystem med OS är det OS som fångar upp avbrott och producerar mjukvaruavbrott : signals. A signal is a software interrupt delivered to a process. En process är ett program under exekvering! Det vi frambesvärjar i datorn med program! Programspråk erbjuder stöd för att hantera signaler. Man måste lära sig att programmera på ett speciellt sätt. Disclaimer Vilka signaler? Signaler används mycket i samband med att man skriver samverkande program: program som ger upphov till flera processer som måste sammarbeta. Vi kommer inte att avhandla dessa efterssom det tillkommer nya problem och nya programmeringstekniker. För er som är intresserad av detta finns andra kurser, till exempel www.hh.se/staff/vero/concurrent OS signalerar om både fel som kan göra att programmet inte kan fortsätta på normal sätt och händelser så som tangenttrykning eller mus förflyttning eller klockans slag Example Programmets användare vill avsluta exekvering i våra system: Cĉ. En väckarklocka (alarm) är redo. Data finns tillgänglig för input.
Vad skall man göra? Första exemplet 1. Definiera en funktion för att ta hand om signalen (det är OS som anropar den!) 2. Registrera den som signal hanterare (i C finns det ett antal sätt att göra detta!) 3. Skriv program som gör det som skall göras i de vanliga fall! #include<signal.h> #include<stdio.h> #include<stdlib.h> void timehandler(int signr) printf("\nyou are taking too much time!\n"); exit(0); main(int argc, char * argv[]){ sigset(sigalrm,timehandler); char s[20]; alarm(3); while(1){ printf("what is the meaning of life?\n"); scanf("%s",s); Att komma ihåg Andra exemplet I main är det sigset(sigalrm,timehandler); som instalerar timehandler som hanterare av SIGLARM Signaturen för en hanterare måste vara void name (int arg) Man måste kolla vilka signaler finns och vad de heter! Detta kan variera från system till system. int seconds; void timehandler(int signr){ printf("\nyou are taking too much time!\n"); alarm( seconds ); main(int argc, char * argv[]){ sigset(sigalrm,timehandler); seconds = atoi(argv[1]); char s[20]; alarm( seconds ); while(1){ printf("what is the meaning of life?\n"); scanf("%s",s);
Globala variabler Klockan När hanteraren behöver andra värden än argumentet måste dessa värden sparas av de andra funktioner i variabler som alla ser. Dessa variabler heter globala och de deklareras utanför alla funktioner. Se till att det initieras i main! I båda exempel använde vi oss av tidssignaler. I gnu biblioteket finns tre olika typer av tidssignaler. SIGALRM This signal typically indicates expiration of a timer that measures real or clock time. It is used by the alarm function, for example. SIGVTALRM This signal typically indicates expiration of a timer that measures CPU time used by the current process. The name is an abbreviation for virtual time alarm. SIGPROF This signal typically indicates expiration of a timer that measures both CPU time used by the current process, and CPU time expended on behalf of the process by the system. Larm The alarm and setitimer functions provide a mechanism for a process to interrupt itself in the future. They do this by setting a timer; when the timer expires, the process receives a signal. int alarm (unsigned int seconds) Portability Note The setitimer and getitimer functions are derived from BSD Unix, while the alarm function is specified by the POSIX.1 standard. setitimer is more powerful than alarm, but alarm is more widely used. The alarm function sets the real-time timer to expire in seconds seconds. If you want to cancel any existing alarm, you can do this by calling alarm with a seconds argument of zero. The return value indicates how many seconds remain before the previous alarm would have been sent. If there is no previous alarm, alarm returns zero.
För användaren Hur skall de hanteras? Det finns ett antal signaler programanvändaren kan skicka till en process för att få den att avslutas. SIGINT The SIGINT (program interrupt) signal is sent when the user types the INTR character (normally C-c). Och andra SIGTERM, SIGQUIT, SIGKILL, SIGHUP These signals are all used to tell a process to terminate, in one way or another. They have different names because they re used for slightly different purposes, and programs might want to handle them differently. The reason for handling these signals is usually so your program can tidy up as appropriate before actually terminating. For example, you might want to save state information, delete temporary files, or restore the previous terminal modes. Such a handler should end by specifying the default action for the signal that happened and then reraising it; this will cause the program to terminate with that signal, as if it had not had a handler. The (obvious) default action for all of these signals is to cause the process to terminate. Tredje exemplet Att hantera terminalen void ctrlc(int signr) { printf("you pressed ctrlc\n"); exit(0); main(int argc, char * argv[]){ sigset(sigint,ctrlc); long fib_2 = 0; long fib_1 = 1; while(1){ printf("%d%s",fib_1,"\n"); fib_1 = fib_1 + fib_2; fib_2 = fib_1 - fib_2; Vi kommer att använda terminalen som device. För detta finns ett mycket använt bibliotek som följer med de flesta system. Det heter curses och det finns en ny variant som heter ncurse. Programming guide www.apmaths.uwo.ca/~xli/ncurses.html man sidor topin> man curses topin> man ncurses
Curses Ett litet curses program Man använder curses för att placera och flytta text i en terminal. Genom att kombinera detta med interaction med användaren och avbrott kan man göra menysystem, spel, med mera. Man måste och man måste topin>gcc prog -lcurses I vissa system är det istället main(){ initscr(); noecho(); clear(); move(10,20); addstr("hello world"); refresh(); getch(); endwin(); >gcc prog -lncurses Att flytta omkring main(){ int row=10; int i; initscr(); clear(); for(i=0;i<30;i++){ addstr("hello"); refresh(); usleep(100000); addstr(" "); endwin(); Asynkron input Om vi vill interagera med det som sker på terminalen utan att rörelser avstannar kan vi inte använda vanliga input funktioner som scanf eller getchar de blokerar och låter programmet vänta på input! Det finns funktioner för så kallad asynkron input som blir färdiga omedelbart men genererar en signal när input finns redo. Detta är platform beroende. Idag skall jag visa hur man gör i det system som vi använder i skolan. Nästa föreläsning kommer vi att se hur det kan ske i andra platformar.
main(){ int i; aio_result_t result; initscr(); clear(); row=10; sigset(sigio,handleinput); for(i=0;i<30;i++){ addstr("hello"); refresh(); usleep(100000); aioread(stdin_fileno, bf, 1, 0, SEEK_SET, &result); addstr(" "); endwin(); Man måste definiera int row; char bf[1]; void handleinput(int signr){ aiowait(null); if(bf[0]== z ){ beep(); row++; Observera Man måste #include<signal.h> #include<unistd.h> #include<sys/types.h> #include<sys/asynch.h> och man måste gcc curses3.c -lcurses -laio