On Wed, Mar 24, 2021 at 9:18 AM Matias N. <mat...@imap.cc> wrote: > > > On Tue, Mar 23, 2021, at 22:09, Nathan Hartman wrote: > > On Tue, Mar 23, 2021 at 8:39 PM Matias N. <mat...@imap.cc <mailto: > matias%40imap.cc>> wrote: > > > > > Hi, > > > while using getopt() from a task started from NSH I realized subsequent > > > calls reused the global optind and similar variables resulting in > different > > > results each time. I'm aware this is expected in FLAT mode and is > related > > > to the issue of static C++ constructors (they would only be called > once, > > > not every time the task is started). > > > > > > What I wonder is what could we do to avoid this common pitfall: > > > - document it somewhere (a common issues/troubleshooting section in the > > > docs would be good to have anyways) and just accept the issue >
Wiki already mention this issue here: https://cwiki.apache.org/confluence/display/NUTTX/Linux+Processes+vs+NuttX+Tasks Greg shares many knowledge in wiki. To improve the visibility, it's better to migrate Confluence to Documentation. > > - religiously initialize globals myself before being used (a pain, error > > > prone, and a bit adhoc, working only for FLAT mode) > > > - support reentrant versions of all possible APIs and always use these > in FLAT mode Yes, it's the right direction to promote the reentrant API. > > > - devise a mechanism to mimic what would be done by OS in KERNEL mode > (add > > > some custom handler to APIs internally using globals, such as getopt, > that can be > > > called either manually by user or by the OS itself when the task is > started?) The custom handler isn't enough here, because the real problem is we need the global variables per task/process. As Greg suggests, we need something like TLS but per task/process not per thread(e.g. task_getspecific/task_setspecific). Once the mechanism is done, getopt can be converted to confirm the standard trivally. > > > - other? The transparent/standard solution is switched to the ELF binary(note: it doesn't depend on KERNEL mode), and then loses the XIP benefit(huge memory penalty). But, it's doable to XIP again by combining ELF loader and ROMFS. > > > > > > When using globals, best practice is to make it really clear that the > > variables are global. Many programmers do this by prefixing global > variable > > names with g_*. > > > > I take a different approach: A long time ago, I started grouping all > > globals in a struct, which has one global instance called Global. It > makes > > it easy to find all globals, and furthermore at the start of the program > as > > a matter of policy the first thing I do is memset() the Global struct to > 0. > > Yes, I know that is often redundant to the startup code, but in some > > situations the startup code doesn't initialize globals. The FLAT model is > > one example of this (from the 2nd invocation onwards). I've seen other > > examples of this over the years. By memset()ing your globals at the start > > of main() you can rest assured that the globals are in fact zeroed, > > regardless of whatever else happened before main(). It has another side > > benefit: with globals grouped this way, it becomes trivial to take a > > standalone program and turn it into a component of a larger program. > > tl;dr, this > > approach has worked great for me for a long time. > > That sounds like a good approach. > > > > > Caveat: It won't help if your program (or any API called by it) uses > > globals that are outside your control, and therefore, not initialized by > > you. :-/ > > Yes, my concern is about functions such as getopt(). If you just follow the > description of the API and use it as normal you reach this pitfall. I was > looking > for some approach to avoid this as much as possible. For getopt() I see > there's > even no standard getopt_r(), so we would have to provide our own, which > may not > be a bad idea. > Still, this issue will probably present in many other places. > > Seldom people will call getopt_r in Linux, because the different process gets the new and clean copy, but it is crucial for NuttX to work correctly. Yes, getopt_r isn't standardized by committee, but it follows the convention used by other similar functions(e.g. strtok_r) and implemented by glibc. > > > Nathan > > > > Best, > Matias