Split the lwkt_token code out of lwkt_thread.c. Give it its own file.
[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.1 2004/02/09 21:13:18 dillon 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     int         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 == -1).  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->gd_cpuid) {
129 #ifdef INVARIANTS
130         if (token_debug)
131             printf("GT(%d,%d) ", req->tok->t_cpu, req->cpu);
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->gd_cpuid) {
164         struct lwkt_gettoken_req req;
165         int seq;
166         int dcpu;
167
168         req.cpu = mycpu->gd_cpuid;
169         req.tok = tok;
170         dcpu = (volatile int)tok->t_cpu;
171         KKASSERT(dcpu >= 0 && dcpu < ncpus);
172 #ifdef INVARIANTS
173         if (token_debug)
174             printf("REQT%d ", dcpu);
175 #endif
176         seq = lwkt_send_ipiq(dcpu, lwkt_gettoken_remote, &req);
177         lwkt_wait_ipiq(dcpu, seq);
178 #ifdef INVARIANTS
179         if (token_debug)
180             printf("REQR%d ", tok->t_cpu);
181 #endif
182     }
183 #endif
184     /*
185      * leave us in a critical section on return.  This will be undone
186      * by lwkt_reltoken().  Bump the generation number.
187      */
188     return(++tok->t_gen);
189 }
190
191 /*
192  * Attempt to acquire ownership of a token.  Returns 1 on success, 0 on
193  * failure.
194  */
195 int
196 lwkt_trytoken(lwkt_token_t tok)
197 {
198     crit_enter();
199 #ifdef SMP
200     if (tok->t_cpu != mycpu->gd_cpuid) {
201         crit_exit();
202         return(0);
203     } 
204 #endif
205     /* leave us in the critical section */
206     ++tok->t_gen;
207     return(1);
208 }
209
210 /*
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.
214  *
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).
218  *
219  * We might have lost the token, so check that.
220  *
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.
223  */
224 int
225 lwkt_reltoken(lwkt_token_t tok)
226 {
227     int gen;
228
229     if (tok->t_cpu == mycpu->gd_cpuid) {
230         tok->t_cpu = tok->t_reqcpu;
231     }
232     gen = tok->t_gen;
233     crit_exit();
234     return(gen);
235 }
236
237 /*
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.
242  *
243  * For efficiency we inline the best-case situation for lwkt_regettoken()
244  * (i.e .we still own the token).
245  */
246 int
247 lwkt_gentoken(lwkt_token_t tok, int *gen)
248 {
249     if (tok->t_cpu == mycpu->gd_cpuid && tok->t_gen == *gen)
250         return(0);
251     *gen = lwkt_regettoken(tok);
252     return(-1);
253 }
254
255 /*
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
259  * either way).
260  */
261 int
262 lwkt_regettoken(lwkt_token_t tok)
263 {
264     /* assert we are in a critical section */
265     if (tok->t_cpu != mycpu->gd_cpuid) {
266 #ifdef SMP
267         while (tok->t_cpu != mycpu->gd_cpuid) {
268             struct lwkt_gettoken_req req;
269             int seq;
270             int dcpu;
271
272             req.cpu = mycpu->gd_cpuid;
273             req.tok = tok;
274             dcpu = (volatile int)tok->t_cpu;
275             KKASSERT(dcpu >= 0 && dcpu < ncpus);
276 #ifdef INVARIANTS
277             if (token_debug)
278                 printf("REQT%d ", dcpu);
279 #endif
280             seq = lwkt_send_ipiq(dcpu, lwkt_gettoken_remote, &req);
281             lwkt_wait_ipiq(dcpu, seq);
282 #ifdef INVARIATNS
283             if (token_debug)
284                 printf("REQR%d ", tok->t_cpu);
285 #endif
286         }
287 #endif
288     }
289     ++tok->t_gen;
290     return(tok->t_gen);
291 }
292
293 void
294 lwkt_inittoken(lwkt_token_t tok)
295 {
296     /*
297      * Zero structure and set cpu owner and reqcpu to cpu 0.
298      */
299     bzero(tok, sizeof(*tok));
300 }
301