AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
pipe.c
Go to the documentation of this file.
1
6
7#include <core/system.h>
8
9#include <ds/ringbuf.h>
10#include <aquila/fcntl.h>
11
12#include <fs/pipe.h>
13#include <fs/posix.h>
14#include <sys/sched.h>
15#include <sys/signal.h>
16
17MALLOC_DEFINE(M_PIPE, "pipe", "pipe structure");
18
19/*
20 * A pipe has a vnode for each end, which the end's open files reference;
21 * when the last one is closed, the end is gone. An anonymous pipe
22 * (pipe()) has both ends from the start. A FIFO makes them as it is
23 * opened, and a third one for opening it read-write, which is both.
24 */
25
27
29static int has_readers(struct pipe *pipe)
30{
31 return pipe->r_node || pipe->rw_node;
32}
33
35static int has_writers(struct pipe *pipe)
36{
37 return pipe->w_node || pipe->rw_node;
38}
39
41static void pipefs_pfree(struct pipe *pipe)
42{
43 if (pipe) {
44 if (pipe->ring)
45 ringbuf_free(pipe->ring);
46 kfree(pipe);
47 }
48}
49
51static ssize_t pipefs_read(struct vnode *node, off_t offset __unused, struct iobuf *io)
52{
53 struct pipe *pipe = node->p;
54 return ringbuf_read_iobuf(pipe->ring, io->resid, io);
55}
56
59static ssize_t pipefs_write(struct vnode *node, off_t offset __unused, struct iobuf *io)
60{
61 struct pipe *pipe = node->p;
62
63 /* no one left to read the data */
64 if (!has_readers(pipe))
65 return -EPIPE;
66
67 return ringbuf_write_iobuf(pipe->ring, io->resid, io);
68}
69
73static int pipefs_close(struct vnode *node)
74{
75 struct pipe *pipe = node->p;
76
77 if (node == pipe->w_node)
78 pipe->w_node = NULL;
79 else if (node == pipe->rw_node)
80 pipe->rw_node = NULL;
81 else
82 pipe->r_node = NULL;
83
84 kfree(node);
85
86 if (!has_readers(pipe) && !has_writers(pipe)) {
87 /* a FIFO loses its data once no one has it open */
88 if (pipe->fifo) {
89 pipe->fifo->fifo = NULL;
91 }
92
94 return 0;
95 }
96
97 /* wake up the other end, so that it sees the end of the file, or
98 * EPIPE */
100 return 0;
101}
102
105static int pipefs_eof(struct file *file)
106{
107 struct pipe *pipe = file->vnode->p;
108
109 return !has_writers(pipe) && !ringbuf_available(pipe->ring);
110}
111
113static int pipefs_can_read(struct file *file, size_t size)
114{
115 struct vnode *node = file->vnode;
116 struct pipe *pipe = node->p;
117
118 if (!has_writers(pipe)) /* the read won't wait: it returns 0 */
119 return 1;
120
121 return size <= ringbuf_available(pipe->ring);
122}
123
125static int pipefs_can_write(struct file *file, size_t size)
126{
127 struct vnode *node = file->vnode;
128 struct pipe *pipe = node->p;
129 size_t avail = ringbuf_available(pipe->ring);
130
131 if (!has_readers(pipe)) /* the write won't wait: it fails with EPIPE */
132 return 1;
133
134 /* the ring buffer holds at most size - 1 bytes */
135 if (avail >= pipe->ring->size - 1)
136 return 0;
137
138 return size <= pipe->ring->size - 1 - avail;
139}
140
142static int pipefs_mkpipe(struct pipe **ref)
143{
144 struct pipe *pipe;
145
146 pipe = kmalloc(sizeof(struct pipe), &M_PIPE, M_ZERO);
147 if (!pipe) return -ENOMEM;
148
149 pipe->ring = ringbuf_new(PIPE_BUFLEN);
150
151 if (!pipe->ring) {
153 return -ENOMEM;
154 }
155
156 if (ref) *ref = pipe;
157
158 return 0;
159}
160
163static struct vnode *pipefs_end(struct pipe *pipe, int which)
164{
165 struct vnode **end = which == END_READ ? &pipe->r_node :
166 which == END_WRITE ? &pipe->w_node : &pipe->rw_node;
167
168 if (*end) {
169 (*end)->ref++;
170 return *end;
171 }
172
173 struct vnode *node = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);
174 if (!node)
175 return NULL;
176
177 /* readers and writers share one wait queue: readers sleep on the
178 * read queue and wake the write queue, writers the opposite */
179 node->read_queue = &pipe->queue;
180 node->write_queue = &pipe->queue;
181
182 node->fs = &pipefs;
183 node->p = pipe;
184 node->ref = 1;
185 node->mode = S_IFIFO | 0600;
186
187 *end = node;
188 return node;
189}
190
199int pipefs_pipe(struct file *read, struct file *write)
200{
201 int err = 0;
202 struct pipe *pipe = NULL;
203
204 if (!read || !write)
205 return -EINVAL;
206
207 if ((err = pipefs_mkpipe(&pipe)))
208 return err;
209
210 read->vnode = pipefs_end(pipe, END_READ);
211 if (!read->vnode) {
213 return -ENOMEM;
214 }
215
216 write->vnode = pipefs_end(pipe, END_WRITE);
217 if (!write->vnode) {
218 kfree(read->vnode);
220 return -ENOMEM;
221 }
222
223 write->flags = O_WRONLY;
224 return 0;
225}
226
240{
241 struct vnode *fifo = file->vnode;
242 struct pipe *pipe = fifo->fifo;
243 int accmode = file->flags & O_ACCMODE;
244 int err;
245
246 if (!pipe) {
247 if ((err = pipefs_mkpipe(&pipe)))
248 return err;
249
250 /* the pipe holds the reference the open came with */
251 pipe->fifo = fifo;
252 fifo->fifo = pipe;
253 fifo->ref++;
254 }
255
256 if (accmode == O_WRONLY && (file->flags & O_NONBLOCK) && !has_readers(pipe)) {
257 err = -ENXIO;
258 goto error;
259 }
260
261 int which = accmode == O_RDONLY ? END_READ : accmode == O_WRONLY ? END_WRITE : END_RDWR;
262 struct vnode *end = pipefs_end(pipe, which);
263
264 if (!end)
265 goto e_nomem;
266
267 if (which != END_WRITE)
268 pipe->r_opens++;
269 if (which != END_READ)
270 pipe->w_opens++;
271
272 /* the other end may be waiting for this one */
274
275 /* wait until the other side opens, or has opened: one that opened,
276 * wrote and closed while this one waited to run again counts too
277 * (POSIX) */
278 unsigned long r_seen = pipe->r_opens, w_seen = pipe->w_opens;
279
280 if (!(file->flags & O_NONBLOCK)) {
281 while (which == END_READ ? !has_writers(pipe) && pipe->w_opens == w_seen :
282 which == END_WRITE ? !has_readers(pipe) && pipe->r_opens == r_seen : 0) {
283 if ((err = waitq_sleep(&pipe->queue))) {
284 /* this releases the pipe too, if it was its only end */
285 vfs_close(end);
286 return err;
287 }
288 }
289 }
290
292 file->vnode = end;
293 return 0;
294
295e_nomem:
296 err = -ENOMEM;
297error:
298 /* if nothing else uses the pipe, it goes */
299 if (!has_readers(pipe) && !has_writers(pipe)) {
300 fifo->fifo = NULL;
303 }
304
305 return err;
306}
307
308struct fs pipefs = {
309 .name = "pipefs",
310
311 .vops = {
312 .read = pipefs_read,
313 .write = pipefs_write,
314 .close = pipefs_close,
315 },
316
317 .fops = {
318 .read = posix_file_read,
319 .write = posix_file_write,
320 .close = posix_file_close,
321
322 .can_read = pipefs_can_read,
323 .can_write = pipefs_can_write,
324 .eof = pipefs_eof,
325 },
326};
int vfs_close(struct vnode *vnode)
Drops a reference to a vnode.
Definition close.c:18
#define MALLOC_DEFINE(type, _name, _desc)
Definition kvmem.h:30
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
#define M_ZERO
Definition kvmem.h:26
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
@ END_RDWR
Definition pipe.c:26
@ END_READ
Definition pipe.c:26
@ END_WRITE
Definition pipe.c:26
static struct vnode * pipefs_end(struct pipe *pipe, int which)
Returns a new reference to an end of a pipe (END_*), making the end if it doesn't exist yet,...
Definition pipe.c:163
struct fs pipefs
Definition pipe.c:308
static ssize_t pipefs_write(struct vnode *node, off_t offset, struct iobuf *io)
Writes into the pipe's ring buffer, as much as fits.
Definition pipe.c:59
static int has_writers(struct pipe *pipe)
Says whether a pipe has an end open for writing.
Definition pipe.c:35
static int pipefs_can_read(struct file *file, size_t size)
Says whether a read of size bytes would go on without waiting.
Definition pipe.c:113
static ssize_t pipefs_read(struct vnode *node, off_t offset, struct iobuf *io)
Reads what the pipe's ring buffer has, up to what is asked for.
Definition pipe.c:51
int pipefs_fifo_open(struct file *file)
Opens a FIFO: the open file's vnode becomes an end of the FIFO's pipe, made by its first open.
Definition pipe.c:239
static int pipefs_eof(struct file *file)
Says whether a read is at the end of the file: no writers are left, and the pipe is empty.
Definition pipe.c:105
int pipefs_pipe(struct file *read, struct file *write)
Makes an anonymous pipe, for pipe(): one open file for each end.
Definition pipe.c:199
static int pipefs_can_write(struct file *file, size_t size)
Says whether a write of size bytes would go on without waiting.
Definition pipe.c:125
static void pipefs_pfree(struct pipe *pipe)
Frees a pipe and its ring buffer.
Definition pipe.c:41
static int has_readers(struct pipe *pipe)
Says whether a pipe has an end open for reading.
Definition pipe.c:29
static int pipefs_mkpipe(struct pipe **ref)
Makes a new pipe, with no ends.
Definition pipe.c:142
static int pipefs_close(struct vnode *node)
Closes an end of a pipe, when its last open file is closed.
Definition pipe.c:73
#define PIPE_BUFLEN
Definition pipe.h:14
int posix_file_close(struct file *file)
Closes an open file by dropping its reference to its vnode.
Definition close.c:15
ssize_t posix_file_read(struct file *file, struct iobuf *io)
Reads from an open file at its offset, and moves the offset past what was read.
Definition read.c:29
ssize_t posix_file_write(struct file *file, struct iobuf *io)
Writes to an open file at its offset, and moves the offset past what was written.
Definition write.c:25
#define NULL
Definition stddef.h:27
An open file (POSIX's "open file description", fs/file.c).
Definition vfs.h:157
int flags
Definition vfs.h:164
A filesystem type.
Definition vfs.h:98
An iobuf.
Definition iobuf.h:35
size_t resid
Definition iobuf.h:38
A pipe, or a FIFO's pipe.
Definition pipe.h:17
struct waitq queue
readers and writers sleep here
Definition pipe.h:24
struct vnode * r_node
its ends, NULL once closed (rw_node: a FIFO opened read-write)
Definition pipe.h:19
struct vnode * w_node
Definition pipe.h:20
unsigned long w_opens
Definition pipe.h:30
struct vnode * fifo
the FIFO this is the pipe of, or NULL for pipe()
Definition pipe.h:33
struct ringbuf * ring
the data written, not read yet
Definition pipe.h:36
unsigned long r_opens
how many times a FIFO was opened for reading and for writing, so far: an open waiting for the other s...
Definition pipe.h:29
struct vnode * rw_node
Definition pipe.h:21
size_t size
Definition ringbuf.h:20
A file in memory (a vnode): what its inode says, and the kernel's own state.
Definition vfs.h:113
struct waitq * write_queue
Definition vfs.h:137
size_t ref
how many references there are to it
Definition vfs.h:133
struct fs * fs
Definition vfs.h:127
struct waitq * read_queue
where its readers and writers sleep
Definition vfs.h:136
void * p
the filesystem's own data
Definition vfs.h:130
mode_t mode
Definition vfs.h:118
struct pipe * fifo
the pipe of a FIFO while it is open
Definition vfs.h:143
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10
void waitq_wakeup(struct waitq *waitq)
Wakes up every thread sleeping on a wait queue, and every thread polling it.
Definition waitq.c:178
int waitq_sleep(struct waitq *waitq)
Puts the current thread to sleep on a wait queue until it is woken up.
Definition waitq.c:50