Add to git.
[pthrlib.git] / src / pthr_stack.c
1 /* Pseudothread stacks.
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Library General Public
5  * License as published by the Free Software Foundation; either
6  * version 2 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Library General Public License for more details.
12  *
13  * You should have received a copy of the GNU Library General Public
14  * License along with this library; if not, write to the Free
15  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  * $Id: pthr_stack.c,v 1.4 2003/02/05 22:13:33 rich Exp $
18  */
19
20 /* The _PTH_GET_STACK and _PTH_RETURN_STACK functions are responsible
21  * for allocating new stacks and returning them when they are finished.
22  *
23  * We are careful to avoid freeing up a stack while we are actually
24  * using it. This means in particular that the _PTH_RETURN_STACK
25  * function doesn't directly free up the current stack. It will
26  * be freed up instead next time this function is called.
27  *
28  * Linux has the ability to allocate stacks from anonymous memory.
29  * We use this ability if available. However, Linux also has the
30  * ability to allocate "grows down" stack segments using the
31  * non-portable MAP_GROWSDOWN flag. We *don't* use this feature
32  * because (a) LinuxThreads itself doesn't use it any more and
33  * (b) it can cause intermittent failures if something else
34  * happens to allocate memory in the middle of our (as yet
35  * unallocated) stack.
36  *
37  * On Linux we also allocate a guard page to protect against
38  * stack overflow.
39  */
40
41 #include "config.h"
42
43 #include <stdlib.h>
44
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48
49 #ifdef HAVE_SYS_MMAN_H
50 #include <sys/mman.h>
51 #endif
52
53 #include "pthr_stack.h"
54
55 #define GUARD_PAGE_SIZE 8192
56
57 #ifndef MAP_ANONYMOUS
58 #define MAP_ANONYMOUS MAP_ANON
59 #endif
60
61 static inline void *
62 alloc_stack (int size)
63 {
64   void *base;
65
66   /* Allocate the actual stack memory. */
67   base = mmap (0, size, PROT_READ|PROT_WRITE|PROT_EXEC,
68                MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
69   if (base == MAP_FAILED) return 0;
70
71   /* Allocate a guard page right at the bottom of the stack. */
72   if (mprotect (base, GUARD_PAGE_SIZE, 0) == -1) abort ();
73
74   return base;
75 }
76
77 static inline void
78 free_stack (void *base, int size)
79 {
80   munmap (base, size);
81 }
82
83 /* Stack pending deallocation (see notes above). */
84 static void *pending_stack_base = 0;
85 static int pending_stack_size = 0;
86
87 void *
88 _pth_get_stack (int size)
89 {
90   void *base;
91
92   /* Is there a stack waiting to be freed up? If so, free it now. */
93   if (pending_stack_base)
94     {
95       free_stack (pending_stack_base, pending_stack_size);
96       pending_stack_base = 0;
97     }
98
99   /* Allocate a stack of the appropriate size, if available. */
100   base = alloc_stack (size);
101   if (!base) return 0;
102
103   return base;
104 }
105
106 void
107 _pth_return_stack (void *base, int size)
108 {
109   /* Is there a stack waiting to be freed up? If so, free it now. */
110   if (pending_stack_base)
111     {
112       free_stack (pending_stack_base, pending_stack_size);
113       pending_stack_base = 0;
114     }
115
116   /* Don't actually free the stack right now. We're still using it. */
117   pending_stack_base = base;
118   pending_stack_size = size;
119 }