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