This is an archive of the discontinued LLVM Phabricator instance.

[lldb/test] Fix data racing issue in TestStackCoreScriptedProcess
ClosedPublic

Authored by mib on Dec 6 2022, 4:08 PM.

Details

Summary

This patch should fix an nondeterministic error in TestStackCoreScriptedProcess.

In order to test both the multithreading capability and shared library
loading in Scripted Processes, the test would create multiple threads
that would take the same variable as a reference.

The first thread would alter the value and the second thread would
monitor the value until it gets altered. This assumed a certain ordering
regarding the std::thread spawning, however the ordering was not
always guaranteed at runtime.

To fix that, the test now makes use of a std::condition_variable
shared between the each thread. On the former, it will notify the other
thread when the variable gets initialized or updated and on the latter,
it will wait until the variable it receives a new notification.

This should fix the data racing issue while preserving the testing
coverage.

rdar://98678134

Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>

Diff Detail

Event Timeline

mib created this revision.Dec 6 2022, 4:08 PM
Herald added a project: Restricted Project. · View Herald TranscriptDec 6 2022, 4:08 PM
mib requested review of this revision.Dec 6 2022, 4:08 PM
mib updated this revision to Diff 480674.Dec 6 2022, 4:09 PM

Run clang-format

mib edited the summary of this revision. (Show Details)Dec 6 2022, 4:14 PM
bulbazord requested changes to this revision.Dec 6 2022, 4:44 PM

I think that the idea you've laid out in the summary makes sense but the implementation seems off.
My understanding of std::condition_variable is that combined with std::mutex it is used to facilitate inter-thread synchronization. That would make sense if thread_1 and thread_2 both used a mutex and condition_variable to communicate with each other about the status of n but it looks like only thread_1 actually uses and manages the mutex/condition_variable. Why is call_and_wait invoking notify_one when it's also what invokes baz (which is what is invoking wait)? This seems somewhat sketchy because the thread that is performing the notifications is the same thread that is performing the wait.

To accomplish your goal, I think it would probably look more like this:

  1. compute_pow should acquire the lock on the mutex, modify n, unlock, and then invoke cv.notify_one().
  2. call_and_wait should only invoke baz. I don't think that the implementation of baz would require any modifications. Maybe thread_2 could run baz directly instead?

Perhaps I'm mistaken about some details but I think this could probably be written in a clearer way.

This revision now requires changes to proceed.Dec 6 2022, 4:44 PM
mib updated this revision to Diff 480796.Dec 7 2022, 12:39 AM

Address @bulbazord comments

bulbazord added inline comments.Dec 7 2022, 10:58 AM
lldb/test/API/functionalities/scripted_process/main.cpp
17

Why do you need this initial notification?

24–26

Why does this need to be in a while loop? The condition_variable's wait function should guarantee that baz only ever returns 42, no? Unless I'm missing something.

mib updated this revision to Diff 482433.Dec 13 2022, 4:58 AM

Update test program and test

mib marked an inline comment as done.Dec 13 2022, 5:04 AM
bulbazord accepted this revision.Dec 13 2022, 11:51 AM

LGTM, small nit

lldb/test/API/functionalities/scripted_process/main.cpp
21

nit: no need to relock, you're done modifying n. The lock will get freed right after anyway.

This revision is now accepted and ready to land.Dec 13 2022, 11:51 AM
JDevlieghere added inline comments.Dec 13 2022, 1:12 PM
lldb/test/API/functionalities/scripted_process/main.cpp
14–15

Unless I misunderstand the code, I don't think you need this while loop anymore. baz should block until the condition variable is changed.

mib updated this revision to Diff 488029.Jan 10 2023, 4:28 PM
mib marked 3 inline comments as done.

Address comments from @JDevlieghere & @bulbazord

lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py