aboutsummaryrefslogtreecommitdiff
path: root/src/libthread/create.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libthread/create.c')
-rw-r--r--src/libthread/create.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/src/libthread/create.c b/src/libthread/create.c
new file mode 100644
index 00000000..ab803a2c
--- /dev/null
+++ b/src/libthread/create.c
@@ -0,0 +1,182 @@
+#include "threadimpl.h"
+
+#define free
+Pqueue _threadpq;
+
+static int nextID(void);
+
+/*
+ * Create and initialize a new Thread structure attached to a given proc.
+ */
+
+typedef struct Stack Stack;
+struct Stack {
+ ulong magic;
+ Thread *thr;
+ Stack *next;
+ uchar buf[STKSIZE-12];
+};
+
+static Stack *stkfree;
+static Lock stklock;
+
+void
+_stackfree(void *v)
+{
+ Stack *s;
+
+ s = v;
+ lock(&stklock);
+ s->thr = nil;
+ s->magic = 0;
+ s->next = stkfree;
+ stkfree = s;
+ unlock(&stklock);
+}
+
+static Stack*
+stackalloc(void)
+{
+ char *buf;
+ Stack *s;
+ int i;
+
+ lock(&stklock);
+ while(stkfree == nil){
+ unlock(&stklock);
+ assert(STKSIZE == sizeof(Stack));
+ buf = malloc(STKSIZE+128*STKSIZE);
+ s = (Stack*)(((ulong)buf+STKSIZE)&~(STKSIZE-1));
+ for(i=0; i<128; i++)
+ _stackfree(&s[i]);
+ lock(&stklock);
+ }
+ s = stkfree;
+ stkfree = stkfree->next;
+ unlock(&stklock);
+ s->magic = STKMAGIC;
+ return s;
+}
+
+static int
+newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp)
+{
+ int id;
+ Thread *t;
+ Stack *s;
+
+ if(stacksize < 32)
+ sysfatal("bad stacksize %d", stacksize);
+ t = _threadmalloc(sizeof(Thread), 1);
+ s = stackalloc();
+ s->thr = t;
+ t->stk = (char*)s;
+ t->stksize = STKSIZE;
+ _threaddebugmemset(s->buf, 0xFE, sizeof s->buf);
+ _threadinitstack(t, f, arg);
+ t->proc = p;
+ t->grp = grp;
+ if(name)
+ t->cmdname = strdup(name);
+ t->id = nextID();
+ id = t->id;
+ t->next = (Thread*)~0;
+ _threaddebug(DBGSCHED, "create thread %d.%d name %s", p->pid, t->id, name);
+ lock(&p->lock);
+ p->nthreads++;
+ if(p->threads.head == nil)
+ p->threads.head = t;
+ else{
+ t->prevt = p->threads.tail;
+ t->prevt->nextt = t;
+ }
+ p->threads.tail = t;
+ t->state = Ready;
+ _threadready(t);
+ unlock(&p->lock);
+ return id;
+}
+
+static int
+nextID(void)
+{
+ static Lock l;
+ static int id;
+ int i;
+
+ lock(&l);
+ i = ++id;
+ unlock(&l);
+ return i;
+}
+
+int
+procrfork(void (*f)(void *), void *arg, uint stacksize, int rforkflag)
+{
+ Proc *p;
+ int id;
+
+ p = _threadgetproc();
+ assert(p->newproc == nil);
+ p->newproc = _newproc(f, arg, stacksize, nil, p->thread->grp, rforkflag);
+ id = p->newproc->threads.head->id;
+ _sched();
+ return id;
+}
+
+int
+proccreate(void (*f)(void*), void *arg, uint stacksize)
+{
+ return procrfork(f, arg, stacksize, 0);
+}
+
+void
+_freeproc(Proc *p)
+{
+ Thread *t, *nextt;
+
+ for(t = p->threads.head; t; t = nextt){
+ if(t->cmdname)
+ free(t->cmdname);
+ assert(t->stk != nil);
+ _stackfree((Stack*)t->stk);
+ nextt = t->nextt;
+ free(t);
+ }
+ free(p);
+}
+
+/*
+ * Create a new thread and schedule it to run.
+ * The thread grp is inherited from the currently running thread.
+ */
+int
+threadcreate(void (*f)(void *arg), void *arg, uint stacksize)
+{
+ return newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
+}
+
+/*
+ * Create and initialize a new Proc structure with a single Thread
+ * running inside it. Add the Proc to the global process list.
+ */
+Proc*
+_newproc(void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp, int rforkflag)
+{
+ Proc *p;
+
+ p = _threadmalloc(sizeof *p, 1);
+ p->pid = -1;
+ p->rforkflag = rforkflag;
+ newthread(p, f, arg, stacksize, name, grp);
+
+ lock(&_threadpq.lock);
+ if(_threadpq.head == nil)
+ _threadpq.head = p;
+ else
+ *_threadpq.tail = p;
+ _threadpq.tail = &p->next;
+ unlock(&_threadpq.lock);
+ return p;
+}
+