File: Future.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 (212 lines) | stat: -rw-r--r-- 5,758 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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#pragma once
#include "Object.h"
#include "Handle.h"
#include "OS/Future.h"
#include "OS/Sync.h"
#include "Core/GcTypeStore.h"

namespace storm {
	STORM_PKG(core);

	class Exception;

	/**
	 * Future-object exposed to the runtime and built into function calls. By calling
	 * 'asyncThreadCall' on a function, you will get one of these objects. It also simplifies the
	 * interface of the Future in code since it supports copying of the future (references the same
	 * result) and also correctly handles cases where the result is not waited for.
	 *
	 * The future takes care of any copying of the objects.
	 */
	class FutureBase : public Object {
		STORM_CLASS;
	public:
		// Create.
		FutureBase(const Handle &type);

		// Copy ctor.
		FutureBase(const FutureBase &o);

		// Destructor to keep the reference count of Data.
		~FutureBase();

		// Deep copy.
		virtual void STORM_FN deepCopy(CloneEnv *env);

		// Post a result.
		void CODECALL postRaw(const void *value);

		// Post an error (assuming we're inside a catch-block).
		void error();

		// Post an error.
		void STORM_FN error(Exception *exception);

		// Wait for the result. 'to' is empty memory where the value will be copied into.
		void CODECALL resultRaw(void *to);

		// Get the result as an exception if it was an exception, otherwise just return whenever we have a result.
		void STORM_FN errorResult();

		// Detach the future, ie. tell it we don't care about the result.
		void STORM_FN detach();

		// Get the underlying future object. Note: when you call this function,
		// you are required to call either postRaw or error on the future object, otherwise
		// we will leak resources!
		os::FutureBase *rawFuture();

		// Get the place where the result is to be stored.
		void *rawResult() { return data->result->v; }

		// Tell this future instance that it does not need to clone the result before returning it.
		// This is set when we have a future that we know will be posted on the same Thread as the
		// current thread. We will clear this flag as soon as "deepCopy" is called (which indicates
		// that we crossed a Thread boundary).
		void CODECALL setNoClone();

	private:
		// Custom extension of the 'FutureBase' object, so that we may get a notification when a
		// result has been posted.
		class FutureNotify : public os::FutureBase {
		public:
			// Ctor.
			FutureNotify();

		protected:
			// Custom notify so that we can keep the Data struct alive long enough.
			virtual void notify();
		};

		// Data shared between futures. Since we allow copies, we need to share one FutureBase
		// object. This struct is allocated on the non-moving GC heap since it contains potentially
		// sensitive constructs (like OS semaphores and locks).
		//
		// We use reference counting here to get slightly more prompt destruction of the data
		// object. This is since the FutureBase object is allocated in a generational pool, which
		// is collected more frequently, while the Data object is in a non-moving pool that is
		// rarely collected.  This way, we can at least free the OS resources earlier while making
		// sure that we don't accidentally leak memory in certain situations (the finalizer on Data
		// is a backup).
		struct Data {
			Data(const Handle &handle, GcArray<byte> *result);

			~Data();

			// The Future object we are using.
			FutureNotify future;

			// Handle.
			const Handle *handle;

			// Result. We use 'filled' to determine if anything is stored here.
			GcArray<byte> *result;

			// References.
			nat refs;

			// Release on receiving a result?
			nat releaseOnResult;

			// Add/release references.
			void addRef();
			void release();

			// Called when the semaphore is notified.
			static void resultPosted(FutureNotify *sema);

			// Finalizer for this type.
			static void finalize(void *object, os::Thread *thread);

			// GC description for this type.
			static const GcTypeStore<3> gcType;
		};

		// Pointer to the data.
		UNKNOWN(PTR_GC) Data *data;

		// Can we skip cloning the result?
		Bool noClone;
	};

	// Declare the template.
	STORM_TEMPLATE(Future, createFuture);

	/**
	 * Specialized class, compatible with the template instantiations generated
	 * by the Storm runtime.
	 */
	template <class T>
	class Future : public FutureBase {
		STORM_SPECIAL;
	public:
		// Type lookup.
		static Type *stormType(Engine &e) {
			return runtime::cppTemplate(e, FutureId, 1, StormInfo<T>::id());
		}

		// Create.
		Future() : FutureBase(StormInfo<T>::handle(engine())) {
			runtime::setVTable(this);
		}

		// Copy.
		Future(const Future<T> *o) : FutureBase(o) {
			runtime::setVTable(this);
		}

		// Post result.
		void post(T t) {
			cloned(t, new (this) CloneEnv());
			postRaw(&t);
		}

		// Get result.
		T result() {
			byte data[sizeof(T)];
			resultRaw(data);
			T copy = *(T *)data;
			((T *)data)->~T();
			return copy;
		}
	};

	/**
	 * Special case for 'void'
	 */
	template <>
	class Future<void> : public FutureBase {
		STORM_SPECIAL;
	public:
		// Type lookup.
		static Type *stormType(Engine &e) {
			return runtime::cppTemplate(e, FutureId, 1, StormInfo<void>::id());
		}

		// Create.
		Future() : FutureBase(StormInfo<void>::handle(engine())) {
			runtime::setVTable(this);
		}

		// Copy.
		Future(const Future<void> &o) : FutureBase(o) {
			runtime::setVTable(this);
		}

		// Post.
		void post() {
			postRaw(null);
		}

		// Get result.
		void result() {
			resultRaw(null);
		}
	};

	// Expose the "clone exception" helper for cases where we use the low-level os::Future directly
	// in C++. This function makes sure to clone Storm exceptions before they are re-thrown from the
	// Future. No env is needed for this function.
	os::PtrThrowable *updateFutureExceptions(os::PtrThrowable *ptr, void *env);

}