/* generate a fake reply * it assumes the REPLY_LOCK is already held and returns unlocked */ static void fake_reply(struct cell *t, int branch, int code) { struct cancel_info cancel_data; short do_cancel_branch; enum rps reply_status; init_cancel_info(&cancel_data); do_cancel_branch = is_invite(t) && prepare_cancel_branch(t, branch, 0); /* mark branch as canceled */ t->uac[branch].request.flags |= F_RB_CANCELED; t->uac[branch].request.flags |= F_RB_RELAYREPLY; if(is_local(t)) { reply_status = local_reply(t, FAKED_REPLY, branch, code, &cancel_data); } else { /* rely reply, but don't put on wait, we still need t * to send the cancels */ reply_status = relay_reply(t, FAKED_REPLY, branch, code, &cancel_data, 0); } /* now when out-of-lock do the cancel I/O */ #ifdef CANCEL_REASON_SUPPORT if(do_cancel_branch) cancel_branch(t, branch, &cancel_data.reason, 0); #else /* CANCEL_REASON_SUPPORT */ if(do_cancel_branch) cancel_branch(t, branch, 0); #endif /* CANCEL_REASON_SUPPORT */ /* it's cleaned up on error; if no error occurred and transaction completed regularly, I have to clean-up myself */ if(reply_status == RPS_COMPLETED) put_on_wait(t); }
/** Prepare to cancel a transaction. * Determine which branches should be canceled and prepare them (internally * mark them as "cancel in progress", see prepare_cancel_branch()). * Can be called without REPLY_LOCK, since prepare_cancel_branch() is atomic * now * -- andrei * WARNING: - has side effects, see prepare_cancel_branch() * - one _must_ call cancel_uacs(cancel_bm) if *cancel_bm!=0 or * you'll have some un-cancelable branches (because they remain * "marked" internally) * @param t - transaction whose branches will be canceled * @param cancel_bm - pointer to a branch bitmap that will be filled with * the branches that must be canceled (must be passed to cancel_uacs() if * !=0). * @param skip - branch bitmap of branches that should not be canceled */ void prepare_to_cancel(struct cell *t, branch_bm_t *cancel_bm, branch_bm_t skip_branches) { int i; int branches_no; branch_bm_t mask; *cancel_bm=0; branches_no=t->nr_of_outgoings; mask=~skip_branches; membar_depends(); for( i=0 ; i<branches_no ; i++ ) { *cancel_bm |= ((mask & (1<<i)) && prepare_cancel_branch(t, i, 1))<<i; } }