ktr the end of various ipiq sending operation.
[dragonfly.git] / sys / kern / lwkt_ipiq.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_ipiq.c,v 1.26 2008/05/01 09:37:48 sephe Exp $
35  */
36
37 /*
38  * This module implements IPI message queueing and the MI portion of IPI
39  * message processing.
40  */
41
42 #ifdef _KERNEL
43
44 #include "opt_ddb.h"
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/proc.h>
50 #include <sys/rtprio.h>
51 #include <sys/queue.h>
52 #include <sys/thread2.h>
53 #include <sys/sysctl.h>
54 #include <sys/ktr.h>
55 #include <sys/kthread.h>
56 #include <machine/cpu.h>
57 #include <sys/lock.h>
58 #include <sys/caps.h>
59
60 #include <vm/vm.h>
61 #include <vm/vm_param.h>
62 #include <vm/vm_kern.h>
63 #include <vm/vm_object.h>
64 #include <vm/vm_page.h>
65 #include <vm/vm_map.h>
66 #include <vm/vm_pager.h>
67 #include <vm/vm_extern.h>
68 #include <vm/vm_zone.h>
69
70 #include <machine/stdarg.h>
71 #include <machine/smp.h>
72 #include <machine/atomic.h>
73
74 #else
75
76 #include <sys/stdint.h>
77 #include <libcaps/thread.h>
78 #include <sys/thread.h>
79 #include <sys/msgport.h>
80 #include <sys/errno.h>
81 #include <libcaps/globaldata.h>
82 #include <machine/cpufunc.h>
83 #include <sys/thread2.h>
84 #include <sys/msgport2.h>
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <machine/lock.h>
89 #include <machine/cpu.h>
90 #include <machine/atomic.h>
91
92 #endif
93
94 #ifdef SMP
95 static __int64_t ipiq_count;    /* total calls to lwkt_send_ipiq*() */
96 static __int64_t ipiq_fifofull; /* number of fifo full conditions detected */
97 static __int64_t ipiq_avoided;  /* interlock with target avoids cpu ipi */
98 static __int64_t ipiq_passive;  /* passive IPI messages */
99 static __int64_t ipiq_cscount;  /* number of cpu synchronizations */
100 static int ipiq_optimized = 1;  /* XXX temporary sysctl */
101 #ifdef PANIC_DEBUG
102 static int      panic_ipiq_cpu = -1;
103 static int      panic_ipiq_count = 100;
104 #endif
105 #endif
106
107 #ifdef _KERNEL
108
109 #ifdef SMP
110 SYSCTL_QUAD(_lwkt, OID_AUTO, ipiq_count, CTLFLAG_RW, &ipiq_count, 0, "");
111 SYSCTL_QUAD(_lwkt, OID_AUTO, ipiq_fifofull, CTLFLAG_RW, &ipiq_fifofull, 0, "");
112 SYSCTL_QUAD(_lwkt, OID_AUTO, ipiq_avoided, CTLFLAG_RW, &ipiq_avoided, 0, "");
113 SYSCTL_QUAD(_lwkt, OID_AUTO, ipiq_passive, CTLFLAG_RW, &ipiq_passive, 0, "");
114 SYSCTL_QUAD(_lwkt, OID_AUTO, ipiq_cscount, CTLFLAG_RW, &ipiq_cscount, 0, "");
115 SYSCTL_INT(_lwkt, OID_AUTO, ipiq_optimized, CTLFLAG_RW, &ipiq_optimized, 0, "");
116 #ifdef PANIC_DEBUG
117 SYSCTL_INT(_lwkt, OID_AUTO, panic_ipiq_cpu, CTLFLAG_RW, &panic_ipiq_cpu, 0, "");
118 SYSCTL_INT(_lwkt, OID_AUTO, panic_ipiq_count, CTLFLAG_RW, &panic_ipiq_count, 0, "");
119 #endif
120
121 #define IPIQ_STRING     "func=%p arg1=%p arg2=%d scpu=%d dcpu=%d"
122 #define IPIQ_ARG_SIZE   (sizeof(void *) * 2 + sizeof(int) * 3)
123
124 #if !defined(KTR_IPIQ)
125 #define KTR_IPIQ        KTR_ALL
126 #endif
127 KTR_INFO_MASTER(ipiq);
128 KTR_INFO(KTR_IPIQ, ipiq, send_norm, 0, IPIQ_STRING, IPIQ_ARG_SIZE);
129 KTR_INFO(KTR_IPIQ, ipiq, send_pasv, 1, IPIQ_STRING, IPIQ_ARG_SIZE);
130 KTR_INFO(KTR_IPIQ, ipiq, send_nbio, 2, IPIQ_STRING, IPIQ_ARG_SIZE);
131 KTR_INFO(KTR_IPIQ, ipiq, send_fail, 3, IPIQ_STRING, IPIQ_ARG_SIZE);
132 KTR_INFO(KTR_IPIQ, ipiq, receive, 4, IPIQ_STRING, IPIQ_ARG_SIZE);
133 KTR_INFO(KTR_IPIQ, ipiq, sync_start, 5, "cpumask=%08x", sizeof(cpumask_t));
134 KTR_INFO(KTR_IPIQ, ipiq, sync_add, 6, "cpumask=%08x", sizeof(cpumask_t));
135 KTR_INFO(KTR_IPIQ, ipiq, cpu_send, 7, IPIQ_STRING, IPIQ_ARG_SIZE);
136 KTR_INFO(KTR_IPIQ, ipiq, send_end, 8, IPIQ_STRING, IPIQ_ARG_SIZE);
137
138 #define logipiq(name, func, arg1, arg2, sgd, dgd)       \
139         KTR_LOG(ipiq_ ## name, func, arg1, arg2, sgd->gd_cpuid, dgd->gd_cpuid)
140 #define logipiq2(name, arg)     \
141         KTR_LOG(ipiq_ ## name, arg)
142
143 #endif  /* SMP */
144 #endif  /* KERNEL */
145
146 #ifdef SMP
147
148 static int lwkt_process_ipiq_core(globaldata_t sgd, lwkt_ipiq_t ip, 
149                                   struct intrframe *frame);
150 static void lwkt_cpusync_remote1(lwkt_cpusync_t poll);
151 static void lwkt_cpusync_remote2(lwkt_cpusync_t poll);
152
153 /*
154  * Send a function execution request to another cpu.  The request is queued
155  * on the cpu<->cpu ipiq matrix.  Each cpu owns a unique ipiq FIFO for every
156  * possible target cpu.  The FIFO can be written.
157  *
158  * If the FIFO fills up we have to enable interrupts to avoid an APIC
159  * deadlock and process pending IPIQs while waiting for it to empty.   
160  * Otherwise we may soft-deadlock with another cpu whos FIFO is also full.
161  *
162  * We can safely bump gd_intr_nesting_level because our crit_exit() at the
163  * end will take care of any pending interrupts.
164  *
165  * The actual hardware IPI is avoided if the target cpu is already processing
166  * the queue from a prior IPI.  It is possible to pipeline IPI messages
167  * very quickly between cpus due to the FIFO hysteresis.
168  *
169  * Need not be called from a critical section.
170  */
171 int
172 lwkt_send_ipiq3(globaldata_t target, ipifunc3_t func, void *arg1, int arg2)
173 {
174     lwkt_ipiq_t ip;
175     int windex;
176     struct globaldata *gd = mycpu;
177
178     logipiq(send_norm, func, arg1, arg2, gd, target);
179
180     if (target == gd) {
181         func(arg1, arg2, NULL);
182         logipiq(send_end, func, arg1, arg2, gd, target);
183         return(0);
184     } 
185     crit_enter();
186     ++gd->gd_intr_nesting_level;
187 #ifdef INVARIANTS
188     if (gd->gd_intr_nesting_level > 20)
189         panic("lwkt_send_ipiq: TOO HEAVILY NESTED!");
190 #endif
191     KKASSERT(curthread->td_pri >= TDPRI_CRIT);
192     ++ipiq_count;
193     ip = &gd->gd_ipiq[target->gd_cpuid];
194
195     /*
196      * Do not allow the FIFO to become full.  Interrupts must be physically
197      * enabled while we liveloop to avoid deadlocking the APIC.
198      */
199     if (ip->ip_windex - ip->ip_rindex > MAXCPUFIFO / 2) {
200         unsigned int eflags = read_eflags();
201
202         if (atomic_poll_acquire_int(&ip->ip_npoll) || ipiq_optimized == 0) {
203             logipiq(cpu_send, func, arg1, arg2, gd, target);
204             cpu_send_ipiq(target->gd_cpuid);
205         }
206         cpu_enable_intr();
207         ++ipiq_fifofull;
208         while (ip->ip_windex - ip->ip_rindex > MAXCPUFIFO / 4) {
209             KKASSERT(ip->ip_windex - ip->ip_rindex != MAXCPUFIFO - 1);
210             lwkt_process_ipiq();
211         }
212         write_eflags(eflags);
213     }
214
215     /*
216      * Queue the new message
217      */
218     windex = ip->ip_windex & MAXCPUFIFO_MASK;
219     ip->ip_func[windex] = func;
220     ip->ip_arg1[windex] = arg1;
221     ip->ip_arg2[windex] = arg2;
222     cpu_sfence();
223     ++ip->ip_windex;
224     --gd->gd_intr_nesting_level;
225
226     /*
227      * signal the target cpu that there is work pending.
228      */
229     if (atomic_poll_acquire_int(&ip->ip_npoll)) {
230         logipiq(cpu_send, func, arg1, arg2, gd, target);
231         cpu_send_ipiq(target->gd_cpuid);
232     } else {
233         if (ipiq_optimized == 0) {
234             logipiq(cpu_send, func, arg1, arg2, gd, target);
235             cpu_send_ipiq(target->gd_cpuid);
236         } else {
237             ++ipiq_avoided;
238         }
239     }
240     crit_exit();
241
242     logipiq(send_end, func, arg1, arg2, gd, target);
243     return(ip->ip_windex);
244 }
245
246 /*
247  * Similar to lwkt_send_ipiq() but this function does not actually initiate
248  * the IPI to the target cpu unless the FIFO has become too full, so it is
249  * very fast.
250  *
251  * This function is used for non-critical IPI messages, such as memory
252  * deallocations.  The queue will typically be flushed by the target cpu at
253  * the next clock interrupt.
254  *
255  * Need not be called from a critical section.
256  */
257 int
258 lwkt_send_ipiq3_passive(globaldata_t target, ipifunc3_t func,
259                         void *arg1, int arg2)
260 {
261     lwkt_ipiq_t ip;
262     int windex;
263     struct globaldata *gd = mycpu;
264
265     KKASSERT(target != gd);
266     crit_enter();
267     logipiq(send_pasv, func, arg1, arg2, gd, target);
268     ++gd->gd_intr_nesting_level;
269 #ifdef INVARIANTS
270     if (gd->gd_intr_nesting_level > 20)
271         panic("lwkt_send_ipiq: TOO HEAVILY NESTED!");
272 #endif
273     KKASSERT(curthread->td_pri >= TDPRI_CRIT);
274     ++ipiq_count;
275     ++ipiq_passive;
276     ip = &gd->gd_ipiq[target->gd_cpuid];
277
278     /*
279      * Do not allow the FIFO to become full.  Interrupts must be physically
280      * enabled while we liveloop to avoid deadlocking the APIC.
281      */
282     if (ip->ip_windex - ip->ip_rindex > MAXCPUFIFO / 2) {
283         unsigned int eflags = read_eflags();
284
285         if (atomic_poll_acquire_int(&ip->ip_npoll) || ipiq_optimized == 0) {
286             logipiq(cpu_send, func, arg1, arg2, gd, target);
287             cpu_send_ipiq(target->gd_cpuid);
288         }
289         cpu_enable_intr();
290         ++ipiq_fifofull;
291         while (ip->ip_windex - ip->ip_rindex > MAXCPUFIFO / 4) {
292             KKASSERT(ip->ip_windex - ip->ip_rindex != MAXCPUFIFO - 1);
293             lwkt_process_ipiq();
294         }
295         write_eflags(eflags);
296     }
297
298     /*
299      * Queue the new message
300      */
301     windex = ip->ip_windex & MAXCPUFIFO_MASK;
302     ip->ip_func[windex] = func;
303     ip->ip_arg1[windex] = arg1;
304     ip->ip_arg2[windex] = arg2;
305     cpu_sfence();
306     ++ip->ip_windex;
307     --gd->gd_intr_nesting_level;
308
309     /*
310      * Do not signal the target cpu, it will pick up the IPI when it next
311      * polls (typically on the next tick).
312      */
313     crit_exit();
314
315     logipiq(send_end, func, arg1, arg2, gd, target);
316     return(ip->ip_windex);
317 }
318
319 /*
320  * Send an IPI request without blocking, return 0 on success, ENOENT on 
321  * failure.  The actual queueing of the hardware IPI may still force us
322  * to spin and process incoming IPIs but that will eventually go away
323  * when we've gotten rid of the other general IPIs.
324  */
325 int
326 lwkt_send_ipiq3_nowait(globaldata_t target, ipifunc3_t func, 
327                        void *arg1, int arg2)
328 {
329     lwkt_ipiq_t ip;
330     int windex;
331     struct globaldata *gd = mycpu;
332
333     logipiq(send_nbio, func, arg1, arg2, gd, target);
334     KKASSERT(curthread->td_pri >= TDPRI_CRIT);
335     if (target == gd) {
336         func(arg1, arg2, NULL);
337         logipiq(send_end, func, arg1, arg2, gd, target);
338         return(0);
339     } 
340     ++ipiq_count;
341     ip = &gd->gd_ipiq[target->gd_cpuid];
342
343     if (ip->ip_windex - ip->ip_rindex >= MAXCPUFIFO * 2 / 3) {
344         logipiq(send_fail, func, arg1, arg2, gd, target);
345         return(ENOENT);
346     }
347     windex = ip->ip_windex & MAXCPUFIFO_MASK;
348     ip->ip_func[windex] = func;
349     ip->ip_arg1[windex] = arg1;
350     ip->ip_arg2[windex] = arg2;
351     cpu_sfence();
352     ++ip->ip_windex;
353
354     /*
355      * This isn't a passive IPI, we still have to signal the target cpu.
356      */
357     if (atomic_poll_acquire_int(&ip->ip_npoll)) {
358         logipiq(cpu_send, func, arg1, arg2, gd, target);
359         cpu_send_ipiq(target->gd_cpuid);
360     } else {
361         if (ipiq_optimized == 0) {
362             logipiq(cpu_send, func, arg1, arg2, gd, target);
363             cpu_send_ipiq(target->gd_cpuid);
364         } else {
365             ++ipiq_avoided;
366         }
367     }
368
369     logipiq(send_end, func, arg1, arg2, gd, target);
370     return(0);
371 }
372
373 /*
374  * deprecated, used only by fast int forwarding.
375  */
376 int
377 lwkt_send_ipiq3_bycpu(int dcpu, ipifunc3_t func, void *arg1, int arg2)
378 {
379     return(lwkt_send_ipiq3(globaldata_find(dcpu), func, arg1, arg2));
380 }
381
382 /*
383  * Send a message to several target cpus.  Typically used for scheduling.
384  * The message will not be sent to stopped cpus.
385  */
386 int
387 lwkt_send_ipiq3_mask(u_int32_t mask, ipifunc3_t func, void *arg1, int arg2)
388 {
389     int cpuid;
390     int count = 0;
391
392     mask &= ~stopped_cpus;
393     while (mask) {
394         cpuid = bsfl(mask);
395         lwkt_send_ipiq3(globaldata_find(cpuid), func, arg1, arg2);
396         mask &= ~(1 << cpuid);
397         ++count;
398     }
399     return(count);
400 }
401
402 /*
403  * Wait for the remote cpu to finish processing a function.
404  *
405  * YYY we have to enable interrupts and process the IPIQ while waiting
406  * for it to empty or we may deadlock with another cpu.  Create a CPU_*()
407  * function to do this!  YYY we really should 'block' here.
408  *
409  * MUST be called from a critical section.  This routine may be called
410  * from an interrupt (for example, if an interrupt wakes a foreign thread
411  * up).
412  */
413 void
414 lwkt_wait_ipiq(globaldata_t target, int seq)
415 {
416     lwkt_ipiq_t ip;
417     int maxc = 100000000;
418
419     if (target != mycpu) {
420         ip = &mycpu->gd_ipiq[target->gd_cpuid];
421         if ((int)(ip->ip_xindex - seq) < 0) {
422             unsigned int eflags = read_eflags();
423             cpu_enable_intr();
424             while ((int)(ip->ip_xindex - seq) < 0) {
425                 crit_enter();
426                 lwkt_process_ipiq();
427                 crit_exit();
428                 if (--maxc == 0)
429                         kprintf("LWKT_WAIT_IPIQ WARNING! %d wait %d (%d)\n", mycpu->gd_cpuid, target->gd_cpuid, ip->ip_xindex - seq);
430                 if (maxc < -1000000)
431                         panic("LWKT_WAIT_IPIQ");
432                 /*
433                  * xindex may be modified by another cpu, use a load fence
434                  * to ensure that the loop does not use a speculative value
435                  * (which may improve performance).
436                  */
437                 cpu_lfence();
438             }
439             write_eflags(eflags);
440         }
441     }
442 }
443
444 int
445 lwkt_seq_ipiq(globaldata_t target)
446 {
447     lwkt_ipiq_t ip;
448
449     ip = &mycpu->gd_ipiq[target->gd_cpuid];
450     return(ip->ip_windex);
451 }
452
453 /*
454  * Called from IPI interrupt (like a fast interrupt), which has placed
455  * us in a critical section.  The MP lock may or may not be held.
456  * May also be called from doreti or splz, or be reentrantly called
457  * indirectly through the ip_func[] we run.
458  *
459  * There are two versions, one where no interrupt frame is available (when
460  * called from the send code and from splz, and one where an interrupt
461  * frame is available.
462  */
463 void
464 lwkt_process_ipiq(void)
465 {
466     globaldata_t gd = mycpu;
467     globaldata_t sgd;
468     lwkt_ipiq_t ip;
469     int n;
470
471 again:
472     for (n = 0; n < ncpus; ++n) {
473         if (n != gd->gd_cpuid) {
474             sgd = globaldata_find(n);
475             ip = sgd->gd_ipiq;
476             if (ip != NULL) {
477                 while (lwkt_process_ipiq_core(sgd, &ip[gd->gd_cpuid], NULL))
478                     ;
479             }
480         }
481     }
482     if (gd->gd_cpusyncq.ip_rindex != gd->gd_cpusyncq.ip_windex) {
483         if (lwkt_process_ipiq_core(gd, &gd->gd_cpusyncq, NULL)) {
484             if (gd->gd_curthread->td_cscount == 0)
485                 goto again;
486             need_ipiq();
487         }
488     }
489 }
490
491 #ifdef _KERNEL
492 void
493 lwkt_process_ipiq_frame(struct intrframe *frame)
494 {
495     globaldata_t gd = mycpu;
496     globaldata_t sgd;
497     lwkt_ipiq_t ip;
498     int n;
499
500 again:
501     for (n = 0; n < ncpus; ++n) {
502         if (n != gd->gd_cpuid) {
503             sgd = globaldata_find(n);
504             ip = sgd->gd_ipiq;
505             if (ip != NULL) {
506                 while (lwkt_process_ipiq_core(sgd, &ip[gd->gd_cpuid], frame))
507                     ;
508             }
509         }
510     }
511     if (gd->gd_cpusyncq.ip_rindex != gd->gd_cpusyncq.ip_windex) {
512         if (lwkt_process_ipiq_core(gd, &gd->gd_cpusyncq, frame)) {
513             if (gd->gd_curthread->td_cscount == 0)
514                 goto again;
515             need_ipiq();
516         }
517     }
518 }
519 #endif
520
521 static int
522 lwkt_process_ipiq_core(globaldata_t sgd, lwkt_ipiq_t ip, 
523                        struct intrframe *frame)
524 {
525     int ri;
526     int wi;
527     ipifunc3_t copy_func;
528     void *copy_arg1;
529     int copy_arg2;
530
531     /*
532      * Obtain the current write index, which is modified by a remote cpu.
533      * Issue a load fence to prevent speculative reads of e.g. data written
534      * by the other cpu prior to it updating the index.
535      */
536     KKASSERT(curthread->td_pri >= TDPRI_CRIT);
537     wi = ip->ip_windex;
538     cpu_lfence();
539
540     /*
541      * Note: xindex is only updated after we are sure the function has
542      * finished execution.  Beware lwkt_process_ipiq() reentrancy!  The
543      * function may send an IPI which may block/drain.
544      *
545      * Note: due to additional IPI operations that the callback function
546      * may make, it is possible for both rindex and windex to advance and
547      * thus for rindex to advance passed our cached windex.
548      */
549     while (wi - (ri = ip->ip_rindex) > 0) {
550         ri &= MAXCPUFIFO_MASK;
551         copy_func = ip->ip_func[ri];
552         copy_arg1 = ip->ip_arg1[ri];
553         copy_arg2 = ip->ip_arg2[ri];
554         cpu_mfence();
555         ++ip->ip_rindex;
556         KKASSERT((ip->ip_rindex & MAXCPUFIFO_MASK) == ((ri + 1) & MAXCPUFIFO_MASK));
557         logipiq(receive, copy_func, copy_arg1, copy_arg2, sgd, mycpu);
558         copy_func(copy_arg1, copy_arg2, frame);
559         cpu_sfence();
560         ip->ip_xindex = ip->ip_rindex;
561
562 #ifdef PANIC_DEBUG
563         /*
564          * Simulate panics during the processing of an IPI
565          */
566         if (mycpu->gd_cpuid == panic_ipiq_cpu && panic_ipiq_count) {
567                 if (--panic_ipiq_count == 0) {
568 #ifdef DDB
569                         Debugger("PANIC_DEBUG");
570 #else
571                         panic("PANIC_DEBUG");
572 #endif
573                 }
574         }
575 #endif
576     }
577
578     /*
579      * Return non-zero if there are more IPI messages pending on this
580      * ipiq.  ip_npoll is left set as long as possible to reduce the
581      * number of IPIs queued by the originating cpu, but must be cleared
582      * *BEFORE* checking windex.
583      */
584     atomic_poll_release_int(&ip->ip_npoll);
585     return(wi != ip->ip_windex);
586 }
587
588 static void
589 lwkt_sync_ipiq(void *arg)
590 {
591     cpumask_t *cpumask = arg;
592
593     atomic_clear_int(cpumask, mycpu->gd_cpumask);
594     if (*cpumask == 0)
595         wakeup(cpumask);
596 }
597
598 void
599 lwkt_synchronize_ipiqs(const char *wmesg)
600 {
601     cpumask_t other_cpumask;
602
603     other_cpumask = mycpu->gd_other_cpus & smp_active_mask;
604     lwkt_send_ipiq_mask(other_cpumask, lwkt_sync_ipiq, &other_cpumask);
605
606     crit_enter();
607     while (other_cpumask != 0) {
608         tsleep_interlock(&other_cpumask);
609         if (other_cpumask != 0)
610             tsleep(&other_cpumask, 0, wmesg, 0);
611     }
612     crit_exit();
613 }
614
615 #endif
616
617 /*
618  * CPU Synchronization Support
619  *
620  * lwkt_cpusync_simple()
621  *
622  *      The function is executed synchronously before return on remote cpus.
623  *      A lwkt_cpusync_t pointer is passed as an argument.  The data can
624  *      be accessed via arg->cs_data.
625  *
626  *      XXX should I just pass the data as an argument to be consistent?
627  */
628
629 void
630 lwkt_cpusync_simple(cpumask_t mask, cpusync_func_t func, void *data)
631 {
632     struct lwkt_cpusync cmd;
633
634     cmd.cs_run_func = NULL;
635     cmd.cs_fin1_func = func;
636     cmd.cs_fin2_func = NULL;
637     cmd.cs_data = data;
638     lwkt_cpusync_start(mask & mycpu->gd_other_cpus, &cmd);
639     if (mask & (1 << mycpu->gd_cpuid))
640         func(&cmd);
641     lwkt_cpusync_finish(&cmd);
642 }
643
644 /*
645  * lwkt_cpusync_fastdata()
646  *
647  *      The function is executed in tandem with return on remote cpus.
648  *      The data is directly passed as an argument.  Do not pass pointers to
649  *      temporary storage as the storage might have
650  *      gone poof by the time the target cpu executes
651  *      the function.
652  *
653  *      At the moment lwkt_cpusync is declared on the stack and we must wait
654  *      for all remote cpus to ack in lwkt_cpusync_finish(), but as a future
655  *      optimization we should be able to put a counter in the globaldata
656  *      structure (if it is not otherwise being used) and just poke it and
657  *      return without waiting. XXX
658  */
659 void
660 lwkt_cpusync_fastdata(cpumask_t mask, cpusync_func2_t func, void *data)
661 {
662     struct lwkt_cpusync cmd;
663
664     cmd.cs_run_func = NULL;
665     cmd.cs_fin1_func = NULL;
666     cmd.cs_fin2_func = func;
667     cmd.cs_data = NULL;
668     lwkt_cpusync_start(mask & mycpu->gd_other_cpus, &cmd);
669     if (mask & (1 << mycpu->gd_cpuid))
670         func(data);
671     lwkt_cpusync_finish(&cmd);
672 }
673
674 /*
675  * lwkt_cpusync_start()
676  *
677  *      Start synchronization with a set of target cpus, return once they are
678  *      known to be in a synchronization loop.  The target cpus will execute
679  *      poll->cs_run_func() IN TANDEM WITH THE RETURN.
680  *
681  *      XXX future: add lwkt_cpusync_start_quick() and require a call to
682  *      lwkt_cpusync_add() or lwkt_cpusync_wait(), allowing the caller to
683  *      potentially absorb the IPI latency doing something useful.
684  */
685 void
686 lwkt_cpusync_start(cpumask_t mask, lwkt_cpusync_t poll)
687 {
688     globaldata_t gd = mycpu;
689
690     poll->cs_count = 0;
691     poll->cs_mask = mask;
692 #ifdef SMP
693     logipiq2(sync_start, mask & gd->gd_other_cpus);
694     poll->cs_maxcount = lwkt_send_ipiq_mask(
695                 mask & gd->gd_other_cpus & smp_active_mask,
696                 (ipifunc1_t)lwkt_cpusync_remote1, poll);
697 #endif
698     if (mask & gd->gd_cpumask) {
699         if (poll->cs_run_func)
700             poll->cs_run_func(poll);
701     }
702 #ifdef SMP
703     if (poll->cs_maxcount) {
704         ++ipiq_cscount;
705         ++gd->gd_curthread->td_cscount;
706         while (poll->cs_count != poll->cs_maxcount) {
707             crit_enter();
708             lwkt_process_ipiq();
709             crit_exit();
710         }
711     }
712 #endif
713 }
714
715 void
716 lwkt_cpusync_add(cpumask_t mask, lwkt_cpusync_t poll)
717 {
718     globaldata_t gd = mycpu;
719 #ifdef SMP
720     int count;
721 #endif
722
723     mask &= ~poll->cs_mask;
724     poll->cs_mask |= mask;
725 #ifdef SMP
726     logipiq2(sync_add, mask & gd->gd_other_cpus);
727     count = lwkt_send_ipiq_mask(
728                 mask & gd->gd_other_cpus & smp_active_mask,
729                 (ipifunc1_t)lwkt_cpusync_remote1, poll);
730 #endif
731     if (mask & gd->gd_cpumask) {
732         if (poll->cs_run_func)
733             poll->cs_run_func(poll);
734     }
735 #ifdef SMP
736     poll->cs_maxcount += count;
737     if (poll->cs_maxcount) {
738         if (poll->cs_maxcount == count)
739             ++gd->gd_curthread->td_cscount;
740         while (poll->cs_count != poll->cs_maxcount) {
741             crit_enter();
742             lwkt_process_ipiq();
743             crit_exit();
744         }
745     }
746 #endif
747 }
748
749 /*
750  * Finish synchronization with a set of target cpus.  The target cpus will
751  * execute cs_fin1_func(poll) prior to this function returning, and will
752  * execute cs_fin2_func(data) IN TANDEM WITH THIS FUNCTION'S RETURN.
753  *
754  * If cs_maxcount is non-zero then we are mastering a cpusync with one or
755  * more remote cpus and must account for it in our thread structure.
756  */
757 void
758 lwkt_cpusync_finish(lwkt_cpusync_t poll)
759 {
760     globaldata_t gd = mycpu;
761
762     poll->cs_count = -1;
763     if (poll->cs_mask & gd->gd_cpumask) {
764         if (poll->cs_fin1_func)
765             poll->cs_fin1_func(poll);
766         if (poll->cs_fin2_func)
767             poll->cs_fin2_func(poll->cs_data);
768     }
769 #ifdef SMP
770     if (poll->cs_maxcount) {
771         while (poll->cs_count != -(poll->cs_maxcount + 1)) {
772             crit_enter();
773             lwkt_process_ipiq();
774             crit_exit();
775         }
776         --gd->gd_curthread->td_cscount;
777     }
778 #endif
779 }
780
781 #ifdef SMP
782
783 /*
784  * helper IPI remote messaging function.
785  * 
786  * Called on remote cpu when a new cpu synchronization request has been
787  * sent to us.  Execute the run function and adjust cs_count, then requeue
788  * the request so we spin on it.
789  */
790 static void
791 lwkt_cpusync_remote1(lwkt_cpusync_t poll)
792 {
793     atomic_add_int(&poll->cs_count, 1);
794     if (poll->cs_run_func)
795         poll->cs_run_func(poll);
796     lwkt_cpusync_remote2(poll);
797 }
798
799 /*
800  * helper IPI remote messaging function.
801  *
802  * Poll for the originator telling us to finish.  If it hasn't, requeue
803  * our request so we spin on it.  When the originator requests that we
804  * finish we execute cs_fin1_func(poll) synchronously and cs_fin2_func(data)
805  * in tandem with the release.
806  */
807 static void
808 lwkt_cpusync_remote2(lwkt_cpusync_t poll)
809 {
810     if (poll->cs_count < 0) {
811         cpusync_func2_t savef;
812         void *saved;
813
814         if (poll->cs_fin1_func)
815             poll->cs_fin1_func(poll);
816         if (poll->cs_fin2_func) {
817             savef = poll->cs_fin2_func;
818             saved = poll->cs_data;
819             atomic_add_int(&poll->cs_count, -1);
820             savef(saved);
821         } else {
822             atomic_add_int(&poll->cs_count, -1);
823         }
824     } else {
825         globaldata_t gd = mycpu;
826         lwkt_ipiq_t ip;
827         int wi;
828
829         ip = &gd->gd_cpusyncq;
830         wi = ip->ip_windex & MAXCPUFIFO_MASK;
831         ip->ip_func[wi] = (ipifunc3_t)(ipifunc1_t)lwkt_cpusync_remote2;
832         ip->ip_arg1[wi] = poll;
833         ip->ip_arg2[wi] = 0;
834         cpu_sfence();
835         ++ip->ip_windex;
836     }
837 }
838
839 #endif