aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--get_stack_direction.c62
-rw-r--r--get_stack_limit.c74
-rw-r--r--get_stack_space.c71
-rw-r--r--libsimple.h1
-rw-r--r--libsimple/stack.h11
-rw-r--r--needstack.c53
7 files changed, 277 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 5a2ada3..8e0048c 100644
--- a/Makefile
+++ b/Makefile
@@ -53,6 +53,7 @@ SUBHDR =\
libsimple/realloc.h\
libsimple/search.h\
libsimple/sort.h\
+ libsimple/stack.h\
libsimple/str.h\
libsimple/strdup.h\
libsimple/strn.h\
@@ -552,6 +553,9 @@ OBJ =\
fexecv.o\
freadlink.o\
generate_seed.o\
+ get_stack_direction.o\
+ get_stack_limit.o\
+ get_stack_space.o\
getcwd.o\
getenv_e.o\
getenv_ne.o\
@@ -639,6 +643,7 @@ OBJ =\
minimise_number_string.o\
multimespec.o\
multimeval.o\
+ needstack.o\
posix_memalignn.o\
posix_memalignz.o\
posix_memalignzn.o\
diff --git a/get_stack_direction.c b/get_stack_direction.c
new file mode 100644
index 0000000..2f639da
--- /dev/null
+++ b/get_stack_direction.c
@@ -0,0 +1,62 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+#ifdef SUPPORTED
+# undef SUPPORTED
+#endif
+
+
+#if defined(__GNUC__)
+# define SUPPORTED
+
+__attribute__((__noinline__))
+static void *
+get_callee_frame_address(void)
+{
+ return __builtin_frame_address(0);
+}
+
+
+__attribute__((__noinline__))
+static int
+get_stack_direction(void)
+{
+ void *callerptr, *calleeptr;
+ uintptr_t caller, callee;
+ callerptr = __builtin_frame_address(0);
+ calleeptr = get_callee_frame_address();
+ caller = (uintptr_t)callerptr;
+ callee = (uintptr_t)calleeptr;
+ return callee > caller ? +1 : callee < caller ? -1 : 0;
+}
+
+#endif
+
+
+int
+libsimple_get_stack_direction(void)
+{
+#ifdef SUPPORTED
+ int r = get_stack_direction();
+ if (!r)
+ errno = ENOTSUP;
+ return r;
+#else
+ errno = ENOTSUP;
+ return 0;
+#endif
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/get_stack_limit.c b/get_stack_limit.c
new file mode 100644
index 0000000..363147a
--- /dev/null
+++ b/get_stack_limit.c
@@ -0,0 +1,74 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+int
+libsimple_get_stack_limit(size_t *restrict soft, size_t *restrict hard)
+{
+ char buf[4096], *line;
+ int fd;
+ ssize_t r;
+ size_t off = 0;
+ size_t lineoff, linelen;
+
+ fd = open("/proc/self/limits", O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ for (;;) {
+ read_again:
+ r = read(fd, &buf[off], sizeof(buf) - off);
+ if (r <= 0) {
+ if (r && errno == EINTR)
+ continue;
+ close(fd);
+ if (!r)
+ errno = EIO;
+ return -1;
+ }
+ off += (size_t)r;
+
+ for (lineoff = 0; lineoff < off; lineoff += linelen) {
+ char *lf = strchr(&buf[lineoff], '\n');
+ if (!lf) {
+ memmove(&buf[0], &buf[lineoff], off -= lineoff);
+ goto read_again;
+ }
+ line = &buf[lineoff];
+ linelen = (size_t)(&lf[1] - line);
+ if (linelen > sizeof("Max stack size ") - 1U)
+ if (!strcmp(line, "Max stack size "))
+ goto line_found;
+ }
+
+ }
+
+line_found:
+ close(fd);
+ line = &line[sizeof("Max stack size ") - 1U];
+
+ while (*line == ' ')
+ line++;
+ if (soft)
+ *soft = (size_t)strtoull(line, NULL, 10);
+
+ while (*line == ' ')
+ line++;
+ if (hard)
+ *hard = (size_t)strtoull(line, NULL, 10);
+
+ return 0;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/get_stack_space.c b/get_stack_space.c
new file mode 100644
index 0000000..7f1fdd3
--- /dev/null
+++ b/get_stack_space.c
@@ -0,0 +1,71 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+int
+libsimple_get_stack_space(uintptr_t *restrict low, uintptr_t *restrict high)
+{
+ char buf[4096], *line;
+ int fd;
+ ssize_t r;
+ size_t off = 0;
+ size_t lineoff, linelen;
+
+ fd = open("/proc/self/maps", O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ for (;;) {
+ read_again:
+ r = read(fd, &buf[off], sizeof(buf) - off);
+ if (r <= 0) {
+ if (r && errno == EINTR)
+ continue;
+ close(fd);
+ if (!r)
+ errno = EIO;
+ return -1;
+ }
+ off += (size_t)r;
+
+ for (lineoff = 0; lineoff < off; lineoff += linelen) {
+ char *lf = strchr(&buf[lineoff], '\n');
+ if (!lf) {
+ memmove(&buf[0], &buf[lineoff], off -= lineoff);
+ goto read_again;
+ }
+ line = &buf[lineoff];
+ linelen = (size_t)(&lf[1] - line);
+ if (linelen > sizeof(" [stack]\n") - 1U)
+ if (!strcmp(&line[linelen - (sizeof(" [stack]\n") - 1U)], " [stack]\n"))
+ goto line_found;
+ }
+
+ }
+
+line_found:
+ close(fd);
+
+ *low = (uintptr_t)strtoumax(line, &line, 16);
+ *high = (uintptr_t)strtoumax(&line[1], &line, 16);
+ if (*low > *high) {
+ *low ^= *high;
+ *high ^= *low;
+ *low ^= *high;
+ }
+
+ return 0;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/libsimple.h b/libsimple.h
index 1b22653..5758582 100644
--- a/libsimple.h
+++ b/libsimple.h
@@ -172,6 +172,7 @@
#include "libsimple/ascii.h"
#include "libsimple/exec.h"
#include "libsimple/sort.h"
+#include "libsimple/stack.h"
/**
diff --git a/libsimple/stack.h b/libsimple/stack.h
new file mode 100644
index 0000000..0562e7f
--- /dev/null
+++ b/libsimple/stack.h
@@ -0,0 +1,11 @@
+/* See LICENSE file for copyright and license details. */
+
+
+int libsimple_get_stack_space(uintptr_t *restrict, uintptr_t *restrict); /* TODO man, doc */
+int libsimple_get_stack_limit(size_t *restrict, size_t *restrict); /* TODO man, doc */
+int libsimple_get_stack_direction(void); /* TODO man, doc */
+
+int libsimple_needstack(size_t); /* TODO man, doc */
+#ifndef needstack
+# define needstack libsimple_needstack
+#endif
diff --git a/needstack.c b/needstack.c
new file mode 100644
index 0000000..11d8ed4
--- /dev/null
+++ b/needstack.c
@@ -0,0 +1,53 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+int
+libsimple_needstack(size_t n)
+{
+ size_t limit1, limit2, limit, used;
+ uintptr_t low, high, current;
+ void *currentptr;
+
+ currentptr = __builtin_frame_address(0);
+ current = (uintptr_t)currentptr;
+ if (libsimple_get_stack_space(&low, &high))
+ return -1;
+ if (libsimple_get_stack_limit(&limit1, NULL))
+ return -1;
+ limit2 = (size_t)(high - low);
+ limit = limit1 < limit2 ? limit1 : limit2;
+
+ switch (libsimple_get_stack_direction()) {
+ case +1:
+ if (current < low)
+ goto enotsup;
+ used = (size_t)(current - low);
+ break;
+ case -1:
+ if (current > high)
+ goto enotsup;
+ used = (size_t)(high - current);
+ break;
+ default:
+ enotsup:
+ errno = ENOTSUP;
+ return -1;
+ }
+
+ /* TODO it would be nice to be able to grow the stack */
+ return used <= limit && n <= limit - used;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif