[PATCH v4 05/16] Add LogMessageVerbSigSafe() for logging messages while in signal context
Peter Hutterer
peter.hutterer at who-t.net
Wed May 23 21:55:57 PDT 2012
On Mon, May 14, 2012 at 02:14:26PM -0700, Chase Douglas wrote:
> Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
> ---
> Changes since v3:
> * Rebased onto master
> - Log writing now occurs in LogSWrite, which is now signal-safe
> * Removed timestamp logging, it's not safe to get the current timestamp
tempted to have this added again with the required MONOTONIC_CLOCK defines
defines, the timestamps would be useful to have. follow up patch though.
A rather cross-eyed Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
for the series.
Cheers,
Peter
> * Updated pnprintf to use 21 character string for number formats
>
> include/os.h | 54 ++++++++++++++++++++++++++
> os/log.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 170 insertions(+), 4 deletions(-)
>
> diff --git a/include/os.h b/include/os.h
> index 276eb52..8e7aedb 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
> @@ -583,6 +584,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
> @@ -604,6 +607,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,
> @@ -654,4 +660,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)
> +
> #endif /* OS_H */
> diff --git a/os/log.c b/os/log.c
> index 5394847..8adf6cc 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,90 @@ LogSetParameter(LogParameter param, int value)
> }
> }
>
> -/* This function does the actual log message writes. */
> +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[21];
> + 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. 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 +375,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 +497,36 @@ 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;
> + 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, num_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.9.5
>
More information about the xorg-devel
mailing list