5c46ed14d941cf32ea51075af3d2ba9828fc8819
[dragonfly.git] / sys / kern / lwkt_token.c
1 /*
2  * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sys/kern/lwkt_token.c,v 1.16 2005/06/19 21:50:47 dillon Exp $
35  */
36
37 #ifdef _KERNEL
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/proc.h>
43 #include <sys/rtprio.h>
44 #include <sys/queue.h>
45 #include <sys/thread2.h>
46 #include <sys/sysctl.h>
47 #include <sys/kthread.h>
48 #include <machine/cpu.h>
49 #include <sys/lock.h>
50 #include <sys/caps.h>
51
52 #include <vm/vm.h>
53 #include <vm/vm_param.h>
54 #include <vm/vm_kern.h>
55 #include <vm/vm_object.h>
56 #include <vm/vm_page.h>
57 #include <vm/vm_map.h>
58 #include <vm/vm_pager.h>
59 #include <vm/vm_extern.h>
60 #include <vm/vm_zone.h>
61
62 #include <machine/stdarg.h>
63 #include <machine/ipl.h>
64 #include <machine/smp.h>
65
66 #define THREAD_STACK    (UPAGES * PAGE_SIZE)
67
68 #else
69
70 #include <sys/stdint.h>
71 #include <libcaps/thread.h>
72 #include <sys/thread.h>
73 #include <sys/msgport.h>
74 #include <sys/errno.h>
75 #include <libcaps/globaldata.h>
76 #include <machine/cpufunc.h>
77 #include <sys/thread2.h>
78 #include <sys/msgport2.h>
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <string.h>
82 #include <machine/lock.h>
83 #include <machine/cpu.h>
84
85 #endif
86
87 #define MAKE_TOKENS_SPIN
88 /* #define MAKE_TOKENS_YIELD */
89
90 #ifndef LWKT_NUM_POOL_TOKENS
91 #define LWKT_NUM_POOL_TOKENS    1024    /* power of 2 */
92 #endif
93 #define LWKT_MASK_POOL_TOKENS   (LWKT_NUM_POOL_TOKENS - 1)
94
95 #ifdef INVARIANTS
96 static int token_debug = 0;
97 #endif
98
99 #ifdef SMP
100 static void lwkt_reqtoken_remote(void *data);
101 #endif
102
103 static lwkt_token       pool_tokens[LWKT_NUM_POOL_TOKENS];
104
105 #ifdef _KERNEL
106
107 #ifdef INVARIANTS
108 SYSCTL_INT(_lwkt, OID_AUTO, token_debug, CTLFLAG_RW, &token_debug, 0, "");
109 #endif
110
111 #endif
112
113 #ifdef SMP
114
115 /*
116  * Determine if we own all the tokens in the token reference list.
117  * Return 1 on success, 0 on failure. 
118  *
119  * As a side effect, queue requests for tokens we want which are owned
120  * by other cpus.  The magic number is used to communicate when the 
121  * target cpu has processed the request.  Note, however, that the
122  * target cpu may not be able to assign the token to us which is why
123  * the scheduler must spin.
124  */
125 int
126 lwkt_chktokens(thread_t td)
127 {
128     globaldata_t gd = td->td_gd;        /* mycpu */
129     lwkt_tokref_t refs;
130     globaldata_t dgd;
131     lwkt_token_t tok;
132     __uint32_t magic;
133     int r = 1;
134
135     for (refs = td->td_toks; refs; refs = refs->tr_next) {
136         tok = refs->tr_tok;
137         if ((dgd = tok->t_cpu) != gd) {
138             cpu_ccfence();      /* don't let the compiler reload tok->t_cpu */
139             r = 0;
140
141             /*
142              * Queue a request to the target cpu, exit the loop early if
143              * we are unable to queue the IPI message.  The magic number
144              * flags whether we have a pending ipi request queued or not.
145              * It can be set from MAGIC2 to MAGIC1 by a remote cpu but can
146              * only be set from MAGIC1 to MAGIC2 by our cpu.
147              */
148             magic = refs->tr_magic;
149             cpu_ccfence();
150             if (magic == LWKT_TOKREF_MAGIC1) {
151                 refs->tr_magic = LWKT_TOKREF_MAGIC2;    /* MP synched slowreq*/
152                 refs->tr_reqgd = gd;
153                 tok->t_reqcpu = gd;     /* MP unsynchronized 'fast' req */
154                 if (lwkt_send_ipiq_nowait(dgd, lwkt_reqtoken_remote, refs)) {
155                     /* failed */
156                     refs->tr_magic = LWKT_TOKREF_MAGIC1;
157                     break;
158                 }
159             } else if (magic != LWKT_TOKREF_MAGIC2) {
160                 panic("lwkt_chktoken(): token ref %p tok %p bad magic %08x\n",
161                         refs, refs->tr_tok, magic);
162             }
163         }
164     }
165     return(r);
166 }
167
168 #endif
169
170 /*
171  * Check if we already own the token.  Return 1 on success, 0 on failure.
172  */
173 int
174 lwkt_havetoken(lwkt_token_t tok)
175 {
176     globaldata_t gd = mycpu;
177     thread_t td = gd->gd_curthread;
178     lwkt_tokref_t ref;
179
180     for (ref = td->td_toks; ref; ref = ref->tr_next) {
181         if (ref->tr_tok == tok)
182             return(1);
183     }
184     return(0);
185 }
186
187 int
188 lwkt_havetokref(lwkt_tokref_t xref)
189 {
190     globaldata_t gd = mycpu;
191     thread_t td = gd->gd_curthread;
192     lwkt_tokref_t ref;
193
194     for (ref = td->td_toks; ref; ref = ref->tr_next) {
195         if (ref == xref)
196             return(1);
197     }
198     return(0);
199 }
200
201 #ifdef SMP
202
203 /*
204  * Returns 1 if it is ok to give a token away, 0 if it is not.
205  */
206 static int
207 lwkt_oktogiveaway_token(lwkt_token_t tok)
208 {
209     globaldata_t gd = mycpu;
210     lwkt_tokref_t ref;
211     thread_t td;
212
213     for (td = gd->gd_curthread; td; td = td->td_preempted) {
214         for (ref = td->td_toks; ref; ref = ref->tr_next) {
215             if (ref->tr_tok == tok)
216                 return(0);
217         }
218     }
219     return(1);
220 }
221
222 #endif
223
224 /*
225  * Acquire a serializing token
226  */
227
228 static __inline
229 void
230 _lwkt_gettokref(lwkt_tokref_t ref)
231 {
232     lwkt_tokref_t scan;
233     lwkt_token_t tok;
234     globaldata_t gd;
235     thread_t td;
236
237     gd = mycpu;                 /* our cpu */
238     KKASSERT(ref->tr_magic == LWKT_TOKREF_MAGIC1);
239     td = gd->gd_curthread;      /* our thread */
240
241     /*
242      * Link the request into our thread's list.  This interlocks against
243      * remote requests from other cpus, prevents the token from being
244      * given away if our cpu already owns it, and interlocks against 
245      * preempting threads which may want the token.  This also allows us to
246      * avoid using a critical section.
247      */
248     ref->tr_next = td->td_toks;
249     cpu_ccfence();      /* prevent compiler reordering */
250     td->td_toks = ref;
251     tok = ref->tr_tok;
252
253     /*
254      * If we are preempting another thread which owns the token we have to
255      * yield to get out from the preemption because we cannot obtain a token
256      * owned by the thread we are preempting.
257      */
258     if (td->td_preempted) {
259         while ((td = td->td_preempted) != NULL) {
260             for (scan = td->td_toks; scan; scan = scan->tr_next) {
261                 if (scan->tr_tok == tok) {
262                     lwkt_yield();
263                     KKASSERT(tok->t_cpu == gd);
264                     goto breakout;
265                 }
266             }
267         }
268 breakout: ;
269         td = gd->gd_curthread;  /* our thread, again */
270     }
271
272     /*
273      * If our cpu does not own the token then (currently) spin while we
274      * await it.  XXX we should yield here but some testing is required
275      * before we do so, there could be some interlock issues with e.g.
276      * softupdates before we can yield.  ZZZ
277      */
278 #ifdef SMP
279     if (tok->t_cpu != gd) {
280 #if defined(MAKE_TOKENS_SPIN)
281         int x = 40000000;
282         int y = 10;
283         crit_enter();
284         while (lwkt_chktokens(td) == 0) {
285             lwkt_process_ipiq();
286             lwkt_drain_token_requests();
287             if (--x == 0) {
288                 x = 40000000;
289                 printf("CHKTOKEN looping on cpu %d\n", gd->gd_cpuid);
290 #ifdef _KERNEL
291                 if (--y == 0)
292                         panic("CHKTOKEN looping on cpu %d", gd->gd_cpuid);
293 #endif
294             }
295             splz();
296         }
297         crit_exit();
298 #elif defined(MAKE_TOKENS_YIELD)
299         lwkt_yield();
300 #else
301 #error MAKE_TOKENS_XXX ?
302 #endif
303         KKASSERT(tok->t_cpu == gd);
304     }
305 #endif
306 }
307
308
309 /*
310  * Attempt to acquire a serializing token
311  */
312 static __inline
313 int
314 _lwkt_trytokref(lwkt_tokref_t ref)
315 {
316     lwkt_token_t tok;
317     globaldata_t gd;
318     thread_t td;
319
320     gd = mycpu;                 /* our cpu */
321     KKASSERT(ref->tr_magic == LWKT_TOKREF_MAGIC1);
322     td = gd->gd_curthread;      /* our thread */
323
324     /*
325      * Link the request into our thread's list.  This interlocks against
326      * remote requests from other cpus and prevents the token from being
327      * given away if our cpu already owns it.  This also allows us to
328      * avoid using a critical section.
329      *
330      * Force a panic to occur if chktokens is called while the reference
331      * is linked to td_toks but before we have resolved whether we can
332      * keep it.  chktokens should never be called on our ref list
333      * preemptively.
334      */
335     ref->tr_magic = LWKT_TOKREF_MAGIC3;
336     ref->tr_next = td->td_toks;
337     cpu_ccfence();      /* prevent compiler reordering */
338     td->td_toks = ref;
339
340     /*
341      * If our cpu does not own the token then stop now.
342      *
343      * Otherwise make sure the token is not held by a thread we are
344      * preempting.  If it is, stop.
345      */
346     tok = ref->tr_tok;
347 #ifdef SMP
348     if (tok->t_cpu != gd) {
349         td->td_toks = ref->tr_next;     /* remove ref */
350         ref->tr_magic = LWKT_TOKREF_MAGIC1;
351         return(0);
352     }
353 #endif
354     if (td->td_preempted) {
355         while ((td = td->td_preempted) != NULL) {
356             lwkt_tokref_t scan;
357             for (scan = td->td_toks; scan; scan = scan->tr_next) {
358                 if (scan->tr_tok == tok) {
359                     td = gd->gd_curthread;      /* our thread */
360                     td->td_toks = ref->tr_next; /* remove ref */
361                     ref->tr_magic = LWKT_TOKREF_MAGIC1;
362                     return(0);
363                 }
364             }
365         }
366     }
367
368     /*
369      * We own the token, legitimize the reference.
370      */
371     ref->tr_magic = LWKT_TOKREF_MAGIC1;
372     /* 'td' variable no longer valid */
373     return(1);
374 }
375
376 void
377 lwkt_gettoken(lwkt_tokref_t ref, lwkt_token_t tok)
378 {
379     lwkt_tokref_init(ref, tok);
380     _lwkt_gettokref(ref);
381 }
382
383 void
384 lwkt_gettokref(lwkt_tokref_t ref)
385 {
386     _lwkt_gettokref(ref);
387 }
388
389 int
390 lwkt_trytoken(lwkt_tokref_t ref, lwkt_token_t tok)
391 {
392     lwkt_tokref_init(ref, tok);
393     return(_lwkt_trytokref(ref));
394 }
395
396 int
397 lwkt_trytokref(lwkt_tokref_t ref)
398 {
399     return(_lwkt_trytokref(ref));
400 }
401
402 /*
403  * Release a serializing token
404  */
405 void
406 lwkt_reltoken(lwkt_tokref *_ref)
407 {
408     lwkt_tokref_t scan;
409     lwkt_tokref *ref;
410     lwkt_tokref **pref;
411     lwkt_token_t tok;
412     globaldata_t gd;
413     thread_t td;
414     int giveaway;
415
416     /*
417      * Guard check and stack check (if in the same stack page).  We must
418      * also wait for any action pending on remote cpus which we do by
419      * checking the magic number and yielding in a loop.
420      */
421     ref = _ref;
422 #ifdef INVARIANTS
423     if ((((intptr_t)ref ^ (intptr_t)&_ref) & ~(intptr_t)PAGE_MASK) == 0)
424         KKASSERT((char *)ref > (char *)&_ref);
425     KKASSERT(ref->tr_magic == LWKT_TOKREF_MAGIC1 || 
426              ref->tr_magic == LWKT_TOKREF_MAGIC2);
427 #endif
428
429     tok = ref->tr_tok;
430     gd = mycpu;
431     td = gd->gd_curthread;
432     KKASSERT(tok->t_cpu == gd);
433
434     /*
435      * We can only give away the token if we aren't holding it recursively.
436      * Also use the opportunity to locate the link field for the token.
437      *
438      * We do not have to scan preempted threads since by definition we cannot
439      * be holding any token held by a thread we are preempting.
440      */
441     giveaway = 1;
442     for (pref = &td->td_toks; (ref = *pref) != _ref; pref = &ref->tr_next) {
443         KKASSERT(ref != NULL);
444         if (ref->tr_tok == tok)
445             giveaway = 0;
446     }
447     for (scan = ref->tr_next; scan; scan = scan->tr_next) {
448         if (scan->tr_tok == tok)
449             giveaway = 0;
450     }
451     if (giveaway == 0) {
452         printf("Warning: no giveaway lwkt_reltoken caller %p\n",
453                 ((void **)&_ref)[-1]);
454     }
455
456     /*
457      * Give the token away (if we can) before removing the interlock.  Once
458      * the interlock is removed, the token can be given away by an IPI.
459      */
460     if (giveaway)
461         tok->t_cpu = tok->t_reqcpu;     
462     *pref = ref->tr_next;
463
464     /*
465      * If we had gotten the token opportunistically and it still happens to
466      * be queued to a target cpu, we have to wait for the target cpu
467      * to finish processing it.  This does not happen very often and does
468      * not need to be optimal.
469      */
470     while (ref->tr_magic == LWKT_TOKREF_MAGIC2) {
471 #if defined(MAKE_TOKENS_SPIN)
472         crit_enter();
473 #ifdef SMP
474         lwkt_process_ipiq();
475 #endif
476         splz();
477         crit_exit();
478 #elif defined(MAKE_TOKENS_YIELD)
479         lwkt_yield();
480 #else
481 #error MAKE_TOKENS_XXX ?
482 #endif
483     }
484     KKASSERT(ref->tr_magic == LWKT_TOKREF_MAGIC1);
485 }
486
487 /*
488  * Pool tokens are used to provide a type-stable serializing token
489  * pointer that does not race against disappearing data structures.
490  *
491  * This routine is called in early boot just after we setup the BSP's
492  * globaldata structure.
493  */
494 void
495 lwkt_token_pool_init(void)
496 {
497     int i;
498
499     for (i = 0; i < LWKT_NUM_POOL_TOKENS; ++i)
500         lwkt_token_init(&pool_tokens[i]);
501 }
502
503 lwkt_token_t
504 lwkt_token_pool_get(void *ptraddr)
505 {
506     int i;
507
508     i = ((int)(intptr_t)ptraddr >> 2) ^ ((int)(intptr_t)ptraddr >> 12);
509     return(&pool_tokens[i & LWKT_MASK_POOL_TOKENS]);
510 }
511
512 #ifdef SMP
513
514 /*
515  * This is the receiving side of a remote IPI requesting a token.  If we
516  * cannot immediately hand the token off to another cpu we queue it.
517  *
518  * NOTE!  we 'own' the ref structure, but we only 'own' the token if
519  * t_cpu == mycpu.
520  */
521 static void
522 lwkt_reqtoken_remote(void *data)
523 {
524     lwkt_tokref_t ref = data;
525     globaldata_t gd = mycpu;
526     lwkt_token_t tok = ref->tr_tok;
527
528     /*
529      * We do not have to queue the token if we can give it away
530      * immediately.  Otherwise we queue it to our globaldata structure.
531      */
532     KKASSERT(ref->tr_magic == LWKT_TOKREF_MAGIC2);
533     if (lwkt_oktogiveaway_token(tok)) {
534         if (tok->t_cpu == gd)
535             tok->t_cpu = ref->tr_reqgd;
536         cpu_ccfence();  /* prevent compiler reordering */
537         ref->tr_magic = LWKT_TOKREF_MAGIC1;
538     } else {
539         ref->tr_gdreqnext = gd->gd_tokreqbase;
540         gd->gd_tokreqbase = ref;
541     }
542 }
543
544 /*
545  * Must be called from a critical section.  Satisfy all remote token
546  * requests that are pending on our globaldata structure.  The request
547  * does not have to be satisfied with a successful change of ownership
548  * but we do have to acknowledge that we have completed processing the
549  * request by setting the magic number back to MAGIC1.
550  *
551  * NOTE!  we 'own' the ref structure, but we only 'own' the token if
552  * t_cpu == mycpu.
553  */
554 void
555 lwkt_drain_token_requests(void)
556 {
557     globaldata_t gd = mycpu;
558     lwkt_tokref_t ref;
559
560     while ((ref = gd->gd_tokreqbase) != NULL) {
561         gd->gd_tokreqbase = ref->tr_gdreqnext;
562         KKASSERT(ref->tr_magic == LWKT_TOKREF_MAGIC2);
563         if (ref->tr_tok->t_cpu == gd)
564             ref->tr_tok->t_cpu = ref->tr_reqgd;
565         cpu_ccfence();  /* prevent compiler reordering */
566         ref->tr_magic = LWKT_TOKREF_MAGIC1;
567     }
568 }
569
570 #endif
571
572 /*
573  * Initialize the owner and release-to cpu to the current cpu
574  * and reset the generation count.
575  */
576 void
577 lwkt_token_init(lwkt_token_t tok)
578 {
579     tok->t_cpu = tok->t_reqcpu = mycpu;
580 }
581
582 void
583 lwkt_token_uninit(lwkt_token_t tok)
584 {
585     /* empty */
586 }