diff options
Diffstat (limited to 'lib/libkse/arch/amd64/include/pthread_md.h')
-rw-r--r-- | lib/libkse/arch/amd64/include/pthread_md.h | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/lib/libkse/arch/amd64/include/pthread_md.h b/lib/libkse/arch/amd64/include/pthread_md.h new file mode 100644 index 0000000..3e451fd --- /dev/null +++ b/lib/libkse/arch/amd64/include/pthread_md.h @@ -0,0 +1,268 @@ +/*- + * Copyright (C) 2003 David Xu <davidxu@freebsd.org> + * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* + * Machine-dependent thread prototypes/definitions for the thread kernel. + */ +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include <stddef.h> +#include <sys/types.h> +#include <sys/kse.h> +#include <machine/sysarch.h> +#include <ucontext.h> + +#define KSE_STACKSIZE 16384 +#define DTV_OFFSET offsetof(struct tcb, tcb_dtv) + +#define THR_GETCONTEXT(ucp) \ + (void)_amd64_save_context(&(ucp)->uc_mcontext) +#define THR_SETCONTEXT(ucp) \ + (void)_amd64_restore_context(&(ucp)->uc_mcontext, 0, NULL) + +#define PER_KSE +#undef PER_THREAD + +struct kse; +struct pthread; +struct tdv; + +/* + * %fs points to a struct kcb. + */ +struct kcb { + struct tcb *kcb_curtcb; + struct kcb *kcb_self; /* self reference */ + struct kse *kcb_kse; + struct kse_mailbox kcb_kmbx; +}; + +struct tcb { + struct tcb *tcb_self; /* required by rtld */ + void *tcb_dtv; /* required by rtld */ + struct pthread *tcb_thread; + void *tcb_spare[1]; /* align tcb_tmbx to 16 bytes */ + struct kse_thr_mailbox tcb_tmbx; +}; + +/* + * Evaluates to the byte offset of the per-kse variable name. + */ +#define __kcb_offset(name) __offsetof(struct kcb, name) + +/* + * Evaluates to the type of the per-kse variable name. + */ +#define __kcb_type(name) __typeof(((struct kcb *)0)->name) + +/* + * Evaluates to the value of the per-kse variable name. + */ +#define KCB_GET64(name) ({ \ + __kcb_type(name) __result; \ + \ + u_long __i; \ + __asm __volatile("movq %%fs:%1, %0" \ + : "=r" (__i) \ + : "m" (*(u_long *)(__kcb_offset(name)))); \ + __result = (__kcb_type(name))__i; \ + \ + __result; \ +}) + +/* + * Sets the value of the per-kse variable name to value val. + */ +#define KCB_SET64(name, val) ({ \ + __kcb_type(name) __val = (val); \ + \ + u_long __i; \ + __i = (u_long)__val; \ + __asm __volatile("movq %1,%%fs:%0" \ + : "=m" (*(u_long *)(__kcb_offset(name))) \ + : "r" (__i)); \ +}) + +static __inline u_long +__kcb_readandclear64(volatile u_long *addr) +{ + u_long result; + + __asm __volatile ( + " xorq %0, %0;" + " xchgq %%fs:%1, %0;" + "# __kcb_readandclear64" + : "=&r" (result) + : "m" (*addr)); + return (result); +} + +#define KCB_READANDCLEAR64(name) ({ \ + __kcb_type(name) __result; \ + \ + __result = (__kcb_type(name)) \ + __kcb_readandclear64((u_long *)__kcb_offset(name)); \ + __result; \ +}) + + +#define _kcb_curkcb() KCB_GET64(kcb_self) +#define _kcb_curtcb() KCB_GET64(kcb_curtcb) +#define _kcb_curkse() ((struct kse *)KCB_GET64(kcb_kmbx.km_udata)) +#define _kcb_get_tmbx() KCB_GET64(kcb_kmbx.km_curthread) +#define _kcb_set_tmbx(value) KCB_SET64(kcb_kmbx.km_curthread, (void *)value) +#define _kcb_readandclear_tmbx() KCB_READANDCLEAR64(kcb_kmbx.km_curthread) + +/* + * The constructors. + */ +struct tcb *_tcb_ctor(struct pthread *, int); +void _tcb_dtor(struct tcb *tcb); +struct kcb *_kcb_ctor(struct kse *); +void _kcb_dtor(struct kcb *); + +/* Called from the KSE to set its private data. */ +static __inline void +_kcb_set(struct kcb *kcb) +{ + amd64_set_fsbase(kcb); +} + +/* Get the current kcb. */ +static __inline struct kcb * +_kcb_get(void) +{ + return (_kcb_curkcb()); +} + +static __inline struct kse_thr_mailbox * +_kcb_critical_enter(void) +{ + struct kse_thr_mailbox *crit; + + crit = _kcb_readandclear_tmbx(); + return (crit); +} + +static __inline void +_kcb_critical_leave(struct kse_thr_mailbox *crit) +{ + _kcb_set_tmbx(crit); +} + +static __inline int +_kcb_in_critical(void) +{ + return (_kcb_get_tmbx() == NULL); +} + +static __inline void +_tcb_set(struct kcb *kcb, struct tcb *tcb) +{ + kcb->kcb_curtcb = tcb; +} + +static __inline struct tcb * +_tcb_get(void) +{ + return (_kcb_curtcb()); +} + +static __inline struct pthread * +_get_curthread(void) +{ + struct tcb *tcb; + + tcb = _kcb_curtcb(); + if (tcb != NULL) + return (tcb->tcb_thread); + else + return (NULL); +} + +static __inline struct kse * +_get_curkse(void) +{ + return ((struct kse *)_kcb_curkse()); +} + +void _amd64_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack, + size_t stacksz); +int _amd64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc); +int _amd64_save_context(mcontext_t *mc); + +static __inline int +_thread_enter_uts(struct tcb *tcb, struct kcb *kcb) +{ + int ret; + + ret = _amd64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext); + if (ret == 0) { + _amd64_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func, + kcb->kcb_kmbx.km_stack.ss_sp, + kcb->kcb_kmbx.km_stack.ss_size); + /* We should not reach here. */ + return (-1); + } + else if (ret < 0) + return (-1); + return (0); +} + +static __inline int +_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox) +{ + extern int _libkse_debug; + + if ((kcb == NULL) || (tcb == NULL)) + return (-1); + kcb->kcb_curtcb = tcb; + + if (_libkse_debug == 0) { + tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp; + if (setmbox != 0) + _amd64_restore_context( + &tcb->tcb_tmbx.tm_context.uc_mcontext, + (intptr_t)&tcb->tcb_tmbx, + (intptr_t *)(void *)&kcb->kcb_kmbx.km_curthread); + else + _amd64_restore_context( + &tcb->tcb_tmbx.tm_context.uc_mcontext, + 0, NULL); + /* We should not reach here. */ + } else { + if (setmbox) + kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX); + else + kse_switchin(&tcb->tcb_tmbx, 0); + } + + return (-1); +} +#endif |