Annotation of src/lib/libpuffs/callcontext.c, Revision 1.7.4.2
1.7.4.2 ! matt 1: /* $NetBSD$ */
1.1 pooka 2:
3: /*
4: * Copyright (c) 2006 Antti Kantee. All Rights Reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: */
27:
28: #include <sys/cdefs.h>
29: #if !defined(lint)
1.7.4.2 ! matt 30: __RCSID("$NetBSD$");
1.1 pooka 31: #endif /* !lint */
32:
33: #include <sys/types.h>
1.7.4.1 matt 34: #include <sys/mman.h>
1.1 pooka 35:
36: #include <assert.h>
1.7.4.1 matt 37: #include <errno.h>
38: #ifdef PUFFS_WITH_THREADS
39: #include <pthread.h>
40: #endif
1.1 pooka 41: #include <puffs.h>
42: #include <stdio.h>
43: #include <stdlib.h>
44: #include <string.h>
1.3 pooka 45: #include <ucontext.h>
1.7.4.2 ! matt 46: #include <unistd.h>
1.1 pooka 47:
48: #include "puffs_priv.h"
49:
50: /*
51: * user stuff
52: */
53:
54: void
55: puffs_cc_yield(struct puffs_cc *pcc)
56: {
57:
1.5 pooka 58: assert(pcc->pcc_flags & PCC_REALCC);
1.6 pooka 59: pcc->pcc_flags &= ~PCC_BORROWED;
1.1 pooka 60:
61: /* romanes eunt domus */
62: swapcontext(&pcc->pcc_uc, &pcc->pcc_uc_ret);
63: }
64:
65: void
66: puffs_cc_continue(struct puffs_cc *pcc)
67: {
68:
1.5 pooka 69: assert(pcc->pcc_flags & PCC_REALCC);
70:
1.1 pooka 71: /* ramble on */
72: swapcontext(&pcc->pcc_uc_ret, &pcc->pcc_uc);
73: }
74:
1.6 pooka 75: /*
76: * "Borrows" pcc, *NOT* called from pcc owner. Acts like continue.
77: * So the idea is to use this, give something the context back to
78: * run to completion and then jump back to where ever this was called
79: * from after the op dispatching is complete (or if the pcc decides to
80: * yield again).
81: */
82: void
83: puffs_goto(struct puffs_cc *loanpcc)
84: {
85:
86: assert(loanpcc->pcc_flags & PCC_REALCC);
87: loanpcc->pcc_flags |= PCC_BORROWED;
88:
89: swapcontext(&loanpcc->pcc_uc_ret, &loanpcc->pcc_uc);
90: }
91:
1.7.4.1 matt 92: void
93: puffs_cc_schedule(struct puffs_cc *pcc)
94: {
95: struct puffs_usermount *pu = pcc->pcc_pu;
96:
97: assert(pu->pu_state & PU_INLOOP);
98: TAILQ_INSERT_TAIL(&pu->pu_sched, pcc, entries);
99: }
100:
101: int
102: puffs_cc_getcaller(struct puffs_cc *pcc, pid_t *pid, lwpid_t *lid)
103: {
104:
105: if ((pcc->pcc_flags & PCC_HASCALLER) == 0) {
106: errno = ESRCH;
107: return -1;
108: }
109:
110: if (pid)
111: *pid = pcc->pcc_pid;
112: if (lid)
113: *lid = pcc->pcc_lid;
114: return 0;
115: }
116:
117: #ifdef PUFFS_WITH_THREADS
118: int pthread__stackid_setup(void *, size_t, pthread_t *);
119: #endif
120:
1.7.4.2 ! matt 121: /* for fakecc-users, need only one */
! 122: static struct puffs_cc fakecc;
! 123:
1.7.4.1 matt 124: int
1.7.4.2 ! matt 125: puffs_cc_create(struct puffs_usermount *pu, struct puffs_framebuf *pb,
1.7.4.1 matt 126: int type, struct puffs_cc **pccp)
1.1 pooka 127: {
128: struct puffs_cc *volatile pcc;
1.7.4.1 matt 129: size_t stacksize = 1<<pu->pu_cc_stackshift;
1.7.4.2 ! matt 130: long psize = sysconf(_SC_PAGESIZE);
1.1 pooka 131: stack_t *st;
1.7.4.2 ! matt 132: void *volatile sp;
1.7.4.1 matt 133:
134: #ifdef PUFFS_WITH_THREADS
135: extern size_t pthread__stacksize;
136: stacksize = pthread__stacksize;
137: #endif
1.1 pooka 138:
1.7.4.2 ! matt 139: /*
! 140: * There are two paths and in the long run we don't have time to
! 141: * change the one we're on. For non-real cc's, we just simply use
! 142: * a static copy. For the other cases, we mmap the stack and
! 143: * manually reserve a bit from the top for the data structure
! 144: * (or, well, the bottom).
! 145: *
! 146: * XXX: threaded mode doesn't work very well now. Not that it's
! 147: * supported anyhow.
! 148: */
! 149: if (type == PCC_FAKECC) {
! 150: pcc = &fakecc;
! 151: sp = NULL;
! 152: } else {
! 153: sp = mmap(NULL, stacksize, PROT_READ|PROT_WRITE,
! 154: MAP_ANON|MAP_PRIVATE|MAP_ALIGNED(pu->pu_cc_stackshift),
! 155: -1, 0);
! 156: if (sp == MAP_FAILED)
! 157: return -1;
! 158:
! 159: pcc = sp;
! 160: sp = (uint8_t *)sp + psize;
! 161: }
! 162:
1.1 pooka 163: memset(pcc, 0, sizeof(struct puffs_cc));
164: pcc->pcc_pu = pu;
1.7.4.2 ! matt 165: pcc->pcc_pb = pb;
1.7.4.1 matt 166: pcc->pcc_flags = type;
1.7.4.2 ! matt 167:
! 168: /* Not a real cc? Don't need to init more */
1.7.4.1 matt 169: if (pcc->pcc_flags != PCC_REALCC)
170: goto out;
1.1 pooka 171:
172: /* initialize both ucontext's */
173: if (getcontext(&pcc->pcc_uc) == -1) {
1.7.4.2 ! matt 174: munmap(pcc, stacksize);
1.7.4.1 matt 175: return -1;
1.1 pooka 176: }
177: if (getcontext(&pcc->pcc_uc_ret) == -1) {
1.7.4.2 ! matt 178: munmap(pcc, stacksize);
1.7.4.1 matt 179: return -1;
1.1 pooka 180: }
181: /* return here. it won't actually be "here" due to swapcontext() */
182: pcc->pcc_uc.uc_link = &pcc->pcc_uc_ret;
183:
184: /* allocate stack for execution */
185: st = &pcc->pcc_uc.uc_stack;
1.7.4.2 ! matt 186:
1.7.4.1 matt 187: st->ss_sp = pcc->pcc_stack = sp;
1.7.4.2 ! matt 188: st->ss_size = stacksize - psize;
1.1 pooka 189: st->ss_flags = 0;
190:
1.7.4.1 matt 191: #ifdef PUFFS_WITH_THREADS
192: {
193: pthread_t pt;
194: extern int __isthreaded;
195: if (__isthreaded)
1.7.4.2 ! matt 196: pthread__stackid_setup(sp, stacksize /* XXXb0rked */, &pt);
1.7.4.1 matt 197: }
198: #endif
199:
1.1 pooka 200: /*
201: * Give us an initial context to jump to.
202: *
203: * XXX: Our manual page says that portable code shouldn't rely on
204: * being able to pass pointers through makecontext(). kjk says
205: * that NetBSD code doesn't need to worry about this. uwe says
206: * it would be like putting a "keep away from children" sign on a
207: * box of toys. I didn't ask what simon says; he's probably busy
208: * "fixing" typos in comments.
209: */
210: makecontext(&pcc->pcc_uc, (void *)puffs_calldispatcher,
211: 1, (uintptr_t)pcc);
212:
1.7.4.1 matt 213: out:
214: *pccp = pcc;
215: return 0;
216: }
217:
218: void
219: puffs_cc_setcaller(struct puffs_cc *pcc, pid_t pid, lwpid_t lid)
220: {
221:
222: pcc->pcc_pid = pid;
223: pcc->pcc_lid = lid;
224: pcc->pcc_flags |= PCC_HASCALLER;
1.1 pooka 225: }
226:
227: void
228: puffs_cc_destroy(struct puffs_cc *pcc)
229: {
1.7.4.1 matt 230: struct puffs_usermount *pu = pcc->pcc_pu;
231: size_t stacksize = 1<<pu->pu_cc_stackshift;
1.1 pooka 232:
1.7.4.1 matt 233: #ifdef PUFFS_WITH_THREADS
234: extern size_t pthread__stacksize;
235: stacksize = pthread__stacksize;
236: #endif
237:
1.7.4.2 ! matt 238: if ((pcc->pcc_flags & PCC_FAKECC) == 0)
! 239: munmap(pcc, stacksize);
! 240: }
! 241:
! 242: struct puffs_cc *
! 243: puffs_cc_getcc(struct puffs_usermount *pu)
! 244: {
! 245: extern int puffs_fakecc, puffs_usethreads;
! 246: size_t stacksize = 1<<pu->pu_cc_stackshift;
! 247: uintptr_t bottom;
! 248:
! 249: if (puffs_fakecc)
! 250: return &fakecc;
! 251: #ifndef PUFFS_WITH_THREADS
! 252: if (puffs_usethreads)
! 253: return &fakecc;
! 254: #endif
! 255:
! 256: bottom = ((uintptr_t)&bottom) & ~(stacksize-1);
! 257: return (struct puffs_cc *)bottom;
1.1 pooka 258: }
CVSweb <webmaster@jp.NetBSD.org>