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