|
Server : Apache/2.2.2 (Fedora) System : Linux App1.pathumtani.go.th 2.6.20-1.2320.fc5smp #1 SMP Tue Jun 12 19:40:16 EDT 2007 i686 User : apache ( 48) PHP Version : 5.2.9 Disable Function : NONE Directory : /usr/share/systemtap/runtime/ |
Upload File : |
/* -*- linux-c -*-
* Print Functions
* Copyright (C) 2005, 2006 Red Hat Inc.
*
* This file is part of systemtap, and is free software. You can
* redistribute it and/or modify it under the terms of the GNU General
* Public License (GPL); either version 2, or (at your option) any
* later version.
*/
#ifndef _PRINT_C_
#define _PRINT_C_
#include "string.h"
#include "io.c"
#include "vsprintf.c"
/** @file print.c
* Printing Functions.
*/
/** @addtogroup print Print Functions
* The print buffer is for collecting output to send to the user daemon.
* This is a per-cpu static buffer. The buffer is sent when
* _stp_print_flush() is called.
*
* The reason to do this is to allow multiple small prints to be combined then
* timestamped and sent together to staprun. This is more efficient than sending
* numerous small packets.
*
* This function is called automatically when the print buffer is full.
* It MUST also be called at the end of every probe that prints something.
* @{
*/
#ifdef STP_RELAYFS
#define STP_TIMESTAMP_SIZE (sizeof(uint32_t))
#else
#define STP_TIMESTAMP_SIZE 0
#endif /* STP_RELAYFS */
#define STP_PRINT_BUF_START (STP_TIMESTAMP_SIZE)
typedef struct __stp_pbuf {
uint32_t len; /* bytes used in the buffer */
char timestamp[STP_TIMESTAMP_SIZE];
char buf[STP_BUFFER_SIZE];
} _stp_pbuf;
void *Stp_pbuf = NULL;
int _stp_print_init (void)
{
Stp_pbuf = alloc_percpu(_stp_pbuf);
if (unlikely(Stp_pbuf == 0))
return -1;
return 0;
}
void _stp_print_cleanup (void)
{
if (Stp_pbuf)
free_percpu(Stp_pbuf);
}
/** Send the print buffer to the transport now.
* Output accumulates in the print buffer until it
* is filled, or this is called. This MUST be called before returning
* from a probe or accumulated output in the print buffer will be lost.
*
* @note Preemption must be disabled to use this.
*/
void _stp_print_flush (void)
{
_stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
/* check to see if there is anything in the buffer */
if (pb->len == 0)
return;
#ifdef STP_RELAYFS_MERGE
/* In merge-mode, staprun expects relayfs data to start with a 4-byte length */
/* followed by a 4-byte sequence number. In non-merge mode, anything goes. */
*((uint32_t *)pb->timestamp) = _stp_seq_inc();
if (unlikely(_stp_transport_write(pb, pb->len+4+STP_TIMESTAMP_SIZE) < 0))
atomic_inc (&_stp_transport_failures);
#else
if (unlikely(_stp_transport_write(pb->buf, pb->len) < 0))
atomic_inc (&_stp_transport_failures);
#endif
pb->len = 0;
}
#ifndef STP_MAXBINARYARGS
#define STP_MAXBINARYARGS 127
#endif
/** Reserves space in the output buffer for direct I/O.
*/
#if defined STP_RELAYFS && !defined STP_RELAYFS_MERGE
static void * _stp_reserve_bytes (int numbytes)
{
if (unlikely(numbytes == 0))
return NULL;
_stp_print_flush();
return relay_reserve(_stp_chan, numbytes);
}
#else
static void * _stp_reserve_bytes (int numbytes)
{
_stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
int size = STP_BUFFER_SIZE - pb->len;
void * ret;
if (unlikely(numbytes == 0 || numbytes > STP_BUFFER_SIZE))
return NULL;
if (numbytes > size)
_stp_print_flush();
ret = pb->buf + pb->len;
pb->len += numbytes;
return ret;
}
#endif /* STP_RELAYFS */
/** Write 64-bit args directly into the output stream.
* This function takes a variable number of 64-bit arguments
* and writes them directly into the output stream. Marginally faster
* than doing the same in _stp_vsnprintf().
* @sa _stp_vsnprintf()
*/
static void _stp_print_binary (int num, ...)
{
va_list vargs;
int i;
int64_t *args;
if (unlikely(num > STP_MAXBINARYARGS))
num = STP_MAXBINARYARGS;
args = _stp_reserve_bytes(num * sizeof(int64_t));
if (args != NULL) {
va_start(vargs, num);
for (i = 0; i < num; i++) {
args[i] = va_arg(vargs, int64_t);
}
va_end(vargs);
}
}
/** Print into the print buffer.
* Like printf, except output goes to the print buffer.
* Safe because overflowing the buffer is not allowed.
*
* @sa _stp_print_flush()
*/
#define _stp_printf(args...) _stp_sprintf(_stp_stdout,args)
/** Print into the print buffer.
* Use this if your function already has a va_list.
* You probably want _stp_printf().
*/
#define _stp_vprintf(fmt,args) _stp_vsprintf(_stp_stdout,fmt,args)
/** Write a C string into the print buffer.
* Copies a string into a print buffer.
* Safe because overflowing the buffer is not allowed.
* This is more efficient than using _stp_printf() if you don't
* need fancy formatting.
*
* @param str A C string.
* @sa _stp_print
*/
#define _stp_print_cstr(str) _stp_string_cat_cstr(_stp_stdout,str)
/** Write a String into the print buffer.
* Copies a String into a print buffer.
* Safe because overflowing the buffer is not allowed.
* This is more efficient than using _stp_printf() if you don't
* need fancy formatting.
*
* @param str A String.
* @sa _stp_print
*/
#define _stp_print_string(str) _stp_string_cat_string(_stp_stdout,str)
/* This function is used when printing maps or stats. */
/* Probably belongs elsewhere, but is here for now. */
/* It takes a format specification like those used for */
/* printing maps and stats. It prints chars until it sees */
/* a special format char (beginning with '%'. Then it */
/* returns a pointer to that. */
static char *next_fmt(char *fmt, int *num)
{
char *f = fmt;
int in_fmt = 0;
*num = 0;
while (*f) {
if (in_fmt) {
if (*f == '%') {
_stp_string_cat_char(_stp_stdout,'%');
in_fmt = 0;
} else if (*f > '0' && *f <= '9') {
*num = *f - '0';
f++;
return f;
} else
return f;
} else if (*f == '%')
in_fmt = 1;
else
_stp_string_cat_char(_stp_stdout,*f);
f++;
}
return f;
}
/** Write a String or C string into the print buffer.
* This macro selects the proper function to call.
* @param str A String or C string (char *)
* @sa _stp_print_cstr _stp_print_string
*/
#define _stp_print(str) \
({ \
if (__builtin_types_compatible_p (typeof (str), char[])) { \
char *x = (char *)str; \
_stp_string_cat_cstr(_stp_stdout,x); \
} else { \
String x = (String)str; \
_stp_string_cat_string(_stp_stdout,x); \
} \
})
/** @} */
#endif /* _PRINT_C_ */