d13917a29a5750e1d834b2ffeab5ce30bf24237a
[folly.git] / folly / experimental / exception_tracer / StackTrace.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/experimental/exception_tracer/StackTrace.h>
18
19 #include <cassert>
20 #include <cstdlib>
21 #include <new>
22 #include <folly/experimental/symbolizer/StackTrace.h>
23
24 namespace folly { namespace exception_tracer {
25
26 class StackTraceStack::Node : public StackTrace {
27  public:
28   static Node* allocate();
29   void deallocate();
30
31   Node* next;
32
33  private:
34   Node() : next(nullptr) { }
35   ~Node() { }
36 };
37
38 auto StackTraceStack::Node::allocate() -> Node* {
39   // Null pointer on error, please.
40   return new (std::nothrow) Node();
41 }
42
43 void StackTraceStack::Node::deallocate() {
44   delete this;
45 }
46
47 bool StackTraceStack::pushCurrent() {
48   checkGuard();
49   auto node = Node::allocate();
50   if (!node) {
51     // cannot allocate memory
52     return false;
53   }
54
55   ssize_t n = folly::symbolizer::getStackTrace(node->addresses, kMaxFrames);
56   if (n == -1) {
57     node->deallocate();
58     return false;
59   }
60   node->frameCount = n;
61
62   node->next = top_;
63   top_ = node;
64   return true;
65 }
66
67 bool StackTraceStack::pop() {
68   checkGuard();
69   if (!top_) {
70     return false;
71   }
72
73   auto node = top_;
74   top_ = node->next;
75   node->deallocate();
76   return true;
77 }
78
79 bool StackTraceStack::moveTopFrom(StackTraceStack& other) {
80   checkGuard();
81   if (!other.top_) {
82     return false;
83   }
84
85   auto node = other.top_;
86   other.top_ = node->next;
87   node->next = top_;
88   top_ = node;
89   return true;
90 }
91
92 void StackTraceStack::clear() {
93   checkGuard();
94   while (top_) {
95     pop();
96   }
97 }
98
99 StackTrace* StackTraceStack::top() {
100   checkGuard();
101   return top_;
102 }
103
104 StackTrace* StackTraceStack::next(StackTrace* p) {
105   checkGuard();
106   assert(p);
107   return static_cast<Node*>(p)->next;
108 }
109
110 }}  // namespaces