Rio Buffered Input Functions

Một phần của tài liệu Computer systems a programmers perspective randal e bryant, david r ohallaron (Trang 933 - 938)

10.5 Robust Reading and Writing with the Rio 'Package

10.5.2 Rio Buffered Input Functions

Suppose we wanted to write a pro&f.am that coui;its the number of lines in a text file.

How might w~ do this? One approach is to use the reaclJunction to transfer 1 brte at a tfrne from the file to the user"s \nemory, check;,{g each byte f6t"the 'n~Wline character. The disadvantage of this approach is that it is inefficient, requirihg a irap to the kernel to read ea,c)l. byte in the file.

A better agproach is to c~ll a wrapp,~r function,(rio_re,l'l.\ll:i..ne,1;>). that copies the ~l'.t line from an internal read b~ffefr, i'l\!Pmatically making a read call to refill the buffer whenever it becomes empty. For files that contain both text lines and binhry data (such as the HTrP'fesponses d'escribetl in 'section 11.5.3), we also pro'viO'e a buffered rersibn of !-io_readn, calld& ~io_i-eãalinb, that transfers raw bytes from 1ne"sa'me. read buffer'as rio_reac;tlineb.

'

#include "csapp.h"

'void rio_readinitb(rio_t *rp, int fd);

Returns: nothing ssize_t rio_readlineb(rio_t *rp, void *usrbà,f, .size_t} maxle.H);

ssize_t rio_reacb;J.b(rio_t *rp, yoid *usrbu~, size_t n);

Returns: number of bytes read if OK, 0 on EOF, -1 on 'trror The rio_readini tb function,is called once per open descriptor. It associates the descriptor fd with a read buffer of type rio_ t at address rp.

The rio_readlineb function-reads the nexi text line from file rp (including the terminating newline character), copies'H to 'inemory location usrbuf, and terminates the.text line with the NULL (zero) character. The rio_readlineb function reads a(\nost maxlen-1 bytes, leaving room for the terminating NULL character. Text lines that exceed maxlen-1 bytes are truncated and terminated with a NULL character. '

The rio_readnb fiinctfon reads up ton bytes from file rp'to memory locatiOn usrbuf. Calls to rio_feadlineb and rio_readnb can be interleaved arbitrarily on the same descriptor.-However; calls to these buffered functions should not be interleaved with.calls to the unbuffered rio_readnfonction.1"

You will encounter numerous examples of theR10 functions in the remainder of this text: Figure 10.5 shows how toJJse the Rm functions to copy a text file from standard input to standard output, one line, at a time.

Figure 10.6 shows'"the format,of a read buffer, along with the code for the rio_readini tb function that initializes it. The rio_readini tb function sets up an empty read buffer and associates an open file descriptor with that buffer.

Section 10.5 Robust Reading and Writing witMhe Rio Package 899 - - - codelsrdcsapp.c

1 ssize_t rio_readn(int fd, void •usrbuf, size_t n) 2 {

3 size_t nleft = n;

4 ssize_t nread;

5 char *bufp = usrbuf;

6

7 while (nleft > 0) {

8 if ((nread = read(fd, bufp, nleft)) < 0) {

9 if (errno == EINTR) /• Interrupted by sig handler return •/

10 nread = O; !• a.Ild,tall read() again •/

11 else '•

12 13 14 15 16 17 18 19 20 }

} ••

return -1;

}

else if (nread break;

nleft -= nread;

bufp += nreadi return (n - nleft);

/* errno set by read() •/

O)

L I• EDf' •/ ~ " ã

/* Return >= 0 •I

- - - , , . - - - c o d e / s r d c s a p p . c

- - - code/srdcsapp.c

'

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 161'

17

ssize_t rio_writen(int fd, void •usrbuf, size_t n) {

size_t nleft = n;

) > ssize_t nwritten;

char •bufp = usrbuf;

while (nleft > O) {

J ••

}

if ((nwritten = write(fd, bufp, nleft)) <= 0) {

i f (errno == EINTR) /• Interrupt,ed bl'. sig handle~

nwritte~ = Oi /• and call write() again •/

else

return -1;

} ' ,, '

nleft -= nwritten;

bufp ,. += nwritten;

/• errno set" by write() */

return -tJ..t 18 }

ã.

retui-n •/

•(' l ' 1•

---0 .. ~~-~---codelsrdcsapp.c

l

Figure110.4 The rio_readn and' rio_w:b ten functions.

• '

900 Chapter J-0. . .System-Level 1/0 h 'I

---~~---coddio/cpfile.c

#include 11csapp.h" "

2

3 int main(int argC, char **argv)

4 {

5 int n;

6 rio_t rio;

7 char buf[MAXLINE];

8

9 Rio_readinitb(&rio, ~TDIN_FILENO);

10 while((n = Rio_readlinebC&.rio, buf,, MAXLINE)) != •Q) 11 Rio_writen(STDDUT_FILENO, buf, n);

12 }

---~--code!io!cpfilec

Figure 10.5 Copying a text file from standard input, to standard output.

---~---code!include!csapp.h

#define RIO_BUFSIZE 8192 typedef struct {

int rio_fd;

int rio_cnt;

char *rio_bufptr;

char rio_buf[RIO_BUFSIZ~];

} rio_t;

/* Descriptor for this internal buf */

I• Unread~bytes in internal buf *f I* Next unread byte in internal buf */

I* Internal buffer */

.:~ l"

- - - . . . , , - - - code!include!csapp.h - - - 'code!srdcsapp.c

2 3 4 5 6

void rio_readinitb(rio_t *rp. int fd) {

rp->rio_fd = fd;

rp->rio_cnt ~ = 9; .. , r \, .

}

rp->rio_bufptr =, rp->rio_buf;;

• /!: ' •

<

---,,,,~,---~.r.----code!srdcsapp.c

Figure 10.6 A read buffer of type rio_t and the rio_readini tb function that initializes it.

The heart of the Rio read routines is the rio_read function shown in Fig- ure 10.7.'The rio_read function is a buffered version of the Linux read function.

When rio_read is called with a request to read n bytes, there are rp->r~o_cnt unread bytes in the read buffer. If the buffer is empty, then it is replenished with a call to read. Receiving a short count from this invocatiqn of read is not an er- ror; it sin:ply has the effect of.partially filling the read,buffer. Once the 'buffer is

Section 10.5 Robust Reading and Writing with the Rio Package 901

2 3

static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n) {

int cnt;

4 !

5 while (rp->rio_cnt <= O) { /• Refill if buf is empty •/

6 rp->rio_cnt = read(rp->rio_fd, rp->rio_buf,

7 sizeof(rp->rio_buf));

B if (rp->rio_cnt < 0) {

9 if (errno != EINTR) /* Interrupted by sig handler return */

10 11

return -1;

}

12 else if (rp->rio_cnt 0) I• EDF •/

13 return O;

14 else ~

15

16 }

'rp->rio_bufptr. rp->rio_buf~ /.-* Reset buffer ptr *I

17

18 /*Copy min(n, rp->rio_cnt) bytes from internal,buf to user buf */

19 cnt = n;

20 if (rp->rio_cnt < n)

21 cnt = rp->rio_c:nt;

22 memcpy(usrbuf, rp->rio_bufptr. cnt);

23 rp->rio_bufptr += cnt;

24 25 26~ }

rp->rio_cnt return cnt;

cnt;

I

---~=---~-"--- code/srdcsapp.c

Figure 10.7 The internal rio_read function.

. '

nonempty, rio_read copies the minimum of n and rp->rio_cnt bytes from the read buffer to the user bJ,lffer and returns the number of bytes coPied.

To an application pr<Jgram, the ~io_read function"haiitqe same semantics as the Linux read function. On error, it returns -.1 and sets errno appropriately. On EOF, it returns 0. It returns a_ short cm,mt if the number of requested bytes exceeds the number of unread bytes in the read buffer. The similarity'of the two functions

r

makes it easy to build different kinds of buffered read functions by substituting rio_read for read. For example, the rio_readnb functfun in"Figure 10.8 has the same structure as rio_readn, with rio_read substituted for read. Similarly, the rio_readlineb routine in Figure 10.8 calls rio_read at most maxien-1 times.

Each call returns 1 byte from the read buffer, which is then checked for being tlie terminating newline.

902 Chapter 1 O System-Level 1/0

---~---code/srdcsapp.c

ssize_t rio_read~ineb(rio_t *rp, void *usrbuf, size_'t maxlen) 2

~ 4 5 6 7 8 9 10 11 12 13 14 15 16 17

ãns

19 20 21 22 23

{

}

int n, re;

char c, *bufp usrbuf;

for (n = 1i n < maxlen; n++) { if ((reã= rio_re~d(tp, &e, 1))

*bufp++ = c;

i f (eã== '\n') {

}

n++;

break;

} else if (re == 0) { i f (n == 1)

1) {

return O; I• EDF, no data read '*/

else break;

} else

return -1;

}

•bufp Oã

return n-1; '

/* EOF, some data was read*/

<

/* Error *I

- - - ' - code!src/csapp.c

--~--- codelsrc/csapp.c

ssize_t rio_readnb(rio~t *rp, void *usrbuf, size~t n)

2 {

3 size_t nlefi = n; , r

4 ssize_t nread;

5 char *bufp = usrbuf;

'" ôii

6

7 while (nleft > 0) {

' ' •r , •} 1 , 1 •I

if ((nread = rio_read(rp, bufp, nleft)) < 0)

8 9 10 11

J" ã~"' • , f ) f

returq -1; I* errno set by read() */

' • •• • ' - ( t ' ~

'll•

12

else if (niead ~= 0) ã

ã~re~'; . . ,/,ã * EDF i} 1'

' j

nleft -= àead;

"

...

bufp += nread;

),

return (n, - nleft)'; " l• Retw;n >= o •I ,,

ã' I

J

---~---code!src/csapp.c

13 14, 15

16 } .,

Figure 10.8 The rio_readlineb and rio_readnb fu~ctions.

Section 10.6 Reading~File Metadata 903

""" 'if""i""41~-""' - . . . - - " " " ' - - ~ ,....,,.

~ )(side 'Origlns' of\he Rib package -

• "' ' < 1' .,,~ ?''' ~ ,j< 't "" , ~., ~

f ""\be Rm fun?tions ~re mspir~d,by the readiine, readn,'and w~i ten functions.described by W. Richard j Stevens m his classic network programmmg'text [110]. The•rJ'.'o_readn and rio_writen f\mct10ns are

identical to the Stevens readn and wri ten furlctions. However;~the Stevens reãa'dline function has some' ' limit~tions that3re"Cbrrected~inãR10. First, beCause readline is buffered ~ii:d ;eadn is not, these two ' function~ ca~ot b~'tls~il togetlier pn \he sam~ descripfoi;. 'Secdnd, beeause 'it uses 'a static buffer, the Stevens readline function knot th'~ead-sati!, which reqilirecfStevens to intj6duce a different thread-

~safe version~called read.line_r. ;We 'have cofrected both of these flaws With the rio_readlineb and rio_readnb fun~tiops1 "'.hich ~re' m~tmi)l_Y coIIJ~atible ~Q,(i!hfead-saJe: : ,

Một phần của tài liệu Computer systems a programmers perspective randal e bryant, david r ohallaron (Trang 933 - 938)

Tải bản đầy đủ (PDF)

(1.120 trang)