9os

Experimental kernel using plan9 ideas for embedded device
git clone git://git.simple-cc.org/9os
Log | Files | Refs | README | LICENSE

proc.c (6554B)


      1 #include <os9/os9.h>
      2 
      3 #include <errno.h>
      4 #include <limits.h>
      5 
      6 #include <libk.h>
      7 
      8 static Task tasktab[NR_TASKS];
      9 
     10 /* per cpu globals */
     11 Task *proc;
     12 long long now;
     13 int cpuid;
     14 
     15 void
     16 locktask(Task *tp)
     17 {
     18 	if (tp != proc)
     19 		lock(&tp->m);
     20 }
     21 
     22 void
     23 unlocktask(Task *tp)
     24 {
     25 	if (tp != proc)
     26 		unlock(&tp->m);
     27 }
     28 
     29 int
     30 getntask(int n, Task **tpp)
     31 {
     32 	Task *tp;
     33 
     34 	if (n >= NR_TASKS) {
     35 		seterror(EINVAL);
     36 		return -1;
     37 	}
     38 	tp = &tasktab[n];
     39 
     40 	locktask(tp);
     41 	if (tp->state == TFREE) {
     42 		unlocktask(tp);
     43 		return 0;
     44 	}
     45 
     46 	*tpp	= tp;
     47 	return 1;
     48 }
     49 
     50 Task *
     51 gettask(int pid)
     52 {
     53 	Task *tp, *p;
     54 
     55 	tp = NULL;
     56 	for (p = tasktab; p < &tasktab[NR_TASKS]; ++p) {
     57 		locktask(p);
     58 		if (p->pid == pid && p->state != TFREE) {
     59 			tp = p;
     60 			break;
     61 		}
     62 		unlocktask(p);
     63 	}
     64 
     65 	return tp;
     66 }
     67 
     68 static Task *
     69 newslot(void)
     70 {
     71 	Task *tp;
     72 
     73 	for (tp = tasktab; tp < &tasktab[NR_TASKS]; tp++) {
     74 		locktask(tp);
     75 		if (tp->state == TFREE)
     76 			break;
     77 		unlocktask(tp);
     78 	}
     79 
     80 	if (tp == &tasktab[NR_TASKS]) {
     81 		seterror(ENOMEM);
     82 		return NULL;
     83 	}
     84 
     85 	return tp;
     86 }
     87 
     88 static Task *
     89 newtask(void)
     90 {
     91 	int pid;
     92 	Task *tp;
     93 	static int last = -1;
     94 	static mutex_t m;
     95 
     96 	assert(NR_TASKS < MAXTID);
     97 
     98 	lock(&m);
     99 	tp = NULL;
    100 	pid = last;
    101 
    102 	for (;;) {
    103 		if (pid == MAXTID)
    104 			pid = -1;
    105 		pid++;
    106 		if (pid == last)
    107 			goto err;
    108 		if ((tp = gettask(pid)) == NULL)
    109 			break;
    110 		unlocktask(tp);
    111 	}
    112 
    113 	if ((tp = newslot()) == NULL)
    114 		goto err;
    115 	if (!newkstack(tp))
    116 		goto err;
    117 
    118 	last = pid;
    119 	tp->pid = pid;
    120 	tp->ppid = 0;
    121 	tp->state = TINIT;
    122 
    123 	unlock(&m);
    124 
    125 	return tp;
    126 err:
    127 	unlock(&m);
    128 	seterror(ENOMEM);
    129 
    130 	return NULL;
    131 }
    132 
    133 /*
    134  * tp must be blocked when this function is called
    135  */
    136 static void
    137 deltask(Task *tp)
    138 {
    139 	delmap(tp->text);
    140 	delmap(tp->data);
    141 	delspace(tp->ns);
    142 	delfds(tp->fds);
    143 	unlocktask(tp);
    144 }
    145 
    146 static Task *
    147 clone(Task *parent)
    148 {
    149 	Task *tp;
    150 
    151 	if ((tp = newtask()) == NULL)
    152 		return NULL;
    153 
    154 	if (!initptable(tp) || !newstack(tp))
    155 		goto err;
    156 
    157 	tp->ppid = parent->pid;
    158 
    159 	tp->entry = parent->entry;
    160 
    161 	tp->prio = parent->prio;
    162 	tp->baseprio = parent->baseprio;
    163 	tp->retainprio = parent->retainprio;
    164 
    165 	tp->wait = parent->wait;
    166 	tp->locklevel = parent->locklevel;
    167 	tp->affinity = parent->affinity;
    168 
    169 	tp->period = parent->period;
    170 	tp->duration = parent->duration;
    171 	tp->capacity = parent->capacity;
    172 
    173 	tp->deadline = parent->deadline;
    174 	tp->deadtime = parent->deadtime;
    175 
    176 	tp->flags = parent->flags;
    177 	tp->state = TREADY;
    178 
    179 	tp->text = parent->text;
    180 	if (tp->text)
    181 		incref(&tp->text->ref);
    182 
    183 	tp->data = parent->data;
    184 	if (tp->data)
    185 		incref(&tp->data->ref);
    186 
    187 	tp->ns = parent->ns;
    188 	if (tp->ns)
    189 		incref(&tp->ns->ref);
    190 
    191 	tp->fds = parent->fds;
    192 	if (tp->fds)
    193 		incref(&tp->fds->ref);
    194 
    195 	return tp;
    196 
    197 err:
    198 	deltask(tp);
    199 	return NULL;
    200 }
    201 
    202 int
    203 rfork(int flags)
    204 {
    205 	int pid;
    206 	Task *tp;
    207 	Nspace *ns;
    208 	Fdset *fds;
    209 	Map *data;
    210 
    211 	if ((flags & (RFMEM|RFPROC)) == 0
    212 	||  (flags & (RFNAMEG|RFCNAMEG))  == (RFNAMEG|RFCNAMEG)
    213 	||  (flags & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) {
    214 		seterror(EINVAL);
    215 		return -1;
    216 	}
    217 
    218 	tp = proc;
    219 	ns = NULL;
    220 	fds = NULL;
    221 	data = NULL;
    222 
    223 	if ((flags & RFPROC) != 0) {
    224 		if ((tp = clone(proc)) == NULL)
    225 			return -1;
    226 		/*
    227 		 * if dupctx() returns 0 then we are the child and
    228 		 * the mutex was already released by the parent
    229 		 */
    230 		if (dupctx(tp) == 0)
    231 			return 0;
    232 	}
    233 	if ((flags & RFCNAMEG) != 0) {
    234 		if ((ns = newspace(NULL)) == NULL)
    235 			goto err;
    236 	}
    237 	if ((flags & RFNAMEG) != 0) {
    238 		if ((ns = newspace(proc->ns)) == NULL)
    239 			goto err;
    240 	}
    241 	if ((flags & RFCFDG) != 0) {
    242 		if ((fds = newfds(NULL)) == NULL)
    243 			goto err;
    244 	}
    245 	if ((flags & RFFDG) != 0) {
    246 		if ((fds = newfds(proc->fds)) == NULL)
    247 			goto err;
    248 	}
    249 	if ((flags & RFMEM) == 0) {
    250 		if ((data = newmap(proc->data)) == NULL)
    251 			goto err;
    252 	}
    253 
    254 	if (tp->ns != ns) {
    255 		delspace(tp->ns);
    256 		tp->ns = ns;
    257 	}
    258 	if (tp->fds != fds) {
    259 		delfds(tp->fds);
    260 		tp->fds = fds;
    261 	}
    262 	if (tp->data != data) {
    263 		delmap(tp->data);
    264 		tp->data = data;
    265 	}
    266 
    267 	pid = tp->pid;
    268 	if (flags & RFPROC)
    269 		unlocktask(tp);
    270 
    271 	return pid;
    272 
    273 err:
    274 	if (data)
    275 		delmap(data);
    276 	if (fds)
    277 		delfds(fds);
    278 	if (ns)
    279 		delspace(ns);
    280 
    281 	if (flags & RFPROC)
    282 		deltask(tp);
    283 
    284 	return -1;
    285 }
    286 
    287 Task *
    288 kproc(void *fn)
    289 {
    290 	Task *tp, *zero;
    291 
    292 	zero = gettask(0);
    293 	if ((tp = clone(zero)) == NULL)
    294 		panic("kproc failed");
    295 
    296 	tp->entry = fn;
    297 	ictx(tp, fn);
    298 	unlocktask(tp);
    299 	unlocktask(zero);
    300 
    301 	return tp;
    302 }
    303 
    304 static void
    305 idle(void)
    306 {
    307 }
    308 
    309 void
    310 sched(void)
    311 {
    312 	Task *new, *tp;
    313 	int prio;
    314 	long long wait, mask;
    315 	static mutex_t m;
    316 
    317 	if (proc->state == TRUNNING) {
    318 		if (proc->flags&TLOCK_PREEMP)
    319 			return;
    320 		proc->state = TREADY;
    321 	}
    322 	unlock(&proc->m);
    323 
    324 repeat:
    325 	new = NULL;
    326 	prio = -1;
    327 	wait = -1;
    328 	mask = 1ul << cpuid;
    329 
    330 	lock(&m);
    331 	for (tp = tasktab; tp < &tasktab[NR_TASKS]; ++tp) {
    332 		lock(&tp->m);
    333 
    334 		if (tp->state == TREADY
    335 		&&  (tp->affinity & mask) != 0
    336 		&&  tp->prio >= prio
    337 		&&  (tp->prio != prio || tp->wait > wait)) {
    338 			new = tp;
    339 			prio = tp->prio;
    340 			wait = tp->wait;
    341 		}
    342 
    343 		unlock(&tp->m);
    344 	}
    345 
    346 	if (!new) {
    347 		unlock(&m);
    348 		idle();
    349 		goto repeat;
    350 	}
    351 
    352 	proc = new;
    353 	lock(&proc->m);
    354 	proc->state = TRUNNING;
    355 	unlock(&m);
    356 
    357 	swtch(&proc->ctx);
    358 }
    359 
    360 static void
    361 initfn(void)
    362 {
    363 	switch (rfork(RFPROC|RFMEM)) {
    364 	case 0:
    365 		/* exec("/blobs/init"); */
    366 	case -1:
    367 		panic("out of sync");
    368 	default:
    369 		debug();
    370 		break;
    371 	}
    372 }
    373 
    374 static Task *
    375 inittask(void)
    376 {
    377 	Task *tp;
    378 
    379 	if ((tp = newtask()) == NULL)
    380 		return NULL;
    381 
    382 	tp->text = NULL;
    383 	tp->data = NULL;
    384 	tp->fds = newfds(NULL);
    385 	tp->ns = newspace(NULL);
    386 
    387 	tp->entry = initfn;
    388 
    389 	tp->prio = 0;
    390 	tp->baseprio = 0;
    391 	tp->retainprio = 0;
    392 
    393 	tp->wait = 0;
    394 	tp->locklevel = 0;
    395 	tp->affinity = -1;
    396 
    397 	tp->period = 0;
    398 	tp->duration = 0;
    399 	tp->capacity = 0;
    400 
    401 	tp->deadline = 0;
    402 	tp->deadtime = 0;
    403 
    404 	tp->flags = 0;
    405 	tp->state = TREADY;
    406 
    407 	ictx(tp, initfn);
    408 
    409 	return tp;
    410 }
    411 
    412 void
    413 seterror(int n)
    414 {
    415 	proc->errno = n;
    416 }
    417 
    418 /*
    419  * sleep() and wakeup() are highly inspired in
    420  * the paper 'Process Sleep and Wakeup on a
    421  * Shared-memory Multiprocessor'
    422  */
    423 void
    424 sleep(Rendez *r, int (*cond)(void *), void *arg)
    425 {
    426 	lockspin(&r->s);
    427 
    428 	if (!(*cond)(arg)) {
    429 		unlockspin(&r->s);
    430 		return;
    431 	}
    432 
    433 	proc->state = TWAITING;
    434 	proc->next = r->task;
    435 	r->task = proc;
    436 	unlockspin(&r->s);
    437 	sched();
    438 }
    439 
    440 void
    441 wakeup(Rendez *r)
    442 {
    443 	Task *tp, *next;
    444 
    445 	lockspin(&r->s);
    446 	for (tp = r->task; tp; tp = next) {
    447 		if (tp->state != TWAITING)
    448 			panic("wakeup: not sleeping");
    449 		next = tp->next;
    450 		tp->next = NULL;
    451 		tp->state = TREADY;
    452 	}
    453 	r->task = NULL;
    454 	unlockspin(&r->s);
    455 }
    456 
    457 void
    458 iproc(void)
    459 {
    460 	Task *tp;
    461 
    462 	for (tp = tasktab; tp < &tasktab[NR_TASKS]; ++tp) {
    463 		tp->pid = tp->ppid = -1;
    464 		tp->state = TFREE;
    465 	}
    466 
    467 	if ((tp = inittask()) == NULL)
    468 		panic("init task failed");
    469 	proc = tp;
    470 
    471 	kprint("%d availabe task slots\n", NR_TASKS);
    472 }