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