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

Stack size of non-main threads on POSIX #15045

Open
HertzDevil opened this issue Sep 27, 2024 · 2 comments
Open

Stack size of non-main threads on POSIX #15045

HertzDevil opened this issue Sep 27, 2024 · 2 comments

Comments

@HertzDevil
Copy link
Contributor

On Unix-like systems, the size of a stack depends on where the corresponding fiber is:

  • The main fiber of the main thread uses ulimit -Ss, or the result of calling getrlimit with RLIMIT_STACK;
  • All spawned fibers use Fiber::StackPool::STACK_SIZE, which is exactly 8 MiB;
  • The main fiber of any non-main thread is configured by the attr argument to GC.pthread_create; since we aren't passing any, an implementation-specific default is used.

The last one varies greatly across platforms, down to just 128 KiB on Alpine Linux. Normally, this isn't a concern for the Crystal runtime, since under -Dpreview_mt all the extra main fibers are just the scheduler's worker loops, which are not expected to arbitrarily grow their stacks. However, this would still be relevant if one tries to do Thread.new directly, so we might want to standardize this stack size as well.

Windows doesn't make a distinction between main and extra threads if we pass 0 as the stack size when spawning a new thread with GC.beginthreadex, since they both pick up the value of the /STACK link flag.

@straight-shoota
Copy link
Member

It's worth noting that Thread.new is currently not a public API. There should eventually be a public API to spawn a thread explicitly.
With crystal-lang/rfcs#2 this is implemented as ExecutionContext::Isolated: A context that starts a single thread to run one exclusive fiber. So user code still runs in a fiber and the thread stack will be unused except for starting the fiber. We could perhaps consider using the thread stack as the fiber stack to avoid an additional allocation, but that would be an implementation detail (and probably not very clever).

I think that means that all spawned threads can be initialized with rather minimal stack size.
On Linux, the minimum value is PTHREAD_STACK_MIN (16kB).

@ysbaddaden
Copy link
Contributor

Indeed, the current ExecutionContext::Isolated doesn't create another fiber, and just uses the thread's stack. It would be pointless to create another fiber.

Maybe we should be able to pass an explicit stack when creating a thread, just for that specific case... or maybe to be able to specify very small stacks for scheduler threads since their run loop don't need more than a few KB at worst.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Backlog
Development

No branches or pull requests

3 participants