File: StackMirror.cpp

package info (click to toggle)
storm-lang 0.7.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,004 kB
  • sloc: ansic: 261,462; cpp: 140,405; 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 (124 lines) | stat: -rw-r--r-- 3,108 bytes parent folder | download | duplicates (2)
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
#include "stdafx.h"
#include "StackMirror.h"
#include "Engine.h"

namespace storm {

	StackMirror::StackMirror(os::UThreadData *thread) : thread(thread), root(null), stackContents(null), stackCount(0) {
		if (thread)
			thread->addRef();
	}

	StackMirror::StackMirror(const StackMirror &o) : thread(o.thread), root(null), stackContents(null), stackCount(0) {
		if (o.thread)
			thread->addRef();

		allocContents(o.stackCount);
		for (size_t i = 0; i < o.stackCount; i++)
			stackContents[i] = o.stackContents[i];
	}

	StackMirror::~StackMirror() {
		clear();
	}

	StackMirror &StackMirror::operator =(const StackMirror &o) {
		if (&o == this)
			return *this;

		clear();

		thread = o.thread;
		if (thread)
			thread->addRef();

		allocContents(o.stackCount);
		for (size_t i = 0; i < o.stackCount; i++)
			stackContents[i] = o.stackContents[i];

		return *this;
	}

	void StackMirror::clear() {
		if (thread)
			thread->release();
		thread = null;

		freeContents();
	}

	void StackMirror::allocContents(size_t count) {
		stackCount = count;
		stackContents = (size_t *)malloc(count * sizeof(size_t));
		memset(stackContents, 0, count * sizeof(size_t));
		root = engine().gc.createRoot(stackContents, count, true);
	}

	void StackMirror::freeContents() {
		if (root)
			Gc::destroyRoot(root);
		root = null;

		if (stackContents)
			free(stackContents);
		stackContents = null;
		stackCount = 0;
	}

	StackMirror *StackMirror::save(EnginePtr e, Word threadId) {
		os::UThreadData *data = reinterpret_cast<os::UThreadData *>(static_cast<size_t>(threadId));
		if (!data)
			return null;

		// If the desc does not exist, then it is currently running, and we can not copy it.
		const os::Stack &stack = data->stack;
		if (!stack.desc)
			return null;

		// We more or less assume that the desc is at the top of the stack. This is always the case,
		// except maybe when the thread was just created, or when a detour is set up.
		if (stack.desc->low != stack.desc)
			return null;

		StackMirror *mirror = new (e.v) StackMirror(data);

		size_t *low = (size_t *)stack.desc->low;
		size_t toCopy = size_t(stack.base()) - size_t(low);
		toCopy /= sizeof(size_t);

		mirror->allocContents(toCopy);
		for (size_t i = 0; i < toCopy; i++) {
			mirror->stackContents[i] = low[i];
		}

		return mirror;
	}

	Bool StackMirror::restore() {
		if (!thread || !stackContents)
			return false;

		os::Stack &stack = thread->stack;
		if (!stack.desc)
			return false;

		size_t *base = (size_t *)stack.base();
		base -= stackCount;

		// Note: We are storing the stack contents in a pinned set already, so it is fine for us to
		// copy first and set the 'desc' later. No objects will be missed anyway. Otherwise, we
		// would have to copy the StackDesc first, then update 'desc' and then copy the rest of the data.
		for (size_t i = 0; i < stackCount; i++)
			base[i] = stackContents[i];

		stack.desc = (os::Stack::Desc *)base;

		// Check if the thread is scheduled anywhere. If not, resurrect it and put it on the ready queue now!
		if (!thread->next) {
			thread->owner()->resurrect(thread);
		}

		return true;
	}

}