What I'm thinking is that, besides the TLS based solution, adding a
non-standard getopt() seems to be a good option anyway, since it is a
lightweight solution to this particular function.
Why do you think TLS is not lightweight. It is very lightweight. The
non-standard, non-portable approach is essentially the same
computationally.
TLS is simply a little chunk of memory that lies at the "bottom" of
the stack ("bottom" meaning the lowest address when the push-down
stack memory was allocated). Get the bottom of the stack and you have
the TLS data.
TLS is more efficient if you can align stacks. Then the TLS pointer
can be obtained by just ANDing the current stack pointer. That is
trivial.
If the stack is not aligned, then we have to ask the OS where the
stack allocation begins.
Since each thread has its own stack, this provides a nearly
instantaneous way to get thread-specific data.
So I would say that the complexity is higher only because this is not
standard, familiar C programming, but in terms of light- vs
heavy-weight, I do not see a real difference. No decisions should be
made based on that weighty-ness dimension. The significant, important
criteria are standard vs. non-standard and portable vs. non-portable.
Those matter.
And given that there are a dozen or more cases where thread-safety of
globals needed, TLS is a more reasonable general solution than trying to
re=write re-entrant versions of all of the functions that rely on
globals and damaging the OS.