Fix typo.
[dragonfly.git] / sys / kern / lwkt_token.c
1 /*
2  * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  * $DragonFly: src/sys/kern/lwkt_token.c,v 1.4 2004/02/18 16:31:37 joerg Exp $
27  */
28
29 #ifdef _KERNEL
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/proc.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>
41 #include <sys/lock.h>
42 #include <sys/caps.h>
43
44 #include <vm/vm.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>
53
54 #include <machine/stdarg.h>
55 #include <machine/ipl.h>
56 #include <machine/smp.h>
57
58 #define THREAD_STACK    (UPAGES * PAGE_SIZE)
59
60 #else
61
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>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <machine/cpufunc.h>
74 #include <machine/lock.h>
75
76 #endif
77
78 #ifdef INVARIANTS
79 static int token_debug = 0;
80 #endif
81
82 #ifdef _KERNEL
83
84 #ifdef INVARIANTS
85 SYSCTL_INT(_lwkt, OID_AUTO, token_debug, CTLFLAG_RW, &token_debug, 0, "");
86 #endif
87
88 #endif
89
90 typedef struct lwkt_gettoken_req {
91     lwkt_token_t tok;
92     globaldata_t cpu;
93 } lwkt_gettoken_req;
94
95 /*
96  * Acquire ownership of a token
97  *
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).
103  *
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 ?
106  *
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.
109  *
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.  
113  *
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.
119  */
120
121 #ifdef SMP
122
123 static
124 void
125 lwkt_gettoken_remote(void *arg)
126 {
127     lwkt_gettoken_req *req = arg;
128     if (req->tok->t_cpu == mycpu) {
129 #ifdef INVARIANTS
130         if (token_debug)
131             printf("GT(%d,%d) ", req->tok->t_cpu->gd_cpuid, req->cpu->gd_cpuid);
132 #endif
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 */
136     }
137 }
138
139 #endif
140
141 int
142 lwkt_gettoken(lwkt_token_t tok)
143 {
144     /*
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
148      * to the token.
149      */
150
151     crit_enter();
152 #ifdef INVARIANTS
153     if (curthread->td_pri > 1800) {
154         printf("lwkt_gettoken: %p called from %p: crit sect nesting warning\n",
155             tok, ((int **)&tok)[-1]);
156     }
157     if (curthread->td_pri > 2000) {
158         curthread->td_pri = 1000;
159         panic("too HIGH!");
160     }
161 #endif
162 #ifdef SMP
163     while (tok->t_cpu != mycpu) {
164         struct lwkt_gettoken_req req;
165         int seq;
166         globaldata_t dcpu;
167
168         req.cpu = mycpu;
169         req.tok = tok;
170         dcpu = tok->t_cpu;
171 #ifdef INVARIANTS
172         if (token_debug)
173             printf("REQT%d ", dcpu->gd_cpuid);
174 #endif
175         seq = lwkt_send_ipiq(dcpu, lwkt_gettoken_remote, &req);
176         lwkt_wait_ipiq(dcpu, seq);
177 #ifdef INVARIANTS
178         if (token_debug)
179             printf("REQR%d ", tok->t_cpu->gd_cpuid);
180 #endif
181     }
182 #endif
183     /*
184      * leave us in a critical section on return.  This will be undone
185      * by lwkt_reltoken().  Bump the generation number.
186      */
187     return(++tok->t_gen);
188 }
189
190 /*
191  * Attempt to acquire ownership of a token.  Returns 1 on success, 0 on
192  * failure.
193  */
194 int
195 lwkt_trytoken(lwkt_token_t tok)
196 {
197     crit_enter();
198 #ifdef SMP
199     if (tok->t_cpu != mycpu) {
200         crit_exit();
201         return(0);
202     } 
203 #endif
204     /* leave us in the critical section */
205     ++tok->t_gen;
206     return(1);
207 }
208
209 /*
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.
213  *
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).
217  *
218  * We might have lost the token, so check that.
219  *
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.
222  */
223 int
224 lwkt_reltoken(lwkt_token_t tok)
225 {
226     int gen;
227
228     if (tok->t_cpu == mycpu) {
229         tok->t_cpu = tok->t_reqcpu;
230     }
231     gen = tok->t_gen;
232     crit_exit();
233     return(gen);
234 }
235
236 /*
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.
241  *
242  * For efficiency we inline the best-case situation for lwkt_regettoken()
243  * (i.e .we still own the token).
244  */
245 int
246 lwkt_gentoken(lwkt_token_t tok, int *gen)
247 {
248     if (tok->t_cpu == mycpu && tok->t_gen == *gen)
249         return(0);
250     *gen = lwkt_regettoken(tok);
251     return(-1);
252 }
253
254 /*
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
258  * either way).
259  */
260 int
261 lwkt_regettoken(lwkt_token_t tok)
262 {
263     /* assert we are in a critical section */
264     if (tok->t_cpu != mycpu) {
265 #ifdef SMP
266         while (tok->t_cpu != mycpu) {
267             struct lwkt_gettoken_req req;
268             int seq;
269             globaldata_t dcpu;
270
271             req.cpu = mycpu;
272             req.tok = tok;
273             dcpu = tok->t_cpu;
274 #ifdef INVARIANTS
275             if (token_debug)
276                 printf("REQT%d ", dcpu->gd_cpuid);
277 #endif
278             seq = lwkt_send_ipiq(dcpu, lwkt_gettoken_remote, &req);
279             lwkt_wait_ipiq(dcpu, seq);
280 #ifdef INVARIANTS
281             if (token_debug)
282                 printf("REQR%d ", tok->t_cpu->gd_cpuid);
283 #endif
284         }
285 #endif
286     }
287     ++tok->t_gen;
288     return(tok->t_gen);
289 }
290
291 void
292 lwkt_inittoken(lwkt_token_t tok)
293 {
294     /*
295      * Zero structure and set cpu owner and reqcpu to cpu 0.
296      */
297     tok->t_cpu = tok->t_reqcpu = mycpu;
298     tok->t_gen = 0;
299 }
300