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

Deadlocks with delegates #15

Open
sean-anderson-seco opened this issue Nov 19, 2024 · 0 comments
Open

Deadlocks with delegates #15

sean-anderson-seco opened this issue Nov 19, 2024 · 0 comments

Comments

@sean-anderson-seco
Copy link

sean-anderson-seco commented Nov 19, 2024

Because of the GIL, a python delegate will cause a deadlock if it holds any locks that the main thread tries to acquire, assuming the delegate is called on another thread:

Thread 1                       Thread 2
============================== ================================
PythonEngine.EndAllowThreads()
python_code()
 CSharp.FuncA() 
                               CSharp.ThreadB()
                                lock(obj)
                                CallDelegate()
                                 PythonEngine.EndAllowThreads()
  lock(obj)

Although there are opportunities for deadlock with the explicit locking, one hazardous lock is that used by the garbage collector. Whenever C# code allocates memory, the GC may need to "stop the world" in order to free up resources. If this is done in a cooperative manner (such as with MONO_THREADS_SUSPEND set to coop or hybrid), then deadlock can result. This is because coop mode requires mono threads to periodically execute MONO_SUSPEND_CHECK, which will not occur when PythonEngine.EndAllowThreads is waiting for the GIL. For mono at least, this can be resolved by setting MONO_THREADS_SUSPEND to preemptive, which uses signals to induce GC pauses. As this setting can only be configured with an environmental variable, users will need to set it manually. I am not sure about the behavior of other runtimes.

Of course, it is also possible to introduce deadlocks using explicit locking. Given the delegate-oriented renode API, eliminating the use of python delegates altogether would be unsatisfactory. Ideally, callbacks would not be called with locks held, but sometimes this is necessary to provide API guarantees. I think the best way to approach this would be to document both the general problem (as it can be a bit tricky to recognize), as well as document some specific pitfalls.

Another alternative could be to introduce a select-style interface that could register delegates and actions. However, this would make it difficult to synchronously respond to events. Maybe something using Monitor.TryCompilePlugin could be wired up?

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

No branches or pull requests

1 participant