2 * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $DragonFly: src/sys/kern/lwkt_token.c,v 1.1 2004/02/09 21:13:18 dillon Exp $
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
35 #include <sys/rtprio.h>
36 #include <sys/queue.h>
37 #include <sys/thread2.h>
38 #include <sys/sysctl.h>
39 #include <sys/kthread.h>
40 #include <machine/cpu.h>
45 #include <vm/vm_param.h>
46 #include <vm/vm_kern.h>
47 #include <vm/vm_object.h>
48 #include <vm/vm_page.h>
49 #include <vm/vm_map.h>
50 #include <vm/vm_pager.h>
51 #include <vm/vm_extern.h>
52 #include <vm/vm_zone.h>
54 #include <machine/stdarg.h>
55 #include <machine/ipl.h>
56 #include <machine/smp.h>
58 #define THREAD_STACK (UPAGES * PAGE_SIZE)
62 #include <sys/stdint.h>
63 #include <libcaps/thread.h>
64 #include <sys/thread.h>
65 #include <sys/msgport.h>
66 #include <sys/errno.h>
67 #include <libcaps/globaldata.h>
68 #include <sys/thread2.h>
69 #include <sys/msgport2.h>
73 #include <machine/cpufunc.h>
74 #include <machine/lock.h>
79 static int token_debug = 0;
85 SYSCTL_INT(_lwkt, OID_AUTO, token_debug, CTLFLAG_RW, &token_debug, 0, "");
90 typedef struct lwkt_gettoken_req {
96 * Acquire ownership of a token
98 * Acquire ownership of a token. The token may have spl and/or critical
99 * section side effects, depending on its purpose. These side effects
100 * guarentee that you will maintain ownership of the token as long as you
101 * do not block. If you block you may lose access to the token (but you
102 * must still release it even if you lose your access to it).
104 * YYY for now we use a critical section to prevent IPIs from taking away
105 * a token, but do we really only need to disable IPIs ?
107 * YYY certain tokens could be made to act like mutexes when performance
108 * would be better (e.g. t_cpu == -1). This is not yet implemented.
110 * YYY the tokens replace 4.x's simplelocks for the most part, but this
111 * means that 4.x does not expect a switch so for now we cannot switch
112 * when waiting for an IPI to be returned.
114 * YYY If the token is owned by another cpu we may have to send an IPI to
115 * it and then block. The IPI causes the token to be given away to the
116 * requesting cpu, unless it has already changed hands. Since only the
117 * current cpu can give away a token it owns we do not need a memory barrier.
118 * This needs serious optimization.
125 lwkt_gettoken_remote(void *arg)
127 lwkt_gettoken_req *req = arg;
128 if (req->tok->t_cpu == mycpu->gd_cpuid) {
131 printf("GT(%d,%d) ", req->tok->t_cpu, req->cpu);
133 req->tok->t_cpu = req->cpu;
134 req->tok->t_reqcpu = req->cpu; /* YYY leave owned by target cpu */
135 /* else set reqcpu to point to current cpu for release */
142 lwkt_gettoken(lwkt_token_t tok)
145 * Prevent preemption so the token can't be taken away from us once
146 * we gain ownership of it. Use a synchronous request which might
147 * block. The request will be forwarded as necessary playing catchup
153 if (curthread->td_pri > 1800) {
154 printf("lwkt_gettoken: %p called from %p: crit sect nesting warning\n",
155 tok, ((int **)&tok)[-1]);
157 if (curthread->td_pri > 2000) {
158 curthread->td_pri = 1000;
163 while (tok->t_cpu != mycpu->gd_cpuid) {
164 struct lwkt_gettoken_req req;
168 req.cpu = mycpu->gd_cpuid;
170 dcpu = (volatile int)tok->t_cpu;
171 KKASSERT(dcpu >= 0 && dcpu < ncpus);
174 printf("REQT%d ", dcpu);
176 seq = lwkt_send_ipiq(dcpu, lwkt_gettoken_remote, &req);
177 lwkt_wait_ipiq(dcpu, seq);
180 printf("REQR%d ", tok->t_cpu);
185 * leave us in a critical section on return. This will be undone
186 * by lwkt_reltoken(). Bump the generation number.
188 return(++tok->t_gen);
192 * Attempt to acquire ownership of a token. Returns 1 on success, 0 on
196 lwkt_trytoken(lwkt_token_t tok)
200 if (tok->t_cpu != mycpu->gd_cpuid) {
205 /* leave us in the critical section */
211 * Release your ownership of a token. Releases must occur in reverse
212 * order to aquisitions, eventually so priorities can be unwound properly
213 * like SPLs. At the moment the actual implemention doesn't care.
215 * We can safely hand a token that we own to another cpu without notifying
216 * it, but once we do we can't get it back without requesting it (unless
217 * the other cpu hands it back to us before we check).
219 * We might have lost the token, so check that.
221 * Return the token's generation number. The number is useful to callers
222 * who may want to know if the token was stolen during potential blockages.
225 lwkt_reltoken(lwkt_token_t tok)
229 if (tok->t_cpu == mycpu->gd_cpuid) {
230 tok->t_cpu = tok->t_reqcpu;
238 * Reacquire a token that might have been lost. 0 is returned if the
239 * generation has not changed (nobody stole the token from us), -1 is
240 * returned otherwise. The token is reacquired regardless but the
241 * generation number is not bumped further if we already own the token.
243 * For efficiency we inline the best-case situation for lwkt_regettoken()
244 * (i.e .we still own the token).
247 lwkt_gentoken(lwkt_token_t tok, int *gen)
249 if (tok->t_cpu == mycpu->gd_cpuid && tok->t_gen == *gen)
251 *gen = lwkt_regettoken(tok);
256 * Re-acquire a token that might have been lost. The generation number
257 * is bumped and returned regardless of whether the token had been lost
258 * or not (because we only have cpu granularity we have to bump the token
262 lwkt_regettoken(lwkt_token_t tok)
264 /* assert we are in a critical section */
265 if (tok->t_cpu != mycpu->gd_cpuid) {
267 while (tok->t_cpu != mycpu->gd_cpuid) {
268 struct lwkt_gettoken_req req;
272 req.cpu = mycpu->gd_cpuid;
274 dcpu = (volatile int)tok->t_cpu;
275 KKASSERT(dcpu >= 0 && dcpu < ncpus);
278 printf("REQT%d ", dcpu);
280 seq = lwkt_send_ipiq(dcpu, lwkt_gettoken_remote, &req);
281 lwkt_wait_ipiq(dcpu, seq);
284 printf("REQR%d ", tok->t_cpu);
294 lwkt_inittoken(lwkt_token_t tok)
297 * Zero structure and set cpu owner and reqcpu to cpu 0.
299 bzero(tok, sizeof(*tok));