ticks_t wait_handler(ticks_t ti, struct timer_ln *wait_tl, void *data) { struct cell *p_cell; ticks_t ret; p_cell = (struct cell *)data; #ifdef TIMER_DEBUG LM_DBG("WAIT timer hit @%d for %p (timer_lm %p)\n", ti, p_cell, wait_tl); #endif #ifdef TM_DEL_UNREF /* stop cancel timers if any running */ if(is_invite(p_cell)) cleanup_localcancel_timers(p_cell); /* remove the cell from the hash table */ LOCK_HASH(p_cell->hash_index); remove_from_hash_table_unsafe(p_cell); UNLOCK_HASH(p_cell->hash_index); p_cell->flags |= T_IN_AGONY; if(t_linked_timers(p_cell)) { UNREF_FREE(p_cell, 0); } else { UNREF_FREE(p_cell, 1); } ret = 0; #else /* TM_DEL_UNREF */ if(p_cell->flags & T_IN_AGONY) { /* delayed delete */ /* we call delete now without any locking on hash/ref_count; we can do that because delete_handler is only entered after the delete timer was installed from wait_handler, which removed transaction from hash table and did not destroy it because some processes were using it; that means that the processes currently using the transaction can unref and no new processes can ref -- we can wait until ref_count is zero safely without locking */ ret = delete_cell(p_cell, 0 /* don't unlock on return */); } else { /* stop cancel timers if any running */ if(is_invite(p_cell)) cleanup_localcancel_timers(p_cell); /* remove the cell from the hash table */ LOCK_HASH(p_cell->hash_index); remove_from_hash_table_unsafe(p_cell); p_cell->flags |= T_IN_AGONY; /* delete (returns with UNLOCK-ed_HASH) */ ret = delete_cell(p_cell, 1 /* unlock on return */); } #endif /* TM_DEL_UNREF */ return ret; }
inline static void wait_handler( struct timer_link *wait_tl ) { struct cell *p_cell; p_cell = get_wait_timer_payload( wait_tl ); #ifdef EXTRA_DEBUG if (p_cell->damocles) { LM_ERR("transaction %p scheduled for deletion and" " called from WAIT timer\n",p_cell); abort(); } LM_DBG("WAIT timer hit\n"); #endif /* stop cancel timers if any running */ if ( is_invite(p_cell) ) cleanup_localcancel_timers( p_cell ); /* the transaction is already removed from WT_LIST by the timer */ /* remove the cell from the hash table */ LM_DBG("removing %p from table \n", p_cell ); LOCK_HASH( p_cell->hash_index ); remove_from_hash_table_unsafe( p_cell ); /* jku: no more here -- we do it when we put a transaction on wait */ #ifdef EXTRA_DEBUG p_cell->damocles = 1; #endif /* delete (returns with UNLOCK-ed_HASH) */ delete_cell( p_cell, 1 /* unlock on return */ ); LM_DBG("done\n"); }