X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2Fexperimental%2Fexception_tracer%2FStackTrace.h;h=4218c5a1ab1c791216f434bc6fe6584eac77a0a2;hp=b7354498c3fc127bfebe609f8a6edccdea88d2df;hb=3680f888411a4eea23aae712149932f4bb37d349;hpb=ec61097ac903e471c1440b3c09818d8a1748de6d diff --git a/folly/experimental/exception_tracer/StackTrace.h b/folly/experimental/exception_tracer/StackTrace.h index b7354498..4218c5a1 100644 --- a/folly/experimental/exception_tracer/StackTrace.h +++ b/folly/experimental/exception_tracer/StackTrace.h @@ -18,71 +18,86 @@ #ifndef FOLLY_EXPERIMENTAL_EXCEPTION_TRACER_STACKTRACE_H_ #define FOLLY_EXPERIMENTAL_EXCEPTION_TRACER_STACKTRACE_H_ -#include -#include +#include +#include +#include -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct StackTrace { - uintptr_t* frameIPs; /* allocated with malloc() */ - size_t frameCount; -} StackTrace; - -/** - * Get the current stack trace, allocating trace->frameIPs using malloc(). - * Skip the topmost "skip" frames. - * Return 0 on success, a negative value on error. - * On error, trace->frameIPs is NULL. - */ -int getCurrentStackTrace(size_t skip, StackTrace* trace); +namespace folly { namespace exception_tracer { -/** - * Free data allocated in a StackTrace object. - */ -void destroyStackTrace(StackTrace* trace); +constexpr size_t kMaxFrames = 500; -/** - * A stack of stack traces. - */ -typedef struct StackTraceStack { - StackTrace trace; - struct StackTraceStack* next; -} StackTraceStack; - -/** - * Push the current stack trace onto the stack. - * Return 0 on success, a negative value on error. - * On error, the stack is unchanged. - */ -int pushCurrentStackTrace(size_t skip, StackTraceStack** head); - -/** - * Pop (and destroy) the top stack trace from the stack. - */ -void popStackTrace(StackTraceStack** head); +struct StackTrace { + StackTrace() : frameCount(0) { } -/** - * Completely empty the stack, destroying everything. - */ -void clearStack(StackTraceStack** head); - -/** - * Move the top stack trace from one stack to another. - * Return 0 on success, a negative value on error (if the source stack is - * empty) - */ -int moveTop(StackTraceStack** from, StackTraceStack** to); - -/** - * Initialize the stack tracing code. - */ -void initStackTrace(); + size_t frameCount; + uintptr_t addresses[kMaxFrames]; +}; + +// note: no constructor so this can be __thread. +// A StackTraceStack MUST be placed in zero-initialized memory. +class StackTraceStack { + class Node; + public: + /** + * Push the current stack trace onto the stack. + * Returns false on failure (not enough memory, getting stack trace failed), + * true on success. + */ + bool pushCurrent(); + + /** + * Pop the top stack trace from the stack. + * Returns true on success, false on failure (stack was empty). + */ + bool pop(); + + /** + * Move the top stack trace from other onto this. + * Returns true on success, false on failure (other was empty). + */ + bool moveTopFrom(StackTraceStack& other); + + /** + * Clear the stack. + */ + + void clear(); + + /** + * Is the stack empty? + */ + bool empty() const { return !top_; } + + /** + * Return the top stack trace, or nullptr if the stack is empty. + */ + StackTrace* top(); + + /** + * Return the stack trace following p, or nullptr if p is the bottom of + * the stack. + */ + StackTrace* next(StackTrace* p); + + private: + // In debug mode, we assert that we're in zero-initialized memory by + // checking that the two guards around top_ are zero. + void checkGuard() const { +#ifndef NDEBUG + assert(guard1_ == 0 && guard2_ == 0); +#endif + } -#ifdef __cplusplus -} /* extern "C" */ +#ifndef NDEBUG + uintptr_t guard1_; #endif + Node* top_; +#ifndef NDEBUG + uintptr_t guard2_; +#endif +}; + +}} // namespaces #endif /* FOLLY_EXPERIMENTAL_EXCEPTION_TRACER_STACKTRACE_H_ */