Implement %disable/fork in run time.

This commit is contained in:
Cary R 2013-10-18 17:20:57 -07:00
parent e12d2b2f36
commit 589bb59268
1 changed files with 62 additions and 28 deletions

View File

@ -63,6 +63,11 @@ using namespace std;
* child of the current thread, and the current thread a parent of the
* new thread. Any child can be reaped by a %join.
*
* Children that are detached with %join/detach need to have a different
* parent/child relationship since the parent can still effect them if
* it uses the %disable/fork or %wait/fork opcodes. The i_am_detached
* flag and detached_children set are used for this relationship.
*
* Children placed into a task or function scope are given special
* treatment, which is required to make task/function calls that they
* represent work correctly. These task/function children are copied
@ -198,12 +203,15 @@ struct vthread_s {
/* My parent sets this when it wants me to wake it up. */
unsigned i_am_joining :1;
unsigned i_am_detached :1;
unsigned i_have_ended :1;
unsigned waiting_for_event :1;
unsigned is_scheduled :1;
unsigned delay_delete :1;
/* This points to the children of the thread. */
set<struct vthread_s*>children;
/* This points to the detached children of the thread. */
set<struct vthread_s*>detached_children;
/* No more than 1 of the children are tasks or functions. */
set<vthread_s*>task_func_children;
/* This points to my parent, if I have one. */
@ -533,10 +541,11 @@ vthread_t vthread_new(vvp_code_t pc, struct __vpiScope*scope)
thr->wt_context = 0;
thr->rd_context = 0;
thr->i_am_joining = 0;
thr->is_scheduled = 0;
thr->i_have_ended = 0;
thr->delay_delete = 0;
thr->i_am_joining = 0;
thr->i_am_detached = 0;
thr->is_scheduled = 0;
thr->i_have_ended = 0;
thr->delay_delete = 0;
thr->waiting_for_event = 0;
thr->event = 0;
thr->ecount = 0;
@ -603,13 +612,19 @@ static void vthread_reap(vthread_t thr)
}
}
if (thr->parent) {
//assert(thr->parent->child == thr);
thr->parent->children.erase(thr);
/* assert that the given element was removed. */
if (thr->i_am_detached) {
size_t res = thr->parent->detached_children.erase(thr);
assert(res == 1);
} else {
size_t res = thr->parent->children.erase(thr);
assert(res == 1);
}
}
thr->parent = 0;
// Remove myself from the containing scope.
// Remove myself from the containing scope if needed.
thr->parent_scope->threads.erase(thr);
thr->pc = codespace_null();
@ -2143,7 +2158,7 @@ static bool do_disable(vthread_t thr, vthread_t match)
{
bool flag = false;
/* Pull the target thread out of its scope. */
/* Pull the target thread out of its scope if needed. */
thr->parent_scope->threads.erase(thr);
/* Turn the thread off by setting is program counter to
@ -2227,24 +2242,21 @@ bool of_DISABLE_FORK(vthread_t thr, vvp_code_t)
{
/* If a %disable/fork is being executed then the parent thread
* cannot be waiting in a join. */
assert(thr->i_am_joining == 0);
assert(! thr->i_am_joining);
/* There should be no active children to disable. */
assert(thr->children.empty());
/* Disable any detached children. */
fprintf(stderr, "Sorry: %%disable/fork has not been implemented. It "
"will be ignored.\n");
#if 0
while (!thr->children.empty()) {
vthread_t tmp = *(thr->children.begin());
assert(tmp);
assert(tmp->parent == thr);
while (!thr->detached_children.empty()) {
vthread_t child = *(thr->detached_children.begin());
assert(child);
assert(child->parent == thr);
/* Disabling the children can never match the parent thread. */
assert(! do_disable(tmp, thr));
vthread_reap(tmp);
bool res = do_disable(child, thr);
assert(! res);
vthread_reap(child);
}
#endif
return true;
}
@ -2556,11 +2568,27 @@ bool of_END(vthread_t thr, vvp_code_t)
thr->i_have_ended = 1;
thr->pc = codespace_null();
/* Fully detach any detached children. */
while (!thr->detached_children.empty()) {
vthread_t child = *(thr->detached_children.begin());
assert(child);
assert(child->parent == thr);
assert(child->i_am_detached);
child->parent = 0;
child->i_am_detached = 0;
thr->detached_children.erase(thr->detached_children.begin());
}
/* It is an error to still have active children running at this
* point in time. They should have all been detached or joined. */
assert(thr->children.empty());
/* If I have a parent who is waiting for me, then mark that I
have ended, and schedule that parent. Also, finish the
%join for the parent. */
if (thr->parent && thr->parent->i_am_joining) {
vthread_t tmp = thr->parent;
assert(! thr->i_am_detached);
// Detect that the parent is waiting on a task or function
// thread. These threads must be reaped first. If the
@ -2575,15 +2603,18 @@ bool of_END(vthread_t thr, vvp_code_t)
return false;
}
/* If I have no parents, then no one can %join me and there is
no reason to stick around. This can happen, for example if
I am an ``initial'' thread.
/* If this thread is not fully detached then remove it from the
* parents detached_children set. */
if (thr->i_am_detached) {
assert(thr->parent);
size_t res = thr->parent->detached_children.erase(thr);
assert(res == 1);
}
If I have children at this point, then I must have been the
main thread (there is no other parent) and an error (not
enough %joins) has been detected. */
/* If I have no parent, then no one can %join me and there is
* no reason to stick around. This can happen, for example if
* I am an ``initial'' thread. */
if (thr->parent == 0) {
assert(thr->children.empty());
vthread_reap(thr);
return false;
}
@ -3089,6 +3120,7 @@ static void do_join(vthread_t thr, vthread_t child)
{
assert(child->parent == thr);
/* Remove the thread from the task/function set if needed. */
thr->task_func_children.erase(child);
/* If the immediate child thread is in an automatic scope... */
@ -3160,8 +3192,10 @@ bool of_JOIN_DETACH(vthread_t thr, vvp_code_t cp)
vthread_reap(child);
} else {
thr->children.erase(child);
child->parent = 0;
size_t res = child->parent->children.erase(child);
assert(res == 1);
child->i_am_detached = 1;
thr->detached_children.insert(child);
}
}