2017-03-08 23:59:10 +00:00
|
|
|
/* Stack allocation implementation for coroutine contexts.
|
|
|
|
*
|
2017-04-06 18:14:52 +00:00
|
|
|
* This file is part of libostd. See COPYING.md for futher information.
|
2017-03-08 23:59:10 +00:00
|
|
|
*/
|
|
|
|
|
2017-04-09 14:44:45 +00:00
|
|
|
#include <cstddef>
|
2017-03-08 23:59:10 +00:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <new>
|
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
#include "ostd/internal/win32.hh"
|
|
|
|
#include "ostd/platform.hh"
|
|
|
|
#include "ostd/context_stack.hh"
|
|
|
|
|
|
|
|
#ifdef OSTD_PLATFORM_POSIX
|
|
|
|
# include <unistd.h>
|
|
|
|
# include <sys/mman.h>
|
|
|
|
# include <sys/resource.h>
|
|
|
|
# include <sys/time.h>
|
|
|
|
# include <signal.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace ostd {
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
#ifdef OSTD_PLATFORM_POSIX
|
|
|
|
# if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
|
|
|
|
constexpr bool CONTEXT_USE_MMAP = true;
|
|
|
|
# ifdef MAP_ANON
|
|
|
|
constexpr auto CONTEXT_MAP_ANON = MAP_ANON;
|
|
|
|
# else
|
|
|
|
constexpr auto CONTEXT_MAP_ANON = MAP_ANONYMOUS;
|
|
|
|
# endif
|
|
|
|
# else
|
|
|
|
constexpr bool CONTEXT_USE_MMAP = false;
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2017-04-09 14:44:45 +00:00
|
|
|
OSTD_EXPORT void *stack_alloc(std::size_t sz) {
|
2017-03-08 23:59:10 +00:00
|
|
|
#if defined(OSTD_PLATFORM_WIN32)
|
|
|
|
void *p = VirtualAlloc(0, sz, MEM_COMMIT, PAGE_READWRITE);
|
|
|
|
if (!p) {
|
2017-03-10 02:05:05 +00:00
|
|
|
throw std::bad_alloc{};
|
2017-03-08 23:59:10 +00:00
|
|
|
}
|
|
|
|
return p;
|
|
|
|
#elif defined(OSTD_PLATFORM_POSIX)
|
|
|
|
if constexpr(CONTEXT_USE_MMAP) {
|
|
|
|
void *p = mmap(
|
|
|
|
0, sz, PROT_READ | PROT_WRITE,
|
|
|
|
MAP_PRIVATE | CONTEXT_MAP_ANON, -1, 0
|
|
|
|
);
|
|
|
|
if (p == MAP_FAILED) {
|
|
|
|
throw std::bad_alloc{};
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
void *p = std::malloc(sz);
|
|
|
|
if (!p) {
|
|
|
|
throw std::bad_alloc{};
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-04-09 14:44:45 +00:00
|
|
|
OSTD_EXPORT void stack_free(void *p, std::size_t sz) noexcept {
|
2017-03-08 23:59:10 +00:00
|
|
|
#if defined(OSTD_PLATFORM_WIN32)
|
|
|
|
(void)sz;
|
|
|
|
VirtualFree(p, 0, MEM_RELEASE);
|
|
|
|
#elif defined(OSTD_PLATFORM_POSIX)
|
|
|
|
if constexpr(CONTEXT_USE_MMAP) {
|
|
|
|
munmap(p, sz);
|
|
|
|
} else {
|
|
|
|
std::free(p);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-04-09 14:44:45 +00:00
|
|
|
OSTD_EXPORT std::size_t stack_main_size() noexcept {
|
2017-03-22 16:31:57 +00:00
|
|
|
#if defined(OSTD_PLATFORM_WIN32)
|
|
|
|
/* 4 MiB for windows... */
|
|
|
|
return 4 * 1024 * 1024;
|
|
|
|
#else
|
|
|
|
struct rlimit l;
|
|
|
|
getrlimit(RLIMIT_STACK, &l);
|
2017-04-09 14:44:45 +00:00
|
|
|
return std::size_t(l.rlim_cur);
|
2017-03-22 16:31:57 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-04-09 14:44:45 +00:00
|
|
|
OSTD_EXPORT void stack_protect(void *p, std::size_t sz) noexcept {
|
2017-03-08 23:59:10 +00:00
|
|
|
#if defined(OSTD_PLATFORM_WIN32)
|
|
|
|
DWORD oo;
|
|
|
|
VirtualProtect(p, sz, PAGE_READWRITE | PAGE_GUARD, &oo);
|
|
|
|
#elif defined(OSTD_PLATFORM_POSIX)
|
|
|
|
mprotect(p, sz, PROT_NONE);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* used by stack traits */
|
2017-04-09 14:44:45 +00:00
|
|
|
inline void ctx_pagesize(std::size_t *s) noexcept {
|
2017-03-08 23:59:10 +00:00
|
|
|
#if defined(OSTD_PLATFORM_WIN32)
|
|
|
|
SYSTEM_INFO si;
|
|
|
|
GetSystemInfo(&si);
|
2017-04-09 14:44:45 +00:00
|
|
|
*s = std::size_t(si.dwPageSize);
|
2017-03-08 23:59:10 +00:00
|
|
|
#elif defined(OSTD_PLATFORM_POSIX)
|
2017-04-09 14:44:45 +00:00
|
|
|
*s = std::size_t(sysconf(_SC_PAGESIZE));
|
2017-03-08 23:59:10 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef OSTD_PLATFORM_POSIX
|
|
|
|
inline void ctx_rlimit_get(rlimit *l) noexcept {
|
|
|
|
getrlimit(RLIMIT_STACK, l);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline rlimit ctx_rlimit() noexcept {
|
|
|
|
static rlimit l;
|
|
|
|
static std::once_flag fl;
|
|
|
|
std::call_once(fl, ctx_rlimit_get, &l);
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} /* namespace detail */
|
|
|
|
|
|
|
|
bool stack_traits::is_unbounded() noexcept {
|
|
|
|
#if defined(OSTD_PLATFORM_WIN32)
|
|
|
|
return true;
|
|
|
|
#elif defined(OSTD_PLATFORM_POSIX)
|
|
|
|
return detail::ctx_rlimit().rlim_max == RLIM_INFINITY;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-04-09 14:44:45 +00:00
|
|
|
std::size_t stack_traits::page_size() noexcept {
|
|
|
|
static std::size_t size = 0;
|
2017-03-08 23:59:10 +00:00
|
|
|
static std::once_flag fl;
|
|
|
|
std::call_once(fl, detail::ctx_pagesize, &size);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2017-04-09 14:44:45 +00:00
|
|
|
std::size_t stack_traits::minimum_size() noexcept {
|
2017-03-08 23:59:10 +00:00
|
|
|
#if defined(OSTD_PLATFORM_WIN32)
|
2017-03-19 23:50:57 +00:00
|
|
|
/* no func on windows, sane default of 8 KiB */
|
|
|
|
return 8 * 1024;
|
2017-03-08 23:59:10 +00:00
|
|
|
#elif defined(OSTD_PLATFORM_POSIX)
|
2017-03-19 23:50:57 +00:00
|
|
|
/* typically 8 KiB but can be much larger on some platforms */
|
2017-03-08 23:59:10 +00:00
|
|
|
return SIGSTKSZ;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-04-09 14:44:45 +00:00
|
|
|
std::size_t stack_traits::maximum_size() noexcept {
|
2017-03-08 23:59:10 +00:00
|
|
|
#if defined(OSTD_PLATFORM_WIN32)
|
2017-03-19 23:50:57 +00:00
|
|
|
/* value is technically undefined when is_unbounded() is
|
|
|
|
* true, just default to 1 GiB so we actually return something
|
|
|
|
*/
|
2017-03-08 23:59:10 +00:00
|
|
|
return 1024 * 1024 * 1024;
|
|
|
|
#elif defined(OSTD_PLATFORM_POSIX)
|
2017-03-19 23:50:57 +00:00
|
|
|
/* can be RLIM_INFINITY, but that's ok, see above */
|
2017-04-09 14:44:45 +00:00
|
|
|
return std::size_t(detail::ctx_rlimit().rlim_max);
|
2017-03-08 23:59:10 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-04-09 14:44:45 +00:00
|
|
|
std::size_t stack_traits::default_size() noexcept {
|
2017-03-08 23:59:10 +00:00
|
|
|
#if defined(OSTD_PLATFORM_WIN32)
|
2017-03-19 23:50:57 +00:00
|
|
|
/* no func on windows either, default to 64 KiB */
|
|
|
|
return 8 * 8 * 1024;
|
2017-03-08 23:59:10 +00:00
|
|
|
#elif defined(OSTD_PLATFORM_POSIX)
|
2017-03-19 23:50:57 +00:00
|
|
|
/* default to at least 64 KiB (see minimum_size comment) */
|
2017-04-09 14:44:45 +00:00
|
|
|
constexpr std::size_t r = std::max(8 * 8 * 1024, SIGSTKSZ);
|
2017-03-08 23:59:10 +00:00
|
|
|
if (is_unbounded()) {
|
|
|
|
return r;
|
|
|
|
}
|
2017-04-09 14:44:45 +00:00
|
|
|
std::size_t m = maximum_size();
|
2017-03-08 23:59:10 +00:00
|
|
|
if (r > m) {
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-03-17 02:04:15 +00:00
|
|
|
struct coroutine_context;
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
OSTD_EXPORT thread_local coroutine_context *coro_current = nullptr;
|
|
|
|
}
|
|
|
|
|
2017-03-08 23:59:10 +00:00
|
|
|
} /* namespace ostd */
|