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

lib: posix: auto allocate pthread stack if needed #16435

Closed

Conversation

tgorochowik
Copy link
Member

POSIX 1003.1 spec allows creating pthreads with attrib as NULL. In that
case, the stack needs to be auto-allocated.

Signed-off-by: Tomasz Gorochowik tgorochowik@antmicro.com

@tgorochowik tgorochowik requested a review from pfalcon as a code owner May 28, 2019 09:13
@pfalcon
Copy link
Contributor

pfalcon commented May 28, 2019

I'd prefer if the title was "lib: posix: auto allocate pthread stack if needed", though I may imagine that makes it too long for prescriptive checks we have.

@tgorochowik tgorochowik force-pushed the pthread-stack-allocation branch from 926d57a to dbf0646 Compare May 28, 2019 09:27
@tgorochowik tgorochowik changed the title lib: posix: auto allocate pthread stacks lib: posix: auto allocate pthread stack if needed May 28, 2019
@zephyrbot
Copy link
Collaborator

zephyrbot commented May 28, 2019

All checks are passing now.

Review history of this comment for details about previous failed status.
Note that some checks might have not completed yet.

@aescolar aescolar added the area: POSIX POSIX API Library label May 28, 2019
@tgorochowik tgorochowik force-pushed the pthread-stack-allocation branch from dbf0646 to bc4f254 Compare May 28, 2019 10:35
lib/posix/Kconfig Outdated Show resolved Hide resolved
Copy link
Contributor

@pfalcon pfalcon left a comment

Choose a reason for hiding this comment

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

Thanks for the patch, it's definitely helpful. But I really think that non-initialized thread attrs behavior should be clarified.

@@ -160,6 +152,20 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *attr,
if (pthread_num >= CONFIG_MAX_PTHREAD_COUNT) {
return EAGAIN;
}
if ((attr == NULL) || (attr->initialized == 0U)
Copy link
Contributor

Choose a reason for hiding this comment

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

These double-parens look really weird, please don't inherit them from previous code you change. But bigger problem is that this check doesn't look correct. It could be such only if you take frivolous interpretation of this phrase from http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html:

The behavior is undefined if the value specified by the attr argument to pthread_create() does not refer to an initialized thread attributes object.

So, if such behavior is undefined, you could treat uninitialized attrs as NULL attrs. But this way, we only complicate our own life with handling more attrs, etc.

Please add attr != NULL && attr->initialized == 0 check where previous EINVAL return was, this should simplify and clarify behavior for now and future.

Copy link
Member Author

Choose a reason for hiding this comment

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

You are right, it is better not to do anything when the behavior is undefined. This also allowed me to restore the test I originally removed.

@pfalcon
Copy link
Contributor

pfalcon commented May 28, 2019

@tgorochowik, And outside of "review-marks" comments: I wanted to post when your previous patch gets merged, but missed it, but here you just patch the related test... So, umm, well, we really need to start think about regression tests for this stuff. I know firsthand that writing tests complicate bootstrapping a subsystem (and we're effectively at this stage yet with posix in zephyr), but as we add more features, it becomes more and more important. And just a fresh example, when functionality carefully crafted by one developer was just erased by another: #16453 .

To clarify, I don't see myself adding -1 review due to lack of tests anytime soon, but definitely going to treat that stuff less relaxed on my devel side, and "promote" it with contributors.

From IEEE Std 1003.1-2017:

The pthread_attr_getstacksize() and pthread_attr_setstacksize()
functions, respectively, shall get and set the thread creation stacksize
attribute in the attr object.

The stacksize attribute shall define the minimum stack size (in bytes)
allocated for the created threads stack.

The behavior is undefined if the value specified by the attr argument
to pthread_attr_getstacksize() or pthread_attr_setstacksize() does not
refer to an initialized thread attributes object.

Signed-off-by: Tomasz Gorochowik <tgorochowik@antmicro.com>
POSIX 1003.1 spec allows creating pthreads with attrib as NULL. In that
case, the stack needs to be auto-allocated.

Signed-off-by: Tomasz Gorochowik <tgorochowik@antmicro.com>
For now use automatic stack allocation for just a single thread to
minimize the memory required for malloc arena size.

Signed-off-by: Tomasz Gorochowik <tgorochowik@antmicro.com>
@tgorochowik tgorochowik force-pushed the pthread-stack-allocation branch from bc4f254 to 0add6ff Compare May 29, 2019 11:48
@tgorochowik
Copy link
Member Author

tgorochowik commented May 29, 2019

@pfalcon Thank you for your review! I just pushed an updated version.

To highlight the changes from the previous revision:

  • I restored the EINVAL being returned for cases where the behavior is undefined
  • I added the _setstacksize function implementation, so it is now possible to use automatically allocated stack with a requested size (but the default will be used if it's not specified)
  • I created a larger if which just checks if the passed attrs are null or not, tje else block will be a good place to add handling other custom attributes from users if it's necessary
  • I modified the tests to use one thread with an automatically allocated stack (just one thread to minimize the malloc arena requirements) - Hopefully the CI will pass with this change as I tested the test changes only on selected platforms.

Please let me know what you think about these changes

Copy link
Contributor

@pfalcon pfalcon left a comment

Choose a reason for hiding this comment

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

Thanks for going thru trouble of updating it. Let me skip "isn't there a way to do it differently?" questions and approve. But CI of course needs to be fixed.

default 1024
help
If pthread_create is called without attributes specifying that an externally
defined stack is to be used, the stack will be allocated automatically with
Copy link
Contributor

Choose a reason for hiding this comment

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

"externally defined stack is to be used" might need an update now.

#define BOUNCES 64
#define STACKS (1024 + CONFIG_TEST_EXTRA_STACKSIZE)
#define THREAD_PRIORITY 3
#define ONE_SECOND 1

#if CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE < STACKS * N_THR_T_AUTO_STACK
#error "Insufficient malloc arena size"
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems to hit for 119 tests or so... ;-).

@nashif nashif requested review from andrewboie and andyross May 29, 2019 13:28
@jukkar
Copy link
Member

jukkar commented May 29, 2019

To clarify, I don't see myself adding -1 review due to lack of tests anytime soon, but definitely going to treat that stuff less relaxed on my devel side, and "promote" it with contributors.

I think the default should be that the tests are submitted together with new functionality. Writing tests afterwards is just pita. It should be an exception if no tests are created for new stuff.

@pfalcon
Copy link
Contributor

pfalcon commented May 29, 2019

It should be an exception if no tests are created for new stuff.

Right. We should just weigh a chance of motivating people to contribute more by providing quicker turnaround vs discouraging them by arbitrarily blocking their PRs (arbitrarily because rule of "tests are submitted together" is far from being closely followed). I'm personally all for the encouraging vs discouraging choice.

And on technical side, writing tests for Zephyr is oftentimes a pita itself, so we should look to improve that (good selection of convenience and helper functions, existing tests maintained and improved to serve a good copy-paste base, etc.)

@jukkar
Copy link
Member

jukkar commented May 30, 2019

Right. We should just weigh a chance of motivating people to contribute more by providing quicker turnaround vs discouraging them by arbitrarily blocking their PRs (arbitrarily because rule of "tests are submitted together" is far from being closely followed). I'm personally all for the encouraging vs discouraging choice.

We are just moving the pain later if the writing the tests is postponed.

And on technical side, writing tests for Zephyr is oftentimes a pita itself, so we should look to improve that (good selection of convenience and helper functions, existing tests maintained and improved to serve a good copy-paste base, etc.)

IMHO it is not "oftentimes" but more or less always PITA to write the tests. Fortunately we have lot of skeleton tests that can be utilized when creating new tests.

@pfalcon
Copy link
Contributor

pfalcon commented Jun 3, 2019

Ping @tgorochowik, can you please check CI failures here?

Copy link
Contributor

@andrewboie andrewboie left a comment

Choose a reason for hiding this comment

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

This is not going to work. There is a reason why all stacks have to be declared with K_THREAD_STACK_DEFINE(mystack, 4096) instead of just char mystack[4096]. Stack buffers have size/alignment restrictions which need to be handled, and additional memory may be reserved within the object for other data like hardware stack overflow guard regions.

You can't use calloc() to allocate a stack buffer, there's no way to enforce proper alignment. You're going to need to set up some pool of available stacks with K_THREAD_STACK_ARRAY_DEFINE() and have some code to manage unused stack buffers within that pool.

In addition, your changes to the test code in tests/posix/common are not sufficient. This is not getting merged until you prove that this patch actually works in the test case.

@cfriedt
Copy link
Member

cfriedt commented Jun 4, 2020

Interesting. I had a similar proposal in #25973, but was a bit more conservative with it, suggesting that static allocation be explored before heap allocation.

E.g.

CONFIG_PTHREAD_DYNAMIC_STACK=y
CONFIG_PTHREAD_DYNAMIC_STACK_SIZE=512
CONFIG_PTHREAD_MAX_DYNAMIC_STACKS=2

and using K_THREAD_STACK_ARRAY_DEFINE(), which would likely make @andrewboie a bit happier (although I believe thread permissions will still need some attention).

@tgorochowik - would you be interested in combining our approaches?

Some alternatives I considered were EITHER static OR heap allocation, as well as a hybrid approach that first consumed statically declared stacks, and then went to heap allocation if those stacks were exhausted.

Personally, I feel that static allocation would be more friendly on small devices with only 10s of kBs of SRAM.

@tgorochowik
Copy link
Member Author

@cfriedt unfortunately I don't have any resources to continue this at the moment, please feel free to take over or extract anything you find useful here and use it for your implementation, thanks for pinging me!

@cfriedt
Copy link
Member

cfriedt commented Jun 4, 2020

@tgorochowik Cool - I have a direct use for this, so I might do that. Thanks!

@github-actions github-actions bot added area: API Changes to public APIs area: Tests Issues related to a particular existing or missing test labels Jun 29, 2020
@github-actions github-actions bot added has-conflicts Issue/PR has conflicts with another issue/PR and removed has-conflicts Issue/PR has conflicts with another issue/PR labels Jun 29, 2020
@nashif nashif added the Stale label Sep 4, 2020
@github-actions github-actions bot closed this Sep 19, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: API Changes to public APIs area: POSIX POSIX API Library area: Tests Issues related to a particular existing or missing test has-conflicts Issue/PR has conflicts with another issue/PR Stale
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants