Blob


1 #include "threadimpl.h"
3 #define free
4 Pqueue _threadpq;
6 static int nextID(void);
8 /*
9 * Create and initialize a new Thread structure attached to a given proc.
10 */
12 typedef struct Stack Stack;
13 struct Stack {
14 ulong magic;
15 Thread *thr;
16 Stack *next;
17 uchar buf[STKSIZE-12];
18 };
20 static Stack *stkfree;
21 static Lock stklock;
23 void
24 _stackfree(void *v)
25 {
26 Stack *s;
28 s = v;
29 lock(&stklock);
30 s->thr = nil;
31 s->magic = 0;
32 s->next = stkfree;
33 stkfree = s;
34 unlock(&stklock);
35 }
37 static Stack*
38 stackalloc(void)
39 {
40 char *buf;
41 Stack *s;
42 int i;
44 lock(&stklock);
45 while(stkfree == nil){
46 unlock(&stklock);
47 assert(STKSIZE == sizeof(Stack));
48 buf = malloc(STKSIZE+128*STKSIZE);
49 s = (Stack*)(((ulong)buf+STKSIZE)&~(STKSIZE-1));
50 for(i=0; i<128; i++)
51 _stackfree(&s[i]);
52 lock(&stklock);
53 }
54 s = stkfree;
55 stkfree = stkfree->next;
56 unlock(&stklock);
57 s->magic = STKMAGIC;
58 return s;
59 }
61 static int
62 newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp)
63 {
64 int id;
65 Thread *t;
66 Stack *s;
68 if(stacksize < 32)
69 sysfatal("bad stacksize %d", stacksize);
70 t = _threadmalloc(sizeof(Thread), 1);
71 s = stackalloc();
72 s->thr = t;
73 t->stk = (char*)s;
74 t->stksize = STKSIZE;
75 _threaddebugmemset(s->buf, 0xFE, sizeof s->buf);
76 _threadinitstack(t, f, arg);
77 t->proc = p;
78 t->grp = grp;
79 if(name)
80 t->cmdname = strdup(name);
81 t->id = nextID();
82 id = t->id;
83 t->next = (Thread*)~0;
84 _threaddebug(DBGSCHED, "create thread %d.%d name %s", p->pid, t->id, name);
85 lock(&p->lock);
86 p->nthreads++;
87 if(p->threads.head == nil)
88 p->threads.head = t;
89 else{
90 t->prevt = p->threads.tail;
91 t->prevt->nextt = t;
92 }
93 p->threads.tail = t;
94 t->state = Ready;
95 _threadready(t);
96 unlock(&p->lock);
97 return id;
98 }
100 static int
101 nextID(void)
103 static Lock l;
104 static int id;
105 int i;
107 lock(&l);
108 i = ++id;
109 unlock(&l);
110 return i;
113 int
114 procrfork(void (*f)(void *), void *arg, uint stacksize, int rforkflag)
116 Proc *p;
117 int id;
119 p = _threadgetproc();
120 assert(p->newproc == nil);
121 p->newproc = _newproc(f, arg, stacksize, nil, p->thread->grp, rforkflag);
122 id = p->newproc->threads.head->id;
123 _sched();
124 return id;
127 int
128 proccreate(void (*f)(void*), void *arg, uint stacksize)
130 return procrfork(f, arg, stacksize, 0);
133 void
134 _freeproc(Proc *p)
136 Thread *t, *nextt;
138 for(t = p->threads.head; t; t = nextt){
139 if(t->cmdname)
140 free(t->cmdname);
141 assert(t->stk != nil);
142 _stackfree((Stack*)t->stk);
143 nextt = t->nextt;
144 free(t);
146 free(p);
149 /*
150 * Create a new thread and schedule it to run.
151 * The thread grp is inherited from the currently running thread.
152 */
153 int
154 threadcreate(void (*f)(void *arg), void *arg, uint stacksize)
156 return newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
159 /*
160 * Create and initialize a new Proc structure with a single Thread
161 * running inside it. Add the Proc to the global process list.
162 */
163 Proc*
164 _newproc(void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp, int rforkflag)
166 Proc *p;
168 p = _threadmalloc(sizeof *p, 1);
169 p->pid = -1;
170 p->rforkflag = rforkflag;
171 newthread(p, f, arg, stacksize, name, grp);
173 lock(&_threadpq.lock);
174 if(_threadpq.head == nil)
175 _threadpq.head = p;
176 else
177 *_threadpq.tail = p;
178 _threadpq.tail = &p->next;
179 unlock(&_threadpq.lock);
180 return p;