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;
}
}
|