fiber: make the concurrent fiber_join safer
Prior to this patch a bunch of illegal conditions was possible: 1. The joinability of a fiber could be changed while the fiber is being joined by someone. This could lead to double recycling: the first one happened on the fiber finish, and the second one in the fiber join. 2. The joinability of a dead joinable fiber could be altered, this led to inability jo join the dead fiber and free its resources. 3. A running fiber could be joined concurrently by two or more fibers, so the fiber could be recycled more than once (once per each concurrent join). 4. A dead recycled fiber could be made joinable and joined leading to the double recycle. Fixed these issues by adding a new FIBER_JOIN_BEEN_INVOKED flag: now the `fiber_set_joinable` and `fiber_join_timeout` functions detect the double join. Because of the API limitations both of them panic when an invalid condition is met: - The `fiber_set_joinable` was not designed to report errors. - The `fiber_join_timeout` can't raise any error unless a timeout is met, because the `fiber_join` users don't expect to receive any error from this function at all (except the one generated by the joined fiber). It's still possible that a fiber join is performed on a struct which has been recycled and, if the new fiber is joinable too, this can't be detected. The current fiber API does not allow to fix this, so this is to be the user's responsibility, they should be warned about the fact the double join to the same fiber is illegal. Closes #7562 @TarantoolBot document Title: `fiber_join`, `fiber_join_timeout` and `fiber_set_joinable` behave differently now. `fiber_join` and `fiber_join_timeout` now panic in case if double join of the given fiber is detected. `fiber_set_joinable` now panics if the given fiber is dead or is joined already. This prevents some amount of error conditions that could happen when using the API in an unexpected way, including: - Making a dead joinable fiber non-joinable could lead to a memory leak: one can't join the fiber anymore. - Making a dead joinable fiber joinable again is a sign of attempt to join the fiber later. That means the fiber struct may be joined later, when it's been recycled and reused. This could lead to a very hard to debug double join. - Making an alive joined fiber non-joinable would lead to the double free: once on the fiber function finish, and secondly in the active fiber join finish. Risks of making it joinable are described above. - Making a dead and recycled fiber joinable allowed to join the fiber once again leading to a double free. Any given by the API `struct fiber` should only be joined once. If a fiber is joined after the first join on it has finished the behavior is undefined: it can either be a panic or an incidental join to a totally foreign fiber.
Showing
- changelogs/unreleased/gh-7562-fiber_join.md 6 additions, 0 deletionschangelogs/unreleased/gh-7562-fiber_join.md
- src/lib/core/fiber.c 61 additions, 0 deletionssrc/lib/core/fiber.c
- src/lib/core/fiber.h 15 additions, 1 deletionsrc/lib/core/fiber.h
- test/unit/fiber.cc 14 additions, 0 deletionstest/unit/fiber.cc
- test/unit/fiber.result 1 addition, 0 deletionstest/unit/fiber.result
Loading
Please register or sign in to comment