Assigning errno in protected builds

31 views
Skip to first unread message

Michael Jung

unread,
Aug 6, 2019, 12:49:53 AM8/6/19
to nu...@googlegroups.com
Hello,

there is now a single line left in current master libwebsockets code that must be patched to be able to compile the static library for NuttX and this is only required for protected (and most likely kernel) builds:

-       errno = 0;
+       set_errno(0);

As far as I understand, this is because the errno variable is maintained as a member of the respective task's control block, which is not accessible from user space code in protected builds. For such builds 'errno' is defined to be a macro that does a syscall to retrieve and return the errno value. Naturally, this does not produce an lvalue and thus can not be assigned to, which is why the non-POSIX set_errno function is required.

This is not really a problem for libwebsockets: Its a trivial patch to apply to work around this issue. I am pretty sure Andy Green would even accept such code upstream.

However, there probably is a lot of code out there that assigns to the errno variable and thus requires porting effort in this regard in order to use it with NuttX protected builds.

I guess the correct fix would be to support POSIX semantics by moving the errno variable from the task control block to some form of thread local storage that is easily accessible by both kernel and user space code?

Any opinions on whether and how this could be done and how much effort it would be?

Thanks!
Michael

Gregory Nutt

unread,
Aug 6, 2019, 9:12:08 AM8/6/19
to nu...@googlegroups.com
Hi, Michael,
I don't know what the correct solution would be.  TLS could work OK in
the kernel build mode, but not in the protected mode.  It does not work
in the protected build because there is a common, physically addressed
user heap.  This needs more explanation...

TLS works by putting the errno value (and other local data) in a
reserved area at the base of each thread's stack.  The stacks must be
aligned to N bytes where N is a power of 2.  Then the TLS can be
recovered from the current stack pointer like:  tls = ((sp) & ~((N) -1).

But, in addition to alignment, the value of N limits the size of the
stack.  Because the available SRAM in the heap is relatively small, the
alignment limits require a small value of N.  But larger stacks require
a larger value of N.  So there is typically no ideal alignment that
works properly in the protected build. This is because of smallish SRAM
sizes and physical addressing.

In the kernel build, we have the possibility of aligning the "virtual"
stack to large values of N, like 20 or so.  So TLS could be made to work
well in that case.  But I don't think it is a good solution in the
protected build.

That is why I created the set_errno() and get_errno() macros/functions. 
They are less than ideal but will work without TLS.


Another thing I have thought about, mostly for getpid() support, is to
have a global region of memory that holds the current errno and pid. 
This would be saved, restored on each context switch it works like TLS. 
This, however, would be really awkward in SMP modes.

Greg


Michael Jung

unread,
Aug 6, 2019, 10:01:43 AM8/6/19
to nu...@googlegroups.com
Hi Greg,

thanks for your reply.

Can we not have a syscall to get the base address of the calling task's stack? This way the thread local memory block could still be placed at the base of each thread's stack, but we do not have to rely on the SP and alignment constraints (which could still be done for kernel builds to avoid the performance penalty of the syscall, of course).

Bye,
Michael



--
You received this message because you are subscribed to the Google Groups "NuttX" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nuttx+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/nuttx/a36fa378-84c3-b91c-2274-8d29b23ddc28%40gmail.com.

Gregory Nutt

unread,
Aug 6, 2019, 10:09:55 AM8/6/19
to nu...@googlegroups.com

> Can we not have a syscall to get the base address of the calling
> task's stack? This way the thread local memory block could still be
> placed at the base of each thread's stack, but we do not have to rely
> on the SP and alignment constraints (which could still be done for
> kernel builds to avoid the performance penalty of the syscall, of course).

Yes, that would work.  Similar calls already exists for pthreads.  This
gets the "top" of the push down stack.  That is the wrong end of the
stack for TLS:

FAR void *pthread_get_stackaddr_np(pthread_t thread);

But this gets the size of the stack allocation:

ssize_t pthread_get_stacksize_np(pthread_t thread);

Re-implementing TLS using similar APIs (see libs/libc/tls) and then
adapting all of the errno access would be a pretty big job, however.

Greg

Reply all
Reply to author
Forward
0 new messages