summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordzwdz2022-07-09 20:47:13 +0200
committerdzwdz2022-07-09 20:47:13 +0200
commitfff36661c92f30685e2d83825a11b67ad8921a0e (patch)
tree7711025c8ad988e48a5925c546151e6c1cfa96fe /src
parentfcfb57c12ce4544017098092a66f8427584c1879 (diff)
kernel/pipes: process queueing
Diffstat (limited to 'src')
-rw-r--r--src/init/tests/pipe.c66
-rw-r--r--src/kernel/pipe.c19
-rw-r--r--src/kernel/proc.c3
-rw-r--r--src/kernel/proc.h1
4 files changed, 69 insertions, 20 deletions
diff --git a/src/init/tests/pipe.c b/src/init/tests/pipe.c
index e03c485..a980cb8 100644
--- a/src/init/tests/pipe.c
+++ b/src/init/tests/pipe.c
@@ -51,28 +51,68 @@ void test_pipe(void) {
/* writing to pipes with one end closed */
assert(_syscall_pipe(ends, 0) >= 0);
- if (!_syscall_fork(0, NULL)) {
- _syscall_close(ends[1]);
- assert(_syscall_read(ends[0], buf, 16, 0) < 0);
- _syscall_exit(0);
- } else {
- _syscall_close(ends[1]);
+ for (int i = 0; i < 16; i++) {
+ if (!_syscall_fork(0, NULL)) {
+ _syscall_close(ends[1]);
+ assert(_syscall_read(ends[0], buf, 16, 0) < 0);
+ _syscall_exit(0);
+ }
+ }
+ _syscall_close(ends[1]);
+ for (int i = 0; i < 16; i++)
_syscall_await();
+ _syscall_close(ends[0]);
+
+ assert(_syscall_pipe(ends, 0) >= 0);
+ for (int i = 0; i < 16; i++) {
+ if (!_syscall_fork(0, NULL)) {
+ _syscall_close(ends[0]);
+ assert(_syscall_write(ends[1], buf, 16, 0) < 0);
+ _syscall_exit(0);
+ }
}
+ _syscall_close(ends[0]);
+ for (int i = 0; i < 16; i++)
+ _syscall_await();
+ _syscall_close(ends[1]);
+
+ /* queueing */
assert(_syscall_pipe(ends, 0) >= 0);
- if (!_syscall_fork(0, NULL)) {
- _syscall_close(ends[0]);
- assert(_syscall_write(ends[1], buf, 16, 0) < 0);
- _syscall_exit(0);
- } else {
- _syscall_close(ends[0]);
+ for (int i = 0; i < 16; i++) {
+ if (!_syscall_fork(0, NULL)) {
+ assert(_syscall_write(ends[1], pipe_msgs[0], 5, -1) == 5);
+ _syscall_exit(0);
+ }
+ }
+ _syscall_close(ends[1]);
+ for (int i = 0; i < 16; i++) {
+ assert(_syscall_read(ends[0], buf, sizeof buf, 0) == 5);
_syscall_await();
}
+ assert(_syscall_read(ends[0], buf, sizeof buf, 0) < 0);
+ _syscall_close(ends[0]);
+
+ assert(_syscall_pipe(ends, 0) >= 0);
+ for (int i = 0; i < 16; i++) {
+ if (!_syscall_fork(0, NULL)) {
+ memset(buf, 0, sizeof buf);
+ assert(_syscall_read(ends[0], buf, 5, -1) == 5);
+ assert(!memcmp(buf, pipe_msgs[1], 5));
+ _syscall_exit(0);
+ }
+ }
+ _syscall_close(ends[0]);
+ for (int i = 0; i < 16; i++) {
+ assert(_syscall_write(ends[1], pipe_msgs[1], 5, -1) == 5);
+ _syscall_await();
+ }
+ assert(_syscall_write(ends[1], pipe_msgs[1], 5, -1) < 0);
+ _syscall_close(ends[1]);
+
// not a to.do detect when all processes that can read are stuck on writing to the pipe and vice versa
// it seems like linux just lets the process hang endlessly.
// TODO kill process that's waiting on a pipe
- // TODO queue
}
diff --git a/src/kernel/pipe.c b/src/kernel/pipe.c
index 34cb263..edd1388 100644
--- a/src/kernel/pipe.c
+++ b/src/kernel/pipe.c
@@ -9,16 +9,19 @@ bool pipe_joinqueue(struct handle *h, bool wants_write,
assert(h && h->type == HANDLE_PIPE);
if (wants_write == h->pipe.write_end) return false;
if (!h->pipe.sister) return false;
- if (h->pipe.queued) {
- assert(h->pipe.queued->state == PS_WAITS4PIPE);
- panic_unimplemented();
+
+ struct process **slot = &h->pipe.queued;
+ while (*slot) {
+ assert((*slot)->state == PS_WAITS4PIPE);
+ slot = &((*slot)->waits4pipe.next);
}
process_transition(proc, PS_WAITS4PIPE);
- h->pipe.queued = proc;
+ *slot = proc;
proc->waits4pipe.pipe = h;
proc->waits4pipe.buf = pbuf;
proc->waits4pipe.len = pbuflen;
+ proc->waits4pipe.next = NULL;
return true;
}
@@ -46,19 +49,21 @@ void pipe_trytransfer(struct handle *h) {
{
panic_unimplemented();
}
+ h->pipe.queued = h->pipe.queued->waits4pipe.next;
+ h->pipe.sister->pipe.queued = h->pipe.sister->pipe.queued->waits4pipe.next;
process_transition(rdr, PS_RUNNING);
process_transition(wtr, PS_RUNNING);
- h->pipe.queued = NULL;
- h->pipe.sister->pipe.queued = NULL;
regs_savereturn(&rdr->regs, len);
regs_savereturn(&wtr->regs, len);
}
void pipe_invalidate_end(struct handle *h) {
struct process *p = h->pipe.queued;
- if (p) {
+ while (p) {
+ assert(p->state == PS_WAITS4PIPE);
process_transition(p, PS_RUNNING);
regs_savereturn(&p->regs, -1);
+ p = p->waits4pipe.next;
}
h->pipe.queued = NULL;
}
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index c69cb14..86170aa 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -116,6 +116,9 @@ void process_kill(struct process *p, int ret) {
if (p->state == PS_WAITS4FS)
p->waits4fs.req->caller = NULL;
+ if (p->state == PS_WAITS4PIPE)
+ panic_unimplemented();
+
for (handle_t h = 0; h < HANDLE_MAX; h++)
handle_close(p->handles[h]);
diff --git a/src/kernel/proc.h b/src/kernel/proc.h
index 20585bc..c400f7d 100644
--- a/src/kernel/proc.h
+++ b/src/kernel/proc.h
@@ -47,6 +47,7 @@ struct process {
struct handle *pipe;
char __user *buf;
size_t len;
+ struct process *next;
} waits4pipe;
};
struct vfs_request *handled_req;