1
1
#pragma once
2
- #include < base/defines.h>
3
2
#include < boost/context/stack_context.hpp>
4
- #include < Common/formatReadable.h>
5
- #include < Common/CurrentMemoryTracker.h>
6
- #include < Common/Exception.h>
7
- #include < base/getPageSize.h>
8
- #include < sys/time.h>
9
- #include < sys/resource.h>
10
- #include < sys/mman.h>
11
-
12
- #if defined(BOOST_USE_VALGRIND)
13
- #include < valgrind/valgrind.h>
14
- #endif
15
-
16
- // / Required for older Darwin builds, that lack definition of MAP_ANONYMOUS
17
- #ifndef MAP_ANONYMOUS
18
- #define MAP_ANONYMOUS MAP_ANON
19
- #endif
20
-
21
- namespace DB ::ErrorCodes
22
- {
23
- extern const int CANNOT_ALLOCATE_MEMORY;
24
- }
25
3
26
4
// / This is an implementation of allocator for fiber stack.
27
5
// / The reference implementation is protected_fixedsize_stack from boost::context.
28
6
// / This implementation additionally track memory usage. It is the main reason why it is needed.
29
7
class FiberStack
30
8
{
31
- private:
32
- size_t stack_size;
33
- size_t page_size = 0 ;
34
9
public:
35
10
// / NOTE: If you see random segfaults in CI and stack starts from boost::context::...fiber...
36
11
// / probably it worth to try to increase stack size for coroutines.
@@ -39,51 +14,12 @@ class FiberStack
39
14
// / way. We will have 80 pages with 4KB page size.
40
15
static constexpr size_t default_stack_size = 320 * 1024 ; // / 64KB was not enough for tests
41
16
42
- explicit FiberStack (size_t stack_size_ = default_stack_size) : stack_size(stack_size_)
43
- {
44
- page_size = getPageSize ();
45
- }
46
-
47
- boost::context::stack_context allocate () const
48
- {
49
- size_t num_pages = 1 + (stack_size - 1 ) / page_size;
50
- size_t num_bytes = (num_pages + 1 ) * page_size; // / Add one page at bottom that will be used as guard-page
17
+ explicit FiberStack (size_t stack_size_ = default_stack_size);
51
18
52
- void * vp = ::mmap (nullptr , num_bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1 , 0 );
53
- if (MAP_FAILED == vp)
54
- throw DB::ErrnoException (DB::ErrorCodes::CANNOT_ALLOCATE_MEMORY, " FiberStack: Cannot mmap {}." , ReadableSize (num_bytes));
19
+ boost::context::stack_context allocate () const ;
20
+ void deallocate (boost::context::stack_context & sctx) const ;
55
21
56
- // / TODO: make reports on illegal guard page access more clear.
57
- // / Currently we will see segfault and almost random stacktrace.
58
- if (-1 == ::mprotect (vp, page_size, PROT_NONE))
59
- {
60
- ::munmap (vp, num_bytes);
61
- throw DB::ErrnoException (DB::ErrorCodes::CANNOT_ALLOCATE_MEMORY, " FiberStack: cannot protect guard page" );
62
- }
63
-
64
- // / Do not count guard page in memory usage.
65
- auto trace = CurrentMemoryTracker::alloc (num_pages * page_size);
66
- trace.onAlloc (vp, num_pages * page_size);
67
-
68
- boost::context::stack_context sctx;
69
- sctx.size = num_bytes;
70
- sctx.sp = static_cast < char * >(vp) + sctx.size ;
71
- #if defined(BOOST_USE_VALGRIND)
72
- sctx.valgrind_stack_id = VALGRIND_STACK_REGISTER (sctx.sp , vp);
73
- #endif
74
- return sctx;
75
- }
76
-
77
- void deallocate (boost::context::stack_context & sctx) const
78
- {
79
- #if defined(BOOST_USE_VALGRIND)
80
- VALGRIND_STACK_DEREGISTER (sctx.valgrind_stack_id );
81
- #endif
82
- void * vp = static_cast < char * >(sctx.sp ) - sctx.size ;
83
- ::munmap (vp, sctx.size);
84
-
85
- // / Do not count guard page in memory usage.
86
- auto trace = CurrentMemoryTracker::free (sctx.size - page_size);
87
- trace.onFree (vp, sctx.size - page_size);
88
- }
22
+ private:
23
+ const size_t stack_size;
24
+ const size_t page_size;
89
25
};
0 commit comments