06efcfb3c5daa10843268a9b95421f066c5be63e
[openafs.git] / src / lwp / process.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* process.c - manage lwp context switches be means of setjmp/longjmp. */
11
12 #include <afsconfig.h>
13
14 /*
15  * We must include at least one system header on Linux prior to including
16  * afs/param.h, or the __GLIBC__ and __GLIBC_MINOR__ macros will not yet be
17  * defined and we won't know whether we're using ucontext.
18  */
19 #include <stdio.h>
20 #include <assert.h>
21 #ifdef HAVE_STDLIB_H
22 # include <stdlib.h>
23 #endif
24
25 #include <afs/param.h>
26
27 #include "lwp.h"
28
29 #if defined(AFS_OSF_ENV) || defined(AFS_S390_LINUX20_ENV)
30 extern int PRE_Block;           /* used in lwp.c and process.s */
31 #else
32 extern char PRE_Block;          /* used in lwp.c and process.s */
33 #endif
34
35 #if defined(USE_UCONTEXT) && defined(HAVE_UCONTEXT_H)
36
37 afs_int32
38 savecontext(void (*ep) (void), struct lwp_context *savearea, char *newsp)
39 {
40 #if defined(AFS_LINUX20_ENV)
41     /* getcontext does not export stack info */
42     int stackvar;
43 #endif
44
45     PRE_Block = 1;
46
47     savearea->state = 0;
48     getcontext(&savearea->ucontext);
49 #if defined(AFS_LINUX20_ENV)
50     savearea->topstack = (char *)&stackvar;
51 #else
52     savearea->topstack = savearea->ucontext.uc_stack.ss_sp;
53 #endif
54     switch (savearea->state) {
55     case 0:
56         if (newsp) {
57             ucontext_t thread;
58
59             getcontext(&thread);
60             thread.uc_stack.ss_sp =
61                 newsp - AFS_LWP_MINSTACKSIZE + sizeof(void *) +
62                 sizeof(void *);
63             thread.uc_stack.ss_size = AFS_LWP_MINSTACKSIZE - sizeof(void *);
64             makecontext(&thread, ep, 0);
65             setcontext(&thread);
66         } else
67             (*ep) ();
68         break;
69     case 2:
70         break;
71     }
72     return 0;
73 }
74
75 void
76 returnto(struct lwp_context *savearea)
77 {
78     PRE_Block = 0;
79
80     savearea->state = 2;
81     setcontext(&savearea->ucontext);
82 }
83
84 #else
85
86 /*
87  * Magic stack pointer
88  */
89 #if     defined(AFS_SGI64_ENV)
90 # ifdef _BSD_COMPAT
91 #  define LWP_SP 34
92 # else
93 #  define LWP_SP JB_SP
94 # endif
95 #elif   defined(AFS_HPUX_ENV) || defined(AFS_PARISC_LINUX24_ENV)
96 #define LWP_SP  1
97 #elif   defined(AFS_LINUX20_ENV)
98 #if defined(AFS_PPC_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
99 #define LWP_SP 0
100 #elif   defined(AFS_I386_LINUX20_ENV)
101 #define LWP_SP 4
102 #elif   defined(AFS_S390_LINUX20_ENV)
103 #define LWP_SP 9
104 #define LWP_FP 5
105 #elif   defined(AFS_SPARC_LINUX20_ENV)
106 #define LWP_SP 0
107 #define LWP_FP 1
108 #elif   defined(AFS_SPARC64_LINUX20_ENV) && defined(AFS_32BIT_USR_ENV)
109 #define LWP_SP 0
110 #define LWP_FP 1
111 #elif defined(AFS_ALPHA_LINUX20_ENV)
112 #define LWP_SP 8
113 #define LWP_FP 7
114 #elif defined(AFS_PARISC_LINUX24_ENV)
115 #define LWP_SP 19
116 #else
117 #error Unsupported linux LWP system type.
118 #endif
119 #elif   defined(AFS_X86_FBSD_ENV)
120 #define LWP_SP 4
121 #elif   defined(AFS_DARWIN_ENV)
122 #define LWP_SP 16
123 #else
124 Need offset to SP in jmp_buf for this platform.
125 #endif
126 /**
127   * On SGIs the type of the elements of the array passed to setjmp
128   * differs based on the ISA chosen. It is int for mips1 and mips2 and
129   * __uint64_t for mips3 and mips4
130   */
131 #ifdef AFS_SGI64_ENV
132 #if (_MIPS_ISA == _MIPS_ISA_MIPS3 || _MIPS_ISA == _MIPS_ISA_MIPS4)
133 typedef __uint64_t jmp_buf_type;
134 #endif
135 #else
136 #if defined(AFS_ALPHA_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
137 typedef long jmp_buf_type;
138 #else
139 typedef int jmp_buf_type;
140 #endif /*AFS_ALPHA_LINUX20_ENV */
141 #endif /*SGI*/
142
143     static jmp_buf jmp_tmp;
144 static void (*EP) (void);
145 static int rc;
146 static jmp_buf_type *jmpBuffer;
147
148 /** Starting with Glibc 2.4 pointers in jmp_buf are mangled (XOR) for "protection".
149   * On Sparc ucontext functions are not implemented.
150   */
151 #define ptr_mangle(x) (x)
152 #ifdef AFS_LINUX20_ENV
153
154 #ifdef __GLIBC__
155 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 3)
156
157 #if defined(AFS_SPARC64_LINUX24_ENV) || defined(AFS_SPARC_LINUX24_ENV)
158 /* technically we should use POINTER_GUARD
159  * ( == offsetof (tcbhead_t, pointer_guard) )
160  * instead of 0x18
161  */
162 #undef ptr_mangle
163 static int ptr_mangle(int p)
164 {
165     register char *tls_ptr __asm__("%g7");
166     return p ^ *(int*)(tls_ptr + 0x18);
167 }
168 #else
169 #error need ptr_mangle support or use UCONTEXT
170 #endif
171
172 #endif
173 #endif
174 #endif
175
176
177 afs_int32
178 savecontext(void (*ep)(void), struct lwp_context *savearea, char *sp)
179 {
180     int code;
181
182     PRE_Block = 1;
183     EP = ep;
184
185     code = setjmp(savearea->setjmp_buffer);
186     jmpBuffer = (jmp_buf_type *) savearea->setjmp_buffer;
187     savearea->topstack = (char *) ptr_mangle(jmpBuffer[LWP_SP]);
188
189 #if     defined(DEBUG)
190     {
191         int i, *ptr = (int *)savearea->setjmp_buffer;
192         printf("savecontext\n");
193         for (i = 0; i < 5; i++)
194             printf("(%d) 0x%x   ", i, ptr[i]);
195         printf("\n");
196         for (i = 5; i < 10; i++)
197             printf("(%d) 0x%x   ", i, ptr[i]);
198         printf("\n");
199     }
200 #endif
201     switch (code) {
202     case 0:
203         if (!sp)
204             (*EP) ();
205         else {
206             rc = setjmp(jmp_tmp);
207             switch (rc) {
208             case 0:
209                 jmpBuffer = (jmp_buf_type *) jmp_tmp;
210                 jmpBuffer[LWP_SP] = ptr_mangle((jmp_buf_type) sp);
211 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV) || (defined(AFS_SPARC64_LINUX20_ENV) && defined(AFS_32BIT_USR_ENV))
212                 jmpBuffer[LWP_FP] = ptr_mangle((jmp_buf_type) sp);
213 #endif
214                 longjmp(jmp_tmp, 1);
215                 break;
216             case 1:
217                 (*EP) ();
218                 assert(0);      /* never returns */
219                 break;
220             default:
221                 perror("Error in setjmp1\n");
222                 exit(2);
223             }
224         }
225         break;
226     case 2:                     /* restoring frame */
227         break;
228
229     default:
230         perror("Error in setjmp2 : restoring\n");
231         exit(3);
232     }
233     return 0;
234 }
235
236 void
237 returnto(struct lwp_context * savearea)
238 {
239 #if     defined(DEBUG)
240     int i, *ptr = savearea->setjmp_buffer;
241
242     printf("Returning to \n");
243     for (i = 0; i < 5; i++)
244         printf("(%d) 0x%x   ", i, ptr[i]);
245     printf("\n");
246     for (i = 5; i < 10; i++)
247         printf("(%d) 0x%x   ", i, ptr[i]);
248     printf("\n");
249 #endif
250     PRE_Block = 0;
251     longjmp(savearea->setjmp_buffer, 2);
252     return;
253 }
254
255 #endif