Remove erroneous use of the `Fl' mdoc macro and replace it with
[dragonfly.git] / lib / libcaps / uthread.c
1 /*
2  * Copyright (c) 2003 Galen Sampson <galen_sampson@yahoo.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/lib/libcaps/uthread.c,v 1.4 2004/04/24 09:26:25 joerg Exp $
27  */
28
29 /*
30  * Each cpu in a system has its own self-contained light weight kernel
31  * thread scheduler, which means that generally speaking we only need
32  * to use a critical section to avoid problems.  Foreign thread 
33  * scheduling is queued via (async) IPIs.
34  */
35
36 #include "defs.h"
37
38 void cpu_lwkt_switch(thread_t);
39
40 /*
41  * system message port for the system call interface
42  */
43 lwkt_port_t             sysport;
44
45 static void
46 lwkt_idleloop(void *dummy)
47 {
48     globaldata_t gd = mycpu;
49
50     DBPRINTF(("idlestart cpu %d pri %d (should be < 32) mpcount %d (should be 0)\n",
51         gd->gd_cpuid, curthread->td_pri, curthread->td_mpcount));
52
53     gd->gd_pid = getpid();
54
55     for (;;) {
56         /*
57          * If only our 'main' thread is left, schedule it.
58          */
59         if (gd->gd_num_threads == gd->gd_sys_threads) {
60             int i;
61             globaldata_t tgd;
62
63             for (i = 0; i < ncpus; ++i) {
64                 tgd = globaldata_find(i);
65                 if (tgd->gd_num_threads != tgd->gd_sys_threads)
66                     break;
67             }
68             if (i == ncpus && (main_td.td_flags & TDF_RUNQ) == 0)
69                 lwkt_schedule(&main_td);
70         }
71
72         /*
73          * Wait for an interrupt, aka wait for a signal or an upcall to
74          * occur, then switch away.
75          */
76         crit_enter();
77         if (gd->gd_runqmask || (curthread->td_flags & TDF_IDLE_NOHLT)) {
78             curthread->td_flags &= ~TDF_IDLE_NOHLT;
79         } else {
80             printf("cpu %d halting\n", gd->gd_cpuid);
81             cpu_halt();
82             printf("cpu %d resuming\n", gd->gd_cpuid);
83         }
84         crit_exit();
85         lwkt_switch();
86     }
87 }
88
89 /*
90  * Userland override of lwkt_init_thread. The only difference is
91  * the manipulation of gd->gd_num_threads.
92  */
93 static void
94 lwkt_init_thread_remote(void *arg)
95
96     thread_t td = arg;
97     globaldata_t gd = td->td_gd;
98
99     printf("init_thread_remote td %p on cpu %d\n", td, gd->gd_cpuid);
100      
101     TAILQ_INSERT_TAIL(&gd->gd_tdallq, td, td_allq);
102     ++gd->gd_num_threads;
103     if (td->td_flags & TDF_SYSTHREAD)
104         ++gd->gd_sys_threads;
105 }
106
107 void
108 lwkt_init_thread(thread_t td, void *stack, int flags, struct globaldata *gd)
109 {
110     bzero(td, sizeof(struct thread));
111     td->td_kstack = stack;
112     td->td_flags |= flags;
113     td->td_gd = gd;
114     td->td_pri = TDPRI_KERN_DAEMON + TDPRI_CRIT;
115     lwkt_initport(&td->td_msgport, td);
116     cpu_init_thread(td);
117     if (td == &gd->gd_idlethread) {
118         TAILQ_INSERT_TAIL(&gd->gd_tdallq, td, td_allq);
119         /* idle thread is not counted in gd_num_threads */
120     } else if (gd == mycpu) {
121         crit_enter();
122         TAILQ_INSERT_TAIL(&gd->gd_tdallq, td, td_allq);
123         ++gd->gd_num_threads;
124         if (td->td_flags & TDF_SYSTHREAD)
125             ++gd->gd_sys_threads;
126         crit_exit();
127     } else {
128         lwkt_send_ipiq(gd, lwkt_init_thread_remote, td);
129     }
130 }
131
132 /*
133  * Userland override of lwkt_exit. The only difference is
134  * the manipulation of gd->gd_num_threads;
135  */
136 void
137 lwkt_exit(void)
138 {
139     thread_t td = curthread;
140     globaldata_t gd = mycpu;
141
142     if (td->td_flags & TDF_VERBOSE)
143         printf("kthread %p %s has exited\n", td, td->td_comm);
144     crit_enter();
145     lwkt_deschedule_self(td);
146     ++gd->gd_tdfreecount;
147     if (td->td_flags & TDF_SYSTHREAD)
148         --gd->gd_sys_threads;
149     --gd->gd_num_threads;
150     TAILQ_INSERT_TAIL(&gd->gd_tdfreeq, td, td_threadq);
151     cpu_thread_exit();
152 }
153
154 /*
155  * Userland override of lwkt_gdinit.  Called from mi_gdinit().  Note that
156  * critical sections do not work until lwkt_init_thread() is called.  The
157  * idle thread will be left in a critical section.
158  */
159 void
160 lwkt_gdinit(struct globaldata *gd)
161 {
162     int i;
163
164     for (i = 0; i < sizeof(gd->gd_tdrunq)/sizeof(gd->gd_tdrunq[0]); ++i)
165         TAILQ_INIT(&gd->gd_tdrunq[i]);
166     gd->gd_runqmask = 0;
167     gd->gd_curthread = &gd->gd_idlethread;
168     TAILQ_INIT(&gd->gd_tdallq);
169
170     /* Set up this cpu's idle thread */
171     lwkt_init_thread(&gd->gd_idlethread, libcaps_alloc_stack(THREAD_STACK), 0, gd);
172     cpu_set_thread_handler(&gd->gd_idlethread, lwkt_exit, lwkt_idleloop, NULL);
173 }
174
175 /*
176  * Start threading.
177  */
178 void
179 lwkt_start_threading(thread_t td)
180 {
181     lwkt_switch();
182 }
183