lean2/src/util/stackinfo.cpp
Leonardo de Moura fb5c7c8e92 fix(util/stackinfo): on OSX Boost does not seem to be based on pthread library
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2014-06-07 20:47:46 -07:00

130 lines
3.5 KiB
C++

/*
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 <pthread.h>
#include <memory.h>
#include <iostream>
#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 <sys/resource.h> // NOLINT
#else
#include <sys/time.h> // NOLINT
#include <sys/resource.h> // 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;
MK_THREAD_LOCAL_GET(size_t, get_g_stack_size, 0);
MK_THREAD_LOCAL_GET(size_t, get_g_stack_base, 0);
void save_stack_info(bool main) {
g_stack_info_init = true;
get_g_stack_size() = get_stack_size(main);
char x;
get_g_stack_base() = reinterpret_cast<size_t>(&x);
}
size_t get_used_stack_size() {
char y;
size_t curr_stack = reinterpret_cast<size_t>(&y);
return get_g_stack_base() - curr_stack;
}
size_t get_available_stack_size() {
size_t sz = get_used_stack_size();
if (sz > get_g_stack_size())
return 0;
else
return get_g_stack_size() - sz;
}
void check_stack(char const * component_name) {
if (g_stack_info_init && get_used_stack_size() + LEAN_MIN_STACK_SPACE > get_g_stack_size())
throw stack_space_exception(component_name);
}
}
#endif