Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

When after this, the consumer calls a callback, the callback must be able to invoke the consumer again. This is allowed because the thread-local variable corresponds to the top of the stack. Therefore, code that is not aware of this KIP (all programs in existence till now) will continue to work as before.
The callback may now chose to access the thread-local variable, and store the access key on the local-variable of another thread, thereby allowing that thread to access the consumer. Because acquire  immediately and atomically stores a new access key, it is not possible for multiple threads to use a valid access key concurrently.
When a callback passes on the access-key to another thread, it must wait for that other thread to complete before returning from the callback.

When release is invoked, we first validate that the top of the stack is equal to the thread-local variable. If it is not equal, it means that another nested invocations must end firsta callback didn't wait for the other thread to complete. After the check we pop the top value of the access-key stack, and then copy the new top of the stack to the thread-local variable, or if the stack is now empty we clear the thread-local variable.

...

As far as the author is aware, there are currently no (integration) tests that test the thread-id check. If there would be, these should continue to pass. In addition, they could be extended to support the additional behavior.

Rejected Alternatives

Alternative A: add a configuration to disable the thread-id check

Disabling the thread-id check based on configuration would be a very easy change for us. However, without the check it will become very easy to use the consumer wrong, especially from multi-threaded asynchronous runtimes.

Alternative B: disallow concurrent invocations, but allow them from any thread

This is a stronger approach than alternative A, but a lot weaker than the proposed change. For example, with this alternative, when a callback is running, a completely unrelated thread may use the consumer. Since that thread is unrelated there is no coordination between when the callback ends and the other thread causing the consumer to be running on threads after all. This can lead to very hard to track bugs.