pthread_md.h revision 174112
1/*- 2 * Copyright (c) 2002 Daniel Eischen <deischen@freebsd.org>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/lib/libkse/arch/i386/include/pthread_md.h 174112 2007-11-30 17:20:29Z deischen $ 27 */ 28/* 29 * Machine-dependent thread prototypes/definitions for the thread kernel. 30 */ 31#ifndef _PTHREAD_MD_H_ 32#define _PTHREAD_MD_H_ 33 34#include <stddef.h> 35#include <sys/types.h> 36#include <sys/kse.h> 37#include <machine/sysarch.h> 38#include <ucontext.h> 39 40extern int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *); 41extern int _thr_getcontext(mcontext_t *); 42 43#define KSE_STACKSIZE 16384 44#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) 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_KSE 50#undef PER_THREAD 51 52struct kse; 53struct pthread; 54 55/* 56 * %gs points to a struct kcb. 57 */ 58struct kcb { 59 struct tcb *kcb_curtcb; 60 struct kcb *kcb_self; /* self reference */ 61 struct kse *kcb_kse; 62 struct kse_mailbox kcb_kmbx; 63}; 64 65struct tcb { 66 struct tcb *tcb_self; /* required by rtld */ 67 void *tcb_dtv; /* required by rtld */ 68 struct pthread *tcb_thread; 69 void *tcb_spare; /* align tcb_tmbx to 16 bytes */ 70 struct kse_thr_mailbox tcb_tmbx; 71}; 72 73/* 74 * Evaluates to the byte offset of the per-kse variable name. 75 */ 76#define __kcb_offset(name) __offsetof(struct kcb, name) 77 78/* 79 * Evaluates to the type of the per-kse variable name. 80 */ 81#define __kcb_type(name) __typeof(((struct kcb *)0)->name) 82 83/* 84 * Evaluates to the value of the per-kse variable name. 85 */ 86#define KCB_GET32(name) ({ \ 87 __kcb_type(name) __result; \ 88 \ 89 u_int __i; \ 90 __asm __volatile("movl %%gs:%1, %0" \ 91 : "=r" (__i) \ 92 : "m" (*(u_int *)(__kcb_offset(name)))); \ 93 __result = (__kcb_type(name))__i; \ 94 \ 95 __result; \ 96}) 97 98/* 99 * Sets the value of the per-kse variable name to value val. 100 */ 101#define KCB_SET32(name, val) ({ \ 102 __kcb_type(name) __val = (val); \ 103 \ 104 u_int __i; \ 105 __i = (u_int)__val; \ 106 __asm __volatile("movl %1,%%gs:%0" \ 107 : "=m" (*(u_int *)(__kcb_offset(name))) \ 108 : "r" (__i)); \ 109}) 110 111static __inline u_long 112__kcb_readandclear32(volatile u_long *addr) 113{ 114 u_long result; 115 116 __asm __volatile ( 117 " xorl %0, %0;" 118 " xchgl %%gs:%1, %0;" 119 "# __kcb_readandclear32" 120 : "=&r" (result) 121 : "m" (*addr)); 122 return (result); 123} 124 125#define KCB_READANDCLEAR32(name) ({ \ 126 __kcb_type(name) __result; \ 127 \ 128 __result = (__kcb_type(name)) \ 129 __kcb_readandclear32((u_long *)__kcb_offset(name)); \ 130 __result; \ 131}) 132 133 134#define _kcb_curkcb() KCB_GET32(kcb_self) 135#define _kcb_curtcb() KCB_GET32(kcb_curtcb) 136#define _kcb_curkse() ((struct kse *)KCB_GET32(kcb_kmbx.km_udata)) 137#define _kcb_get_tmbx() KCB_GET32(kcb_kmbx.km_curthread) 138#define _kcb_set_tmbx(value) KCB_SET32(kcb_kmbx.km_curthread, (void *)value) 139#define _kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread) 140 141 142/* 143 * The constructors. 144 */ 145struct tcb *_tcb_ctor(struct pthread *, int); 146void _tcb_dtor(struct tcb *tcb); 147struct kcb *_kcb_ctor(struct kse *); 148void _kcb_dtor(struct kcb *); 149 150/* Called from the KSE to set its private data. */ 151static __inline void 152_kcb_set(struct kcb *kcb) 153{ 154 i386_set_gsbase(kcb); 155} 156 157/* Get the current kcb. */ 158static __inline struct kcb * 159_kcb_get(void) 160{ 161 return (_kcb_curkcb()); 162} 163 164static __inline struct kse_thr_mailbox * 165_kcb_critical_enter(void) 166{ 167 struct kse_thr_mailbox *crit; 168 169 crit = _kcb_readandclear_tmbx(); 170 return (crit); 171} 172 173static __inline void 174_kcb_critical_leave(struct kse_thr_mailbox *crit) 175{ 176 _kcb_set_tmbx(crit); 177} 178 179static __inline int 180_kcb_in_critical(void) 181{ 182 return (_kcb_get_tmbx() == NULL); 183} 184 185static __inline void 186_tcb_set(struct kcb *kcb, struct tcb *tcb) 187{ 188 kcb->kcb_curtcb = tcb; 189} 190 191static __inline struct tcb * 192_tcb_get(void) 193{ 194 return (_kcb_curtcb()); 195} 196 197static __inline struct pthread * 198_get_curthread(void) 199{ 200 struct tcb *tcb; 201 202 tcb = _kcb_curtcb(); 203 if (tcb != NULL) 204 return (tcb->tcb_thread); 205 else 206 return (NULL); 207} 208 209static __inline struct kse * 210_get_curkse(void) 211{ 212 return ((struct kse *)_kcb_curkse()); 213} 214 215void _i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack, 216 size_t stacksz); 217 218static __inline int 219_thread_enter_uts(struct tcb *tcb, struct kcb *kcb) 220{ 221 int ret; 222 223 ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext); 224 if (ret == 0) { 225 _i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func, 226 kcb->kcb_kmbx.km_stack.ss_sp, 227 kcb->kcb_kmbx.km_stack.ss_size); 228 /* We should not reach here. */ 229 return (-1); 230 } 231 else if (ret < 0) 232 return (-1); 233 return (0); 234} 235 236static __inline int 237_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox) 238{ 239 extern int _libkse_debug; 240 241 if ((kcb == NULL) || (tcb == NULL)) 242 return (-1); 243 kcb->kcb_curtcb = tcb; 244 if (_libkse_debug == 0) { 245 tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp; 246 if (setmbox != 0) 247 _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext, 248 (intptr_t)&tcb->tcb_tmbx, 249 (intptr_t *)(void *)&kcb->kcb_kmbx.km_curthread); 250 else 251 _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext, 252 0, NULL); 253 } else { 254 if (setmbox) 255 kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX); 256 else 257 kse_switchin(&tcb->tcb_tmbx, 0); 258 } 259 260 /* We should not reach here. */ 261 return (-1); 262} 263 264#endif 265