From d28aa0c2f1fc8827ee7f6958ab8d13630b9d2be9 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Sun, 24 Mar 2019 05:43:04 +0100 Subject: fsm_dealloc_test: no need for ST_DESTROYING A separate ST_DESTROYING state originally helped with certain deallocation scenarios. But now that fsm.c avoids re-entering osmo_fsm_inst_term() twice and gracefully handles FSM instance deallocations for termination cascades, it is actually just as safe without a separate ST_DESTROYING state. ST_DESTROYING was used to flag deallocation and prevent entering osmo_fsm_inst_term() twice, which works only in a very limited range of scenarios. Remove ST_DESTROYING from fsm_dealloc_test.c to show that all tested scenarios still clean up gracefully. Change-Id: I05354e6cad9b82ba474fa50ffd41d481b3c697b4 --- tests/fsm/fsm_dealloc_test.c | 54 +- tests/fsm/fsm_dealloc_test.err | 3267 +++++++++++++++++++--------------------- 2 files changed, 1521 insertions(+), 1800 deletions(-) diff --git a/tests/fsm/fsm_dealloc_test.c b/tests/fsm/fsm_dealloc_test.c index f8d2b1ee..ce492056 100644 --- a/tests/fsm/fsm_dealloc_test.c +++ b/tests/fsm/fsm_dealloc_test.c @@ -22,7 +22,6 @@ static const struct value_string test_fsm_event_names[] = { enum state { ST_ALIVE, - ST_DESTROYING, }; enum objname { @@ -148,52 +147,19 @@ void alive(struct osmo_fsm_inst *fi, uint32_t event, void *data) case EV_OTHER_GONE: if (other_gone(obj, data)) { /* Something this object depends on is gone, trigger deallocation */ - osmo_fsm_inst_state_chg(fi, ST_DESTROYING, 0, 0); + osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, 0); } break; case EV_CHILD_GONE: if (!child_gone(obj, data)) { /* All children are gone. Deallocate. */ - osmo_fsm_inst_state_chg(fi, ST_DESTROYING, 0, 0); + osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, 0); } break; case EV_DESTROY: - osmo_fsm_inst_state_chg(fi, ST_DESTROYING, 0, 0); - break; - - default: - OSMO_ASSERT(false); - } - PUT(); -} - -void destroying_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) -{ - struct obj *obj = fi->priv; - GET(); - LOGPFSML(fi, LOGL_DEBUG, "%s() from %s\n", __func__, osmo_fsm_state_name(fi->fsm, prev_state)); - osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, 0); - PUT(); -} - -void destroying(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct obj *obj = fi->priv; - GET(); - LOGPFSML(fi, LOGL_DEBUG, "%s(%s)\n", __func__, osmo_fsm_event_name(fi->fsm, event)); - switch (event) { - case EV_OTHER_GONE: - other_gone(obj, data); - break; - - case EV_CHILD_GONE: - child_gone(obj, data); - break; - - case EV_DESTROY: - LOGPFSML(fi, LOGL_DEBUG, "already destroying\n"); + osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, 0); break; default: @@ -214,24 +180,10 @@ static const struct osmo_fsm_state test_fsm_states[] = { , .out_state_mask = 0 | S(ST_ALIVE) - | S(ST_DESTROYING) , .onenter = alive_onenter, .action = alive, }, - [ST_DESTROYING] = { - .name = "destroying", - .in_event_mask = 0 - | S(EV_CHILD_GONE) - | S(EV_OTHER_GONE) - | S(EV_DESTROY) - , - .out_state_mask = 0 - | S(ST_DESTROYING) - , - .onenter = destroying_onenter, - .action = destroying, - }, }; void cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause) diff --git a/tests/fsm/fsm_dealloc_test.err b/tests/fsm/fsm_dealloc_test.err index aa7db51e..d12c5aa3 100644 --- a/tests/fsm/fsm_dealloc_test.err +++ b/tests/fsm/fsm_dealloc_test.err @@ -66,11 +66,7 @@ DLGLOBAL DEBUG test(root){alive}: alive(EV_OTHER_GONE) DLGLOBAL DEBUG 3 (__twig1a.cleanup(),root.alive(),root.other_gone()) DLGLOBAL DEBUG test(root){alive}: EV_OTHER_GONE: Dropped reference root.other[0] = __twig1a DLGLOBAL DEBUG 2 (__twig1a.cleanup(),root.alive()) -DLGLOBAL DEBUG test(root){alive}: state_chg to destroying -DLGLOBAL DEBUG 3 (__twig1a.cleanup(),root.alive(),root.destroying_onenter()) -DLGLOBAL DEBUG test(root){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(root){destroying}: Ignoring trigger to terminate: already terminating -DLGLOBAL DEBUG 2 (__twig1a.cleanup(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: Ignoring trigger to terminate: already terminating DLGLOBAL DEBUG 1 (__twig1a.cleanup()) DLGLOBAL DEBUG test(_branch1){alive}: Received Event EV_CHILD_GONE DLGLOBAL DEBUG 2 (__twig1a.cleanup(),_branch1.alive()) @@ -79,131 +75,121 @@ DLGLOBAL DEBUG 3 (__twig1a.cleanup(),_branch1.alive(),_branch1.child_gone()) DLGLOBAL DEBUG test(_branch1){alive}: EV_CHILD_GONE: Dropped reference _branch1.child[0] = __twig1a DLGLOBAL DEBUG test(_branch1){alive}: No more children DLGLOBAL DEBUG 2 (__twig1a.cleanup(),_branch1.alive()) -DLGLOBAL DEBUG test(_branch1){alive}: state_chg to destroying -DLGLOBAL DEBUG 3 (__twig1a.cleanup(),_branch1.alive(),_branch1.destroying_onenter()) -DLGLOBAL DEBUG test(_branch1){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(_branch1){destroying}: Ignoring trigger to terminate: already terminating -DLGLOBAL DEBUG 2 (__twig1a.cleanup(),_branch1.alive()) +DLGLOBAL DEBUG test(_branch1){alive}: Ignoring trigger to terminate: already terminating DLGLOBAL DEBUG 1 (__twig1a.cleanup()) DLGLOBAL DEBUG test(__twig1a){alive}: cleanup() done DLGLOBAL DEBUG 0 (-) DLGLOBAL DEBUG test(__twig1a){alive}: Deferring: will deallocate with test(root) -DLGLOBAL DEBUG test(_branch1){destroying}: Removing from parent test(root) +DLGLOBAL DEBUG test(_branch1){alive}: Removing from parent test(root) DLGLOBAL DEBUG 1 (_branch1.cleanup()) -DLGLOBAL DEBUG test(_branch1){destroying}: cleanup() -DLGLOBAL DEBUG test(_branch1){destroying}: scene forgets _branch1 -DLGLOBAL DEBUG test(_branch1){destroying}: removing reference _branch1.other[0] -> other +DLGLOBAL DEBUG test(_branch1){alive}: cleanup() +DLGLOBAL DEBUG test(_branch1){alive}: scene forgets _branch1 +DLGLOBAL DEBUG test(_branch1){alive}: removing reference _branch1.other[0] -> other DLGLOBAL DEBUG test(other){alive}: Received Event EV_OTHER_GONE DLGLOBAL DEBUG 2 (_branch1.cleanup(),other.alive()) DLGLOBAL DEBUG test(other){alive}: alive(EV_OTHER_GONE) DLGLOBAL DEBUG 3 (_branch1.cleanup(),other.alive(),other.other_gone()) DLGLOBAL DEBUG test(other){alive}: EV_OTHER_GONE: Dropped reference other.other[1] = _branch1 DLGLOBAL DEBUG 2 (_branch1.cleanup(),other.alive()) -DLGLOBAL DEBUG test(other){alive}: state_chg to destroying -DLGLOBAL DEBUG 3 (_branch1.cleanup(),other.alive(),other.destroying_onenter()) -DLGLOBAL DEBUG test(other){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(other){destroying}: Terminating in cascade, depth 3 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(root)) -DLGLOBAL DEBUG test(other){destroying}: pre_term() -DLGLOBAL DEBUG 4 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup()) -DLGLOBAL DEBUG test(other){destroying}: cleanup() -DLGLOBAL DEBUG test(other){destroying}: scene forgets other -DLGLOBAL DEBUG test(other){destroying}: removing reference other.other[0] -> _branch0 +DLGLOBAL DEBUG test(other){alive}: Terminating in cascade, depth 3 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(root)) +DLGLOBAL DEBUG test(other){alive}: pre_term() +DLGLOBAL DEBUG 3 (_branch1.cleanup(),other.alive(),other.cleanup()) +DLGLOBAL DEBUG test(other){alive}: cleanup() +DLGLOBAL DEBUG test(other){alive}: scene forgets other +DLGLOBAL DEBUG test(other){alive}: removing reference other.other[0] -> _branch0 DLGLOBAL DEBUG test(_branch0){alive}: Received Event EV_OTHER_GONE -DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive()) +DLGLOBAL DEBUG 4 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) DLGLOBAL DEBUG test(_branch0){alive}: alive(EV_OTHER_GONE) -DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.other_gone()) +DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.other_gone()) DLGLOBAL DEBUG test(_branch0){alive}: EV_OTHER_GONE: Dropped reference _branch0.other[0] = other -DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive()) -DLGLOBAL DEBUG test(_branch0){alive}: state_chg to destroying -DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter()) -DLGLOBAL DEBUG test(_branch0){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(_branch0){destroying}: Terminating in cascade, depth 4 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(root)) -DLGLOBAL DEBUG test(_branch0){destroying}: pre_term() +DLGLOBAL DEBUG 4 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) +DLGLOBAL DEBUG test(_branch0){alive}: Terminating in cascade, depth 4 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(root)) +DLGLOBAL DEBUG test(_branch0){alive}: pre_term() DLGLOBAL DEBUG test(__twig0b){alive}: Terminating in cascade, depth 5 (cause = OSMO_FSM_TERM_PARENT, caused by: test(root)) DLGLOBAL DEBUG test(__twig0b){alive}: pre_term() DLGLOBAL DEBUG test(__twig0b){alive}: Removing from parent test(_branch0) -DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ +DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),__twig0b.cleanup()) DLGLOBAL DEBUG test(__twig0b){alive}: cleanup() DLGLOBAL DEBUG test(__twig0b){alive}: scene forgets __twig0b -DLGLOBAL DEBUG test(_branch0){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 8 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch0){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 9 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch0){destroying}: EV_CHILD_GONE: Dropped reference _branch0.child[1] = __twig0b -DLGLOBAL DEBUG test(_branch0){destroying}: still exists: child[0] -DLGLOBAL DEBUG 8 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ +DLGLOBAL DEBUG test(_branch0){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0b.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0b.cleanup(),_branch0.child_gone()) +DLGLOBAL DEBUG test(_branch0){alive}: EV_CHILD_GONE: Dropped reference _branch0.child[1] = __twig0b +DLGLOBAL DEBUG test(_branch0){alive}: still exists: child[0] +DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0b.cleanup()) +DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),__twig0b.cleanup()) DLGLOBAL DEBUG test(__twig0b){alive}: cleanup() done -DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter()) +DLGLOBAL DEBUG 4 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) DLGLOBAL DEBUG test(__twig0b){alive}: Deferring: will deallocate with test(root) DLGLOBAL DEBUG test(__twig0a){alive}: Terminating in cascade, depth 5 (cause = OSMO_FSM_TERM_PARENT, caused by: test(root)) DLGLOBAL DEBUG test(__twig0a){alive}: pre_term() DLGLOBAL DEBUG test(__twig0a){alive}: Removing from parent test(_branch0) -DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ +DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup()) DLGLOBAL DEBUG test(__twig0a){alive}: cleanup() DLGLOBAL DEBUG test(__twig0a){alive}: scene forgets __twig0a DLGLOBAL DEBUG test(__twig0a){alive}: removing reference __twig0a.other[0] -> other -DLGLOBAL DEBUG test(other){destroying}: Received Event EV_OTHER_GONE -DLGLOBAL DEBUG 8 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG test(other){destroying}: destroying(EV_OTHER_GONE) -DLGLOBAL DEBUG 9 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG 8 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch0){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 8 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch0){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 9 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch0){destroying}: EV_CHILD_GONE: Dropped reference _branch0.child[0] = __twig0a -DLGLOBAL DEBUG test(_branch0){destroying}: No more children -DLGLOBAL DEBUG 8 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ +DLGLOBAL DEBUG test(other){alive}: Received Event EV_OTHER_GONE +DLGLOBAL DEBUG 6 (_branch1.cleanup(),2*other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup()) +DLGLOBAL DEBUG test(other){alive}: alive(EV_OTHER_GONE) +DLGLOBAL DEBUG 7 (_branch1.cleanup(),2*other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup(),other.other_gone()) +DLGLOBAL DEBUG 6 (_branch1.cleanup(),2*other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup()) +DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0a.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0a.cleanup(),_branch0.child_gone()) +DLGLOBAL DEBUG test(_branch0){alive}: EV_CHILD_GONE: Dropped reference _branch0.child[0] = __twig0a +DLGLOBAL DEBUG test(_branch0){alive}: No more children +DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0a.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: Ignoring trigger to terminate: already terminating +DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup()) DLGLOBAL DEBUG test(__twig0a){alive}: cleanup() done -DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter()) +DLGLOBAL DEBUG 4 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) DLGLOBAL DEBUG test(__twig0a){alive}: Deferring: will deallocate with test(root) -DLGLOBAL DEBUG test(_branch0){destroying}: Removing from parent test(root) -DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch0){destroying}: cleanup() -DLGLOBAL DEBUG test(_branch0){destroying}: scene forgets _branch0 -DLGLOBAL DEBUG test(root){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 8 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG test(root){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 9 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG test(root){destroying}: EV_CHILD_GONE: Dropped reference root.child[0] = _branch0 -DLGLOBAL DEBUG test(root){destroying}: still exists: child[1] -DLGLOBAL DEBUG 8 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch0){destroying}: cleanup() done -DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter()) -DLGLOBAL DEBUG test(root){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter(),r -DLGLOBAL DEBUG test(root){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG test(root){destroying}: EV_CHILD_GONE with NULL data, must be a parent_term event. Ignore. -DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive(),_branch0.destroying_onenter()) -DLGLOBAL DEBUG test(_branch0){destroying}: Deferring: will deallocate with test(root) -DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0.alive()) -DLGLOBAL DEBUG 4 (_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup()) -DLGLOBAL DEBUG test(other){destroying}: cleanup() done -DLGLOBAL DEBUG 3 (_branch1.cleanup(),other.alive(),other.destroying_onenter()) -DLGLOBAL DEBUG test(other){destroying}: Deferring: will deallocate with test(root) +DLGLOBAL DEBUG test(_branch0){alive}: Removing from parent test(root) +DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: cleanup() +DLGLOBAL DEBUG test(_branch0){alive}: scene forgets _branch0 +DLGLOBAL DEBUG test(root){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.cleanup(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 7 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.cleanup(),root.alive(),root.child_gone()) +DLGLOBAL DEBUG test(root){alive}: EV_CHILD_GONE: Dropped reference root.child[0] = _branch0 +DLGLOBAL DEBUG test(root){alive}: still exists: child[1] +DLGLOBAL DEBUG 6 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.cleanup(),root.alive()) +DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: cleanup() done +DLGLOBAL DEBUG 4 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) +DLGLOBAL DEBUG test(root){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 5 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG test(root){alive}: EV_CHILD_GONE with NULL data, must be a parent_term event. Ignore. +DLGLOBAL DEBUG 4 (_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) +DLGLOBAL DEBUG test(_branch0){alive}: Deferring: will deallocate with test(root) +DLGLOBAL DEBUG 3 (_branch1.cleanup(),other.alive(),other.cleanup()) +DLGLOBAL DEBUG test(other){alive}: cleanup() done DLGLOBAL DEBUG 2 (_branch1.cleanup(),other.alive()) +DLGLOBAL DEBUG test(other){alive}: Deferring: will deallocate with test(root) DLGLOBAL DEBUG 1 (_branch1.cleanup()) -DLGLOBAL DEBUG test(root){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 2 (_branch1.cleanup(),root.destroying()) -DLGLOBAL DEBUG test(root){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 3 (_branch1.cleanup(),root.destroying(),root.child_gone()) -DLGLOBAL DEBUG test(root){destroying}: EV_CHILD_GONE: Dropped reference root.child[1] = _branch1 -DLGLOBAL DEBUG test(root){destroying}: No more children -DLGLOBAL DEBUG 2 (_branch1.cleanup(),root.destroying()) +DLGLOBAL DEBUG test(root){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 2 (_branch1.cleanup(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 3 (_branch1.cleanup(),root.alive(),root.child_gone()) +DLGLOBAL DEBUG test(root){alive}: EV_CHILD_GONE: Dropped reference root.child[1] = _branch1 +DLGLOBAL DEBUG test(root){alive}: No more children +DLGLOBAL DEBUG 2 (_branch1.cleanup(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: Ignoring trigger to terminate: already terminating DLGLOBAL DEBUG 1 (_branch1.cleanup()) -DLGLOBAL DEBUG test(_branch1){destroying}: cleanup() done +DLGLOBAL DEBUG test(_branch1){alive}: cleanup() done DLGLOBAL DEBUG 0 (-) -DLGLOBAL DEBUG test(_branch1){destroying}: Deferring: will deallocate with test(root) +DLGLOBAL DEBUG test(_branch1){alive}: Deferring: will deallocate with test(root) DLGLOBAL DEBUG 1 (root.cleanup()) -DLGLOBAL DEBUG test(root){destroying}: cleanup() -DLGLOBAL DEBUG test(root){destroying}: scene forgets root -DLGLOBAL DEBUG test(root){destroying}: cleanup() done +DLGLOBAL DEBUG test(root){alive}: cleanup() +DLGLOBAL DEBUG test(root){alive}: scene forgets root +DLGLOBAL DEBUG test(root){alive}: cleanup() done DLGLOBAL DEBUG 0 (-) -DLGLOBAL DEBUG test(root){destroying}: Deallocated, including all deferred deallocations +DLGLOBAL DEBUG test(root){alive}: Deallocated, including all deferred deallocations DLGLOBAL DEBUG --- after term cascade: DLGLOBAL DEBUG --- all deallocated. DLGLOBAL DEBUG scene_alloc() @@ -243,177 +229,164 @@ DLGLOBAL DEBUG --- destroy-event at root DLGLOBAL DEBUG test(root){alive}: Received Event EV_DESTROY DLGLOBAL DEBUG 1 (root.alive()) DLGLOBAL DEBUG test(root){alive}: alive(EV_DESTROY) -DLGLOBAL DEBUG test(root){alive}: state_chg to destroying -DLGLOBAL DEBUG 2 (root.alive(),root.destroying_onenter()) -DLGLOBAL DEBUG test(root){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(root){destroying}: Terminating (cause = OSMO_FSM_TERM_REGULAR) -DLGLOBAL DEBUG test(root){destroying}: pre_term() +DLGLOBAL DEBUG test(root){alive}: Terminating (cause = OSMO_FSM_TERM_REGULAR) +DLGLOBAL DEBUG test(root){alive}: pre_term() DLGLOBAL DEBUG test(_branch1){alive}: Terminating in cascade, depth 2 (cause = OSMO_FSM_TERM_PARENT, caused by: test(root)) DLGLOBAL DEBUG test(_branch1){alive}: pre_term() DLGLOBAL DEBUG test(__twig1b){alive}: Terminating in cascade, depth 3 (cause = OSMO_FSM_TERM_PARENT, caused by: test(root)) DLGLOBAL DEBUG test(__twig1b){alive}: pre_term() DLGLOBAL DEBUG test(__twig1b){alive}: Removing from parent test(_branch1) -DLGLOBAL DEBUG 3 (root.alive(),root.destroying_onenter(),__twig1b.cleanup()) +DLGLOBAL DEBUG 2 (root.alive(),__twig1b.cleanup()) DLGLOBAL DEBUG test(__twig1b){alive}: cleanup() DLGLOBAL DEBUG test(__twig1b){alive}: scene forgets __twig1b DLGLOBAL DEBUG test(_branch1){alive}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),__twig1b.cleanup(),_branch1.alive()) +DLGLOBAL DEBUG 3 (root.alive(),__twig1b.cleanup(),_branch1.alive()) DLGLOBAL DEBUG test(_branch1){alive}: alive(EV_CHILD_GONE) -DLGLOBAL DEBUG 5 (root.alive(),root.destroying_onenter(),__twig1b.cleanup(),_branch1.alive(),_branch1.child_gone()) +DLGLOBAL DEBUG 4 (root.alive(),__twig1b.cleanup(),_branch1.alive(),_branch1.child_gone()) DLGLOBAL DEBUG test(_branch1){alive}: EV_CHILD_GONE: Dropped reference _branch1.child[1] = __twig1b DLGLOBAL DEBUG test(_branch1){alive}: still exists: child[0] -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),__twig1b.cleanup(),_branch1.alive()) -DLGLOBAL DEBUG 3 (root.alive(),root.destroying_onenter(),__twig1b.cleanup()) +DLGLOBAL DEBUG 3 (root.alive(),__twig1b.cleanup(),_branch1.alive()) +DLGLOBAL DEBUG 2 (root.alive(),__twig1b.cleanup()) DLGLOBAL DEBUG test(__twig1b){alive}: cleanup() done -DLGLOBAL DEBUG 2 (root.alive(),root.destroying_onenter()) +DLGLOBAL DEBUG 1 (root.alive()) DLGLOBAL DEBUG test(__twig1b){alive}: Deferring: will deallocate with test(root) DLGLOBAL DEBUG test(__twig1a){alive}: Terminating in cascade, depth 3 (cause = OSMO_FSM_TERM_PARENT, caused by: test(root)) DLGLOBAL DEBUG test(__twig1a){alive}: pre_term() DLGLOBAL DEBUG test(__twig1a){alive}: Removing from parent test(_branch1) -DLGLOBAL DEBUG 3 (root.alive(),root.destroying_onenter(),__twig1a.cleanup()) +DLGLOBAL DEBUG 2 (root.alive(),__twig1a.cleanup()) DLGLOBAL DEBUG test(__twig1a){alive}: cleanup() DLGLOBAL DEBUG test(__twig1a){alive}: scene forgets __twig1a DLGLOBAL DEBUG test(__twig1a){alive}: removing reference __twig1a.other[0] -> root -DLGLOBAL DEBUG test(root){destroying}: Received Event EV_OTHER_GONE -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),__twig1a.cleanup(),root.destroying()) -DLGLOBAL DEBUG test(root){destroying}: destroying(EV_OTHER_GONE) -DLGLOBAL DEBUG 5 (root.alive(),root.destroying_onenter(),__twig1a.cleanup(),root.destroying(),root.other_gone()) -DLGLOBAL DEBUG test(root){destroying}: EV_OTHER_GONE: Dropped reference root.other[0] = __twig1a -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),__twig1a.cleanup(),root.destroying()) -DLGLOBAL DEBUG 3 (root.alive(),root.destroying_onenter(),__twig1a.cleanup()) +DLGLOBAL DEBUG test(root){alive}: Received Event EV_OTHER_GONE +DLGLOBAL DEBUG 3 (2*root.alive(),__twig1a.cleanup()) +DLGLOBAL DEBUG test(root){alive}: alive(EV_OTHER_GONE) +DLGLOBAL DEBUG 4 (2*root.alive(),__twig1a.cleanup(),root.other_gone()) +DLGLOBAL DEBUG test(root){alive}: EV_OTHER_GONE: Dropped reference root.other[0] = __twig1a +DLGLOBAL DEBUG 3 (2*root.alive(),__twig1a.cleanup()) +DLGLOBAL DEBUG test(root){alive}: Ignoring trigger to terminate: already terminating +DLGLOBAL DEBUG 2 (root.alive(),__twig1a.cleanup()) DLGLOBAL DEBUG test(_branch1){alive}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),__twig1a.cleanup(),_branch1.alive()) +DLGLOBAL DEBUG 3 (root.alive(),__twig1a.cleanup(),_branch1.alive()) DLGLOBAL DEBUG test(_branch1){alive}: alive(EV_CHILD_GONE) -DLGLOBAL DEBUG 5 (root.alive(),root.destroying_onenter(),__twig1a.cleanup(),_branch1.alive(),_branch1.child_gone()) +DLGLOBAL DEBUG 4 (root.alive(),__twig1a.cleanup(),_branch1.alive(),_branch1.child_gone()) DLGLOBAL DEBUG test(_branch1){alive}: EV_CHILD_GONE: Dropped reference _branch1.child[0] = __twig1a DLGLOBAL DEBUG test(_branch1){alive}: No more children -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),__twig1a.cleanup(),_branch1.alive()) -DLGLOBAL DEBUG test(_branch1){alive}: state_chg to destroying -DLGLOBAL DEBUG 5 (root.alive(),root.destroying_onenter(),__twig1a.cleanup(),_branch1.alive(),_branch1.destroying_onenter()) -DLGLOBAL DEBUG test(_branch1){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(_branch1){destroying}: Ignoring trigger to terminate: already terminating -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),__twig1a.cleanup(),_branch1.alive()) -DLGLOBAL DEBUG 3 (root.alive(),root.destroying_onenter(),__twig1a.cleanup()) +DLGLOBAL DEBUG 3 (root.alive(),__twig1a.cleanup(),_branch1.alive()) +DLGLOBAL DEBUG test(_branch1){alive}: Ignoring trigger to terminate: already terminating +DLGLOBAL DEBUG 2 (root.alive(),__twig1a.cleanup()) DLGLOBAL DEBUG test(__twig1a){alive}: cleanup() done -DLGLOBAL DEBUG 2 (root.alive(),root.destroying_onenter()) +DLGLOBAL DEBUG 1 (root.alive()) DLGLOBAL DEBUG test(__twig1a){alive}: Deferring: will deallocate with test(root) -DLGLOBAL DEBUG test(_branch1){destroying}: Removing from parent test(root) -DLGLOBAL DEBUG 3 (root.alive(),root.destroying_onenter(),_branch1.cleanup()) -DLGLOBAL DEBUG test(_branch1){destroying}: cleanup() -DLGLOBAL DEBUG test(_branch1){destroying}: scene forgets _branch1 -DLGLOBAL DEBUG test(_branch1){destroying}: removing reference _branch1.other[0] -> other +DLGLOBAL DEBUG test(_branch1){alive}: Removing from parent test(root) +DLGLOBAL DEBUG 2 (root.alive(),_branch1.cleanup()) +DLGLOBAL DEBUG test(_branch1){alive}: cleanup() +DLGLOBAL DEBUG test(_branch1){alive}: scene forgets _branch1 +DLGLOBAL DEBUG test(_branch1){alive}: removing reference _branch1.other[0] -> other DLGLOBAL DEBUG test(other){alive}: Received Event EV_OTHER_GONE -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive()) +DLGLOBAL DEBUG 3 (root.alive(),_branch1.cleanup(),other.alive()) DLGLOBAL DEBUG test(other){alive}: alive(EV_OTHER_GONE) -DLGLOBAL DEBUG 5 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.other_gone()) +DLGLOBAL DEBUG 4 (root.alive(),_branch1.cleanup(),other.alive(),other.other_gone()) DLGLOBAL DEBUG test(other){alive}: EV_OTHER_GONE: Dropped reference other.other[1] = _branch1 -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive()) -DLGLOBAL DEBUG test(other){alive}: state_chg to destroying -DLGLOBAL DEBUG 5 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter()) -DLGLOBAL DEBUG test(other){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(other){destroying}: Terminating in cascade, depth 3 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(root)) -DLGLOBAL DEBUG test(other){destroying}: pre_term() -DLGLOBAL DEBUG 6 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup()) -DLGLOBAL DEBUG test(other){destroying}: cleanup() -DLGLOBAL DEBUG test(other){destroying}: scene forgets other -DLGLOBAL DEBUG test(other){destroying}: removing reference other.other[0] -> _branch0 +DLGLOBAL DEBUG 3 (root.alive(),_branch1.cleanup(),other.alive()) +DLGLOBAL DEBUG test(other){alive}: Terminating in cascade, depth 3 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(root)) +DLGLOBAL DEBUG test(other){alive}: pre_term() +DLGLOBAL DEBUG 4 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup()) +DLGLOBAL DEBUG test(other){alive}: cleanup() +DLGLOBAL DEBUG test(other){alive}: scene forgets other +DLGLOBAL DEBUG test(other){alive}: removing reference other.other[0] -> _branch0 DLGLOBAL DEBUG test(_branch0){alive}: Received Event EV_OTHER_GONE -DLGLOBAL DEBUG 7 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. +DLGLOBAL DEBUG 5 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) DLGLOBAL DEBUG test(_branch0){alive}: alive(EV_OTHER_GONE) -DLGLOBAL DEBUG 8 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. +DLGLOBAL DEBUG 6 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.other_gone()) DLGLOBAL DEBUG test(_branch0){alive}: EV_OTHER_GONE: Dropped reference _branch0.other[0] = other -DLGLOBAL DEBUG 7 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. -DLGLOBAL DEBUG test(_branch0){alive}: state_chg to destroying -DLGLOBAL DEBUG 8 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. -DLGLOBAL DEBUG test(_branch0){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(_branch0){destroying}: Terminating in cascade, depth 4 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(root)) -DLGLOBAL DEBUG test(_branch0){destroying}: pre_term() +DLGLOBAL DEBUG 5 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) +DLGLOBAL DEBUG test(_branch0){alive}: Terminating in cascade, depth 4 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(root)) +DLGLOBAL DEBUG test(_branch0){alive}: pre_term() DLGLOBAL DEBUG test(__twig0b){alive}: Terminating in cascade, depth 5 (cause = OSMO_FSM_TERM_PARENT, caused by: test(root)) DLGLOBAL DEBUG test(__twig0b){alive}: pre_term() DLGLOBAL DEBUG test(__twig0b){alive}: Removing from parent test(_branch0) -DLGLOBAL DEBUG 9 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. +DLGLOBAL DEBUG 6 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),__twig0b.cleanup()) DLGLOBAL DEBUG test(__twig0b){alive}: cleanup() DLGLOBAL DEBUG test(__twig0b){alive}: scene forgets __twig0b -DLGLOBAL DEBUG test(_branch0){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 10 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG test(_branch0){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 11 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG test(_branch0){destroying}: EV_CHILD_GONE: Dropped reference _branch0.child[1] = __twig0b -DLGLOBAL DEBUG test(_branch0){destroying}: still exists: child[0] -DLGLOBAL DEBUG 10 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG 9 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. +DLGLOBAL DEBUG test(_branch0){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 7 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0b.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 8 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0b.cleanup(),_branch0.child_gone()) +DLGLOBAL DEBUG test(_branch0){alive}: EV_CHILD_GONE: Dropped reference _branch0.child[1] = __twig0b +DLGLOBAL DEBUG test(_branch0){alive}: still exists: child[0] +DLGLOBAL DEBUG 7 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0b.cleanup()) +DLGLOBAL DEBUG 6 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),__twig0b.cleanup()) DLGLOBAL DEBUG test(__twig0b){alive}: cleanup() done -DLGLOBAL DEBUG 8 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. +DLGLOBAL DEBUG 5 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) DLGLOBAL DEBUG test(__twig0b){alive}: Deferring: will deallocate with test(root) DLGLOBAL DEBUG test(__twig0a){alive}: Terminating in cascade, depth 5 (cause = OSMO_FSM_TERM_PARENT, caused by: test(root)) DLGLOBAL DEBUG test(__twig0a){alive}: pre_term() DLGLOBAL DEBUG test(__twig0a){alive}: Removing from parent test(_branch0) -DLGLOBAL DEBUG 9 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. +DLGLOBAL DEBUG 6 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup()) DLGLOBAL DEBUG test(__twig0a){alive}: cleanup() DLGLOBAL DEBUG test(__twig0a){alive}: scene forgets __twig0a DLGLOBAL DEBUG test(__twig0a){alive}: removing reference __twig0a.other[0] -> other -DLGLOBAL DEBUG test(other){destroying}: Received Event EV_OTHER_GONE -DLGLOBAL DEBUG 10 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG test(other){destroying}: destroying(EV_OTHER_GONE) -DLGLOBAL DEBUG 11 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG 10 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG 9 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. -DLGLOBAL DEBUG test(_branch0){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 10 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG test(_branch0){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 11 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG test(_branch0){destroying}: EV_CHILD_GONE: Dropped reference _branch0.child[0] = __twig0a -DLGLOBAL DEBUG test(_branch0){destroying}: No more children -DLGLOBAL DEBUG 10 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG 9 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. +DLGLOBAL DEBUG test(other){alive}: Received Event EV_OTHER_GONE +DLGLOBAL DEBUG 7 (root.alive(),_branch1.cleanup(),2*other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup()) +DLGLOBAL DEBUG test(other){alive}: alive(EV_OTHER_GONE) +DLGLOBAL DEBUG 8 (root.alive(),_branch1.cleanup(),2*other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup(),other.other_gone()) +DLGLOBAL DEBUG 7 (root.alive(),_branch1.cleanup(),2*other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup()) +DLGLOBAL DEBUG 6 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 7 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0a.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 8 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0a.cleanup(),_branch0.child_gone()) +DLGLOBAL DEBUG test(_branch0){alive}: EV_CHILD_GONE: Dropped reference _branch0.child[0] = __twig0a +DLGLOBAL DEBUG test(_branch0){alive}: No more children +DLGLOBAL DEBUG 7 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),2*_branch0.alive(),__twig0a.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: Ignoring trigger to terminate: already terminating +DLGLOBAL DEBUG 6 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),__twig0a.cleanup()) DLGLOBAL DEBUG test(__twig0a){alive}: cleanup() done -DLGLOBAL DEBUG 8 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. +DLGLOBAL DEBUG 5 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) DLGLOBAL DEBUG test(__twig0a){alive}: Deferring: will deallocate with test(root) -DLGLOBAL DEBUG test(_branch0){destroying}: Removing from parent test(root) -DLGLOBAL DEBUG 9 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. -DLGLOBAL DEBUG test(_branch0){destroying}: cleanup() -DLGLOBAL DEBUG test(_branch0){destroying}: scene forgets _branch0 -DLGLOBAL DEBUG test(root){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 10 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG test(root){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 11 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG test(root){destroying}: EV_CHILD_GONE: Dropped reference root.child[0] = _branch0 -DLGLOBAL DEBUG test(root){destroying}: still exists: child[1] -DLGLOBAL DEBUG 10 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0 -DLGLOBAL DEBUG 9 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. -DLGLOBAL DEBUG test(_branch0){destroying}: cleanup() done -DLGLOBAL DEBUG 8 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. -DLGLOBAL DEBUG test(root){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 9 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. -DLGLOBAL DEBUG test(root){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG test(root){destroying}: EV_CHILD_GONE with NULL data, must be a parent_term event. Ignore. -DLGLOBAL DEBUG 8 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. -DLGLOBAL DEBUG test(_branch0){destroying}: Deferring: will deallocate with test(root) -DLGLOBAL DEBUG 7 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch0. -DLGLOBAL DEBUG 6 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup()) -DLGLOBAL DEBUG test(other){destroying}: cleanup() done -DLGLOBAL DEBUG 5 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive(),other.destroying_onenter()) -DLGLOBAL DEBUG test(other){destroying}: Deferring: will deallocate with test(root) -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),other.alive()) -DLGLOBAL DEBUG 3 (root.alive(),root.destroying_onenter(),_branch1.cleanup()) -DLGLOBAL DEBUG test(root){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),root.destroying()) -DLGLOBAL DEBUG test(root){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 5 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),root.destroying(),root.child_gone()) -DLGLOBAL DEBUG test(root){destroying}: EV_CHILD_GONE: Dropped reference root.child[1] = _branch1 -DLGLOBAL DEBUG test(root){destroying}: No more children -DLGLOBAL DEBUG 4 (root.alive(),root.destroying_onenter(),_branch1.cleanup(),root.destroying()) -DLGLOBAL DEBUG 3 (root.alive(),root.destroying_onenter(),_branch1.cleanup()) -DLGLOBAL DEBUG test(_branch1){destroying}: cleanup() done -DLGLOBAL DEBUG 2 (root.alive(),root.destroying_onenter()) -DLGLOBAL DEBUG test(_branch1){destroying}: Deferring: will deallocate with test(root) -DLGLOBAL DEBUG 3 (root.alive(),root.destroying_onenter(),root.cleanup()) -DLGLOBAL DEBUG test(root){destroying}: cleanup() -DLGLOBAL DEBUG test(root){destroying}: scene forgets root -DLGLOBAL DEBUG test(root){destroying}: cleanup() done -DLGLOBAL DEBUG 2 (root.alive(),root.destroying_onenter()) -DLGLOBAL DEBUG test(root){destroying}: Deallocated, including all deferred deallocations +DLGLOBAL DEBUG test(_branch0){alive}: Removing from parent test(root) +DLGLOBAL DEBUG 6 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: cleanup() +DLGLOBAL DEBUG test(_branch0){alive}: scene forgets _branch0 +DLGLOBAL DEBUG test(root){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 7 (2*root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.cleanup()) +DLGLOBAL DEBUG test(root){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 8 (2*root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.cleanup(),root.child_gone()) +DLGLOBAL DEBUG test(root){alive}: EV_CHILD_GONE: Dropped reference root.child[0] = _branch0 +DLGLOBAL DEBUG test(root){alive}: still exists: child[1] +DLGLOBAL DEBUG 7 (2*root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.cleanup()) +DLGLOBAL DEBUG 6 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive(),_branch0.cleanup()) +DLGLOBAL DEBUG test(_branch0){alive}: cleanup() done +DLGLOBAL DEBUG 5 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) +DLGLOBAL DEBUG test(root){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 6 (2*root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) +DLGLOBAL DEBUG test(root){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG test(root){alive}: EV_CHILD_GONE with NULL data, must be a parent_term event. Ignore. +DLGLOBAL DEBUG 5 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup(),_branch0.alive()) +DLGLOBAL DEBUG test(_branch0){alive}: Deferring: will deallocate with test(root) +DLGLOBAL DEBUG 4 (root.alive(),_branch1.cleanup(),other.alive(),other.cleanup()) +DLGLOBAL DEBUG test(other){alive}: cleanup() done +DLGLOBAL DEBUG 3 (root.alive(),_branch1.cleanup(),other.alive()) +DLGLOBAL DEBUG test(other){alive}: Deferring: will deallocate with test(root) +DLGLOBAL DEBUG 2 (root.alive(),_branch1.cleanup()) +DLGLOBAL DEBUG test(root){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 3 (2*root.alive(),_branch1.cleanup()) +DLGLOBAL DEBUG test(root){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 4 (2*root.alive(),_branch1.cleanup(),root.child_gone()) +DLGLOBAL DEBUG test(root){alive}: EV_CHILD_GONE: Dropped reference root.child[1] = _branch1 +DLGLOBAL DEBUG test(root){alive}: No more children +DLGLOBAL DEBUG 3 (2*root.alive(),_branch1.cleanup()) +DLGLOBAL DEBUG test(root){alive}: Ignoring trigger to terminate: already terminating +DLGLOBAL DEBUG 2 (root.alive(),_branch1.cleanup()) +DLGLOBAL DEBUG test(_branch1){alive}: cleanup() done +DLGLOBAL DEBUG 1 (root.alive()) +DLGLOBAL DEBUG test(_branch1){alive}: Deferring: will deallocate with test(root) +DLGLOBAL DEBUG 2 (root.alive(),root.cleanup()) +DLGLOBAL DEBUG test(root){alive}: cleanup() +DLGLOBAL DEBUG test(root){alive}: scene forgets root +DLGLOBAL DEBUG test(root){alive}: cleanup() done DLGLOBAL DEBUG 1 (root.alive()) +DLGLOBAL DEBUG test(root){alive}: Deallocated, including all deferred deallocations DLGLOBAL DEBUG 0 (-) DLGLOBAL DEBUG --- after destroy-event cascade: DLGLOBAL DEBUG --- all deallocated. @@ -490,145 +463,131 @@ DLGLOBAL DEBUG 3 (__twig0a.cleanup(),_branch0.alive(),_branch0.child_gone()) DLGLOBAL DEBUG test(_branch0){alive}: EV_CHILD_GONE: Dropped reference _branch0.child[0] = __twig0a DLGLOBAL DEBUG test(_branch0){alive}: No more children DLGLOBAL DEBUG 2 (__twig0a.cleanup(),_branch0.alive()) -DLGLOBAL DEBUG test(_branch0){alive}: state_chg to destroying -DLGLOBAL DEBUG 3 (__twig0a.cleanup(),_branch0.alive(),_branch0.destroying_onenter()) -DLGLOBAL DEBUG test(_branch0){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(_branch0){destroying}: Ignoring trigger to terminate: already terminating -DLGLOBAL DEBUG 2 (__twig0a.cleanup(),_branch0.alive()) +DLGLOBAL DEBUG test(_branch0){alive}: Ignoring trigger to terminate: already terminating DLGLOBAL DEBUG 1 (__twig0a.cleanup()) DLGLOBAL DEBUG test(__twig0a){alive}: cleanup() done DLGLOBAL DEBUG 0 (-) DLGLOBAL DEBUG test(__twig0a){alive}: Deferring: will deallocate with test(_branch0) -DLGLOBAL DEBUG test(_branch0){destroying}: Removing from parent test(root) +DLGLOBAL DEBUG test(_branch0){alive}: Removing from parent test(root) DLGLOBAL DEBUG 1 (_branch0.cleanup()) -DLGLOBAL DEBUG test(_branch0){destroying}: cleanup() -DLGLOBAL DEBUG test(_branch0){destroying}: scene forgets _branch0 -DLGLOBAL DEBUG test(_branch0){destroying}: removing reference _branch0.other[0] -> other +DLGLOBAL DEBUG test(_branch0){alive}: cleanup() +DLGLOBAL DEBUG test(_branch0){alive}: scene forgets _branch0 +DLGLOBAL DEBUG test(_branch0){alive}: removing reference _branch0.other[0] -> other DLGLOBAL DEBUG test(other){alive}: Received Event EV_OTHER_GONE DLGLOBAL DEBUG 2 (_branch0.cleanup(),other.alive()) DLGLOBAL DEBUG test(other){alive}: alive(EV_OTHER_GONE) DLGLOBAL DEBUG 3 (_branch0.cleanup(),other.alive(),other.other_gone()) DLGLOBAL DEBUG test(other){alive}: EV_OTHER_GONE: Dropped reference other.other[0] = _branch0 DLGLOBAL DEBUG 2 (_branch0.cleanup(),other.alive()) -DLGLOBAL DEBUG test(other){alive}: state_chg to destroying -DLGLOBAL DEBUG 3 (_branch0.cleanup(),other.alive(),other.destroying_onenter()) -DLGLOBAL DEBUG test(other){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(other){destroying}: Terminating in cascade, depth 2 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(_branch0)) -DLGLOBAL DEBUG test(other){destroying}: pre_term() -DLGLOBAL DEBUG 4 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup()) -DLGLOBAL DEBUG test(other){destroying}: cleanup() -DLGLOBAL DEBUG test(other){destroying}: scene forgets other -DLGLOBAL DEBUG test(other){destroying}: removing reference other.other[1] -> _branch1 +DLGLOBAL DEBUG test(other){alive}: Terminating in cascade, depth 2 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(_branch0)) +DLGLOBAL DEBUG test(other){alive}: pre_term() +DLGLOBAL DEBUG 3 (_branch0.cleanup(),other.alive(),other.cleanup()) +DLGLOBAL DEBUG test(other){alive}: cleanup() +DLGLOBAL DEBUG test(other){alive}: scene forgets other +DLGLOBAL DEBUG test(other){alive}: removing reference other.other[1] -> _branch1 DLGLOBAL DEBUG test(_branch1){alive}: Received Event EV_OTHER_GONE -DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive()) +DLGLOBAL DEBUG 4 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive()) DLGLOBAL DEBUG test(_branch1){alive}: alive(EV_OTHER_GONE) -DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.other_gone()) +DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),_branch1.other_gone()) DLGLOBAL DEBUG test(_branch1){alive}: EV_OTHER_GONE: Dropped reference _branch1.other[0] = other -DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive()) -DLGLOBAL DEBUG test(_branch1){alive}: state_chg to destroying -DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter()) -DLGLOBAL DEBUG test(_branch1){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(_branch1){destroying}: Terminating in cascade, depth 3 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(_branch0)) -DLGLOBAL DEBUG test(_branch1){destroying}: pre_term() +DLGLOBAL DEBUG 4 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive()) +DLGLOBAL DEBUG test(_branch1){alive}: Terminating in cascade, depth 3 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(_branch0)) +DLGLOBAL DEBUG test(_branch1){alive}: pre_term() DLGLOBAL DEBUG test(__twig1b){alive}: Terminating in cascade, depth 4 (cause = OSMO_FSM_TERM_PARENT, caused by: test(_branch0)) DLGLOBAL DEBUG test(__twig1b){alive}: pre_term() DLGLOBAL DEBUG test(__twig1b){alive}: Removing from parent test(_branch1) -DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ +DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),__twig1b.cleanup()) DLGLOBAL DEBUG test(__twig1b){alive}: cleanup() DLGLOBAL DEBUG test(__twig1b){alive}: scene forgets __twig1b -DLGLOBAL DEBUG test(_branch1){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 8 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch1){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 9 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch1){destroying}: EV_CHILD_GONE: Dropped reference _branch1.child[1] = __twig1b -DLGLOBAL DEBUG test(_branch1){destroying}: still exists: child[0] -DLGLOBAL DEBUG 8 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ +DLGLOBAL DEBUG test(_branch1){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.cleanup(),2*_branch1.alive(),__twig1b.cleanup()) +DLGLOBAL DEBUG test(_branch1){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.cleanup(),2*_branch1.alive(),__twig1b.cleanup(),_branch1.child_gone()) +DLGLOBAL DEBUG test(_branch1){alive}: EV_CHILD_GONE: Dropped reference _branch1.child[1] = __twig1b +DLGLOBAL DEBUG test(_branch1){alive}: still exists: child[0] +DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.cleanup(),2*_branch1.alive(),__twig1b.cleanup()) +DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),__twig1b.cleanup()) DLGLOBAL DEBUG test(__twig1b){alive}: cleanup() done -DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter()) +DLGLOBAL DEBUG 4 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive()) DLGLOBAL DEBUG test(__twig1b){alive}: Deferring: will deallocate with test(_branch0) DLGLOBAL DEBUG test(__twig1a){alive}: Terminating in cascade, depth 4 (cause = OSMO_FSM_TERM_PARENT, caused by: test(_branch0)) DLGLOBAL DEBUG test(__twig1a){alive}: pre_term() DLGLOBAL DEBUG test(__twig1a){alive}: Removing from parent test(_branch1) -DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ +DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),__twig1a.cleanup()) DLGLOBAL DEBUG test(__twig1a){alive}: cleanup() DLGLOBAL DEBUG test(__twig1a){alive}: scene forgets __twig1a DLGLOBAL DEBUG test(__twig1a){alive}: removing reference __twig1a.other[0] -> root DLGLOBAL DEBUG test(root){alive}: Received Event EV_OTHER_GONE -DLGLOBAL DEBUG 8 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ +DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),__twig1a.cleanup(),root.alive()) DLGLOBAL DEBUG test(root){alive}: alive(EV_OTHER_GONE) -DLGLOBAL DEBUG 9 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ +DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),__twig1a.cleanup(),root.alive(),root.other_gone()) DLGLOBAL DEBUG test(root){alive}: EV_OTHER_GONE: Dropped reference root.other[0] = __twig1a -DLGLOBAL DEBUG 8 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(root){alive}: state_chg to destroying -DLGLOBAL DEBUG 9 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(root){destroying}: destroying_onenter() from alive -DLGLOBAL DEBUG test(root){destroying}: Terminating in cascade, depth 5 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(_branch0)) -DLGLOBAL DEBUG test(root){destroying}: pre_term() -DLGLOBAL DEBUG test(_branch1){destroying}: Ignoring trigger to terminate: already terminating -DLGLOBAL ERROR test(root){destroying}: Internal error while terminating child FSMs: a child FSM is stuck -DLGLOBAL DEBUG 10 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(), -DLGLOBAL DEBUG test(root){destroying}: cleanup() -DLGLOBAL DEBUG test(root){destroying}: scene forgets root -DLGLOBAL DEBUG test(root){destroying}: cleanup() done -DLGLOBAL DEBUG 9 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(root){destroying}: Deferring: will deallocate with test(_branch0) -DLGLOBAL DEBUG 8 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch1){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 8 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch1){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 9 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch1){destroying}: EV_CHILD_GONE: Dropped reference _branch1.child[0] = __twig1a -DLGLOBAL DEBUG test(_branch1){destroying}: No more children -DLGLOBAL DEBUG 8 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ +DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),__twig1a.cleanup(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: Terminating in cascade, depth 5 (cause = OSMO_FSM_TERM_REGULAR, caused by: test(_branch0)) +DLGLOBAL DEBUG test(root){alive}: pre_term() +DLGLOBAL DEBUG test(_branch1){alive}: Ignoring trigger to terminate: already terminating +DLGLOBAL ERROR test(root){alive}: Internal error while terminating child FSMs: a child FSM is stuck +DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),__twig1a.cleanup(),root.alive(),root.cleanup()) +DLGLOBAL DEBUG test(root){alive}: cleanup() +DLGLOBAL DEBUG test(root){alive}: scene forgets root +DLGLOBAL DEBUG test(root){alive}: cleanup() done +DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),__twig1a.cleanup(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: Deferring: will deallocate with test(_branch0) +DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),__twig1a.cleanup()) +DLGLOBAL DEBUG test(_branch1){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.cleanup(),2*_branch1.alive(),__twig1a.cleanup()) +DLGLOBAL DEBUG test(_branch1){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.cleanup(),2*_branch1.alive(),__twig1a.cleanup(),_branch1.child_gone()) +DLGLOBAL DEBUG test(_branch1){alive}: EV_CHILD_GONE: Dropped reference _branch1.child[0] = __twig1a +DLGLOBAL DEBUG test(_branch1){alive}: No more children +DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.cleanup(),2*_branch1.alive(),__twig1a.cleanup()) +DLGLOBAL DEBUG test(_branch1){alive}: Ignoring trigger to terminate: already terminating +DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),__twig1a.cleanup()) DLGLOBAL DEBUG test(__twig1a){alive}: cleanup() done -DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter()) +DLGLOBAL DEBUG 4 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive()) DLGLOBAL DEBUG test(__twig1a){alive}: Deferring: will deallocate with test(_branch0) -DLGLOBAL DEBUG test(_branch1){destroying}: Removing from parent test(root) -DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch1){destroying}: cleanup() -DLGLOBAL DEBUG test(_branch1){destroying}: scene forgets _branch1 -DLGLOBAL DEBUG test(root){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 8 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(root){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 9 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(root){destroying}: EV_CHILD_GONE: Dropped reference root.child[1] = _branch1 -DLGLOBAL DEBUG test(root){destroying}: still exists: child[0] -DLGLOBAL DEBUG 8 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),_ -DLGLOBAL DEBUG test(_branch1){destroying}: cleanup() done -DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter()) -DLGLOBAL DEBUG test(root){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter(),r -DLGLOBAL DEBUG test(root){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG test(root){destroying}: EV_CHILD_GONE with NULL data, must be a parent_term event. Ignore. -DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive(),_branch1.destroying_onenter()) -DLGLOBAL DEBUG test(_branch1){destroying}: Deferring: will deallocate with test(_branch0) -DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup(),_branch1.alive()) -DLGLOBAL DEBUG 4 (_branch0.cleanup(),other.alive(),other.destroying_onenter(),other.cleanup()) -DLGLOBAL DEBUG test(other){destroying}: cleanup() done -DLGLOBAL DEBUG 3 (_branch0.cleanup(),other.alive(),other.destroying_onenter()) -DLGLOBAL DEBUG test(other){destroying}: Deferring: will deallocate with test(_branch0) +DLGLOBAL DEBUG test(_branch1){alive}: Removing from parent test(root) +DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),_branch1.cleanup()) +DLGLOBAL DEBUG test(_branch1){alive}: cleanup() +DLGLOBAL DEBUG test(_branch1){alive}: scene forgets _branch1 +DLGLOBAL DEBUG test(root){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),_branch1.cleanup(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 7 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),_branch1.cleanup(),root.alive(),root.child_gone()) +DLGLOBAL DEBUG test(root){alive}: EV_CHILD_GONE: Dropped reference root.child[1] = _branch1 +DLGLOBAL DEBUG test(root){alive}: still exists: child[0] +DLGLOBAL DEBUG 6 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),_branch1.cleanup(),root.alive()) +DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),_branch1.cleanup()) +DLGLOBAL DEBUG test(_branch1){alive}: cleanup() done +DLGLOBAL DEBUG 4 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive()) +DLGLOBAL DEBUG test(root){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 5 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG test(root){alive}: EV_CHILD_GONE with NULL data, must be a parent_term event. Ignore. +DLGLOBAL DEBUG 4 (_branch0.cleanup(),other.alive(),other.cleanup(),_branch1.alive()) +DLGLOBAL DEBUG test(_branch1){alive}: Deferring: will deallocate with test(_branch0) +DLGLOBAL DEBUG 3 (_branch0.cleanup(),other.alive(),other.cleanup()) +DLGLOBAL DEBUG test(other){alive}: cleanup() done DLGLOBAL DEBUG 2 (_branch0.cleanup(),other.alive()) +DLGLOBAL DEBUG test(other){alive}: Deferring: will deallocate with test(_branch0) DLGLOBAL DEBUG 1 (_branch0.cleanup()) -DLGLOBAL DEBUG test(root){destroying}: Received Event EV_CHILD_GONE -DLGLOBAL DEBUG 2 (_branch0.cleanup(),root.destroying()) -DLGLOBAL DEBUG test(root){destroying}: destroying(EV_CHILD_GONE) -DLGLOBAL DEBUG 3 (_branch0.cleanup(),root.destroying(),root.child_gone()) -DLGLOBAL DEBUG test(root){destroying}: EV_CHILD_GONE: Dropped reference root.child[0] = _branch0 -DLGLOBAL DEBUG test(root){destroying}: No more children -DLGLOBAL DEBUG 2 (_branch0.cleanup(),root.destroying()) +DLGLOBAL DEBUG test(root){alive}: Received Event EV_CHILD_GONE +DLGLOBAL DEBUG 2 (_branch0.cleanup(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: alive(EV_CHILD_GONE) +DLGLOBAL DEBUG 3 (_branch0.cleanup(),root.alive(),root.child_gone()) +DLGLOBAL DEBUG test(root){alive}: EV_CHILD_GONE: Dropped reference root.child[0] = _branch0 +DLGLOBAL DEBUG test(root){alive}: No more children +DLGLOBAL DEBUG 2 (_branch0.cleanup(),root.alive()) +DLGLOBAL DEBUG test(root){alive}: Ignoring trigger to terminate: already termi