2013-12-01 20:42:32 +00:00
|
|
|
/*
|
|
|
|
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>
|
2013-12-09 22:56:48 +00:00
|
|
|
#include "util/thread.h"
|
2013-12-01 20:42:32 +00:00
|
|
|
#include "util/exception.h"
|
|
|
|
|
2013-12-10 06:30:54 +00:00
|
|
|
#if !defined(LEAN_USE_SPLIT_STACK)
|
|
|
|
|
2013-12-09 22:56:48 +00:00
|
|
|
#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
|
|
|
|
|
2013-12-01 20:42:32 +00:00
|
|
|
#define LEAN_MIN_STACK_SPACE 128*1024 // 128 Kb
|
|
|
|
|
|
|
|
namespace lean {
|
2013-12-04 16:26:50 +00:00
|
|
|
void throw_get_stack_size_failed() {
|
2013-12-02 15:56:53 +00:00
|
|
|
throw exception("failed to retrieve thread stack size");
|
|
|
|
}
|
|
|
|
|
2013-12-09 22:56:48 +00:00
|
|
|
#if defined(LEAN_WINDOWS)
|
2013-12-04 19:32:30 +00:00
|
|
|
size_t get_stack_size(int ) {
|
2013-12-02 05:03:57 +00:00
|
|
|
return LEAN_WIN_STACK_SIZE;
|
2013-12-01 20:42:32 +00:00
|
|
|
}
|
2013-12-02 04:44:58 +00:00
|
|
|
#elif defined (__APPLE__)
|
2013-12-04 16:56:41 +00:00
|
|
|
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 {
|
2013-12-09 22:56:48 +00:00
|
|
|
#if defined(LEAN_MULTI_THREAD)
|
2014-06-08 03:47:46 +00:00
|
|
|
{
|
|
|
|
#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
|
2013-12-04 16:56:41 +00:00
|
|
|
}
|
2013-12-09 22:56:48 +00:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
2013-12-02 03:18:01 +00:00
|
|
|
}
|
|
|
|
}
|
2013-12-01 20:42:32 +00:00
|
|
|
#else
|
2013-12-09 22:56:48 +00:00
|
|
|
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();
|
|
|
|
}
|
2013-12-10 02:44:14 +00:00
|
|
|
return curr.rlim_cur;
|
2013-12-09 22:56:48 +00:00
|
|
|
} 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
|
2013-12-02 15:56:53 +00:00
|
|
|
}
|
2013-12-01 20:42:32 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-06-03 21:01:46 +00:00
|
|
|
static bool g_stack_info_init = false;
|
2014-09-24 19:51:04 +00:00
|
|
|
LEAN_THREAD_VALUE(size_t, g_stack_size, 0);
|
|
|
|
LEAN_THREAD_VALUE(size_t, g_stack_base, 0);
|
2013-12-01 20:42:32 +00:00
|
|
|
|
2013-12-04 16:56:41 +00:00
|
|
|
void save_stack_info(bool main) {
|
2014-06-03 21:01:46 +00:00
|
|
|
g_stack_info_init = true;
|
2014-09-24 19:51:04 +00:00
|
|
|
g_stack_size = get_stack_size(main);
|
2013-12-01 20:42:32 +00:00
|
|
|
char x;
|
2014-09-24 19:51:04 +00:00
|
|
|
g_stack_base = reinterpret_cast<size_t>(&x);
|
2013-12-01 20:42:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t get_used_stack_size() {
|
|
|
|
char y;
|
|
|
|
size_t curr_stack = reinterpret_cast<size_t>(&y);
|
2014-09-24 19:51:04 +00:00
|
|
|
return g_stack_base - curr_stack;
|
2013-12-01 20:42:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t get_available_stack_size() {
|
|
|
|
size_t sz = get_used_stack_size();
|
2014-09-24 19:51:04 +00:00
|
|
|
if (sz > g_stack_size)
|
2013-12-01 20:42:32 +00:00
|
|
|
return 0;
|
|
|
|
else
|
2014-09-24 19:51:04 +00:00
|
|
|
return g_stack_size - sz;
|
2013-12-01 20:42:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-07 22:59:21 +00:00
|
|
|
void check_stack(char const * component_name) {
|
2014-09-24 19:51:04 +00:00
|
|
|
if (g_stack_info_init && get_used_stack_size() + LEAN_MIN_STACK_SPACE > g_stack_size)
|
2013-12-07 22:59:21 +00:00
|
|
|
throw stack_space_exception(component_name);
|
2013-12-01 20:42:32 +00:00
|
|
|
}
|
|
|
|
}
|
2013-12-10 06:30:54 +00:00
|
|
|
#endif
|