This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

stdout from threads when using GCC and Sys/BIOS on ARM?

Other Parts Discussed in Thread: SYSBIOS

Hello,

I am trying to use stdout (e.g. fprintf(stdout,"hello world\n");) from a thread without success.  Functions where stdout is implicit (e.g. printf) work fine.  I am using Sys/BIOS 6_35_04_50, gcc version gcc-arm-none-eabi-4_7-2012q4, and I am compiling for an A15.  

I notice that stdio.h maps stdout:

#define stdout (_REENT->_stdout)

to the current thread's context via __getreent().  However no thread's context (other than the "main" thread) points to a valid FILE pointer for stdout.

I have a temporary workaround in a single source file using stdout by performing:

# if defined(stdout)
# undef stdout
# define stdout _stdout_r(_GLOBAL_REENT)
# endif

But I am hoping that there is a better and more general solution out there.   I am supporting a large code base so making platform specific workarounds like these is not idea.

Thanks

P.S.  This question crosses the boundary between OS and compiler/runtime libraries.  I apologize if I chose the wrong forum to post into.

  • David,

    Are you using CCS? If you are, what version? Also what xdctools are you using?

    Moses

  • Moses,

    I am using xdctools_3_25_04_88, but I do not believe it matters.

    Replicating is easy.  Just try to do a fprintf(stdout, "frpintf from thread: %d\n", Task_getPri(Task_self())); from main() and from a thread (e.g. Task).  You will find that it is only printed from the main thread. Replacing the fprintf with a regular printf will work fine since the implied stdout is retrieve differently in that case. 

    As I pointed out before, I believe this is due to how stdout is retrieved (as defined in stdio.h from the gcc tools) and via the __getreent() function as defined by ti.sysbios.rts.gnu.ReentSupport

    Thanks,

    -David

  • Hi David,

    We enable re-entrancy support, rebuild the newlib C runtime libraries and ship them with XDC Tools. The expectation is that the application is linked with our C runtime libraries and not the default ones shipped with the GNU tools. Can you confirm if you are linking with the C runtime libraries in XDC Tools ?


    If not, please read the below FAQ for details on how to link with our libraries:

    http://processors.wiki.ti.com/index.php/SYS/BIOS_with_GCC_(CortexA)#What_do_I_need_to_do_to_make_the_C_runtime_library_re-entrant_when_building_SYS.2FBIOS_applications_for_Cortex-A_GNU_targets.C2.A0.3F

    Best,

    Ashish

  • Anish,

    Thanks for you pointers.  Yes I can confirm that I am linking against XDC.

    Again, simple to reproduce.  For example I can take the TI supplied example project "client" from nsp_gmacsw_4_09_01_02 and add the line:

    fprintf(stdout, "fprintf from thread: %d\n", Task_getPri(Task_self()));

    to the function "LOCAL_linkStatus" (after "#include <ti/sysbios/knl/Task.h>" of course).  The printf will work, the fprintf will not.  If I add my workaround mentioned above, everything will work.

    Best Regards,

    -David

  • Hi David,

    I tried to repro the issue using SYS/BIOS 6.35.04.50 but was not succesful. Both fprintf and printf work fine for me.

    As far as I know, it should not matter whether you use the global reentrancy structure's stdio handle or the task's local re-entrancy structure's stdio handle as they both point to the same file internally.

    I am not familiar with the nsp_gmacsw_4_09_01_02 product or the GNU examples included with this product. Can you share the example you are using ? I just want to take a quick look at the cfg script.

    Have you tried adding a fflush(stdout) after the fprintf() call from within a task thread ? If not, can you try adding the flush call ? If the app never exits and the prints are being buffered, they may not get printed until the stdio file stream is closed.

    Best,

    Ashish

  • Ashish,

    Thank you for trying to reproduce my problem.  That is so strange that you are unable to reproduce while it appears easy for me.  I did verify that I could reproduce with SysBIOS 6.35.04.50 and the GCC compiler previously mentioned.  

    Here is a little tracing that I did...

    The SysBIOS call ReentSupport_getReent() (C:\ti\bios_6_35_04_50\packages\ti\sysbios\rts\gnu\ReentSupport.c) will allocate and initiate a new _reent structure if one does not already exist for a given task.  The structure is initialized using _REENT_INIT_PTR which is defined in "C:\ti\ccsv5\tools\compiler\gcc-arm-none-eabi-4_7-2012q4\arm-none-eabi\include\sys\reent.h".  This macro will set 

    (var)->_stdout = &(var)->__sf[1]; \

    but __sf will be all cleared because it is initialized with:

    memset(&(var)->__sf, 0, sizeof((var)->__sf)); \

    Thus for all Tasks, stdout will be a zeroed out FILE structure.  AFAIK it will never point back to _GLOBAL_REENT->stdout.

    If it helps, I have attached the cfg file used for this example project. 1856.client.cfg

    Best Regards,

    -David

  • Hi David,

    The vfprintf function (which is internally called by fprintf) has a CHECK_INIT macro that is defined to call __sinit. If the given task's reentrancy structure has not been initialized before (i.e. the sdidinit field is 0), then it will be called from within vfprintf. If you look at the __sinit() function in "libc/findfp.c", it initializes (var)->_stdin/_stdout/_stderr.

    Since you are seeing a problem, I am guessing you are hitting some corner case. Can you share a test case demonstrating the problem that we can try out on our end ?

    Best,

    Ashish

  • Ashish,

    Sorry for the slow reply...

    I took the "client" sample app from the NSP, removed all the NDK sample and boiled it down to a sample similar what I had posted before.  I did take a look at the map file and noticed that while the project has specified a particular XDC version, the version of libc included with GCC is what is being linked in.  If this is incorrect, please provide guidance on how to change the project / cfg settings since I was using the sample code as an example.

    5543.packages.zip

    Thanks,

    David

  • Hi David,

    I did not get a chance to import and try out the sample you attached yet, but I did go through the project files and I believe the problem is that the app is not linking with the correct C runtime libraries. That is it is not linking with the libraries we ship with XDC Tools but instead linking with the runtime libraries shipped with the GNU toolchain which is not built with re-entrancy support enabled.

    The solution would be to add a "-L$(XDCTOOLS)/packages/gnu/targets/arm/libs/install-native/arm-none-eabi/lib/fpu" option to the link line where $(XDCTOOLS) is the path to the xdctools installation on your machine. It looks like you are using CCS to build your project, so you can add the "-L" library search path option in the project properties as shown below:

    Best,

    Ashish

  • Adding to my previous post:

    Its probably already clear from the screenshot but I wanted to mention again that when adding "-L" to project properties, you can use ${XDC_CG_ROOT} to specify the xdc tools installation path. CCS will expand this env variable.

    Example:

    -L${XDC_CG_ROOT}/packages/gnu/targets/arm/libs/install-native/arm-none-eabi/lib/fpu

  • Ashish,

    I can confirm that adding the new library search path solves the issue.  Thanks for your help!

    Given the that example project from TI wasn't doing this, could there perhaps a more automated way of doing this?  ie since the XDC tools are being used already, can they be updated so that they change the linker command file to automatically link against the XDC versions of the RTS?

    Thanks,

    -David

  • Hi David,

    We do take care of adding the "-L" option if the app is built using package.bld build flow (i.e. the application sources are put in a package and the package is built using xdc tools on cmd line). In this build flow, the A15F xdc target provides both the compiler and linker options required for the build.

    However, when building projects using makefiles (and configuro) on cmd line or when building in CCS, the xdc tools only serve up compiler options (compiler.opt) but not linker options. Therefore, we have no way of contributing linker options.

    That said, there is a bug filed against XDC Tools to start generating a linker.opt (in addition to a compiler.opt). Once this feature is added, we should be able to do what you suggested.

    Here's a link to the XDC Tools bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=434020

    Best,

    Ashish