Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2008 VMware, Inc.
  4.  * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
  5.  * Copyright 2010 LunarG, Inc.
  6.  * All Rights Reserved.
  7.  *
  8.  * Permission is hereby granted, free of charge, to any person obtaining a
  9.  * copy of this software and associated documentation files (the
  10.  * "Software"), to deal in the Software without restriction, including
  11.  * without limitation the rights to use, copy, modify, merge, publish,
  12.  * distribute, sub license, and/or sell copies of the Software, and to
  13.  * permit persons to whom the Software is furnished to do so, subject to
  14.  * the following conditions:
  15.  *
  16.  * The above copyright notice and this permission notice (including the
  17.  * next paragraph) shall be included in all copies or substantial portions
  18.  * of the Software.
  19.  *
  20.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  23.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  25.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  26.  * DEALINGS IN THE SOFTWARE.
  27.  *
  28.  **************************************************************************/
  29.  
  30.  
  31. /**
  32.  * Logging facility for debug/info messages.
  33.  * _EGL_FATAL messages are printed to stderr
  34.  * The EGL_LOG_LEVEL var controls the output of other warning/info/debug msgs.
  35.  */
  36.  
  37.  
  38. #include <stdarg.h>
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include "c11/threads.h"
  42.  
  43. #include "egllog.h"
  44. #include "eglstring.h"
  45.  
  46. #define MAXSTRING 1000
  47. #define FALLBACK_LOG_LEVEL _EGL_WARNING
  48.  
  49.  
  50. static struct {
  51.    mtx_t mutex;
  52.  
  53.    EGLBoolean initialized;
  54.    EGLint level;
  55.    _EGLLogProc logger;
  56.    EGLint num_messages;
  57. } logging = {
  58.    _MTX_INITIALIZER_NP,
  59.    EGL_FALSE,
  60.    FALLBACK_LOG_LEVEL,
  61.    NULL,
  62.    0
  63. };
  64.  
  65. static const char *level_strings[] = {
  66.    /* the order is important */
  67.    "fatal",
  68.    "warning",
  69.    "info",
  70.    "debug",
  71.    NULL
  72. };
  73.  
  74.  
  75. /**
  76.  * Set the function to be called when there is a message to log.
  77.  * Note that the function will be called with an internal lock held.
  78.  * Recursive logging is not allowed.
  79.  */
  80. void
  81. _eglSetLogProc(_EGLLogProc logger)
  82. {
  83.    EGLint num_messages = 0;
  84.  
  85.    mtx_lock(&logging.mutex);
  86.  
  87.    if (logging.logger != logger) {
  88.       logging.logger = logger;
  89.  
  90.       num_messages = logging.num_messages;
  91.       logging.num_messages = 0;
  92.    }
  93.  
  94.    mtx_unlock(&logging.mutex);
  95.  
  96.    if (num_messages)
  97.       _eglLog(_EGL_DEBUG,
  98.               "New logger installed. "
  99.               "Messages before the new logger might not be available.");
  100. }
  101.  
  102.  
  103. /**
  104.  * Set the log reporting level.
  105.  */
  106. void
  107. _eglSetLogLevel(EGLint level)
  108. {
  109.    switch (level) {
  110.    case _EGL_FATAL:
  111.    case _EGL_WARNING:
  112.    case _EGL_INFO:
  113.    case _EGL_DEBUG:
  114.       mtx_lock(&logging.mutex);
  115.       logging.level = level;
  116.       mtx_unlock(&logging.mutex);
  117.       break;
  118.    default:
  119.       break;
  120.    }
  121. }
  122.  
  123.  
  124. /**
  125.  * The default logger.  It prints the message to stderr.
  126.  */
  127. static void
  128. _eglDefaultLogger(EGLint level, const char *msg)
  129. {
  130.    fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg);
  131. }
  132.  
  133.  
  134. /**
  135.  * Initialize the logging facility.
  136.  */
  137. static void
  138. _eglInitLogger(void)
  139. {
  140.    const char *log_env;
  141.    EGLint i, level = -1;
  142.  
  143.    if (logging.initialized)
  144.       return;
  145.  
  146.    log_env = getenv("EGL_LOG_LEVEL");
  147.    if (log_env) {
  148.       for (i = 0; level_strings[i]; i++) {
  149.          if (_eglstrcasecmp(log_env, level_strings[i]) == 0) {
  150.             level = i;
  151.             break;
  152.          }
  153.       }
  154.    }
  155.    else {
  156.       level = FALLBACK_LOG_LEVEL;
  157.    }
  158.  
  159.    logging.logger = _eglDefaultLogger;
  160.    logging.level = (level >= 0) ? level : FALLBACK_LOG_LEVEL;
  161.    logging.initialized = EGL_TRUE;
  162.  
  163.    /* it is fine to call _eglLog now */
  164.    if (log_env && level < 0) {
  165.       _eglLog(_EGL_WARNING,
  166.               "Unrecognized EGL_LOG_LEVEL environment variable value. "
  167.               "Expected one of \"fatal\", \"warning\", \"info\", \"debug\". "
  168.               "Got \"%s\". Falling back to \"%s\".",
  169.               log_env, level_strings[FALLBACK_LOG_LEVEL]);
  170.    }
  171. }
  172.  
  173.  
  174. /**
  175.  * Log a message with message logger.
  176.  * \param level one of _EGL_FATAL, _EGL_WARNING, _EGL_INFO, _EGL_DEBUG.
  177.  */
  178. void
  179. _eglLog(EGLint level, const char *fmtStr, ...)
  180. {
  181.    va_list args;
  182.    char msg[MAXSTRING];
  183.    int ret;
  184.  
  185.    /* one-time initialization; a little race here is fine */
  186.    if (!logging.initialized)
  187.       _eglInitLogger();
  188.    if (level > logging.level || level < 0)
  189.       return;
  190.  
  191.    mtx_lock(&logging.mutex);
  192.  
  193.    if (logging.logger) {
  194.       va_start(args, fmtStr);
  195.       ret = vsnprintf(msg, MAXSTRING, fmtStr, args);
  196.       if (ret < 0 || ret >= MAXSTRING)
  197.          strcpy(msg, "<message truncated>");
  198.       va_end(args);
  199.  
  200.       logging.logger(level, msg);
  201.       logging.num_messages++;
  202.    }
  203.  
  204.    mtx_unlock(&logging.mutex);
  205.  
  206.    if (level == _EGL_FATAL)
  207.       exit(1); /* or abort()? */
  208. }
  209.