2 * Copyright (c) 2002 Daniel Eischen <deischen@freebsd.org>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 * Machine-dependent thread prototypes/definitions for the thread kernel.
31 #ifndef _PTHREAD_MD_H_
32 #define _PTHREAD_MD_H_
35 #include <sys/types.h>
37 #include <machine/sysarch.h>
40 extern int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
41 extern int _thr_getcontext(mcontext_t *);
43 extern int _thr_using_setbase;
45 #define KSE_STACKSIZE 16384
46 #define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
48 #define THR_GETCONTEXT(ucp) _thr_getcontext(&(ucp)->uc_mcontext)
49 #define THR_SETCONTEXT(ucp) _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
58 * %gs points to a struct kcb.
61 struct tcb *kcb_curtcb;
62 struct kcb *kcb_self; /* self reference */
65 struct kse_mailbox kcb_kmbx;
69 struct tcb *tcb_self; /* required by rtld */
70 void *tcb_dtv; /* required by rtld */
71 struct pthread *tcb_thread;
72 void *tcb_spare; /* align tcb_tmbx to 16 bytes */
73 struct kse_thr_mailbox tcb_tmbx;
77 * Evaluates to the byte offset of the per-kse variable name.
79 #define __kcb_offset(name) __offsetof(struct kcb, name)
82 * Evaluates to the type of the per-kse variable name.
84 #define __kcb_type(name) __typeof(((struct kcb *)0)->name)
87 * Evaluates to the value of the per-kse variable name.
89 #define KCB_GET32(name) ({ \
90 __kcb_type(name) __result; \
93 __asm __volatile("movl %%gs:%1, %0" \
95 : "m" (*(u_int *)(__kcb_offset(name)))); \
96 __result = (__kcb_type(name))__i; \
102 * Sets the value of the per-kse variable name to value val.
104 #define KCB_SET32(name, val) ({ \
105 __kcb_type(name) __val = (val); \
108 __i = (u_int)__val; \
109 __asm __volatile("movl %1,%%gs:%0" \
110 : "=m" (*(u_int *)(__kcb_offset(name))) \
114 static __inline u_long
115 __kcb_readandclear32(volatile u_long *addr)
121 " xchgl %%gs:%1, %0;"
122 "# __kcb_readandclear32"
128 #define KCB_READANDCLEAR32(name) ({ \
129 __kcb_type(name) __result; \
131 __result = (__kcb_type(name)) \
132 __kcb_readandclear32((u_long *)__kcb_offset(name)); \
137 #define _kcb_curkcb() KCB_GET32(kcb_self)
138 #define _kcb_curtcb() KCB_GET32(kcb_curtcb)
139 #define _kcb_curkse() ((struct kse *)KCB_GET32(kcb_kmbx.km_udata))
140 #define _kcb_get_tmbx() KCB_GET32(kcb_kmbx.km_curthread)
141 #define _kcb_set_tmbx(value) KCB_SET32(kcb_kmbx.km_curthread, (void *)value)
142 #define _kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread)
148 struct tcb *_tcb_ctor(struct pthread *, int);
149 void _tcb_dtor(struct tcb *tcb);
150 struct kcb *_kcb_ctor(struct kse *);
151 void _kcb_dtor(struct kcb *);
153 /* Called from the KSE to set its private data. */
155 _kcb_set(struct kcb *kcb)
159 if (_thr_using_setbase == 1) {
160 i386_set_gsbase(kcb);
162 val = (kcb->kcb_ldt << 3) | 7;
163 __asm __volatile("movl %0, %%gs" : : "r" (val));
168 /* Get the current kcb. */
169 static __inline struct kcb *
172 return (_kcb_curkcb());
175 static __inline struct kse_thr_mailbox *
176 _kcb_critical_enter(void)
178 struct kse_thr_mailbox *crit;
180 crit = _kcb_readandclear_tmbx();
185 _kcb_critical_leave(struct kse_thr_mailbox *crit)
191 _kcb_in_critical(void)
193 return (_kcb_get_tmbx() == NULL);
197 _tcb_set(struct kcb *kcb, struct tcb *tcb)
199 kcb->kcb_curtcb = tcb;
202 static __inline struct tcb *
205 return (_kcb_curtcb());
208 static __inline struct pthread *
215 return (tcb->tcb_thread);
220 static __inline struct kse *
223 return ((struct kse *)_kcb_curkse());
226 void _i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
230 _thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
234 ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext);
236 _i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
237 kcb->kcb_kmbx.km_stack.ss_sp,
238 kcb->kcb_kmbx.km_stack.ss_size);
239 /* We should not reach here. */
248 _thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
250 extern int _libkse_debug;
252 if ((kcb == NULL) || (tcb == NULL))
254 kcb->kcb_curtcb = tcb;
255 if (_libkse_debug == 0) {
256 tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
258 _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
259 (intptr_t)&tcb->tcb_tmbx,
260 (intptr_t *)&kcb->kcb_kmbx.km_curthread);
262 _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
266 kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
268 kse_switchin(&tcb->tcb_tmbx, 0);
271 /* We should not reach here. */