summaryrefslogtreecommitdiff
path: root/lib/libpuffs/callcontext.c
diff options
context:
space:
mode:
authorpooka <pooka@NetBSD.org>2008-01-28 18:35:49 +0000
committerpooka <pooka@NetBSD.org>2008-01-28 18:35:49 +0000
commitd1d05d65b94de0b1c74d001d0f98e05b646d538f (patch)
tree7dd80f18258298311bb60954621b95a3c4a2b673 /lib/libpuffs/callcontext.c
parentf3b8aacb17bf459faf28a2822562269980f4be59 (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.c255
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;