Blob


1 #include "threadimpl.h"
3 Pqueue _threadpq;
4 int _threadprocs;
6 static int nextID(void);
8 /*
9 * Create and initialize a new Thread structure attached to a given proc.
10 */
11 void
12 _stackfree(void *v)
13 {
14 free(v);
15 }
17 static int
18 newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp)
19 {
20 int id;
21 Thread *t;
22 char *s;
24 if(stacksize < 32)
25 sysfatal("bad stacksize %d", stacksize);
26 t = _threadmalloc(sizeof(Thread), 1);
27 t->lastfd = -1;
28 s = _threadmalloc(stacksize, 0);
29 t->stk = (uchar*)s;
30 t->stksize = stacksize;
31 _threaddebugmemset(s, 0xFE, stacksize);
32 _threadinitstack(t, f, arg);
33 t->proc = p;
34 t->grp = grp;
35 if(name)
36 t->cmdname = strdup(name);
37 t->id = nextID();
38 id = t->id;
39 t->next = (Thread*)~0;
40 _threaddebug(DBGSCHED, "create thread %d.%d name %s", p->pid, t->id, name);
41 lock(&p->lock);
42 p->nthreads++;
43 if(p->threads.head == nil)
44 p->threads.head = t;
45 else{
46 t->prevt = p->threads.tail;
47 t->prevt->nextt = t;
48 }
49 p->threads.tail = t;
50 t->state = Ready;
51 _threadready(t);
52 unlock(&p->lock);
53 return id;
54 }
56 static int
57 nextID(void)
58 {
59 static Lock l;
60 static int id;
61 int i;
63 lock(&l);
64 i = ++id;
65 unlock(&l);
66 return i;
67 }
69 int
70 procrfork(void (*f)(void *), void *arg, uint stacksize, int rforkflag)
71 {
72 Proc *p;
73 int id;
75 p = _threadgetproc();
76 assert(p->newproc == nil);
77 p->newproc = _newproc(f, arg, stacksize, nil, p->thread->grp, rforkflag);
78 id = p->newproc->threads.head->id;
79 _sched();
80 return id;
81 }
83 int
84 proccreate(void (*f)(void*), void *arg, uint stacksize)
85 {
86 Proc *p;
88 p = _threadgetproc();
89 if(p->idle){
90 fprint(2, "cannot create procs once there is an idle thread\n");
91 werrstr("cannot create procs once there is an idle thread");
92 return -1;
93 }
94 return procrfork(f, arg, stacksize, 0);
95 }
97 void
98 _freeproc(Proc *p)
99 {
100 Thread *t, *nextt;
102 for(t = p->threads.head; t; t = nextt){
103 if(t->cmdname)
104 free(t->cmdname);
105 assert(t->stk != nil);
106 _stackfree(t->stk);
107 nextt = t->nextt;
108 free(t);
110 free(p);
113 /*
114 * Create a new thread and schedule it to run.
115 * The thread grp is inherited from the currently running thread.
116 */
117 int
118 threadcreate(void (*f)(void *arg), void *arg, uint stacksize)
120 return newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
123 int
124 threadcreateidle(void (*f)(void *arg), void *arg, uint stacksize)
126 int id;
128 if(_threadprocs!=1){
129 fprint(2, "cannot have idle thread in multi-proc program\n");
130 werrstr("cannot have idle thread in multi-proc program");
131 return -1;
133 id = newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
134 _threaddebug(DBGSCHED, "idle is %d", id);
135 _threadidle();
136 return id;
139 /*
140 * Create and initialize a new Proc structure with a single Thread
141 * running inside it. Add the Proc to the global process list.
142 */
143 Proc*
144 _newproc(void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp, int rforkflag)
146 Proc *p;
148 p = _threadmalloc(sizeof *p, 1);
149 p->pid = -1;
150 p->rforkflag = rforkflag;
151 newthread(p, f, arg, stacksize, name, grp);
153 lock(&_threadpq.lock);
154 if(_threadpq.head == nil)
155 _threadpq.head = p;
156 else
157 *_threadpq.tail = p;
158 _threadpq.tail = &p->next;
160 if(_threadprocs == 1)
161 _threadmultiproc();
162 _threadprocs++;
163 unlock(&_threadpq.lock);
164 return p;