|
From: <sv...@va...> - 2009-05-09 22:54:31
|
Author: sewardj
Date: 2009-05-09 23:54:24 +0100 (Sat, 09 May 2009)
New Revision: 9808
Log:
Change the way VG_(message) behaves w.r.t. newlines, to make it more
like printf.
Prior to this commit, it would print the ==PID== preamble before the
message, and a newline after it, and if the message itself contained a
newline then the result was bad -- those new lines would not start
with a preamble.
This commit adds two changes in behaviour:
* if the message contains a newline, then the preamble will be printed
after each one. Hence it is now possible to use VG_(message) to
print multi-line messages correctly.
* VG_(message) no longer implicitly adds a newline at the end of the
message -- callers must do that themselves, explicitly, exactly as
with printf. Benefit is that is is now possible to use multiple
calls to VG_(message) to build up a single line of output.
VG_(message) now buffers output more aggressively than it did before,
to save on write syscalls, although it will immediately flush any any
time it encounters a newline. As a result of this buffering it is
necessary to add a VG_(message_flush) routine, to flush any buffered
output.
Modified:
branches/MESSAGING_TIDYUP/coregrind/m_libcprint.c
branches/MESSAGING_TIDYUP/include/pub_tool_libcprint.h
Modified: branches/MESSAGING_TIDYUP/coregrind/m_libcprint.c
===================================================================
--- branches/MESSAGING_TIDYUP/coregrind/m_libcprint.c 2009-05-09 19:59:48 UTC (rev 9807)
+++ branches/MESSAGING_TIDYUP/coregrind/m_libcprint.c 2009-05-09 22:54:24 UTC (rev 9808)
@@ -74,53 +74,52 @@
printf() and friends
------------------------------------------------------------------ */
+/* --------- printf --------- */
+
typedef
struct {
- HChar buf[128];
- Int n;
+ HChar buf[512];
+ Int buf_used;
}
- printf_buf;
+ printf_buf_t;
-static UInt vprintf_to_buf ( printf_buf *prbuf,
- const HChar *format, va_list vargs );
-static UInt printf_to_buf ( printf_buf* prbuf, const HChar *format, ... );
-
// Adds a single char to the buffer. When the buffer gets sufficiently
// full, we write its contents to the logging sink.
-static void add_to_myprintf_buf ( HChar c, void *p )
+static void add_to__printf_buf ( HChar c, void *p )
{
- printf_buf *myprintf_buf = (printf_buf *)p;
+ printf_buf_t *b = (printf_buf_t *)p;
- if (myprintf_buf->n > sizeof(myprintf_buf->buf) - 2 ) {
- send_bytes_to_logging_sink( myprintf_buf->buf, myprintf_buf->n );
- myprintf_buf->n = 0;
+ if (b->buf_used > sizeof(b->buf) - 2 ) {
+ send_bytes_to_logging_sink( b->buf, b->buf_used );
+ b->buf_used = 0;
}
- myprintf_buf->buf[myprintf_buf->n++] = c;
- myprintf_buf->buf[myprintf_buf->n] = 0;
- tl_assert(myprintf_buf->n < sizeof(myprintf_buf->buf));
+ b->buf[b->buf_used++] = c;
+ b->buf[b->buf_used] = 0;
+ tl_assert(b->buf_used < sizeof(b->buf));
}
-UInt VG_(vprintf) ( const HChar *format, va_list vargs )
+static UInt vprintf_to_buf ( printf_buf_t *prbuf,
+ const HChar *format, va_list vargs )
{
UInt ret = 0;
- printf_buf myprintf_buf = {"",0};
- ret = vprintf_to_buf(&myprintf_buf, format, vargs);
- // Write out any chars left in the buffer.
- if (myprintf_buf.n > 0) {
- send_bytes_to_logging_sink( myprintf_buf.buf, myprintf_buf.n );
+ if (VG_(clo_log_fd) >= 0) {
+ ret = VG_(debugLog_vprintf)
+ ( add_to__printf_buf, prbuf, format, vargs );
}
return ret;
}
-static UInt vprintf_to_buf ( printf_buf *prbuf,
- const HChar *format, va_list vargs )
+UInt VG_(vprintf) ( const HChar *format, va_list vargs )
{
UInt ret = 0;
+ printf_buf_t myprintf_buf = {"",0};
- if (VG_(clo_log_fd) >= 0) {
- ret = VG_(debugLog_vprintf)
- ( add_to_myprintf_buf, prbuf, format, vargs );
+ ret = vprintf_to_buf(&myprintf_buf, format, vargs);
+ // Write out any chars left in the buffer.
+ if (myprintf_buf.buf_used > 0) {
+ send_bytes_to_logging_sink( myprintf_buf.buf,
+ myprintf_buf.buf_used );
}
return ret;
}
@@ -137,33 +136,39 @@
return ret;
}
-static UInt printf_to_buf ( printf_buf* prbuf, const HChar *format, ... )
-{
- UInt ret;
- va_list vargs;
+//static UInt printf_to_buf ( printf_buf_t* prbuf, const HChar *format, ... )
+//{
+// UInt ret;
+// va_list vargs;
+//
+// va_start(vargs, format);
+// ret = vprintf_to_buf(prbuf, format, vargs);
+// va_end(vargs);
+//
+// return ret;
+//}
- va_start(vargs, format);
- ret = vprintf_to_buf(prbuf, format, vargs);
- va_end(vargs);
- return ret;
-}
+/* --------- sprintf --------- */
-/* A general replacement for sprintf(). */
-static void add_to_vg_sprintf_buf ( HChar c, void *p )
+/* If we had an explicit buf structure here, it would contain only one
+ field, indicating where the next char is to go. So use p directly
+ for that, rather than having it be a pointer to a structure. */
+
+static void add_to__sprintf_buf ( HChar c, void *p )
{
- char **vg_sprintf_ptr = p;
- *(*vg_sprintf_ptr)++ = c;
+ HChar** b = p;
+ *(*b)++ = c;
}
UInt VG_(vsprintf) ( Char* buf, const HChar *format, va_list vargs )
{
Int ret;
- Char *vg_sprintf_ptr = buf;
+ HChar* sprintf_ptr = buf;
ret = VG_(debugLog_vprintf)
- ( add_to_vg_sprintf_buf, &vg_sprintf_ptr, format, vargs );
- add_to_vg_sprintf_buf('\0', &vg_sprintf_ptr);
+ ( add_to__sprintf_buf, &sprintf_ptr, format, vargs );
+ add_to__sprintf_buf('\0', &sprintf_ptr);
vg_assert(VG_(strlen)(buf) == ret);
@@ -183,18 +188,19 @@
}
-/* A replacement for snprintf. */
+/* --------- snprintf --------- */
+
typedef
struct {
HChar* buf;
Int buf_size;
Int buf_used;
}
- snprintf_buf;
+ snprintf_buf_t;
-static void add_to_vg_snprintf_buf ( HChar c, void* p )
+static void add_to__snprintf_buf ( HChar c, void* p )
{
- snprintf_buf* b = p;
+ snprintf_buf_t* b = p;
if (b->buf_size > 0 && b->buf_used < b->buf_size) {
b->buf[b->buf_used++] = c;
if (b->buf_used < b->buf_size)
@@ -207,13 +213,13 @@
UInt VG_(vsnprintf) ( Char* buf, Int size, const HChar *format, va_list vargs )
{
Int ret;
- snprintf_buf b;
+ snprintf_buf_t b;
b.buf = buf;
b.buf_size = size < 0 ? 0 : size;
b.buf_used = 0;
ret = VG_(debugLog_vprintf)
- ( add_to_vg_snprintf_buf, &b, format, vargs );
+ ( add_to__snprintf_buf, &b, format, vargs );
return b.buf_used;
}
@@ -321,48 +327,132 @@
message()
------------------------------------------------------------------ */
-UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
+/* A buffer for accumulating VG_(message) style output. This is
+ pretty much the same as VG_(printf)'s scheme, with two differences:
+
+ * The message buffer persists between calls, so that multiple
+ calls to VG_(message) can build up output.
+
+ * Whenever the first character on a line is emitted, the
+ ==PID== style preamble is stuffed in before it.
+*/
+typedef
+ struct {
+ HChar buf[512+128];
+ Int buf_used;
+ Bool atLeft; /* notionally, is the next char position at the
+ leftmost column? */
+ VgMsgKind kind;
+ Int my_pid;
+ }
+ vmessage_buf_t;
+
+static vmessage_buf_t vmessage_buf = {"", 0, True, Vg_UserMsg, -1};
+
+
+// Adds a single char to the buffer. We aim to have at least 128
+// bytes free in the buffer, so that it's always possible to emit
+// the preamble into the buffer if c happens to be the character
+// following a \n. When the buffer gets too full, we write its
+// contents to the logging sink.
+static void add_to__vmessage_buf ( HChar c, void *p )
{
- UInt count = 0;
- Char c;
- Int i, depth;
- printf_buf myprintf_buf = {"",0};
+ HChar tmp[64];
+ vmessage_buf_t* b = (vmessage_buf_t*)p;
- switch (kind) {
- case Vg_UserMsg: c = '='; break;
- case Vg_DebugMsg: c = '-'; break;
- case Vg_DebugExtraMsg: c = '+'; break;
- case Vg_ClientMsg: c = '*'; break;
- default: c = '?'; break;
+ vg_assert(b->buf_used >= 0 && b->buf_used < sizeof(b->buf)-128);
+
+ if (UNLIKELY(b->atLeft)) {
+ // insert preamble
+ HChar ch;
+ Int i, depth;
+
+ switch (b->kind) {
+ case Vg_UserMsg: ch = '='; break;
+ case Vg_DebugMsg: ch = '-'; break;
+ case Vg_DebugExtraMsg: ch = '+'; break;
+ case Vg_ClientMsg: ch = '*'; break;
+ default: ch = '?'; break;
+ }
+
+ // Print one '>' in front of the messages for each level of
+ // self-hosting being performed.
+ depth = RUNNING_ON_VALGRIND;
+ if (depth > 10)
+ depth = 10; // ?!?!
+ for (i = 0; i < depth; i++) {
+ b->buf[b->buf_used++] = '>';
+ }
+
+ b->buf[b->buf_used++] = ch;
+ b->buf[b->buf_used++] = ch;
+
+ if (VG_(clo_time_stamp)) {
+ VG_(memset)(tmp, 0, sizeof(tmp));
+ VG_(elapsed_wallclock_time)(tmp);
+ tmp[sizeof(tmp)-1] = 0;
+ for (i = 0; tmp[i]; i++)
+ b->buf[b->buf_used++] = tmp[i];
+ }
+
+ VG_(sprintf)(tmp, "%d", b->my_pid);
+ tmp[sizeof(tmp)-1] = 0;
+ for (i = 0; tmp[i]; i++)
+ b->buf[b->buf_used++] = tmp[i];
+
+ b->buf[b->buf_used++] = ch;
+ b->buf[b->buf_used++] = ch;
+ b->buf[b->buf_used++] = ' ';
+
+ /* We can't possibly have stuffed 96 chars in merely as a result
+ of making the preamble (can we?) */
+ vg_assert(b->buf_used < sizeof(b->buf)-32);
}
- // Print one '>' in front of the messages for each level of self-hosting
- // being performed.
- depth = RUNNING_ON_VALGRIND;
- for (i = 0; i < depth; i++) {
- count += printf_to_buf (&myprintf_buf, ">");
+ b->buf[b->buf_used++] = c;
+ b->buf[b->buf_used] = 0;
+
+ if (b->buf_used >= sizeof(b->buf) - 128) {
+ send_bytes_to_logging_sink( b->buf, b->buf_used );
+ b->buf_used = 0;
}
-
- if (!VG_(clo_xml))
- count += printf_to_buf (&myprintf_buf, "%c%c", c,c);
- if (VG_(clo_time_stamp)) {
- HChar buf[50];
- VG_(elapsed_wallclock_time)(buf);
- count += printf_to_buf(&myprintf_buf, "%s ", buf);
+ b->atLeft = c == '\n';
+}
+
+
+UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
+{
+ UInt ret;
+
+ /* Note (carefully) that the buf persists from call to call, unlike
+ with the other printf variants in earlier parts of this file. */
+ vmessage_buf_t* b = &vmessage_buf; /* shorthand for convenience */
+
+ /* We have to set this each call, so that the correct flavour
+ of preamble is emitted at each \n. */
+ b->kind = kind;
+
+ /* Cache the results of getpid just once, so we don't have to call
+ getpid once for each line of text output. */
+ if (UNLIKELY(b->my_pid == -1)) {
+ b->my_pid = VG_(getpid)();
+ vg_assert(b->my_pid >= 0);
}
- if (!VG_(clo_xml))
- count += printf_to_buf (&myprintf_buf, "%d%c%c ", VG_(getpid)(), c,c);
+ ret = VG_(debugLog_vprintf) ( add_to__vmessage_buf,
+ b, format, vargs );
- count += vprintf_to_buf (&myprintf_buf, format, vargs);
- count += printf_to_buf (&myprintf_buf, "\n");
+ /* If the message finished exactly with a \n, then flush it at this
+ point. If not, assume more bits of the same line will turn up
+ in later messages, so don't bother to flush it right now. */
- if (myprintf_buf.n > 0) {
- send_bytes_to_logging_sink( myprintf_buf.buf, myprintf_buf.n );
+ if (b->atLeft && b->buf_used > 0) {
+ send_bytes_to_logging_sink( b->buf, b->buf_used );
+ b->buf_used = 0;
}
- return count;
+ return ret;
}
/* Send a simple single-part XML message. */
@@ -387,6 +477,16 @@
return count;
}
+/* Flush any output that has accumulated in vmessage_buf as a
+ result of previous calls to VG_(message) et al. */
+void VG_(message_flush) ( void )
+{
+ vmessage_buf_t* b = &vmessage_buf;
+ send_bytes_to_logging_sink( b->buf, b->buf_used );
+ b->buf_used = 0;
+}
+
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
Modified: branches/MESSAGING_TIDYUP/include/pub_tool_libcprint.h
===================================================================
--- branches/MESSAGING_TIDYUP/include/pub_tool_libcprint.h 2009-05-09 19:59:48 UTC (rev 9807)
+++ branches/MESSAGING_TIDYUP/include/pub_tool_libcprint.h 2009-05-09 22:54:24 UTC (rev 9808)
@@ -71,7 +71,7 @@
------------------------------------------------------------------ */
/* No, really. I _am_ that strange. */
-#define OINK(nnn) VG_(message)(Vg_DebugMsg, "OINK %d",nnn)
+#define OINK(nnn) VG_(message)(Vg_DebugMsg, "OINK %d\n",nnn)
/* Print a message prefixed by "??<pid>?? "; '?' depends on the VgMsgKind.
Should be used for all user output. */
@@ -84,14 +84,14 @@
}
VgMsgKind;
-/* Send a single-part message. Appends a newline. The format
- specification may contain any ISO C format specifier or %t.
- No attempt is made to let the compiler verify consistency of the
- format string and the argument list. */
+/* Send a single-part message. The format specification may contain
+ any ISO C format specifier or %t. No attempt is made to let the
+ compiler verify consistency of the format string and the argument
+ list. */
extern UInt VG_(message_no_f_c)( VgMsgKind kind, const HChar* format, ... );
-/* Send a single-part message. Appends a newline. The format
- specification may contain any ISO C format specifier. The gcc compiler
- will verify consistency of the format string and the argument list. */
+/* Send a single-part message. The format specification may contain
+ any ISO C format specifier. The gcc compiler will verify
+ consistency of the format string and the argument list. */
extern UInt VG_(message)( VgMsgKind kind, const HChar* format, ... )
PRINTF_CHECK(2, 3);
@@ -104,6 +104,9 @@
#define VG_EMSG( format, args... ) VG_(message)(Vg_DebugExtraMsg, \
format, ##args)
+/* Flush any output cached by previous calls to VG_(message) et al. */
+extern void VG_(message_flush) ( void );
+
#endif // __PUB_TOOL_LIBCPRINT_H
/*--------------------------------------------------------------------*/
|