pthread_md.h revision 134326
1113656Sdeischen/*-
2113656Sdeischen * Copyright (c) 2002 Daniel Eischen <deischen@freebsd.org>.
3113656Sdeischen * All rights reserved.
4113656Sdeischen *
5113656Sdeischen * Redistribution and use in source and binary forms, with or without
6113656Sdeischen * modification, are permitted provided that the following conditions
7113656Sdeischen * are met:
8113656Sdeischen * 1. Redistributions of source code must retain the above copyright
9113656Sdeischen *    notice, this list of conditions and the following disclaimer.
10113656Sdeischen * 2. Redistributions in binary form must reproduce the above copyright
11113656Sdeischen *    notice, this list of conditions and the following disclaimer in the
12113656Sdeischen *    documentation and/or other materials provided with the distribution.
13113656Sdeischen *
14113656Sdeischen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15113656Sdeischen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16113656Sdeischen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17113656Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18113656Sdeischen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19113656Sdeischen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20113656Sdeischen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21113656Sdeischen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22113656Sdeischen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23113656Sdeischen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24113656Sdeischen * SUCH DAMAGE.
25113656Sdeischen *
26113656Sdeischen * $FreeBSD: head/lib/libkse/arch/i386/include/pthread_md.h 134326 2004-08-26 02:41:01Z davidxu $
27113656Sdeischen */
28113656Sdeischen/*
29113656Sdeischen * Machine-dependent thread prototypes/definitions for the thread kernel.
30113656Sdeischen */
31113656Sdeischen#ifndef _PTHREAD_MD_H_
32113656Sdeischen#define	_PTHREAD_MD_H_
33113656Sdeischen
34133801Sdavidxu#include <stddef.h>
35118277Sdeischen#include <sys/kse.h>
36113656Sdeischen#include <ucontext.h>
37113656Sdeischen
38118277Sdeischenextern int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
39118277Sdeischenextern int _thr_getcontext(mcontext_t *);
40113656Sdeischen
41120263Smarcel#define	KSE_STACKSIZE		16384
42133801Sdavidxu#define	DTV_OFFSET		offsetof(struct tcb, tcb_dtv)
43120263Smarcel
44118510Sdeischen#define	THR_GETCONTEXT(ucp)	_thr_getcontext(&(ucp)->uc_mcontext)
45118510Sdeischen#define	THR_SETCONTEXT(ucp)	_thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
46113656Sdeischen
47118510Sdeischen#define	PER_KSE
48118510Sdeischen#undef	PER_THREAD
49116771Smarcel
50118510Sdeischenstruct kse;
51118510Sdeischenstruct pthread;
52118510Sdeischen
53116771Smarcel/*
54118510Sdeischen * %gs points to a struct kcb.
55116771Smarcel */
56118510Sdeischenstruct kcb {
57118510Sdeischen	struct tcb		*kcb_curtcb;
58118510Sdeischen	struct kcb		*kcb_self;	/* self reference */
59118510Sdeischen	int			kcb_ldt;
60118510Sdeischen	struct kse		*kcb_kse;
61118510Sdeischen	struct kse_mailbox	kcb_kmbx;
62116771Smarcel};
63116771Smarcel
64118510Sdeischenstruct tcb {
65133756Sdfr	struct tcb		*tcb_self;	/* required by rtld */
66133756Sdfr	void			*tcb_dtv;	/* required by rtld */
67118510Sdeischen	struct pthread		*tcb_thread;
68118510Sdeischen	void			*tcb_spare;	/* align tcb_tmbx to 16 bytes */
69118510Sdeischen	struct kse_thr_mailbox	tcb_tmbx;
70118510Sdeischen};
71118277Sdeischen
72118510Sdeischen/*
73118510Sdeischen * Evaluates to the byte offset of the per-kse variable name.
74118510Sdeischen */
75118510Sdeischen#define	__kcb_offset(name)	__offsetof(struct kcb, name)
76118510Sdeischen
77118510Sdeischen/*
78118510Sdeischen * Evaluates to the type of the per-kse variable name.
79118510Sdeischen */
80118510Sdeischen#define	__kcb_type(name)	__typeof(((struct kcb *)0)->name)
81118510Sdeischen
82118510Sdeischen/*
83118510Sdeischen * Evaluates to the value of the per-kse variable name.
84118510Sdeischen */
85118510Sdeischen#define	KCB_GET32(name) ({					\
86118510Sdeischen	__kcb_type(name) __result;				\
87118510Sdeischen								\
88118510Sdeischen	u_int __i;						\
89118510Sdeischen	__asm __volatile("movl %%gs:%1, %0"			\
90118510Sdeischen	    : "=r" (__i)					\
91118510Sdeischen	    : "m" (*(u_int *)(__kcb_offset(name))));		\
92134326Sdavidxu	__result = (__kcb_type(name))__i;			\
93118510Sdeischen								\
94118510Sdeischen	__result;						\
95118510Sdeischen})
96118510Sdeischen
97118510Sdeischen/*
98118510Sdeischen * Sets the value of the per-kse variable name to value val.
99118510Sdeischen */
100118510Sdeischen#define	KCB_SET32(name, val) ({					\
101118510Sdeischen	__kcb_type(name) __val = (val);				\
102118510Sdeischen								\
103118510Sdeischen	u_int __i;						\
104134319Sdavidxu	__i = (u_int)__val;					\
105118510Sdeischen	__asm __volatile("movl %1,%%gs:%0"			\
106118510Sdeischen	    : "=m" (*(u_int *)(__kcb_offset(name)))		\
107118510Sdeischen	    : "r" (__i));					\
108118510Sdeischen})
109118510Sdeischen
110118510Sdeischenstatic __inline u_long
111118510Sdeischen__kcb_readandclear32(volatile u_long *addr)
112118510Sdeischen{
113118510Sdeischen	u_long result;
114118510Sdeischen
115118510Sdeischen	__asm __volatile (
116118510Sdeischen	    "	xorl	%0, %0;"
117118510Sdeischen	    "	xchgl	%%gs:%1, %0;"
118118510Sdeischen	    "# __kcb_readandclear32"
119118510Sdeischen	    : "=&r" (result)
120118510Sdeischen	    : "m" (*addr));
121118510Sdeischen	return (result);
122118510Sdeischen}
123118510Sdeischen
124118510Sdeischen#define	KCB_READANDCLEAR32(name) ({				\
125118510Sdeischen	__kcb_type(name) __result;				\
126118510Sdeischen								\
127118510Sdeischen	__result = (__kcb_type(name))				\
128118510Sdeischen	    __kcb_readandclear32((u_long *)__kcb_offset(name)); \
129118510Sdeischen	__result;						\
130118510Sdeischen})
131118510Sdeischen
132118510Sdeischen
133118510Sdeischen#define	_kcb_curkcb()		KCB_GET32(kcb_self)
134118510Sdeischen#define	_kcb_curtcb()		KCB_GET32(kcb_curtcb)
135118510Sdeischen#define	_kcb_curkse()		((struct kse *)KCB_GET32(kcb_kmbx.km_udata))
136118510Sdeischen#define	_kcb_get_tmbx()		KCB_GET32(kcb_kmbx.km_curthread)
137118510Sdeischen#define	_kcb_set_tmbx(value)	KCB_SET32(kcb_kmbx.km_curthread, (void *)value)
138118510Sdeischen#define	_kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread)
139118510Sdeischen
140118510Sdeischen
141118510Sdeischen/*
142118510Sdeischen * The constructors.
143118510Sdeischen */
144133756Sdfrstruct tcb	*_tcb_ctor(struct pthread *, int);
145118510Sdeischenvoid		_tcb_dtor(struct tcb *tcb);
146118510Sdeischenstruct kcb	*_kcb_ctor(struct kse *);
147118510Sdeischenvoid		_kcb_dtor(struct kcb *);
148118510Sdeischen
149118510Sdeischen/* Called from the KSE to set its private data. */
150118510Sdeischenstatic __inline void
151118510Sdeischen_kcb_set(struct kcb *kcb)
152118510Sdeischen{
153118510Sdeischen	int val;
154118510Sdeischen
155118510Sdeischen	val = (kcb->kcb_ldt << 3) | 7;
156118510Sdeischen	__asm __volatile("movl %0, %%gs" : : "r" (val));
157118510Sdeischen}
158118510Sdeischen
159118510Sdeischen/* Get the current kcb. */
160118510Sdeischenstatic __inline struct kcb *
161118510Sdeischen_kcb_get(void)
162118510Sdeischen{
163118510Sdeischen	return (_kcb_curkcb());
164118510Sdeischen}
165118510Sdeischen
166118510Sdeischenstatic __inline struct kse_thr_mailbox *
167118510Sdeischen_kcb_critical_enter(void)
168118510Sdeischen{
169118510Sdeischen	struct kse_thr_mailbox *crit;
170118510Sdeischen
171118510Sdeischen	crit = _kcb_readandclear_tmbx();
172118510Sdeischen	return (crit);
173118510Sdeischen}
174118510Sdeischen
175118510Sdeischenstatic __inline void
176118510Sdeischen_kcb_critical_leave(struct kse_thr_mailbox *crit)
177118510Sdeischen{
178118510Sdeischen	_kcb_set_tmbx(crit);
179118510Sdeischen}
180118510Sdeischen
181118277Sdeischenstatic __inline int
182118510Sdeischen_kcb_in_critical(void)
183118277Sdeischen{
184118510Sdeischen	return (_kcb_get_tmbx() == NULL);
185118510Sdeischen}
186118510Sdeischen
187118510Sdeischenstatic __inline void
188118510Sdeischen_tcb_set(struct kcb *kcb, struct tcb *tcb)
189118510Sdeischen{
190118510Sdeischen	kcb->kcb_curtcb = tcb;
191118510Sdeischen}
192118510Sdeischen
193118510Sdeischenstatic __inline struct tcb *
194118510Sdeischen_tcb_get(void)
195118510Sdeischen{
196118510Sdeischen	return (_kcb_curtcb());
197118510Sdeischen}
198118510Sdeischen
199118510Sdeischenstatic __inline struct pthread *
200118510Sdeischen_get_curthread(void)
201118510Sdeischen{
202118510Sdeischen	struct tcb *tcb;
203118510Sdeischen
204118510Sdeischen	tcb = _kcb_curtcb();
205118510Sdeischen	if (tcb != NULL)
206118510Sdeischen		return (tcb->tcb_thread);
207118510Sdeischen	else
208118510Sdeischen		return (NULL);
209118510Sdeischen}
210118510Sdeischen
211118510Sdeischenstatic __inline struct kse *
212118510Sdeischen_get_curkse(void)
213118510Sdeischen{
214118510Sdeischen	return ((struct kse *)_kcb_curkse());
215118510Sdeischen}
216118510Sdeischen
217118510Sdeischenvoid	_i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
218118510Sdeischen    size_t stacksz);
219118510Sdeischen
220118510Sdeischenstatic __inline int
221118510Sdeischen_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
222118510Sdeischen{
223118277Sdeischen	int ret;
224118277Sdeischen
225118510Sdeischen	ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext);
226118277Sdeischen	if (ret == 0) {
227118510Sdeischen		_i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
228118510Sdeischen		    kcb->kcb_kmbx.km_stack.ss_sp,
229118510Sdeischen		    kcb->kcb_kmbx.km_stack.ss_size);
230118277Sdeischen		/* We should not reach here. */
231118277Sdeischen		return (-1);
232118277Sdeischen	}
233118277Sdeischen	else if (ret < 0)
234118277Sdeischen		return (-1);
235118277Sdeischen	return (0);
236118277Sdeischen}
237118277Sdeischen
238118277Sdeischenstatic __inline int
239118510Sdeischen_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
240118277Sdeischen{
241132125Sdavidxu	extern int _libkse_debug;
242132125Sdavidxu
243118510Sdeischen	if ((kcb == NULL) || (tcb == NULL))
244118510Sdeischen		return (-1);
245118510Sdeischen	kcb->kcb_curtcb = tcb;
246132125Sdavidxu	if (_libkse_debug == 0) {
247132125Sdavidxu		tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
248132125Sdavidxu		if (setmbox != 0)
249132125Sdavidxu			_thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
250132125Sdavidxu			    (intptr_t)&tcb->tcb_tmbx,
251132125Sdavidxu			    (intptr_t *)&kcb->kcb_kmbx.km_curthread);
252132125Sdavidxu		else
253132125Sdavidxu			_thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
254132125Sdavidxu				0, NULL);
255132125Sdavidxu	} else {
256132125Sdavidxu		if (setmbox)
257132125Sdavidxu			kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
258132125Sdavidxu		else
259132125Sdavidxu			kse_switchin(&tcb->tcb_tmbx, 0);
260132125Sdavidxu	}
261132125Sdavidxu
262118277Sdeischen	/* We should not reach here. */
263118277Sdeischen	return (-1);
264118277Sdeischen}
265118277Sdeischen
266113656Sdeischen#endif
267