* same with xv6
[mascara-docs.git] / i386 / ucla / src / lab5 / lib / pipe.c
blobdb30760034e401dce6aa8b79653b45279d887775
1 #include <inc/lib.h>
3 #define debug 0
5 static ssize_t devpipe_read(struct Fd *fd, void *buf, size_t n);
6 static ssize_t devpipe_write(struct Fd *fd, const void *buf, size_t n);
7 static int devpipe_stat(struct Fd *fd, struct Stat *stat);
8 static int devpipe_close(struct Fd *fd);
10 struct Dev devpipe =
12 /* .dev_id = */ 'p',
13 /* .dev_name = */ "pipe",
14 /* .dev_read = */ devpipe_read,
15 /* .dev_write = */ devpipe_write,
16 /* .dev_close = */ devpipe_close,
17 /* .dev_stat = */ devpipe_stat,
18 /* .dev_trunc = */ 0
21 #define PIPEBUFSIZ 32 // small to provoke races
23 struct Pipe {
24 off_t p_rpos; // read position
25 off_t p_wpos; // write position
26 uint8_t p_buf[PIPEBUFSIZ]; // data buffer
29 int
30 pipe(int pfd[2])
32 int r;
33 struct Fd *fd0, *fd1;
34 void *va;
36 // allocate the file descriptor table entries
37 if ((r = fd_find_unused(&fd0)) < 0
38 || (r = sys_page_alloc(0, fd0, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
39 goto err;
41 if ((r = fd_find_unused(&fd1)) < 0
42 || (r = sys_page_alloc(0, fd1, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
43 goto err1;
45 // allocate the pipe structure as first data page in both
46 va = fd2data(fd0);
47 if ((r = sys_page_alloc(0, va, PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
48 goto err2;
49 if ((r = sys_page_map(0, va, 0, fd2data(fd1), PTE_P|PTE_W|PTE_U|PTE_SHARE)) < 0)
50 goto err3;
52 // set up fd structures
53 fd0->fd_dev_id = devpipe.dev_id;
54 fd0->fd_omode = O_RDONLY;
56 fd1->fd_dev_id = devpipe.dev_id;
57 fd1->fd_omode = O_WRONLY;
59 if (debug)
60 cprintf("[%08x] pipecreate %08x\n", thisenv->env_id, vpt[PGNUM(va)]);
62 pfd[0] = fd2num(fd0);
63 pfd[1] = fd2num(fd1);
64 return 0;
66 err3:
67 sys_page_unmap(0, va);
68 err2:
69 sys_page_unmap(0, fd1);
70 err1:
71 sys_page_unmap(0, fd0);
72 err:
73 return r;
76 static int
77 _pipeisclosed(struct Fd *fd, struct Pipe *p)
79 // Check pageref(fd) and pageref(p),
80 // returning 1 if they're the same, 0 otherwise.
82 // The logic here is that pageref(p) is the total
83 // number of readers *and* writers, whereas pageref(fd)
84 // is the number of file descriptors like fd (readers if fd is
85 // a reader, writers if fd is a writer).
87 // If the number of file descriptors like fd is equal
88 // to the total number of readers and writers, then
89 // everybody left is what fd is. So the other end of
90 // the pipe is closed.
92 // LAB 5: Your code here.
94 panic("_pipeisclosed not implemented");
95 return 0;
98 int
99 pipeisclosed(int fdnum)
101 struct Fd *fd;
102 struct Pipe *p;
103 int r;
105 if ((r = fd_lookup(fdnum, &fd, true)) < 0)
106 return r;
107 p = (struct Pipe*) fd2data(fd);
108 return _pipeisclosed(fd, p);
111 static ssize_t
112 devpipe_read(struct Fd *fd, void *vbuf, size_t n)
114 struct Pipe *p = (struct Pipe *) fd2data(fd);
115 uint8_t *buf = (uint8_t *) vbuf;
116 size_t i;
118 for (i = 0; i < n; i++) {
119 while (p->p_rpos == p->p_wpos) {
120 // The pipe is currently empty.
121 // If any data has been read, return it.
122 // Otherwise, check for EOF; if not EOF, yield
123 // and try again.
124 if (i > 0)
125 return i;
126 else if (_pipeisclosed(fd, p))
127 return 0;
128 else
129 sys_yield();
132 buf[i] = p->p_buf[p->p_rpos % PIPEBUFSIZ];
133 // The increment must come AFTER we write to the buffer,
134 // or the C compiler might update the pointer before writing
135 // to the buffer! In fact, we need a memory barrier here---
136 // on some machines a memory barrier instruction.
137 asm volatile("" : : : "memory");
138 p->p_rpos++;
141 return i;
144 static ssize_t
145 devpipe_write(struct Fd *fd, const void *vbuf, size_t n)
147 // Write a loop that transfers one byte at a time.
148 // Your code should be patterned on pipe_read above.
149 // Unlike in read, it is not okay to write only some of the data:
150 // if the pipe fills and you've only copied some of the data,
151 // wait for the pipe to empty and then keep copying.
152 // If the pipe is full and closed, return the number of characters
153 // written. Use _pipeisclosed to check whether the pipe is closed.
155 // LAB 5: Your code here.
157 panic("devpipe_write not implemented");
158 return -E_INVAL;
161 static int
162 devpipe_stat(struct Fd *fd, struct Stat *stat)
164 struct Pipe *p = (struct Pipe*) fd2data(fd);
165 strcpy(stat->st_name, "<pipe>");
166 stat->st_size = p->p_wpos - p->p_rpos;
167 stat->st_ftype = FTYPE_REG;
168 stat->st_dev = &devpipe;
169 return 0;
172 static int
173 devpipe_close(struct Fd *fd)
175 (void) sys_page_unmap(0, fd);
176 return sys_page_unmap(0, fd2data(fd));