"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/gallium/auxiliary/util/u_log.c" (16 Sep 2020, 6074 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "u_log.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright 2017 Advanced Micro Devices, Inc.
    3  *
    4  * Permission is hereby granted, free of charge, to any person obtaining a
    5  * copy of this software and associated documentation files (the "Software"),
    6  * to deal in the Software without restriction, including without limitation
    7  * on the rights to use, copy, modify, merge, publish, distribute, sub
    8  * license, and/or sell copies of the Software, and to permit persons to whom
    9  * the Software is furnished to do so, subject to the following conditions:
   10  *
   11  * The above copyright notice and this permission notice (including the next
   12  * paragraph) shall be included in all copies or substantial portions of the
   13  * Software.
   14  *
   15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
   18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
   19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
   20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
   21  * USE OR OTHER DEALINGS IN THE SOFTWARE.
   22  */
   23 
   24 #include "u_log.h"
   25 
   26 #include "util/u_memory.h"
   27 #include "util/u_string.h"
   28 
   29 struct page_entry {
   30    const struct u_log_chunk_type *type;
   31    void *data;
   32 };
   33 
   34 struct u_log_page {
   35    struct page_entry *entries;
   36    unsigned num_entries;
   37    unsigned max_entries;
   38 };
   39 
   40 struct u_log_auto_logger {
   41    u_auto_log_fn *callback;
   42    void *data;
   43 };
   44 
   45 /**
   46  * Initialize the given logging context.
   47  */
   48 void
   49 u_log_context_init(struct u_log_context *ctx)
   50 {
   51    memset(ctx, 0, sizeof(*ctx));
   52 }
   53 
   54 /**
   55  * Free all resources associated with the given logging context.
   56  *
   57  * Pages taken from the context via \ref u_log_new_page must be destroyed
   58  * separately.
   59  */
   60 void
   61 u_log_context_destroy(struct u_log_context *ctx)
   62 {
   63    u_log_page_destroy(ctx->cur);
   64    FREE(ctx->auto_loggers);
   65    memset(ctx, 0, sizeof(*ctx));
   66 }
   67 
   68 /**
   69  * Add an auto logger.
   70  *
   71  * Auto loggers are called each time a chunk is added to the log.
   72  */
   73 void
   74 u_log_add_auto_logger(struct u_log_context *ctx, u_auto_log_fn *callback,
   75                       void *data)
   76 {
   77    struct u_log_auto_logger *new_auto_loggers =
   78       REALLOC(ctx->auto_loggers,
   79               sizeof(*new_auto_loggers) * ctx->num_auto_loggers,
   80               sizeof(*new_auto_loggers) * (ctx->num_auto_loggers + 1));
   81    if (!new_auto_loggers) {
   82       fprintf(stderr, "Gallium u_log: out of memory\n");
   83       return;
   84    }
   85 
   86    unsigned idx = ctx->num_auto_loggers++;
   87    ctx->auto_loggers = new_auto_loggers;
   88    ctx->auto_loggers[idx].callback = callback;
   89    ctx->auto_loggers[idx].data = data;
   90 }
   91 
   92 /**
   93  * Make sure that auto loggers have run.
   94  */
   95 void
   96 u_log_flush(struct u_log_context *ctx)
   97 {
   98    if (!ctx->num_auto_loggers)
   99       return;
  100 
  101    struct u_log_auto_logger *auto_loggers = ctx->auto_loggers;
  102    unsigned num_auto_loggers = ctx->num_auto_loggers;
  103 
  104    /* Prevent recursion. */
  105    ctx->num_auto_loggers = 0;
  106    ctx->auto_loggers = NULL;
  107 
  108    for (unsigned i = 0; i < num_auto_loggers; ++i)
  109       auto_loggers[i].callback(auto_loggers[i].data, ctx);
  110 
  111    assert(!ctx->num_auto_loggers);
  112    ctx->num_auto_loggers = num_auto_loggers;
  113    ctx->auto_loggers = auto_loggers;
  114 }
  115 
  116 static void str_print(void *data, FILE *stream)
  117 {
  118    fputs((char *)data, stream);
  119 }
  120 
  121 static const struct u_log_chunk_type str_chunk_type = {
  122    .destroy = free,
  123    .print = str_print,
  124 };
  125 
  126 void
  127 u_log_printf(struct u_log_context *ctx, const char *fmt, ...)
  128 {
  129    va_list va;
  130    char *str = NULL;
  131 
  132    va_start(va, fmt);
  133    int ret = vasprintf(&str, fmt, va);
  134    va_end(va);
  135 
  136    if (ret >= 0) {
  137       u_log_chunk(ctx, &str_chunk_type, str);
  138    } else {
  139       fprintf(stderr, "Gallium u_log_printf: out of memory\n");
  140    }
  141 }
  142 
  143 /**
  144  * Add a custom chunk to the log.
  145  *
  146  * type->destroy will be called as soon as \p data is no longer needed.
  147  */
  148 void
  149 u_log_chunk(struct u_log_context *ctx, const struct u_log_chunk_type *type,
  150             void *data)
  151 {
  152    struct u_log_page *page = ctx->cur;
  153 
  154    u_log_flush(ctx);
  155 
  156    if (!page) {
  157       ctx->cur = CALLOC_STRUCT(u_log_page);
  158       page = ctx->cur;
  159       if (!page)
  160          goto out_of_memory;
  161    }
  162 
  163    if (page->num_entries >= page->max_entries) {
  164       unsigned new_max_entries = MAX2(16, page->num_entries * 2);
  165       struct page_entry *new_entries = REALLOC(page->entries,
  166                                                page->max_entries * sizeof(*page->entries),
  167                                                new_max_entries * sizeof(*page->entries));
  168       if (!new_entries)
  169          goto out_of_memory;
  170 
  171       page->entries = new_entries;
  172       page->max_entries = new_max_entries;
  173    }
  174 
  175    page->entries[page->num_entries].type = type;
  176    page->entries[page->num_entries].data = data;
  177    page->num_entries++;
  178    return;
  179 
  180 out_of_memory:
  181    fprintf(stderr, "Gallium: u_log: out of memory\n");
  182 }
  183 
  184 /**
  185  * Convenience helper that starts a new page and prints the previous one.
  186  */
  187 void
  188 u_log_new_page_print(struct u_log_context *ctx, FILE *stream)
  189 {
  190    u_log_flush(ctx);
  191 
  192    if (ctx->cur) {
  193       u_log_page_print(ctx->cur, stream);
  194       u_log_page_destroy(ctx->cur);
  195       ctx->cur = NULL;
  196    }
  197 }
  198 
  199 /**
  200  * Return the current page from the logging context and start a new one.
  201  *
  202  * The caller is responsible for destroying the returned page.
  203  */
  204 struct u_log_page *
  205 u_log_new_page(struct u_log_context *ctx)
  206 {
  207    u_log_flush(ctx);
  208 
  209    struct u_log_page *page = ctx->cur;
  210    ctx->cur = NULL;
  211    return page;
  212 }
  213 
  214 /**
  215  * Free all data associated with \p page.
  216  */
  217 void
  218 u_log_page_destroy(struct u_log_page *page)
  219 {
  220    if (!page)
  221       return;
  222 
  223    for (unsigned i = 0; i < page->num_entries; ++i) {
  224       if (page->entries[i].type->destroy)
  225          page->entries[i].type->destroy(page->entries[i].data);
  226    }
  227    FREE(page->entries);
  228    FREE(page);
  229 }
  230 
  231 /**
  232  * Print the given page to \p stream.
  233  */
  234 void
  235 u_log_page_print(struct u_log_page *page, FILE *stream)
  236 {
  237    for (unsigned i = 0; i < page->num_entries; ++i)
  238       page->entries[i].type->print(page->entries[i].data, stream);
  239 }