Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix race conditions in tracing.ml #5601

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

edwintorok
Copy link
Contributor

A quick look at tracing.ml has shown several places where a global hashtable is read without holding locks.

This is not thread safe (I probably wasn't paying attention when the original code got merged).

@GabrielBuica you can base your PR that changes observer_mode on top of this, should be a more correct starting point.

This does introduce nesting of locks though (tracer provider lock -> Spans lock), but that should be fine, I don't think it can deadlock, due to the order in which these locks are declared in the code I don't think it is possible for code in Spans to attempt to acquire the global tracer provider lock (the value is not declared yet, so it'd be a compile error).

It is not safe to access a global hashtable from multiple threads, even if the operations are read-only
(it may be concurrently changed by another thread, which then may result in errors in the racing thread).

This means we must always take the mutex, and because OCaml doesn't have a reader-writer mutex, we need to take the exclusive mutex.

Eventually we should use a better datastructure here (immutable maps, or lock-free datastructures), but for now
fix the datastructure that we currently use to be thread-safe.

Signed-off-by: Edwin Török <edwin.torok@cloud.com>
In preparation for OCaml 5, on OCaml 4 they'd be equivalent.

Note that adding Atomic doesn't make operations on these values always atomic: that is
the responsibility of surrounding code.
E.g. Atomic.get + Atomic.set is not atomic, because another domain might've raced and changed the value inbetween
(so in that case Atomic.compare_and_set should be used).

However for global flags that are read multiple times, but set from a central place this isn't a problem.

Signed-off-by: Edwin Török <edwin.torok@cloud.com>
@edwintorok
Copy link
Contributor Author

The 'tracing' module compiles, but I haven't done more testing than that on this change.

@lindig
Copy link
Contributor

lindig commented May 1, 2024

Would it make sense to create a functor that wraps Hashtbl and protects its functions with a lock? Then all that we would need is updating the names and it would be re-usable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants