acf848f325b1f6f8f2c9bec83d6770e9d68180dc
[dragonfly.git] / sys / sys / thread2.h
1 /*
2  * SYS/THREAD2.H
3  *
4  * Implements inline procedure support for the LWKT subsystem. 
5  *
6  * Generally speaking these routines only operate on threads associated
7  * with the current cpu.  For example, a higher priority thread pending
8  * on a different cpu will not be immediately scheduled by a yield() on
9  * this cpu.
10  */
11
12 #ifndef _SYS_THREAD2_H_
13 #define _SYS_THREAD2_H_
14
15 #ifndef _KERNEL
16
17 #error "This file should not be included by userland programs."
18
19 #else
20
21 /*
22  * Userland will have its own globaldata which it includes prior to this.
23  */
24 #ifndef _SYS_SYSTM_H_
25 #include <sys/systm.h>
26 #endif
27 #ifndef _SYS_GLOBALDATA_H_
28 #include <sys/globaldata.h>
29 #endif
30 #include <machine/cpufunc.h>
31
32 /*
33  * Is a token held by the specified thread?
34  */
35 static __inline int
36 _lwkt_token_held(lwkt_token_t tok, thread_t td)
37 {
38         return ((tok->t_count & ~(TOK_EXCLUSIVE|TOK_EXCLREQ)) ||
39                 (tok->t_ref >= &td->td_toks_base &&
40                  tok->t_ref < td->td_toks_stop));
41 }
42
43 /*
44  * Critical section debugging
45  */
46 #ifdef DEBUG_CRIT_SECTIONS
47 #define __DEBUG_CRIT_ARG__              const char *id
48 #define __DEBUG_CRIT_ADD_ARG__          , const char *id
49 #define __DEBUG_CRIT_PASS_ARG__         , id
50 #define __DEBUG_CRIT_ENTER(td)          _debug_crit_enter((td), id)
51 #define __DEBUG_CRIT_EXIT(td)           _debug_crit_exit((td), id)
52 #define crit_enter()                    _crit_enter(mycpu, __FUNCTION__)
53 #define crit_enter_id(id)               _crit_enter(mycpu, id)
54 #define crit_enter_gd(curgd)            _crit_enter((curgd), __FUNCTION__)
55 #define crit_enter_quick(curtd)         _crit_enter_quick((curtd), __FUNCTION__)
56 #define crit_enter_hard()               _crit_enter_hard(mycpu, __FUNCTION__)
57 #define crit_enter_hard_gd(curgd)       _crit_enter_hard((curgd), __FUNCTION__)
58 #define crit_exit()                     _crit_exit(mycpu, __FUNCTION__)
59 #define crit_exit_id(id)                _crit_exit(mycpu, id)
60 #define crit_exit_gd(curgd)             _crit_exit((curgd), __FUNCTION__)
61 #define crit_exit_quick(curtd)          _crit_exit_quick((curtd), __FUNCTION__)
62 #define crit_exit_hard()                _crit_exit_hard(mycpu, __FUNCTION__)
63 #define crit_exit_hard_gd(curgd)        _crit_exit_hard((curgd), __FUNCTION__)
64 #define crit_exit_noyield(curtd)        _crit_exit_noyield((curtd),__FUNCTION__)
65 #else
66 #define __DEBUG_CRIT_ARG__              void
67 #define __DEBUG_CRIT_ADD_ARG__
68 #define __DEBUG_CRIT_PASS_ARG__
69 #define __DEBUG_CRIT_ENTER(td)
70 #define __DEBUG_CRIT_EXIT(td)
71 #define crit_enter()                    _crit_enter(mycpu)
72 #define crit_enter_id(id)               _crit_enter(mycpu)
73 #define crit_enter_gd(curgd)            _crit_enter((curgd))
74 #define crit_enter_quick(curtd)         _crit_enter_quick((curtd))
75 #define crit_enter_hard()               _crit_enter_hard(mycpu)
76 #define crit_enter_hard_gd(curgd)       _crit_enter_hard((curgd))
77 #define crit_exit()                     crit_exit_wrapper()
78 #define crit_exit_id(id)                _crit_exit(mycpu)
79 #define crit_exit_gd(curgd)             _crit_exit((curgd))
80 #define crit_exit_quick(curtd)          _crit_exit_quick((curtd))
81 #define crit_exit_hard()                _crit_exit_hard(mycpu)
82 #define crit_exit_hard_gd(curgd)        _crit_exit_hard((curgd))
83 #define crit_exit_noyield(curtd)        _crit_exit_noyield((curtd))
84 #endif
85
86 extern void crit_exit_wrapper(__DEBUG_CRIT_ARG__);
87
88 /*
89  * Track crit_enter()/crit_exit() pairs and warn on mismatches.
90  */
91 #ifdef DEBUG_CRIT_SECTIONS
92
93 static __inline void
94 _debug_crit_enter(thread_t td, const char *id)
95 {
96     int wi = td->td_crit_debug_index;
97
98     td->td_crit_debug_array[wi & CRIT_DEBUG_ARRAY_MASK] = id;
99     ++td->td_crit_debug_index;
100 }
101
102 static __inline void
103 _debug_crit_exit(thread_t td, const char *id)
104 {
105     const char *gid;
106     int wi;
107
108     wi = td->td_crit_debug_index - 1;
109     if ((gid = td->td_crit_debug_array[wi & CRIT_DEBUG_ARRAY_MASK]) != id) {
110         if (td->td_in_crit_report == 0) {
111             td->td_in_crit_report = 1;
112             kprintf("crit_exit(%s) expected id %s\n", id, gid);
113             td->td_in_crit_report = 0;
114         }
115     }
116     --td->td_crit_debug_index;
117 }
118
119 #endif
120
121 /*
122  * Critical sections prevent preemption, but allowing explicit blocking
123  * and thread switching.  Any interrupt occuring while in a critical
124  * section is made pending and returns immediately.  Interrupts are not
125  * physically disabled.
126  *
127  * Hard critical sections prevent preemption and disallow any blocking
128  * or thread switching, and in addition will assert on any blockable
129  * operation (acquire token not already held, lockmgr, mutex ops, or
130  * splz).  Spinlocks can still be used in hard sections.
131  *
132  * All critical section routines only operate on the current thread.
133  * Passed gd or td arguments are simply optimizations when mycpu or
134  * curthread is already available to the caller.
135  */
136
137 /*
138  * crit_enter
139  */
140 static __inline void
141 _crit_enter_quick(thread_t td __DEBUG_CRIT_ADD_ARG__)
142 {
143     ++td->td_critcount;
144     __DEBUG_CRIT_ENTER(td);
145     cpu_ccfence();
146 }
147
148 static __inline void
149 _crit_enter(globaldata_t gd __DEBUG_CRIT_ADD_ARG__)
150 {
151     _crit_enter_quick(gd->gd_curthread __DEBUG_CRIT_PASS_ARG__);
152 }
153
154 static __inline void
155 _crit_enter_hard(globaldata_t gd __DEBUG_CRIT_ADD_ARG__)
156 {
157     _crit_enter_quick(gd->gd_curthread __DEBUG_CRIT_PASS_ARG__);
158     ++gd->gd_intr_nesting_level;
159 }
160
161
162 /*
163  * crit_exit*()
164  *
165  * NOTE: Conditionalizing just gd_reqflags, a case which is virtually
166  *       never true regardless of crit_count, should result in 100%
167  *       optimal code execution.  We don't check crit_count because
168  *       it just bloats the inline and does not improve performance.
169  *
170  * NOTE: This can produce a considerable amount of code despite the
171  *       relatively few lines of code so the non-debug case typically
172  *       just wraps it in a real function, crit_exit_wrapper().
173  */
174 static __inline void
175 _crit_exit_noyield(thread_t td __DEBUG_CRIT_ADD_ARG__)
176 {
177     __DEBUG_CRIT_EXIT(td);
178     --td->td_critcount;
179 #ifdef INVARIANTS
180     if (__predict_false(td->td_critcount < 0))
181         crit_panic();
182 #endif
183     cpu_ccfence();      /* prevent compiler reordering */
184 }
185
186 static __inline void
187 _crit_exit_quick(thread_t td __DEBUG_CRIT_ADD_ARG__)
188 {
189     _crit_exit_noyield(td __DEBUG_CRIT_PASS_ARG__);
190     if (__predict_false(td->td_gd->gd_reqflags & RQF_IDLECHECK_MASK))
191         lwkt_maybe_splz(td);
192 }
193
194 static __inline void
195 _crit_exit(globaldata_t gd __DEBUG_CRIT_ADD_ARG__)
196 {
197     _crit_exit_quick(gd->gd_curthread __DEBUG_CRIT_PASS_ARG__);
198 }
199
200 static __inline void
201 _crit_exit_hard(globaldata_t gd __DEBUG_CRIT_ADD_ARG__)
202 {
203     --gd->gd_intr_nesting_level;
204     _crit_exit_quick(gd->gd_curthread __DEBUG_CRIT_PASS_ARG__);
205 }
206
207 static __inline int
208 crit_test(thread_t td)
209 {
210     return(td->td_critcount);
211 }
212
213 /*
214  * Return whether any threads are runnable.
215  */
216 static __inline int
217 lwkt_runnable(void)
218 {
219     return (TAILQ_FIRST(&mycpu->gd_tdrunq) != NULL);
220 }
221
222 static __inline int
223 lwkt_getpri(thread_t td)
224 {
225     return(td->td_pri);
226 }
227
228 static __inline int
229 lwkt_getpri_self(void)
230 {
231     return(lwkt_getpri(curthread));
232 }
233
234 /*
235  * Reduce our priority in preparation for a return to userland.  If
236  * our passive release function was still in place, our priority was
237  * never raised and does not need to be reduced.
238  *
239  * See also lwkt_passive_release() and platform/blah/trap.c
240  */
241 static __inline void
242 lwkt_passive_recover(thread_t td)
243 {
244     if (td->td_release == NULL)
245         lwkt_setpri_self(TDPRI_USER_NORM);
246     td->td_release = NULL;
247 }
248
249 /*
250  * cpusync support
251  */
252 static __inline void
253 lwkt_cpusync_init(lwkt_cpusync_t cs, cpumask_t mask,
254                   cpusync_func_t func, void *data)
255 {
256         cs->cs_mask = mask;
257         /* cs->cs_mack = 0; handled by _interlock */
258         cs->cs_func = func;
259         cs->cs_data = data;
260 }
261
262 #ifdef SMP
263
264 /*
265  * IPIQ messaging wrappers.  IPIQ remote functions are passed three arguments:
266  * a void * pointer, an integer, and a pointer to the trap frame (or NULL if
267  * the trap frame is not known).  However, we wish to provide opaque 
268  * interfaces for simpler callbacks... the basic IPI messaging function as
269  * used by the kernel takes a single argument.
270  */
271 static __inline int
272 lwkt_send_ipiq(globaldata_t target, ipifunc1_t func, void *arg)
273 {
274     return(lwkt_send_ipiq3(target, (ipifunc3_t)func, arg, 0));
275 }
276
277 static __inline int
278 lwkt_send_ipiq2(globaldata_t target, ipifunc2_t func, void *arg1, int arg2)
279 {
280     return(lwkt_send_ipiq3(target, (ipifunc3_t)func, arg1, arg2));
281 }
282
283 static __inline int
284 lwkt_send_ipiq_mask(cpumask_t mask, ipifunc1_t func, void *arg)
285 {
286     return(lwkt_send_ipiq3_mask(mask, (ipifunc3_t)func, arg, 0));
287 }
288
289 static __inline int
290 lwkt_send_ipiq2_mask(cpumask_t mask, ipifunc2_t func, void *arg1, int arg2)
291 {
292     return(lwkt_send_ipiq3_mask(mask, (ipifunc3_t)func, arg1, arg2));
293 }
294
295 static __inline int
296 lwkt_send_ipiq_nowait(globaldata_t target, ipifunc1_t func, void *arg)
297 {
298     return(lwkt_send_ipiq3_nowait(target, (ipifunc3_t)func, arg, 0));
299 }
300
301 static __inline int
302 lwkt_send_ipiq2_nowait(globaldata_t target, ipifunc2_t func, 
303                        void *arg1, int arg2)
304 {
305     return(lwkt_send_ipiq3_nowait(target, (ipifunc3_t)func, arg1, arg2));
306 }
307
308 static __inline int
309 lwkt_send_ipiq_passive(globaldata_t target, ipifunc1_t func, void *arg)
310 {
311     return(lwkt_send_ipiq3_passive(target, (ipifunc3_t)func, arg, 0));
312 }
313
314 static __inline int
315 lwkt_send_ipiq2_passive(globaldata_t target, ipifunc2_t func, 
316                        void *arg1, int arg2)
317 {
318     return(lwkt_send_ipiq3_passive(target, (ipifunc3_t)func, arg1, arg2));
319 }
320
321 static __inline int
322 lwkt_send_ipiq_bycpu(int dcpu, ipifunc1_t func, void *arg)
323 {
324     return(lwkt_send_ipiq3_bycpu(dcpu, (ipifunc3_t)func, arg, 0));
325 }
326
327 static __inline int
328 lwkt_send_ipiq2_bycpu(int dcpu, ipifunc2_t func, void *arg1, int arg2)
329 {
330     return(lwkt_send_ipiq3_bycpu(dcpu, (ipifunc3_t)func, arg1, arg2));
331 }
332
333 #endif  /* SMP */
334 #endif  /* _KERNEL */
335 #endif  /* _SYS_THREAD2_H_ */
336