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