[PATCH v3 05/16] Add LogMessageVerbSigSafe() for logging messages while in signal context

Peter Hutterer peter.hutterer at who-t.net
Thu May 10 23:23:38 PDT 2012


On Mon, Apr 16, 2012 at 11:14:22AM -0700, Chase Douglas wrote:
> Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
> ---
>  include/os.h |   56 ++++++++++++++++++++++
>  os/log.c     |  148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 204 insertions(+), 0 deletions(-)
> 
> diff --git a/include/os.h b/include/os.h
> index 166c60c..683679f 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
> @@ -582,6 +583,8 @@ typedef enum {
>      X_UNKNOWN = -1              /* unknown -- this must always be last */
>  } MessageType;
>  
> +typedef const uint64_t log_param_t;
> +
>  extern _X_EXPORT const char *
>  LogInit(const char *fname, const char *backup);
>  extern _X_EXPORT void
> @@ -595,6 +598,8 @@ extern _X_EXPORT void
>  LogWrite(int verb, const char *f, ...)
>  _X_ATTRIBUTE_PRINTF(2, 3);
>  extern _X_EXPORT void
> +LogWriteSigSafe(int verb, const char *f, log_param_t *args, int num_args);
> +extern _X_EXPORT void
>  LogVMessageVerb(MessageType type, int verb, const char *format, va_list args)
>  _X_ATTRIBUTE_PRINTF(3, 0);
>  extern _X_EXPORT void
> @@ -603,6 +608,9 @@ _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,
> +                       const log_param_t *args, int num_args);
>  
>  extern _X_EXPORT void
>  LogVHdrMessageVerb(MessageType type, int verb,
> @@ -653,4 +661,52 @@ LogPrintMarkers(void);
>  extern _X_EXPORT void
>  xorg_backtrace(void);
>  
> +#define NARG(...) (NARG_(__VA_ARGS__, RSEQ_N) - (sizeof(#__VA_ARGS__) == 1))
> +#define NARG_(...) NARG__(__VA_ARGS__)
> +#define NARG__( _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) (N)
> +#define RSEQ_N 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
> +
> +#define ARG_N_9_(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) (log_param_t)(N)
> +#define ARG_N_9(...) ARG_N_9_(__VA_ARGS__)
> +#define ARG_N_8_(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) (log_param_t)(N)
> +#define ARG_N_8(...) ARG_N_8_(__VA_ARGS__)
> +#define ARG_N_7_(_1, _2, _3, _4, _5, _6, _7, N, ...) (log_param_t)(N)
> +#define ARG_N_7(...) ARG_N_7_(__VA_ARGS__)
> +#define ARG_N_6_(_1, _2, _3, _4, _5, _6, N, ...) (log_param_t)(N)
> +#define ARG_N_6(...) ARG_N_6_(__VA_ARGS__)
> +#define ARG_N_5_(_1, _2, _3, _4, _5, N, ...) (log_param_t)(N)
> +#define ARG_N_5(...) ARG_N_5_(__VA_ARGS__)
> +#define ARG_N_4_(_1, _2, _3, _4, N, ...) (log_param_t)(N)
> +#define ARG_N_4(...) ARG_N_4_(__VA_ARGS__)
> +#define ARG_N_3_(_1, _2, _3, N, ...) (log_param_t)(N)
> +#define ARG_N_3(...) ARG_N_3_(__VA_ARGS__)
> +#define ARG_N_2_(_1, _2, N, ...) (log_param_t)(N)
> +#define ARG_N_2(...) ARG_N_2_(__VA_ARGS__)
> +#define ARG_N_1_(_1, N, ...) (log_param_t)(N)
> +#define ARG_N_1(...) ARG_N_1_(__VA_ARGS__)
> +#define ARG_N_0(N, ...) (log_param_t)(sizeof(#N) != 1 ? N : 0)
> +
> +/* Only 10 arguments are supported. If more are needed, update the NARG__,
> + * RSEQ_N, and ARG_N_* macros. */
> +#define LogMessageVerbSigSafe(type, verb, fmt, ...) do { \
> +    int _num_args = NARG(__VA_ARGS__); \
> +    uint64_t _args[_num_args]; \
> +_Pragma("GCC diagnostic push") \
> +_Pragma("GCC diagnostic ignored \"-Wbad-function-cast\"") \
> +    switch (_num_args) { \
> +        case 10: _args[9] = ARG_N_9(__VA_ARGS__, RSEQ_N); \
> +        case 9: _args[8] = ARG_N_8(__VA_ARGS__, RSEQ_N); \
> +        case 8: _args[7] = ARG_N_7(__VA_ARGS__, RSEQ_N); \
> +        case 7: _args[6] = ARG_N_6(__VA_ARGS__, RSEQ_N); \
> +        case 6: _args[5] = ARG_N_5(__VA_ARGS__, RSEQ_N); \
> +        case 5: _args[4] = ARG_N_4(__VA_ARGS__, RSEQ_N); \
> +        case 4: _args[3] = ARG_N_3(__VA_ARGS__, RSEQ_N); \
> +        case 3: _args[2] = ARG_N_2(__VA_ARGS__, RSEQ_N); \
> +        case 2: _args[1] = ARG_N_1(__VA_ARGS__, RSEQ_N); \
> +        case 1: _args[0] = ARG_N_0(__VA_ARGS__, RSEQ_N); \
> +    } \
> +_Pragma("GCC diagnostic pop") \
> +    _LogMessageVerbSigSafe(type, verb, fmt, _args, _num_args); \
> +} while(0)
> +

whoah, crazy, but this seems to be correct.

>  #endif                          /* OS_H */
> diff --git a/os/log.c b/os/log.c
> index cd924a3..3747fe0 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,6 +279,70 @@ LogSetParameter(LogParameter param, int value)
>      }
>  }
>  
> +static int
> +pnprintf(char *string, size_t size, const char *f, log_param_t *args,
> +         int num_args)
> +{
> +    int f_idx = 0;
> +    int s_idx = 0;
> +    int p_idx = 0;
> +    int f_len = strlen_sigsafe(f);
> +    char *string_arg;
> +    char number[20];
> +    int p_len;
> +    int i;
> +
> +    for (; f_idx < f_len && s_idx < size - 1; f_idx++) {
> +        if (f[f_idx] != '%' || p_idx >= num_args) {
> +            string[s_idx++] = f[f_idx];
> +            continue;
> +        }
> +
> +        switch (f[++f_idx]) {
> +        case 's':
> +            string_arg = (char *)args[p_idx++];
> +            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((uint64_t)args[p_idx++], 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((uint64_t)args[p_idx++], number);
> +            p_len = strlen_sigsafe(number);
> +
> +            for (i = 0; i < p_len && s_idx < size - 1; i++)
> +                string[s_idx++] = number[i];
> +            break;
> +
> +        default:
> +            p_idx++;
> +            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. */
>  
>  void
> @@ -326,6 +398,63 @@ LogVWrite(int verb, const char *f, va_list args)
>  }
>  
>  void
> +LogWriteSigSafe(int verb, const char *f, log_param_t *args, int num_args)
> +{
> +    static char tmpBuffer[1024];
> +    int len = 0;
> +    char number[20];
> +    static Bool newline = TRUE;
> +
> +    if (newline) {
> +        CARD32 ms = GetTimeInMillis();

GetTimeInMillis calls gettimeofday() which isn't signal-safe, afaict.

Cheers,
  Peter

> +        FormatUInt64(ms / 1000, number);
> +
> +        if (logFileFd >= 0) {
> +            write(logFileFd, "[", 1);
> +            write(logFileFd, number, strlen_sigsafe(number));
> +            write(logFileFd, ".", 1);
> +            number[0] = '0' + (ms % 1000) / 100;
> +            write(logFileFd, number, 1);
> +            number[0] = '0' + (ms % 100) / 10;
> +            write(logFileFd, number, 1);
> +            number[0] = '0' + ms % 10;
> +            write(logFileFd, number, 1);
> +            write(logFileFd, "] ", 2);
> +        }
> +    }
> +
> +    if (verb < 0 || logFileVerbosity >= verb || logVerbosity >= verb)
> +        len = pnprintf(tmpBuffer, sizeof(tmpBuffer), f, args, num_args);
> +
> +    if (len > 0)
> +        newline = (tmpBuffer[len - 1] == '\n');
> +
> +    if ((verb < 0 || logVerbosity >= verb) && len > 0)
> +        write(2, tmpBuffer, len);
> +
> +    if ((verb < 0 || logFileVerbosity >= verb) && len > 0) {
> +        if (logFileFd >= 0) {
> +            write(logFileFd, tmpBuffer, len);
> +#ifndef WIN32
> +            if (logFlush && logSync)
> +                fsync(logFileFd);
> +#endif
> +        } else if (!inSignalContext && needBuffer) {
> +            if (len > bufferUnused) {
> +                bufferSize += 1024;
> +                bufferUnused += 1024;
> +                saveBuffer = realloc(saveBuffer, bufferSize);
> +                if (!saveBuffer)
> +                    FatalError("realloc() failed while saving log messages\n");
> +            }
> +            bufferUnused -= len;
> +            memcpy(saveBuffer + bufferPos, tmpBuffer, len);
> +            bufferPos += len;
> +        }
> +    }
> +}
> +
> +void
>  LogWrite(int verb, const char *f, ...)
>  {
>      va_list args;
> @@ -420,6 +549,25 @@ 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,
> +                       const log_param_t *args, int num_args)
> +{
> +    const char *type_str;
> +
> +    type_str = LogMessageTypeVerbString(type, verb);
> +    if (!type_str)
> +        return;
> +
> +    if (type_str[0] != '\0') {
> +        const log_param_t type_args[1] = { (log_param_t)type_str };
> +        LogWriteSigSafe(verb, "%s ", type_args, 1);
> +    }
> +
> +    LogWriteSigSafe(verb, format, args, num_args);
> +}
> +
>  void
>  LogVHdrMessageVerb(MessageType type, int verb, const char *msg_format,
>                     va_list msg_args, const char *hdr_format, va_list hdr_args)
> -- 
> 1.7.9.1
> 


More information about the xorg-devel mailing list