xref: /plan9/sys/src/libthread/create.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier #include <u.h>
2*9a747e4fSDavid du Colombier #include <libc.h>
3*9a747e4fSDavid du Colombier #include <thread.h>
4*9a747e4fSDavid du Colombier #include "threadimpl.h"
5*9a747e4fSDavid du Colombier 
6*9a747e4fSDavid du Colombier Pqueue _threadpq;
7*9a747e4fSDavid du Colombier 
8*9a747e4fSDavid du Colombier static int
nextID(void)9*9a747e4fSDavid du Colombier nextID(void)
10*9a747e4fSDavid du Colombier {
11*9a747e4fSDavid du Colombier 	static Lock l;
12*9a747e4fSDavid du Colombier 	static int id;
13*9a747e4fSDavid du Colombier 	int i;
14*9a747e4fSDavid du Colombier 
15*9a747e4fSDavid du Colombier 	lock(&l);
16*9a747e4fSDavid du Colombier 	i = ++id;
17*9a747e4fSDavid du Colombier 	unlock(&l);
18*9a747e4fSDavid du Colombier 	return i;
19*9a747e4fSDavid du Colombier }
20*9a747e4fSDavid du Colombier 
21*9a747e4fSDavid du Colombier /*
22*9a747e4fSDavid du Colombier  * Create and initialize a new Thread structure attached to a given proc.
23*9a747e4fSDavid du Colombier  */
24*9a747e4fSDavid du Colombier static int
newthread(Proc * p,void (* f)(void * arg),void * arg,uint stacksize,char * name,int grp)25*9a747e4fSDavid du Colombier newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp)
26*9a747e4fSDavid du Colombier {
27*9a747e4fSDavid du Colombier 	int id;
28*9a747e4fSDavid du Colombier 	Thread *t;
29*9a747e4fSDavid du Colombier 
30*9a747e4fSDavid du Colombier 	if(stacksize < 32)
31*9a747e4fSDavid du Colombier 		sysfatal("bad stacksize %d", stacksize);
32*9a747e4fSDavid du Colombier 	t = _threadmalloc(sizeof(Thread), 1);
33*9a747e4fSDavid du Colombier 	t->stksize = stacksize;
34*9a747e4fSDavid du Colombier 	t->stk = _threadmalloc(stacksize, 0);
35*9a747e4fSDavid du Colombier 	memset(t->stk, 0xFE, stacksize);
36*9a747e4fSDavid du Colombier 	_threadinitstack(t, f, arg);
37*9a747e4fSDavid du Colombier 	t->grp = grp;
38*9a747e4fSDavid du Colombier 	if(name)
39*9a747e4fSDavid du Colombier 		t->cmdname = strdup(name);
40*9a747e4fSDavid du Colombier 	t->id = nextID();
41*9a747e4fSDavid du Colombier 	id = t->id;
42*9a747e4fSDavid du Colombier 	t->next = (Thread*)~0;
43*9a747e4fSDavid du Colombier 	t->proc = p;
44*9a747e4fSDavid du Colombier 	_threaddebug(DBGSCHED, "create thread %d.%d name %s", p->pid, t->id, name);
45*9a747e4fSDavid du Colombier 	lock(&p->lock);
46*9a747e4fSDavid du Colombier 	p->nthreads++;
47*9a747e4fSDavid du Colombier 	if(p->threads.head == nil)
48*9a747e4fSDavid du Colombier 		p->threads.head = t;
49*9a747e4fSDavid du Colombier 	else
50*9a747e4fSDavid du Colombier 		*p->threads.tail = t;
51*9a747e4fSDavid du Colombier 	p->threads.tail = &t->nextt;
52*9a747e4fSDavid du Colombier 	t->nextt = nil;
53*9a747e4fSDavid du Colombier 	t->state = Ready;
54*9a747e4fSDavid du Colombier 	_threadready(t);
55*9a747e4fSDavid du Colombier 	unlock(&p->lock);
56*9a747e4fSDavid du Colombier 	return id;
57*9a747e4fSDavid du Colombier }
58*9a747e4fSDavid du Colombier 
59*9a747e4fSDavid du Colombier /*
60*9a747e4fSDavid du Colombier  * Create a new thread and schedule it to run.
61*9a747e4fSDavid du Colombier  * The thread grp is inherited from the currently running thread.
62*9a747e4fSDavid du Colombier  */
63*9a747e4fSDavid du Colombier int
threadcreate(void (* f)(void * arg),void * arg,uint stacksize)64*9a747e4fSDavid du Colombier threadcreate(void (*f)(void *arg), void *arg, uint stacksize)
65*9a747e4fSDavid du Colombier {
66*9a747e4fSDavid du Colombier 	return newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
67*9a747e4fSDavid du Colombier }
68*9a747e4fSDavid du Colombier 
69*9a747e4fSDavid du Colombier /*
70*9a747e4fSDavid du Colombier  * Create and initialize a new Proc structure with a single Thread
71*9a747e4fSDavid du Colombier  * running inside it.  Add the Proc to the global process list.
72*9a747e4fSDavid du Colombier  */
73*9a747e4fSDavid du Colombier Proc*
_newproc(void (* f)(void * arg),void * arg,uint stacksize,char * name,int grp,int rforkflag)74*9a747e4fSDavid du Colombier _newproc(void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp, int rforkflag)
75*9a747e4fSDavid du Colombier {
76*9a747e4fSDavid du Colombier 	Proc *p;
77*9a747e4fSDavid du Colombier 
78*9a747e4fSDavid du Colombier 	p = _threadmalloc(sizeof *p, 1);
79*9a747e4fSDavid du Colombier 	p->pid = -1;
80*9a747e4fSDavid du Colombier 	p->rforkflag = rforkflag;
81*9a747e4fSDavid du Colombier 	newthread(p, f, arg, stacksize, name, grp);
82*9a747e4fSDavid du Colombier 
83*9a747e4fSDavid du Colombier 	lock(&_threadpq.lock);
84*9a747e4fSDavid du Colombier 	if(_threadpq.head == nil)
85*9a747e4fSDavid du Colombier 		_threadpq.head = p;
86*9a747e4fSDavid du Colombier 	else
87*9a747e4fSDavid du Colombier 		*_threadpq.tail = p;
88*9a747e4fSDavid du Colombier 	_threadpq.tail = &p->next;
89*9a747e4fSDavid du Colombier 	unlock(&_threadpq.lock);
90*9a747e4fSDavid du Colombier 	return p;
91*9a747e4fSDavid du Colombier }
92*9a747e4fSDavid du Colombier 
93*9a747e4fSDavid du Colombier int
procrfork(void (* f)(void *),void * arg,uint stacksize,int rforkflag)94*9a747e4fSDavid du Colombier procrfork(void (*f)(void *), void *arg, uint stacksize, int rforkflag)
95*9a747e4fSDavid du Colombier {
96*9a747e4fSDavid du Colombier 	Proc *p;
97*9a747e4fSDavid du Colombier 	int id;
98*9a747e4fSDavid du Colombier 
99*9a747e4fSDavid du Colombier 	p = _threadgetproc();
100*9a747e4fSDavid du Colombier 	assert(p->newproc == nil);
101*9a747e4fSDavid du Colombier 	p->newproc = _newproc(f, arg, stacksize, nil, p->thread->grp, rforkflag);
102*9a747e4fSDavid du Colombier 	id = p->newproc->threads.head->id;
103*9a747e4fSDavid du Colombier 	_sched();
104*9a747e4fSDavid du Colombier 	return id;
105*9a747e4fSDavid du Colombier }
106*9a747e4fSDavid du Colombier 
107*9a747e4fSDavid du Colombier int
proccreate(void (* f)(void *),void * arg,uint stacksize)108*9a747e4fSDavid du Colombier proccreate(void (*f)(void*), void *arg, uint stacksize)
109*9a747e4fSDavid du Colombier {
110*9a747e4fSDavid du Colombier 	return procrfork(f, arg, stacksize, 0);
111*9a747e4fSDavid du Colombier }
112*9a747e4fSDavid du Colombier 
113*9a747e4fSDavid du Colombier void
_freeproc(Proc * p)114*9a747e4fSDavid du Colombier _freeproc(Proc *p)
115*9a747e4fSDavid du Colombier {
116*9a747e4fSDavid du Colombier 	Thread *t, *nextt;
117*9a747e4fSDavid du Colombier 
118*9a747e4fSDavid du Colombier 	for(t = p->threads.head; t; t = nextt){
119*9a747e4fSDavid du Colombier 		if(t->cmdname)
120*9a747e4fSDavid du Colombier 			free(t->cmdname);
121*9a747e4fSDavid du Colombier 		assert(t->stk != nil);
122*9a747e4fSDavid du Colombier 		free(t->stk);
123*9a747e4fSDavid du Colombier 		nextt = t->nextt;
124*9a747e4fSDavid du Colombier 		free(t);
125*9a747e4fSDavid du Colombier 	}
126*9a747e4fSDavid du Colombier 	free(p);
127*9a747e4fSDavid du Colombier }
128*9a747e4fSDavid du Colombier 
129*9a747e4fSDavid du Colombier void
_freethread(Thread * t)130*9a747e4fSDavid du Colombier _freethread(Thread *t)
131*9a747e4fSDavid du Colombier {
132*9a747e4fSDavid du Colombier 	Proc *p;
133*9a747e4fSDavid du Colombier 	Thread **l;
134*9a747e4fSDavid du Colombier 
135*9a747e4fSDavid du Colombier 	p = t->proc;
136*9a747e4fSDavid du Colombier 	lock(&p->lock);
137*9a747e4fSDavid du Colombier 	for(l=&p->threads.head; *l; l=&(*l)->nextt){
138*9a747e4fSDavid du Colombier 		if(*l == t){
139*9a747e4fSDavid du Colombier 			*l = t->nextt;
140*9a747e4fSDavid du Colombier 			if(*l == nil)
141*9a747e4fSDavid du Colombier 				p->threads.tail = l;
142*9a747e4fSDavid du Colombier 			break;
143*9a747e4fSDavid du Colombier 		}
144*9a747e4fSDavid du Colombier 	}
145*9a747e4fSDavid du Colombier 	unlock(&p->lock);
146*9a747e4fSDavid du Colombier 	if (t->cmdname)
147*9a747e4fSDavid du Colombier 		free(t->cmdname);
148*9a747e4fSDavid du Colombier 	assert(t->stk != nil);
149*9a747e4fSDavid du Colombier 	free(t->stk);
150*9a747e4fSDavid du Colombier 	free(t);
151*9a747e4fSDavid du Colombier }
152*9a747e4fSDavid du Colombier 
153