Main Page | Modules | Directories | File List | Globals | Related Pages

print.c

00001 #ifndef _PRINT_C_ /* -*- linux-c -*- */
00002 #define _PRINT_C_
00003 
00004 #include <linux/config.h>
00005 
00006 #include "io.c"
00007 
00008 /** @file print.c
00009  * @addtogroup print Print Buffer
00010  * Print Buffer Functions.
00011  * The print buffer is for collecting output to send to the user daemon.
00012  * This is a per-cpu static buffer.  The buffer is sent when
00013  * _stp_print_flush() is called.
00014  *
00015  * The reason to do this is to allow multiple small prints to be combined then
00016  * timestamped and sent together to stpd. It could flush automatically on newlines,
00017  * but what about stack traces which span many lines?  So try this and see how it works for us.
00018  * @{
00019  */
00020 
00021 /** Size of buffer, not including terminating NULL */
00022 #define STP_PRINT_BUF_LEN 8000
00023 
00024 static int _stp_pbuf_len[NR_CPUS];
00025 
00026 #ifdef STP_NETLINK_ONLY
00027 #define STP_PRINT_BUF_START 0
00028 static char _stp_pbuf[NR_CPUS][STP_PRINT_BUF_LEN + 1];
00029 
00030 void _stp_print_flush (void)
00031 {
00032         int cpu = smp_processor_id();
00033         char *buf = &_stp_pbuf[cpu][0];
00034         int len = _stp_pbuf_len[cpu];
00035 
00036         if (len == 0)
00037                 return;
00038 
00039         if ( app.logging == 0) {
00040                 _stp_pbuf_len[cpu] = 0;
00041                 return;
00042         }
00043         
00044         /* enforce newline at end  */
00045         if (buf[len - 1] != '\n') {
00046                 buf[len++] = '\n';
00047                 buf[len] = '\0';
00048         }
00049         
00050         send_reply (STP_REALTIME_DATA, buf, len + 1, stpd_pid);
00051         _stp_pbuf_len[cpu] = 0;
00052 }
00053 
00054 #else /* ! STP_NETLINK_ONLY */
00055 /* size of timestamp, in bytes, including space */
00056 #define TIMESTAMP_SIZE 19
00057 #define STP_PRINT_BUF_START (TIMESTAMP_SIZE + 1)
00058 static char _stp_pbuf[NR_CPUS][STP_PRINT_BUF_LEN + STP_PRINT_BUF_START + 1];
00059 
00060 /** Send the print buffer now.
00061  * Output accumulates in the print buffer until this is called.
00062  * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
00063  */
00064 
00065 void _stp_print_flush (void)
00066 {
00067         int cpu = smp_processor_id();
00068         char *buf = &_stp_pbuf[cpu][0];
00069         char *ptr = buf + STP_PRINT_BUF_START;
00070         struct timeval tv;
00071 
00072         if (_stp_pbuf_len[cpu] == 0)
00073                 return;
00074         
00075         /* enforce newline at end  */
00076         if (ptr[_stp_pbuf_len[cpu]-1] != '\n') {
00077                 ptr[_stp_pbuf_len[cpu]++] = '\n';
00078                 ptr[_stp_pbuf_len[cpu]] = '\0';
00079         }
00080         
00081         do_gettimeofday(&tv);
00082         scnprintf (buf, TIMESTAMP_SIZE+1, "[%li.%06li] ", tv.tv_sec, tv.tv_usec);
00083         buf[TIMESTAMP_SIZE] = ' ';
00084         relayapp_write(buf, _stp_pbuf_len[cpu] + TIMESTAMP_SIZE + 2);
00085         _stp_pbuf_len[cpu] = 0;
00086 }
00087 #endif /* STP_NETLINK_ONLY */
00088 
00089 /** Print into the print buffer.
00090  * Like printf, except output goes to the print buffer.
00091  * Safe because overflowing the buffer is not allowed.
00092  * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
00093  * 
00094  * @param fmt A printf-style format string followed by a 
00095  * variable number of args.
00096  * @sa _stp_print_flush()
00097  */
00098 
00099 void _stp_printf (const char *fmt, ...)
00100 {
00101         int num;
00102         va_list args;
00103         int cpu = smp_processor_id();
00104         char *buf = &_stp_pbuf[cpu][STP_PRINT_BUF_START] + _stp_pbuf_len[cpu];
00105         va_start(args, fmt);
00106         num = vscnprintf(buf, STP_PRINT_BUF_LEN - _stp_pbuf_len[cpu], fmt, args);
00107         va_end(args);
00108         if (num > 0)
00109                 _stp_pbuf_len[cpu] += num;
00110 }
00111 
00112 /** Print into the print buffer.
00113  * Use this if your function already has a va_list.
00114  * You probably want _stp_printf().
00115  */
00116 
00117 void _stp_vprintf (const char *fmt, va_list args)
00118 {
00119         int num;
00120         int cpu = smp_processor_id();
00121         char *buf = &_stp_pbuf[cpu][STP_PRINT_BUF_START] + _stp_pbuf_len[cpu];
00122         num = vscnprintf(buf, STP_PRINT_BUF_LEN -_stp_pbuf_len[cpu], fmt, args);
00123         if (num > 0)
00124                 _stp_pbuf_len[cpu] += num;
00125 }
00126 
00127 /** Write a C string into the print buffer.
00128  * Copies a string into a print buffer.
00129  * Safe because overflowing the buffer is not allowed.
00130  * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
00131  * This is more efficient than using _stp_printf() if you don't
00132  * need fancy formatting.
00133  *
00134  * @param str A C string.
00135  * @sa _stp_print
00136  */
00137 
00138 void _stp_print_cstr (const char *str)
00139 {
00140         int cpu = smp_processor_id();
00141         char *buf = &_stp_pbuf[cpu][STP_PRINT_BUF_START] + _stp_pbuf_len[cpu];
00142         int num = strlen (str);
00143         if (num > STP_PRINT_BUF_LEN - _stp_pbuf_len[cpu])
00144                 num = STP_PRINT_BUF_LEN - _stp_pbuf_len[cpu];
00145         strncpy (buf, str, num+1);
00146         _stp_pbuf_len[cpu] += num;
00147 }
00148 
00149 /** Clear the scratch buffer.
00150  * This function should be called before anything is written to 
00151  * the scratch buffer.  Output will accumulate in the buffer
00152  * until this function is called again.  
00153  * @returns A pointer to the buffer.
00154  */
00155 
00156 char *_stp_print_clear (void)
00157 {
00158         int cpu = smp_processor_id();
00159         _stp_pbuf_len[cpu] = 0;
00160         return &_stp_pbuf[cpu][STP_PRINT_BUF_START];
00161 }
00162 
00163 #include "string.c"
00164 
00165 /** Write a String into the print buffer.
00166  * Copies a String into a print buffer.
00167  * Safe because overflowing the buffer is not allowed.
00168  * Size is limited by length of print buffer, #STP_PRINT_BUF_LEN.
00169  * This is more efficient than using _stp_printf() if you don't
00170  * need fancy formatting.
00171  *
00172  * @param str A String.
00173  * @sa _stp_print
00174  */
00175 
00176 void _stp_print_string (String str)
00177 {
00178         if (str->len)
00179                 _stp_print_cstr (str->buf);
00180 }
00181 
00182 /** Write a String or C string into the print buffer.
00183  * This macro selects the proper function to call.
00184  * @param str A String or C string (char *)
00185  * @sa _stp_print_cstr _stp_print_string
00186  */
00187 
00188 #define _stp_print(str)                                                 \
00189         ({                                                              \
00190           if (__builtin_types_compatible_p (typeof (str), char[])) {    \
00191                   char *x = (char *)str;                                \
00192                   _stp_print_cstr(x);                                   \
00193           } else {                                                      \
00194                   String x = (String)str;                               \
00195                   _stp_print_string(x);                                 \
00196           }                                                             \
00197   })
00198 
00199 /** @} */
00200 #endif /* _PRINT_C_ */