xref: /openbsd-src/lib/librthread/rthread_stack.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /* $OpenBSD: rthread_stack.c,v 1.4 2010/05/26 21:40:05 guenther Exp $ */
2 /* $snafu: rthread_stack.c,v 1.12 2005/01/11 02:45:28 marc Exp $ */
3 
4 /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
5 
6 #include <sys/types.h>
7 #include <sys/mman.h>
8 
9 #include <machine/param.h>
10 #include <machine/spinlock.h>
11 
12 #include <errno.h>
13 #include <pthread.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 
17 #include "rthread.h"
18 
19 struct stack *
20 _rthread_alloc_stack(pthread_t thread)
21 {
22 	struct stack *stack;
23 	caddr_t base;
24 	caddr_t guard;
25 	caddr_t start = NULL;
26 	size_t pgsz;
27 	size_t size;
28 
29 	/* guard pages are forced to a multiple of the page size */
30 	pgsz = sysconf(_SC_PAGESIZE);
31 	if (pgsz == (size_t)-1)
32 		return NULL;
33 
34 	/* figure out the actual requested size, including guard size */
35 	size = thread->attr.stack_size + thread->attr.guard_size;
36 	size += pgsz - 1;
37 	size &= ~(pgsz - 1);
38 
39 	/*
40 	 * Allocate some stack space unless an address was provided.
41 	 * A provided address is ASSUMED to be correct with respect to
42 	 * alignment constraints.
43 	 */
44 	if (size > thread->attr.guard_size) {
45 		if (thread->attr.stack_addr)
46 			base = thread->attr.stack_addr;
47 		else {
48 			base = mmap(NULL, size, PROT_READ | PROT_WRITE,
49 				    MAP_ANON, -1, 0);
50 			if (base == MAP_FAILED)
51 				return (NULL);
52 		}
53 		/* memory protect the guard region */
54 
55 #ifdef MACHINE_STACK_GROWS_UP
56 		guard = base + size - thread->attr.guard_size;
57 		start = base;
58 #else
59 		guard = base;
60 		start = base + size;
61 #endif
62 		if (mprotect(guard, thread->attr.guard_size, PROT_NONE) == -1) {
63 			munmap(base, size);
64 			return (NULL);
65 		}
66 
67 		/* wrap up the info in a struct stack and return it */
68 		stack = malloc(sizeof(*stack));
69 		if (!stack) {
70 			munmap(base, size);
71 			return (NULL);
72 		}
73 		stack->sp = start;
74 		stack->base = base;
75 		stack->guard = guard;
76 		stack->guardsize = thread->attr.guard_size;
77 		stack->len = size;
78 		return (stack);
79 	}
80 	errno = EINVAL;
81 	return (NULL);
82 }
83 
84 void
85 _rthread_free_stack(struct stack *stack)
86 {
87 	munmap(stack->base, stack->len);
88 	free(stack);
89 }
90 
91