[PATCH v7 04/15] Add LogMessageVerbSigSafe() for logging messages while in signal context

Peter Hutterer peter.hutterer at who-t.net
Wed Jun 20 22:56:35 PDT 2012


From: Chase Douglas <chase.douglas at canonical.com>

[whot: edited to use varargs]

Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Changes to previous version:
- use varargs, not magic preprocessor expansion

 include/os.h |    7 ++++
 os/log.c     |  126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 129 insertions(+), 4 deletions(-)

diff --git a/include/os.h b/include/os.h
index 276eb52..b3f9088 100644
--- a/include/os.h
+++ b/include/os.h
@@ -49,6 +49,7 @@ SOFTWARE.
 
 #include "misc.h"
 #include <stdarg.h>
+#include <stdint.h>
 #include <string.h>
 
 #define SCREEN_SAVER_ON   0
@@ -604,6 +605,12 @@ _X_ATTRIBUTE_PRINTF(3, 4);
 extern _X_EXPORT void
 LogMessage(MessageType type, const char *format, ...)
 _X_ATTRIBUTE_PRINTF(2, 3);
+extern _X_EXPORT void
+LogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...)
+_X_ATTRIBUTE_PRINTF(3, 4);
+extern _X_EXPORT void
+LogVMessageVerbSigSafe(MessageType type, int verb, const char *format, va_list args)
+_X_ATTRIBUTE_PRINTF(3, 0);
 
 extern _X_EXPORT void
 LogVHdrMessageVerb(MessageType type, int verb,
diff --git a/os/log.c b/os/log.c
index 5394847..a3c1305 100644
--- a/os/log.c
+++ b/os/log.c
@@ -172,6 +172,14 @@ asm(".desc ___crashreporter_info__, 0x10");
 #define X_NONE_STRING			""
 #endif
 
+static size_t
+strlen_sigsafe(const char *s)
+{
+    size_t len;
+    for (len = 0; s[len]; len++);
+    return len;
+}
+
 /*
  * LogInit is called to start logging to a file.  It is also called (with
  * NULL arguments) when logging to a file is not wanted.  It must always be
@@ -271,16 +279,88 @@ LogSetParameter(LogParameter param, int value)
     }
 }
 
-/* This function does the actual log message writes. */
+static int
+pnprintf(char *string, size_t size, const char *f, va_list args)
+{
+    int f_idx = 0;
+    int s_idx = 0;
+    int f_len = strlen_sigsafe(f);
+    char *string_arg;
+    char number[21];
+    int p_len;
+    int i;
+
+    for (; f_idx < f_len && s_idx < size - 1; f_idx++) {
+        if (f[f_idx] != '%') {
+            string[s_idx++] = f[f_idx];
+            continue;
+        }
+
+        switch (f[++f_idx]) {
+        case 's':
+            string_arg = va_arg(args, char*);
+            p_len = strlen_sigsafe(string_arg);
+
+            for (i = 0; i < p_len && s_idx < size - 1; i++)
+                string[s_idx++] = string_arg[i];
+            break;
+
+        case 'u':
+            FormatUInt64(va_arg(args, uint64_t), number);
+            p_len = strlen_sigsafe(number);
+
+            for (i = 0; i < p_len && s_idx < size - 1; i++)
+                string[s_idx++] = number[i];
+            break;
+
+        case 'p':
+            string[s_idx++] = '0';
+            if (s_idx < size - 1)
+                string[s_idx++] = 'x';
+            /* Intentional fall-through */
+
+        case 'x':
+            FormatUInt64Hex(va_arg(args, uint64_t), number);
+            p_len = strlen_sigsafe(number);
+
+            for (i = 0; i < p_len && s_idx < size - 1; i++)
+                string[s_idx++] = number[i];
+            break;
+
+        default:
+            va_arg(args, char*);
+            string[s_idx++] = '%';
+            if (s_idx < size - 1)
+                string[s_idx++] = f[f_idx];
+            break;
+        }
+    }
+
+    string[s_idx] = '\0';
+
+    return s_idx;
+}
+
+/* This function does the actual log message writes. It must be signal safe.
+ * When attempting to call non-signal-safe functions, guard them with a check
+ * of the inSignalContext global variable. */
 static void
 LogSWrite(int verb, const char *buf, size_t len, Bool end_line)
 {
     static Bool newline = TRUE;
 
     if (verb < 0 || logVerbosity >= verb)
-        fwrite(buf, len, 1, stderr);
+        write(2, buf, len);
+
     if (verb < 0 || logFileVerbosity >= verb) {
-        if (logFile) {
+        if (inSignalContext && logFileFd >= 0) {
+            write(logFileFd, buf, len);
+#ifdef WIN32
+            if (logFlush && logSync)
+                fsync(logFileFd);
+#endif
+        }
+        else if (!inSignalContext && logFile) {
             if (newline)
                 fprintf(logFile, "[%10.3f] ", GetTimeInMillis() / 1000.0);
             newline = end_line;
@@ -293,7 +373,7 @@ LogSWrite(int verb, const char *buf, size_t len, Bool end_line)
 #endif
             }
         }
-        else if (needBuffer) {
+        else if (!inSignalContext && needBuffer) {
             if (len > bufferUnused) {
                 bufferSize += 1024;
                 bufferUnused += 1024;
@@ -415,6 +495,44 @@ LogMessage(MessageType type, const char *format, ...)
     va_end(ap);
 }
 
+/* Log a message using only signal safe functions. */
+void
+LogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    LogVMessageVerbSigSafe(type, verb, format, ap);
+    va_end(ap);
+}
+
+void
+LogVMessageVerbSigSafe(MessageType type, int verb, const char *format, va_list args)
+{
+    const char *type_str;
+    char buf[1024];
+    int len;
+    Bool newline;
+
+    type_str = LogMessageTypeVerbString(type, verb);
+    if (!type_str)
+        return;
+
+    /* if type_str is not "", prepend it and ' ', to message */
+    if (type_str[0] != '\0') {
+        LogSWrite(verb, type_str, strlen_sigsafe(type_str), FALSE);
+        LogSWrite(verb, " ", 1, FALSE);
+    }
+
+    len = pnprintf(buf, sizeof(buf), format, args);
+
+    /* Force '\n' at end of truncated line */
+    if (sizeof(buf) - len == 1)
+        buf[len - 1] = '\n';
+
+    newline = (buf[len - 1] == '\n');
+    LogSWrite(verb, buf, len, newline);
+}
+
 void
 LogVHdrMessageVerb(MessageType type, int verb, const char *msg_format,
                    va_list msg_args, const char *hdr_format, va_list hdr_args)
-- 
1.7.10.2



More information about the xorg-devel mailing list