]> git.pond.sub.org Git - empserver/blob - src/lib/lwp/arch.c
(lwpNewContext) [MAKECONTEXT_SP_HIGH]: Work around makecontext()
[empserver] / src / lib / lwp / arch.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2005, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  arch.c: architecture-dependant process context code
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1994
32  *     Steve McClure, 1994-2000
33  */
34
35 #include <stdlib.h>
36 #include "lwp.h"
37 #include "lwpint.h"
38
39 #if defined(_EMPTH_LWP)
40
41 /*
42  * Implement machine-dependent functions lwpNewContext(),
43  * lwpSwitchContext().
44  */
45
46
47 #if defined UCONTEXT
48
49 /*
50  * Alternate aproach using setcontext and getcontext instead of setjmp
51  * and longjump.  This should work on any SVr4 machine independant of
52  * architecture.
53  */
54
55 int
56 lwpNewContext(struct lwpProc *newp, int stacksz)
57 {
58     char *s;
59     int size, redsize;
60
61     /* Make size a multiple of sizeof(long) to keep things aligned */
62     stacksz = (stacksz + sizeof(long) - 1) & -sizeof(long);
63     /* Add a red zone on each side of the stack for LWP_STACKCHECK */
64     redsize = newp->flags & LWP_STACKCHECK ? LWP_REDZONE : 0;
65     size = stacksz + 2 * redsize;
66
67     s = malloc(size);
68     if (!s)
69         return -1;
70
71     newp->sbtm = s;
72     newp->size = size;
73     newp->ustack = s + redsize;
74     newp->usize = stacksz;
75
76     if (getcontext(&newp->context) < 0) {
77         free(s);
78         return -1;
79     }
80     newp->context.uc_stack.ss_sp = newp->ustack;
81     newp->context.uc_stack.ss_size = newp->usize;
82 #ifdef MAKECONTEXT_SP_HIGH
83     /*
84      * Known systems that are broken that way: Solaris prior to 10,
85      * IRIX.
86      */
87     newp->context.uc_stack.ss_sp += stacksz - 8;
88 #endif
89     newp->context.uc_stack.ss_flags = 0;
90     newp->context.uc_link = NULL;
91     makecontext(&newp->context, lwpEntryPoint, 0);
92     return 0;
93 }
94
95 void
96 lwpSwitchContext(struct lwpProc *oldp, struct lwpProc *nextp)
97 {
98     if (!oldp) {
99         setcontext(&nextp->context);
100         abort();
101     } else {
102         if (swapcontext(&oldp->context, &nextp->context) < 0)
103             abort();
104     }
105 }
106
107 #else  /* !UCONTEXT */
108
109 /*
110  * If lwpSave() and lwpRestore() are #def'd to setjmp() and longjmp(),
111  * then lwpInitContext() needs to set up the jmp_buf for a longjmp(),
112  * similar to setjmp().  To figure that out for another machine, check
113  * their source or reverse engineer.
114  */
115
116 #if defined(hpc)
117
118 #define STKALIGN 64
119
120 static struct lwpProc *tempcontext;
121 static struct lwpProc *initcontext = NULL;
122 static int startpoint;
123
124 static void
125 startcontext(void)
126 {
127     int space[10000];
128     int x;
129
130     startpoint = (void *)&x;
131     if (!setjmp(initcontext->context))
132         longjmp(tempcontext->context, 1);
133
134     if (!setjmp(tempcontext->context))
135         longjmp(LwpCurrent->context, 1);
136
137     lwpEntryPoint();
138 }
139
140 static void
141 lwpInitContext(struct lwpProc *newp, void *sp)
142 {
143     struct lwpProc holder;
144     int endpoint;
145
146     if (initcontext == NULL) {
147         initcontext = malloc(sizeof(struct lwpProc));
148         tempcontext = &holder;
149         if (!setjmp(tempcontext->context))
150             startcontext();
151     }
152
153     tempcontext = newp;
154     endpoint = &endpoint;
155     if (endpoint < startpoint) {
156         if (!setjmp(LwpCurrent->context))
157             longjmp(initcontext->context, 1);
158     } else {
159         LwpCurrent->size = endpoint - startpoint;
160         LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
161         memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
162         if (!setjmp(LwpCurrent->context))
163             longjmp(initcontext->context, 1);
164         memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
165     }
166 }
167
168 static int
169 lwpSave(jmp_buf jb)
170 {
171     int endpoint;
172
173     endpoint = &endpoint;
174     if (initcontext == NULL || endpoint < startpoint)
175         return setjmp(jb, 1);
176
177     LwpCurrent->size = endpoint - startpoint;
178     LwpCurrent->sbtm = realloc(LwpCurrent->sbtm, LwpCurrent->size);
179     memcpy(LwpCurrent->sbtm, startpoint, LwpCurrent->size);
180     if (setjmp(jb, 1)) {
181         memcpy(startpoint, LwpCurrent->sbtm, LwpCurrent->size);
182         return 1;
183     }
184     return 0;
185 }
186
187 #elif defined(hpux)
188
189 #define STKALIGN 64
190
191 static void
192 lwpInitContext(volatile struct lwpProc *volatile newp, void *sp)
193 {
194     static jmp_buf *cpp;
195
196     if (!lwpSave(LwpCurrent->context)) {
197         cpp = (jmp_buf *)&newp->context;
198         asm volatile ("ldw      %0, %%sp"::"o" (sp));
199         if (!lwpSave(*cpp))
200             lwpRestore(LwpCurrent->context);
201         lwpEntryPoint();
202     }
203 }
204
205 static int
206 lwpSave(jmp_buf jb)
207 {
208     /* save stack pointer and return program counter */
209     asm("stw    %sp, 4(%arg0)");
210     asm("stw    %rp, 8(%arg0)");
211
212     /* save "callee save" registers */
213     asm("stw    %r3, 12(%arg0)");
214     asm("stw    %r4, 16(%arg0)");
215     asm("stw    %r5, 20(%arg0)");
216     asm("stw    %r6, 24(%arg0)");
217     asm("stw    %r7, 28(%arg0)");
218     asm("stw    %r8, 32(%arg0)");
219     asm("stw    %r9, 36(%arg0)");
220     asm("stw    %r10, 40(%arg0)");
221     asm("stw    %r11, 44(%arg0)");
222     asm("stw    %r12, 48(%arg0)");
223     asm("stw    %r13, 52(%arg0)");
224     asm("stw    %r14, 56(%arg0)");
225     asm("stw    %r15, 60(%arg0)");
226     asm("stw    %r16, 64(%arg0)");
227     asm("stw    %r17, 68(%arg0)");
228     asm("stw    %r18, 72(%arg0)");
229
230     /* save "callee save" space register */
231     asm volatile ("mfsp %sr3, %r1");
232     asm("stw    %r1, 0(%arg0)");
233
234     /* indicate "true return" from saved() */
235     asm("ldi    0, %ret0");
236
237     asm(".LABEL _comefrom_");
238 }
239
240 static void
241 lwpRestore(jmp_buf jb)
242 {
243     /* restore stack pointer and program counter */
244     asm volatile ("ldw  4(%arg0), %sp");
245     asm volatile ("ldw  8(%arg0), %rp");
246
247     /* restore "callee save" space register */
248     asm volatile ("ldw  0(%arg0), %r1");
249     asm volatile ("mtsp %r1, %sr3");
250
251     /* restore "callee save" registers */
252     asm volatile ("ldw  12(%arg0), %r3");
253     asm volatile ("ldw  16(%arg0), %r4");
254     asm volatile ("ldw  20(%arg0), %r5");
255     asm volatile ("ldw  24(%arg0), %r6");
256     asm volatile ("ldw  28(%arg0), %r7");
257     asm volatile ("ldw  32(%arg0), %r8");
258     asm volatile ("ldw  36(%arg0), %r9");
259     asm volatile ("ldw  40(%arg0), %r10");
260     asm volatile ("ldw  44(%arg0), %r11");
261     asm volatile ("ldw  48(%arg0), %r12");
262     asm volatile ("ldw  52(%arg0), %r13");
263     asm volatile ("ldw  56(%arg0), %r14");
264     asm volatile ("ldw  60(%arg0), %r15");
265     asm volatile ("ldw  64(%arg0), %r16");
266     asm volatile ("ldw  68(%arg0), %r17");
267     asm volatile ("ldw  72(%arg0), %r18");
268
269     /* warp to saved() to unwind the frame correctly */
270     asm volatile ("bl   _comefrom_, %r0");
271     asm volatile ("ldi  1, %ret0");
272 }
273
274 #elif defined(FBSD)
275
276 static void
277 lwpInitContext(struct lwpProc *newp, void *sp)
278 {
279     setjmp(newp->context);
280     newp->context->_jb[2] = (int)sp;
281     newp->context->_jb[3] = (int)sp;
282     newp->context->_jb[0] = (int)lwpEntryPoint;
283 }
284
285 #elif defined(__linux__)
286
287 static void
288 lwpInitContext(struct lwpProc *newp, void *sp)
289 {
290 #if defined(__GLIBC__) && (__GLIBC__ >= 2)
291 #if defined(__PPC__)
292     newp->context->__jmpbuf[JB_GPR1] = (int)sp;
293     newp->context->__jmpbuf[JB_LR] = (int)lwpEntryPoint;
294 #else
295     newp->context->__jmpbuf[JB_SP] = (int)sp;
296     newp->context->__jmpbuf[JB_BP] = (int)sp;
297     newp->context->__jmpbuf[JB_PC] = (int)lwpEntryPoint;
298 #endif
299 #else
300     newp->context->__sp = sp;
301     newp->context->__bp = sp;
302     newp->context->__pc = (void *)lwpEntryPoint;
303 #endif
304 }
305
306 #elif defined(SUN3)
307
308 static void
309 lwpInitContext(struct lwpProc *newp, void *sp)
310 {
311     newp->context[2] = (int)sp;
312     newp->context[3] = (int)lwpEntryPoint;
313 }
314
315 #elif defined(SUN4)
316
317 static void
318 lwpInitContext(struct lwpProc *newp, void *sp)
319 {
320     static jmp_buf *cpp;
321
322     memset(newp->context, 0, sizeof(newp->context));
323     newp->context[0] = (int)sp;
324     /* preserve cpp for new context */
325     cpp = (jmp_buf *) & newp->context;
326     if (!_setjmp(LwpCurrent->context)) {
327         /* create new context */
328         /* flush registers */
329         asm("ta 0x03");
330         /* %o0 <- newp */
331         asm("ld [%fp+0x44], %o0");
332         /* %o1 <- newp->context[0] */
333         asm("ld [%o0], %o1");
334         /* create min frame on new stack */
335         asm("save       %o1,-96, %sp");
336         if (!_setjmp(*cpp))
337             _longjmp(LwpCurrent->context, 1);
338         lwpEntryPoint();
339     }
340 }
341
342 #define lwpSave(x)      _setjmp(x)
343 #define lwpRestore(x)   _longjmp(x, 1)
344
345 #elif defined(ALPHA)
346
347 #include <c_asm.h>
348
349 static void
350 lwpInitContext(struct lwpProc *newp, void *sp)
351 {
352     extern long *_gp;
353
354     /* register values obtained from setjmp.h */
355     _setjmp(newp->context);
356     newp->context[2] = (long)lwpEntryPoint;     /* program counter */
357     newp->context[30] = (long)lwpEntryPoint;    /* return address */
358     newp->context[31] = (long)lwpEntryPoint;    /* fake program value (!) */
359     newp->context[34] = (long)sp;       /* stack pointer */
360 }
361
362 static int
363 lwpSave(jmp_buf jb)
364 {
365     return _setjmp(jb);
366 }
367
368 static void
369 lwpRestore(jmp_buf jb)
370 {
371     /* resume, but get the pv from the jmp_buf */
372     asm("ldq    %pv, 248(%a0)");
373     asm("stq    %a0, 16(%sp)");
374     /* generates a warning, but functions just fine */
375     asm("bsr    %ra, __longjump_resume");
376 }
377
378 #elif defined(AIX32)
379
380 #define LWP_EXTRASTACK 12
381
382 /* Code is in .s files, as compiler doesn't grok asm */
383 extern int lwpSave(jmp_buf);
384 extern void lwpRestore(jmp_buf);
385 extern void lwpInitContext(struct lwpProc *);
386
387 #endif
388
389 #ifndef LWP_EXTRASTACK
390 #define LWP_EXTRASTACK 0
391 #endif
392 #ifndef STKALIGN
393 #define STKALIGN sizeof(double)
394 #endif
395 #ifndef lwpSave
396 #define lwpSave(x)      setjmp(x)
397 #endif
398 #ifndef lwpRestore
399 #define lwpRestore(x)   longjmp(x, 1)
400 #endif
401
402 int
403 lwpNewContext(struct lwpProc *newp, int stacksz)
404 {
405     char *s, *sp;
406     int size, redsize;
407
408     if (CANT_HAPPEN(STKALIGN == 0|| (STKALIGN & (STKALIGN - 1))))
409         return -1;              /* STKALIGN not power of 2 */
410
411     /* Make size a multiple of sizeof(long) to keep things aligned */
412     stacksz = (stacksz + sizeof(long) - 1) & -sizeof(long);
413     /* Add a red zone on each side of the stack for LWP_STACKCHECK */
414     redsize = newp->flags & LWP_STACKCHECK ? LWP_REDZONE : 0;
415     size = stacksz + 2 * redsize + LWP_EXTRASTACK + STKALIGN - 1;
416
417     s = malloc(size);
418     if (!s)
419         return -1;
420
421     if (LwpStackGrowsDown) {
422         /*
423          * Stack layout for stack growing downward:
424          *     ptr        block      size
425          *     --------------------------------------
426          *                red zone   LWP_REDZONE
427          *     sp      -> extra      LWP_EXTRASTACK
428          *     ustack  -> stack      stacksz
429          *                red zone   LWP_REDZONE
430          *                waste      STKALIGN - 1 - x
431          * sp is aligned to a multiple of STKALIGN.
432          */
433         sp = s + redsize + stacksz;
434         sp = (char *)0 + (((sp + STKALIGN - 1) - (char *)0) & -STKALIGN);
435         newp->ustack = sp - stacksz;
436     } else {
437         /*
438          * Stack layout for stack growing upward:
439          *     ptr        block      size
440          *     --------------------------------------
441          *                waste      x
442          *                red zone   LWP_REDZONE
443          *     sp      -> stack      stacksz
444          *     ustack  -> extra      LWP_EXTRASTACK
445          *                red zone   LWP_REDZONE
446          *                waste      STKALIGN - 1 - x
447          * sp is aligned to a multiple of STKALIGN.
448          */
449         sp = s + redsize + LWP_EXTRASTACK;
450         sp = (char *)0 + (((sp + STKALIGN - 1) - (char *)0) & -STKALIGN);
451         newp->ustack = sp - LWP_EXTRASTACK;
452     }
453     newp->sbtm = s;
454     newp->size = size;
455     newp->usize = stacksz + LWP_EXTRASTACK;
456     lwpInitContext(newp, sp);
457     return 0;
458 }
459
460 void
461 lwpSwitchContext(struct lwpProc *oldp, struct lwpProc *nextp)
462 {
463     if (!(oldp && lwpSave(oldp->context)))
464         lwpRestore(nextp->context);
465 }
466
467 #endif /* !UCONTEXT */
468
469 #endif