pthread_md.h revision 120263
1283514Sarybchik/*-
2283514Sarybchik * Copyright (c) 2002 Daniel Eischen <deischen@freebsd.org>.
3283514Sarybchik * All rights reserved.
4283514Sarybchik *
5283514Sarybchik * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions
7283514Sarybchik * are met:
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright
9283514Sarybchik *    notice, this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright
11283514Sarybchik *    notice, this list of conditions and the following disclaimer in the
12283514Sarybchik *    documentation and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15283514Sarybchik * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16283514Sarybchik * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17283514Sarybchik * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18283514Sarybchik * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19283514Sarybchik * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20283514Sarybchik * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21283514Sarybchik * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22283514Sarybchik * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23283514Sarybchik * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24283514Sarybchik * SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * $FreeBSD: head/lib/libkse/arch/i386/include/pthread_md.h 120263 2003-09-19 23:28:13Z marcel $
27283514Sarybchik */
28283514Sarybchik/*
29283514Sarybchik * Machine-dependent thread prototypes/definitions for the thread kernel.
30283514Sarybchik */
31283514Sarybchik#ifndef _PTHREAD_MD_H_
32283514Sarybchik#define	_PTHREAD_MD_H_
33283514Sarybchik
34283514Sarybchik#include <sys/kse.h>
35283514Sarybchik#include <ucontext.h>
36283514Sarybchik
37283514Sarybchikextern int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
38283514Sarybchikextern int _thr_getcontext(mcontext_t *);
39283514Sarybchik
40283514Sarybchik#define	KSE_STACKSIZE		16384
41283514Sarybchik
42283514Sarybchik#define	THR_GETCONTEXT(ucp)	_thr_getcontext(&(ucp)->uc_mcontext)
43283514Sarybchik#define	THR_SETCONTEXT(ucp)	_thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
44283514Sarybchik
45283514Sarybchik#define	PER_KSE
46283514Sarybchik#undef	PER_THREAD
47283514Sarybchik
48283514Sarybchikstruct kse;
49283514Sarybchikstruct pthread;
50283514Sarybchikstruct tdv;
51283514Sarybchik
52283514Sarybchik/*
53283514Sarybchik * %gs points to a struct kcb.
54283514Sarybchik */
55293974Sarybchikstruct kcb {
56293974Sarybchik	struct tcb		*kcb_curtcb;
57293974Sarybchik	struct kcb		*kcb_self;	/* self reference */
58283514Sarybchik	int			kcb_ldt;
59283514Sarybchik	struct kse		*kcb_kse;
60283514Sarybchik	struct kse_mailbox	kcb_kmbx;
61283514Sarybchik};
62283514Sarybchik
63283514Sarybchikstruct tcb {
64283514Sarybchik	struct tdv		*tcb_tdv;
65283514Sarybchik	struct pthread		*tcb_thread;
66283514Sarybchik	void			*tcb_addr;	/* allocated tcb address */
67283514Sarybchik	void			*tcb_spare;	/* align tcb_tmbx to 16 bytes */
68283514Sarybchik	struct kse_thr_mailbox	tcb_tmbx;
69283514Sarybchik};
70293974Sarybchik
71293974Sarybchik/*
72293974Sarybchik * Evaluates to the byte offset of the per-kse variable name.
73283514Sarybchik */
74283514Sarybchik#define	__kcb_offset(name)	__offsetof(struct kcb, name)
75283514Sarybchik
76283514Sarybchik/*
77283514Sarybchik * Evaluates to the type of the per-kse variable name.
78293974Sarybchik */
79293974Sarybchik#define	__kcb_type(name)	__typeof(((struct kcb *)0)->name)
80293974Sarybchik
81283514Sarybchik/*
82283514Sarybchik * Evaluates to the value of the per-kse variable name.
83283514Sarybchik */
84283514Sarybchik#define	KCB_GET32(name) ({					\
85283514Sarybchik	__kcb_type(name) __result;				\
86283514Sarybchik								\
87283514Sarybchik	u_int __i;						\
88283514Sarybchik	__asm __volatile("movl %%gs:%1, %0"			\
89283514Sarybchik	    : "=r" (__i)					\
90283514Sarybchik	    : "m" (*(u_int *)(__kcb_offset(name))));		\
91283514Sarybchik	__result = *(__kcb_type(name) *)&__i;			\
92283514Sarybchik								\
93293974Sarybchik	__result;						\
94293974Sarybchik})
95293974Sarybchik
96283514Sarybchik/*
97283514Sarybchik * Sets the value of the per-kse variable name to value val.
98283514Sarybchik */
99293974Sarybchik#define	KCB_SET32(name, val) ({					\
100283514Sarybchik	__kcb_type(name) __val = (val);				\
101293974Sarybchik								\
102283514Sarybchik	u_int __i;						\
103283514Sarybchik	__i = *(u_int *)&__val;					\
104283514Sarybchik	__asm __volatile("movl %1,%%gs:%0"			\
105283514Sarybchik	    : "=m" (*(u_int *)(__kcb_offset(name)))		\
106283514Sarybchik	    : "r" (__i));					\
107293974Sarybchik})
108293974Sarybchik
109293974Sarybchikstatic __inline u_long
110283514Sarybchik__kcb_readandclear32(volatile u_long *addr)
111283514Sarybchik{
112283514Sarybchik	u_long result;
113283514Sarybchik
114283514Sarybchik	__asm __volatile (
115283514Sarybchik	    "	xorl	%0, %0;"
116283514Sarybchik	    "	xchgl	%%gs:%1, %0;"
117283514Sarybchik	    "# __kcb_readandclear32"
118283514Sarybchik	    : "=&r" (result)
119283514Sarybchik	    : "m" (*addr));
120283514Sarybchik	return (result);
121283514Sarybchik}
122283514Sarybchik
123283514Sarybchik#define	KCB_READANDCLEAR32(name) ({				\
124283514Sarybchik	__kcb_type(name) __result;				\
125283514Sarybchik								\
126283514Sarybchik	__result = (__kcb_type(name))				\
127283514Sarybchik	    __kcb_readandclear32((u_long *)__kcb_offset(name)); \
128283514Sarybchik	__result;						\
129293974Sarybchik})
130293974Sarybchik
131293974Sarybchik
132283514Sarybchik#define	_kcb_curkcb()		KCB_GET32(kcb_self)
133283514Sarybchik#define	_kcb_curtcb()		KCB_GET32(kcb_curtcb)
134283514Sarybchik#define	_kcb_curkse()		((struct kse *)KCB_GET32(kcb_kmbx.km_udata))
135283514Sarybchik#define	_kcb_get_tmbx()		KCB_GET32(kcb_kmbx.km_curthread)
136283514Sarybchik#define	_kcb_set_tmbx(value)	KCB_SET32(kcb_kmbx.km_curthread, (void *)value)
137293974Sarybchik#define	_kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread)
138293974Sarybchik
139283514Sarybchik
140283514Sarybchik/*
141283514Sarybchik * The constructors.
142293974Sarybchik */
143293974Sarybchikstruct tcb	*_tcb_ctor(struct pthread *);
144293974Sarybchikvoid		_tcb_dtor(struct tcb *tcb);
145293974Sarybchikstruct kcb	*_kcb_ctor(struct kse *);
146283514Sarybchikvoid		_kcb_dtor(struct kcb *);
147283514Sarybchik
148293939Sarybchik/* Called from the KSE to set its private data. */
149293939Sarybchikstatic __inline void
150293939Sarybchik_kcb_set(struct kcb *kcb)
151293939Sarybchik{
152293939Sarybchik	int val;
153293939Sarybchik
154293939Sarybchik	val = (kcb->kcb_ldt << 3) | 7;
155293958Sarybchik	__asm __volatile("movl %0, %%gs" : : "r" (val));
156293958Sarybchik}
157293958Sarybchik
158293958Sarybchik/* Get the current kcb. */
159293958Sarybchikstatic __inline struct kcb *
160293958Sarybchik_kcb_get(void)
161293958Sarybchik{
162283514Sarybchik	return (_kcb_curkcb());
163283514Sarybchik}
164283514Sarybchik
165283514Sarybchikstatic __inline struct kse_thr_mailbox *
166283514Sarybchik_kcb_critical_enter(void)
167283514Sarybchik{
168283514Sarybchik	struct kse_thr_mailbox *crit;
169283514Sarybchik
170283514Sarybchik	crit = _kcb_readandclear_tmbx();
171283514Sarybchik	return (crit);
172283514Sarybchik}
173283514Sarybchik
174283514Sarybchikstatic __inline void
175283514Sarybchik_kcb_critical_leave(struct kse_thr_mailbox *crit)
176283514Sarybchik{
177283514Sarybchik	_kcb_set_tmbx(crit);
178283514Sarybchik}
179283514Sarybchik
180283514Sarybchikstatic __inline int
181283514Sarybchik_kcb_in_critical(void)
182283514Sarybchik{
183293999Sarybchik	return (_kcb_get_tmbx() == NULL);
184283514Sarybchik}
185293999Sarybchik
186283514Sarybchikstatic __inline void
187283514Sarybchik_tcb_set(struct kcb *kcb, struct tcb *tcb)
188293999Sarybchik{
189283514Sarybchik	kcb->kcb_curtcb = tcb;
190293999Sarybchik}
191283514Sarybchik
192283514Sarybchikstatic __inline struct tcb *
193283514Sarybchik_tcb_get(void)
194283514Sarybchik{
195293974Sarybchik	return (_kcb_curtcb());
196293974Sarybchik}
197293974Sarybchik
198283514Sarybchikstatic __inline struct pthread *
199283514Sarybchik_get_curthread(void)
200283514Sarybchik{
201283514Sarybchik	struct tcb *tcb;
202283514Sarybchik
203293974Sarybchik	tcb = _kcb_curtcb();
204293974Sarybchik	if (tcb != NULL)
205283514Sarybchik		return (tcb->tcb_thread);
206283514Sarybchik	else
207283514Sarybchik		return (NULL);
208283514Sarybchik}
209283514Sarybchik
210283514Sarybchikstatic __inline struct kse *
211283514Sarybchik_get_curkse(void)
212283514Sarybchik{
213283514Sarybchik	return ((struct kse *)_kcb_curkse());
214283514Sarybchik}
215283514Sarybchik
216283514Sarybchikvoid	_i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
217283514Sarybchik    size_t stacksz);
218283514Sarybchik
219293974Sarybchikstatic __inline int
220293974Sarybchik_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
221293974Sarybchik{
222283514Sarybchik	int ret;
223283514Sarybchik
224283514Sarybchik	ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext);
225283514Sarybchik	if (ret == 0) {
226283514Sarybchik		_i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
227283514Sarybchik		    kcb->kcb_kmbx.km_stack.ss_sp,
228283514Sarybchik		    kcb->kcb_kmbx.km_stack.ss_size);
229283514Sarybchik		/* We should not reach here. */
230283514Sarybchik		return (-1);
231283514Sarybchik	}
232283514Sarybchik	else if (ret < 0)
233283514Sarybchik		return (-1);
234283514Sarybchik	return (0);
235283514Sarybchik}
236283514Sarybchik
237283514Sarybchikstatic __inline int
238283514Sarybchik_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
239283514Sarybchik{
240283514Sarybchik	if ((kcb == NULL) || (tcb == NULL))
241283514Sarybchik		return (-1);
242283514Sarybchik	kcb->kcb_curtcb = tcb;
243283514Sarybchik	if (setmbox != 0)
244283514Sarybchik		_thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
245283514Sarybchik		    (intptr_t)&tcb->tcb_tmbx,
246283514Sarybchik		    (intptr_t *)&kcb->kcb_kmbx.km_curthread);
247283514Sarybchik	else
248283514Sarybchik		_thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext, 0, NULL);
249283514Sarybchik	/* We should not reach here. */
250283514Sarybchik	return (-1);
251283514Sarybchik}
252283514Sarybchik
253283514Sarybchik#endif
254283514Sarybchik