170 likes | 286 Views
제 34 강 : Interactive Terminal. Interactive Terminal. c. c. c. c. c. c. Data structure for Characters. Array: poor insert/delete 1-link-1-char space overhead Compromise 1-link-N-char. Linux project is very fun to. L. i. n. u. x. c. c_next. c c c
E N D
제34강 : Interactive Terminal Interactive Terminal
c c c c c c Data structure for Characters • Array: poor insert/delete • 1-link-1-char space overhead • Compromise 1-link-N-char Linux project is very fun to L i n u x c c_next c c c c c c Linux projec info cblock 8140: struct cblock { 8141: struct cblock *c_next; 8142: char info[6]; 8143: };
c_next c c c c c c c c c c c c 8140: struct cblock { 8141: struct cblock *c_next; 8142: char info[6]; 8143: }; info cblock c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c 8146: struct cblock cfree[NCLIST]; 0 1 2 3 4 5 6 7 8 7926: struct tty 7927: { 7928: struct clist t_rawq; 7929: struct clist t_canq; 7930: struct clist t_outq; …………………… 7943: }; tty t_rawq t_canq t_outq clist c_cc c_cf c_cl Raw queue Canonical queue Output queue tty c_cc c_cf c_cl 7908: struct clist 7909: { 7910: int c_cc; 7911: int c_cf; 7912: int c_cl; 7913: }; c_cc c_cf c_cl getc() putc() kernel functions
tty t_rawq t_canonq t_outq c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c first last count cblock clist c c c c c c c c c c c c first last count first last count c c c c c c c c c c c c
7926: struct tty 7927: { 7928: struct clist t_rawq; /* input chars right off device */ 7929: struct clist t_canq; /* input chars after erase and kill */ 7930: struct clist t_outq; /* output list to device */ 7931: int t_flags; /* mode, settable by stty call */ 7932: int *t_addr; /* device address (register or startup fcn) */ 7933: 7934: char t_delct; /* number of delimiters in raw q */ 7935: char t_col; /* printing column of device */ 7936: char t_erase; /* erase character */ 7937: char t_kill; /* kill character */ 7938: char t_state; /* internal state, not visible externally */ 7939: 7940: char t_char; /* character temporary */ 7941: int t_speeds; /* output+input line speed */ 7942: int t_dev; /* device name */ 7943: }; 7944: /* --------------------------- */ 7965: /* modes */ 7969: #define ECHO 010 7970: #define CRMOD 020 7971: #define RAW 040 7972: #define ODDP 0100 7973: #define EVENP 0200
(A) Device initiates(top / bottom half) When the user types a char on the keyboard HW interrupt ….. Stores char in the raw queue (If anyone was waiting, wakeup) echo? Raw queue (vi) HW asm interrupt Interrupt handler C interrupt handler klrint(dev) 8078 ttyinput(tty) 8333
8333:ttyinput(ac, atp) /* HW interrupt routine klrint() calls this */ 8334: struct tty *atp; 8335: { 8336: register int t_flags, c; 8337: register struct tty *tp; 8338: 8339: tp = atp; 8340: c = ac; 8341: t_flags = tp->t_flags; 8342: if ((c =& 0177) == ‘ r' && t_flags&CRMOD) /* new char is end-of-line. canonical mode 8343: c = ‘ n'; 8344: if ((t_flags&RAW)==0 && (c==CQUIT || c==CINTR)) { /* not raw mode & char is quit or delete 8345: signal(tp, c==CINTR? SIGINT:SIGQIT); / * signal() to send software interrupt 8346: flushtty(tp); 8347: return; 8348: } 8349: if (tp->t_rawq.c_cc>=TTYHOG) { 8350: flushtty(tp); 8351: return; 8352: } 8353: if (t_flags&LCASE && c>='A' && c<='Z') 8354: c =+ 'a'-'A'; 8355: putc(c, &tp->t_rawq); /* insert char into raw queue (23-3-3) 8356: if (t_flags&RAW || c==‘ n' || c==004) { /* wakeup if ((raw mode) or (newline) or ..) 8357: wakeup(&tp->t_rawq); /* wake up if process was sleeping on this tty rawq 8358: if (putc(0377, &tp->t_rawq)==0) /* insert delimeter char (eight-1’s into raw_Q) 8359: tp->t_delct++; /* inc delimiter-count (amount of work waiting) 8360: } 8361: if (t_flags&ECHO) { /* need echo? Output this char on screen. 8362: ttyoutput(c, tp); 8363: ttstart(tp); 8364: } 8365: } 8333 (25-2)
(B) Application Process Initiates User a.out (sh) says scanf(3) system call read(std, &here) readi() cdevsw[] 6234 klread() 4671, 8062 ttread() 8535 canon() 8274 ---------------------------- (case canon mode) access canon queue, if empty, copy rawq canonq (case raw mode) access raw queue if rawq is empty, sleep there ------------------------ copy character(s) to user space user a.out Canon queue <canon> erase, kill … <raw> just copy Raw queue
4669: int (*cdevsw[])( ) 4670: { 4671: &klopen, &klclose, &klread, &klwrite, &klsgtty, /* console */ 4672: 4673: &pcopen, &pcclose, &pcread, &pcwrite, &nodev, /* pc */ 4674:
8535: ttread(atp) 8536: struct tty *atp; 8537: { 8538: register struct tty *tp; 8539: 8540: tp = atp; 8541: if ((tp->t_state&CARR_ON)==0) 8542: return; 8543: if (tp->t_canq.c_cc || canon(tp)) 8544: while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0) ; 8545: } (25-1) Canon queue has char Canon queue is empty so copy from raw queue to canon queue • Get char from the given clist Yes, you can use u if char file! • passc() 6517 • copy data to user space • using struct u Remember? iomove() passc() cpass() N byte 1-char (K->U) 1-char (K<-U)
8274: canon(atp) 8275: struct tty *atp; 8276: { register char *bp; 8278: char *bp1; 8279: register struct tty *tp; 8280: register int c; 8281: 8282: tp = atp; 8283: spl5(); 8284: while (tp->t_delct==0) { /* no input from terminal? (zero delimeters). 8285: if ((tp->t_state&CARR_ON)==0) 8286: return(0); 8287: sleep(&tp->t_rawq, TTIPRI); /* sleep here at the rawq 8288: } 8289: spl0(); 8290: loop: 8291: bp = &canonb[2]; /* bp points to array canonb[2] (0202 global array[256]) 8292: while ((c=getc(&tp->t_rawq)) >= 0) { /* Take one char from rawq per loop 8293: if (c==0377) { /* if delimeter .. 8294: tp->t_delct--; 8295: break; 8296: } (25-1)
8297: if ((tp->t_flags & RAW) = = 0) { /* Canonical mode. special char(line editing) 8298: if (bp[-1] != ‘ ') { /* if previous char was not backslash, then 8299: if (c==tp->t_erase) { /* erase character –line discipline 8300: if (bp > &canonb[2]) 8301: bp--; /* backup the buffer pointer 8302: continue; 8303: } 8304: if (c==tp->t_kill) /* kill character – line discipline 8305: goto loop; /* throw away the whole buffer 8306: if (c==CEOT) 8307: continue; 8308: } else 8309: if (maptab[c] && (maptab[c]==c || (tp->t_flags&LCASE))) { 8310: if (bp[-2] != ‘ ') 8311: c = maptab[c]; 8312: bp--; 8313: } 8314: } 8315: *bp++ = c; /* put char into *bp (i.e. canonb[]) 8316: if (bp>=canonb+CANBSIZ) /* canon[] buffer overflow? 8317: break; 8318: } 8319: bp1 = bp; /* while loop ended -- now canonb[] has char’s ready for delivery 8320: bp = &canonb[2]; 8321: c = &tp->t_canq; 8322: while (bp<bp1) 8323: putc(*bp++, c); /* copy canonb[] into canonical queue of this tty 8324: return(1); /* successful return (1) 8325: } erase/kill … processing Case 1) canonical mode – after line editing Case 2) raw mode – no line editing as input from keyboard
Summary • User types on keyboard ----- HW interrupt • From I/O device buffer to tty raw queue • Insert delimiter (all 12’s), count++ • Echo, if requested • Wakeup application process if sleeping on raw queue • sh, vi invokes read(tty, &here,..) ---- system call • sleep if raw queue is empty(different than block mode) • Copy from tty raw queue to canon queue • erase, kill processing if tty is in canonical mode • Copy from tty canon queue to user space (&here) • return
1 sys call 2 cdevsw[] 3 klread() 4 ttread() Application Code 6 getc() - passc() Canon queue (sh) <erase/kill> 5 canon() Output queue <no line editing> 1 klintr() 2 ttinput() Raw queue (vi)