]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libkse/arch/i386/include/pthread_md.h
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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 #define KSE_STACKSIZE           16384
44 #define DTV_OFFSET              offsetof(struct tcb, tcb_dtv)
45
46 #define THR_GETCONTEXT(ucp)     _thr_getcontext(&(ucp)->uc_mcontext)
47 #define THR_SETCONTEXT(ucp)     _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
48
49 #define PER_KSE
50 #undef  PER_THREAD
51
52 struct kse;
53 struct pthread;
54
55 /*
56  * %gs points to a struct kcb.
57  */
58 struct kcb {
59         struct tcb              *kcb_curtcb;
60         struct kcb              *kcb_self;      /* self reference */
61         struct kse              *kcb_kse;
62         struct kse_mailbox      kcb_kmbx;
63 };
64
65 struct tcb {
66         struct tcb              *tcb_self;      /* required by rtld */
67         void                    *tcb_dtv;       /* required by rtld */
68         struct pthread          *tcb_thread;
69         void                    *tcb_spare;     /* align tcb_tmbx to 16 bytes */
70         struct kse_thr_mailbox  tcb_tmbx;
71 };
72
73 /*
74  * Evaluates to the byte offset of the per-kse variable name.
75  */
76 #define __kcb_offset(name)      __offsetof(struct kcb, name)
77
78 /*
79  * Evaluates to the type of the per-kse variable name.
80  */
81 #define __kcb_type(name)        __typeof(((struct kcb *)0)->name)
82
83 /*
84  * Evaluates to the value of the per-kse variable name.
85  */
86 #define KCB_GET32(name) ({                                      \
87         __kcb_type(name) __result;                              \
88                                                                 \
89         u_int __i;                                              \
90         __asm __volatile("movl %%gs:%1, %0"                     \
91             : "=r" (__i)                                        \
92             : "m" (*(u_int *)(__kcb_offset(name))));            \
93         __result = (__kcb_type(name))__i;                       \
94                                                                 \
95         __result;                                               \
96 })
97
98 /*
99  * Sets the value of the per-kse variable name to value val.
100  */
101 #define KCB_SET32(name, val) ({                                 \
102         __kcb_type(name) __val = (val);                         \
103                                                                 \
104         u_int __i;                                              \
105         __i = (u_int)__val;                                     \
106         __asm __volatile("movl %1,%%gs:%0"                      \
107             : "=m" (*(u_int *)(__kcb_offset(name)))             \
108             : "r" (__i));                                       \
109 })
110
111 static __inline u_long
112 __kcb_readandclear32(volatile u_long *addr)
113 {
114         u_long result;
115
116         __asm __volatile (
117             "   xorl    %0, %0;"
118             "   xchgl   %%gs:%1, %0;"
119             "# __kcb_readandclear32"
120             : "=&r" (result)
121             : "m" (*addr));
122         return (result);
123 }
124
125 #define KCB_READANDCLEAR32(name) ({                             \
126         __kcb_type(name) __result;                              \
127                                                                 \
128         __result = (__kcb_type(name))                           \
129             __kcb_readandclear32((u_long *)__kcb_offset(name)); \
130         __result;                                               \
131 })
132
133
134 #define _kcb_curkcb()           KCB_GET32(kcb_self)
135 #define _kcb_curtcb()           KCB_GET32(kcb_curtcb)
136 #define _kcb_curkse()           ((struct kse *)KCB_GET32(kcb_kmbx.km_udata))
137 #define _kcb_get_tmbx()         KCB_GET32(kcb_kmbx.km_curthread)
138 #define _kcb_set_tmbx(value)    KCB_SET32(kcb_kmbx.km_curthread, (void *)value)
139 #define _kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread)
140
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         i386_set_gsbase(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    _i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
216     size_t stacksz);
217
218 static __inline int
219 _thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
220 {
221         int ret;
222
223         ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext);
224         if (ret == 0) {
225                 _i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
226                     kcb->kcb_kmbx.km_stack.ss_sp,
227                     kcb->kcb_kmbx.km_stack.ss_size);
228                 /* We should not reach here. */
229                 return (-1);
230         }
231         else if (ret < 0)
232                 return (-1);
233         return (0);
234 }
235
236 static __inline int
237 _thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
238 {
239         extern int _libkse_debug;
240
241         if ((kcb == NULL) || (tcb == NULL))
242                 return (-1);
243         kcb->kcb_curtcb = tcb;
244         if (_libkse_debug == 0) {
245                 tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
246                 if (setmbox != 0)
247                         _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
248                             (intptr_t)&tcb->tcb_tmbx,
249                             (intptr_t *)(void *)&kcb->kcb_kmbx.km_curthread);
250                 else
251                         _thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
252                                 0, NULL);
253         } else {
254                 if (setmbox)
255                         kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
256                 else
257                         kse_switchin(&tcb->tcb_tmbx, 0);
258         }
259
260         /* We should not reach here. */
261         return (-1);
262 }
263
264 #endif