From 8052642eadfb95b244f978b10889dff51f9133f5 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 10 Jun 2017 20:48:38 +0100 Subject: Rework to only allocate one thing in the corked state and nothing in the uncorked state --- include/nslog/nslog.h | 45 ++++++++++++----------- src/core.c | 100 +++++++++++++++++++++++++++++--------------------- test/basic.c | 22 +++++++---- 3 files changed, 96 insertions(+), 71 deletions(-) diff --git a/include/nslog/nslog.h b/include/nslog/nslog.h index fff31a7..ffa87bd 100644 --- a/include/nslog/nslog.h +++ b/include/nslog/nslog.h @@ -15,6 +15,8 @@ #ifndef NSLOG_NSLOG_H_ #define NSLOG_NSLOG_H_ +#include + typedef enum { NSLOG_LEVEL_DEEPDEBUG = 0, NSLOG_LEVEL_DEBUG = 1, @@ -45,16 +47,15 @@ typedef struct nslog_category_s { struct nslog_category_s *next; } nslog_category_t; -typedef struct nslog_entry_s { +typedef struct nslog_entry_context_s { nslog_category_t *category; nslog_level level; const char *filename; const char *funcname; int lineno; - char message[0]; /* NUL terminated */ -} nslog_entry_t; +} nslog_entry_context_t; -#define NSLOG_DECLARE_CATEGORY(catname) \ +#define NSLOG_DECLARE_CATEGORY(catname) \ extern nslog_category_t __nslog_category_##catname #define NSLOG_DEFINE_CATEGORY(catname, description) \ @@ -75,31 +76,31 @@ typedef struct nslog_entry_s { NULL, \ } -#define NSLOG(catname, level, logmsg, args...) \ - if (NSLOG_LEVEL_##level >= NSLOG_COMPILED_MIN_LEVEL) { \ - nslog__log(&__nslog_category_##catname, \ - NSLOG_LEVEL_##level, \ - __FILE__, \ - __LINE__, \ - __PRETTY_FUNCTION__, \ - logmsg, \ - ##args); \ - } - -void nslog__log(nslog_category_t *category, - nslog_level level, - const char *filename, - int lineno, - const char *funcname, +#define NSLOG(catname, level, logmsg, args...) \ + do { \ + if (NSLOG_LEVEL_##level >= NSLOG_COMPILED_MIN_LEVEL) { \ + nslog_entry_context_t ctx = { \ + &__nslog_category_##catname, \ + NSLOG_LEVEL_##level, \ + __FILE__, \ + __PRETTY_FUNCTION__, \ + __LINE__, \ + }; \ + nslog__log(&ctx, logmsg, ##args); \ + } \ + } while(0) + +void nslog__log(nslog_entry_context_t *ctx, const char *pattern, - ...) __attribute__ ((format (printf, 6, 7))); + ...) __attribute__ ((format (printf, 2, 3))); typedef enum { NSLOG_NO_ERROR = 0, NSLOG_NO_MEMORY = 1, } nslog_error; -typedef void (*nslog_callback)(void *context, nslog_entry_t *msg); +typedef void (*nslog_callback)(void *context, nslog_entry_context_t *ctx, + const char *fmt, va_list args); nslog_error nslog_set_render_callback(nslog_callback cb, void *context); diff --git a/src/core.c b/src/core.c index 0665195..ee5f2bc 100644 --- a/src/core.c +++ b/src/core.c @@ -20,12 +20,14 @@ #include #include + static bool nslog__corked = true; static struct nslog_cork_chain { struct nslog_cork_chain *next; - nslog_entry_t *entry; -} *nslog__cork_chain = NULL; + nslog_entry_context_t context; + char message[0]; /* NUL terminated */ +} *nslog__cork_chain = NULL, *nslog__cork_chain_last = NULL; static nslog_callback nslog__cb = NULL; static void *nslog__cb_ctx = NULL; @@ -70,58 +72,56 @@ static void nslog__normalise_category(nslog_category_t *cat) } } -static void nslog__deliver(nslog_entry_t *entry) +static void nslog__log_corked(nslog_entry_context_t *ctx, + int measured_len, + const char *fmt, + va_list args) +{ + /* If corked, we need to store a copy */ + struct nslog_cork_chain *newcork = malloc(sizeof(*newcork) + measured_len + 1); + if (newcork == NULL) { + /* Wow, something went wrong */ + return; + } + newcork->context = *ctx; + vsprintf(newcork->message, fmt, args); + if (nslog__cork_chain == NULL) { + nslog__cork_chain = nslog__cork_chain_last = newcork; + } else { + nslog__cork_chain_last->next = newcork; + nslog__cork_chain_last = newcork; + } +} + +static void nslog__log_uncorked(nslog_entry_context_t *ctx, + const char *fmt, + va_list args) { /* TODO: Add filtering here */ if (nslog__cb != NULL) { - if (entry->category->name == NULL) { - nslog__normalise_category(entry->category); + if (ctx->category->name == NULL) { + nslog__normalise_category(ctx->category); } - (*nslog__cb)(nslog__cb_ctx, entry); + (*nslog__cb)(nslog__cb_ctx, ctx, fmt, args); } } -void nslog__log(nslog_category_t *category, - nslog_level level, - const char *filename, - int lineno, - const char *funcname, +void nslog__log(nslog_entry_context_t *ctx, const char *pattern, ...) { va_list ap; va_start(ap, pattern); - va_list ap2; - va_copy(ap2, ap); - int slen = vsnprintf(NULL, 0, pattern, ap); - va_end(ap); - nslog_entry_t *entry = malloc(sizeof(nslog_entry_t) + slen + 1); - if (entry == NULL) { - /* We're at ENOMEM! log entry is lost */ - va_end(ap2); - return; - } - entry->category = category; - entry->level = level; - entry->filename = filename; - entry->funcname = funcname; - entry->lineno = lineno; - vsprintf(entry->message, pattern, ap2); - va_end(ap2); if (nslog__corked) { - struct nslog_cork_chain *chained = malloc(sizeof(struct nslog_cork_chain)); - if (chained == NULL) { - /* ENOMEM during corked operation! wow */ - free(entry); - return; - } - chained->next = nslog__cork_chain; - chained->entry = entry; - nslog__cork_chain = chained; + va_list ap2; + va_copy(ap2, ap); + int slen = vsnprintf(NULL, 0, pattern, ap); + va_end(ap); + nslog__log_corked(ctx, slen, pattern, ap2); + va_end(ap2); } else { - /* Not corked */ - nslog__deliver(entry); - free(entry); + nslog__log_uncorked(ctx, pattern, ap); + va_end(ap); } } @@ -133,14 +133,30 @@ nslog_error nslog_set_render_callback(nslog_callback cb, void *context) return NSLOG_NO_ERROR; } + +static void __nslog__deliver_corked_entry(nslog_entry_context_t *ctx, + const char *fmt, + ...) +{ + va_list args; + va_start(args, fmt); + if (nslog__cb != NULL) { + (*nslog__cb)(nslog__cb_ctx, ctx, fmt, args); + } + va_end(args); +} + nslog_error nslog_uncork() { if (nslog__corked) { while (nslog__cork_chain != NULL) { struct nslog_cork_chain *ent = nslog__cork_chain; nslog__cork_chain = ent->next; - nslog__deliver(ent->entry); - free(ent->entry); + if (ent->context.category->name == NULL) { + nslog__normalise_category(ent->context.category); + } + __nslog__deliver_corked_entry(&ent->context, + "%s", ent->message); free(ent); } nslog__corked = false; diff --git a/test/basic.c b/test/basic.c index fd40633..7626dd8 100644 --- a/test/basic.c +++ b/test/basic.c @@ -13,21 +13,29 @@ NSLOG_DEFINE_CATEGORY(test, "Test category"); -static void test_render_function(void *ctx, nslog_entry_t *log) +static void test_render_function( + void *_ctx, nslog_entry_context_t *ctx, + const char *fmt, va_list args) { (void)ctx; - fprintf(stderr, "%s %s:%d [%s] %s() %s\n", - nslog_level_name(log->level), - log->filename, log->lineno, - log->category->name, - log->funcname, - log->message); + fprintf(stderr, "%s %s:%d [%s] %s() ", + nslog_level_name(ctx->level), + ctx->filename, ctx->lineno, + ctx->category->name, + ctx->funcname); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); } int main(int argc, char **argv) { nslog_set_render_callback(test_render_function, NULL); + NSLOG(test, INFO, "Pre-uncorking"); + fprintf(stderr, "About to nslog_uncork()\n"); nslog_uncork(); + fprintf(stderr, "Uncorked now\n"); NSLOG(test, WARN, "argc=%d", argc); + for (int i = 0; i < argc; ++i) + NSLOG(test, WARN, "argv[%d] = %s", i, argv[i]); return 0; } -- cgit v1.2.3