File: UThread.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 (175 lines) | stat: -rw-r--r-- 5,362 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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#pragma once
#include "UThreadData.h"

// Note: The implementation is in UThreadData.cpp.
namespace os {

	/**
	 * This is a handle to a specific UThread. Currently, not many operations
	 * is supported on another UThread than the current. Therefore, the backing
	 * UThread is not kept after the UThread has terminated.
	 */
	class UThread {
	public:

		/**
		 * Description of how to handle the result from a function call on another
		 * thread. When the function completes, 'done' is called with its result.
		 * If an exception is thrown, 'error' is called with the exception instead.
		 * 'data' may be used to provide custom data to the callbacks.
		 */
		template <class R, class Param>
		struct Result {
			Param *data;
			void (*done)(Param *, R);
			void (*error)(Param *, const Exception &);
		};

		// Specific for void.
		template <class Param>
		struct Result<void, Param> {
			Param *data;
			void (*done)(Param *);
			void (*error)(Param *, const Exception &);
		};

		// Copy.
		UThread(const UThread &o) : data(o.data) {
			if (data)
				data->addRef();
		}

		// Assign.
		UThread &operator =(const UThread &o) {
			if (this != &o) {
				if (data)
					data->release();
				data = o.data;
				if (data)
					data->addRef();
			}
			return *this;
		}

		// Destroy.
		~UThread() {
			if (data)
				data->release();
		}

#ifdef USE_MOVE
		// Move.
		UThread(UThread &&o) : data(o.data) {
			o.data = null;
		}

		UThread &operator =(UThread &&o) {
			std::swap(data, o.data);
			return *this;
		}
#endif

		// Same UThread?
		inline bool operator ==(const UThread &o) const { return data == o.data; }
		inline bool operator !=(const UThread &o) const { return data != o.data; }

		// Get an unique identifier for this thread.
		inline uintptr_t id() const { return (uintptr_t)data; }

		// Yield to another UThread. Returns sometime in the future. Returns 'true' if other
		// threads were run between the call and the return.
		static bool leave();

		// See if there are any UThreads that are currently sleeping, and may wake in the future.
		// This can be used together with "leave" to detect if we need to keep "polling" for
		// sleeping threads from custom thread-wait logic in certain cases (e.g. when it cannot use
		// the standard "wait" function).
		static bool anySleeping();

		// Yield for a specific amount of time.
		static void sleep(nat ms);

		// Any more UThreads to run here?
		static bool any();

		// Get the currently running UThread.
		static UThread current();

		// Get the thread data. Mainly for internal use.
		inline UThreadData *threadData() { return data; }

		// Value representing no thread.
		static const UThread invalid;


		/**
		 * Low-level spawn functions. See 'spawn' below for explanations.
		 */

		// Spawn a 'void' function.
		static UThread spawnRaw(const void *fn, bool memberFn, void *firstParam,
								const FnCallRaw &call, const Thread *on = null);

		// Spawn a function, capturing the result in a future.
		static UThread spawnRaw(const void *fn, bool memberFn, void *firstParam,
								const FnCallRaw &call, FutureBase &result,
								void *target, const Thread *on = null);


		/**
		 * Spawn a new UThread on the currently running thread, or another thread. There are a few
		 * variants of spawn here, all of them take some kind of function pointer, optionally with
		 * parameters to run, followed by a reference to the OS thread (Thread *) to run on. If this
		 * is left out, or set to null, the thread of the caller is used.
		 *
		 * All of these return as soon as the new UThread is set up, they do not pre-empt the
		 * currently running thread. Note, however, that any parameters are copied before the call
		 * returns, so there is no need to worry about variables used as parameters going out of
		 * scope.
		 */

		// Spawn using a Fn<void, void>.
		static UThread spawn(const util::Fn<void, void> &fn, const Thread *on = null);

		// Spawn using a FnCall object.
		template <int P>
		static UThread spawn(const void *fn, bool memberFn, const FnCall<void, P> &call, const Thread *on = null) {
			return spawnRaw(fn, memberFn, null, call, on);
		}

		// Spawn using a FnCall object, providing the result in a Future<T>.
		template <class R, int P>
		static UThread spawn(const void *fn, bool memberFn, const FnCall<R, P> &call,
							Future<R> &result, const Thread *on = null) {
			return spawnRaw(fn, memberFn, null, call, result.impl(), result.data(), on);
		}

		// Execute a detour function on this uthread. Assumes that this thread is currently not
		// running and belongs to the same thread as the caller of this function. The detour will be
		// executed synchronously, ie. the current thread will be suspended until the detour is
		// completed.
		// This function is intended to provide stack traces for suspended threads. As such, the
		// stack during the detour will look like the suspended thread called the function in the
		// detour.
		// Returns 'false' if unable to execute the detour, usually since the thread is currently
		// being executed.
		bool detour(const util::Fn<void, void> &fn);

	private:
		friend class UThreadState;

		// Create
		UThread(UThreadData *data);

		// Referenced data.
		UThreadData *data;

		// Insert an UThread.
		static UThread insert(UThreadData *data, ThreadData *on);
	};

}


// Don't ask...
#include "Sync.h"