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