summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2022-02-02 01:12:43 +0300
committerIvan Maidanski <ivmai@mail.ru>2022-02-04 00:29:23 +0300
commit73b67bab7ecc943abd2e3253a26127212442833a (patch)
tree75de90140f8c78edb5637ebb38a73e4bf74705d0
parent6c8923eef141c0de98d369af5ab270caa7d51b67 (diff)
downloadbdwgc-73b67bab7ecc943abd2e3253a26127212442833a.tar.gz
Use mmap to allocate procedure stack buffers on E2K
(fix of commit 990dcdba1) Issue #411 (bdwgc). This commit prevents stack overflow in case of a big procedure stack to be saved. If a procedure stack requires less than 1 memory page for the buffer, then the buffer is still allocated on the local stack. * include/private/gc_priv.h [E2K] (PS_ALLOCA_BUF, ALLOCA_SAFE_LIMIT, FREE_PROCEDURE_STACK_LOCAL): Define macro. * include/private/gc_priv.h [E2K] (PROCEDURE_STACK_ALLOCA_AND_STORE): Rename to GET_PROCEDURE_STACK_LOCAL; update comment; modify implementation to call GC_mmap_procedure_stack_buf (and GC_unmap_procedure_stack_buf) if size > ALLOCA_SAFE_LIMIT. * include/private/gc_priv.h [E2K] (GC_mmap_procedure_stack_buf, GC_unmap_procedure_stack_buf): Declare function. * include/private/gc_priv.h [E2K && THREADS] (GC_alloc_and_get_procedure_stack): Refine comment. * mach_dep.c [E2K]: Include sys/mman.h. * mach_dep.c [E2K] (GC_mmap_procedure_stack_buf, GC_unmap_procedure_stack_buf): Implement. * mark_rts.c [E2K && !THREADS] (GC_push_current_stack): Rename PROCEDURE_STACK_ALLOCA_AND_STORE to GET_PROCEDURE_STACK_LOCAL; call FREE_PROCEDURE_STACK_LOCAL() when bs_lo is not needed. * pthread_stop_world.c [!GC_OPENBSD_UTHREADS && !NACL && E2K] (GC_suspend_handler_inner, GC_push_all_stacks): Likewise.
-rw-r--r--include/private/gc_priv.h64
-rw-r--r--mach_dep.c22
-rw-r--r--mark_rts.c3
-rw-r--r--pthread_stop_world.c12
4 files changed, 83 insertions, 18 deletions
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index d274fcc4..80200259 100644
--- a/include/private/gc_priv.h
+++ b/include/private/gc_priv.h
@@ -1988,25 +1988,65 @@ GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
/* May be called from a signal handler. */
GC_INNER size_t GC_get_procedure_stack(ptr_t, size_t);
- /* Copy procedure (register) stack to a stack-allocated buffer. */
- /* The buffer is freed automatically on the function return. */
- /* May be used from a signal handler. */
-# define PROCEDURE_STACK_ALLOCA_AND_STORE(pbuf, psz) \
+# if defined(CPPCHECK)
+# define PS_ALLOCA_BUF(sz) NULL
+# define ALLOCA_SAFE_LIMIT 0
+# else
+# define PS_ALLOCA_BUF(sz) alloca(sz) /* cannot return NULL */
+# ifndef ALLOCA_SAFE_LIMIT
+# define ALLOCA_SAFE_LIMIT (GC_page_size-16U)
+# endif
+# endif /* !CPPCHECK */
+
+ /* Copy procedure (register) stack to a stack-allocated or */
+ /* memory-mapped buffer. Usable from a signal handler. */
+ /* FREE_PROCEDURE_STACK_LOCAL() must be called with the same */
+ /* *pbuf and *psz values before the caller function returns */
+ /* (thus, the buffer is valid only within the function). */
+# define GET_PROCEDURE_STACK_LOCAL(pbuf, psz) \
do { \
- size_t buf_sz = 0; \
- for (*(pbuf) = NULL; ; buf_sz = *(psz)) { \
- *(psz) = GC_get_procedure_stack(*(pbuf), buf_sz); \
- if (*(psz) <= buf_sz) break; \
- *(pbuf) = alloca(*(psz)); /* cannot return NULL */ \
+ size_t capacity = 0; \
+ GC_ASSERT(GC_page_size != 0); \
+ for (*(pbuf) = NULL; ; capacity = *(psz)) { \
+ *(psz) = GC_get_procedure_stack(*(pbuf), capacity); \
+ if (*(psz) <= capacity) break; \
+ if (*(psz) > ALLOCA_SAFE_LIMIT \
+ || EXPECT(capacity != 0, FALSE)) { \
+ /* Deallocate old buffer if any. */ \
+ if (EXPECT(capacity > ALLOCA_SAFE_LIMIT, FALSE)) \
+ GC_unmap_procedure_stack_buf(*(pbuf),capacity); \
+ *(psz) = ROUNDUP_PAGESIZE(*(psz)); \
+ *(pbuf) = GC_mmap_procedure_stack_buf(*(psz)); \
+ } else { \
+ /* Allocate buffer on the stack if not large. */ \
+ *(pbuf) = PS_ALLOCA_BUF(*(psz)); \
+ } \
+ } \
+ if (capacity > ALLOCA_SAFE_LIMIT \
+ && EXPECT(((capacity - *(psz)) \
+ & ~(GC_page_size-1)) != 0, FALSE)) { \
+ /* Ensure sz value passed to munmap() later */ \
+ /* matches that passed to mmap() above. */ \
+ *(psz) = capacity - (GC_page_size - 1); \
} \
} while (0)
+ /* Indicate that the buffer with copied procedure stack is not needed. */
+# define FREE_PROCEDURE_STACK_LOCAL(buf, sz) \
+ (void)((sz) > ALLOCA_SAFE_LIMIT \
+ ? (GC_unmap_procedure_stack_buf(buf, sz), 0) : 0)
+
+ GC_INNER ptr_t GC_mmap_procedure_stack_buf(size_t);
+ GC_INNER void GC_unmap_procedure_stack_buf(ptr_t, size_t);
+
# ifdef THREADS
/* Allocate a buffer in the GC heap (as an atomic object) and copy */
/* procedure stack there. Assumes the GC allocation lock is held. */
- /* The buffer should be freed with GC_INTERNAL_FREE later when not */
- /* needed (or, alternatively, it could be just garbage-collected). */
- /* Similar to PROCEDURE_STACK_ALLOCA_AND_STORE in other aspects. */
+ /* May trigger a collection (thus, cannot be used in GC_push_roots */
+ /* or in a signal handler). The buffer should be freed with */
+ /* GC_INTERNAL_FREE later when not needed (or, alternatively, it */
+ /* could be just garbage-collected). */
+ /* Similar to GET_PROCEDURE_STACK_LOCAL in other aspects. */
GC_INNER size_t GC_alloc_and_get_procedure_stack(ptr_t *pbuf);
# endif
#endif /* E2K */
diff --git a/mach_dep.c b/mach_dep.c
index 28e44867..ef2df2be 100644
--- a/mach_dep.c
+++ b/mach_dep.c
@@ -28,9 +28,9 @@
#ifdef E2K
# include <errno.h>
-# include <sys/syscall.h>
-
# include <asm/e2k_syswork.h>
+# include <sys/mman.h>
+# include <sys/syscall.h>
# define VA_SIZE 48
# define E2K_PSHTP_SIZE 12
@@ -103,6 +103,24 @@
return NULL;
}
+ GC_INNER ptr_t GC_mmap_procedure_stack_buf(size_t aligned_sz)
+ {
+ void *buf = mmap(NULL, aligned_sz, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, 0 /* fd */, 0 /* offset */);
+ if (MAP_FAILED == buf)
+ ABORT_ARG2("Could not map memory for procedure stack",
+ ": requested %lu bytes, errno= %d",
+ (unsigned long)aligned_sz, errno);
+ return (ptr_t)buf;
+ }
+
+ GC_INNER void GC_unmap_procedure_stack_buf(ptr_t buf, size_t sz)
+ {
+ if (munmap(buf, ROUNDUP_PAGESIZE(sz)) == -1)
+ ABORT_ARG1("munmap failed (for procedure stack space)",
+ ": errno= %d", errno);
+ }
+
# ifdef THREADS
GC_INNER size_t GC_alloc_and_get_procedure_stack(ptr_t *pbuf)
{
diff --git a/mark_rts.c b/mark_rts.c
index 0ed1c379..555387c4 100644
--- a/mark_rts.c
+++ b/mark_rts.c
@@ -840,10 +840,11 @@ STATIC void GC_push_current_stack(ptr_t cold_gc_frame,
ptr_t bs_lo;
size_t stack_size;
- PROCEDURE_STACK_ALLOCA_AND_STORE(&bs_lo, &stack_size);
+ GET_PROCEDURE_STACK_LOCAL(&bs_lo, &stack_size);
GC_push_all_register_sections(bs_lo, bs_lo + stack_size,
TRUE /* eager */,
GC_traced_stack_sect);
+ FREE_PROCEDURE_STACK_LOCAL(bs_lo, stack_size);
}
# endif
# endif /* !THREADS */
diff --git a/pthread_stop_world.c b/pthread_stop_world.c
index 83b70839..c7bbc2bd 100644
--- a/pthread_stop_world.c
+++ b/pthread_stop_world.c
@@ -340,7 +340,7 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED,
if (ao_load_async(&me->suspended_ext)) {
GC_store_stack_ptr(me);
# ifdef E2K
- PROCEDURE_STACK_ALLOCA_AND_STORE(&bs_lo, &stack_size);
+ GET_PROCEDURE_STACK_LOCAL(&bs_lo, &stack_size);
me -> backing_store_end = bs_lo;
me -> backing_store_ptr = bs_lo + stack_size;
# endif
@@ -350,6 +350,7 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED,
GC_log_printf("Continuing %p on GC_resume_thread\n", (void *)self);
# endif
# ifdef E2K
+ FREE_PROCEDURE_STACK_LOCAL(bs_lo, stack_size);
me -> backing_store_ptr = NULL;
me -> backing_store_end = NULL;
# endif
@@ -369,7 +370,7 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED,
}
GC_store_stack_ptr(me);
# ifdef E2K
- PROCEDURE_STACK_ALLOCA_AND_STORE(&bs_lo, &stack_size);
+ GET_PROCEDURE_STACK_LOCAL(&bs_lo, &stack_size);
me -> backing_store_end = bs_lo;
me -> backing_store_ptr = bs_lo + stack_size;
# endif
@@ -414,6 +415,7 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED,
# endif
# ifdef E2K
GC_ASSERT(me -> backing_store_end == bs_lo);
+ FREE_PROCEDURE_STACK_LOCAL(bs_lo, stack_size);
me -> backing_store_ptr = NULL;
me -> backing_store_end = NULL;
# endif
@@ -757,7 +759,7 @@ GC_INNER void GC_push_all_stacks(void)
# elif defined(E2K)
GC_ASSERT(NULL == p -> backing_store_end);
(void)GC_save_regs_in_stack();
- PROCEDURE_STACK_ALLOCA_AND_STORE(&bs_lo, &stack_size);
+ GET_PROCEDURE_STACK_LOCAL(&bs_lo, &stack_size);
bs_hi = bs_lo + stack_size;
# endif
# endif
@@ -834,6 +836,10 @@ GC_INNER void GC_push_all_stacks(void)
traced_stack_sect);
total_size += bs_hi - bs_lo; /* bs_lo <= bs_hi */
# endif
+# ifdef E2K
+ if (THREAD_EQUAL(p -> id, self))
+ FREE_PROCEDURE_STACK_LOCAL(bs_lo, (size_t)(bs_hi - bs_lo));
+# endif
}
}
GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks\n", (int)nthreads);