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

tests/spinlock: Terminate temporary thread after tests #60123

Closed

Conversation

keith-packard
Copy link
Collaborator

The spinlock tests start an additional thread to perform tests with. If the thread isn't stopped after each test, then when the same thread structure is used in subsequent tests, the thread structure will end up in an inconsistent state. In this particular cases, the second instance doesn't end up going through z_thread_entry and so z_tls_current is not set correctly, leading to faults whenever that value is used.

This fault can be demonstrated by running the test with thread local storage enabled:

$ twister -p qemu_cortex_a53_smp \
  --test tests/kernel/spinlock/kernel.multiprocessing.spinlock \
  -xCONFIG_THREAD_LOCAL_STORAGE=y

The spinlock tests start an additional thread to perform tests with. If the
thread isn't stopped after each test, then when the same thread structure
is used in subsequent tests, the thread structure will end up in an
inconsistent state. In this particular cases, the second instance doesn't
end up going through z_thread_entry and so z_tls_current is not set
correctly, leading to faults whenever that value is used.

This fault can be demonstrated by running the test with thread local
storage enabled:

    $ twister -p qemu_cortex_a53_smp \
      --test tests/kernel/spinlock/kernel.multiprocessing.spinlock \
      -xCONFIG_THREAD_LOCAL_STORAGE=y

Signed-off-by: Keith Packard <[email protected]>
@@ -137,6 +137,8 @@ ZTEST(spinlock, test_spinlock_bounce)
bounce_once(1234, false);
}

k_thread_abort(&cpu1_thread);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a good idea to do k_thread_join() to make sure the thread is no longer running.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Waiting for termination is a guarantied part of abort's semantics. Abort and join actually share the same implementation.

Copy link
Contributor

@andyross andyross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. This is a semi-common class of bug, actually. There was discussion a while back in the context of ztest that it would be a good feature (albeit mildly complicated) for the test framework to put a level of indirection around "worker threads" like this to ensure that they don't live beyond their test case.

@keith-packard
Copy link
Collaborator Author

Good catch. This is a semi-common class of bug, actually.

Would it be reasonable to stick a check in k_thread_create to catch these? It seems like an obvious fault to try and create a thread using an already-active struct k_thread.

@andyross
Copy link
Contributor

andyross commented Jul 7, 2023

Would it be reasonable to stick a check in k_thread_create to catch these?

Not without breaking API compatibility, unfortunately. The existing call takes a completely uninitialized thread struct. It might not be zero (or a valid terminated thread), or might have been allocated from the heap and contain previous garbage, etc... We can't do any inspection of the struct at all.

It's a historical wart, basically, like the inexplicable decision to pass three separate pointer arguments. If we were to do it again at some point it would be nice to separate the "init" of the struct from the "spawn" of the thread (and also other stuff, like the pointer nonsense, or removing the timeout argument, which really only has value for static threads -- threads created at runtime can just as easily use a k_timer to do it, via a separate "spawn_thread_later()" wrapper if desired, etc...).

But for the special case of tests... maybe? Have a separate rule when CONFIG_TEST=y where we enforce that it must be valid/zero? That seems weird, but doable.

@keith-packard
Copy link
Collaborator Author

Fixed in #60567

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.

4 participants