Home | History | Annotate | Line # | Download | only in libpuffs
callcontext.c revision 1.27.40.1
      1  1.27.40.1  christos /*	$NetBSD: callcontext.c,v 1.27.40.1 2019/06/10 22:05:26 christos Exp $	*/
      2        1.1     pooka 
      3        1.1     pooka /*
      4       1.20     pooka  * Copyright (c) 2006, 2007, 2008 Antti Kantee.  All Rights Reserved.
      5       1.20     pooka  *
      6       1.20     pooka  * Development of this software was supported by the
      7       1.20     pooka  * Research Foundation of Helsinki University of Technology
      8        1.1     pooka  *
      9        1.1     pooka  * Redistribution and use in source and binary forms, with or without
     10        1.1     pooka  * modification, are permitted provided that the following conditions
     11        1.1     pooka  * are met:
     12        1.1     pooka  * 1. Redistributions of source code must retain the above copyright
     13        1.1     pooka  *    notice, this list of conditions and the following disclaimer.
     14        1.1     pooka  * 2. Redistributions in binary form must reproduce the above copyright
     15        1.1     pooka  *    notice, this list of conditions and the following disclaimer in the
     16        1.1     pooka  *    documentation and/or other materials provided with the distribution.
     17        1.1     pooka  *
     18        1.1     pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     19        1.1     pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20        1.1     pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21        1.1     pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     22        1.1     pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23        1.1     pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     24        1.1     pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25        1.1     pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26        1.1     pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27        1.1     pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28        1.1     pooka  * SUCH DAMAGE.
     29        1.1     pooka  */
     30        1.1     pooka 
     31        1.1     pooka #include <sys/cdefs.h>
     32        1.1     pooka #if !defined(lint)
     33  1.27.40.1  christos __RCSID("$NetBSD: callcontext.c,v 1.27.40.1 2019/06/10 22:05:26 christos Exp $");
     34        1.1     pooka #endif /* !lint */
     35        1.1     pooka 
     36        1.1     pooka #include <sys/types.h>
     37       1.11     pooka #include <sys/mman.h>
     38        1.1     pooka 
     39        1.1     pooka #include <assert.h>
     40        1.9     pooka #include <errno.h>
     41        1.1     pooka #include <puffs.h>
     42        1.1     pooka #include <stdio.h>
     43        1.1     pooka #include <stdlib.h>
     44        1.1     pooka #include <string.h>
     45        1.3     pooka #include <ucontext.h>
     46       1.14     pooka #include <unistd.h>
     47        1.1     pooka 
     48        1.1     pooka #include "puffs_priv.h"
     49        1.1     pooka 
     50       1.22     pooka #if 0
     51       1.22     pooka #define DPRINTF(x) printf x
     52       1.22     pooka #else
     53       1.22     pooka #define DPRINTF(x)
     54       1.22     pooka #endif
     55       1.22     pooka 
     56        1.1     pooka /*
     57       1.20     pooka  * Set the following to 1 to not handle each request on a separate
     58       1.20     pooka  * stack.  This is highly volatile kludge, therefore no external
     59       1.20     pooka  * interface.
     60       1.20     pooka  */
     61       1.20     pooka int puffs_fakecc;
     62       1.20     pooka 
     63       1.20     pooka /*
     64        1.1     pooka  * user stuff
     65        1.1     pooka  */
     66        1.1     pooka 
     67       1.20     pooka /*
     68       1.20     pooka  * So, we need to get back to where we came from.  This can happen in two
     69       1.20     pooka  * different ways:
     70       1.20     pooka  *  1) PCC_MLCONT is set, in which case we need to go to the mainloop
     71       1.20     pooka  *  2) It is not set, and we simply jump to pcc_uc_ret.
     72       1.20     pooka  */
     73        1.1     pooka void
     74        1.1     pooka puffs_cc_yield(struct puffs_cc *pcc)
     75        1.1     pooka {
     76       1.20     pooka 	struct puffs_cc *jumpcc;
     77       1.20     pooka 	int rv;
     78       1.20     pooka 
     79       1.20     pooka 	assert(puffs_fakecc == 0);
     80        1.1     pooka 
     81       1.26      yamt 	if ((~pcc->pcc_flags & (PCC_BORROWED|PCC_DONE)) == 0) {
     82       1.26      yamt 		pcc->pcc_flags &= ~(PCC_BORROWED|PCC_DONE);
     83       1.26      yamt 		/*
     84       1.26      yamt 		 * see the XXX comment in puffs__cc_cont
     85       1.26      yamt 		 */
     86       1.26      yamt 		puffs__cc_destroy(pcc, 1);
     87       1.26      yamt 		setcontext(&pcc->pcc_uc_ret);
     88       1.26      yamt 	}
     89        1.6     pooka 	pcc->pcc_flags &= ~PCC_BORROWED;
     90        1.1     pooka 
     91        1.1     pooka 	/* romanes eunt domus */
     92       1.22     pooka 	DPRINTF(("puffs_cc_yield: "));
     93       1.20     pooka 	if ((pcc->pcc_flags & PCC_MLCONT) == 0) {
     94       1.22     pooka 		DPRINTF(("no mlcont, pcc %p\n", pcc));
     95       1.20     pooka 		swapcontext(&pcc->pcc_uc, &pcc->pcc_uc_ret);
     96       1.20     pooka 	} else {
     97       1.22     pooka 		DPRINTF(("mlcont, pcc %p\n", pcc));
     98       1.20     pooka 		pcc->pcc_flags &= ~PCC_MLCONT;
     99       1.20     pooka 		rv = puffs__cc_create(pcc->pcc_pu, puffs__theloop, &jumpcc);
    100       1.20     pooka 		if (rv)
    101       1.20     pooka 			abort(); /* p-p-p-pa-pa-panic (XXX: fixme) */
    102       1.20     pooka 		swapcontext(&pcc->pcc_uc, &jumpcc->pcc_uc);
    103       1.22     pooka 		DPRINTF(("puffs_cc_yield: post swap pcc %p\n", pcc));
    104       1.20     pooka 	}
    105       1.20     pooka }
    106       1.20     pooka 
    107       1.20     pooka /*
    108       1.20     pooka  * Internal continue routine.  This has slightly different semantics.
    109       1.20     pooka  * We simply make our cc available in the freelist and jump to the
    110       1.20     pooka  * indicated pcc.
    111       1.20     pooka  */
    112       1.20     pooka void
    113       1.20     pooka puffs__cc_cont(struct puffs_cc *pcc)
    114       1.20     pooka {
    115       1.20     pooka 	struct puffs_cc *mycc;
    116       1.20     pooka 
    117       1.20     pooka 	mycc = puffs_cc_getcc(pcc->pcc_pu);
    118       1.22     pooka 	DPRINTF(("puffs__cc_cont: pcc %p, mycc %p\n", pcc, mycc));
    119       1.20     pooka 
    120       1.20     pooka 	/*
    121       1.24      yamt 	 * XXX: race between setcontext() and recycle if
    122       1.20     pooka 	 * we go multithreaded
    123       1.20     pooka 	 */
    124       1.20     pooka 	puffs__cc_destroy(mycc, 1);
    125       1.20     pooka 	pcc->pcc_flags |= PCC_MLCONT;
    126       1.20     pooka 	setcontext(&pcc->pcc_uc);
    127        1.1     pooka }
    128        1.1     pooka 
    129        1.1     pooka void
    130        1.1     pooka puffs_cc_continue(struct puffs_cc *pcc)
    131        1.1     pooka {
    132        1.1     pooka 
    133        1.1     pooka 	/* ramble on */
    134       1.22     pooka 	DPRINTF(("puffs_cc_continue: pcc %p\n", pcc));
    135       1.22     pooka 	if (puffs_fakecc) {
    136       1.20     pooka 		pcc->pcc_func(pcc->pcc_farg);
    137       1.22     pooka 	} else {
    138       1.20     pooka 		swapcontext(&pcc->pcc_uc_ret, &pcc->pcc_uc);
    139       1.22     pooka 	}
    140        1.1     pooka }
    141        1.1     pooka 
    142        1.6     pooka /*
    143        1.6     pooka  * "Borrows" pcc, *NOT* called from pcc owner.  Acts like continue.
    144        1.6     pooka  * So the idea is to use this, give something the context back to
    145        1.6     pooka  * run to completion and then jump back to where ever this was called
    146        1.6     pooka  * from after the op dispatching is complete (or if the pcc decides to
    147        1.6     pooka  * yield again).
    148        1.6     pooka  */
    149        1.6     pooka void
    150       1.20     pooka puffs__goto(struct puffs_cc *loanpcc)
    151        1.6     pooka {
    152        1.6     pooka 
    153        1.6     pooka 	loanpcc->pcc_flags |= PCC_BORROWED;
    154        1.6     pooka 
    155        1.6     pooka 	swapcontext(&loanpcc->pcc_uc_ret, &loanpcc->pcc_uc);
    156        1.6     pooka }
    157        1.6     pooka 
    158       1.10     pooka void
    159       1.10     pooka puffs_cc_schedule(struct puffs_cc *pcc)
    160       1.10     pooka {
    161       1.10     pooka 	struct puffs_usermount *pu = pcc->pcc_pu;
    162       1.10     pooka 
    163       1.10     pooka 	assert(pu->pu_state & PU_INLOOP);
    164       1.18     pooka 	TAILQ_INSERT_TAIL(&pu->pu_sched, pcc, pcc_schedent);
    165       1.10     pooka }
    166       1.10     pooka 
    167        1.9     pooka int
    168        1.9     pooka puffs_cc_getcaller(struct puffs_cc *pcc, pid_t *pid, lwpid_t *lid)
    169        1.9     pooka {
    170        1.9     pooka 
    171        1.9     pooka 	if ((pcc->pcc_flags & PCC_HASCALLER) == 0) {
    172        1.9     pooka 		errno = ESRCH;
    173        1.9     pooka 		return -1;
    174        1.9     pooka 	}
    175        1.9     pooka 
    176        1.9     pooka 	if (pid)
    177        1.9     pooka 		*pid = pcc->pcc_pid;
    178        1.9     pooka 	if (lid)
    179        1.9     pooka 		*lid = pcc->pcc_lid;
    180        1.9     pooka 	return 0;
    181        1.9     pooka }
    182        1.9     pooka 
    183       1.14     pooka static struct puffs_cc fakecc;
    184       1.14     pooka 
    185       1.20     pooka static struct puffs_cc *
    186       1.20     pooka slowccalloc(struct puffs_usermount *pu)
    187        1.1     pooka {
    188        1.1     pooka 	struct puffs_cc *volatile pcc;
    189       1.20     pooka 	void *sp;
    190       1.11     pooka 	size_t stacksize = 1<<pu->pu_cc_stackshift;
    191       1.27     skrll 	const long psize = sysconf(_SC_PAGESIZE);
    192        1.1     pooka 
    193       1.20     pooka 	if (puffs_fakecc)
    194       1.20     pooka 		return &fakecc;
    195       1.18     pooka 
    196       1.20     pooka 	sp = mmap(NULL, stacksize, PROT_READ|PROT_WRITE,
    197       1.20     pooka 	    MAP_ANON|MAP_PRIVATE|MAP_ALIGNED(pu->pu_cc_stackshift), -1, 0);
    198       1.20     pooka 	if (sp == MAP_FAILED)
    199       1.20     pooka 		return NULL;
    200       1.14     pooka 
    201       1.20     pooka 	pcc = sp;
    202        1.1     pooka 	memset(pcc, 0, sizeof(struct puffs_cc));
    203       1.12     pooka 
    204       1.27     skrll #ifndef __MACHINE_STACK_GROWS_UP
    205       1.20     pooka 	mprotect((uint8_t *)sp + psize, (size_t)psize, PROT_NONE);
    206       1.27     skrll #else
    207       1.27     skrll 	mprotect((uint8_t *)sp + stacksize - psize, (size_t)psize, PROT_NONE);
    208       1.27     skrll #endif
    209        1.1     pooka 
    210        1.1     pooka 	/* initialize both ucontext's */
    211        1.1     pooka 	if (getcontext(&pcc->pcc_uc) == -1) {
    212       1.14     pooka 		munmap(pcc, stacksize);
    213       1.20     pooka 		return NULL;
    214        1.1     pooka 	}
    215        1.1     pooka 	if (getcontext(&pcc->pcc_uc_ret) == -1) {
    216       1.14     pooka 		munmap(pcc, stacksize);
    217       1.20     pooka 		return NULL;
    218        1.1     pooka 	}
    219        1.1     pooka 
    220       1.20     pooka 	return pcc;
    221       1.20     pooka }
    222       1.12     pooka 
    223       1.20     pooka int
    224       1.20     pooka puffs__cc_create(struct puffs_usermount *pu, puffs_ccfunc func,
    225       1.20     pooka 	struct puffs_cc **pccp)
    226       1.20     pooka {
    227       1.20     pooka 	struct puffs_cc *pcc;
    228       1.20     pooka 	size_t stacksize = 1<<pu->pu_cc_stackshift;
    229       1.20     pooka 	stack_t *st;
    230       1.18     pooka 
    231       1.20     pooka 	/* Do we have a cached copy? */
    232       1.20     pooka 	if (pu->pu_cc_nstored == 0) {
    233       1.20     pooka 		pcc = slowccalloc(pu);
    234       1.20     pooka 		if (pcc == NULL)
    235       1.20     pooka 			return -1;
    236       1.20     pooka 		pcc->pcc_pu = pu;
    237       1.23     pooka 		DPRINTF(("puffs__cc_create: allocated pcc %p\n", pcc));
    238       1.20     pooka 	} else {
    239       1.20     pooka 		pcc = LIST_FIRST(&pu->pu_ccmagazin);
    240       1.20     pooka 		assert(pcc != NULL);
    241       1.18     pooka 
    242       1.20     pooka 		LIST_REMOVE(pcc, pcc_rope);
    243       1.20     pooka 		pu->pu_cc_nstored--;
    244       1.23     pooka 		DPRINTF(("puffs__cc_create: magazin pcc %p\n", pcc));
    245       1.20     pooka 	}
    246       1.20     pooka 	assert(pcc->pcc_pu == pu);
    247       1.18     pooka 
    248       1.20     pooka 	if (puffs_fakecc) {
    249       1.20     pooka 		pcc->pcc_func = func;
    250       1.20     pooka 		pcc->pcc_farg = pcc;
    251       1.20     pooka 	} else {
    252       1.27     skrll 		const long psize = sysconf(_SC_PAGESIZE);
    253       1.27     skrll 
    254       1.20     pooka 		/* link context */
    255       1.20     pooka 		pcc->pcc_uc.uc_link = &pcc->pcc_uc_ret;
    256        1.1     pooka 
    257       1.20     pooka 		/* setup stack
    258       1.20     pooka 		 *
    259       1.20     pooka 		 * XXX: I guess this should theoretically be preserved by
    260       1.20     pooka 		 * swapcontext().  However, it gets lost.  So reinit it.
    261       1.20     pooka 		 */
    262       1.20     pooka 		st = &pcc->pcc_uc.uc_stack;
    263       1.27     skrll 		st->ss_sp = ((uint8_t *)(void *)pcc) + psize;
    264       1.27     skrll 		st->ss_size = stacksize - psize;
    265       1.20     pooka 		st->ss_flags = 0;
    266       1.20     pooka 
    267       1.20     pooka 		/*
    268       1.20     pooka 		 * Give us an initial context to jump to.
    269       1.20     pooka 		 *
    270       1.20     pooka 		 * Our manual page says that portable code shouldn't
    271       1.20     pooka 		 * rely on being able to pass pointers through makecontext().
    272       1.20     pooka 		 * kjk says that NetBSD code doesn't need to worry about this.
    273       1.20     pooka 		 * uwe says it would be like putting a "keep away from
    274       1.20     pooka 		 * children" sign on a box of toys.
    275       1.20     pooka 		 */
    276       1.20     pooka 		makecontext(&pcc->pcc_uc, (void *)func, 1, (uintptr_t)pcc);
    277       1.20     pooka 	}
    278       1.19     pooka 
    279       1.12     pooka 	*pccp = pcc;
    280       1.12     pooka 	return 0;
    281        1.1     pooka }
    282        1.1     pooka 
    283        1.1     pooka void
    284       1.20     pooka puffs__cc_setcaller(struct puffs_cc *pcc, pid_t pid, lwpid_t lid)
    285        1.9     pooka {
    286        1.9     pooka 
    287        1.9     pooka 	pcc->pcc_pid = pid;
    288        1.9     pooka 	pcc->pcc_lid = lid;
    289        1.9     pooka 	pcc->pcc_flags |= PCC_HASCALLER;
    290        1.9     pooka }
    291        1.9     pooka 
    292       1.23     pooka static void
    293       1.23     pooka cc_free(struct puffs_cc *pcc)
    294       1.23     pooka {
    295       1.23     pooka 	struct puffs_usermount *pu = pcc->pcc_pu;
    296       1.23     pooka 	size_t stacksize = 1<<pu->pu_cc_stackshift;
    297       1.23     pooka 
    298       1.23     pooka 	DPRINTF(("invalidating pcc %p\n", pcc));
    299       1.23     pooka 	assert(!puffs_fakecc);
    300       1.23     pooka 	munmap(pcc, stacksize);
    301       1.23     pooka }
    302       1.23     pooka 
    303        1.9     pooka void
    304       1.20     pooka puffs__cc_destroy(struct puffs_cc *pcc, int nonuke)
    305        1.1     pooka {
    306       1.11     pooka 	struct puffs_usermount *pu = pcc->pcc_pu;
    307        1.1     pooka 
    308       1.25      yamt 	pcc->pcc_flags &= ~PCC_HASCALLER;
    309       1.21     pooka 	assert(pcc->pcc_flags == 0);
    310       1.23     pooka 	assert(!puffs_fakecc);
    311       1.20     pooka 
    312       1.20     pooka 	/* not over limit?  stuff away in the store, otherwise nuke */
    313       1.20     pooka 	if (nonuke || pu->pu_cc_nstored < PUFFS_CCMAXSTORE) {
    314       1.20     pooka 		pcc->pcc_pb = NULL;
    315       1.23     pooka 		DPRINTF(("puffs__cc_destroy: storing pcc %p\n", pcc));
    316       1.18     pooka 		LIST_INSERT_HEAD(&pu->pu_ccmagazin, pcc, pcc_rope);
    317       1.18     pooka 		pu->pu_cc_nstored++;
    318       1.20     pooka 	} else {
    319       1.23     pooka 		cc_free(pcc);
    320       1.23     pooka 	}
    321       1.23     pooka }
    322       1.23     pooka 
    323       1.23     pooka void
    324       1.23     pooka puffs__cc_exit(struct puffs_usermount *pu)
    325       1.23     pooka {
    326       1.23     pooka 	struct puffs_cc *pcc;
    327       1.23     pooka 
    328       1.23     pooka 	while ((pcc = LIST_FIRST(&pu->pu_ccmagazin)) != NULL) {
    329       1.23     pooka 		LIST_REMOVE(pcc, pcc_rope);
    330       1.23     pooka 		cc_free(pcc);
    331       1.18     pooka 	}
    332       1.14     pooka }
    333       1.14     pooka 
    334       1.14     pooka struct puffs_cc *
    335       1.14     pooka puffs_cc_getcc(struct puffs_usermount *pu)
    336       1.14     pooka {
    337       1.14     pooka 	size_t stacksize = 1<<pu->pu_cc_stackshift;
    338       1.14     pooka 	uintptr_t bottom;
    339       1.14     pooka 
    340       1.14     pooka 	if (puffs_fakecc)
    341       1.14     pooka 		return &fakecc;
    342       1.14     pooka 
    343       1.14     pooka 	bottom = ((uintptr_t)&bottom) & ~(stacksize-1);
    344       1.14     pooka 	return (struct puffs_cc *)bottom;
    345        1.1     pooka }
    346       1.22     pooka 
    347       1.22     pooka int
    348       1.22     pooka puffs__cc_savemain(struct puffs_usermount *pu)
    349       1.22     pooka {
    350       1.22     pooka 
    351       1.23     pooka 	if (puffs_fakecc)
    352       1.23     pooka 		return 0;
    353       1.23     pooka 
    354       1.22     pooka 	PU_CLRSFLAG(pu, PU_MAINRESTORE);
    355       1.22     pooka 	return getcontext(&pu->pu_mainctx);
    356       1.22     pooka }
    357       1.22     pooka 
    358       1.22     pooka int
    359       1.22     pooka puffs__cc_restoremain(struct puffs_usermount *pu)
    360       1.22     pooka {
    361       1.22     pooka 
    362       1.23     pooka 	if (puffs_fakecc)
    363       1.23     pooka 		return 0;
    364       1.23     pooka 
    365       1.23     pooka 	puffs__cc_destroy(puffs_cc_getcc(pu), 1);
    366       1.22     pooka 	PU_SETSFLAG(pu, PU_MAINRESTORE);
    367       1.22     pooka 	return setcontext(&pu->pu_mainctx);
    368       1.22     pooka }
    369