pthread_md.h revision 120263
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 120263 2003-09-19 23:28:13Z marcel $
27113656Sdeischen */
28113656Sdeischen/*
29113656Sdeischen * Machine-dependent thread prototypes/definitions for the thread kernel.
30113656Sdeischen */
31113656Sdeischen#ifndef _PTHREAD_MD_H_
32113656Sdeischen#define	_PTHREAD_MD_H_
33113656Sdeischen
34118277Sdeischen#include <sys/kse.h>
35113656Sdeischen#include <ucontext.h>
36113656Sdeischen
37118277Sdeischenextern int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
38118277Sdeischenextern int _thr_getcontext(mcontext_t *);
39113656Sdeischen
40120263Smarcel#define	KSE_STACKSIZE		16384
41120263Smarcel
42118510Sdeischen#define	THR_GETCONTEXT(ucp)	_thr_getcontext(&(ucp)->uc_mcontext)
43118510Sdeischen#define	THR_SETCONTEXT(ucp)	_thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
44113656Sdeischen
45118510Sdeischen#define	PER_KSE
46118510Sdeischen#undef	PER_THREAD
47116771Smarcel
48118510Sdeischenstruct kse;
49118510Sdeischenstruct pthread;
50118510Sdeischenstruct tdv;
51118510Sdeischen
52116771Smarcel/*
53118510Sdeischen * %gs points to a struct kcb.
54116771Smarcel */
55118510Sdeischenstruct kcb {
56118510Sdeischen	struct tcb		*kcb_curtcb;
57118510Sdeischen	struct kcb		*kcb_self;	/* self reference */
58118510Sdeischen	int			kcb_ldt;
59118510Sdeischen	struct kse		*kcb_kse;
60118510Sdeischen	struct kse_mailbox	kcb_kmbx;
61116771Smarcel};
62116771Smarcel
63118510Sdeischenstruct tcb {
64118510Sdeischen	struct tdv		*tcb_tdv;
65118510Sdeischen	struct pthread		*tcb_thread;
66118510Sdeischen	void			*tcb_addr;	/* allocated tcb address */
67118510Sdeischen	void			*tcb_spare;	/* align tcb_tmbx to 16 bytes */
68118510Sdeischen	struct kse_thr_mailbox	tcb_tmbx;
69118510Sdeischen};
70118277Sdeischen
71118510Sdeischen/*
72118510Sdeischen * Evaluates to the byte offset of the per-kse variable name.
73118510Sdeischen */
74118510Sdeischen#define	__kcb_offset(name)	__offsetof(struct kcb, name)
75118510Sdeischen
76118510Sdeischen/*
77118510Sdeischen * Evaluates to the type of the per-kse variable name.
78118510Sdeischen */
79118510Sdeischen#define	__kcb_type(name)	__typeof(((struct kcb *)0)->name)
80118510Sdeischen
81118510Sdeischen/*
82118510Sdeischen * Evaluates to the value of the per-kse variable name.
83118510Sdeischen */
84118510Sdeischen#define	KCB_GET32(name) ({					\
85118510Sdeischen	__kcb_type(name) __result;				\
86118510Sdeischen								\
87118510Sdeischen	u_int __i;						\
88118510Sdeischen	__asm __volatile("movl %%gs:%1, %0"			\
89118510Sdeischen	    : "=r" (__i)					\
90118510Sdeischen	    : "m" (*(u_int *)(__kcb_offset(name))));		\
91118510Sdeischen	__result = *(__kcb_type(name) *)&__i;			\
92118510Sdeischen								\
93118510Sdeischen	__result;						\
94118510Sdeischen})
95118510Sdeischen
96118510Sdeischen/*
97118510Sdeischen * Sets the value of the per-kse variable name to value val.
98118510Sdeischen */
99118510Sdeischen#define	KCB_SET32(name, val) ({					\
100118510Sdeischen	__kcb_type(name) __val = (val);				\
101118510Sdeischen								\
102118510Sdeischen	u_int __i;						\
103118510Sdeischen	__i = *(u_int *)&__val;					\
104118510Sdeischen	__asm __volatile("movl %1,%%gs:%0"			\
105118510Sdeischen	    : "=m" (*(u_int *)(__kcb_offset(name)))		\
106118510Sdeischen	    : "r" (__i));					\
107118510Sdeischen})
108118510Sdeischen
109118510Sdeischenstatic __inline u_long
110118510Sdeischen__kcb_readandclear32(volatile u_long *addr)
111118510Sdeischen{
112118510Sdeischen	u_long result;
113118510Sdeischen
114118510Sdeischen	__asm __volatile (
115118510Sdeischen	    "	xorl	%0, %0;"
116118510Sdeischen	    "	xchgl	%%gs:%1, %0;"
117118510Sdeischen	    "# __kcb_readandclear32"
118118510Sdeischen	    : "=&r" (result)
119118510Sdeischen	    : "m" (*addr));
120118510Sdeischen	return (result);
121118510Sdeischen}
122118510Sdeischen
123118510Sdeischen#define	KCB_READANDCLEAR32(name) ({				\
124118510Sdeischen	__kcb_type(name) __result;				\
125118510Sdeischen								\
126118510Sdeischen	__result = (__kcb_type(name))				\
127118510Sdeischen	    __kcb_readandclear32((u_long *)__kcb_offset(name)); \
128118510Sdeischen	__result;						\
129118510Sdeischen})
130118510Sdeischen
131118510Sdeischen
132118510Sdeischen#define	_kcb_curkcb()		KCB_GET32(kcb_self)
133118510Sdeischen#define	_kcb_curtcb()		KCB_GET32(kcb_curtcb)
134118510Sdeischen#define	_kcb_curkse()		((struct kse *)KCB_GET32(kcb_kmbx.km_udata))
135118510Sdeischen#define	_kcb_get_tmbx()		KCB_GET32(kcb_kmbx.km_curthread)
136118510Sdeischen#define	_kcb_set_tmbx(value)	KCB_SET32(kcb_kmbx.km_curthread, (void *)value)
137118510Sdeischen#define	_kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread)
138118510Sdeischen
139118510Sdeischen
140118510Sdeischen/*
141118510Sdeischen * The constructors.
142118510Sdeischen */
143118510Sdeischenstruct tcb	*_tcb_ctor(struct pthread *);
144118510Sdeischenvoid		_tcb_dtor(struct tcb *tcb);
145118510Sdeischenstruct kcb	*_kcb_ctor(struct kse *);
146118510Sdeischenvoid		_kcb_dtor(struct kcb *);
147118510Sdeischen
148118510Sdeischen/* Called from the KSE to set its private data. */
149118510Sdeischenstatic __inline void
150118510Sdeischen_kcb_set(struct kcb *kcb)
151118510Sdeischen{
152118510Sdeischen	int val;
153118510Sdeischen
154118510Sdeischen	val = (kcb->kcb_ldt << 3) | 7;
155118510Sdeischen	__asm __volatile("movl %0, %%gs" : : "r" (val));
156118510Sdeischen}
157118510Sdeischen
158118510Sdeischen/* Get the current kcb. */
159118510Sdeischenstatic __inline struct kcb *
160118510Sdeischen_kcb_get(void)
161118510Sdeischen{
162118510Sdeischen	return (_kcb_curkcb());
163118510Sdeischen}
164118510Sdeischen
165118510Sdeischenstatic __inline struct kse_thr_mailbox *
166118510Sdeischen_kcb_critical_enter(void)
167118510Sdeischen{
168118510Sdeischen	struct kse_thr_mailbox *crit;
169118510Sdeischen
170118510Sdeischen	crit = _kcb_readandclear_tmbx();
171118510Sdeischen	return (crit);
172118510Sdeischen}
173118510Sdeischen
174118510Sdeischenstatic __inline void
175118510Sdeischen_kcb_critical_leave(struct kse_thr_mailbox *crit)
176118510Sdeischen{
177118510Sdeischen	_kcb_set_tmbx(crit);
178118510Sdeischen}
179118510Sdeischen
180118277Sdeischenstatic __inline int
181118510Sdeischen_kcb_in_critical(void)
182118277Sdeischen{
183118510Sdeischen	return (_kcb_get_tmbx() == NULL);
184118510Sdeischen}
185118510Sdeischen
186118510Sdeischenstatic __inline void
187118510Sdeischen_tcb_set(struct kcb *kcb, struct tcb *tcb)
188118510Sdeischen{
189118510Sdeischen	kcb->kcb_curtcb = tcb;
190118510Sdeischen}
191118510Sdeischen
192118510Sdeischenstatic __inline struct tcb *
193118510Sdeischen_tcb_get(void)
194118510Sdeischen{
195118510Sdeischen	return (_kcb_curtcb());
196118510Sdeischen}
197118510Sdeischen
198118510Sdeischenstatic __inline struct pthread *
199118510Sdeischen_get_curthread(void)
200118510Sdeischen{
201118510Sdeischen	struct tcb *tcb;
202118510Sdeischen
203118510Sdeischen	tcb = _kcb_curtcb();
204118510Sdeischen	if (tcb != NULL)
205118510Sdeischen		return (tcb->tcb_thread);
206118510Sdeischen	else
207118510Sdeischen		return (NULL);
208118510Sdeischen}
209118510Sdeischen
210118510Sdeischenstatic __inline struct kse *
211118510Sdeischen_get_curkse(void)
212118510Sdeischen{
213118510Sdeischen	return ((struct kse *)_kcb_curkse());
214118510Sdeischen}
215118510Sdeischen
216118510Sdeischenvoid	_i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
217118510Sdeischen    size_t stacksz);
218118510Sdeischen
219118510Sdeischenstatic __inline int
220118510Sdeischen_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
221118510Sdeischen{
222118277Sdeischen	int ret;
223118277Sdeischen
224118510Sdeischen	ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext);
225118277Sdeischen	if (ret == 0) {
226118510Sdeischen		_i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
227118510Sdeischen		    kcb->kcb_kmbx.km_stack.ss_sp,
228118510Sdeischen		    kcb->kcb_kmbx.km_stack.ss_size);
229118277Sdeischen		/* We should not reach here. */
230118277Sdeischen		return (-1);
231118277Sdeischen	}
232118277Sdeischen	else if (ret < 0)
233118277Sdeischen		return (-1);
234118277Sdeischen	return (0);
235118277Sdeischen}
236118277Sdeischen
237118277Sdeischenstatic __inline int
238118510Sdeischen_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
239118277Sdeischen{
240118510Sdeischen	if ((kcb == NULL) || (tcb == NULL))
241118510Sdeischen		return (-1);
242118510Sdeischen	kcb->kcb_curtcb = tcb;
243118510Sdeischen	if (setmbox != 0)
244118510Sdeischen		_thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
245118510Sdeischen		    (intptr_t)&tcb->tcb_tmbx,
246118510Sdeischen		    (intptr_t *)&kcb->kcb_kmbx.km_curthread);
247118510Sdeischen	else
248118510Sdeischen		_thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext, 0, NULL);
249118277Sdeischen	/* We should not reach here. */
250118277Sdeischen	return (-1);
251118277Sdeischen}
252118277Sdeischen
253113656Sdeischen#endif
254