commit 1f846556907895e491d5dfeea711b93dc4d38787
parent 11d57f50f23ea8fffe3bdabd37f9ecf8c9e1b3f4
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Sun, 25 Oct 2020 22:47:38 +0100
os9/proc: Add rfork()
Change-Id: I627931dd9348c0d212ca046b87702c30b7f9564f
Diffstat:
2 files changed, 123 insertions(+), 5 deletions(-)
diff --git a/include/os9/os9.h b/include/os9/os9.h
@@ -48,6 +48,15 @@ typedef struct nspace Nspace;
typedef struct fdset Fdset;
typedef struct ref Ref;
+enum rforkflags {
+ RFPROC = 1 << 0,
+ RFNAMEG = 1 << 1,
+ RFCNAMEG = 1 << 2,
+ RFFDG = 1 << 3,
+ RFCFDG = 1 << 4,
+ RFMEM = 1 << 5,
+};
+
enum barrier_type {
CODE,
DATA,
@@ -98,7 +107,13 @@ enum map_attr {
MD = 1 << 3,
};
+struct ref {
+ mutex_t m;
+ int cnt;
+};
+
struct map {
+ Ref ref;
char *name;
unsigned perm;
@@ -144,11 +159,6 @@ struct chan {
mutex_t mutex;
};
-struct ref {
- mutex_t m;
- int cnt;
-};
-
struct mpoint {
Chan *new;
Chan *old;
diff --git a/src/os9/proc.c b/src/os9/proc.c
@@ -1,5 +1,6 @@
#include <os9/os9.h>
+#include <errno.h>
#include <limits.h>
struct nspace {
@@ -8,6 +9,12 @@ struct nspace {
struct mpoint mpoints[NR_MPOINTS];
};
+struct fdset {
+ Ref ref;
+ mutex_t m;
+ Chan fdset[NR_CHANS];
+};
+
static Task tasktab[NR_TASKS];
static void
@@ -108,3 +115,104 @@ newspace(Nspace *from)
return ns;
}
+
+static Fdset *
+newfds(Fdset *from)
+{
+ Fdset *fds;
+
+ fds = alloc(sizeof(*fds));
+ if (from)
+ *fds = *from;
+ initref(&fds->ref);
+
+ return fds;
+}
+
+static Map *
+newmap(Map *from)
+{
+ Map *mp;
+
+ mp = alloc(sizeof(*mp));
+ if (from)
+ *mp = *from;
+ initref(&mp->ref);
+
+ return mp;
+}
+
+int
+rfork(int flags)
+{
+ Task *tp, *parent;
+ int tid;
+
+ tp = parent = task;
+
+ if ((flags & (RFPROC|RFMEM)) == RFPROC|RFMEM
+ || (flags & (RFNAMEG|RFCNAMEG)) == RFNAMEG|RFCNAMEG
+ || (flags & (RFFDG|RFCFDG)) == RFFDG|RFCFDG) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((flags & RFPROC) != 0) {
+ if ((tp = newslot()) == NULL)
+ return -1;
+
+ for (tp = tasktab; tp < &tasktab[NR_TASKS]; ++tp) {
+ if (tp->mode == PDISABLED)
+ break;
+ }
+
+ if (tp == &tasktab[NR_TASKS] || (tid = newtid()) < 0) {
+ errno = ENOMEM;
+ return -1;
+ }
+ tp->tid = tid;
+
+ incref(&parent->text->ref);
+ tp->text = parent->text;
+
+ incref(&parent->data->ref);
+ tp->data = parent->data;
+
+ incref(&parent->stack->ref);
+ tp->stack = parent->stack;
+
+ incref(&parent->ns->ref);
+ tp->ns = parent->ns;
+
+ incref(&parent->fds->ref);
+ tp->fds = parent->fds;
+ }
+
+ if ((flags & RFCNAMEG) != 0) {
+ decref(&tp->ns->ref);
+ tp->ns = newspace(NULL);
+ incref(&tp->ns->ref);
+ }
+ if ((flags & RFNAMEG) != 0) {
+ decref(&tp->ns->ref);
+ tp->ns = newspace(parent->ns);
+ incref(&tp->ns->ref);
+ }
+ if ((flags & RFCFDG) != 0) {
+ decref(&tp->fds->ref);
+ tp->fds = newfds(NULL);
+ incref(&tp->fds->ref);
+ }
+ if ((flags & RFFDG) != 0) {
+ decref(&tp->fds->ref);
+ tp->fds = newfds(parent->fds);
+ incref(&tp->fds->ref);
+ }
+ if ((flags & RFCFDG) != 0) {
+ decref(&tp->data->ref);
+ tp->data = newmap(parent->data);
+ incref(&tp->data->ref);
+ }
+
+ return (flags & RFPROC) ? tp->tid : 0;
+}