]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libc_r/uthread/uthread_stack.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libc_r / uthread / uthread_stack.c
1 /*
2  * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>
3  * Copyright (c) 2000-2001 Jason Evans <jasone@freebsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 #include "namespace.h"
30 #include <sys/types.h>
31 #include <sys/mman.h>
32 #include <sys/param.h>
33 #include <sys/queue.h>
34 #include <stdlib.h>
35 #include <pthread.h>
36 #include "un-namespace.h"
37
38 #include "pthread_private.h"
39
40 /* Spare thread stack. */
41 struct stack {
42         LIST_ENTRY(stack)       qe;             /* Stack queue linkage. */
43         size_t                  stacksize;      /* Stack size (rounded up). */
44         size_t                  guardsize;      /* Guard size. */
45         void                    *stackaddr;     /* Stack address. */
46 };
47
48 /*
49  * Default sized (stack and guard) spare stack queue.  Stacks are cached to
50  * avoid additional complexity managing mmap()ed stack regions.  Spare stacks
51  * are used in LIFO order to increase cache locality.
52  */
53 static LIST_HEAD(, stack)       _dstackq = LIST_HEAD_INITIALIZER(_dstackq);
54
55 /*
56  * Miscellaneous sized (non-default stack and/or guard) spare stack queue.
57  * Stacks are cached to avoid additional complexity managing mmap()ed stack
58  * regions.  This list is unordered, since ordering on both stack size and guard
59  * size would be more trouble than it's worth.  Stacks are allocated from this
60  * cache on a first size match basis.
61  */
62 static LIST_HEAD(, stack)       _mstackq = LIST_HEAD_INITIALIZER(_mstackq);
63
64 /**
65  * Base address of the last stack allocated (including its red zone, if there is
66  * one).  Stacks are allocated contiguously, starting beyond the top of the main
67  * stack.  When a new stack is created, a red zone is typically created
68  * (actually, the red zone is simply left unmapped) above the top of the stack,
69  * such that the stack will not be able to grow all the way to the bottom of the
70  * next stack.  This isn't fool-proof.  It is possible for a stack to grow by a
71  * large amount, such that it grows into the next stack, and as long as the
72  * memory within the red zone is never accessed, nothing will prevent one thread
73  * stack from trouncing all over the next.
74  *
75  * low memory
76  *     . . . . . . . . . . . . . . . . . . 
77  *    |                                   |
78  *    |             stack 3               | start of 3rd thread stack
79  *    +-----------------------------------+
80  *    |                                   |
81  *    |       Red Zone (guard page)       | red zone for 2nd thread
82  *    |                                   |
83  *    +-----------------------------------+
84  *    |  stack 2 - _pthread_stack_default | top of 2nd thread stack
85  *    |                                   |
86  *    |                                   |
87  *    |                                   |
88  *    |                                   |
89  *    |             stack 2               |
90  *    +-----------------------------------+ <-- start of 2nd thread stack
91  *    |                                   |
92  *    |       Red Zone                    | red zone for 1st thread
93  *    |                                   |
94  *    +-----------------------------------+
95  *    |  stack 1 - _pthread_stack_default | top of 1st thread stack
96  *    |                                   |
97  *    |                                   |
98  *    |                                   |
99  *    |                                   |
100  *    |             stack 1               |
101  *    +-----------------------------------+ <-- start of 1st thread stack
102  *    |                                   |   (initial value of last_stack)
103  *    |       Red Zone                    |
104  *    |                                   | red zone for main thread
105  *    +-----------------------------------+
106  *    | USRSTACK - _pthread_stack_initial | top of main thread stack
107  *    |                                   | ^
108  *    |                                   | |
109  *    |                                   | |
110  *    |                                   | | stack growth
111  *    |                                   |
112  *    +-----------------------------------+ <-- start of main thread stack
113  *                                              (USRSTACK)
114  * high memory
115  *
116  */
117 static void *   last_stack;
118
119 void *
120 _thread_stack_alloc(size_t stacksize, size_t guardsize)
121 {
122         void            *stack = NULL;
123         struct stack    *spare_stack;
124         size_t          stack_size;
125
126         /*
127          * Round up stack size to nearest multiple of _pthread_page_size,
128          * so that mmap() * will work.  If the stack size is not an even
129          * multiple, we end up initializing things such that there is unused
130          * space above the beginning of the stack, so the stack sits snugly
131          * against its guard.
132          */
133         if (stacksize % _pthread_page_size != 0)
134                 stack_size = ((stacksize / _pthread_page_size) + 1) *
135                     _pthread_page_size;
136         else
137                 stack_size = stacksize;
138
139         /*
140          * If the stack and guard sizes are default, try to allocate a stack
141          * from the default-size stack cache:
142          */
143         if (stack_size == _pthread_stack_default &&
144             guardsize == _pthread_guard_default) {
145                 /*
146                  * Use the garbage collector mutex for synchronization of the
147                  * spare stack list.
148                  */
149                 if (_pthread_mutex_lock(&_gc_mutex) != 0)
150                         PANIC("Cannot lock gc mutex");
151
152                 if ((spare_stack = LIST_FIRST(&_dstackq)) != NULL) {
153                                 /* Use the spare stack. */
154                         LIST_REMOVE(spare_stack, qe);
155                         stack = spare_stack->stackaddr;
156                 }
157
158                 /* Unlock the garbage collector mutex. */
159                 if (_pthread_mutex_unlock(&_gc_mutex) != 0)
160                         PANIC("Cannot unlock gc mutex");
161         }
162         /*
163          * The user specified a non-default stack and/or guard size, so try to
164          * allocate a stack from the non-default size stack cache, using the
165          * rounded up stack size (stack_size) in the search:
166          */
167         else {
168                 /*
169                  * Use the garbage collector mutex for synchronization of the
170                  * spare stack list.
171                  */
172                 if (_pthread_mutex_lock(&_gc_mutex) != 0)
173                         PANIC("Cannot lock gc mutex");
174
175                 LIST_FOREACH(spare_stack, &_mstackq, qe) {
176                         if (spare_stack->stacksize == stack_size &&
177                             spare_stack->guardsize == guardsize) {
178                                 LIST_REMOVE(spare_stack, qe);
179                                 stack = spare_stack->stackaddr;
180                                 break;
181                         }
182                 }
183
184                 /* Unlock the garbage collector mutex. */
185                 if (_pthread_mutex_unlock(&_gc_mutex) != 0)
186                         PANIC("Cannot unlock gc mutex");
187         }
188
189         /* Check if a stack was not allocated from a stack cache: */
190         if (stack == NULL) {
191
192                 if (last_stack == NULL)
193                         last_stack = _usrstack - _pthread_stack_initial -
194                             _pthread_guard_default;
195
196                 /* Allocate a new stack. */
197                 stack = last_stack - stack_size;
198
199                 /*
200                  * Even if stack allocation fails, we don't want to try to use
201                  * this location again, so unconditionally decrement
202                  * last_stack.  Under normal operating conditions, the most
203                  * likely reason for an mmap() error is a stack overflow of the
204                  * adjacent thread stack.
205                  */
206                 last_stack -= (stack_size + guardsize);
207
208                 /* Stack: */
209                 if (mmap(stack, stack_size, PROT_READ | PROT_WRITE, MAP_STACK,
210                     -1, 0) == MAP_FAILED)
211                         stack = NULL;
212         }
213
214         return (stack);
215 }
216
217 /* This function must be called with _gc_mutex held. */
218 void
219 _thread_stack_free(void *stack, size_t stacksize, size_t guardsize)
220 {
221         struct stack    *spare_stack;
222
223         spare_stack = (stack + stacksize - sizeof(struct stack));
224         /* Round stacksize up to nearest multiple of _pthread_page_size. */
225         if (stacksize % _pthread_page_size != 0) {
226                 spare_stack->stacksize =
227                     ((stacksize / _pthread_page_size) + 1) *
228                     _pthread_page_size;
229         } else
230                 spare_stack->stacksize = stacksize;
231         spare_stack->guardsize = guardsize;
232         spare_stack->stackaddr = stack;
233
234         if (spare_stack->stacksize == _pthread_stack_default &&
235             spare_stack->guardsize == _pthread_guard_default) {
236                 /* Default stack/guard size. */
237                 LIST_INSERT_HEAD(&_dstackq, spare_stack, qe);
238         } else {
239                 /* Non-default stack/guard size. */
240                 LIST_INSERT_HEAD(&_mstackq, spare_stack, qe);
241         }
242 }