Skip to content

Steps stack is not thread-safe #1851

@hamztouiz

Description

@hamztouiz

Description

The global Steps._stack in labgrid/step.py is a plain Python list shared across all threads. I'm hitting an AssertionError in Steps.pop() intermittently, and I believe it is caused by a race condition between threads.

I'm not sure if my usage of USBVideoDriver is the intended one — I'm running a continuous background image capture (OpenCV/GStreamer) while simultaneously calling other @step-decorated drivers from the main thread. It's possible this use case was not anticipated, and that Steps was designed assuming single-threaded usage only.

That said, if other scenarios can also trigger background threads (e.g. async callbacks, GStreamer internals), this could affect more users.

My setup

  • USBVideoDriver is used to capture frames continuously in a background thread (via OpenCV/GStreamer)
  • While the capture is running, the main thread calls USBSDMuxDriver.set_mode() (or any other @step-decorated method)
  • Both threads end up pushing/popping on the same shared _stack, corrupting its order

Traceback

File ".../labgrid/step.py", line 222, in wrapper
    step.stop()
File ".../labgrid/step.py", line 186, in stop
    steps.pop(self)
File ".../labgrid/step.py", line 29, in pop
    assert self._stack[-1] is step
AssertionError

Environment

  • labgrid version: 25.0.1
  • Python: 3.13
  • OS: Ubuntu
  • Test runner: Robot Framework

Question

Is it intentional that Steps is not thread-safe? Is my usage of USBVideoDriver in a background capture thread considered unsupported?

If making _stack thread-local is acceptable, I'd be happy to submit a PR:

import threading

class Steps:
    def __init__(self):
        self._local = threading.local()
        self._subscribers = []

    @property
    def _stack(self):
        if not hasattr(self._local, 'stack'):
            self._local.stack = []
        return self._local.stack

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions