pthread_md.h revision 132125
1/*-
2 * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>.
3 * Copyright (c) 2003 Marcel Moolenaar
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * $FreeBSD: head/lib/libkse/arch/arm/include/pthread_md.h 132125 2004-07-13 22:54:23Z davidxu $
28 */
29
30/*
31 * Machine-dependent thread prototypes/definitions for the thread kernel.
32 */
33#ifndef _PTHREAD_MD_H_
34#define	_PTHREAD_MD_H_
35
36#include <sys/kse.h>
37#include <stddef.h>
38#include <ucontext.h>
39
40#define	KSE_STACKSIZE		16384
41
42int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
43int _thr_getcontext(mcontext_t *);
44
45#define	THR_GETCONTEXT(ucp)	_thr_getcontext(&(ucp)->uc_mcontext)
46#define	THR_SETCONTEXT(ucp)	_thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
47
48#define	PER_THREAD
49
50struct kcb;
51struct kse;
52struct pthread;
53struct tcb;
54struct tdv;	/* We don't know what this is yet? */
55
56
57/*
58 * %r6 points to one of these. We define the static TLS as an array
59 * of long double to enforce 16-byte alignment of the TLS memory.
60 *
61 * XXX - Both static and dynamic allocation of any of these structures
62 *       will result in a valid, well-aligned thread pointer???
63 */
64struct arm_tp {
65	struct tdv		*tp_tdv;	/* dynamic TLS */
66	uint32_t		_reserved_;
67	long double		tp_tls[0];	/* static TLS */
68};
69
70struct tcb {
71	struct pthread		*tcb_thread;
72	void			*tcb_addr;	/* allocated tcb address */
73	struct kcb		*tcb_curkcb;
74	uint32_t		tcb_isfake;
75	uint32_t		tcb_spare[4];
76	struct kse_thr_mailbox	tcb_tmbx;	/* needs 32-byte alignment */
77	struct arm_tp		tcb_tp;
78} __aligned(32);
79
80struct kcb {
81	struct kse_mailbox	kcb_kmbx;
82	struct tcb		kcb_faketcb;
83	struct tcb		*kcb_curtcb;
84	struct kse		*kcb_kse;
85};
86
87register struct arm_tp *_tp __asm("%r6");
88
89#define	_tcb	((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
90
91/*
92 * The kcb and tcb constructors.
93 */
94struct tcb	*_tcb_ctor(struct pthread *);
95void		_tcb_dtor(struct tcb *);
96struct kcb	*_kcb_ctor(struct kse *kse);
97void		_kcb_dtor(struct kcb *);
98
99/* Called from the KSE to set its private data. */
100static __inline void
101_kcb_set(struct kcb *kcb)
102{
103	/* There is no thread yet; use the fake tcb. */
104	_tp = &kcb->kcb_faketcb.tcb_tp;
105}
106
107/*
108 * Get the current kcb.
109 *
110 * This can only be called while in a critical region; don't
111 * worry about having the kcb changed out from under us.
112 */
113static __inline struct kcb *
114_kcb_get(void)
115{
116	return (_tcb->tcb_curkcb);
117}
118
119/*
120 * Enter a critical region.
121 *
122 * Read and clear km_curthread in the kse mailbox.
123 */
124static __inline struct kse_thr_mailbox *
125_kcb_critical_enter(void)
126{
127	struct kse_thr_mailbox *crit;
128	uint32_t flags;
129
130	if (_tcb->tcb_isfake != 0) {
131		/*
132		 * We already are in a critical region since
133		 * there is no current thread.
134		 */
135		crit = NULL;
136	} else {
137		flags = _tcb->tcb_tmbx.tm_flags;
138		_tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
139		crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
140		_tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
141		_tcb->tcb_tmbx.tm_flags = flags;
142	}
143	return (crit);
144}
145
146static __inline void
147_kcb_critical_leave(struct kse_thr_mailbox *crit)
148{
149	/* No need to do anything if this is a fake tcb. */
150	if (_tcb->tcb_isfake == 0)
151		_tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
152}
153
154static __inline int
155_kcb_in_critical(void)
156{
157	uint32_t flags;
158	int ret;
159
160	if (_tcb->tcb_isfake != 0) {
161		/*
162		 * We are in a critical region since there is no
163		 * current thread.
164		 */
165		ret = 1;
166	} else {
167		flags = _tcb->tcb_tmbx.tm_flags;
168		_tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
169		ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
170		_tcb->tcb_tmbx.tm_flags = flags;
171	}
172	return (ret);
173}
174
175static __inline void
176_tcb_set(struct kcb *kcb, struct tcb *tcb)
177{
178	if (tcb == NULL)
179		tcb = &kcb->kcb_faketcb;
180	kcb->kcb_curtcb = tcb;
181	tcb->tcb_curkcb = kcb;
182	_tp = &tcb->tcb_tp;
183}
184
185static __inline struct tcb *
186_tcb_get(void)
187{
188	return (_tcb);
189}
190
191static __inline struct pthread *
192_get_curthread(void)
193{
194	return (_tcb->tcb_thread);
195}
196
197/*
198 * Get the current kse.
199 *
200 * Like _kcb_get(), this can only be called while in a critical region.
201 */
202static __inline struct kse *
203_get_curkse(void)
204{
205	return (_tcb->tcb_curkcb->kcb_kse);
206}
207
208void _arm_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
209    size_t stacksz);
210
211static __inline int
212_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
213{
214	if (_thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
215		/* Make the fake tcb the current thread. */
216		kcb->kcb_curtcb = &kcb->kcb_faketcb;
217		_tp = &kcb->kcb_faketcb.tcb_tp;
218		_arm_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx,
219		    kcb->kcb_kmbx.km_stack.ss_sp,
220		    kcb->kcb_kmbx.km_stack.ss_size);
221		/* We should not reach here. */
222		return (-1);
223	}
224	return (0);
225}
226
227static __inline int
228_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
229{
230	extern int _libkse_debug;
231	mcontext_t *mc;
232
233	_tcb_set(kcb, tcb);
234	mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
235	if (_libkse_debug == 0) {
236		if (setmbox)
237			_thr_setcontext(mc, (intptr_t)&tcb->tcb_tmbx,
238				(intptr_t *)&kcb->kcb_kmbx.km_curthread);
239		else
240			_thr_setcontext(mc, 0, NULL);
241	} else {
242		if (setmbox)
243			kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
244		else
245			kse_switchin(&tcb->tcb_tmbx, 0);
246	}
247
248	/* We should not reach here. */
249	return (-1);
250}
251
252#endif /* _PTHREAD_MD_H_ */
253