pthread_md.h revision 133806
1/* 2 * Copyright 2004 by Peter Grehan. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 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, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/lib/libkse/arch/powerpc/include/pthread_md.h 133806 2004-08-16 05:41:39Z grehan $ 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 40extern void _ppc32_enter_uts(struct kse_mailbox *, kse_func_t, void *, size_t); 41extern int _ppc32_setcontext(mcontext_t *, intptr_t, intptr_t *); 42extern int _ppc32_getcontext(mcontext_t *); 43 44#define KSE_STACKSIZE 16384 45#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_tdv) 46 47#define THR_GETCONTEXT(ucp) _ppc32_getcontext(&(ucp)->uc_mcontext) 48#define THR_SETCONTEXT(ucp) _ppc32_setcontext(&(ucp)->uc_mcontext, 0, NULL) 49 50#define PER_THREAD 51 52struct kcb; 53struct kse; 54struct pthread; 55struct tcb; 56struct tdv; 57 58/* 59 * %r2 points to a struct kcb. 60 */ 61struct ppc32_tp { 62 struct tdv *tp_tdv; /* dynamic TLS */ 63 uint32_t _reserved_; 64 long double tp_tls[0]; /* static TLS */ 65}; 66 67struct tcb { 68 struct kse_thr_mailbox tcb_tmbx; 69 struct pthread *tcb_thread; 70 struct kcb *tcb_curkcb; 71 long tcb_isfake; 72 struct ppc32_tp tcb_tp; 73}; 74 75struct kcb { 76 struct kse_mailbox kcb_kmbx; 77 struct tcb kcb_faketcb; 78 struct tcb *kcb_curtcb; 79 struct kse *kcb_kse; 80}; 81 82/* 83 * From the PowerPC32 TLS spec: 84 * 85 * "r2 is the thread pointer, and points 0x7000 past the end of the 86 * thread control block." Or, 0x7008 past the start of the 8-byte tcb 87 */ 88#define TP_OFFSET 0x7008 89register uint8_t *_tpr __asm("%r2"); 90 91#define _tcb ((struct tcb *)(_tpr - TP_OFFSET - offsetof(struct tcb, tcb_tp))) 92 93/* 94 * The kcb and tcb constructors. 95 */ 96struct tcb *_tcb_ctor(struct pthread *, int); 97void _tcb_dtor(struct tcb *); 98struct kcb *_kcb_ctor(struct kse *kse); 99void _kcb_dtor(struct kcb *); 100 101/* Called from the KSE to set its private data. */ 102static __inline void 103_kcb_set(struct kcb *kcb) 104{ 105 /* There is no thread yet; use the fake tcb. */ 106 _tpr = (uint8_t *)&kcb->kcb_faketcb.tcb_tp + TP_OFFSET; 107} 108 109/* 110 * Get the current kcb. 111 * 112 * This can only be called while in a critical region; don't 113 * worry about having the kcb changed out from under us. 114 */ 115static __inline struct kcb * 116_kcb_get(void) 117{ 118 return (_tcb->tcb_curkcb); 119} 120 121/* 122 * Enter a critical region. 123 * 124 * Read and clear km_curthread in the kse mailbox. 125 */ 126static __inline struct kse_thr_mailbox * 127_kcb_critical_enter(void) 128{ 129 struct kse_thr_mailbox *crit; 130 uint32_t flags; 131 132 if (_tcb->tcb_isfake != 0) { 133 /* 134 * We already are in a critical region since 135 * there is no current thread. 136 */ 137 crit = NULL; 138 } else { 139 flags = _tcb->tcb_tmbx.tm_flags; 140 _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; 141 crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread; 142 _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL; 143 _tcb->tcb_tmbx.tm_flags = flags; 144 } 145 return (crit); 146} 147 148static __inline void 149_kcb_critical_leave(struct kse_thr_mailbox *crit) 150{ 151 /* No need to do anything if this is a fake tcb. */ 152 if (_tcb->tcb_isfake == 0) 153 _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit; 154} 155 156static __inline int 157_kcb_in_critical(void) 158{ 159 uint32_t flags; 160 int ret; 161 162 if (_tcb->tcb_isfake != 0) { 163 /* 164 * We are in a critical region since there is no 165 * current thread. 166 */ 167 ret = 1; 168 } else { 169 flags = _tcb->tcb_tmbx.tm_flags; 170 _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; 171 ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL); 172 _tcb->tcb_tmbx.tm_flags = flags; 173 } 174 return (ret); 175} 176 177static __inline void 178_tcb_set(struct kcb *kcb, struct tcb *tcb) 179{ 180 if (tcb == NULL) 181 tcb = &kcb->kcb_faketcb; 182 kcb->kcb_curtcb = tcb; 183 tcb->tcb_curkcb = kcb; 184 _tpr = (uint8_t *)&tcb->tcb_tp + TP_OFFSET; 185} 186 187static __inline struct tcb * 188_tcb_get(void) 189{ 190 return (_tcb); 191} 192 193static __inline struct pthread * 194_get_curthread(void) 195{ 196 return (_tcb->tcb_thread); 197} 198 199/* 200 * Get the current kse. 201 * 202 * Like _kcb_get(), this can only be called while in a critical region. 203 */ 204static __inline struct kse * 205_get_curkse(void) 206{ 207 return (_tcb->tcb_curkcb->kcb_kse); 208} 209 210static __inline int 211_thread_enter_uts(struct tcb *tcb, struct kcb *kcb) 212{ 213 if (_ppc32_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) { 214 /* Make the fake tcb the current thread. */ 215 kcb->kcb_curtcb = &kcb->kcb_faketcb; 216 _tpr = (uint8_t *)&kcb->kcb_faketcb.tcb_tp + TP_OFFSET; 217 _ppc32_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func, 218 kcb->kcb_kmbx.km_stack.ss_sp, 219 kcb->kcb_kmbx.km_stack.ss_size - 32); 220 /* We should not reach here. */ 221 return (-1); 222 } 223 return (0); 224} 225 226static __inline int 227_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox) 228{ 229 mcontext_t *mc; 230 extern int _libkse_debug; 231 232 _tcb_set(kcb, tcb); 233 mc = &tcb->tcb_tmbx.tm_context.uc_mcontext; 234 235 /* 236 * A full context needs a system call to restore, so use 237 * kse_switchin. Otherwise, the partial context can be 238 * restored with _ppc32_setcontext 239 */ 240 if (mc->mc_vers != _MC_VERSION_KSE && _libkse_debug != 0) { 241 if (setmbox) 242 kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX); 243 else 244 kse_switchin(&tcb->tcb_tmbx, 0); 245 } else { 246 tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp; 247 if (setmbox) 248 _ppc32_setcontext(mc, (intptr_t)&tcb->tcb_tmbx, 249 (intptr_t *)&kcb->kcb_kmbx.km_curthread); 250 else 251 _ppc32_setcontext(mc, 0, NULL); 252 } 253 254 /* We should not reach here. */ 255 return (-1); 256} 257 258#endif /* _PTHREAD_MD_H_ */ 259