xref: /trueos/lib/libkse/arch/sparc64/include/pthread_md.h (revision f1ac56b04d023087e7771958a39880cb905293e9)
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$
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 #define	DTV_OFFSET		offsetof(struct tcb, tcb_tp.tp_tdv)
42 
43 int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
44 int _thr_getcontext(mcontext_t *);
45 
46 #define	THR_GETCONTEXT(ucp)	_thr_getcontext(&(ucp)->uc_mcontext)
47 #define	THR_SETCONTEXT(ucp)	_thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
48 
49 #define	PER_THREAD
50 
51 struct kcb;
52 struct kse;
53 struct pthread;
54 struct tcb;
55 struct tdv;	/* We don't know what this is yet? */
56 
57 
58 /*
59  * %g6 points to one of these. We define the static TLS as an array
60  * of long double to enforce 16-byte alignment of the TLS memory.
61  *
62  * XXX - Both static and dynamic allocation of any of these structures
63  *       will result in a valid, well-aligned thread pointer???
64  */
65 struct sparc64_tp {
66 	struct tdv		*tp_tdv;	/* dynamic TLS */
67 	uint64_t		_reserved_;
68 	long double		tp_tls[0];	/* static TLS */
69 };
70 
71 struct tcb {
72 	struct pthread		*tcb_thread;
73 	void			*tcb_addr;	/* allocated tcb address */
74 	struct kcb		*tcb_curkcb;
75 	uint64_t		tcb_isfake;
76 	uint64_t		tcb_spare[4];
77 	struct kse_thr_mailbox	tcb_tmbx;	/* needs 64-byte alignment */
78 	struct sparc64_tp	tcb_tp;
79 } __aligned(64);
80 
81 struct kcb {
82 	struct kse_mailbox	kcb_kmbx;
83 	struct tcb		kcb_faketcb;
84 	struct tcb		*kcb_curtcb;
85 	struct kse		*kcb_kse;
86 };
87 
88 register struct sparc64_tp *_tp __asm("%g6");
89 
90 #define	_tcb	((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
91 
92 /*
93  * The kcb and tcb constructors.
94  */
95 struct tcb	*_tcb_ctor(struct pthread *, int);
96 void		_tcb_dtor(struct tcb *);
97 struct kcb	*_kcb_ctor(struct kse *kse);
98 void		_kcb_dtor(struct kcb *);
99 
100 /* Called from the KSE to set its private data. */
101 static __inline void
_kcb_set(struct kcb * kcb)102 _kcb_set(struct kcb *kcb)
103 {
104 	/* There is no thread yet; use the fake tcb. */
105 	_tp = &kcb->kcb_faketcb.tcb_tp;
106 }
107 
108 /*
109  * Get the current kcb.
110  *
111  * This can only be called while in a critical region; don't
112  * worry about having the kcb changed out from under us.
113  */
114 static __inline struct kcb *
_kcb_get(void)115 _kcb_get(void)
116 {
117 	return (_tcb->tcb_curkcb);
118 }
119 
120 /*
121  * Enter a critical region.
122  *
123  * Read and clear km_curthread in the kse mailbox.
124  */
125 static __inline struct kse_thr_mailbox *
_kcb_critical_enter(void)126 _kcb_critical_enter(void)
127 {
128 	struct kse_thr_mailbox *crit;
129 	uint32_t flags;
130 
131 	if (_tcb->tcb_isfake != 0) {
132 		/*
133 		 * We already are in a critical region since
134 		 * there is no current thread.
135 		 */
136 		crit = NULL;
137 	} else {
138 		flags = _tcb->tcb_tmbx.tm_flags;
139 		_tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
140 		crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
141 		_tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
142 		_tcb->tcb_tmbx.tm_flags = flags;
143 	}
144 	return (crit);
145 }
146 
147 static __inline void
_kcb_critical_leave(struct kse_thr_mailbox * crit)148 _kcb_critical_leave(struct kse_thr_mailbox *crit)
149 {
150 	/* No need to do anything if this is a fake tcb. */
151 	if (_tcb->tcb_isfake == 0)
152 		_tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
153 }
154 
155 static __inline int
_kcb_in_critical(void)156 _kcb_in_critical(void)
157 {
158 	uint32_t flags;
159 	int ret;
160 
161 	if (_tcb->tcb_isfake != 0) {
162 		/*
163 		 * We are in a critical region since there is no
164 		 * current thread.
165 		 */
166 		ret = 1;
167 	} else {
168 		flags = _tcb->tcb_tmbx.tm_flags;
169 		_tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
170 		ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
171 		_tcb->tcb_tmbx.tm_flags = flags;
172 	}
173 	return (ret);
174 }
175 
176 static __inline void
_tcb_set(struct kcb * kcb,struct tcb * tcb)177 _tcb_set(struct kcb *kcb, struct tcb *tcb)
178 {
179 	if (tcb == NULL)
180 		tcb = &kcb->kcb_faketcb;
181 	kcb->kcb_curtcb = tcb;
182 	tcb->tcb_curkcb = kcb;
183 	_tp = &tcb->tcb_tp;
184 }
185 
186 static __inline struct tcb *
_tcb_get(void)187 _tcb_get(void)
188 {
189 	return (_tcb);
190 }
191 
192 static __inline struct pthread *
_get_curthread(void)193 _get_curthread(void)
194 {
195 	return (_tcb->tcb_thread);
196 }
197 
198 /*
199  * Get the current kse.
200  *
201  * Like _kcb_get(), this can only be called while in a critical region.
202  */
203 static __inline struct kse *
_get_curkse(void)204 _get_curkse(void)
205 {
206 	return (_tcb->tcb_curkcb->kcb_kse);
207 }
208 
209 void _sparc64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
210     size_t stacksz);
211 
212 static __inline int
_thread_enter_uts(struct tcb * tcb,struct kcb * kcb)213 _thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
214 {
215 	if (_thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
216 		/* Make the fake tcb the current thread. */
217 		kcb->kcb_curtcb = &kcb->kcb_faketcb;
218 		_tp = &kcb->kcb_faketcb.tcb_tp;
219 		_sparc64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx,
220 		    kcb->kcb_kmbx.km_stack.ss_sp,
221 		    kcb->kcb_kmbx.km_stack.ss_size);
222 		/* We should not reach here. */
223 		return (-1);
224 	}
225 	return (0);
226 }
227 
228 static __inline int
_thread_switch(struct kcb * kcb,struct tcb * tcb,int setmbox)229 _thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
230 {
231 	extern int _libkse_debug;
232 	mcontext_t *mc;
233 
234 	_tcb_set(kcb, tcb);
235 	mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
236 	if (_libkse_debug == 0) {
237 		tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
238 		if (setmbox)
239 			_thr_setcontext(mc, (intptr_t)&tcb->tcb_tmbx,
240 			    (intptr_t *)(void *)&kcb->kcb_kmbx.km_curthread);
241 		else
242 			_thr_setcontext(mc, 0, NULL);
243 	} else {
244 		if (setmbox)
245 			kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
246 		else
247 			kse_switchin(&tcb->tcb_tmbx, 0);
248 	}
249 
250 	/* We should not reach here. */
251 	return (-1);
252 }
253 
254 #endif /* _PTHREAD_MD_H_ */
255