thr_stack.c revision 141822
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: head/lib/libkse/thread/thr_stack.c 141822 2005-02-13 18:38:06Z deischen $
28 */
29#include <sys/types.h>
30#include <sys/mman.h>
31#include <sys/queue.h>
32#include <stdlib.h>
33#include <pthread.h>
34#include "thr_private.h"
35
36/* Spare thread stack. */
37struct stack {
38	LIST_ENTRY(stack)	qe;		/* Stack queue linkage. */
39	size_t			stacksize;	/* Stack size (rounded up). */
40	size_t			guardsize;	/* Guard size. */
41	void			*stackaddr;	/* Stack address. */
42};
43
44/*
45 * Default sized (stack and guard) spare stack queue.  Stacks are cached
46 * to avoid additional complexity managing mmap()ed stack regions.  Spare
47 * stacks are used in LIFO order to increase cache locality.
48 */
49static LIST_HEAD(, stack)	dstackq = LIST_HEAD_INITIALIZER(dstackq);
50
51/*
52 * Miscellaneous sized (non-default stack and/or guard) spare stack queue.
53 * Stacks are cached to avoid additional complexity managing mmap()ed
54 * stack regions.  This list is unordered, since ordering on both stack
55 * size and guard size would be more trouble than it's worth.  Stacks are
56 * allocated from this cache on a first size match basis.
57 */
58static LIST_HEAD(, stack)	mstackq = LIST_HEAD_INITIALIZER(mstackq);
59
60/**
61 * Base address of the last stack allocated (including its red zone, if
62 * there is one).  Stacks are allocated contiguously, starting beyond the
63 * top of the main stack.  When a new stack is created, a red zone is
64 * typically created (actually, the red zone is mapped with PROT_NONE) above
65 * the top of the stack, such that the stack will not be able to grow all
66 * the way to the bottom of the next stack.  This isn't fool-proof.  It is
67 * possible for a stack to grow by a large amount, such that it grows into
68 * the next stack, and as long as the memory within the red zone is never
69 * accessed, nothing will prevent one thread stack from trouncing all over
70 * the next.
71 *
72 * low memory
73 *     . . . . . . . . . . . . . . . . . .
74 *    |                                   |
75 *    |             stack 3               | start of 3rd thread stack
76 *    +-----------------------------------+
77 *    |                                   |
78 *    |       Red Zone (guard page)       | red zone for 2nd thread
79 *    |                                   |
80 *    +-----------------------------------+
81 *    |  stack 2 - PTHREAD_STACK_DEFAULT  | top of 2nd thread stack
82 *    |                                   |
83 *    |                                   |
84 *    |                                   |
85 *    |                                   |
86 *    |             stack 2               |
87 *    +-----------------------------------+ <-- start of 2nd thread stack
88 *    |                                   |
89 *    |       Red Zone                    | red zone for 1st thread
90 *    |                                   |
91 *    +-----------------------------------+
92 *    |  stack 1 - PTHREAD_STACK_DEFAULT  | top of 1st thread stack
93 *    |                                   |
94 *    |                                   |
95 *    |                                   |
96 *    |                                   |
97 *    |             stack 1               |
98 *    +-----------------------------------+ <-- start of 1st thread stack
99 *    |                                   |   (initial value of last_stack)
100 *    |       Red Zone                    |
101 *    |                                   | red zone for main thread
102 *    +-----------------------------------+
103 *    | USRSTACK - PTHREAD_STACK_INITIAL  | top of main thread stack
104 *    |                                   | ^
105 *    |                                   | |
106 *    |                                   | |
107 *    |                                   | | stack growth
108 *    |                                   |
109 *    +-----------------------------------+ <-- start of main thread stack
110 *                                              (USRSTACK)
111 * high memory
112 *
113 */
114static void *last_stack = NULL;
115
116/*
117 * Round size up to the nearest multiple of
118 * _thr_page_size.
119 */
120static inline size_t
121round_up(size_t size)
122{
123	if (size % _thr_page_size != 0)
124		size = ((size / _thr_page_size) + 1) *
125		    _thr_page_size;
126	return size;
127}
128
129int
130_thr_stack_alloc(struct pthread_attr *attr)
131{
132	struct stack *spare_stack;
133	struct kse *curkse;
134	kse_critical_t crit;
135	size_t stacksize;
136	size_t guardsize;
137	char *stackaddr;
138
139	/*
140	 * Round up stack size to nearest multiple of _thr_page_size so
141	 * that mmap() * will work.  If the stack size is not an even
142	 * multiple, we end up initializing things such that there is
143	 * unused space above the beginning of the stack, so the stack
144	 * sits snugly against its guard.
145	 */
146	stacksize = round_up(attr->stacksize_attr);
147	guardsize = round_up(attr->guardsize_attr);
148
149	attr->stackaddr_attr = NULL;
150	attr->flags &= ~THR_STACK_USER;
151
152	/*
153	 * Use the garbage collector lock for synchronization of the
154	 * spare stack lists and allocations from usrstack.
155	 */
156	crit = _kse_critical_enter();
157	curkse = _get_curkse();
158	KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
159	/*
160	 * If the stack and guard sizes are default, try to allocate a stack
161	 * from the default-size stack cache:
162	 */
163	if ((stacksize == _thr_stack_default) &&
164	    (guardsize == _thr_guard_default)) {
165		if ((spare_stack = LIST_FIRST(&dstackq)) != NULL) {
166			/* Use the spare stack. */
167			LIST_REMOVE(spare_stack, qe);
168			attr->stackaddr_attr = spare_stack->stackaddr;
169		}
170	}
171	/*
172	 * The user specified a non-default stack and/or guard size, so try to
173	 * allocate a stack from the non-default size stack cache, using the
174	 * rounded up stack size (stack_size) in the search:
175	 */
176	else {
177		LIST_FOREACH(spare_stack, &mstackq, qe) {
178			if (spare_stack->stacksize == stacksize &&
179			    spare_stack->guardsize == guardsize) {
180				LIST_REMOVE(spare_stack, qe);
181				attr->stackaddr_attr = spare_stack->stackaddr;
182				break;
183			}
184		}
185	}
186	if (attr->stackaddr_attr != NULL) {
187		/* A cached stack was found.  Release the lock. */
188		KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
189		_kse_critical_leave(crit);
190	}
191	else {
192		/* Allocate a stack from usrstack. */
193		if (last_stack == NULL)
194			last_stack = _usrstack - _thr_stack_initial -
195			    _thr_guard_default;
196
197		/* Allocate a new stack. */
198		stackaddr = last_stack - stacksize - guardsize;
199
200		/*
201		 * Even if stack allocation fails, we don't want to try to
202		 * use this location again, so unconditionally decrement
203		 * last_stack.  Under normal operating conditions, the most
204		 * likely reason for an mmap() error is a stack overflow of
205		 * the adjacent thread stack.
206		 */
207		last_stack -= (stacksize + guardsize);
208
209		/* Release the lock before mmap'ing it. */
210		KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
211		_kse_critical_leave(crit);
212
213		/* Map the stack and guard page together, and split guard
214		   page from allocated space: */
215		if ((stackaddr = mmap(stackaddr, stacksize+guardsize,
216		     PROT_READ | PROT_WRITE, MAP_STACK,
217		     -1, 0)) != MAP_FAILED &&
218		    (guardsize == 0 ||
219		     mprotect(stackaddr, guardsize, PROT_NONE) == 0)) {
220			stackaddr += guardsize;
221		} else {
222			if (stackaddr != MAP_FAILED)
223				munmap(stackaddr, stacksize + guardsize);
224			stackaddr = NULL;
225		}
226		attr->stackaddr_attr = stackaddr;
227	}
228	if (attr->stackaddr_attr != NULL)
229		return (0);
230	else
231		return (-1);
232}
233
234/* This function must be called with _thread_list_lock held. */
235void
236_thr_stack_free(struct pthread_attr *attr)
237{
238	struct stack *spare_stack;
239
240	if ((attr != NULL) && ((attr->flags & THR_STACK_USER) == 0)
241	    && (attr->stackaddr_attr != NULL)) {
242		spare_stack = (attr->stackaddr_attr + attr->stacksize_attr
243		    - sizeof(struct stack));
244		spare_stack->stacksize = round_up(attr->stacksize_attr);
245		spare_stack->guardsize = round_up(attr->guardsize_attr);
246		spare_stack->stackaddr = attr->stackaddr_attr;
247
248		if (spare_stack->stacksize == _thr_stack_default &&
249		    spare_stack->guardsize == _thr_guard_default) {
250			/* Default stack/guard size. */
251			LIST_INSERT_HEAD(&dstackq, spare_stack, qe);
252		} else {
253			/* Non-default stack/guard size. */
254			LIST_INSERT_HEAD(&mstackq, spare_stack, qe);
255		}
256		attr->stackaddr_attr = NULL;
257	}
258}
259