File: StackTrace.cpp

package info (click to toggle)
storm-lang 0.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,028 kB
  • sloc: ansic: 261,471; cpp: 140,432; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (129 lines) | stat: -rw-r--r-- 3,021 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "stdafx.h"
#include "StackTrace.h"
#include "Utils/Semaphore.h"

namespace os {

	/**
	 * Global trace data. Shared information.
	 */
	struct SharedTrace {
		// Semaphore used to signal from the threads.
		Sema signal;

		// Semaphore used by the threads to wait for event.
		Semaphore wait;

		// The main thread.
		Thread main;

		// Create.
		SharedTrace() : signal(0), wait(0), main(Thread::current()) {}
	};

	/**
	 * An instance of this class is created for each thread we are creating stack traces for.
	 * This class keeps track of the state in each thread, and contains functions executed
	 * at various stages of the capture.
	 */
	struct TraceData {
		// Shared data.
		SharedTrace &shared;

		// Traces captured from the UThreads.
		vector<StackTrace> results;

		// Create.
		TraceData(SharedTrace &shared) : shared(shared) {}

		// Main function for the trace.
		void main() {
			prepare();

			// Wait for our signal!
			shared.wait.down();

			capture(false);
		}

		// Preparations.
		void prepare() {
			// Make it known that we're alive.
			shared.signal.up();
		}

		// Capture.
		void capture(bool thisThread) {
			if (thisThread)
				results.push_back(::stackTrace(2));

			vector<UThread> stacks = Thread::current().idleUThreads();

			results.reserve(stacks.size());
			for (size_t i = 0; i < stacks.size(); i++) {
				if (!stacks[i].detour(util::memberVoidFn(this, &TraceData::captureUThread))) {
					WARNING(L"Failed to execute detour!");
				}
			}

			// Signal again.
			shared.signal.up();
		}

		// Function called from all UThreads in the context of that UThread. Performs the actual
		// stack trace capturing.
		void captureUThread() {
			results.push_back(::stackTrace(2));
		}
	};

	vector<vector<StackTrace>> stackTraces(const vector<Thread> &threads) {
		SharedTrace shared;
		vector<TraceData> data(threads.size(), TraceData(shared));

		size_t thisThread = threads.size();

		// Inject a UThread into each thread we're interested in.
		for (size_t i = 0; i < threads.size(); i++) {
			if (threads[i] == shared.main) {
				data[i].prepare();
				thisThread = i;
			} else {
				UThread::spawn(util::memberVoidFn(&data[i], &TraceData::main), &threads[i]);
			}
		}

		// Wait for them all to become ready.
		for (size_t i = 0; i < threads.size(); i++) {
			shared.signal.down();
		}

		// Start the capture!
		for (size_t i = 0; i < threads.size(); i++) {
			shared.wait.up();
		}

		// If we're one of the threads, we also need to do some work...
		if (thisThread < threads.size()) {
			data[thisThread].capture(true);
		}

		// Wait for all to complete.
		for (size_t i = 0; i < threads.size(); i++) {
			shared.signal.down();
		}

		// Collect the results.
		vector<vector<StackTrace>> result(threads.size(), vector<StackTrace>());
		for (size_t i = 0; i < threads.size(); i++) {
			result[i] = data[i].results;
		}
		return result;
	}

	vector<StackTrace> stackTraces(const Thread &thread) {
		vector<Thread> threads(1, thread);
		return stackTraces(threads)[0];
	}

}