5 static int pipeclose(struct Fd
*fd
);
6 static ssize_t
piperead(struct Fd
*fd
, void *buf
, size_t n
, off_t offset
);
7 static int pipestat(struct Fd
*fd
, struct Stat
*stat
);
8 static ssize_t
pipewrite(struct Fd
*fd
, const void *buf
, size_t n
, off_t offset
);
15 .dev_write
= pipewrite
,
16 .dev_close
= pipeclose
,
20 #define PIPEBUFSIZ 32 // small to provoke races
23 off_t p_rpos
; // read position
24 off_t p_wpos
; // write position
25 uint8_t p_buf
[PIPEBUFSIZ
]; // data buffer
35 // allocate the file descriptor table entries
36 if ((r
= fd_alloc(&fd0
)) < 0
37 || (r
= sys_page_alloc(0, fd0
, PTE_P
|PTE_W
|PTE_U
|PTE_SHARE
)) < 0)
40 if ((r
= fd_alloc(&fd1
)) < 0
41 || (r
= sys_page_alloc(0, fd1
, PTE_P
|PTE_W
|PTE_U
|PTE_SHARE
)) < 0)
44 // allocate the pipe structure as first data page in both
46 if ((r
= sys_page_alloc(0, va
, PTE_P
|PTE_W
|PTE_U
|PTE_SHARE
)) < 0)
48 if ((r
= sys_page_map(0, va
, 0, fd2data(fd1
), PTE_P
|PTE_W
|PTE_U
|PTE_SHARE
)) < 0)
51 // set up fd structures
52 fd0
->fd_dev_id
= devpipe
.dev_id
;
53 fd0
->fd_omode
= O_RDONLY
;
55 fd1
->fd_dev_id
= devpipe
.dev_id
;
56 fd1
->fd_omode
= O_WRONLY
;
59 cprintf("[%08x] pipecreate %08x\n", env
->env_id
, vpt
[VPN(va
)]);
66 sys_page_unmap(0, va
);
68 sys_page_unmap(0, fd1
);
70 sys_page_unmap(0, fd0
);
76 _pipeisclosed(struct Fd
*fd
, struct Pipe
*p
)
80 // Check pageref(fd) and pageref(p),
81 // returning 1 if they're the same, 0 otherwise.
83 // The logic here is that pageref(p) is the total
84 // number of readers *and* writers, whereas pageref(fd)
85 // is the number of file descriptors like fd (readers if fd is
86 // a reader, writers if fd is a writer).
88 // If the number of file descriptors like fd is equal
89 // to the total number of readers and writers, then
90 // everybody left is what fd is. So the other end of
91 // the pipe is closed.
97 if (pageref(fd
) == pageref(p
))
99 } while (runs
!= env
->env_runs
);
105 pipeisclosed(int fdnum
)
111 if ((r
= fd_lookup(fdnum
, &fd
)) < 0)
113 p
= (struct Pipe
*) fd2data(fd
);
114 return _pipeisclosed(fd
, p
);
118 piperead(struct Fd
*fd
, void *vbuf
, size_t n
, off_t offset
)
120 // Your code here. See the lab text for a description of
121 // what piperead needs to do. Write a loop that
122 // transfers one byte at a time. If you decide you need
123 // to yield (because the pipe is empty), only yield if
124 // you have not yet copied any bytes. (If you have copied
125 // some bytes, return what you have instead of yielding.)
126 // If the pipe is empty and closed and you didn't copy any data out,
128 // Use _pipeisclosed to check whether the pipe is closed.
136 p
= (struct Pipe
*)fd2data(fd
);
138 for (i
= 0; i
< n
; i
++) {
139 while (p
->p_rpos
>= p
->p_wpos
) {
140 // copied some bytes, then just return
144 // i.e. have not yet copied any bytes
145 if (_pipeisclosed(fd
, p
))
149 buf
[i
] = p
->p_buf
[p
->p_rpos
% PIPEBUFSIZ
];
156 pipewrite(struct Fd
*fd
, const void *vbuf
, size_t n
, off_t offset
)
158 // Your code here. See the lab text for a description of what
159 // pipewrite needs to do. Write a loop that transfers one byte
160 // at a time. Unlike in read, it is not okay to write only some
161 // of the data. If the pipe fills and you've only copied some of
162 // the data, wait for the pipe to empty and then keep copying.
163 // If the pipe is full and closed, return 0.
164 // Use _pipeisclosed to check whether the pipe is closed.
172 p
= (struct Pipe
*)fd2data(fd
);
174 for (i
= 0; i
< n
; i
++) {
175 while (p
->p_wpos
- p
->p_rpos
>= PIPEBUFSIZ
) {
176 if (_pipeisclosed(fd
, p
))
180 p
->p_buf
[p
->p_wpos
% PIPEBUFSIZ
] = buf
[i
];
187 pipestat(struct Fd
*fd
, struct Stat
*stat
)
189 struct Pipe
*p
= (struct Pipe
*) fd2data(fd
);
190 strcpy(stat
->st_name
, "<pipe>");
191 stat
->st_size
= p
->p_wpos
- p
->p_rpos
;
193 stat
->st_dev
= &devpipe
;
198 pipeclose(struct Fd
*fd
)
204 if ((r
= sys_page_unmap(0, fd
)) < 0)
206 return sys_page_unmap(0, p
);