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