xref: /minix3/minix/lib/libmthread/allocate.c (revision 815afbad3330f03122b15d230dbc3d36d38fab54)
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