pthread_md.h revision 145569
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 145569 2005-04-26 20:41:48Z peter $ 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 43extern int _thr_using_setbase; 44 45#define KSE_STACKSIZE 16384 46#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) 47 48#define THR_GETCONTEXT(ucp) _thr_getcontext(&(ucp)->uc_mcontext) 49#define THR_SETCONTEXT(ucp) _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL) 50 51#define PER_KSE 52#undef PER_THREAD 53 54struct kse; 55struct pthread; 56 57/* 58 * %gs points to a struct kcb. 59 */ 60struct kcb { 61 struct tcb *kcb_curtcb; 62 struct kcb *kcb_self; /* self reference */ 63 int kcb_ldt; 64 struct kse *kcb_kse; 65 struct kse_mailbox kcb_kmbx; 66}; 67 68struct tcb { 69 struct tcb *tcb_self; /* required by rtld */ 70 void *tcb_dtv; /* required by rtld */ 71 struct pthread *tcb_thread; 72 void *tcb_spare; /* align tcb_tmbx to 16 bytes */ 73 struct kse_thr_mailbox tcb_tmbx; 74}; 75 76/* 77 * Evaluates to the byte offset of the per-kse variable name. 78 */ 79#define __kcb_offset(name) __offsetof(struct kcb, name) 80 81/* 82 * Evaluates to the type of the per-kse variable name. 83 */ 84#define __kcb_type(name) __typeof(((struct kcb *)0)->name) 85 86/* 87 * Evaluates to the value of the per-kse variable name. 88 */ 89#define KCB_GET32(name) ({ \ 90 __kcb_type(name) __result; \ 91 \ 92 u_int __i; \ 93 __asm __volatile("movl %%gs:%1, %0" \ 94 : "=r" (__i) \ 95 : "m" (*(u_int *)(__kcb_offset(name)))); \ 96 __result = (__kcb_type(name))__i; \ 97 \ 98 __result; \ 99}) 100 101/* 102 * Sets the value of the per-kse variable name to value val. 103 */ 104#define KCB_SET32(name, val) ({ \ 105 __kcb_type(name) __val = (val); \ 106 \ 107 u_int __i; \ 108 __i = (u_int)__val; \ 109 __asm __volatile("movl %1,%%gs:%0" \ 110 : "=m" (*(u_int *)(__kcb_offset(name))) \ 111 : "r" (__i)); \ 112}) 113 114static __inline u_long 115__kcb_readandclear32(volatile u_long *addr) 116{ 117 u_long result; 118 119 __asm __volatile ( 120 " xorl %0, %0;" 121 " xchgl %%gs:%1, %0;" 122 "# __kcb_readandclear32" 123 : "=&r" (result) 124 : "m" (*addr)); 125 return (result); 126} 127 128#define KCB_READANDCLEAR32(name) ({ \ 129 __kcb_type(name) __result; \ 130 \ 131 __result = (__kcb_type(name)) \ 132 __kcb_readandclear32((u_long *)__kcb_offset(name)); \ 133 __result; \ 134}) 135 136 137#define _kcb_curkcb() KCB_GET32(kcb_self) 138#define _kcb_curtcb() KCB_GET32(kcb_curtcb) 139#define _kcb_curkse() ((struct kse *)KCB_GET32(kcb_kmbx.km_udata)) 140#define _kcb_get_tmbx() KCB_GET32(kcb_kmbx.km_curthread) 141#define _kcb_set_tmbx(value) KCB_SET32(kcb_kmbx.km_curthread, (void *)value) 142#define _kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread) 143 144 145/* 146 * The constructors. 147 */ 148struct tcb *_tcb_ctor(struct pthread *, int); 149void _tcb_dtor(struct tcb *tcb); 150struct kcb *_kcb_ctor(struct kse *); 151void _kcb_dtor(struct kcb *); 152 153/* Called from the KSE to set its private data. */ 154static __inline void 155_kcb_set(struct kcb *kcb) 156{ 157 int val; 158 159 if (_thr_using_setbase == 1) { 160 i386_set_gsbase(kcb); 161 } else { 162 val = (kcb->kcb_ldt << 3) | 7; 163 __asm __volatile("movl %0, %%gs" : : "r" (val)); 164 } 165 166} 167 168/* Get the current kcb. */ 169static __inline struct kcb * 170_kcb_get(void) 171{ 172 return (_kcb_curkcb()); 173} 174 175static __inline struct kse_thr_mailbox * 176_kcb_critical_enter(void) 177{ 178 struct kse_thr_mailbox *crit; 179 180 crit = _kcb_readandclear_tmbx(); 181 return (crit); 182} 183 184static __inline void 185_kcb_critical_leave(struct kse_thr_mailbox *crit) 186{ 187 _kcb_set_tmbx(crit); 188} 189 190static __inline int 191_kcb_in_critical(void) 192{ 193 return (_kcb_get_tmbx() == NULL); 194} 195 196static __inline void 197_tcb_set(struct kcb *kcb, struct tcb *tcb) 198{ 199 kcb->kcb_curtcb = tcb; 200} 201 202static __inline struct tcb * 203_tcb_get(void) 204{ 205 return (_kcb_curtcb()); 206} 207 208static __inline struct pthread * 209_get_curthread(void) 210{ 211 struct tcb *tcb; 212 213 tcb = _kcb_curtcb(); 214 if (tcb != NULL) 215 return (tcb->tcb_thread); 216 else 217 return (NULL); 218} 219 220static __inline struct kse * 221_get_curkse(void) 222{ 223 return ((struct kse *)_kcb_curkse()); 224} 225 226void _i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack, 227 size_t stacksz); 228 229static __inline int 230_thread_enter_uts(struct tcb *tcb, struct kcb *kcb) 231{ 232 int ret; 233 234 ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext); 235 if (ret == 0) { 236 _i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func, 237 kcb->kcb_kmbx.km_stack.ss_sp, 238 kcb->kcb_kmbx.km_stack.ss_size); 239 /* We should not reach here. */ 240 return (-1); 241 } 242 else if (ret < 0) 243 return (-1); 244 return (0); 245} 246 247static __inline int 248_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox) 249{ 250 extern int _libkse_debug; 251 252 if ((kcb == NULL) || (tcb == NULL)) 253 return (-1); 254 kcb->kcb_curtcb = tcb; 255 if (_libkse_debug == 0) { 256 tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp; 257 if (setmbox != 0) 258 _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext, 259 (intptr_t)&tcb->tcb_tmbx, 260 (intptr_t *)&kcb->kcb_kmbx.km_curthread); 261 else 262 _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext, 263 0, NULL); 264 } else { 265 if (setmbox) 266 kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX); 267 else 268 kse_switchin(&tcb->tcb_tmbx, 0); 269 } 270 271 /* We should not reach here. */ 272 return (-1); 273} 274 275#endif 276