Skip to content

hal: stop returns once no thread runs a function - #4694

Open
grandixximo wants to merge 1 commit into
LinuxCNC:masterfrom
grandixximo:hal-stop-wait
Open

grandixximo wants to merge 1 commit into
LinuxCNC:masterfrom
grandixximo:hal-stop-wait

Conversation

@grandixximo

Copy link
Copy Markdown
Contributor

Part of #4669. @hdiethelm, this is the thread_task segfault you traced, with the acknowledgement kept per thread.

hal_stop_threads() only cleared threads_running. A thread in the middle of its pass went on calling the rest of its functions, so halcmd stop followed by unloadrt, which is how linuxcnc shuts down, could unload a component while the thread was still running its code. #4630 made delf and unloadrt wait while the threads run, but once they are stopped the entry is freed at once.

  • Each thread sets a busy flag before it reads threads_running and clears it after its pass. Both are sequentially consistent atomics, so either the pass sees the stop or the stop sees the pass.
  • In a user process (halcmd, halrmt), hal_stop_threads() clears threads_running, then waits until no thread is busy, at most 1000 of each thread's periods, and fails with -ETIMEDOUT after that. Called from realtime code, as motmod's exit does, it does not wait.
  • delf with the threads stopped also waits for the thread to finish its pass. That covers a stop from realtime code and a stop that runs while delf waits.
  • HAL_VER goes to 0x16 for the new field.

tests/hal-delf-live now holds the thread inside a function across halcmd stop. On master stop returns with the thread still inside, 3 of 3 runs, and a following unloadrt crashes rtapi_app. With this PR the test passes. The full suite passes apart from blendmath, which does not build with GCC 14 (#4676).

@BsAtHome, the wait is in ULAPI only, after your point on #4630 that realtime code should not call rtapi_delay().

hal_stop_threads() only cleared threads_running. A thread in the middle
of its pass went on running the rest of its functions, so a halcmd stop
followed by unloadrt, which is how linuxcnc shuts down, could unload a
component while the thread was still executing its function, and
rtapi_app crashed in thread_task(). Hannes Diethelm found it in tests
whose functions keep the servo thread busy for most of the period
(LinuxCNC#4669).

Each thread now marks itself busy before it reads threads_running and
clears the mark after its pass. In a user process hal_stop_threads()
clears threads_running, then waits until no thread is busy, at most
1000 of the thread's periods; a stuck thread makes it fail with
-ETIMEDOUT. With both flags sequentially consistent atomics, either the
thread sees the stop or the stop sees the pass. Called from realtime
code it does not wait, as before.

delf with the threads stopped trusted threads_running alone. It now
also waits until the thread has finished its pass, which matters for a
stop from realtime code and for a stop that runs while delf waits.

tests/hal-delf-live holds the thread inside a function across a stop;
the stop must not return before the thread has left it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant