/* Copyright (c) 2013 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Leonardo de Moura */ #include #include #include #include "util/thread.h" #include "util/exception.h" #if !defined(LEAN_USE_SPLIT_STACK) #if defined(LEAN_WINDOWS) // no extra included needed so far #elif defined(__APPLE__) #include // NOLINT #else #include // NOLINT #include // NOLINT #endif #define LEAN_MIN_STACK_SPACE 128*1024 // 128 Kb namespace lean { void throw_get_stack_size_failed() { throw exception("failed to retrieve thread stack size"); } #if defined(LEAN_WINDOWS) size_t get_stack_size(int ) { return LEAN_WIN_STACK_SIZE; } #elif defined (__APPLE__) size_t get_stack_size(int main) { if (main) { // Retrieve stack size of the main thread. struct rlimit curr; if (getrlimit(RLIMIT_STACK, &curr) != 0) { throw_get_stack_size_failed(); } return curr.rlim_max; } else { #if defined(LEAN_MULTI_THREAD) { #if defined(LEAN_USE_BOOST) // Boost does seems to be based on pthread on OSX return get_thread_attributes().get_stack_size(); #else // This branch retrieves the default thread size for pthread threads. // This is *not* the stack size of the main thread. pthread_attr_t attr; memset (&attr, 0, sizeof(attr)); pthread_attr_init(&attr); size_t result; if (pthread_attr_getstacksize(&attr, &result) != 0) { throw_get_stack_size_failed(); } return result; #endif } #else return 0; #endif } } #else size_t get_stack_size(int main) { if (main) { // Retrieve stack size of the main thread. struct rlimit curr; if (getrlimit(RLIMIT_STACK, &curr) != 0) { throw_get_stack_size_failed(); } return curr.rlim_cur; } else { #if defined(LEAN_MULTI_THREAD) pthread_attr_t attr; memset (&attr, 0, sizeof(attr)); if (pthread_getattr_np(pthread_self(), &attr) != 0) { throw_get_stack_size_failed(); } void * ptr; size_t result; if (pthread_attr_getstack (&attr, &ptr, &result) != 0) { throw_get_stack_size_failed(); } if (pthread_attr_destroy(&attr) != 0) { throw_get_stack_size_failed(); } return result; #else return 0; #endif } } #endif static bool g_stack_info_init = false; LEAN_THREAD_VALUE(size_t, g_stack_size, 0); LEAN_THREAD_VALUE(size_t, g_stack_base, 0); void save_stack_info(bool main) { g_stack_info_init = true; g_stack_size = get_stack_size(main); char x; g_stack_base = reinterpret_cast(&x); } size_t get_used_stack_size() { char y; size_t curr_stack = reinterpret_cast(&y); return g_stack_base - curr_stack; } size_t get_available_stack_size() { size_t sz = get_used_stack_size(); if (sz > g_stack_size) return 0; else return g_stack_size - sz; } void check_stack(char const * component_name) { if (g_stack_info_init && get_used_stack_size() + LEAN_MIN_STACK_SPACE > g_stack_size) throw stack_space_exception(component_name); } } #endif