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