1433d6423SLionel Sambuc #define ALLOCATE
2433d6423SLionel Sambuc #include <errno.h>
3433d6423SLionel Sambuc #include <minix/mthread.h>
4433d6423SLionel Sambuc #include <string.h>
5433d6423SLionel Sambuc
6433d6423SLionel Sambuc #include <machine/param.h>
7433d6423SLionel Sambuc #include <machine/vmparam.h>
8433d6423SLionel Sambuc
9433d6423SLionel Sambuc #include <sys/mman.h>
10433d6423SLionel Sambuc
11433d6423SLionel Sambuc #include <uvm/uvm_param.h>
12433d6423SLionel Sambuc
13433d6423SLionel Sambuc #include "global.h"
14433d6423SLionel Sambuc #include "proto.h"
15433d6423SLionel Sambuc
16433d6423SLionel Sambuc static int mthread_increase_thread_pool(void);
17433d6423SLionel Sambuc static void mthread_thread_init(mthread_thread_t thread, mthread_attr_t
18433d6423SLionel Sambuc *tattr, void *(*proc)(void *), void *arg);
19433d6423SLionel Sambuc
20433d6423SLionel Sambuc static void mthread_thread_stop(mthread_thread_t thread);
21433d6423SLionel Sambuc static void mthread_trampoline(void);
22433d6423SLionel Sambuc
23433d6423SLionel Sambuc static int initialized = 0;
24433d6423SLionel Sambuc #define MTHREAD_GUARDSIZE (1 << PGSHIFT) /* 1 page */
25433d6423SLionel Sambuc
26433d6423SLionel Sambuc static struct __mthread_attr default_attr = { MTHREAD_STACK_MIN,
27433d6423SLionel Sambuc NULL,
28433d6423SLionel Sambuc MTHREAD_CREATE_JOINABLE,
29433d6423SLionel Sambuc NULL, NULL };
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc /*===========================================================================*
32433d6423SLionel Sambuc * mthread_equal *
33433d6423SLionel Sambuc *===========================================================================*/
mthread_equal(l,r)34433d6423SLionel Sambuc int mthread_equal(l, r)
35433d6423SLionel Sambuc mthread_thread_t l;
36433d6423SLionel Sambuc mthread_thread_t r;
37433d6423SLionel Sambuc {
38433d6423SLionel Sambuc /* Compare two thread ids */
39433d6423SLionel Sambuc
40433d6423SLionel Sambuc return(l == r);
41433d6423SLionel Sambuc }
42433d6423SLionel Sambuc
43433d6423SLionel Sambuc
44433d6423SLionel Sambuc /*===========================================================================*
45433d6423SLionel Sambuc * mthread_create *
46433d6423SLionel Sambuc *===========================================================================*/
mthread_create(threadid,tattr,proc,arg)47433d6423SLionel Sambuc int mthread_create(threadid, tattr, proc, arg)
48433d6423SLionel Sambuc mthread_thread_t *threadid;
49433d6423SLionel Sambuc mthread_attr_t *tattr;
50433d6423SLionel Sambuc void *(*proc)(void *);
51433d6423SLionel Sambuc void *arg;
52433d6423SLionel Sambuc {
53433d6423SLionel Sambuc /* Register procedure proc for execution in a thread. */
54433d6423SLionel Sambuc mthread_thread_t thread;
55433d6423SLionel Sambuc
56433d6423SLionel Sambuc if (proc == NULL)
57433d6423SLionel Sambuc return(EINVAL);
58433d6423SLionel Sambuc
59433d6423SLionel Sambuc if (!mthread_queue_isempty(&free_threads)) {
60433d6423SLionel Sambuc thread = mthread_queue_remove(&free_threads);
61433d6423SLionel Sambuc mthread_thread_init(thread, tattr, proc, arg);
62433d6423SLionel Sambuc used_threads++;
63433d6423SLionel Sambuc if(threadid != NULL)
64433d6423SLionel Sambuc *threadid = (mthread_thread_t) thread;
65433d6423SLionel Sambuc #ifdef MDEBUG
66433d6423SLionel Sambuc printf("Inited thread %d\n", thread);
67433d6423SLionel Sambuc #endif
68433d6423SLionel Sambuc return(0);
69433d6423SLionel Sambuc } else {
70433d6423SLionel Sambuc if (mthread_increase_thread_pool() == -1)
71433d6423SLionel Sambuc return(EAGAIN);
72433d6423SLionel Sambuc
73433d6423SLionel Sambuc return mthread_create(threadid, tattr, proc, arg);
74433d6423SLionel Sambuc }
75433d6423SLionel Sambuc }
76433d6423SLionel Sambuc
77433d6423SLionel Sambuc
78433d6423SLionel Sambuc /*===========================================================================*
79433d6423SLionel Sambuc * mthread_detach *
80433d6423SLionel Sambuc *===========================================================================*/
mthread_detach(detach)81433d6423SLionel Sambuc int mthread_detach(detach)
82433d6423SLionel Sambuc mthread_thread_t detach;
83433d6423SLionel Sambuc {
84433d6423SLionel Sambuc /* Mark a thread as detached. Consequently, upon exit, resources allocated for
85433d6423SLionel Sambuc * this thread are automatically freed.
86433d6423SLionel Sambuc */
87433d6423SLionel Sambuc mthread_tcb_t *tcb;
88433d6423SLionel Sambuc
89433d6423SLionel Sambuc if (!isokthreadid(detach))
90433d6423SLionel Sambuc return(ESRCH);
91433d6423SLionel Sambuc
92433d6423SLionel Sambuc tcb = mthread_find_tcb(detach);
93433d6423SLionel Sambuc if (tcb->m_state == MS_DEAD) {
94433d6423SLionel Sambuc return(ESRCH);
95433d6423SLionel Sambuc } else if (tcb->m_attr.ma_detachstate != MTHREAD_CREATE_DETACHED) {
96433d6423SLionel Sambuc if (tcb->m_state == MS_EXITING)
97433d6423SLionel Sambuc mthread_thread_stop(detach);
98433d6423SLionel Sambuc else
99433d6423SLionel Sambuc tcb->m_attr.ma_detachstate = MTHREAD_CREATE_DETACHED;
100433d6423SLionel Sambuc }
101433d6423SLionel Sambuc
102433d6423SLionel Sambuc return(0);
103433d6423SLionel Sambuc }
104433d6423SLionel Sambuc
105433d6423SLionel Sambuc
106433d6423SLionel Sambuc /*===========================================================================*
107433d6423SLionel Sambuc * mthread_exit *
108433d6423SLionel Sambuc *===========================================================================*/
mthread_exit(value)109433d6423SLionel Sambuc void mthread_exit(value)
110433d6423SLionel Sambuc void *value;
111433d6423SLionel Sambuc {
112433d6423SLionel Sambuc /* Make a thread stop running and store the result value. */
113433d6423SLionel Sambuc mthread_tcb_t *tcb;
114433d6423SLionel Sambuc
115433d6423SLionel Sambuc tcb = mthread_find_tcb(current_thread);
116433d6423SLionel Sambuc
117433d6423SLionel Sambuc if (tcb->m_state == MS_EXITING) /* Already stopping, nothing to do. */
118433d6423SLionel Sambuc return;
119433d6423SLionel Sambuc
120433d6423SLionel Sambuc mthread_cleanup_values();
121433d6423SLionel Sambuc
122433d6423SLionel Sambuc tcb->m_result = value;
123433d6423SLionel Sambuc tcb->m_state = MS_EXITING;
124433d6423SLionel Sambuc
125433d6423SLionel Sambuc if (tcb->m_attr.ma_detachstate == MTHREAD_CREATE_DETACHED) {
126433d6423SLionel Sambuc mthread_thread_stop(current_thread);
127433d6423SLionel Sambuc } else {
128433d6423SLionel Sambuc /* Joinable thread; notify possibly waiting thread */
129433d6423SLionel Sambuc if (mthread_cond_signal(&(tcb->m_exited)) != 0)
130433d6423SLionel Sambuc mthread_panic("Couldn't signal exit");
131433d6423SLionel Sambuc
132433d6423SLionel Sambuc /* The thread that's actually doing the join will eventually clean
133433d6423SLionel Sambuc * up this thread (i.e., call mthread_thread_stop).
134433d6423SLionel Sambuc */
135433d6423SLionel Sambuc }
136433d6423SLionel Sambuc
137433d6423SLionel Sambuc mthread_schedule();
138433d6423SLionel Sambuc }
139433d6423SLionel Sambuc
140433d6423SLionel Sambuc /*===========================================================================*
141433d6423SLionel Sambuc * mthread_find_tcb *
142433d6423SLionel Sambuc *===========================================================================*/
mthread_find_tcb(thread)143433d6423SLionel Sambuc mthread_tcb_t * mthread_find_tcb(thread)
144433d6423SLionel Sambuc mthread_thread_t thread;
145433d6423SLionel Sambuc {
146433d6423SLionel Sambuc mthread_tcb_t *rt = NULL;
147433d6423SLionel Sambuc
148433d6423SLionel Sambuc if (!isokthreadid(thread)) mthread_panic("Invalid thread id");
149433d6423SLionel Sambuc
150433d6423SLionel Sambuc if (thread == MAIN_THREAD)
151433d6423SLionel Sambuc rt = &mainthread;
152433d6423SLionel Sambuc else
153433d6423SLionel Sambuc rt = threads[thread];
154433d6423SLionel Sambuc
155433d6423SLionel Sambuc return(rt);
156433d6423SLionel Sambuc }
157433d6423SLionel Sambuc
158433d6423SLionel Sambuc
159433d6423SLionel Sambuc /*===========================================================================*
160433d6423SLionel Sambuc * mthread_increase_thread_pool *
161433d6423SLionel Sambuc *===========================================================================*/
mthread_increase_thread_pool(void)162433d6423SLionel Sambuc static int mthread_increase_thread_pool(void)
163433d6423SLionel Sambuc {
164433d6423SLionel Sambuc /* Increase thread pool. No fancy algorithms, just double the size. */
165433d6423SLionel Sambuc mthread_tcb_t **new_tcb;
166433d6423SLionel Sambuc int new_no_threads, old_no_threads, i;
167433d6423SLionel Sambuc
168433d6423SLionel Sambuc old_no_threads = no_threads;
169433d6423SLionel Sambuc
170433d6423SLionel Sambuc if (old_no_threads == 0)
171433d6423SLionel Sambuc new_no_threads = NO_THREADS;
172433d6423SLionel Sambuc else
173433d6423SLionel Sambuc new_no_threads = 2 * old_no_threads;
174433d6423SLionel Sambuc
175433d6423SLionel Sambuc
176433d6423SLionel Sambuc if (new_no_threads >= MAX_THREAD_POOL) {
177433d6423SLionel Sambuc mthread_debug("Reached max number of threads");
178433d6423SLionel Sambuc return(-1);
179433d6423SLionel Sambuc }
180433d6423SLionel Sambuc
181433d6423SLionel Sambuc /* Allocate space to store pointers to thread control blocks */
182433d6423SLionel Sambuc if (old_no_threads == 0) /* No data yet: allocate space */
183433d6423SLionel Sambuc new_tcb = calloc(new_no_threads, sizeof(mthread_tcb_t *));
184433d6423SLionel Sambuc else /* Preserve existing data: reallocate space */
185433d6423SLionel Sambuc new_tcb = realloc(threads, new_no_threads * sizeof(mthread_tcb_t *));
186433d6423SLionel Sambuc
187433d6423SLionel Sambuc if (new_tcb == NULL) {
188433d6423SLionel Sambuc mthread_debug("Can't increase thread pool");
189433d6423SLionel Sambuc return(-1);
190433d6423SLionel Sambuc }
191433d6423SLionel Sambuc
192433d6423SLionel Sambuc /* Allocate space for thread control blocks itself */
193433d6423SLionel Sambuc for (i = old_no_threads; i < new_no_threads; i++) {
194433d6423SLionel Sambuc new_tcb[i] = malloc(sizeof(mthread_tcb_t));
195433d6423SLionel Sambuc if (new_tcb[i] == NULL) {
196433d6423SLionel Sambuc mthread_debug("Can't allocate space for tcb");
197*815afbadSDavid van Moolenbroek /* Undo the allocations made so far. */
198*815afbadSDavid van Moolenbroek while (i-- > old_no_threads)
199*815afbadSDavid van Moolenbroek free(new_tcb[i]);
200*815afbadSDavid van Moolenbroek if (old_no_threads > 0) {
201*815afbadSDavid van Moolenbroek new_tcb = realloc(threads, old_no_threads *
202*815afbadSDavid van Moolenbroek sizeof(mthread_tcb_t *));
203*815afbadSDavid van Moolenbroek if (new_tcb == NULL)
204*815afbadSDavid van Moolenbroek mthread_panic("Unable to shrink tcb array");
205*815afbadSDavid van Moolenbroek } else
206*815afbadSDavid van Moolenbroek free(new_tcb);
207433d6423SLionel Sambuc return(-1);
208433d6423SLionel Sambuc }
209433d6423SLionel Sambuc memset(new_tcb[i], '\0', sizeof(mthread_tcb_t)); /* Clear entry */
210433d6423SLionel Sambuc }
211433d6423SLionel Sambuc
212*815afbadSDavid van Moolenbroek /* We can breathe again, let's tell the others about the good news */
213433d6423SLionel Sambuc threads = new_tcb;
214433d6423SLionel Sambuc no_threads = new_no_threads;
215433d6423SLionel Sambuc
216433d6423SLionel Sambuc /* Add newly available threads to free_threads */
217433d6423SLionel Sambuc for (i = old_no_threads; i < new_no_threads; i++) {
218433d6423SLionel Sambuc mthread_queue_add(&free_threads, i);
219433d6423SLionel Sambuc mthread_thread_reset(i);
220433d6423SLionel Sambuc }
221433d6423SLionel Sambuc
222433d6423SLionel Sambuc #ifdef MDEBUG
223433d6423SLionel Sambuc printf("Increased thread pool from %d to %d threads\n", old_no_threads,
224433d6423SLionel Sambuc new_no_threads);
225433d6423SLionel Sambuc #endif
226433d6423SLionel Sambuc return(0);
227433d6423SLionel Sambuc }
228433d6423SLionel Sambuc
229433d6423SLionel Sambuc
230433d6423SLionel Sambuc /*===========================================================================*
231433d6423SLionel Sambuc * mthread_init *
232433d6423SLionel Sambuc *===========================================================================*/
mthread_init(void)233433d6423SLionel Sambuc static void __attribute__((__constructor__, __used__)) mthread_init(void)
234433d6423SLionel Sambuc {
235433d6423SLionel Sambuc /* Initialize thread system; allocate thread structures and start creating
236433d6423SLionel Sambuc * threads.
237433d6423SLionel Sambuc */
238433d6423SLionel Sambuc
239433d6423SLionel Sambuc if (initialized) return;
240433d6423SLionel Sambuc
241433d6423SLionel Sambuc no_threads = 0;
242433d6423SLionel Sambuc used_threads = 0;
243433d6423SLionel Sambuc need_reset = 0;
244433d6423SLionel Sambuc running_main_thread = 1; /* mthread_init can only be called from the
245433d6423SLionel Sambuc * main thread. Calling it from a thread will
246433d6423SLionel Sambuc * not enter this clause.
247433d6423SLionel Sambuc */
248433d6423SLionel Sambuc
249433d6423SLionel Sambuc if (mthread_getcontext(&(mainthread.m_context)) == -1)
250433d6423SLionel Sambuc mthread_panic("Couldn't save state for main thread");
251433d6423SLionel Sambuc current_thread = MAIN_THREAD;
252433d6423SLionel Sambuc
253433d6423SLionel Sambuc mthread_init_valid_mutexes();
254433d6423SLionel Sambuc mthread_init_valid_conditions();
255433d6423SLionel Sambuc mthread_init_valid_attributes();
256433d6423SLionel Sambuc mthread_init_keys();
257433d6423SLionel Sambuc mthread_init_scheduler();
258433d6423SLionel Sambuc
259433d6423SLionel Sambuc initialized = 1;
260433d6423SLionel Sambuc }
261433d6423SLionel Sambuc
262433d6423SLionel Sambuc
263433d6423SLionel Sambuc /*===========================================================================*
264433d6423SLionel Sambuc * mthread_join *
265433d6423SLionel Sambuc *===========================================================================*/
mthread_join(join,value)266433d6423SLionel Sambuc int mthread_join(join, value)
267433d6423SLionel Sambuc mthread_thread_t join;
268433d6423SLionel Sambuc void **value;
269433d6423SLionel Sambuc {
270433d6423SLionel Sambuc /* Wait for a thread to stop running and copy the result. */
271433d6423SLionel Sambuc
272433d6423SLionel Sambuc mthread_tcb_t *tcb;
273433d6423SLionel Sambuc
274433d6423SLionel Sambuc if (!isokthreadid(join))
275433d6423SLionel Sambuc return(ESRCH);
276433d6423SLionel Sambuc else if (join == current_thread)
277433d6423SLionel Sambuc return(EDEADLK);
278433d6423SLionel Sambuc
279433d6423SLionel Sambuc tcb = mthread_find_tcb(join);
280433d6423SLionel Sambuc if (tcb->m_state == MS_DEAD)
281433d6423SLionel Sambuc return(ESRCH);
282433d6423SLionel Sambuc else if (tcb->m_attr.ma_detachstate == MTHREAD_CREATE_DETACHED)
283433d6423SLionel Sambuc return(EINVAL);
284433d6423SLionel Sambuc
285433d6423SLionel Sambuc /* When the thread hasn't exited yet, we have to wait for that to happen */
286433d6423SLionel Sambuc if (tcb->m_state != MS_EXITING) {
287433d6423SLionel Sambuc mthread_cond_t *c;
288433d6423SLionel Sambuc mthread_mutex_t *m;
289433d6423SLionel Sambuc
290433d6423SLionel Sambuc c = &(tcb->m_exited);
291433d6423SLionel Sambuc m = &(tcb->m_exitm);
292433d6423SLionel Sambuc
293433d6423SLionel Sambuc if (mthread_mutex_init(m, NULL) != 0)
294433d6423SLionel Sambuc mthread_panic("Couldn't initialize mutex to join\n");
295433d6423SLionel Sambuc
296433d6423SLionel Sambuc if (mthread_mutex_lock(m) != 0)
297433d6423SLionel Sambuc mthread_panic("Couldn't lock mutex to join\n");
298433d6423SLionel Sambuc
299433d6423SLionel Sambuc if (mthread_cond_wait(c, m) != 0)
300433d6423SLionel Sambuc mthread_panic("Couldn't wait for join condition\n");
301433d6423SLionel Sambuc
302433d6423SLionel Sambuc if (mthread_mutex_unlock(m) != 0)
303433d6423SLionel Sambuc mthread_panic("Couldn't unlock mutex to join\n");
304433d6423SLionel Sambuc
305433d6423SLionel Sambuc if (mthread_mutex_destroy(m) != 0)
306433d6423SLionel Sambuc mthread_panic("Couldn't destroy mutex to join\n");
307433d6423SLionel Sambuc }
308433d6423SLionel Sambuc
309433d6423SLionel Sambuc /* Thread has exited; copy results */
310433d6423SLionel Sambuc if(value != NULL)
311433d6423SLionel Sambuc *value = tcb->m_result;
312433d6423SLionel Sambuc
313433d6423SLionel Sambuc /* Deallocate resources */
314433d6423SLionel Sambuc mthread_thread_stop(join);
315433d6423SLionel Sambuc return(0);
316433d6423SLionel Sambuc }
317433d6423SLionel Sambuc
318433d6423SLionel Sambuc
319433d6423SLionel Sambuc /*===========================================================================*
320433d6423SLionel Sambuc * mthread_once *
321433d6423SLionel Sambuc *===========================================================================*/
mthread_once(once,proc)322433d6423SLionel Sambuc int mthread_once(once, proc)
323433d6423SLionel Sambuc mthread_once_t *once;
324433d6423SLionel Sambuc void (*proc)(void);
325433d6423SLionel Sambuc {
326433d6423SLionel Sambuc /* Run procedure proc just once */
327433d6423SLionel Sambuc
328433d6423SLionel Sambuc if (once == NULL || proc == NULL)
329433d6423SLionel Sambuc return(EINVAL);
330433d6423SLionel Sambuc
331433d6423SLionel Sambuc if (*once != 1) proc();
332433d6423SLionel Sambuc *once = 1;
333433d6423SLionel Sambuc return(0);
334433d6423SLionel Sambuc }
335433d6423SLionel Sambuc
336433d6423SLionel Sambuc
337433d6423SLionel Sambuc /*===========================================================================*
338433d6423SLionel Sambuc * mthread_self *
339433d6423SLionel Sambuc *===========================================================================*/
mthread_self(void)340433d6423SLionel Sambuc mthread_thread_t mthread_self(void)
341433d6423SLionel Sambuc {
342433d6423SLionel Sambuc /* Return the thread id of the thread calling this function. */
343433d6423SLionel Sambuc
344433d6423SLionel Sambuc return(current_thread);
345433d6423SLionel Sambuc }
346433d6423SLionel Sambuc
347433d6423SLionel Sambuc
348433d6423SLionel Sambuc /*===========================================================================*
349433d6423SLionel Sambuc * mthread_thread_init *
350433d6423SLionel Sambuc *===========================================================================*/
mthread_thread_init(thread,tattr,proc,arg)351433d6423SLionel Sambuc static void mthread_thread_init(thread, tattr, proc, arg)
352433d6423SLionel Sambuc mthread_thread_t thread;
353433d6423SLionel Sambuc mthread_attr_t *tattr;
354433d6423SLionel Sambuc void *(*proc)(void *);
355433d6423SLionel Sambuc void *arg;
356433d6423SLionel Sambuc {
357433d6423SLionel Sambuc /* Initialize a thread so that it, when unsuspended, will run the given
358433d6423SLionel Sambuc * procedure with the given parameter. The thread is marked as runnable.
359433d6423SLionel Sambuc */
360433d6423SLionel Sambuc
361433d6423SLionel Sambuc #define THIS_CTX (&(threads[thread]->m_context))
362433d6423SLionel Sambuc mthread_tcb_t *tcb;
363433d6423SLionel Sambuc size_t stacksize;
364433d6423SLionel Sambuc char *stackaddr;
365433d6423SLionel Sambuc
366433d6423SLionel Sambuc tcb = mthread_find_tcb(thread);
367433d6423SLionel Sambuc tcb->m_next = NULL;
368433d6423SLionel Sambuc tcb->m_state = MS_DEAD;
369433d6423SLionel Sambuc tcb->m_proc = proc;
370433d6423SLionel Sambuc tcb->m_arg = arg;
371433d6423SLionel Sambuc /* Threads use a copy of the provided attributes. This way, if another
372433d6423SLionel Sambuc * thread modifies the attributes (such as detach state), already running
373433d6423SLionel Sambuc * threads are not affected.
374433d6423SLionel Sambuc */
375433d6423SLionel Sambuc if (tattr != NULL)
376433d6423SLionel Sambuc tcb->m_attr = *((struct __mthread_attr *) *tattr);
377433d6423SLionel Sambuc else {
378433d6423SLionel Sambuc tcb->m_attr = default_attr;
379433d6423SLionel Sambuc }
380433d6423SLionel Sambuc
381433d6423SLionel Sambuc if (mthread_cond_init(&(tcb->m_exited), NULL) != 0)
382433d6423SLionel Sambuc mthread_panic("Could not initialize thread");
383433d6423SLionel Sambuc
384433d6423SLionel Sambuc tcb->m_context.uc_link = NULL;
385433d6423SLionel Sambuc
386433d6423SLionel Sambuc /* Construct this thread's context to run procedure proc. */
387433d6423SLionel Sambuc if (mthread_getcontext(&(tcb->m_context)) == -1)
388433d6423SLionel Sambuc mthread_panic("Failed to initialize context state");
389433d6423SLionel Sambuc
390433d6423SLionel Sambuc stacksize = tcb->m_attr.ma_stacksize;
391433d6423SLionel Sambuc stackaddr = tcb->m_attr.ma_stackaddr;
392433d6423SLionel Sambuc
393433d6423SLionel Sambuc if (stacksize == (size_t) 0) {
394433d6423SLionel Sambuc /* User provided too small a stack size. Forget about that stack and
395433d6423SLionel Sambuc * allocate a new one ourselves.
396433d6423SLionel Sambuc */
397433d6423SLionel Sambuc stacksize = (size_t) MTHREAD_STACK_MIN;
398433d6423SLionel Sambuc tcb->m_attr.ma_stackaddr = stackaddr = NULL;
399433d6423SLionel Sambuc }
400433d6423SLionel Sambuc
401433d6423SLionel Sambuc if (stackaddr == NULL) {
402433d6423SLionel Sambuc /* Allocate stack space */
403433d6423SLionel Sambuc size_t guarded_stacksize;
404433d6423SLionel Sambuc char *guard_start, *guard_end;
405433d6423SLionel Sambuc
406433d6423SLionel Sambuc stacksize = round_page(stacksize + MTHREAD_GUARDSIZE);
407433d6423SLionel Sambuc stackaddr = mmap(NULL, stacksize,
408433d6423SLionel Sambuc PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE,
409433d6423SLionel Sambuc -1, 0);
410433d6423SLionel Sambuc if (stackaddr == MAP_FAILED)
411433d6423SLionel Sambuc mthread_panic("Failed to allocate stack to thread");
412433d6423SLionel Sambuc
413433d6423SLionel Sambuc #if defined(__i386__) || defined(__arm__)
414433d6423SLionel Sambuc guard_start = stackaddr;
415433d6423SLionel Sambuc guard_end = stackaddr + MTHREAD_GUARDSIZE;
416433d6423SLionel Sambuc guarded_stacksize = stackaddr + stacksize - guard_end;
417433d6423SLionel Sambuc
418433d6423SLionel Sambuc /* The stack will be used from (stackaddr+stacksize) to stackaddr. That
419433d6423SLionel Sambuc * is, growing downwards. So the "top" of the stack may not grow into
420433d6423SLionel Sambuc * stackaddr+MTHREAD_GUARDSIZE.
421433d6423SLionel Sambuc *
422433d6423SLionel Sambuc * +-------+ stackaddr + stacksize
423433d6423SLionel Sambuc * | |
424433d6423SLionel Sambuc * | | |
425433d6423SLionel Sambuc * | \|/ |
426433d6423SLionel Sambuc * | |
427433d6423SLionel Sambuc * +-------+ stackaddr + MTHREAD_GUARDSIZE
428433d6423SLionel Sambuc * | GUARD |
429433d6423SLionel Sambuc * +-------+ stackaddr
430433d6423SLionel Sambuc */
431433d6423SLionel Sambuc #else
432433d6423SLionel Sambuc # error "Unsupported platform"
433433d6423SLionel Sambuc #endif
434433d6423SLionel Sambuc stacksize = guarded_stacksize;
43575206e2fSCristiano Giuffrida /* Mere unmapping could allow a later allocation to fill the gap. */
43675206e2fSCristiano Giuffrida if (mmap(guard_start, MTHREAD_GUARDSIZE, PROT_NONE,
43775206e2fSCristiano Giuffrida MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0) != guard_start)
43875206e2fSCristiano Giuffrida mthread_panic("unable to overmap stack space for guard");
439433d6423SLionel Sambuc tcb->m_context.uc_stack.ss_sp = guard_end;
440433d6423SLionel Sambuc } else
441433d6423SLionel Sambuc tcb->m_context.uc_stack.ss_sp = stackaddr;
442433d6423SLionel Sambuc
443433d6423SLionel Sambuc tcb->m_context.uc_stack.ss_size = stacksize;
444433d6423SLionel Sambuc makecontext(&(tcb->m_context), mthread_trampoline, 0);
445433d6423SLionel Sambuc
446433d6423SLionel Sambuc mthread_unsuspend(thread); /* Make thread runnable */
447433d6423SLionel Sambuc }
448433d6423SLionel Sambuc
449433d6423SLionel Sambuc
450433d6423SLionel Sambuc /*===========================================================================*
451433d6423SLionel Sambuc * mthread_thread_reset *
452433d6423SLionel Sambuc *===========================================================================*/
mthread_thread_reset(thread)453433d6423SLionel Sambuc void mthread_thread_reset(thread)
454433d6423SLionel Sambuc mthread_thread_t thread;
455433d6423SLionel Sambuc {
456433d6423SLionel Sambuc /* Reset the thread to its default values. Free the allocated stack space. */
457433d6423SLionel Sambuc
458433d6423SLionel Sambuc mthread_tcb_t *rt;
45975206e2fSCristiano Giuffrida size_t stacksize;
46075206e2fSCristiano Giuffrida char *stackaddr;
46175206e2fSCristiano Giuffrida
462433d6423SLionel Sambuc if (!isokthreadid(thread)) mthread_panic("Invalid thread id");
463433d6423SLionel Sambuc
464433d6423SLionel Sambuc rt = mthread_find_tcb(thread);
465433d6423SLionel Sambuc rt->m_tid = thread;
466433d6423SLionel Sambuc rt->m_next = NULL;
467433d6423SLionel Sambuc rt->m_state = MS_DEAD;
468433d6423SLionel Sambuc rt->m_proc = NULL;
469433d6423SLionel Sambuc rt->m_arg = NULL;
470433d6423SLionel Sambuc rt->m_result = NULL;
471433d6423SLionel Sambuc rt->m_cond = NULL;
472433d6423SLionel Sambuc if (rt->m_attr.ma_stackaddr == NULL) { /* We allocated stack space */
473433d6423SLionel Sambuc if (rt->m_context.uc_stack.ss_sp) {
47475206e2fSCristiano Giuffrida stacksize = rt->m_context.uc_stack.ss_size;
47575206e2fSCristiano Giuffrida stackaddr = rt->m_context.uc_stack.ss_sp;
47675206e2fSCristiano Giuffrida #if defined(__i386__) || defined(__arm__)
47775206e2fSCristiano Giuffrida stacksize += MTHREAD_GUARDSIZE;
47875206e2fSCristiano Giuffrida stackaddr -= MTHREAD_GUARDSIZE;
47975206e2fSCristiano Giuffrida #else
48075206e2fSCristiano Giuffrida # error "Unsupported platform"
48175206e2fSCristiano Giuffrida #endif
48275206e2fSCristiano Giuffrida if (munmap(stackaddr, stacksize) != 0) {
483433d6423SLionel Sambuc mthread_panic("unable to unmap memory");
484433d6423SLionel Sambuc }
485433d6423SLionel Sambuc }
486433d6423SLionel Sambuc rt->m_context.uc_stack.ss_sp = NULL;
487433d6423SLionel Sambuc }
488433d6423SLionel Sambuc rt->m_context.uc_stack.ss_size = 0;
489433d6423SLionel Sambuc rt->m_context.uc_link = NULL;
490433d6423SLionel Sambuc }
491433d6423SLionel Sambuc
492433d6423SLionel Sambuc
493433d6423SLionel Sambuc /*===========================================================================*
494433d6423SLionel Sambuc * mthread_thread_stop *
495433d6423SLionel Sambuc *===========================================================================*/
mthread_thread_stop(thread)496433d6423SLionel Sambuc static void mthread_thread_stop(thread)
497433d6423SLionel Sambuc mthread_thread_t thread;
498433d6423SLionel Sambuc {
499433d6423SLionel Sambuc /* Stop thread from running. Deallocate resources. */
500433d6423SLionel Sambuc mthread_tcb_t *stop_thread;
501433d6423SLionel Sambuc
502433d6423SLionel Sambuc if (!isokthreadid(thread)) mthread_panic("Invalid thread id");
503433d6423SLionel Sambuc
504433d6423SLionel Sambuc stop_thread = mthread_find_tcb(thread);
505433d6423SLionel Sambuc
506433d6423SLionel Sambuc if (stop_thread->m_state == MS_DEAD) {
507433d6423SLionel Sambuc /* Already dead, nothing to do */
508433d6423SLionel Sambuc return;
509433d6423SLionel Sambuc }
510433d6423SLionel Sambuc
511433d6423SLionel Sambuc if (mthread_cond_destroy(&(stop_thread->m_exited)) != 0)
512433d6423SLionel Sambuc mthread_panic("Could not destroy condition at thread deallocation\n");
513433d6423SLionel Sambuc
514433d6423SLionel Sambuc /* Can't deallocate ourselves (i.e., we're a detached thread) */
515433d6423SLionel Sambuc if (thread == current_thread) {
516433d6423SLionel Sambuc stop_thread->m_state = MS_NEEDRESET;
517433d6423SLionel Sambuc need_reset++;
518433d6423SLionel Sambuc } else {
519433d6423SLionel Sambuc mthread_thread_reset(thread);
520433d6423SLionel Sambuc used_threads--;
521433d6423SLionel Sambuc mthread_queue_add(&free_threads, thread);
522433d6423SLionel Sambuc }
523433d6423SLionel Sambuc }
524433d6423SLionel Sambuc
525433d6423SLionel Sambuc
526433d6423SLionel Sambuc /*===========================================================================*
527433d6423SLionel Sambuc * mthread_trampoline *
528433d6423SLionel Sambuc *===========================================================================*/
mthread_trampoline(void)529433d6423SLionel Sambuc static void mthread_trampoline(void)
530433d6423SLionel Sambuc {
531433d6423SLionel Sambuc /* Execute the /current_thread's/ procedure. Store its result. */
532433d6423SLionel Sambuc
533433d6423SLionel Sambuc mthread_tcb_t *tcb;
534433d6423SLionel Sambuc void *r;
535433d6423SLionel Sambuc
536433d6423SLionel Sambuc tcb = mthread_find_tcb(current_thread);
537433d6423SLionel Sambuc
538433d6423SLionel Sambuc r = (tcb->m_proc)(tcb->m_arg);
539433d6423SLionel Sambuc mthread_exit(r);
540433d6423SLionel Sambuc }
541433d6423SLionel Sambuc
542433d6423SLionel Sambuc /* pthread compatibility layer. */
543433d6423SLionel Sambuc __weak_alias(pthread_create, mthread_create)
544433d6423SLionel Sambuc __weak_alias(pthread_detach, mthread_detach)
545433d6423SLionel Sambuc __weak_alias(pthread_equal, mthread_equal)
546433d6423SLionel Sambuc __weak_alias(pthread_exit, mthread_exit)
547433d6423SLionel Sambuc __weak_alias(pthread_join, mthread_join)
548433d6423SLionel Sambuc __weak_alias(pthread_once, mthread_once)
549433d6423SLionel Sambuc __weak_alias(pthread_self, mthread_self)
550433d6423SLionel Sambuc
551