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