pthread_md.h revision 118519
1116708Smarcel/*
2116708Smarcel * Copyright (c) 2003 Marcel Moolenaar
3116708Smarcel * All rights reserved.
4116708Smarcel *
5116708Smarcel * Redistribution and use in source and binary forms, with or without
6116708Smarcel * modification, are permitted provided that the following conditions
7116708Smarcel * are met:
8116708Smarcel *
9116708Smarcel * 1. Redistributions of source code must retain the above copyright
10116708Smarcel *    notice, this list of conditions and the following disclaimer.
11116708Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12116708Smarcel *    notice, this list of conditions and the following disclaimer in the
13116708Smarcel *    documentation and/or other materials provided with the distribution.
14116708Smarcel *
15116708Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16116708Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17116708Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18116708Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19116708Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20116708Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21116708Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22116708Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23116708Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24116708Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25116708Smarcel *
26116708Smarcel * $FreeBSD: head/lib/libkse/arch/ia64/include/pthread_md.h 118519 2003-08-06 06:12:54Z deischen $
27116708Smarcel */
28116708Smarcel
29116708Smarcel#ifndef _PTHREAD_MD_H_
30116708Smarcel#define	_PTHREAD_MD_H_
31116708Smarcel
32118510Sdeischen#include <sys/kse.h>
33118518Smarcel#include <stddef.h>
34118510Sdeischen#include <ucontext.h>
35118510Sdeischen
36118507Smarcel#define	THR_GETCONTEXT(ucp)	_ia64_save_context(&(ucp)->uc_mcontext)
37118507Smarcel#define	THR_SETCONTEXT(ucp)	_ia64_restore_context(&(ucp)->uc_mcontext, \
38118507Smarcel				    0, NULL)
39116708Smarcel
40118510Sdeischen#define	PER_THREAD
41116708Smarcel
42118510Sdeischenstruct kcb;
43118510Sdeischenstruct kse;
44118510Sdeischenstruct pthread;
45118510Sdeischenstruct tcb;
46118510Sdeischenstruct tdv;	/* We don't know what this is yet? */
47118510Sdeischen
48118510Sdeischen/*
49118513Smarcel * tp points to one of these. We define the static TLS as an array
50118513Smarcel * of long double to enforce 16-byte alignment of the TLS memory,
51118513Smarcel * struct ia64_tp, struct tcb and also struct kcb. Both static and
52118513Smarcel * dynamic allocation of any of these structures will result in a
53118513Smarcel * valid, well-aligned thread pointer.
54118510Sdeischen */
55118510Sdeischenstruct ia64_tp {
56118510Sdeischen	struct tdv		*tp_tdv;	/* dynamic TLS */
57118518Smarcel	uint64_t		_reserved_;
58118513Smarcel	long double		tp_tls[0];	/* static TLS */
59116771Smarcel};
60116771Smarcel
61118510Sdeischenstruct tcb {
62118510Sdeischen	struct kse_thr_mailbox	tcb_tmbx;
63118510Sdeischen	struct pthread		*tcb_thread;
64118510Sdeischen	struct kcb		*tcb_curkcb;
65118510Sdeischen	long			tcb_isfake;
66118510Sdeischen	struct ia64_tp		tcb_tp;
67118510Sdeischen};
68118510Sdeischen
69118510Sdeischenstruct kcb {
70118510Sdeischen	struct kse_mailbox	kcb_kmbx;
71118510Sdeischen	struct tcb		kcb_faketcb;
72118510Sdeischen	struct tcb		*kcb_curtcb;
73118510Sdeischen	struct kse		*kcb_kse;
74118510Sdeischen};
75118510Sdeischen
76118510Sdeischenregister struct ia64_tp *_tp __asm("%r13");
77118510Sdeischen
78118518Smarcel#define	_tcb	((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
79118518Smarcel
80118510Sdeischen/*
81118510Sdeischen * The kcb and tcb constructors.
82118510Sdeischen */
83118510Sdeischenstruct tcb	*_tcb_ctor(struct pthread *);
84118510Sdeischenvoid		_tcb_dtor(struct tcb *);
85118510Sdeischenstruct kcb	*_kcb_ctor(struct kse *kse);
86118510Sdeischenvoid		_kcb_dtor(struct kcb *);
87118510Sdeischen
88118510Sdeischen/* Called from the KSE to set its private data. */
89118510Sdeischenstatic __inline void
90118510Sdeischen_kcb_set(struct kcb *kcb)
91118510Sdeischen{
92118510Sdeischen	/* There is no thread yet; use the fake tcb. */
93118510Sdeischen	_tp = &kcb->kcb_faketcb.tcb_tp;
94118510Sdeischen}
95118510Sdeischen
96118510Sdeischen/*
97118510Sdeischen * Get the current kcb.
98118510Sdeischen *
99118510Sdeischen * This can only be called while in a critical region; don't
100118510Sdeischen * worry about having the kcb changed out from under us.
101118510Sdeischen */
102118510Sdeischenstatic __inline struct kcb *
103118510Sdeischen_kcb_get(void)
104118510Sdeischen{
105118518Smarcel	return (_tcb->tcb_curkcb);
106118510Sdeischen}
107118510Sdeischen
108118510Sdeischen/*
109118510Sdeischen * Enter a critical region.
110118510Sdeischen *
111118510Sdeischen * Read and clear km_curthread in the kse mailbox.
112118510Sdeischen */
113118510Sdeischenstatic __inline struct kse_thr_mailbox *
114118510Sdeischen_kcb_critical_enter(void)
115118510Sdeischen{
116118510Sdeischen	struct kse_thr_mailbox *crit;
117118510Sdeischen	uint32_t flags;
118118510Sdeischen
119118518Smarcel	if (_tcb->tcb_isfake != 0) {
120118510Sdeischen		/*
121118510Sdeischen		 * We already are in a critical region since
122118510Sdeischen		 * there is no current thread.
123118510Sdeischen		 */
124118510Sdeischen		crit = NULL;
125118510Sdeischen	} else {
126118518Smarcel		flags = _tcb->tcb_tmbx.tm_flags;
127118518Smarcel		_tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
128118518Smarcel		crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
129118518Smarcel		_tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
130118518Smarcel		_tcb->tcb_tmbx.tm_flags = flags;
131118510Sdeischen	}
132118510Sdeischen	return (crit);
133118510Sdeischen}
134118510Sdeischen
135118510Sdeischenstatic __inline void
136118510Sdeischen_kcb_critical_leave(struct kse_thr_mailbox *crit)
137118510Sdeischen{
138118510Sdeischen	/* No need to do anything if this is a fake tcb. */
139118518Smarcel	if (_tcb->tcb_isfake == 0)
140118518Smarcel		_tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
141118510Sdeischen}
142118510Sdeischen
143118510Sdeischenstatic __inline int
144118510Sdeischen_kcb_in_critical(void)
145118510Sdeischen{
146118510Sdeischen	uint32_t flags;
147118510Sdeischen	int ret;
148118510Sdeischen
149118518Smarcel	if (_tcb->tcb_isfake != 0) {
150118510Sdeischen		/*
151118510Sdeischen		 * We are in a critical region since there is no
152118510Sdeischen		 * current thread.
153118510Sdeischen		 */
154118510Sdeischen		ret = 1;
155118510Sdeischen	} else {
156118518Smarcel		flags = _tcb->tcb_tmbx.tm_flags;
157118518Smarcel		_tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
158118518Smarcel		ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
159118518Smarcel		_tcb->tcb_tmbx.tm_flags = flags;
160118510Sdeischen	}
161118510Sdeischen	return (ret);
162118510Sdeischen}
163118510Sdeischen
164118510Sdeischenstatic __inline void
165118510Sdeischen_tcb_set(struct kcb *kcb, struct tcb *tcb)
166118510Sdeischen{
167118518Smarcel	if (tcb == NULL)
168118518Smarcel		tcb = &kcb->kcb_faketcb;
169118518Smarcel	kcb->kcb_curtcb = tcb;
170118518Smarcel	tcb->tcb_curkcb = kcb;
171118518Smarcel	_tp = &tcb->tcb_tp;
172118510Sdeischen}
173118510Sdeischen
174118510Sdeischenstatic __inline struct tcb *
175118510Sdeischen_tcb_get(void)
176118510Sdeischen{
177118518Smarcel	return (_tcb);
178118510Sdeischen}
179118510Sdeischen
180118510Sdeischenstatic __inline struct pthread *
181118510Sdeischen_get_curthread(void)
182118510Sdeischen{
183118518Smarcel	return (_tcb->tcb_thread);
184118510Sdeischen}
185118510Sdeischen
186118510Sdeischen/*
187118510Sdeischen * Get the current kse.
188118510Sdeischen *
189118519Sdeischen * Like _kcb_get(), this can only be called while in a critical region.
190118510Sdeischen */
191118510Sdeischenstatic __inline struct kse *
192118510Sdeischen_get_curkse(void)
193118510Sdeischen{
194118518Smarcel	return (_tcb->tcb_curkcb->kcb_kse);
195118510Sdeischen}
196118510Sdeischen
197116866Smarcelvoid _ia64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
198116866Smarcel    size_t stacksz);
199116866Smarcelint _ia64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc);
200116866Smarcelint _ia64_save_context(mcontext_t *mc);
201116866Smarcel
202116866Smarcelstatic __inline int
203118510Sdeischen_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
204116866Smarcel{
205118510Sdeischen	if (_ia64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
206118510Sdeischen		/* Make the fake tcb the current thread. */
207118510Sdeischen		kcb->kcb_curtcb = &kcb->kcb_faketcb;
208118510Sdeischen		_tp = &kcb->kcb_faketcb.tcb_tp;
209118510Sdeischen		_ia64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx,
210118510Sdeischen		    kcb->kcb_kmbx.km_stack.ss_sp,
211118510Sdeischen		    kcb->kcb_kmbx.km_stack.ss_size);
212116866Smarcel		/* We should not reach here. */
213116866Smarcel		return (-1);
214116866Smarcel	}
215116866Smarcel	return (0);
216116866Smarcel}
217116866Smarcel
218116866Smarcelstatic __inline int
219118510Sdeischen_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
220116866Smarcel{
221118518Smarcel	_tcb_set(kcb, tcb);
222118510Sdeischen	if (setmbox != 0)
223118510Sdeischen		_ia64_restore_context(&tcb->tcb_tmbx.tm_context.uc_mcontext,
224118510Sdeischen		    (intptr_t)&tcb->tcb_tmbx,
225118510Sdeischen		    (intptr_t *)&kcb->kcb_kmbx.km_curthread);
226118510Sdeischen	else
227118510Sdeischen		_ia64_restore_context(&tcb->tcb_tmbx.tm_context.uc_mcontext,
228118510Sdeischen		    0, NULL);
229116866Smarcel	/* We should not reach here. */
230116866Smarcel	return (-1);
231116866Smarcel}
232116866Smarcel
233116708Smarcel#endif /* _PTHREAD_MD_H_ */
234