pthread_md.h revision 118519
1116708Smarcel/* 2116708Smarcel * Copyright (c) 2003 Marcel Moolenaar 3116708Smarcel * All rights reserved. 4116708Smarcel * 5116708Smarcel * Redistribution and use in source and binary forms, with or without 6116708Smarcel * modification, are permitted provided that the following conditions 7116708Smarcel * are met: 8116708Smarcel * 9116708Smarcel * 1. Redistributions of source code must retain the above copyright 10116708Smarcel * notice, this list of conditions and the following disclaimer. 11116708Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12116708Smarcel * notice, this list of conditions and the following disclaimer in the 13116708Smarcel * documentation and/or other materials provided with the distribution. 14116708Smarcel * 15116708Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16116708Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17116708Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18116708Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19116708Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20116708Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21116708Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22116708Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23116708Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24116708Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25116708Smarcel * 26116708Smarcel * $FreeBSD: head/lib/libkse/arch/ia64/include/pthread_md.h 118519 2003-08-06 06:12:54Z deischen $ 27116708Smarcel */ 28116708Smarcel 29116708Smarcel#ifndef _PTHREAD_MD_H_ 30116708Smarcel#define _PTHREAD_MD_H_ 31116708Smarcel 32118510Sdeischen#include <sys/kse.h> 33118518Smarcel#include <stddef.h> 34118510Sdeischen#include <ucontext.h> 35118510Sdeischen 36118507Smarcel#define THR_GETCONTEXT(ucp) _ia64_save_context(&(ucp)->uc_mcontext) 37118507Smarcel#define THR_SETCONTEXT(ucp) _ia64_restore_context(&(ucp)->uc_mcontext, \ 38118507Smarcel 0, NULL) 39116708Smarcel 40118510Sdeischen#define PER_THREAD 41116708Smarcel 42118510Sdeischenstruct kcb; 43118510Sdeischenstruct kse; 44118510Sdeischenstruct pthread; 45118510Sdeischenstruct tcb; 46118510Sdeischenstruct tdv; /* We don't know what this is yet? */ 47118510Sdeischen 48118510Sdeischen/* 49118513Smarcel * tp points to one of these. We define the static TLS as an array 50118513Smarcel * of long double to enforce 16-byte alignment of the TLS memory, 51118513Smarcel * struct ia64_tp, struct tcb and also struct kcb. Both static and 52118513Smarcel * dynamic allocation of any of these structures will result in a 53118513Smarcel * valid, well-aligned thread pointer. 54118510Sdeischen */ 55118510Sdeischenstruct ia64_tp { 56118510Sdeischen struct tdv *tp_tdv; /* dynamic TLS */ 57118518Smarcel uint64_t _reserved_; 58118513Smarcel long double tp_tls[0]; /* static TLS */ 59116771Smarcel}; 60116771Smarcel 61118510Sdeischenstruct tcb { 62118510Sdeischen struct kse_thr_mailbox tcb_tmbx; 63118510Sdeischen struct pthread *tcb_thread; 64118510Sdeischen struct kcb *tcb_curkcb; 65118510Sdeischen long tcb_isfake; 66118510Sdeischen struct ia64_tp tcb_tp; 67118510Sdeischen}; 68118510Sdeischen 69118510Sdeischenstruct kcb { 70118510Sdeischen struct kse_mailbox kcb_kmbx; 71118510Sdeischen struct tcb kcb_faketcb; 72118510Sdeischen struct tcb *kcb_curtcb; 73118510Sdeischen struct kse *kcb_kse; 74118510Sdeischen}; 75118510Sdeischen 76118510Sdeischenregister struct ia64_tp *_tp __asm("%r13"); 77118510Sdeischen 78118518Smarcel#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp))) 79118518Smarcel 80118510Sdeischen/* 81118510Sdeischen * The kcb and tcb constructors. 82118510Sdeischen */ 83118510Sdeischenstruct tcb *_tcb_ctor(struct pthread *); 84118510Sdeischenvoid _tcb_dtor(struct tcb *); 85118510Sdeischenstruct kcb *_kcb_ctor(struct kse *kse); 86118510Sdeischenvoid _kcb_dtor(struct kcb *); 87118510Sdeischen 88118510Sdeischen/* Called from the KSE to set its private data. */ 89118510Sdeischenstatic __inline void 90118510Sdeischen_kcb_set(struct kcb *kcb) 91118510Sdeischen{ 92118510Sdeischen /* There is no thread yet; use the fake tcb. */ 93118510Sdeischen _tp = &kcb->kcb_faketcb.tcb_tp; 94118510Sdeischen} 95118510Sdeischen 96118510Sdeischen/* 97118510Sdeischen * Get the current kcb. 98118510Sdeischen * 99118510Sdeischen * This can only be called while in a critical region; don't 100118510Sdeischen * worry about having the kcb changed out from under us. 101118510Sdeischen */ 102118510Sdeischenstatic __inline struct kcb * 103118510Sdeischen_kcb_get(void) 104118510Sdeischen{ 105118518Smarcel return (_tcb->tcb_curkcb); 106118510Sdeischen} 107118510Sdeischen 108118510Sdeischen/* 109118510Sdeischen * Enter a critical region. 110118510Sdeischen * 111118510Sdeischen * Read and clear km_curthread in the kse mailbox. 112118510Sdeischen */ 113118510Sdeischenstatic __inline struct kse_thr_mailbox * 114118510Sdeischen_kcb_critical_enter(void) 115118510Sdeischen{ 116118510Sdeischen struct kse_thr_mailbox *crit; 117118510Sdeischen uint32_t flags; 118118510Sdeischen 119118518Smarcel if (_tcb->tcb_isfake != 0) { 120118510Sdeischen /* 121118510Sdeischen * We already are in a critical region since 122118510Sdeischen * there is no current thread. 123118510Sdeischen */ 124118510Sdeischen crit = NULL; 125118510Sdeischen } else { 126118518Smarcel flags = _tcb->tcb_tmbx.tm_flags; 127118518Smarcel _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; 128118518Smarcel crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread; 129118518Smarcel _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL; 130118518Smarcel _tcb->tcb_tmbx.tm_flags = flags; 131118510Sdeischen } 132118510Sdeischen return (crit); 133118510Sdeischen} 134118510Sdeischen 135118510Sdeischenstatic __inline void 136118510Sdeischen_kcb_critical_leave(struct kse_thr_mailbox *crit) 137118510Sdeischen{ 138118510Sdeischen /* No need to do anything if this is a fake tcb. */ 139118518Smarcel if (_tcb->tcb_isfake == 0) 140118518Smarcel _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit; 141118510Sdeischen} 142118510Sdeischen 143118510Sdeischenstatic __inline int 144118510Sdeischen_kcb_in_critical(void) 145118510Sdeischen{ 146118510Sdeischen uint32_t flags; 147118510Sdeischen int ret; 148118510Sdeischen 149118518Smarcel if (_tcb->tcb_isfake != 0) { 150118510Sdeischen /* 151118510Sdeischen * We are in a critical region since there is no 152118510Sdeischen * current thread. 153118510Sdeischen */ 154118510Sdeischen ret = 1; 155118510Sdeischen } else { 156118518Smarcel flags = _tcb->tcb_tmbx.tm_flags; 157118518Smarcel _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; 158118518Smarcel ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL); 159118518Smarcel _tcb->tcb_tmbx.tm_flags = flags; 160118510Sdeischen } 161118510Sdeischen return (ret); 162118510Sdeischen} 163118510Sdeischen 164118510Sdeischenstatic __inline void 165118510Sdeischen_tcb_set(struct kcb *kcb, struct tcb *tcb) 166118510Sdeischen{ 167118518Smarcel if (tcb == NULL) 168118518Smarcel tcb = &kcb->kcb_faketcb; 169118518Smarcel kcb->kcb_curtcb = tcb; 170118518Smarcel tcb->tcb_curkcb = kcb; 171118518Smarcel _tp = &tcb->tcb_tp; 172118510Sdeischen} 173118510Sdeischen 174118510Sdeischenstatic __inline struct tcb * 175118510Sdeischen_tcb_get(void) 176118510Sdeischen{ 177118518Smarcel return (_tcb); 178118510Sdeischen} 179118510Sdeischen 180118510Sdeischenstatic __inline struct pthread * 181118510Sdeischen_get_curthread(void) 182118510Sdeischen{ 183118518Smarcel return (_tcb->tcb_thread); 184118510Sdeischen} 185118510Sdeischen 186118510Sdeischen/* 187118510Sdeischen * Get the current kse. 188118510Sdeischen * 189118519Sdeischen * Like _kcb_get(), this can only be called while in a critical region. 190118510Sdeischen */ 191118510Sdeischenstatic __inline struct kse * 192118510Sdeischen_get_curkse(void) 193118510Sdeischen{ 194118518Smarcel return (_tcb->tcb_curkcb->kcb_kse); 195118510Sdeischen} 196118510Sdeischen 197116866Smarcelvoid _ia64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack, 198116866Smarcel size_t stacksz); 199116866Smarcelint _ia64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc); 200116866Smarcelint _ia64_save_context(mcontext_t *mc); 201116866Smarcel 202116866Smarcelstatic __inline int 203118510Sdeischen_thread_enter_uts(struct tcb *tcb, struct kcb *kcb) 204116866Smarcel{ 205118510Sdeischen if (_ia64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) { 206118510Sdeischen /* Make the fake tcb the current thread. */ 207118510Sdeischen kcb->kcb_curtcb = &kcb->kcb_faketcb; 208118510Sdeischen _tp = &kcb->kcb_faketcb.tcb_tp; 209118510Sdeischen _ia64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx, 210118510Sdeischen kcb->kcb_kmbx.km_stack.ss_sp, 211118510Sdeischen kcb->kcb_kmbx.km_stack.ss_size); 212116866Smarcel /* We should not reach here. */ 213116866Smarcel return (-1); 214116866Smarcel } 215116866Smarcel return (0); 216116866Smarcel} 217116866Smarcel 218116866Smarcelstatic __inline int 219118510Sdeischen_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox) 220116866Smarcel{ 221118518Smarcel _tcb_set(kcb, tcb); 222118510Sdeischen if (setmbox != 0) 223118510Sdeischen _ia64_restore_context(&tcb->tcb_tmbx.tm_context.uc_mcontext, 224118510Sdeischen (intptr_t)&tcb->tcb_tmbx, 225118510Sdeischen (intptr_t *)&kcb->kcb_kmbx.km_curthread); 226118510Sdeischen else 227118510Sdeischen _ia64_restore_context(&tcb->tcb_tmbx.tm_context.uc_mcontext, 228118510Sdeischen 0, NULL); 229116866Smarcel /* We should not reach here. */ 230116866Smarcel return (-1); 231116866Smarcel} 232116866Smarcel 233116708Smarcel#endif /* _PTHREAD_MD_H_ */ 234