summaryrefslogtreecommitdiff
path: root/src/lib/dlt_user.c
diff options
context:
space:
mode:
authorStefan Vacek <stefan.vacek@intel.com>2015-08-26 14:05:54 +0200
committerAlexander Wenzel <Alexander.AW.Wenzel@bmw.de>2015-10-07 10:35:25 +0200
commit2f334a851fa1b39cab74724f3d0a0565f86c27b4 (patch)
tree932d06d33fdfcbde8dc439880ecf93af191115dc /src/lib/dlt_user.c
parent133a8bd48b42bb4714ad4472c89277db6dd4f88d (diff)
downloadDLT-daemon-2f334a851fa1b39cab74724f3d0a0565f86c27b4.tar.gz
Allow applications to fork()
- if fork() is called from an application, dlt is reset and user application needs to re-register application and contexts in child-process Signed-off-by: Stefan Vacek <stefan.vacek@intel.com>
Diffstat (limited to 'src/lib/dlt_user.c')
-rw-r--r--src/lib/dlt_user.c220
1 files changed, 172 insertions, 48 deletions
diff --git a/src/lib/dlt_user.c b/src/lib/dlt_user.c
index 28c7381..e1f46ca 100644
--- a/src/lib/dlt_user.c
+++ b/src/lib/dlt_user.c
@@ -68,7 +68,9 @@ static char str[DLT_USER_BUFFER_LENGTH];
static sem_t dlt_mutex;
static pthread_t dlt_receiverthread_handle;
-static pthread_attr_t dlt_receiverthread_attr;
+
+// calling dlt_user_atexit_handler() second time fails with error message
+static int atexit_registered = 0;
/* Segmented Network Trace */
#define DLT_MAX_TRACE_SEGMENT_SIZE 1024
@@ -79,6 +81,26 @@ static pthread_attr_t dlt_receiverthread_attr;
pthread_mutex_t mq_mutex;
pthread_cond_t mq_init_condition;
+void dlt_lock_mutex(pthread_mutex_t *mutex)
+{
+ int32_t lock_mutex_result = pthread_mutex_lock(mutex);
+ if (lock_mutex_result == EOWNERDEAD)
+ {
+ pthread_mutex_consistent(mutex);
+ lock_mutex_result = 0;
+ }
+ else if ( lock_mutex_result != 0 )
+ {
+ snprintf(str,DLT_USER_BUFFER_LENGTH, "Mutex lock failed unexpected pid=%i with result %i!\n", getpid(), lock_mutex_result);
+ dlt_log(LOG_ERR, str);
+ }
+}
+
+inline void dlt_unlock_mutex(pthread_mutex_t *mutex)
+{
+ pthread_mutex_unlock(mutex);
+}
+
/* Structure to pass data to segmented thread */
typedef struct {
DltContext *handle;
@@ -110,6 +132,13 @@ static void dlt_user_trace_network_segmented_thread(void *unused);
static void dlt_user_trace_network_segmented_thread_segmenter(s_segmented_data *data);
static int dlt_user_queue_resend(void);
+static int dlt_start_threads();
+static void dlt_stop_threads();
+static void dlt_fork_pre_fork_handler();
+static void dlt_fork_parent_fork_handler();
+static void dlt_fork_child_fork_handler();
+
+
int dlt_user_check_library_version(const char *user_major_version,const char *user_minor_version){
char str[DLT_USER_BUFFER_LENGTH];
@@ -249,44 +278,38 @@ int dlt_init(void)
return -1;
}
- /* Start receiver thread */
- if (pthread_create(&(dlt_receiverthread_handle),
- 0,
- (void *) &dlt_user_receiverthread_function,
- 0)!=0)
- {
- if (pthread_attr_destroy(&dlt_receiverthread_attr)!=0)
- {
- dlt_log(LOG_WARNING, "Can't destroy thread attributes!\n");
- }
-
- dlt_log(LOG_CRIT, "Can't create receiver thread!\n");
- dlt_user_initialised = 0;
- return -1;
- }
-
- if (pthread_attr_destroy(&dlt_receiverthread_attr)!=0)
- {
- dlt_log(LOG_WARNING, "Can't destroy thread attributes!\n");
- }
-
/* These will be lazy initialized only when needed */
dlt_user.dlt_segmented_queue_read_handle = -1;
dlt_user.dlt_segmented_queue_write_handle = -1;
/* Wait mutext for segmented thread */
- pthread_mutex_init(&mq_mutex, NULL);
+ pthread_mutexattr_t attr;
+ if (pthread_mutexattr_init(&attr) != 0)
+ {
+ dlt_user_initialised = 0;
+ return -1;
+ }
+ /* make mutex robust to prevent from deadlock when the segmented thread was cancelled, but held the mutex */
+ if ( pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST) != 0 )
+ {
+ dlt_user_initialised = 0;
+ return -1;
+ }
+
+ pthread_mutex_init(&mq_mutex, &attr);
+ pthread_mutexattr_destroy(&attr);
pthread_cond_init(&mq_init_condition, NULL);
- /* Start the segmented thread */
- if(pthread_create(&(dlt_user.dlt_segmented_nwt_handle), NULL,
- (void *)dlt_user_trace_network_segmented_thread, NULL))
+ if (dlt_start_threads() < 0)
{
- dlt_log(LOG_CRIT, "Can't start segmented thread!\n");
- return -1;
+ dlt_user_initialised = 0;
+ return -1;
}
- return 0;
+ // prepare for fork() call
+ pthread_atfork(&dlt_fork_pre_fork_handler, &dlt_fork_parent_fork_handler, &dlt_fork_child_fork_handler);
+
+ return 0;
}
int dlt_init_file(const char *name)
@@ -316,12 +339,12 @@ int dlt_init_file(const char *name)
int dlt_init_message_queue(void)
{
- pthread_mutex_lock(&mq_mutex);
+ dlt_lock_mutex(&mq_mutex);
if(dlt_user.dlt_segmented_queue_read_handle >= 0 &&
dlt_user.dlt_segmented_queue_write_handle >= 0)
{
// Already intialized
- pthread_mutex_unlock(&mq_mutex);
+ dlt_unlock_mutex(&mq_mutex);
return 0;
}
@@ -364,7 +387,7 @@ int dlt_init_message_queue(void)
char str[256];
snprintf(str,255,"Can't create message queue read handle!: %s \n",strerror(errno));
dlt_log(LOG_CRIT, str);
- pthread_mutex_unlock(&mq_mutex);
+ dlt_unlock_mutex(&mq_mutex);
return -1;
}
}
@@ -376,12 +399,12 @@ int dlt_init_message_queue(void)
char str[256];
snprintf(str,255,"Can't open message queue write handle!: %s \n",strerror(errno));
dlt_log(LOG_CRIT, str);
- pthread_mutex_unlock(&mq_mutex);
+ dlt_unlock_mutex(&mq_mutex);
return -1;
}
pthread_cond_signal(&mq_init_condition);
- pthread_mutex_unlock(&mq_mutex);
+ dlt_unlock_mutex(&mq_mutex);
return 0;
}
@@ -460,7 +483,11 @@ int dlt_init_common(void)
signal(SIGPIPE,SIG_IGN); /* ignore pipe signals */
- atexit(dlt_user_atexit_handler);
+ if (atexit_registered == 0)
+ {
+ atexit(dlt_user_atexit_handler);
+ atexit_registered = 1;
+ }
#ifdef DLT_TEST_ENABLE
dlt_user.corrupt_user_header = 0;
@@ -570,16 +597,7 @@ int dlt_free(void)
}
dlt_user_initialised = 0;
- if (dlt_receiverthread_handle)
- {
- /* Ignore return value */
- pthread_cancel(dlt_receiverthread_handle);
- }
-
- if (dlt_user.dlt_segmented_nwt_handle)
- {
- pthread_cancel(dlt_user.dlt_segmented_nwt_handle);
- }
+ dlt_stop_threads();
if (dlt_user.dlt_user_handle!=DLT_FD_INIT)
{
@@ -643,8 +661,14 @@ int dlt_free(void)
*/
mq_close(dlt_user.dlt_segmented_queue_write_handle);
mq_close(dlt_user.dlt_segmented_queue_read_handle);
+ dlt_user.dlt_segmented_queue_write_handle = -1;
+ dlt_user.dlt_segmented_queue_read_handle = -1;
mq_unlink(queue_name);
+ pthread_cond_destroy(&mq_init_condition);
+ pthread_mutex_destroy(&mq_mutex);
+ sem_destroy(&dlt_mutex);
+
// allow the user app to do dlt_init() again.
// The flag is unset only to keep almost the same behaviour as before, on EntryNav
// This should be removed for other projects (see documentation of dlt_free()
@@ -2541,12 +2565,12 @@ void dlt_user_trace_network_segmented_thread(void *unused)
while(1)
{
// Wait until message queue is initialized
- pthread_mutex_lock(&mq_mutex);
+ dlt_lock_mutex(&mq_mutex);
if(dlt_user.dlt_segmented_queue_read_handle < 0)
{
pthread_cond_wait(&mq_init_condition, &mq_mutex);
}
- pthread_mutex_unlock(&mq_mutex);
+ dlt_unlock_mutex(&mq_mutex);
ssize_t read = mq_receive(dlt_user.dlt_segmented_queue_read_handle, (char *)&data,
sizeof(s_segmented_data * ), NULL);
@@ -3646,7 +3670,7 @@ int dlt_user_log_send_register_context(DltContextData *log)
{
DltUserHeader userheader;
DltUserControlMsgRegisterContext usercontext;
- DltReturnValue ret;
+ DltReturnValue ret = 0;
if (log==0)
{
@@ -4323,3 +4347,103 @@ void dlt_user_test_corrupt_message_size(int enable,int16_t size)
#endif
+int dlt_start_threads()
+{
+ /* Start receiver thread */
+ if (pthread_create(&(dlt_receiverthread_handle),
+ 0,
+ (void *) &dlt_user_receiverthread_function,
+ 0)!=0)
+ {
+ dlt_log(LOG_CRIT, "Can't create receiver thread!\n");
+ return -1;
+ }
+
+ /* Start the segmented thread */
+ if (pthread_create(&(dlt_user.dlt_segmented_nwt_handle), NULL,
+ (void *)dlt_user_trace_network_segmented_thread, NULL))
+ {
+ dlt_log(LOG_CRIT, "Can't start segmented thread!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void dlt_stop_threads()
+{
+ int dlt_receiverthread_result = 0;
+ int dlt_segmented_nwt_result = 0;
+ if (dlt_receiverthread_handle)
+ {
+ /* do not ignore return value */
+ dlt_receiverthread_result = pthread_cancel(dlt_receiverthread_handle);
+ if (dlt_receiverthread_result != 0)
+ {
+ snprintf(str,DLT_USER_BUFFER_LENGTH, "ERROR pthread_cancel(dlt_receiverthread_handle): %s\n", strerror(errno));
+ dlt_log(LOG_ERR, str);
+ }
+ }
+
+ if (dlt_user.dlt_segmented_nwt_handle)
+ {
+ dlt_segmented_nwt_result = pthread_cancel(dlt_user.dlt_segmented_nwt_handle);
+ if (dlt_segmented_nwt_result != 0)
+ {
+ snprintf(str,DLT_USER_BUFFER_LENGTH, "ERROR pthread_cancel(dlt_user.dlt_segmented_nwt_handle): %s\n", strerror(errno));
+ dlt_log(LOG_ERR, str);
+ }
+ }
+
+ /* make sure that the threads really finished working */
+ if ((dlt_receiverthread_result==0) && dlt_receiverthread_handle)
+ {
+ int joined = pthread_join(dlt_receiverthread_handle, NULL);
+ if (joined < 0)
+ {
+ snprintf(str,DLT_USER_BUFFER_LENGTH, "ERROR pthread_join(dlt_receiverthread_handle, NULL): %s\n", strerror(errno));
+ dlt_log(LOG_ERR, str);
+ }
+ dlt_receiverthread_handle = 0; /* set to invalid */
+ }
+
+ if ((dlt_segmented_nwt_result==0) && dlt_user.dlt_segmented_nwt_handle)
+ {
+ int joined = pthread_join(dlt_user.dlt_segmented_nwt_handle, NULL);
+ if (joined < 0)
+ {
+ snprintf(str,DLT_USER_BUFFER_LENGTH, "ERROR pthread_join(dlt_user.dlt_segmented_nwt_handle, NULL): %s\n", strerror(errno));
+ dlt_log(LOG_ERR, str);
+ }
+ dlt_user.dlt_segmented_nwt_handle = 0; /* set to invalid */
+ }
+}
+
+
+static void dlt_fork_pre_fork_handler()
+{
+ dlt_stop_threads();
+}
+
+
+static void dlt_fork_parent_fork_handler()
+{
+ if (dlt_start_threads() < 0)
+ {
+ snprintf(str,DLT_USER_BUFFER_LENGTH,"Logging disabled, failed re-start thread after fork(pid=%i)!\n", getpid());
+ dlt_log(LOG_WARNING, str);
+ /* cleanup is the only thing we can do here */
+ dlt_log_free();
+ dlt_free();
+ }
+}
+
+
+static void dlt_fork_child_fork_handler()
+{
+ /* don't start anything else but cleanup everything and avoid blow-out of buffers*/
+ dlt_log_free();
+ dlt_free();
+ /* the only thing that remains is the atexit-handler */
+}