1 /* Licensed under Apache License v2.0 - see LICENSE file for details */
2 #ifndef CCAN_ALTSTACK_H
3 #define CCAN_ALTSTACK_H
7 #error "This code expects the AMD64 ABI, but __x86_64__ is false."
11 #include <sys/resource.h>
13 #define ALTSTACK_ERR_MAXLEN 128
16 * altstack - run a function with a dedicated stack, and then release the memory
17 * @max: the maximum size of the new stack
18 * @fn: a function to run
19 * @arg: an argument passed to fn
20 * @out: where to store the return of fn, optional
22 * rlimit is set to @max, and an anonymous noreserve mapping is made.
23 * A jump buffer is setup and a signal handler established for SIGSEGV.
24 * The rsp register is set to the mapped address, with the old rsp value
25 * pushed onto the new stack. The provided @fn is called, with @arg as
26 * its only argument, from non-stack addresses. Once @fn returns,
27 * rsp is popped off the stack. If @out is non-null, it gets the return
28 * value from @fn. The region is unmapped and the other changes undone.
30 * Error messages are appended to a buffer available via altstack_geterr()
31 * and altstack_perror(). errno is set by the failing call, or set to
32 * EOVERFLOW in case SIGSEGV is caught.
34 * altstack() uses thread-local storage, and should not be nested.
37 * // permit recursion depth over a million
38 * // a contrived example! (-O2 replaces the recursion with a loop)
42 * #include <ccan/altstack/altstack.h>
46 * static void dn(unsigned long i)
52 * static void *wrap(void *i)
54 * dn((unsigned long) i);
58 * #define MiB (1024UL*1024UL)
59 * int main(int argc, char *argv[])
63 * n = strtoul(argv[1], 0, 0);
65 * if (altstack(32*MiB, wrap, (void *) n, 0) != 0)
68 * printf("%d\n", depth);
73 * Returns: -1 on error; 0 on success; 1 on error after @fn returns
75 int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out);
78 * altstack_perror - print error messages to stderr
80 void altstack_perror(void);
83 * altstack_geterr - return the error buffer
85 * The error buffer is static thread-local storage.
86 * The buffer is reset with each altstack() call.
88 * Returns: pointer to the error buffer
90 char *altstack_geterr(void);
93 * altstack_used - return amount of stack used
95 * This captures the current rsp value and returns
96 * the difference from the initial rsp value.
98 * Note: this can be used with any stack, including the original.
99 * When using with a non-altstack stack, call altstack_rsp_save()
100 * as early as possible to establish the initial value.
102 * Returns: difference of rsp values
104 ptrdiff_t altstack_used(void);
107 * altstack_max - return usable stack size
109 * Returns: max value from altstack() call
111 rlim_t altstack_max(void);
114 * altstack_remn - return amount of stack remaining
116 * Returns: altstack_max() minus altstack_used()
118 #define altstack_remn() (altstack_max() - altstack_used())
121 * altstack_rsp_save - set initial rsp value
123 * Capture the current value of rsp for future altstack_used()
124 * calculations. altstack() also saves the initial rsp, so
125 * this should only be used in non-altstack contexts.
127 void altstack_rsp_save(void);