[BACK]Return to callcontext.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libpuffs

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/lib/libpuffs/callcontext.c between version 1.19 and 1.20

version 1.19, 2008/01/17 17:43:14 version 1.20, 2008/01/28 18:35:49
Line 1 
Line 1 
 /*      $NetBSD$        */  /*      $NetBSD$        */
   
 /*  /*
  * 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   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 35  __RCSID("$NetBSD$");
Line 38  __RCSID("$NetBSD$");
   
 #include <assert.h>  #include <assert.h>
 #include <errno.h>  #include <errno.h>
 #ifdef PUFFS_WITH_THREADS  
 #include <pthread.h>  
 #endif  
 #include <puffs.h>  #include <puffs.h>
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
Line 48  __RCSID("$NetBSD$");
Line 48  __RCSID("$NetBSD$");
 #include "puffs_priv.h"  #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   * 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  void
 puffs_cc_yield(struct puffs_cc *pcc)  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;          pcc->pcc_flags &= ~PCC_BORROWED;
   
         /* romanes eunt domus */          /* 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  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 */          /* 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);
 }  }
   
 /*  /*
Line 80  puffs_cc_continue(struct puffs_cc *pcc)
Line 126  puffs_cc_continue(struct puffs_cc *pcc)
  * yield again).   * yield again).
  */   */
 void  void
 puffs_goto(struct puffs_cc *loanpcc)  puffs__goto(struct puffs_cc *loanpcc)
 {  {
   
         assert(loanpcc->pcc_flags & PCC_REALCC);  
         loanpcc->pcc_flags |= PCC_BORROWED;          loanpcc->pcc_flags |= PCC_BORROWED;
   
         swapcontext(&loanpcc->pcc_uc_ret, &loanpcc->pcc_uc);          swapcontext(&loanpcc->pcc_uc_ret, &loanpcc->pcc_uc);
Line 114  puffs_cc_getcaller(struct puffs_cc *pcc,
Line 159  puffs_cc_getcaller(struct puffs_cc *pcc,
         return 0;          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;  static struct puffs_cc fakecc;
   
 int  static struct puffs_cc *
 puffs_cc_create(struct puffs_usermount *pu, struct puffs_framebuf *pb,  slowccalloc(struct puffs_usermount *pu)
         int type, struct puffs_cc **pccp)  
 {  {
         struct puffs_cc *volatile pcc;          struct puffs_cc *volatile pcc;
           void *sp;
         size_t stacksize = 1<<pu->pu_cc_stackshift;          size_t stacksize = 1<<pu->pu_cc_stackshift;
         long psize = sysconf(_SC_PAGESIZE);          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);          if (puffs_fakecc)
                 pu->pu_cc_nstored--;                  return &fakecc;
                 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;  
   
                 pcc = sp;          sp = mmap(NULL, stacksize, PROT_READ|PROT_WRITE,
                 mprotect((uint8_t *)sp + psize, (size_t)psize, PROT_NONE);              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));          memset(pcc, 0, sizeof(struct puffs_cc));
         pcc->pcc_pu = pu;  
   
         /* Not a real cc?  Don't need to init more */          mprotect((uint8_t *)sp + psize, (size_t)psize, PROT_NONE);
         if (type != PCC_REALCC)  
                 goto out;  
   
         /* initialize both ucontext's */          /* initialize both ucontext's */
         if (getcontext(&pcc->pcc_uc) == -1) {          if (getcontext(&pcc->pcc_uc) == -1) {
                 munmap(pcc, stacksize);                  munmap(pcc, stacksize);
                 return -1;                  return NULL;
         }          }
         if (getcontext(&pcc->pcc_uc_ret) == -1) {          if (getcontext(&pcc->pcc_uc_ret) == -1) {
                 munmap(pcc, stacksize);                  munmap(pcc, stacksize);
                 return -1;                  return NULL;
         }          }
   
 #ifdef PUFFS_WITH_THREADS          return pcc;
         {  }
         pthread_t pt;  
         extern int __isthreaded;  
         if (__isthreaded)  
                 pthread__stackid_setup(sp, stacksize /* XXXb0rked */, &pt);  
         }  
 #endif  
   
  finalize:  int
         assert(pcc->pcc_pu == pu);  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;
   
         /* return here.  it won't actually be "here" due to swapcontext() */          /* Do we have a cached copy? */
         pcc->pcc_uc.uc_link = &pcc->pcc_uc_ret;          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);
   
         /* setup stack                  LIST_REMOVE(pcc, pcc_rope);
          *                  pu->pu_cc_nstored--;
          * XXX: I guess this should theoretically be preserved by          }
          * swapcontext().  However, it gets lost.  So reinit it.          assert(pcc->pcc_pu == pu);
          */  
         st = &pcc->pcc_uc.uc_stack;  
         st->ss_sp = pcc;  
         st->ss_size = stacksize;  
         st->ss_flags = 0;  
   
         /*          if (puffs_fakecc) {
          * Give us an initial context to jump to.                  pcc->pcc_func = func;
          *                  pcc->pcc_farg = pcc;
          * XXX: Our manual page says that portable code shouldn't rely on          } else {
          * being able to pass pointers through makecontext().  kjk says                  /* link context */
          * that NetBSD code doesn't need to worry about this.  uwe says                  pcc->pcc_uc.uc_link = &pcc->pcc_uc_ret;
          * 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);  
   
  out:                  /* setup stack
         pcc->pcc_pb = pb;                   *
         pcc->pcc_flags = type;                   * 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;          *pccp = pcc;
         return 0;          return 0;
 }  }
   
 void  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;          pcc->pcc_pid = pid;
Line 242  puffs_cc_setcaller(struct puffs_cc *pcc,
Line 261  puffs_cc_setcaller(struct puffs_cc *pcc,
 }  }
   
 void  void
 puffs_cc_destroy(struct puffs_cc *pcc)  puffs__cc_destroy(struct puffs_cc *pcc, int nonuke)
 {  {
         struct puffs_usermount *pu = pcc->pcc_pu;          struct puffs_usermount *pu = pcc->pcc_pu;
         size_t stacksize = 1<<pu->pu_cc_stackshift;          size_t stacksize = 1<<pu->pu_cc_stackshift;
   
         /* not over limit?  stuff away in the store */          assert(pcc->pcc_flags = 0);
         if (pu->pu_cc_nstored < PUFFS_CCMAXSTORE  
             && pcc->pcc_flags & PCC_REALCC) {          /* not over limit?  stuff away in the store, otherwise nuke */
                 pcc->pcc_flags &= ~PCC_DONE;          if (nonuke || pu->pu_cc_nstored < PUFFS_CCMAXSTORE) {
                   pcc->pcc_pb = NULL;
                 LIST_INSERT_HEAD(&pu->pu_ccmagazin, pcc, pcc_rope);                  LIST_INSERT_HEAD(&pu->pu_ccmagazin, pcc, pcc_rope);
                 pu->pu_cc_nstored++;                  pu->pu_cc_nstored++;
                 return;          } else {
         }                  assert(!puffs_fakecc);
   
         /* else: just dump it */  
   
 #ifdef PUFFS_WITH_THREADS  
         extern size_t pthread__stacksize;  
         stacksize = pthread__stacksize;  
 #endif  
   
         if ((pcc->pcc_flags & PCC_FAKECC) == 0)  
                 munmap(pcc, stacksize);                  munmap(pcc, stacksize);
           }
 }  }
   
 struct puffs_cc *  struct puffs_cc *
 puffs_cc_getcc(struct puffs_usermount *pu)  puffs_cc_getcc(struct puffs_usermount *pu)
 {  {
         extern int puffs_fakecc, puffs_usethreads;  
         size_t stacksize = 1<<pu->pu_cc_stackshift;          size_t stacksize = 1<<pu->pu_cc_stackshift;
         uintptr_t bottom;          uintptr_t bottom;
   
         if (puffs_fakecc)          if (puffs_fakecc)
                 return &fakecc;                  return &fakecc;
 #ifndef PUFFS_WITH_THREADS  
         if (puffs_usethreads)  
                 return &fakecc;  
 #endif  
   
         bottom = ((uintptr_t)&bottom) & ~(stacksize-1);          bottom = ((uintptr_t)&bottom) & ~(stacksize-1);
         return (struct puffs_cc *)bottom;          return (struct puffs_cc *)bottom;

Legend:
Removed from v.1.19  
changed lines
  Added in v.1.20

CVSweb <webmaster@jp.NetBSD.org>