Hi Oliver,

[email protected] wrote:
> I have done several changes in rt_print.c and rtdk.h to extend
> the functionality of rt-print lib as follows :
> - Fork save initialisation of the library by using pthread_atfork()
>   There are now two hooks integrated :
>     1. A prepare hook which is called to prepare the fork. This
>         hook clears all open print buffers
>     2. A child hook which is called after the fork on the child side.
>        This hook clears also all open print buffers (just ot be on the save 
> side)
>        and is spawning another printer thread.
> 
> - Adding two addition functions
>     1. rt_syslog( int priority, char *format, ...)
>         which reports all messages to the syslog, using the print buffers of 
> rtprint
>     2. rt_vsyslog( int priority, char *format, va_list args )
>         same as above for va_list arguments.
> 
> Both changes do run in my application as expected. It's now possible to use
> rt_print-lib in a daemonized process and rt_print output can be directed
> to syslog via rt_syslog/rt_vsyslog.

Thanks for the patch. I just have a few comments, see below.

> 
> 
> Oliver
> 
> 
> 
> --- rtdk.h.original   2007-12-09 11:46:36.000000000 +0100
> +++ rtdk.h    2009-10-09 11:46:52.767271100 +0200
>                  
>  int rt_vprintf(const char *format, va_list args);
>  int rt_fprintf(FILE *stream, const char *format, ...);
>  int rt_printf(const char *format, ...);
> +void rt_syslog( int priority, char *format, ...);
                 ^^^
Stray whitespace.

> +void rt_vsyslog(int priority, char *format, va_list args);
> +
>  
>  int rt_print_init(size_t buffer_size, const char *name);
>  void rt_print_cleanup(void); 
> 
> 
> --- rt_print.c.original       2008-09-10 10:36:27.000000000 +0200
> +++ rt_print.c        2009-10-09 11:47:16.014443900 +0200
>                  
>  #include <stdlib.h>
>  #include <string.h>
>  #include <unistd.h>
> +#include <syslog.h>
>  
>  #include <rtdk.h>
>  #include <asm/xenomai/system.h>
>                   
>  
>  #define RT_PRINT_LINE_BREAK          256
>  
> +#define RT_PRINT_SYSLOG_STREAM       ((FILE *)-9999)

Better use NULL here.

> +
>  struct entry_head {
>       FILE *dest;
>       uint32_t seq_no;
> +     int priority;
>       char text[1];
>  } __attribute__((packed));
>  
>                    
>  
>  static void cleanup_buffer(struct print_buffer *buffer);
>  static void print_buffers(void);
> +static void rt_print_reinit_atfork_prepare(void);
> +static void rt_print_reinit_atfork_child(void);
>  
>  /* *** rt_print API *** */
>  
> -int rt_vfprintf(FILE *stream, const char *format, va_list args)
> +static int rt_print_to_buffer(FILE *stream, int priority, const char 
> *format, va_list args)

Line with >80 characters.

>  {
>       struct print_buffer *buffer = pthread_getspecific(__buffer_key);
>       off_t write_pos, read_pos;
>                    
>                       /* Write out empty entry */
>                       head = buffer->ring + write_pos;
>                       head->seq_no = __seq_no;
> +                     head->priority = 0;
>                       head->text[0] = 0;
>  
>                       /* Forward to the ring buffer start */
>                    
>       /* If we were able to write some text, finalise the entry */
>       if (len > 0) {
>               head->seq_no = ++__seq_no;
> +             head->priority = priority;
>               head->dest = stream;
>  
>               /* Move forward by text and head length */
>                    
>               /* An empty entry marks the wrap-around */
>               head = buffer->ring + write_pos;
>               head->seq_no = __seq_no;
> +             head->priority = priority;
>               head->text[0] = 0;
>  
>               write_pos = 0;
>                     
>       return res;
>  }
>  
> +int rt_vfprintf(FILE *stream, const char *format, va_list args)
> +{
> +     return rt_print_to_buffer( stream, 0, format, args);

Stray whitespace.

> +}
> +
>  int rt_vprintf(const char *format, va_list args)
>  {
>       return rt_vfprintf(stdout, format, args);
>                     
>       return n;
>  }
>  
> +void rt_syslog(int priority, char *format, ...)
> +{
> +     va_list args;
> +
> +     va_start(args, format);
> +     rt_print_to_buffer(RT_PRINT_SYSLOG_STREAM, priority, format, args);
> +     va_end(args);
> +
> +     return;
> +}
> +
> +void rt_vsyslog(int priority, char *format, va_list args )

Whitespace.

> +{
> +
> +     rt_print_to_buffer(RT_PRINT_SYSLOG_STREAM, priority, format, args);
> +
> +     return;
> +}
> +
>  static void set_buffer_name(struct print_buffer *buffer, const char *name)
>  {
>       int n;
>                     
>  
>               if (len) {
>                       /* Print out non-empty entry and proceed */
> -                     fprintf(head->dest, "%s", head->text);
> +                     /* Check if output goes to syslog */
> +                     if (head->dest == RT_PRINT_SYSLOG_STREAM) {
> +                             syslog( head->priority, "%s", head->text );

Stray whitespaces. And one /may/ argue that we do not need braces here,
but that's a grey area.

> +                     } else {
> +                             /* Output goes to specified stream */
> +                             fprintf(head->dest, "%s", head->text);
> +                     }
> +
>                       read_pos += sizeof(*head) + len;
>               } else {
>                       /* Emptry entries mark the wrap-around */
>                     
>       }
>  }
>  
> +static void rt_print_reinit_atfork_child(void)
> +{
> +     pthread_attr_t thattr;
> +     struct print_buffer *buffer,*next_b;
> +
> +     /* Clean parent process buffer list -
> +        Shouldn't be necessary because also done at atfork_parent
> +     */
> +     buffer = __first_buffer;
> +     while (buffer) {
> +             next_b = buffer->next;
> +             cleanup_buffer(buffer);
> +             buffer = next_b;
> +     }
> +
> +     /* Throw new thread with printer loop in child process */
> +     pthread_attr_init(&thattr);
> +     pthread_attr_setstacksize(&thattr, PTHREAD_STACK_MIN);
> +     pthread_create(&__printer_thread, &thattr, printer_loop, NULL);
> +     
> pthread_atfork(rt_print_reinit_atfork_prepare,NULL,rt_print_reinit_atfork_child);
> +}

Here is my version:

static void spawn_printer_thread(void)
{
        pthread_attr_t thattr;

        pthread_attr_init(&thattr);
        pthread_attr_setstacksize(&thattr, PTHREAD_STACK_MIN);
        pthread_create(&printer_thread, &thattr, printer_loop, NULL);
}

static void forked_child_init(void)
{
        struct print_buffer *my_buffer = pthread_getspecific(buffer_key);
        struct print_buffer **pbuffer = &first_buffer;

        /* re-init to avoid finding it locked by some parent thread */
        pthread_mutex_init(&buffer_lock, NULL);

        while (*pbuffer) {
                if (*pbuffer == my_buffer)
                        pbuffer = &(*pbuffer)->next;
                else
                        cleanup_buffer(*pbuffer);
        }

        spawn_printer_thread();
}

The major differences are:
 - my code is totally untested :)
 - we have to play safe and re-init the mutex
 - we should not purge a potentially existing buffer of the main thread
 - I don't think we have to re-install the fork hook for the child (the
   parent's installation should survive the fork)

and...

> +
> +static void rt_print_reinit_atfork_prepare(void)
> +{
> +     struct print_buffer *buffer,*next_b;
> +
> +     /* Clean parent process buffer list */
> +     buffer = __first_buffer;
> +     while (buffer) {
> +             next_b = buffer->next;
> +             cleanup_buffer(buffer);
> +             buffer = next_b;
> +     }
> +}
> +

 - we must not destroy the father's environment

>  void __rt_print_init(void)
>  {
>       pthread_attr_t thattr;
>                    
>       pthread_attr_init(&thattr);
>       pthread_attr_setstacksize(&thattr, PTHREAD_STACK_MIN);
>       pthread_create(&__printer_thread, &thattr, printer_loop, NULL);
> +     
> pthread_atfork(rt_print_reinit_atfork_prepare,NULL,rt_print_reinit_atfork_child);
>  } 
> 

Besides that, nice patch!

Jan

-- 
Siemens AG, Corporate Technology, CT SE 2
Corporate Competence Center Embedded Linux

_______________________________________________
Xenomai-help mailing list
[email protected]
https://mail.gna.org/listinfo/xenomai-help

Reply via email to