]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libkse/arch/i386/include/pthread_md.h
This commit was generated by cvs2svn to compensate for changes in r147341,
[FreeBSD/FreeBSD.git] / lib / libkse / arch / i386 / include / pthread_md.h
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$
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
40 extern int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
41 extern int _thr_getcontext(mcontext_t *);
42
43 extern 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
54 struct kse;
55 struct pthread;
56
57 /*
58  * %gs points to a struct kcb.
59  */
60 struct 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
68 struct 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
114 static __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  */
148 struct tcb      *_tcb_ctor(struct pthread *, int);
149 void            _tcb_dtor(struct tcb *tcb);
150 struct kcb      *_kcb_ctor(struct kse *);
151 void            _kcb_dtor(struct kcb *);
152
153 /* Called from the KSE to set its private data. */
154 static __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. */
169 static __inline struct kcb *
170 _kcb_get(void)
171 {
172         return (_kcb_curkcb());
173 }
174
175 static __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
184 static __inline void
185 _kcb_critical_leave(struct kse_thr_mailbox *crit)
186 {
187         _kcb_set_tmbx(crit);
188 }
189
190 static __inline int
191 _kcb_in_critical(void)
192 {
193         return (_kcb_get_tmbx() == NULL);
194 }
195
196 static __inline void
197 _tcb_set(struct kcb *kcb, struct tcb *tcb)
198 {
199         kcb->kcb_curtcb = tcb;
200 }
201
202 static __inline struct tcb *
203 _tcb_get(void)
204 {
205         return (_kcb_curtcb());
206 }
207
208 static __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
220 static __inline struct kse *
221 _get_curkse(void)
222 {
223         return ((struct kse *)_kcb_curkse());
224 }
225
226 void    _i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
227     size_t stacksz);
228
229 static __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
247 static __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