pthread_md.h revision 161828
1/* 2 * Copyright 2004 by Peter Grehan. 3 * Copyright 2006 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 * 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 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: head/lib/libkse/arch/powerpc/include/pthread_md.h 161828 2006-09-01 17:52:13Z marcel $ 30 */ 31 32/* 33 * Machine-dependent thread prototypes/definitions for the thread kernel. 34 */ 35#ifndef _PTHREAD_MD_H_ 36#define _PTHREAD_MD_H_ 37 38#include <sys/kse.h> 39#include <stddef.h> 40#include <ucontext.h> 41 42extern void _ppc32_enter_uts(struct kse_mailbox *, kse_func_t, void *, size_t); 43extern int _ppc32_setcontext(mcontext_t *, intptr_t, intptr_t *); 44extern int _ppc32_getcontext(mcontext_t *); 45 46#define KSE_STACKSIZE 16384 47#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_dtv) 48 49#define THR_GETCONTEXT(ucp) _ppc32_getcontext(&(ucp)->uc_mcontext) 50#define THR_SETCONTEXT(ucp) _ppc32_setcontext(&(ucp)->uc_mcontext, 0, NULL) 51 52#define PER_THREAD 53 54struct kcb; 55struct kse; 56struct pthread; 57struct tcb; 58 59/* 60 * %r2 points to the following. 61 */ 62struct ppc32_tp { 63 void *tp_dtv; /* dynamic thread vector */ 64 uint32_t _reserved_; 65 double tp_tls[0]; /* static TLS */ 66}; 67 68struct tcb { 69 struct kse_thr_mailbox tcb_tmbx; 70 struct pthread *tcb_thread; 71 struct kcb *tcb_curkcb; 72 long tcb_isfake; 73 struct ppc32_tp tcb_tp; 74}; 75 76struct kcb { 77 struct kse_mailbox kcb_kmbx; 78 struct kse *kcb_kse; 79 struct tcb *kcb_curtcb; 80 struct tcb kcb_faketcb; 81}; 82 83/* 84 * From the PowerPC32 TLS spec: 85 * 86 * "r2 is the thread pointer, and points 0x7000 past the end of the 87 * thread control block." Or, 0x7008 past the start of the 8-byte tcb 88 */ 89#define TP_OFFSET 0x7008 90 91static __inline char * 92ppc_get_tp() 93{ 94 register char *r2 __asm__("%r2"); 95 96 return (r2 - TP_OFFSET); 97} 98 99static __inline void 100ppc_set_tp(char *tp) 101{ 102 register char *r2 __asm__("%r2"); 103 __asm __volatile("mr %0,%1" : "=r"(r2) : "r"(tp + TP_OFFSET)); 104} 105 106static __inline struct tcb * 107ppc_get_tcb() 108{ 109 return ((struct tcb *)(ppc_get_tp() - offsetof(struct tcb, tcb_tp))); 110} 111 112static __inline void 113ppc_set_tcb(struct tcb *tcb) 114{ 115 ppc_set_tp((char*)&tcb->tcb_tp); 116} 117 118/* 119 * The kcb and tcb constructors. 120 */ 121struct tcb *_tcb_ctor(struct pthread *, int); 122void _tcb_dtor(struct tcb *); 123struct kcb *_kcb_ctor(struct kse *kse); 124void _kcb_dtor(struct kcb *); 125 126/* Called from the KSE to set its private data. */ 127static __inline void 128_kcb_set(struct kcb *kcb) 129{ 130 /* There is no thread yet; use the fake tcb. */ 131 ppc_set_tcb(&kcb->kcb_faketcb); 132} 133 134/* 135 * Get the current kcb. 136 * 137 * This can only be called while in a critical region; don't 138 * worry about having the kcb changed out from under us. 139 */ 140static __inline struct kcb * 141_kcb_get(void) 142{ 143 return (ppc_get_tcb()->tcb_curkcb); 144} 145 146/* 147 * Enter a critical region. 148 * 149 * Read and clear km_curthread in the kse mailbox. 150 */ 151static __inline struct kse_thr_mailbox * 152_kcb_critical_enter(void) 153{ 154 struct kse_thr_mailbox *crit; 155 struct tcb *tcb; 156 uint32_t flags; 157 158 tcb = ppc_get_tcb(); 159 if (tcb->tcb_isfake != 0) { 160 /* 161 * We already are in a critical region since 162 * there is no current thread. 163 */ 164 crit = NULL; 165 } else { 166 flags = tcb->tcb_tmbx.tm_flags; 167 tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; 168 crit = tcb->tcb_curkcb->kcb_kmbx.km_curthread; 169 tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL; 170 tcb->tcb_tmbx.tm_flags = flags; 171 } 172 return (crit); 173} 174 175static __inline void 176_kcb_critical_leave(struct kse_thr_mailbox *crit) 177{ 178 struct tcb *tcb; 179 180 tcb = ppc_get_tcb(); 181 182 /* No need to do anything if this is a fake tcb. */ 183 if (tcb->tcb_isfake == 0) 184 tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit; 185} 186 187static __inline int 188_kcb_in_critical(void) 189{ 190 struct tcb *tcb; 191 uint32_t flags; 192 int ret; 193 194 tcb = ppc_get_tcb(); 195 if (tcb->tcb_isfake != 0) { 196 /* 197 * We are in a critical region since there is no 198 * current thread. 199 */ 200 ret = 1; 201 } else { 202 flags = tcb->tcb_tmbx.tm_flags; 203 tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; 204 ret = (tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL); 205 tcb->tcb_tmbx.tm_flags = flags; 206 } 207 return (ret); 208} 209 210static __inline void 211_tcb_set(struct kcb *kcb, struct tcb *tcb) 212{ 213 if (tcb == NULL) 214 tcb = &kcb->kcb_faketcb; 215 kcb->kcb_curtcb = tcb; 216 tcb->tcb_curkcb = kcb; 217 ppc_set_tcb(tcb); 218} 219 220static __inline struct tcb * 221_tcb_get(void) 222{ 223 return (ppc_get_tcb()); 224} 225 226static __inline struct pthread * 227_get_curthread(void) 228{ 229 return (ppc_get_tcb()->tcb_thread); 230} 231 232/* 233 * Get the current kse. 234 * 235 * Like _kcb_get(), this can only be called while in a critical region. 236 */ 237static __inline struct kse * 238_get_curkse(void) 239{ 240 return (ppc_get_tcb()->tcb_curkcb->kcb_kse); 241} 242 243static __inline int 244_thread_enter_uts(struct tcb *tcb, struct kcb *kcb) 245{ 246 if (_ppc32_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) { 247 /* Make the fake tcb the current thread. */ 248 kcb->kcb_curtcb = &kcb->kcb_faketcb; 249 ppc_set_tcb(&kcb->kcb_faketcb); 250 _ppc32_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func, 251 kcb->kcb_kmbx.km_stack.ss_sp, 252 kcb->kcb_kmbx.km_stack.ss_size - 32); 253 /* We should not reach here. */ 254 return (-1); 255 } 256 return (0); 257} 258 259static __inline int 260_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox) 261{ 262 mcontext_t *mc; 263 extern int _libkse_debug; 264 265 _tcb_set(kcb, tcb); 266 mc = &tcb->tcb_tmbx.tm_context.uc_mcontext; 267 268 /* 269 * A full context needs a system call to restore, so use 270 * kse_switchin. Otherwise, the partial context can be 271 * restored with _ppc32_setcontext 272 */ 273 if (mc->mc_vers != _MC_VERSION_KSE && _libkse_debug != 0) { 274 if (setmbox) 275 kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX); 276 else 277 kse_switchin(&tcb->tcb_tmbx, 0); 278 } else { 279 tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp; 280 if (setmbox) 281 _ppc32_setcontext(mc, (intptr_t)&tcb->tcb_tmbx, 282 (intptr_t *)&kcb->kcb_kmbx.km_curthread); 283 else 284 _ppc32_setcontext(mc, 0, NULL); 285 } 286 287 /* We should not reach here. */ 288 return (-1); 289} 290 291#endif /* _PTHREAD_MD_H_ */ 292