Currently when we need to initiate transaction rollback from the thread which does not own the transaction, i.e. from Deadlock::report(), or from lock_wait_wsrep_kill(), or from innobase_kill_query(), we "cancel" and release waiting lock(lock_cancel_waiting_and_release()) and signal the tread which owns the transaction with condition variable.
What does it mean to cancel and release waiting lock?
First, it deletes waiting lock from the corresponding lock hash cell and rebuilds waiting graph, i.e. for each waiting lock in the cell it looks for conflicting lock among the cell elements, and, if such lock is found, makes the current element to be waiting for the found lock(lock_rec_dequeue_from_page()).
Then it sets trx->error_state if necessary and signals waiting thread with condition variable(see lock_wait_end()). It's supposed that either the waiting thread is already blocked on lock_wait() or it will invoke lock_wait(), which will return the corresponding error code, what let's the caller to initiate rollback. Rollback, in turns, releases all locks it holds.
We could simplify the above. We could just assign the corresponding value to trx->error_state and just signal transaction thread with condition variable to let the transaction thread to do all necessary things to release and cancel its locks.