diff options
| author | pooka <pooka@NetBSD.org> | 2008-01-28 18:35:49 +0000 |
|---|---|---|
| committer | pooka <pooka@NetBSD.org> | 2008-01-28 18:35:49 +0000 |
| commit | d1d05d65b94de0b1c74d001d0f98e05b646d538f (patch) | |
| tree | 7dd80f18258298311bb60954621b95a3c4a2b673 /lib/libpuffs/callcontext.c | |
| parent | f3b8aacb17bf459faf28a2822562269980f4be59 (diff) | |
Implement lazy contexts for file systems using puffs_mainloop().
Previously each request was executed on its own callcontext and
switched to every time the request was being processed. Now requests
borrow the mainloop context and switch only if/when they yield.
This takes two context switches away from a file system request
bringing down the typical amounts 2->0 (e.g. dtfs) and 4->2 (e.g.
psshfs).
The interfaces for manually executing requests changed a bit:
puffs_dispatch_create() and puffs_dispatch_exec() must now be used.
They are not tested, as nothing in-tree wants them and I doubt
anyone else is really interested in them either.
Also do some misc code cleanup related to execution contexts. The
"work-in-progress checkpoint" committed over a year ago was starting
to look slightly weed-infested.
Diffstat (limited to 'lib/libpuffs/callcontext.c')
| -rw-r--r-- | lib/libpuffs/callcontext.c | 255 |
1 files changed, 131 insertions, 124 deletions
diff --git a/lib/libpuffs/callcontext.c b/lib/libpuffs/callcontext.c index e3f7db48c84..7aa4a719ce5 100644 --- a/lib/libpuffs/callcontext.c +++ b/lib/libpuffs/callcontext.c @@ -1,7 +1,10 @@ -/* $NetBSD: callcontext.c,v 1.19 2008/01/17 17:43:14 pooka Exp $ */ +/* $NetBSD: callcontext.c,v 1.20 2008/01/28 18:35:49 pooka Exp $ */ /* - * Copyright (c) 2006 Antti Kantee. All Rights Reserved. + * Copyright (c) 2006, 2007, 2008 Antti Kantee. All Rights Reserved. + * + * Development of this software was supported by the + * Research Foundation of Helsinki University of Technology * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,7 +30,7 @@ #include <sys/cdefs.h> #if !defined(lint) -__RCSID("$NetBSD: callcontext.c,v 1.19 2008/01/17 17:43:14 pooka Exp $"); +__RCSID("$NetBSD: callcontext.c,v 1.20 2008/01/28 18:35:49 pooka Exp $"); #endif /* !lint */ #include <sys/types.h> @@ -35,9 +38,6 @@ __RCSID("$NetBSD: callcontext.c,v 1.19 2008/01/17 17:43:14 pooka Exp $"); #include <assert.h> #include <errno.h> -#ifdef PUFFS_WITH_THREADS -#include <pthread.h> -#endif #include <puffs.h> #include <stdio.h> #include <stdlib.h> @@ -48,28 +48,74 @@ __RCSID("$NetBSD: callcontext.c,v 1.19 2008/01/17 17:43:14 pooka Exp $"); #include "puffs_priv.h" /* + * Set the following to 1 to not handle each request on a separate + * stack. This is highly volatile kludge, therefore no external + * interface. + */ +int puffs_fakecc; + +/* * user stuff */ +/* + * So, we need to get back to where we came from. This can happen in two + * different ways: + * 1) PCC_MLCONT is set, in which case we need to go to the mainloop + * 2) It is not set, and we simply jump to pcc_uc_ret. + */ void puffs_cc_yield(struct puffs_cc *pcc) { + struct puffs_cc *jumpcc; + int rv; + + assert(puffs_fakecc == 0); - assert(pcc->pcc_flags & PCC_REALCC); pcc->pcc_flags &= ~PCC_BORROWED; /* romanes eunt domus */ - swapcontext(&pcc->pcc_uc, &pcc->pcc_uc_ret); + if ((pcc->pcc_flags & PCC_MLCONT) == 0) { + swapcontext(&pcc->pcc_uc, &pcc->pcc_uc_ret); + } else { + pcc->pcc_flags &= ~PCC_MLCONT; + rv = puffs__cc_create(pcc->pcc_pu, puffs__theloop, &jumpcc); + if (rv) + abort(); /* p-p-p-pa-pa-panic (XXX: fixme) */ + swapcontext(&pcc->pcc_uc, &jumpcc->pcc_uc); + } } +/* + * Internal continue routine. This has slightly different semantics. + * We simply make our cc available in the freelist and jump to the + * indicated pcc. + */ void -puffs_cc_continue(struct puffs_cc *pcc) +puffs__cc_cont(struct puffs_cc *pcc) { + struct puffs_cc *mycc; - assert(pcc->pcc_flags & PCC_REALCC); + mycc = puffs_cc_getcc(pcc->pcc_pu); + + /* + * XXX: race between setcontenxt() and recycle if + * we go multithreaded + */ + puffs__cc_destroy(mycc, 1); + pcc->pcc_flags |= PCC_MLCONT; + setcontext(&pcc->pcc_uc); +} + +void +puffs_cc_continue(struct puffs_cc *pcc) +{ /* ramble on */ - swapcontext(&pcc->pcc_uc_ret, &pcc->pcc_uc); + if (puffs_fakecc) + pcc->pcc_func(pcc->pcc_farg); + else + swapcontext(&pcc->pcc_uc_ret, &pcc->pcc_uc); } /* @@ -80,10 +126,9 @@ puffs_cc_continue(struct puffs_cc *pcc) * yield again). */ void -puffs_goto(struct puffs_cc *loanpcc) +puffs__goto(struct puffs_cc *loanpcc) { - assert(loanpcc->pcc_flags & PCC_REALCC); loanpcc->pcc_flags |= PCC_BORROWED; swapcontext(&loanpcc->pcc_uc_ret, &loanpcc->pcc_uc); @@ -114,126 +159,100 @@ puffs_cc_getcaller(struct puffs_cc *pcc, pid_t *pid, lwpid_t *lid) return 0; } -#ifdef PUFFS_WITH_THREADS -int pthread__stackid_setup(void *, size_t, pthread_t *); -#endif - -/* for fakecc-users, need only one */ static struct puffs_cc fakecc; -int -puffs_cc_create(struct puffs_usermount *pu, struct puffs_framebuf *pb, - int type, struct puffs_cc **pccp) +static struct puffs_cc * +slowccalloc(struct puffs_usermount *pu) { struct puffs_cc *volatile pcc; + void *sp; size_t stacksize = 1<<pu->pu_cc_stackshift; long psize = sysconf(_SC_PAGESIZE); - stack_t *st; - void *volatile sp; - -#ifdef PUFFS_WITH_THREADS - extern size_t pthread__stacksize; - stacksize = pthread__stacksize; -#endif - - /* Do we have a cached copy? */ - if (pu->pu_cc_nstored) { - pcc = LIST_FIRST(&pu->pu_ccmagazin); - assert(pcc != NULL); - LIST_REMOVE(pcc, pcc_rope); - pu->pu_cc_nstored--; - goto finalize; - } - - /* - * There are two paths and in the long run we don't have time to - * change the one we're on. For non-real cc's, we just simply use - * a static copy. For the other cases, we mmap the stack and - * manually reserve a bit from the top for the data structure - * (or, well, the bottom). - * - * XXX: threaded mode doesn't work very well now. Not that it's - * supported anyhow. - */ - if (type == PCC_FAKECC) { - pcc = &fakecc; - sp = NULL; - } else { - sp = mmap(NULL, stacksize, PROT_READ|PROT_WRITE, - MAP_ANON|MAP_PRIVATE|MAP_ALIGNED(pu->pu_cc_stackshift), - -1, 0); - if (sp == MAP_FAILED) - return -1; + if (puffs_fakecc) + return &fakecc; - pcc = sp; - mprotect((uint8_t *)sp + psize, (size_t)psize, PROT_NONE); - } + sp = mmap(NULL, stacksize, PROT_READ|PROT_WRITE, + MAP_ANON|MAP_PRIVATE|MAP_ALIGNED(pu->pu_cc_stackshift), -1, 0); + if (sp == MAP_FAILED) + return NULL; + pcc = sp; memset(pcc, 0, sizeof(struct puffs_cc)); - pcc->pcc_pu = pu; - /* Not a real cc? Don't need to init more */ - if (type != PCC_REALCC) - goto out; + mprotect((uint8_t *)sp + psize, (size_t)psize, PROT_NONE); /* initialize both ucontext's */ if (getcontext(&pcc->pcc_uc) == -1) { munmap(pcc, stacksize); - return -1; + return NULL; } if (getcontext(&pcc->pcc_uc_ret) == -1) { munmap(pcc, stacksize); - return -1; - } - -#ifdef PUFFS_WITH_THREADS - { - pthread_t pt; - extern int __isthreaded; - if (__isthreaded) - pthread__stackid_setup(sp, stacksize /* XXXb0rked */, &pt); + return NULL; } -#endif - finalize: - assert(pcc->pcc_pu == pu); + return pcc; +} - /* return here. it won't actually be "here" due to swapcontext() */ - pcc->pcc_uc.uc_link = &pcc->pcc_uc_ret; +int +puffs__cc_create(struct puffs_usermount *pu, puffs_ccfunc func, + struct puffs_cc **pccp) +{ + struct puffs_cc *pcc; + size_t stacksize = 1<<pu->pu_cc_stackshift; + stack_t *st; - /* setup stack - * - * XXX: I guess this should theoretically be preserved by - * swapcontext(). However, it gets lost. So reinit it. - */ - st = &pcc->pcc_uc.uc_stack; - st->ss_sp = pcc; - st->ss_size = stacksize; - st->ss_flags = 0; + /* Do we have a cached copy? */ + if (pu->pu_cc_nstored == 0) { + pcc = slowccalloc(pu); + if (pcc == NULL) + return -1; + pcc->pcc_pu = pu; + } else { + pcc = LIST_FIRST(&pu->pu_ccmagazin); + assert(pcc != NULL); - /* - * Give us an initial context to jump to. - * - * XXX: Our manual page says that portable code shouldn't rely on - * being able to pass pointers through makecontext(). kjk says - * that NetBSD code doesn't need to worry about this. uwe says - * it would be like putting a "keep away from children" sign on a - * box of toys. - */ - makecontext(&pcc->pcc_uc, (void *)puffs_calldispatcher, - 1, (uintptr_t)pcc); + LIST_REMOVE(pcc, pcc_rope); + pu->pu_cc_nstored--; + } + assert(pcc->pcc_pu == pu); - out: - pcc->pcc_pb = pb; - pcc->pcc_flags = type; + if (puffs_fakecc) { + pcc->pcc_func = func; + pcc->pcc_farg = pcc; + } else { + /* link context */ + pcc->pcc_uc.uc_link = &pcc->pcc_uc_ret; + + /* setup stack + * + * XXX: I guess this should theoretically be preserved by + * swapcontext(). However, it gets lost. So reinit it. + */ + st = &pcc->pcc_uc.uc_stack; + st->ss_sp = pcc; + st->ss_size = stacksize; + st->ss_flags = 0; + + /* + * Give us an initial context to jump to. + * + * Our manual page says that portable code shouldn't + * rely on being able to pass pointers through makecontext(). + * kjk says that NetBSD code doesn't need to worry about this. + * uwe says it would be like putting a "keep away from + * children" sign on a box of toys. + */ + makecontext(&pcc->pcc_uc, (void *)func, 1, (uintptr_t)pcc); + } *pccp = pcc; return 0; } void -puffs_cc_setcaller(struct puffs_cc *pcc, pid_t pid, lwpid_t lid) +puffs__cc_setcaller(struct puffs_cc *pcc, pid_t pid, lwpid_t lid) { pcc->pcc_pid = pid; @@ -242,44 +261,32 @@ puffs_cc_setcaller(struct puffs_cc *pcc, pid_t pid, lwpid_t lid) } void -puffs_cc_destroy(struct puffs_cc *pcc) +puffs__cc_destroy(struct puffs_cc *pcc, int nonuke) { struct puffs_usermount *pu = pcc->pcc_pu; size_t stacksize = 1<<pu->pu_cc_stackshift; - /* not over limit? stuff away in the store */ - if (pu->pu_cc_nstored < PUFFS_CCMAXSTORE - && pcc->pcc_flags & PCC_REALCC) { - pcc->pcc_flags &= ~PCC_DONE; + assert(pcc->pcc_flags = 0); + + /* not over limit? stuff away in the store, otherwise nuke */ + if (nonuke || pu->pu_cc_nstored < PUFFS_CCMAXSTORE) { + pcc->pcc_pb = NULL; LIST_INSERT_HEAD(&pu->pu_ccmagazin, pcc, pcc_rope); pu->pu_cc_nstored++; - return; - } - - /* else: just dump it */ - -#ifdef PUFFS_WITH_THREADS - extern size_t pthread__stacksize; - stacksize = pthread__stacksize; -#endif - - if ((pcc->pcc_flags & PCC_FAKECC) == 0) + } else { + assert(!puffs_fakecc); munmap(pcc, stacksize); + } } struct puffs_cc * puffs_cc_getcc(struct puffs_usermount *pu) { - extern int puffs_fakecc, puffs_usethreads; size_t stacksize = 1<<pu->pu_cc_stackshift; uintptr_t bottom; if (puffs_fakecc) return &fakecc; -#ifndef PUFFS_WITH_THREADS - if (puffs_usethreads) - return &fakecc; -#endif bottom = ((uintptr_t)&bottom) & ~(stacksize-1); return (struct puffs_cc *)bottom; |
