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