diff --git a/intern/clog/CLG_log.h b/intern/clog/CLG_log.h index e580f121892..181984c75bd 100644 --- a/intern/clog/CLG_log.h +++ b/intern/clog/CLG_log.h @@ -76,6 +76,8 @@ struct CLG_LogType { }; struct CLG_LogRef { + CLG_LogRef(const char *identifier); + const char *identifier; CLG_LogType *type; struct CLG_LogRef *next; @@ -114,6 +116,10 @@ void CLG_level_set(CLG_Level level); void CLG_logref_init(CLG_LogRef *clg_ref); +void CLG_logref_register(CLG_LogRef *clg_ref); +void CLG_logref_list_all(void (*callback)(const char *identifier, void *user_data), + void *user_data); + int CLG_color_support_get(CLG_LogRef *clg_ref); /* When true, quiet any NOCHECK logs that would otherwise be printed regardless of log filters @@ -123,6 +129,12 @@ int CLG_color_support_get(CLG_LogRef *clg_ref); void CLG_quiet_set(bool quiet); bool CLG_quiet_get(); +inline CLG_LogRef::CLG_LogRef(const char *identifier) + : identifier(identifier), type(nullptr), next(nullptr) +{ + CLG_logref_register(this); +} + /** Declare outside function, declare as extern in header. */ #define CLG_LOGREF_DECLARE_GLOBAL(var, id) \ static CLG_LogRef _static_##var = {id}; \ diff --git a/intern/clog/clog.cc b/intern/clog/clog.cc index a4328f8340f..fe0583270e0 100644 --- a/intern/clog/clog.cc +++ b/intern/clog/clog.cc @@ -14,6 +14,7 @@ #include #include +#include /* Disable for small single threaded programs * to avoid having to link with pthreads. */ @@ -78,8 +79,6 @@ struct CLG_IDFilter { struct CLogContext { /** Single linked list of types. */ CLG_LogType *types; - /** Single linked list of references. */ - CLG_LogRef *refs; #ifdef WITH_CLOG_PTHREADS pthread_mutex_t types_lock; #endif @@ -113,6 +112,20 @@ struct CLogContext { /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Global LogRef Single Linked List + * \{ */ + +static CLG_LogRef **clg_all_refs_p() +{ + /* Inside a function for correct static initialization order, otherwise + * all_refs might get null initialized only after logrefs are registered.*/ + static CLG_LogRef *all_refs = nullptr; + return &all_refs; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Mini Buffer Functionality * @@ -827,10 +840,8 @@ static void CLG_ctx_free(CLogContext *ctx) MEM_freeN(item); } - while (ctx->refs != nullptr) { - CLG_LogRef *item = ctx->refs; - ctx->refs = item->next; - item->type = nullptr; + for (CLG_LogRef *ref = *clg_all_refs_p(); ref; ref = ref->next) { + ref->type = nullptr; } for (uint i = 0; i < 2; i++) { @@ -944,6 +955,32 @@ bool CLG_quiet_get() * Use to avoid look-ups each time. * \{ */ +void CLG_logref_register(CLG_LogRef *clg_ref) +{ + /* Add to global list of refs, both for setting the type to null on CLG_exit() + * and so CLG_logref_list_all can be used to print all categories. */ + static std::mutex mutex; + std::scoped_lock lock(mutex); + CLG_LogRef **all_refs = clg_all_refs_p(); + clg_ref->next = *all_refs; + *all_refs = clg_ref; +} + +void CLG_logref_list_all(void (*callback)(const char *identifier, void *user_data), + void *user_data) +{ + /* Generate sorted list of unique identifiers. */ + auto cmp = [](const char *a, const char *b) { return std::strcmp(a, b) < 0; }; + std::set identifiers(cmp); + for (CLG_LogRef *ref = *clg_all_refs_p(); ref; ref = ref->next) { + identifiers.insert(ref->identifier); + } + + for (const char *identifier : identifiers) { + callback(identifier, user_data); + } +} + void CLG_logref_init(CLG_LogRef *clg_ref) { #ifdef WITH_CLOG_PTHREADS @@ -951,10 +988,6 @@ void CLG_logref_init(CLG_LogRef *clg_ref) pthread_mutex_lock(&g_ctx->types_lock); #endif if (clg_ref->type == nullptr) { - /* Add to the refs list so we can nullptr the pointers to 'type' when CLG_exit() is called. */ - clg_ref->next = g_ctx->refs; - g_ctx->refs = clg_ref; - CLG_LogType *clg_ty = clg_ctx_type_find_by_name(g_ctx, clg_ref->identifier); if (clg_ty == nullptr) { clg_ty = clg_ctx_type_register(g_ctx, clg_ref->identifier); diff --git a/source/creator/creator_args.cc b/source/creator/creator_args.cc index 844c85db4c5..a2eab2aba42 100644 --- a/source/creator/creator_args.cc +++ b/source/creator/creator_args.cc @@ -732,6 +732,7 @@ static void print_help(bArgs *ba, bool all) BLI_args_print_arg_doc(ba, "--log-show-source"); BLI_args_print_arg_doc(ba, "--log-show-backtrace"); BLI_args_print_arg_doc(ba, "--log-file"); + BLI_args_print_arg_doc(ba, "--log-list-categories"); PRINT("\n"); PRINT("Debug Options:\n"); @@ -1312,6 +1313,19 @@ static int arg_handle_log_set(int argc, const char **argv, void * /*data*/) return 0; } +static const char arg_handle_list_clog_cats_doc[] = + "\n" + "\tList all available logging categories for --log, and exit.\n"; + +static int arg_handle_list_clog_cats(int /*argc*/, const char ** /*argv*/, void * /*data*/) +{ + auto print_identifier = [](const char *identifier, void *) { printf("%s\n", identifier); }; + CLG_logref_list_all(print_identifier, nullptr); + BKE_blender_atexit(); + exit(EXIT_SUCCESS); + return 0; +} + static const char arg_handle_debug_mode_set_doc[] = "\n" "\tTurn debugging on.\n" @@ -2866,10 +2880,12 @@ void main_args_setup(bContext *C, bArgs *ba, bool all) * Also and commands that exit after usage. */ BLI_args_pass_set(ba, ARG_PASS_SETTINGS); BLI_args_add(ba, "-h", "--help", CB(arg_handle_print_help), ba); + /* MS-Windows only. */ BLI_args_add(ba, "/?", nullptr, CB_EX(arg_handle_print_help, win32), ba); BLI_args_add(ba, "-v", "--version", CB(arg_handle_print_version), nullptr); + BLI_args_add(ba, nullptr, "--log-list-categories", CB(arg_handle_list_clog_cats), nullptr); BLI_args_add(ba, "-y", "--enable-autoexec", CB_EX(arg_handle_python_set, enable), (void *)true); BLI_args_add(