Home | History | Annotate | Line # | Download | only in libpuffs
      1  1.30  christos /*	$NetBSD: callcontext.c,v 1.30 2018/07/09 00:47:47 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.30  christos __RCSID("$NetBSD: callcontext.c,v 1.30 2018/07/09 00:47:47 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.30  christos 	    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