diff --git a/.gitignore b/.gitignore index 42308c2f..e2f5feb2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.orig *.bak *.o +*tags # Binaries dev_mngr diff --git a/.travis.yml b/.travis.yml index b842fcde..46911716 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,7 +50,7 @@ before_deploy: deploy: provider: releases api_key: - secure: "TMHoQQwZ4eHnnzfxoDEV15igEFpaVyYWVTN/Q583PtF15CLkbQpfEWDDgKZTMiUbuoeI3X+WPMb2F713wBB6MQ+yVKkRDfHKyIbpTWmwIht5isBnn8+eXuV53X1PzAPJXmzrbos5X3FNExV7eJqf1sldxiVmPyLKMssM+X4wG3+GIHPjxYd1dp/9v9d1uj2DZe1iApDezUxi2Oz3fdVZyx1O8KgyAoQ8uqXc3WDykGNXsJKJGMSFtpTGCyMI6etPZJRA0pn+zrGViYzsZnpv55whzAXGxXWsmo5OT6HvjrjKtiDDSyKLuNM7kqC3MoeYZ+2XGoYycoVMAlPdUKqMqrM/UVJ4ltYsJVb1ROSRpFmK17dEtZwQWLxNPkww/ixZeGFP47UUgdET+8ZDkvNC6ZM0VoMBvvoTKzrotQdM83DqDiGTyXDmgwWXzoqze02iYrV8UdmaX4JEvhMDJJGowzVipHy/VvPO6wRj5v8Achy6ntENM0wPYfQjanM+0pGJvsSHo/rZTP+OWOLtILKtcW7c3jMY/jlNq7jLc/WGEj3GZfUqgx8wN0ldCG0jO0n7OlZtmV5qUkqMNB3WunkFYEujaaCobTDScIjVx10UcXfUYT/iPmZr0Pt/8yBNyPHAORfStKNbVhgwzRZtDKzYKxaU9z2G6gAY9cFAViA8P3U=" + secure: "ammPjSoAPm1RFwXJq2O4JSBHrtOlf/2LNtdB462IpCRek4p9EY/jFEoMhRnYlXWrRdYC0EAk/GSAtCLC7u22G66pACezg1Q0xJdfFSMwo7MWcU2ukSeRoFugw09OuB6E/LZ6NcDVYxXVhht/qqV4Em1N3H/rc+0qkEHUPg1YxjB/YIayuY+LsBQsXXiBBc0NVhNv3L1Lx7uKzvwPnsDtIDSbd8cLmWs3XiHnjbcshhZynHiV3I3eQD0hvCKQ3pK2TItcY7BPPGZbQI6UhVEsjcqDQov2sdw1VhVFSwqlPnpGvLJgvvMBDbdfQfMVdYui0eaSLB52+ZC3HyrQxAJotz43OAZEWzrShts548M2xZDklUhFRu9KovDC8pYNJU+pwumpela9pW3YSBroRwxtfEyeplCaaR0iT0rL9CdQBVRKhmwbVwPsUCKQ1/fngbFRJbSksFf6GXCiykbjkwkPXRdrwdZpff0sUjKmapH1iFBQIQ5k92k7qfd+MFoTgCKovpMWVMpYcBLGK0rxJIZy5gjvuJLX5NwGs+rdDO/oFVVDxXWldcaqDetFYhVZVVKkewdaTDDQb1Pr7FeP8iI6t+JwtsmVjFbrjBs5siN/YhHRzu6Jm0taL7NnktYEXKumlLS0Nn9sQWhKlC86R2pJGKF9+iuweIN1JBaw0y4ScHM=" file_glob: true file: ${HALCS_DEPLOYMENT} skip_cleanup: true diff --git a/Makefile b/Makefile index 82d12bf0..c4dc3686 100644 --- a/Makefile +++ b/Makefile @@ -192,9 +192,11 @@ LIBS = -lm -lzmq -lczmq -lmlm # FIXME: make the project libraries easily interchangeable, specifying # the lib only a single time PROJECT_LIBS_NAME = liberrhand libconvc libhutils libdisptable libllio libhalcsclient \ - libacqclient libbpmclient libsdbutils libsdbfs libpcidriver + libacqclient libbpmclient libsdbutils libsdbfs libpcidriver \ + libpthread PROJECT_LIBS = -lerrhand -lconvc -lhutils -ldisptable -lllio -lhalcsclient \ - -lacqclient -lbpmclient -lsdbutils -lsdbfs -lpcidriver + -lacqclient -lbpmclient -lsdbutils -lsdbfs -lpcidriver \ + -lpthread # General library flags -L LFLAGS = -Lforeign/libsdbfs diff --git a/apps/halcsd/build.gradle b/apps/halcsd/build.gradle index 29839f59..f325f584 100644 --- a/apps/halcsd/build.gradle +++ b/apps/halcsd/build.gradle @@ -32,7 +32,7 @@ model { binaries.all { cCompiler.define '__AFE_RFFE_V2__' - linker.args '-lczmq', '-lpcidriver', '-lmlm' + linker.args '-lczmq', '-lpcidriver', '-lmlm', '-lpthread' } } @@ -64,7 +64,7 @@ model { binaries.all { cCompiler.define '__AFE_RFFE_V2__' - linker.args '-lczmq', '-lpcidriver', '-lmlm' + linker.args '-lczmq', '-lpcidriver', '-lmlm', '-lpthread' } } diff --git a/apps/halcsd/src/halcsd/c/halcsd.c b/apps/halcsd/src/halcsd/c/halcsd.c index d32f1b9d..97744a24 100644 --- a/apps/halcsd/src/halcsd/c/halcsd.c +++ b/apps/halcsd/src/halcsd/c/halcsd.c @@ -136,6 +136,18 @@ int main (int argc, char *argv[]) char *cfg_file = NULL; int opt; + /* Block signals in all of the threads, if not otherwise stated */ + static sigset_t signal_mask; + sigemptyset (&signal_mask); + sigaddset (&signal_mask, SIGUSR1); + sigaddset (&signal_mask, SIGUSR2); + sigaddset (&signal_mask, SIGHUP); + int rc = pthread_sigmask (SIG_BLOCK, &signal_mask, NULL); + if (rc != 0) { + DBE_DEBUG (DBG_DEV_IO | DBG_LVL_FATAL, "[halcsd] Could not block sigmask: %d\n", rc); + goto err_sigmask; + } + while ((opt = getopt_long (argc, argv, shortopt, long_options, NULL)) != -1) { /* Get the user selected options */ switch (opt) { @@ -645,6 +657,7 @@ int main (int argc, char *argv[]) zhashx_destroy (&devio_hints); err_devio_hints_alloc: err_cfg_not_found: +err_sigmask: DBE_DEBUG (DBG_DEV_IO | DBG_LVL_INFO, "[halcsd] Exiting ...\n"); return 0; } diff --git a/apps/halcsd/src/halcsd_cfg/c/halcsd_cfg.c b/apps/halcsd/src/halcsd_cfg/c/halcsd_cfg.c index 05d30770..f4053152 100644 --- a/apps/halcsd/src/halcsd_cfg/c/halcsd_cfg.c +++ b/apps/halcsd/src/halcsd_cfg/c/halcsd_cfg.c @@ -65,6 +65,18 @@ int main (int argc, char *argv[]) char *log_filename = NULL; int opt; + /* Block signals in all of the threads, if not otherwise stated */ + static sigset_t signal_mask; + sigemptyset (&signal_mask); + sigaddset (&signal_mask, SIGUSR1); + sigaddset (&signal_mask, SIGUSR2); + sigaddset (&signal_mask, SIGHUP); + int rc = pthread_sigmask (SIG_BLOCK, &signal_mask, NULL); + if (rc != 0) { + DBE_DEBUG (DBG_DEV_IO | DBG_LVL_FATAL, "[halcsd_cfg] Could not block sigmask: %d\n", rc); + goto err_sigmask; + } + while ((opt = getopt_long (argc, argv, shortopt, long_options, NULL)) != -1) { /* Get the user selected options */ switch (opt) { @@ -266,6 +278,7 @@ int main (int argc, char *argv[]) free (dev_type); free (devio_type_str); free (devio_work_dir); +err_sigmask: DBE_DEBUG (DBG_DEV_IO | DBG_LVL_INFO, "[halcsd_cfg] Exiting ...\n"); return 0; } diff --git a/core/common/include/chips/ad9510_regs.h b/core/common/include/chips/ad9510_regs.h index 003653f8..c04b774f 100644 --- a/core/common/include/chips/ad9510_regs.h +++ b/core/common/include/chips/ad9510_regs.h @@ -293,7 +293,7 @@ #define AD9510_PLL_R_COUNTER_R(reg) WBGEN2_GEN_READ(reg, AD9510_PLL_R_COUNTER_SHIFT, \ AD9510_PLL_R_COUNTER_SIZE) -#define AD9510_REG_PLL_5 0x0A +#define AD9510_REG_PLL_5 0x0D /* Definition for register AD9510_REG_PLL_5 */ #define AD9510_PLL_5_ANTI_BL_PW_SIZE 2 diff --git a/core/common/include/halcs_server_prelude.h b/core/common/include/halcs_server_prelude.h index e7d2a41d..07d23b11 100644 --- a/core/common/include/halcs_server_prelude.h +++ b/core/common/include/halcs_server_prelude.h @@ -16,6 +16,7 @@ #include #include #include +#include /* zeroMQ libraries */ #include diff --git a/core/dev_io/src/dev_io/c/dev_io_core.c b/core/dev_io/src/dev_io/c/dev_io_core.c index f7d6cb49..6c0387d3 100644 --- a/core/dev_io/src/dev_io/c/dev_io_core.c +++ b/core/dev_io/src/dev_io/c/dev_io_core.c @@ -41,6 +41,8 @@ #define DEVIO_MAX_DESTRUCT_MSG_TRIES 10 #define DEVIO_LINGER_TIME 100 /* in ms */ +#define DEVIO_DFLT_MONITOR_INTERVAL 1000 /* /n ms */ + struct _devio_t { /* General information */ zactor_t **pipes_mgmt; /* Address nodes using this array of actors (Management PIPES) */ @@ -117,6 +119,11 @@ static devio_err_e _devio_engine_handle_socket (devio_t *devio, void *sock, zloop_reader_fn handler); static int _devio_handle_pipe_backend (zloop_t *loop, zsock_t *reader, void *args); +/* Handle monitors */ +static int _devio_engine_set_monitor (devio_t *devio, size_t interval, + zloop_timer_fn monitor); +static devio_err_e _devio_engine_cancel_monitor (devio_t* devio, int identifier); + /* Utilities */ static zactor_t *_devio_get_pipe_from_smio_id (devio_t *self, uint32_t smio_id, uint32_t inst_id); @@ -178,6 +185,10 @@ devio_t * devio_new (char *name, uint32_t id, char *endpoint_dev, assert (reg_ops); assert (endpoint_broker); + /* Just satisfy compilers that complain for unused functions */ + _devio_engine_set_monitor (NULL, 0, NULL); + _devio_engine_cancel_monitor (NULL, 0); + /* Set logfile available for all dev_mngr and dev_io instances. * We accept NULL as a parameter, meaning to suppress all messages */ errhand_log_new (log_file_name, DEVIO_DFLT_LOG_MODE); @@ -260,10 +271,12 @@ devio_t * devio_new (char *name, uint32_t id, char *endpoint_dev, _devio_set_spawn_clhd_handler (self, &hutils_spawn_chld); devio_err_e derr = devio_set_sig_handler (self, &devio_sigchld_handler); - ASSERT_TEST(derr==DEVIO_SUCCESS, "Error setting signal handlers", err_set_sig_handlers); + ASSERT_TEST(derr==DEVIO_SUCCESS, "Error setting SIGCHLD signal handlers", + err_set_sig_handlers); derr = _devio_register_sig_handlers (self); - ASSERT_TEST(derr==DEVIO_SUCCESS, "Error registering setting up signal handlers", err_sig_handlers); + ASSERT_TEST(derr==DEVIO_SUCCESS, "Error registering setting up signal handlers", + err_sig_handlers); /* Concatenate recv'ed name with a llio identifier */ size_t llio_name_len = sizeof (char)*(strlen(name)+strlen(LLIO_STR)+1); @@ -554,6 +567,45 @@ static devio_err_e _devio_engine_handle_socket (devio_t *devio, void *sock, return err; } +/* From Malamute https://github.com/zeromq/malamute/blob/master/src/mlm_server_engine.inc + * + * Register monitor function that will be called at regular intervals + * by the server engine. Returns an identifier that can be used to cancel it. */ + +static int _devio_engine_set_monitor (devio_t *devio, size_t interval, + zloop_timer_fn monitor) +{ + int err = -1; + + if (devio) { + devio_t *self = (devio_t *) devio; + err = zloop_timer (self->loop, interval, 0, monitor, self); + ASSERT_TEST(err >= 0, "Could not register zloop_timer", + err_zloop_timer, -1); + } + +err_zloop_timer: + return err; +} + +/* From Malamute https://github.com/zeromq/malamute/blob/master/src/mlm_server_engine.inc + * + * Cancel the monitor function with the given identifier. */ +static devio_err_e _devio_engine_cancel_monitor (devio_t* devio, int identifier) +{ + int err = -1; + + if (devio) { + devio_t *self = (devio_t *) devio; + err = zloop_timer_end (self->loop, identifier); + ASSERT_TEST(err >= 0, "Could not deregister zloop_timer", + err_zloop_timer, -1); + } + +err_zloop_timer: + return err; +} + /************************************************************/ /********************** zloop handlers **********************/ /************************************************************/ @@ -832,6 +884,10 @@ static int _devio_handle_pipe_backend (zloop_t *loop, zsock_t *reader, void *arg return 0; } +/************************************************************/ +/********************* zmonitor handlers ********************/ +/************************************************************/ + /************************************************************/ /********************** PIPE methods ************************/ /************************************************************/ @@ -852,9 +908,6 @@ static zactor_t *_devio_get_pipe_from_smio_id (devio_t *self, uint32_t smio_id, char *smio_key = _devio_gen_smio_key (self, smio_mod_handler, inst_id); ASSERT_ALLOC (smio_key, err_key_alloc); - DBE_DEBUG (DBG_SM_IO | DBG_LVL_ERR, - "_devio_get_pipe_from_smio_id: smio_key %s\n", smio_key); - /* Finally, do the lookup */ smio_actor_p = (zactor_t **) zhashx_lookup (self->sm_io_h, smio_key); ASSERT_TEST (smio_actor_p != NULL, "Could not find SMIO PIPE from SMIO ID", @@ -1479,6 +1532,46 @@ static devio_err_e _devio_check_send_cfg_done (devio_t *self) return err; } +/* Signal actor to catch signals block by every other + * thread, but this one */ +void signal_actor (zsock_t *pipe, void *args) +{ + /* Initialize */ + devio_t *self = (devio_t *) args; + + /* Tell parent we are initializing */ + zsock_signal (pipe, 0); + + sigset_t sig_mask; + sigemptyset (&sig_mask); + sigaddset (&sig_mask, SIGUSR1); + sigaddset (&sig_mask, SIGUSR2); + sigaddset (&sig_mask, SIGHUP); + + int sig_caught; + + while (!zsys_interrupted) { + sigwait (&sig_mask, &sig_caught); + switch (sig_caught) + { + /* Reopen Logs */ + case SIGUSR1: + DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io] Caught SIGUSR1!\n"); + errhand_reallog_destroy (); + errhand_log_new (self->log_file, DEVIO_DFLT_LOG_MODE); + break; + /* Undefined */ + case SIGUSR2: + DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io] Caught SIGUSR2!\n"); + break; + /* Undefined */ + case SIGHUP: + DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io] Caught SIGHUP!\n"); + break; + } + } +} + /* Main devio loop implemented as actor */ void devio_loop (zsock_t *pipe, void *args) { @@ -1488,12 +1581,23 @@ void devio_loop (zsock_t *pipe, void *args) devio_t *self = (devio_t *) args; self->pipe = pipe; + /* Unblock signals for this thread only. We can't use the regular + * signal handlers as all thread will inherit and we want only + * this thread to treat them */ + sigset_t signal_mask; + sigemptyset (&signal_mask); + pthread_sigmask (SIG_UNBLOCK, &signal_mask, NULL); + /* Tell parent we are initializing */ zsock_signal (pipe, 0); /* Set-up server register commands handler */ _devio_engine_handle_socket (self, pipe, _devio_handle_pipe); + /* Initialize signal handlers for specific signals */ + zactor_t *server = zactor_new (signal_actor, self); + UNUSED(server); + /* Run reactor until there's a termination signal */ zloop_start (self->loop); } @@ -1529,6 +1633,11 @@ llio_t *devio_get_llio (devio_t *self) return self->llio; } +/* Register signal handlers for specified signals. Bear in mind that you can't, + * by default register handlers for SIGINT/SIGTERM as they are automatically + * managed by CZMQ library. If needed, you can call zsys_handler_set () and CZMQ + * will disable its signal handling for those signals, but zctx_interrupt and + * zsys_interrupt will not work as expected anymore. */ devio_err_e devio_set_sig_handler (devio_t *self, devio_sig_handler_t *sig_handler) { assert (self); @@ -1554,7 +1663,7 @@ static devio_err_e _devio_register_sig_handlers (devio_t *self) int err = sigaction (sig_handler->signal, &act, NULL); CHECK_ERR(err, DEVIO_ERR_SIGACTION); - DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_INFO, "[dev_mngr_core] registered signal %d\n", + DBE_DEBUG (DBG_DEV_IO | DBG_LVL_INFO, "[dev_io_core] registered signal %d\n", sig_handler->signal); sig_handler = (devio_sig_handler_t *) diff --git a/core/dev_mngr/src/dev_mngr/c/dev_mngr.c b/core/dev_mngr/src/dev_mngr/c/dev_mngr.c index c3da1c2b..cf03d593 100644 --- a/core/dev_mngr/src/dev_mngr/c/dev_mngr.c +++ b/core/dev_mngr/src/dev_mngr/c/dev_mngr.c @@ -65,6 +65,18 @@ int main (int argc, char *argv[]) char *cfg_file = NULL; int opt; + /* Block signals in all of the threads, if not otherwise stated */ + static sigset_t signal_mask; + sigemptyset (&signal_mask); + sigaddset (&signal_mask, SIGUSR1); + sigaddset (&signal_mask, SIGUSR2); + sigaddset (&signal_mask, SIGHUP); + int rc = pthread_sigmask (SIG_BLOCK, &signal_mask, NULL); + if (rc != 0) { + DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_FATAL, "[halcsd_cfg] Could not block sigmask: %d\n", rc); + goto err_sigmask; + } + while ((opt = getopt_long (argc, argv, shortopt, long_options, NULL)) != -1) { /* Get the user selected options */ switch (opt) { @@ -379,6 +391,7 @@ int main (int argc, char *argv[]) err_dmngr_hints_alloc: free (cfg_file); err_parse_cfg: +err_sigmask: DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_INFO, "[dev_mngr] Exiting ...\n"); return 0; diff --git a/foreign/libsdbfs/tools/sdb-read-lnls.c b/foreign/libsdbfs/tools/sdb-read-lnls.c index 24a5b22f..ac1be0e4 100644 --- a/foreign/libsdbfs/tools/sdb-read-lnls.c +++ b/foreign/libsdbfs/tools/sdb-read-lnls.c @@ -39,7 +39,7 @@ static void help(void) } struct sdbr_drvdata { - llio_t *llio; + llio_t *llio; }; /* @@ -287,7 +287,7 @@ int main(int argc, char **argv) fs->name = fsname; /* not mandatory */ fs->blocksize = 256; /* only used for writing, actually */ fs->entrypoint = opt_entry; - fs->read = do_read; + fs->read = do_read; if (opt_verbose) fs->flags |= SDBFS_F_VERBOSE; @@ -307,8 +307,9 @@ int main(int argc, char **argv) else err = do_cat_id(fs, int64, int32); - llio_destroy(&((struct sdbr_drvdata *)fs->drvdata)->llio); - free(fs->drvdata); + llio_release(((struct sdbr_drvdata *)fs->drvdata)->llio, NULL); + llio_destroy(&((struct sdbr_drvdata *)fs->drvdata)->llio); + free(fs->drvdata); sdbfs_dev_destroy(fs); return err; } diff --git a/libs/errhand/include/errhand_print.h b/libs/errhand/include/errhand_print.h index a072ecda..b289ce62 100644 --- a/libs/errhand/include/errhand_print.h +++ b/libs/errhand/include/errhand_print.h @@ -28,6 +28,7 @@ int errhand_log_new (const char *log_file_name, const char *mode); void errhand_log_file_destroy (); int errhand_log_destroy (); void errhand_log_print_zmq_msg (struct _zmsg_t *msg); +void errhand_reallog_destroy (); /********************** Error handling macros **********************/ diff --git a/libs/errhand/src/errhand/c/errhand_print.c b/libs/errhand/src/errhand/c/errhand_print.c index d572962e..fc194c80 100644 --- a/libs/errhand/src/errhand/c/errhand_print.c +++ b/libs/errhand/src/errhand/c/errhand_print.c @@ -11,8 +11,21 @@ #define ERRHAND_DATE_LENGTH 20 #define ERRHAND_TEXT_LENGTH 1024 +/* TODO: We should not be using mutexes really. The correct + * design is probably to create a socket to send/recv + * messages from all the threads and treat them accordingly */ +typedef pthread_mutex_t errhand_mutex_t; + +#define ERRHAND_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#define ERRHAND_MUTEX_INIT(m) pthread_mutex_init (&m, NULL); +#define ERRHAND_MUTEX_LOCK(m) pthread_mutex_lock (&m); +#define ERRHAND_MUTEX_UNLOCK(m) pthread_mutex_unlock (&m); +#define ERRHAND_MUTEX_DESTROY(m) pthread_mutex_destroy (&m); + /* Our logfile */ static FILE *_errhand_logfile = NULL; +/* Mutex to guard out logfile handler */ +static errhand_mutex_t _logfile_mutex = ERRHAND_MUTEX_INITIALIZER; void errhand_print (const char *fmt, ...) { @@ -24,14 +37,10 @@ void errhand_print (const char *fmt, ...) } /* Based on CZMQ s_log () function. Available in - * https://github.com/zeromq/czmq/blob/master/src/zsys.c */ + * https://github.com/zeromq/czmq/blob/master/src/zsys.c. + * Must be called with the mutex held */ static void _errhand_log_write (char *errhand_lvl_str, char *msg, bool verbose) { - /* Default to stdout */ - if (!_errhand_logfile) { - _errhand_logfile = stdout; - } - time_t curtime = time (NULL); struct tm *loctime = localtime (&curtime); char date [ERRHAND_DATE_LENGTH]; @@ -46,8 +55,16 @@ static void _errhand_log_write (char *errhand_lvl_str, char *msg, bool verbose) snprintf (log_text, ERRHAND_TEXT_LENGTH, "%s", msg); } - fprintf (_errhand_logfile, "%s", log_text); - fflush (_errhand_logfile); + ERRHAND_MUTEX_LOCK(_logfile_mutex); + /* Only open/close functions should modify global _errhand_logfile */ + FILE *local_errhand_logfile = _errhand_logfile; + /* Default to stdout */ + if (!local_errhand_logfile) { + local_errhand_logfile = stdout; + } + fprintf (local_errhand_logfile, "%s", log_text); + fflush (local_errhand_logfile); + ERRHAND_MUTEX_UNLOCK(_logfile_mutex); } /* Based on CZMQ zsys_error () function. Available in @@ -71,12 +88,16 @@ void errhand_log_print (int errhand_lvl, const char *fmt, ...) void errhand_log_print_zmq_msg (zmsg_t *msg) { + ERRHAND_MUTEX_LOCK(_logfile_mutex); + /* Only open/close functions should modify global _errhand_logfile */ + FILE *local_errhand_logfile = _errhand_logfile; /* Default to stdout */ - if (!_errhand_logfile) { - _errhand_logfile = stdout; + if (!local_errhand_logfile) { + local_errhand_logfile = stdout; } - errhand_lprint_zmq_msg (msg, _errhand_logfile); + errhand_lprint_zmq_msg (msg, local_errhand_logfile); + ERRHAND_MUTEX_UNLOCK(_logfile_mutex); } void errhand_print_vec (const char *fmt, const char *data, int len) @@ -148,21 +169,42 @@ void errhand_log_file_destroy () int errhand_log_new (const char *log_file_name, const char *mode) { + ERRHAND_MUTEX_LOCK(_logfile_mutex); int err = 0; - FILE *log_file = errhand_log_open (log_file_name, mode); + /* Only one file can be opened */ + if (_errhand_logfile) { + goto exit; + } + FILE *log_file = errhand_log_open (log_file_name, mode); _errhand_log_file_new (log_file); + + /* So we can be safe handlers will be safely destroyed */ + atexit (errhand_reallog_destroy); + +exit: + ERRHAND_MUTEX_UNLOCK(_logfile_mutex); return err; } +/* Dummy function provided just for compatibility */ int errhand_log_destroy () { -#if 0 - int err = -1; + return 0; +} + +/* Must only be called when absolutely sure no one is using + * the logfile */ +void errhand_reallog_destroy () +{ + ERRHAND_MUTEX_LOCK(_logfile_mutex); + if (!_errhand_logfile) { + goto exit; + } - err = errhand_log_close (_errhand_logfile); + errhand_log_close (_errhand_logfile); _errhand_log_file_destroy(); - return err; -#endif - return 0; + +exit: + ERRHAND_MUTEX_UNLOCK(_logfile_mutex); }