File: ActiveFunctions.h

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 (142 lines) | stat: -rw-r--r-- 4,313 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
130
131
132
133
134
135
136
137
138
139
140
141
142
#pragma once
#include "OS/Sync.h"

namespace storm {
	STORM_PKG(core.lang);

	class ActiveFunctions;


	/**
	 * RAII-type used for pausing all threads in the system. Also collects stack-traces for the
	 * threads, to allow querying and replacing active functions on the stack.
	 *
	 * This class is intentionally only usable from C++. The stored stack traces can, however, be
	 * accessed from Storm as well.
	 */
	class PauseThreads : NoCopy {
	public:
		// Pause all threads, capture call-stack information.
		PauseThreads(Engine &e);

		// Release the threads again.
		~PauseThreads();

		// Get active functions. Does not add a ref to the result.
		inline ActiveFunctions *activeFunctions() const {
			return data;
		}

	private:
		// Semaphore used by all threads to signal that they have started waiting.
		// Note: this needs to be a Semaphore, otherwise we might have stack traces for threads
		// that are no longer active.
		Semaphore signal;

		// Use by this class to pause the other threads. Note: it is a Semaphore, not an os::Sema.
		// This pauses the user-level scheduler fully.
		Semaphore wait;

		// Number of threads.
		size_t threadCount;

		// Contents maintained by us.
		ActiveFunctions *data;

		// Lock to avoid concurrent calls to 'data->addThread'.
		// As with other primitives, a native lock to avoid unintended UThread execution.
		util::Lock dataLock;

		// Main entry-point in each thread.
		void threadMain();

		// Capture a stack trace of the current thread.
		void captureStacks(Bool includeCurrent);
	};


	/**
	 * Data returned by 'find' in 'ActiveFunctions'. Contains offset + number of occurrences for a
	 * single active function.
	 */
	struct ActiveOffset {
		// Offset into the queried active function.
		size_t offset;

		// Number of occurrences in the system.
		size_t count;

		// Create.
		ActiveOffset(size_t offset, size_t count)
			: offset(offset), count(count) {}
	};

	// Output.
	wostream &operator <<(wostream &to, const ActiveOffset &offset);

	/**
	 * Data produced by PauseThreads. Includes information about the call stacks for all threads,
	 * including the one that was paused. This allows replacing return pointers on the stack during
	 * updates, for example.
	 *
	 * This data structure is allocated on the C++ heap. All pointers inside it either refer to
	 * locations on the stack, or objects that are pinned on the stack, so it is fine to keep them
	 * in non-gc memory.
	 *
	 * The data structure is cleared whenever the creating PauseThreads object is destroyed. This
	 * prevents stale pointers to the stack.
	 */
	class ActiveFunctions {
	public:
		// Create.
		ActiveFunctions();

		// Add a reference to the refcount.
		void addRef();

		// Release a reference.
		void release();

		// Find all active instances of a particular function.
		vector<ActiveOffset> find(const void *function) const;

		// Replace occurrences of a particular function. Only replaces the specified offsets in the
		// function. Replacements will *not* be reflected in future calls to "find". Returns the
		// number of instances that was replaced. Both 'function' and 'replace' are expected to be
		// pointers to the start of functions allocated on the GC heap.
		size_t replace(const void *function, size_t fOffset, const void *replace, size_t rOffset) const;

	private:
		// This is the API that PauseThreads is expected to use.
		friend class PauseThreads;

		// Add a set of UThread stack traces from an array.
		void addThread(const vector<::StackTrace> &src);

		// Called when data collection is complete to allow pre-processing for efficient lookup down
		// the line.
		void done();

		// Called to clear contents whenever the PauseThreads object goes out of scope.
		void clear();

	private:
		// All stack frames, in one big array to make it easier to refer to them.
		vector<StackFrame> frames;

		// Starting positions of each UThread inside 'frames'.
		vector<size_t> uthreadStart;

		// Starting positions of each Thread inside 'uthreadStart'.
		vector<size_t> threadStart;

		// The elements in 'frames', sorted based on the address in each frame to make them easy to
		// find later on.
		vector<size_t> sortedFrames;

		// Number of references to this structure. Used to avoid stale references from Storm
		// objects.
		size_t refs;
	};

}