Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Altera_Forum
Honored Contributor I
1,866 Views

printf thread safe ?

Dear all, I am using printf() in a task to display debug information in a Nios terminal window. However, I was wondering if printf() is thread safe. I am facing some buggy behaviour which I suspect to be caused by using printf(). However, the documentation tells me that standard C functions should be thread safe. Any help or comments on this is appreciated.

0 Kudos
7 Replies
Altera_Forum
Honored Contributor I
276 Views

Where did you see in the documentation that the standard C functions were thread safe? AFAIK the libc used with the Nios EDS (newlib (http://sourceware.org/newlib/)) and the Altera drivers aren't OS and don't include any mutex or synchronization mechanism. I would avoid using printf() or any standard I/O function from multiple threads under uC/OS.

Altera_Forum
Honored Contributor I
276 Views

Hi Daixiwen,  

Chapter 10 of the Nios II developer's handbook has a section about Newlib telling that programs based on MicroC/OS-II can call ANSI C standard library functions. I interpret this as that they are thread safe...  

By the way, I am not using printf from different threads. I have an interrupt routine which post some messages to another task. From that task I decide to send debug info to the Nios II terminal window with printf(). 

I want to explain why i came to this question on this forum: 

 

One of the Altera provided sample projects shows another way to override the default printf() function. It looks like this: 

 

int printf( const char * format, ... ) 

OS_SEM_DATA semdata; 

INT8U err; 

char* string; 

int length; 

int ret_code; 

 

// If the OSPrintfSem semaphore has not yet been initialized, 

// wait until it has before we proceed. 

while( OSSemQuery( OSPrintfSem, &semdata ) != OS_NO_ERR ) 

OSTimeDlyHMSM( 0, 0, 0, 10 ); 

 

// Grab the printf semaphore before we try any printing. 

OSSemPend( OSPrintfSem, 0, &err ); 

if( err == OS_NO_ERR ) 

string = malloc( 256 ); 

va_list ap; 

 

va_start( ap ,format ); 

ret_code = vsprintf( string, format, ap ); 

va_end( ap ); 

 

length = strlen( string ); 

fwrite ( string, 1, length, stdout ); 

free( string ); 

 

err = OSSemPost( OSPrintfSem ); 

 

if( err == OS_NO_ERR ) 

return( ret_code ); 

else 

return( -1 ); 

 

I had no problems at all when I used the default Nios II internal IIC. But for some reasons I needed to switch to the external vectored interrupt controller and then all problems began. It took me headache to understand what was going on and why my processor seemed to stall sometimes in alt_tick() ( i posted another message which did not result in responses on this forum).  

Today I discovered that I could solve this issue by using another implementation of the printf by using something like this: 

 

int printf(const char *format, ...) 

alt_u8 err; 

OSSemPend(OSPrintfSem, 0, &err); 

 

va_list vl; 

va_start(vl, format); 

vprintf(format, vl); 

va_end(vl); 

 

OSSemPost(OSPrintfSem); 

 

That solved unexpected behaviour of my Nios hangup behaviour. Therefore I was triggered again about all this printf() behaviour and found the text in the Nios manual which indicates that printf() should be thread safe. Or I missinterpret something there.... 

 

Anyway... when using the default printf() I get buggy behaviour and using the second example above of replacing the default printf() seems to solve my problem. 

 

But i still do not understand why I did not got this faulty behaviour with the IIC....(where I used the first example above of the replaced printf()... 

 

regards
Altera_Forum
Honored Contributor I
276 Views

I don't think that a lot of people here used the VIC, and when they do it can be with very custom software or OSes, so I'm not sure you'll get a lot of answers. 

I don't really interpret "can call ANSI C standard library functions" as "ANSI C standard library functions are thread safe". I just interpret it as "you can call the functions" ;) I haven't looked at the code but I'd be very surprised if Altera added some# ifdefs and all the synchronization functions to the functions that need it in newlib. 

The problems with those kind of bugs is that sometimes it just works by chance, so it could be possible that in some cases you don't see it. 

Still, it's rather strange that you have this behaviour, and that you fixed it with adding the semaphore to printf(), when you are only using printf() from one thread.
Altera_Forum
Honored Contributor I
276 Views

Thread safe isn't the same as interrupt safe. 

If you want to call a function (that uses shared data) from an interrupt, you have do disable the interrupt whenever you are modifying the shared data. 

What you seem to have been doing is putting the current thread to sleep from within an interrupt handler. This is illegal for all OS I know about. 

 

I don't know anything about uC/OS, but calling stdio functions from interrupt routing is almost certainly illegal. 

There might be something like a kernel printf() that is interrupt safe - for writes to the console.
Altera_Forum
Honored Contributor I
276 Views

Hi Daixiwen, 

 

Well I am glad that you gave me a response :).  

The external VIC is indeed not too well documented. There are some example projects such as AN595 but when it comes to the interresting parts like preemption then you will end up alone in the dark wood. 

Therefore I hoped to find any guru here to help me to get out of that nasty dark wood. 

 

Unfortunately I needed the external VIC because I have a piece of hardware implemented which generates interrupts at an interval of 524us and the interrupt routine may not be delayed too much by another task such as the complete ethernet stuff which is also running. I experienced that issues when using the IIC which uses the round robin scheduling in software. 

With the VIC I can make the time critical IRQ non maskable. 

 

Anyway. With respect to the two printf() implementations as shown above I suspect the malloc() and free() functions to cause the buggy behaviour. I don't know why but these are the main differences between the two implementations.
Altera_Forum
Honored Contributor I
276 Views

 

--- Quote Start ---  

Thread safe isn't the same as interrupt safe. 

If you want to call a function (that uses shared data) from an interrupt, you have do disable the interrupt whenever you are modifying the shared data. 

What you seem to have been doing is putting the current thread to sleep from within an interrupt handler. This is illegal for all OS I know about. 

 

I don't know anything about uC/OS, but calling stdio functions from interrupt routing is almost certainly illegal. 

There might be something like a kernel printf() that is interrupt safe - for writes to the console. 

--- Quote End ---  

 

 

Hi dsl, I think I am not violating the rule that you mention. I do not call printf from my interrupt routine. Within my interrupt routine I am posting a message into a message que to another task. That task pends this message and from there a call to printing debug information is done... 

 

In fact.. .from that task I call one of the example printf() functions mentioned above... 

 

regards!
Altera_Forum
Honored Contributor I
276 Views

I just checked it on my newly multi threaded program. The printf() function is not thread safe. Before you use printf(), lock the printing function and call fflush(stdout) before any printf() calls.int myPrint(char *str){MY_LOCK LOCK; fflush(stdout); printf("%s\n", str);}

Reply