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 s = _threadmalloc(stacksize, 0);
28 t->stk = (char*)s;
29 t->stksize = stacksize;
30 _threaddebugmemset(s, 0xFE, stacksize);
31 _threadinitstack(t, f, arg);
32 t->proc = p;
33 t->grp = grp;
34 if(name)
35 t->cmdname = strdup(name);
36 t->id = nextID();
37 id = t->id;
38 t->next = (Thread*)~0;
39 _threaddebug(DBGSCHED, "create thread %d.%d name %s", p->pid, t->id, name);
40 lock(&p->lock);
41 p->nthreads++;
42 if(p->threads.head == nil)
43 p->threads.head = t;
44 else{
45 t->prevt = p->threads.tail;
46 t->prevt->nextt = t;
47 }
48 p->threads.tail = t;
49 t->state = Ready;
50 _threadready(t);
51 unlock(&p->lock);
52 return id;
53 }
55 static int
56 nextID(void)
57 {
58 static Lock l;
59 static int id;
60 int i;
62 lock(&l);
63 i = ++id;
64 unlock(&l);
65 return i;
66 }
68 int
69 procrfork(void (*f)(void *), void *arg, uint stacksize, int rforkflag)
70 {
71 Proc *p;
72 int id;
74 p = _threadgetproc();
75 assert(p->newproc == nil);
76 p->newproc = _newproc(f, arg, stacksize, nil, p->thread->grp, rforkflag);
77 id = p->newproc->threads.head->id;
78 _sched();
79 return id;
80 }
82 int
83 proccreate(void (*f)(void*), void *arg, uint stacksize)
84 {
85 Proc *p;
87 p = _threadgetproc();
88 if(p->idle){
89 werrstr("cannot create procs once there is an idle thread");
90 return -1;
91 }
92 return procrfork(f, arg, stacksize, 0);
93 }
95 void
96 _freeproc(Proc *p)
97 {
98 Thread *t, *nextt;
100 for(t = p->threads.head; t; t = nextt){
101 if(t->cmdname)
102 free(t->cmdname);
103 assert(t->stk != nil);
104 _stackfree(t->stk);
105 nextt = t->nextt;
106 free(t);
108 free(p);
111 /*
112 * Create a new thread and schedule it to run.
113 * The thread grp is inherited from the currently running thread.
114 */
115 int
116 threadcreate(void (*f)(void *arg), void *arg, uint stacksize)
118 return newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
121 int
122 threadcreateidle(void (*f)(void *arg), void *arg, uint stacksize)
124 int id;
126 if(_threadprocs!=1){
127 werrstr("cannot have idle thread in multi-proc program");
128 return -1;
130 id = newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
131 _threaddebug(DBGSCHED, "idle is %d", id);
132 _threadidle();
133 return id;
136 /*
137 * Create and initialize a new Proc structure with a single Thread
138 * running inside it. Add the Proc to the global process list.
139 */
140 Proc*
141 _newproc(void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp, int rforkflag)
143 Proc *p;
145 p = _threadmalloc(sizeof *p, 1);
146 p->pid = -1;
147 p->rforkflag = rforkflag;
148 newthread(p, f, arg, stacksize, name, grp);
150 lock(&_threadpq.lock);
151 if(_threadpq.head == nil)
152 _threadpq.head = p;
153 else
154 *_threadpq.tail = p;
155 _threadpq.tail = &p->next;
156 _threadprocs++;
157 unlock(&_threadpq.lock);
158 return p;