Working %disable and reap handling references from scheduler.
This commit is contained in:
parent
3765bdd3ac
commit
66f83f3b08
|
|
@ -0,0 +1,74 @@
|
|||
:vpi_module "system";
|
||||
|
||||
; Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
;
|
||||
; This source code is free software; you can redistribute it
|
||||
; and/or modify it in source code form under the terms of the GNU
|
||||
; General Public License as published by the Free Software
|
||||
; Foundation; either version 2 of the License, or (at your option)
|
||||
; any later version.
|
||||
;
|
||||
; This program is distributed in the hope that it will be useful,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program; if not, write to the Free Software
|
||||
; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
|
||||
; This example is similar to the following Verilog code. The idea is
|
||||
; to test the disable statement. The task creates a scope (called test)
|
||||
; that is a hook for the disable statement to get at the thread that
|
||||
; threatens to fail the test. If the disable statement works properly,
|
||||
; the test task will be disabled before the #5 delay expires.
|
||||
;
|
||||
; module main;
|
||||
; task test;
|
||||
; begin
|
||||
; #5 $display("FAILED...");
|
||||
; $finish;
|
||||
; end
|
||||
; endtask
|
||||
;
|
||||
; initial begin
|
||||
; fork
|
||||
; test;
|
||||
; #1 disable test;
|
||||
; join
|
||||
; $display("PASSED");
|
||||
; end
|
||||
; endmodule
|
||||
;
|
||||
|
||||
S_main .scope "main";
|
||||
S_test .scope "test", S_main;
|
||||
|
||||
|
||||
; This code in the implementation of the thread that goes into the
|
||||
; test scope. The idea is to disable this thread before it does its
|
||||
; job and prints a failure.
|
||||
.scope S_test;
|
||||
T_0/1 ;
|
||||
%delay 5;
|
||||
%vpi_call "$display", "FAILED -- thread wasn't disbled";
|
||||
%vpi_call "$finish";
|
||||
%end;
|
||||
|
||||
; This is the main thread. Fork the thread under test, delay for a
|
||||
; moment to let it run, then %disable the test thread. If I don't
|
||||
; disable the test thread in time, then the child will print an error
|
||||
; message and exit.
|
||||
.scope S_main;
|
||||
T_0 ;
|
||||
%fork T_0/1, S_test;
|
||||
%delay 1;
|
||||
|
||||
%disable S_test ; This is the statement that I'm testing.
|
||||
|
||||
%join;
|
||||
%vpi_call "$display", "PASSED";
|
||||
%end;
|
||||
|
||||
.thread T_0;
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: schedule.cc,v 1.5 2001/04/18 04:21:23 steve Exp $"
|
||||
#ident "$Id: schedule.cc,v 1.6 2001/04/21 00:34:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "schedule.h"
|
||||
|
|
@ -120,6 +120,7 @@ void schedule_vthread(vthread_t thr, unsigned delay)
|
|||
cur->delay = delay;
|
||||
cur->thr = thr;
|
||||
cur->type = TYPE_THREAD;
|
||||
vthread_mark_scheduled(thr);
|
||||
|
||||
schedule_event_(cur);
|
||||
}
|
||||
|
|
@ -195,6 +196,9 @@ void schedule_simulate(void)
|
|||
|
||||
/*
|
||||
* $Log: schedule.cc,v $
|
||||
* Revision 1.6 2001/04/21 00:34:39 steve
|
||||
* Working %disable and reap handling references from scheduler.
|
||||
*
|
||||
* Revision 1.5 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vthread.cc,v 1.28 2001/04/18 05:04:19 steve Exp $"
|
||||
#ident "$Id: vthread.cc,v 1.29 2001/04/21 00:34:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vthread.h"
|
||||
|
|
@ -87,6 +87,7 @@ struct vthread_s {
|
|||
unsigned schedule_parent_on_end :1;
|
||||
unsigned i_have_ended :1;
|
||||
unsigned waiting_for_event :1;
|
||||
unsigned is_scheduled :1;
|
||||
/* This points to the sole child of the thread. */
|
||||
struct vthread_s*child;
|
||||
/* This points to my parent, if I have one. */
|
||||
|
|
@ -194,9 +195,19 @@ static void vthread_reap(vthread_t thr)
|
|||
thr->scope_prev->scope_next = thr->scope_next;
|
||||
|
||||
thr->pc = 0;
|
||||
delete thr;
|
||||
|
||||
/* If this thread is not scheduled, then is it safe to delete
|
||||
it now. Otherwise, let the schedule event (which will
|
||||
execute the thread at of_ZOMBIE) delete the object. */
|
||||
if (thr->is_scheduled == 0)
|
||||
delete thr;
|
||||
}
|
||||
|
||||
void vthread_mark_scheduled(vthread_t thr)
|
||||
{
|
||||
assert(thr->is_scheduled == 0);
|
||||
thr->is_scheduled = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function runs a thread by fetching an instruction,
|
||||
|
|
@ -204,6 +215,9 @@ static void vthread_reap(vthread_t thr)
|
|||
*/
|
||||
void vthread_run(vthread_t thr)
|
||||
{
|
||||
assert(thr->is_scheduled);
|
||||
thr->is_scheduled = 0;
|
||||
|
||||
for (;;) {
|
||||
vvp_code_t cp = codespace_index(thr->pc);
|
||||
thr->pc += 1;
|
||||
|
|
@ -492,18 +506,24 @@ bool of_DISABLE(vthread_t thr, vvp_code_t cp)
|
|||
assert(tmp->child == 0);
|
||||
assert(tmp != thr);
|
||||
/* XXXX Not supported yet. */
|
||||
assert(tmp->waiting_for_event);
|
||||
assert(tmp->waiting_for_event == 0);
|
||||
|
||||
tmp->pc = 0;
|
||||
tmp->i_have_ended = 1;
|
||||
|
||||
/* If a parent is waiting in a %join, wake it up. */
|
||||
if (tmp->schedule_parent_on_end) {
|
||||
/* If a parent is waiting in a %join, wake it up. */
|
||||
assert(tmp->parent);
|
||||
schedule_vthread(tmp->parent, 0);
|
||||
}
|
||||
vthread_reap(tmp);
|
||||
|
||||
if (tmp->parent == 0) {
|
||||
} else if (tmp->parent) {
|
||||
/* If the parent is yet to %join me, let its %join
|
||||
do the reaping. */
|
||||
//assert(tmp->is_scheduled == 0);
|
||||
|
||||
} else {
|
||||
/* No parent at all. Goodby. */
|
||||
vthread_reap(tmp);
|
||||
}
|
||||
}
|
||||
|
|
@ -523,23 +543,10 @@ bool of_END(vthread_t thr, vvp_code_t)
|
|||
thr->i_have_ended = 1;
|
||||
thr->pc = 0;
|
||||
|
||||
#if 0
|
||||
/* Reap direct descendents that have already ended. Do
|
||||
this in a loop until I run out of dead children. */
|
||||
|
||||
while (thr->child && (thr->child->i_have_ended)) {
|
||||
fprintf(stderr, "vvp warning: A thread left dangling "
|
||||
"children at %%end. This is caused\n"
|
||||
" : by a missing %%join.\n");
|
||||
vthread_t tmp = thr->child;
|
||||
vthread_reap(tmp);
|
||||
}
|
||||
#else
|
||||
/* If this thread has children, then there is a programming
|
||||
error as there were not enough %join instructions to reap
|
||||
all the children. */
|
||||
assert(thr->child == 0);
|
||||
#endif
|
||||
|
||||
|
||||
/* If I have a parent who is waiting for me, then mark that I
|
||||
|
|
@ -556,12 +563,6 @@ bool of_END(vthread_t thr, vvp_code_t)
|
|||
no reason to stick around. This can happen, for example if
|
||||
I am an ``initial'' thread. */
|
||||
if (thr->parent == 0) {
|
||||
#if 0
|
||||
if (thr->child)
|
||||
fprintf(stderr, "vvp warning: A thread left dangling "
|
||||
"children at delete. This is caused\n"
|
||||
" : by a missing %%join.\n");
|
||||
#endif
|
||||
vthread_reap(thr);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -872,6 +873,9 @@ bool of_ZOMBIE(vthread_t thr, vvp_code_t)
|
|||
|
||||
/*
|
||||
* $Log: vthread.cc,v $
|
||||
* Revision 1.29 2001/04/21 00:34:39 steve
|
||||
* Working %disable and reap handling references from scheduler.
|
||||
*
|
||||
* Revision 1.28 2001/04/18 05:04:19 steve
|
||||
* %end complete the %join for the parent.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#if !defined(WINNT)
|
||||
#ident "$Id: vthread.h,v 1.4 2001/04/18 04:21:23 steve Exp $"
|
||||
#ident "$Id: vthread.h,v 1.5 2001/04/21 00:34:39 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -42,6 +42,12 @@ typedef struct vthread_s*vthread_t;
|
|||
*/
|
||||
extern vthread_t vthread_new(unsigned long sa, struct __vpiScope*scope);
|
||||
|
||||
/*
|
||||
* This function marks the thread as scheduled. It is used only by the
|
||||
* schedule_vthread function.
|
||||
*/
|
||||
extern void vthread_mark_scheduled(vthread_t thr);
|
||||
|
||||
/*
|
||||
* Cause this thread to execute instructions until in is put to sleep
|
||||
* by executing some sort of delay or wait instruction.
|
||||
|
|
@ -59,6 +65,9 @@ extern void vthread_schedule_list(vthread_t thr);
|
|||
|
||||
/*
|
||||
* $Log: vthread.h,v $
|
||||
* Revision 1.5 2001/04/21 00:34:39 steve
|
||||
* Working %disable and reap handling references from scheduler.
|
||||
*
|
||||
* Revision 1.4 2001/04/18 04:21:23 steve
|
||||
* Put threads into scopes.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue