File: Exception.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 (162 lines) | stat: -rw-r--r-- 4,196 bytes parent folder | download | duplicates (3)
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
#include "stdafx.h"
#include "Exception.h"
#include "Gc.h"
#include "Utils/Lock.h"

namespace storm {

	// Static exceptions (zero initialized by the compiler).
	HeapExceptions staticExceptions = { heapExStaticCount, 0, 0 };

	// Dynamically managed exceptions.
	HeapExceptions *dynamicExceptions = null;

	// Lock when they are modified.
	static util::Lock exLock;

	// Try to add an exception to a HeapExceptions structure. Will not attempt to resize.
	static bool add(HeapExceptions *to, void *ptr, size_t size) {
		// Full?
		if (!to || to->filled == to->count)
			return false;

		size_t hint = to->hint;
		while (to->data[hint].ptr) {
			if (++hint > to->count)
				hint = 0;
		}

		// We found an empty location!
		to->hint = hint;

		// We need to make sure to write the size first. Otherwise, a scanner might use the wrong
		// size when scanning.
		atomicWrite(to->data[hint].size, size);
		atomicWrite(to->data[hint].ptr, ptr);

		// Update 'filled'. Make sure we read reasonable values from a scanner.
		atomicIncrement(to->filled);

		return true;
	}

	// Grow the dynamic list of exceptions. Calls 'terminate' on failure.
	static void growDynamic() {
		size_t newCount = heapExStaticCount;
		HeapExceptions *old = dynamicExceptions;
		if (old) {
			// Grow linearly. We don't expect a massive increase in size.
			newCount = old->count + heapExStaticCount;
		}

		size_t newSize = sizeof(HeapExceptions) + sizeof(HeapExceptions)*(newCount - heapExStaticCount);
		HeapExceptions *alloc = (HeapExceptions *)malloc(newSize);
		memset(alloc, 0, newSize);
		alloc->count = newCount;

		// Copy the old content, if applicable. Note: We don't need to be careful about the contents
		// of the new one as it is not made public yet.
		if (old) {
			for (size_t i = 0; i < old->count; i++) {
				if (old->data[i].ptr)
					alloc->data[alloc->hint++] = old->data[i];
			}
		}

		// Publish the new one.
		atomicWrite(dynamicExceptions, alloc);

		// Now, we can kill the old one. We know that the GC is not scanning the old one at this
		// point since the GC will pause all threads during scanning. Otherwise, we would need to
		// have a more complicated protocol for hand-offs.
		free(old);
	}

	// Remove an element.
	static bool remove(HeapExceptions *from, void *ptr) {
		if (!from || from->filled == 0)
			return false;

		for (size_t i = 0; i < from->count; i++) {
			if (from->data[i].ptr == ptr) {
				// Be careful with clearing the pointer.
				atomicWrite(from->data[i].ptr, (void *)null);
				atomicWrite(from->data[i].size, (size_t)0);
				return true;
			}
		}

		return false;
	}

	void trackException(void *ptr, size_t size) {
		util::Lock::L z(exLock);

		if (add(&staticExceptions, ptr, size))
			return;

		if (add(dynamicExceptions, ptr, size))
			return;

		// We need to re-size the dynamic part...
		growDynamic();

		// This *will* succeed.
		add(dynamicExceptions, ptr, size);
	}

	void untrackException(void *ptr) {
		util::Lock::L z(exLock);

		if (remove(&staticExceptions, ptr))
			return;

		if (remove(dynamicExceptions, ptr)) {
			// If the dynamic part is empty now, remove it!
			HeapExceptions *dyn = dynamicExceptions;
			if (dyn->filled == 0) {
				atomicWrite(dynamicExceptions, (HeapExceptions *)null);
				free(dyn);
			}
		}
	}


#if defined(WINDOWS)

	// Not needed on Windows, as long as we don't use std::exception_ptr to store GC allocated
	// exceptions (which we don't want to do on POSIX either). Thus, we only need to stub out the
	// API here.

#elif defined(POSIX)

	/**
	 * Hooks into the ABI.
	 */

	typedef void *(*AbiAllocEx)(size_t);
	typedef void (*AbiFreeEx)(void *);

	AbiAllocEx allocEx = null;
	AbiFreeEx freeEx = null;

	extern "C" SHARED_EXPORT void *__cxa_allocate_exception(size_t thrown_size) {
		if (!allocEx)
			allocEx = (AbiAllocEx)dlsym(RTLD_NEXT, "__cxa_allocate_exception");

		void *result = (*allocEx)(thrown_size);
		trackException(result, thrown_size);
		return result;
	}

	extern "C" SHARED_EXPORT void __cxa_free_exception(void *thrown_object) {
		if (!freeEx)
			freeEx = (AbiFreeEx)dlsym(RTLD_NEXT, "__cxa_free_exception");

		untrackException(thrown_object);
		return (*freeEx)(thrown_object);
	}

#endif

}