Skip to content

Manage service render window from server main thread.

  • closes async/paraview#157

The issue

The link above has a good summary of the problem. To be clear, the render service invoked certain Cocoa window system API which is only meant to be invoked from the main thread - corresponds to the main thread of the server(in a remote session) or client(built-in session). On macOS, all pv* executables in built-in/remote sessions crashed because of a Cocoa API exception on the render service thread. A workaround would've been to avoid rs startup, use ds for geometry delivery, and a separate pvrenderserver process or something similar for rendering. However, it is tricky right now because the rs-ds are started by default in the existing code. This approach may be possible once we've got a nice API that can start/connect to external services.

The fix

Re-route thread-sensitive API from the background thread onto the main thread by taking advantage of rxcpp run loops. When a background thread knows it's about to execute a thread-sensitive block of code, it will enqueue that block of code - can be a lambda/function with args on the main thread's rxcpp run loop. Since the background thread expects the result or completion of an action, it blocks until the main thread finishes the task. As we only do this for create/resize/context of a window, it is negligible. When proposing to move certain blocks of code on the main thread this way, the bar of entry is going to be really really high - only if the app crashes/memory corruption, etc; since we want to keep the main thread as free as possible.

Create/Resize window in Mac OS:

  • A proxy property can now define a new XML attribute run_on_main_thread that lets us apply properties from the server's main thread instead of a background thread.
  • To that end, vtkRemotingCoreUtilities::RunAsBlocking(func, coordination, args...) was introduced. It can enqueue a function on the server's main thread or any other thread. This method waits for completion and returns the result of the function. We use this function for creating a render window as well. This is a C++-only method and must be used with great care. When invoked with a coordination corresponding to the caller's thread, it will deadlock. For now, it satisfies the purpose, we can extend it with future(s) as needed later on.

Render() in Mac OS:

  • With those two changes, the render service thread no longer crashed during Create/Resize window on macOS, however, vtkCocoaRenderWindow would call certain Cocoa API during every render from the vtkOpenGLRenderWindow::Start() method. As a result, all executables crash just after creating the server window during the first render. To remedy this problem, a new factory override is set up for vtkRenderWindow on Apple MacOSX. It subclasses vtkCocoaRenderWindow, and overrides the vtkCocoaRenderWindow::Start method such that a non-main thread enqueues sensitive superclass API on the server's main thread.

VTK override

  • This MR also contains an initial attempt at overriding vtk-master classes. Some of these ideas can be used when we sync up with VTK master notes
Edited by Jaswant Panchumarti (Kitware)

Merge request reports