diff --git a/vvp/schedule.cc b/vvp/schedule.cc index 104ed30d5..a9700891f 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -669,6 +669,9 @@ void schedule_generic(vvp_gen_event_t obj, vvp_time64_t delay, cur->delete_obj_when_done = delete_when_done; schedule_event_(cur, delay, sync_flag? (ro_flag?SEQ_ROSYNC:SEQ_RWSYNC) : SEQ_ACTIVE); + + if (sync_flag) + vthread_delay_delete(); } void schedule_at_start_of_simtime(vvp_gen_event_t obj, vvp_time64_t delay) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 03e4124a1..04237dcc2 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -111,6 +111,7 @@ struct vthread_s { unsigned i_have_ended :1; unsigned waiting_for_event :1; unsigned is_scheduled :1; + unsigned delay_delete :1; unsigned fork_count :8; /* This points to the sole child of the thread. */ struct vthread_s*child; @@ -411,6 +412,7 @@ vthread_t vthread_new(vvp_code_t pc, struct __vpiScope*scope) thr->schedule_parent_on_end = 0; thr->is_scheduled = 0; thr->i_have_ended = 0; + thr->delay_delete = 0; thr->waiting_for_event = 0; thr->fork_count = 0; thr->event = 0; @@ -498,7 +500,10 @@ static void vthread_reap(vthread_t thr) if ((thr->is_scheduled == 0) && (thr->waiting_for_event == 0)) { assert(thr->fork_count == 0); assert(thr->wait_next == 0); - schedule_del_thr(thr); + if (thr->delay_delete) + schedule_del_thr(thr); + else + vthread_delete(thr); } } @@ -517,6 +522,12 @@ void vthread_mark_scheduled(vthread_t thr) } } +void vthread_delay_delete() +{ + if (running_thread) + running_thread->delay_delete = 1; +} + /* * This function runs each thread by fetching an instruction, * incrementing the PC, and executing the instruction. The thread may @@ -4541,9 +4552,12 @@ bool of_XOR(vthread_t thr, vvp_code_t cp) bool of_ZOMBIE(vthread_t thr, vvp_code_t) { thr->pc = codespace_null(); - if ((thr->parent == 0) && (thr->child == 0)) - schedule_del_thr(thr); - + if ((thr->parent == 0) && (thr->child == 0)) { + if (thr->delay_delete) + schedule_del_thr(thr); + else + vthread_delete(thr); + } return false; } diff --git a/vvp/vthread.h b/vvp/vthread.h index 46999fa57..0e8d47966 100644 --- a/vvp/vthread.h +++ b/vvp/vthread.h @@ -1,7 +1,7 @@ #ifndef __vthread_H #define __vthread_H /* - * Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2009 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 @@ -48,6 +48,14 @@ extern vthread_t vthread_new(vvp_code_t sa, struct __vpiScope*scope); */ extern void vthread_mark_scheduled(vthread_t thr); +/* + * This function causes deletion of the currently running thread to + * be delayed until after all sync events have been processed for the + * time step in which the thread terminates. It is only used by the + * schedule_generic function. + */ +extern void vthread_delay_delete(); + /* * Cause this thread to execute instructions until in is put to sleep * by executing some sort of delay or wait instruction.