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.4 2004/02/18 16:31:37 joerg 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 == NULL). 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) {
131 printf("GT(%d,%d) ", req->tok->t_cpu->gd_cpuid, req->cpu->gd_cpuid);
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) {
164 struct lwkt_gettoken_req req;
173 printf("REQT%d ", dcpu->gd_cpuid);
175 seq = lwkt_send_ipiq(dcpu, lwkt_gettoken_remote, &req);
176 lwkt_wait_ipiq(dcpu, seq);
179 printf("REQR%d ", tok->t_cpu->gd_cpuid);
184 * leave us in a critical section on return. This will be undone
185 * by lwkt_reltoken(). Bump the generation number.
187 return(++tok->t_gen);
191 * Attempt to acquire ownership of a token. Returns 1 on success, 0 on
195 lwkt_trytoken(lwkt_token_t tok)
199 if (tok->t_cpu != mycpu) {
204 /* leave us in the critical section */
210 * Release your ownership of a token. Releases must occur in reverse
211 * order to aquisitions, eventually so priorities can be unwound properly
212 * like SPLs. At the moment the actual implemention doesn't care.
214 * We can safely hand a token that we own to another cpu without notifying
215 * it, but once we do we can't get it back without requesting it (unless
216 * the other cpu hands it back to us before we check).
218 * We might have lost the token, so check that.
220 * Return the token's generation number. The number is useful to callers
221 * who may want to know if the token was stolen during potential blockages.
224 lwkt_reltoken(lwkt_token_t tok)
228 if (tok->t_cpu == mycpu) {
229 tok->t_cpu = tok->t_reqcpu;
237 * Reacquire a token that might have been lost. 0 is returned if the
238 * generation has not changed (nobody stole the token from us), -1 is
239 * returned otherwise. The token is reacquired regardless but the
240 * generation number is not bumped further if we already own the token.
242 * For efficiency we inline the best-case situation for lwkt_regettoken()
243 * (i.e .we still own the token).
246 lwkt_gentoken(lwkt_token_t tok, int *gen)
248 if (tok->t_cpu == mycpu && tok->t_gen == *gen)
250 *gen = lwkt_regettoken(tok);
255 * Re-acquire a token that might have been lost. The generation number
256 * is bumped and returned regardless of whether the token had been lost
257 * or not (because we only have cpu granularity we have to bump the token
261 lwkt_regettoken(lwkt_token_t tok)
263 /* assert we are in a critical section */
264 if (tok->t_cpu != mycpu) {
266 while (tok->t_cpu != mycpu) {
267 struct lwkt_gettoken_req req;
276 printf("REQT%d ", dcpu->gd_cpuid);
278 seq = lwkt_send_ipiq(dcpu, lwkt_gettoken_remote, &req);
279 lwkt_wait_ipiq(dcpu, seq);
282 printf("REQR%d ", tok->t_cpu->gd_cpuid);
292 lwkt_inittoken(lwkt_token_t tok)
295 * Zero structure and set cpu owner and reqcpu to cpu 0.
297 tok->t_cpu = tok->t_reqcpu = mycpu;