diff --git a/src/hd-rum-translator/hd-rum-translator.cpp b/src/hd-rum-translator/hd-rum-translator.cpp index f1c11cf78..6a45e65e8 100644 --- a/src/hd-rum-translator/hd-rum-translator.cpp +++ b/src/hd-rum-translator/hd-rum-translator.cpp @@ -679,8 +679,10 @@ static string format_port_list(struct hd_rum_translator_state *s) return oss.str(); } +#define EXIT(retval) { common_cleanup(init); return retval; } int main(int argc, char **argv) { + struct init_data *init; struct hd_rum_translator_state state; int qsize; @@ -691,8 +693,8 @@ int main(int argc, char **argv) int i; struct cmdline_parameters params; - if (!common_preinit(argc, argv)) { - return EXIT_FAILURE; + if ((init = common_preinit(argc, argv)) == nullptr) { + EXIT(EXIT_FAILURE); } print_version(); @@ -700,7 +702,7 @@ int main(int argc, char **argv) if (argc == 1) { usage(argv[0]); - return EXIT_FAILURE; + EXIT(EXIT_FAILURE); } #ifndef WIN32 @@ -722,7 +724,7 @@ int main(int argc, char **argv) bool ret = parse_fmt(argc, argv, ¶ms); if (ret == false) { - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); } if (params.verbose) { @@ -731,7 +733,7 @@ int main(int argc, char **argv) if ((bufsize = atoi(params.bufsize)) <= 0) { fprintf(stderr, "invalid buffer size: %d\n", bufsize); - return 1; + EXIT(1); } switch (params.bufsize[strlen(params.bufsize) - 1]) { case 'K': @@ -751,7 +753,7 @@ int main(int argc, char **argv) if (params.port <= 0) { fprintf(stderr, "invalid port: %d\n", params.port); - return 1; + EXIT(1); } state.qhead = state.qtail = state.queue = qinit(qsize); @@ -759,7 +761,7 @@ int main(int argc, char **argv) /* input socket */ if ((sock_in = udp_init_if("localhost", NULL, params.port, 0, 255, false, false)) == NULL) { perror("input socket"); - return 2; + EXIT(2); } if (udp_set_recv_buf(sock_in, bufsize) != TRUE) { @@ -773,7 +775,7 @@ int main(int argc, char **argv) if (params.control_port != -1) { if (control_init(params.control_port, params.control_connection_type, &state.control_state, &state.mod, 0) != 0) { fprintf(stderr, "Warning: Unable to create remote control.\n"); - return EXIT_FAIL_CONTROL_SOCK; + EXIT(EXIT_FAIL_CONTROL_SOCK); } control_start(state.control_state); } @@ -781,7 +783,7 @@ int main(int argc, char **argv) // we need only one shared receiver decompressor for all recompressing streams state.decompress = hd_rum_decompress_init(&state.mod, params.out_conf, params.capture_filter); if(!state.decompress) { - return EXIT_FAIL_DECODER; + EXIT(EXIT_FAIL_DECODER); } for (i = 0; i < params.host_count; i++) { @@ -795,7 +797,7 @@ int main(int argc, char **argv) state.replicas[i] = new replica(params.hosts[i].addr, rx_port, tx_port, bufsize, &state.mod, params.hosts[i].force_ip_version); } catch (string const &s) { fputs(s.c_str(), stderr); - return EXIT_FAILURE; + EXIT(EXIT_FAILURE); } if(params.hosts[i].compression == NULL) { @@ -816,7 +818,7 @@ int main(int argc, char **argv) if(state.replicas[i]->recompress == 0) { fprintf(stderr, "Initializing output port '%s' failed!\n", params.hosts[i].addr); - return EXIT_FAILURE; + EXIT(EXIT_FAILURE); } // we don't care about this clients, we only tell decompressor to // take care about them @@ -827,7 +829,7 @@ int main(int argc, char **argv) if (pthread_create(&thread, NULL, writer, (void *) &state)) { fprintf(stderr, "cannot create writer thread\n"); - return 2; + EXIT(2); } uint64_t received_data = 0; @@ -884,7 +886,7 @@ int main(int argc, char **argv) if (state.qtail->size < 0 && !should_exit) { printf("read: %s\n", strerror(err)); - return 2; + EXIT(2); } // pass poisoned pill to the worker @@ -912,6 +914,8 @@ int main(int argc, char **argv) qdestroy(state.queue); + common_cleanup(init); + printf("Exit\n"); return 0; diff --git a/src/host.cpp b/src/host.cpp index bec98302c..e1e5bfd34 100644 --- a/src/host.cpp +++ b/src/host.cpp @@ -63,11 +63,14 @@ #include #include #include +#include #include #include -#ifdef HAVE_X +#if defined HAVE_X || defined BUILD_LIBRARIES #include +#endif +#if defined HAVE_X #include /// @todo /// The actual SONAME should be actually figured in configure. @@ -108,8 +111,21 @@ std::unordered_map commandline_params; mainloop_t mainloop; void *mainloop_udata; -static void common_cleanup() +struct init_data { + list opened_libs; +}; + +void common_cleanup(struct init_data *init) { + if (init) { +#if defined BUILD_LIBRARIES + for (auto a : init->opened_libs) { + dlclose(a); + } +#endif + } + delete init; + #ifdef USE_MTRACE muntrace(); #endif @@ -165,8 +181,10 @@ static int x11_error_handler(Display *d, XErrorEvent *e) { } #endif -bool common_preinit(int argc, char *argv[]) +struct init_data *common_preinit(int argc, char *argv[]) { + struct init_data *init; + uv_argc = argc; uv_argv = argv; @@ -205,16 +223,17 @@ bool common_preinit(int argc, char *argv[]) int err = WSAStartup(MAKEWORD(2, 2), &wsaData); if(err != 0) { fprintf(stderr, "WSAStartup failed with error %d.", err); - return false; + return nullptr; } if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { fprintf(stderr, "Counld not found usable version of Winsock.\n"); WSACleanup(); - return false; + return nullptr; } #endif - open_all("ultragrid_*.so"); // load modules + init = new init_data{}; + open_all("ultragrid_*.so", init->opened_libs); // load modules #ifdef USE_MTRACE mtrace(); @@ -223,9 +242,7 @@ bool common_preinit(int argc, char *argv[]) perf_init(); perf_record(UVP_INIT, 0); - atexit(common_cleanup); - - return true; + return init; } #include diff --git a/src/host.h b/src/host.h index b1f7170eb..7a91d8afe 100644 --- a/src/host.h +++ b/src/host.h @@ -131,7 +131,9 @@ void set_audio_delay(int val); #define RATE_DEFAULT (-2) #define RATE_FLAG_FIXED_RATE (1ll<<62ll) ///< use the bitrate as fixed, not capped -bool common_preinit(int argc, char *argv[]); +struct init_data; +struct init_data *common_preinit(int argc, char *argv[]); +void common_cleanup(struct init_data *init_data); /** * @param use_vidcap Use user suplied video capture device to elaborate input format. diff --git a/src/lib_common.cpp b/src/lib_common.cpp index 8a199cadc..7a09cb7da 100644 --- a/src/lib_common.cpp +++ b/src/lib_common.cpp @@ -171,7 +171,7 @@ static int running_from_path(char * uv_argv[]) { } #endif -void open_all(const char *pattern) { +void open_all(const char *pattern, list &libs) { #ifdef BUILD_LIBRARIES char path[512]; glob_t glob_buf; @@ -189,7 +189,8 @@ void open_all(const char *pattern) { glob(path, 0, NULL, &glob_buf); for(unsigned int i = 0; i < glob_buf.gl_pathc; ++i) { - if (!dlopen(glob_buf.gl_pathv[i], RTLD_NOW|RTLD_GLOBAL)) { + void *handle = dlopen(glob_buf.gl_pathv[i], RTLD_NOW|RTLD_GLOBAL); + if (!handle) { char *error = dlerror(); verbose_msg("Library %s opening warning: %s \n", glob_buf.gl_pathv[i], error); @@ -197,7 +198,9 @@ void open_all(const char *pattern) { if (filename && error) { lib_errors.emplace(filename, error); } + continue; } + libs.push_back(handle); } globfree(&glob_buf); diff --git a/src/lib_common.h b/src/lib_common.h index 37572255b..8e1094909 100644 --- a/src/lib_common.h +++ b/src/lib_common.h @@ -62,6 +62,11 @@ #endif /* BUILD_LIBRARIES */ +#ifdef __cplusplus +#include +void open_all(const char *pattern, std::list &libs); +#endif + #ifdef __cplusplus extern "C" { #endif @@ -78,7 +83,6 @@ enum library_class { LIBRARY_CLASS_VIDEO_POSTPROCESS, LIBRARY_CLASS_VIDEO_RXTX, }; -void open_all(const char *pattern); const void *load_library(const char *name, enum library_class, int abi_version); void register_library(const char *name, const void *info, enum library_class, int abi_version, int hidden); void list_modules(enum library_class, int abi_version, bool full); diff --git a/src/main.cpp b/src/main.cpp index 5c74a1b23..52394f5d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -589,8 +589,11 @@ static bool parse_params(char *optarg) return true; } +#define EXIT(retval) { common_cleanup(init); return retval; } + int main(int argc, char *argv[]) { + struct init_data *init = nullptr; #if defined HAVE_SCHED_SETSCHEDULER && defined USE_RT struct sched_param sp; #endif @@ -721,9 +724,9 @@ int main(int argc, char *argv[]) } optind = 1; - if (!common_preinit(argc, argv)) { + if ((init = common_preinit(argc, argv)) == nullptr) { log_msg(LOG_LEVEL_FATAL, "common_preinit() failed!\n"); - return EXIT_FAILURE; + EXIT(EXIT_FAILURE); } struct state_uv uv{}; @@ -742,7 +745,7 @@ int main(int argc, char *argv[]) case 'd': if (strcmp(optarg, "help") == 0 || strcmp(optarg, "fullhelp") == 0) { list_video_display_devices(strcmp(optarg, "fullhelp") == 0); - return 0; + EXIT(0); } requested_display = optarg; if(strchr(optarg, ':')) { @@ -754,7 +757,7 @@ int main(int argc, char *argv[]) case 't': if (strcmp(optarg, "help") == 0 || strcmp(optarg, "fullhelp") == 0) { list_video_capture_devices(strcmp(optarg, "fullhelp") == 0); - return 0; + EXIT(0); } vidcap_params_set_device(vidcap_params_tail, optarg); vidcap_params_tail = vidcap_params_allocate_next(vidcap_params_tail); @@ -763,13 +766,13 @@ int main(int argc, char *argv[]) requested_mtu = atoi(optarg); if (requested_mtu < 576 && optarg[strlen(optarg) - 1] != '!') { log_msg(LOG_LEVEL_WARNING, "MTU %1$u seems to be too low, use \"%1$u!\" to force.\n", requested_mtu); - return EXIT_FAIL_USAGE; + EXIT(EXIT_FAIL_USAGE); } break; case 'M': decoder_mode = get_video_mode_from_str(optarg); if (decoder_mode == VIDEO_UNKNOWN) { - return strcasecmp(optarg, "help") == 0 ? EXIT_SUCCESS : EXIT_FAIL_USAGE; + EXIT(strcasecmp(optarg, "help") == 0 ? EXIT_SUCCESS : EXIT_FAIL_USAGE); } break; case 'p': @@ -777,11 +780,11 @@ int main(int argc, char *argv[]) break; case 'v': print_configuration(); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); case 'c': if (strcmp(optarg, "help") == 0 || strcmp(optarg, "fullhelp") == 0) { show_compress_help(strcmp(optarg, "fullhelp") == 0); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); } requested_compression = optarg; break; @@ -801,7 +804,7 @@ int main(int argc, char *argv[]) } if (strcmp(audio_protocol, "help") == 0) { printf("Audio protocol can be one of: " AUDIO_PROTOCOLS "\n"); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); } break; case OPT_VIDEO_PROTOCOL: @@ -818,7 +821,7 @@ int main(int argc, char *argv[]) cout << "Specify a " << style::bold << "common" << style::reset << " protocol for both audio and video.\n"; cout << "Audio protocol can be one of: " << style::bold << AUDIO_PROTOCOLS "\n" << style::reset; video_rxtx::list(strcmp(optarg, "fullhelp") == 0); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); } audio_protocol = video_protocol = optarg; if (strchr(optarg, ':')) { @@ -830,14 +833,14 @@ int main(int argc, char *argv[]) case 'r': if (strcmp(optarg, "help") == 0 || strcmp(optarg, "fullhelp") == 0) { audio_playback_help(strcmp(optarg, "full") == 0); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); } audio_recv = optarg; break; case 's': if (strcmp(optarg, "help") == 0 || strcmp(optarg, "fullhelp") == 0) { audio_capture_print_help(strcmp(optarg, "full") == 0); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); } audio_send = optarg; break; @@ -859,7 +862,7 @@ int main(int argc, char *argv[]) break; case 'h': usage(uv_argv[0], false); - return 0; + EXIT(0); case 'P': if(strchr(optarg, ':')) { char *save_ptr = NULL; @@ -872,7 +875,7 @@ int main(int argc, char *argv[]) audio_tx_port = atoi(tok); } else { usage(uv_argv[0]); - return EXIT_FAIL_USAGE; + EXIT(EXIT_FAIL_USAGE); } } } else { @@ -881,10 +884,10 @@ int main(int argc, char *argv[]) break; case 'l': if (!parse_bitrate(optarg, &bitrate)) { - return EXIT_FAILURE; + EXIT(EXIT_FAILURE); } if (bitrate == RATE_DEFAULT) { - return EXIT_SUCCESS; // help written + EXIT(EXIT_SUCCESS); // help written } break; case '4': @@ -903,12 +906,12 @@ int main(int argc, char *argv[]) audio_capture_channels = atoi(optarg); if (audio_capture_channels < 1 || audio_capture_channels > MAX_AUDIO_CAPTURE_CHANNELS) { log_msg(LOG_LEVEL_ERROR, "Invalid number of channels %d!\n", audio_capture_channels); - return EXIT_FAIL_USAGE; + EXIT(EXIT_FAIL_USAGE); } break; case OPT_AUDIO_CAPTURE_FORMAT: if (!parse_audio_capture_format(optarg)) { - return EXIT_FAIL_USAGE; + EXIT(EXIT_FAIL_USAGE); } break; case OPT_ECHO_CANCELLATION: @@ -916,7 +919,7 @@ int main(int argc, char *argv[]) break; case OPT_FULLHELP: usage(uv_argv[0], true); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); case OPT_CUDA_DEVICE: #ifdef HAVE_GPUJPEG if(strcmp("help", optarg) == 0) { @@ -926,9 +929,9 @@ int main(int argc, char *argv[]) if(ret == 0) { module_done(CAST_MODULE(compression)); } - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); } else { - return EXIT_FAILURE; + EXIT(EXIT_FAILURE); } } else { char *item, *save_ptr = NULL; @@ -936,7 +939,7 @@ int main(int argc, char *argv[]) while((item = strtok_r(optarg, ",", &save_ptr))) { if(i >= MAX_CUDA_DEVICES) { fprintf(stderr, "Maximal number of CUDA device exceeded.\n"); - return EXIT_FAILURE; + EXIT(EXIT_FAILURE); } cuda_devices[i] = atoi(item); optarg = NULL; @@ -947,7 +950,7 @@ int main(int argc, char *argv[]) break; #else fprintf(stderr, "CUDA support is not enabled!\n"); - return EXIT_FAIL_USAGE; + EXIT(EXIT_FAIL_USAGE); #endif // HAVE_CUDA case OPT_MCAST_IF: requested_mcast_if = optarg; @@ -965,7 +968,7 @@ int main(int argc, char *argv[]) char dev_string[1024]; int ret; if ((ret = playback_set_device(dev_string, sizeof dev_string, optarg)) <= 0) { - return ret == 0 ? EXIT_SUCCESS : EXIT_FAIL_USAGE; + EXIT(ret == 0 ? EXIT_SUCCESS : EXIT_FAIL_USAGE); } vidcap_params_set_device(vidcap_params_tail, dev_string); vidcap_params_tail = vidcap_params_allocate_next(vidcap_params_tail); @@ -974,11 +977,11 @@ int main(int argc, char *argv[]) case OPT_AUDIO_CODEC: if(strcmp(optarg, "help") == 0) { list_audio_codecs(); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); } audio_codec = optarg; if (!check_audio_codec(optarg)) { - return EXIT_FAIL_USAGE; + EXIT(EXIT_FAIL_USAGE); } break; case OPT_CAPTURE_FILTER: @@ -996,11 +999,11 @@ int main(int argc, char *argv[]) if(connection_type < 0 || connection_type > 1){ usage(uv_argv[0]); - return EXIT_FAIL_USAGE; + EXIT(EXIT_FAIL_USAGE); } if ((tok = strtok_r(NULL, ":", &save_ptr))) { usage(uv_argv[0]); - return EXIT_FAIL_USAGE; + EXIT(EXIT_FAIL_USAGE); } } else { control_port = atoi(optarg); @@ -1023,25 +1026,25 @@ int main(int argc, char *argv[]) break; case OPT_LIST_MODULES: list_all_modules(); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); case OPT_START_PAUSED: start_paused = true; break; case OPT_PARAM: if (!parse_params(optarg)) { - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); } break; case OPT_PIX_FMTS: print_pixel_formats(); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); case OPT_VIDEO_CODECS: print_video_codecs(); - return EXIT_SUCCESS; + EXIT(EXIT_SUCCESS); case '?': default: usage(uv_argv[0]); - return EXIT_FAIL_USAGE; + EXIT(EXIT_FAIL_USAGE); } } @@ -1051,7 +1054,7 @@ int main(int argc, char *argv[]) if (argc > 1) { log_msg(LOG_LEVEL_ERROR, "Multiple receivers given!\n"); usage(uv_argv[0]); - return EXIT_FAIL_USAGE; + EXIT(EXIT_FAIL_USAGE); } if (argc > 0) { @@ -1181,12 +1184,12 @@ int main(int argc, char *argv[]) exporter = export_init(&uv.root_module, export_opts, should_export); if (!exporter) { log_msg(LOG_LEVEL_ERROR, "Export initialization failed.\n"); - return EXIT_FAILURE; + EXIT(EXIT_FAILURE); } if (control_init(control_port, connection_type, &control, &uv.root_module, force_ip_version) != 0) { LOG(LOG_LEVEL_FATAL) << "Error: Unable to initialize remote control!\n"; - return EXIT_FAIL_CONTROL_SOCK; + EXIT(EXIT_FAIL_CONTROL_SOCK); } uv.audio = audio_cfg_init (&uv.root_module, audio_host, audio_rx_port, @@ -1461,6 +1464,8 @@ cleanup: signal(SIGABRT, SIG_IGN); signal(SIGSEGV, SIG_IGN); + common_cleanup(init); + printf("Exit\n"); return exit_status; diff --git a/src/video_capture/v4l2.c b/src/video_capture/v4l2.c index 1a2e3032c..c27a18e4b 100644 --- a/src/video_capture/v4l2.c +++ b/src/video_capture/v4l2.c @@ -113,7 +113,7 @@ static void enqueue_all_finished_frames(struct vidcap_v4l2_state *s) { } } -static void common_cleanup(struct vidcap_v4l2_state *s) { +static void vidcap_v4l2_common_cleanup(struct vidcap_v4l2_state *s) { if (!s) { return; } @@ -759,7 +759,7 @@ static int vidcap_v4l2_init(struct vidcap_params *params, void **state) error: free(tmp); - common_cleanup(s); + vidcap_v4l2_common_cleanup(s); return VIDCAP_INIT_FAIL; } @@ -768,7 +768,7 @@ static void vidcap_v4l2_done(void *state) { struct vidcap_v4l2_state *s = (struct vidcap_v4l2_state *) state; - common_cleanup(s); + vidcap_v4l2_common_cleanup(s); } static void vidcap_v4l2_dispose_video_frame(struct video_frame *frame) {