summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Herkenhoff <sherkenhoff@de.adit-jv.com>2019-02-04 22:16:00 +0900
committerChristoph Lipka <clipka@users.noreply.github.com>2019-02-04 14:16:00 +0100
commit18321f3551098d6313c0f3f3620bc74b53b84472 (patch)
treefb9200b6782a1b9f3d368d6f530f9d521bbefe1d
parent892325dbc0983a18d5d16a10faefc0e982bf9660 (diff)
downloadDLT-daemon-18321f3551098d6313c0f3f3620bc74b53b84472.tar.gz
libdlt: Do not allow DLT usage in forked child (#95)
DLT shall not be used in a forked child until a variant of exec() is called, because DLT is using non async-signal-safe functions. The forking process can continue to use libdlt's logging facilities, but any attempt to use libdlt from the forked child will be denied. The fork-handler test is updated to reflect this by trying to log from the forked child which will fail. The fork then calls exec and runs another application that can continue to use DLT. Signed-off-by: Simon Herkenhoff <sherkenhoff@jp.adit-jv.com>
-rw-r--r--src/lib/dlt_user.c94
-rw-r--r--src/tests/dlt-test-fork-handler.c22
2 files changed, 74 insertions, 42 deletions
diff --git a/src/lib/dlt_user.c b/src/lib/dlt_user.c
index d45bb91..66ffd0b 100644
--- a/src/lib/dlt_user.c
+++ b/src/lib/dlt_user.c
@@ -95,9 +95,8 @@ static pthread_t dlt_receiverthread_handle;
/* calling dlt_user_atexit_handler() second time fails with error message */
static int atexit_registered = 0;
-/* calling atfork_handler() only once */
-static int atfork_registered = 0;
-
+/* used to disallow DLT usage in fork() child */
+static int g_dlt_is_child = 0;
/* Segmented Network Trace */
#define DLT_MAX_TRACE_SEGMENT_SIZE 1024
@@ -174,8 +173,6 @@ static DltReturnValue dlt_user_log_out_error_handling(void *ptr1,
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();
@@ -431,10 +428,7 @@ DltReturnValue dlt_init(void)
}
/* prepare for fork() call */
- if (atfork_registered == 0) {
- atfork_registered = 1;
- pthread_atfork(&dlt_fork_pre_fork_handler, &dlt_fork_parent_fork_handler, &dlt_fork_child_fork_handler);
- }
+ pthread_atfork(NULL, NULL, &dlt_fork_child_fork_handler);
return DLT_RETURN_OK;
}
@@ -710,6 +704,11 @@ DltReturnValue dlt_init_common(void)
void dlt_user_atexit_handler(void)
{
+ /* parent will do clean-up */
+ if (g_dlt_is_child) {
+ return;
+ }
+
if (!dlt_user_initialised) {
dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
/* close file */
@@ -950,6 +949,10 @@ DltReturnValue dlt_register_app(const char *appid, const char *description)
{
DltReturnValue ret = DLT_RETURN_OK;
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
if (!dlt_user_initialised) {
if (dlt_init() < 0) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
@@ -1025,6 +1028,10 @@ DltReturnValue dlt_register_context(DltContext *handle, const char *contextid, c
if (handle == NULL)
return DLT_RETURN_WRONG_PARAMETER;
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
if (!dlt_user_initialised) {
if (dlt_init() < 0) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
@@ -1059,6 +1066,10 @@ DltReturnValue dlt_register_context_ll_ts_llccb(DltContext *handle,
if ((handle == NULL) || (contextid == NULL) || (contextid[0] == '\0'))
return DLT_RETURN_WRONG_PARAMETER;
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
if ((loglevel < DLT_USER_LOG_LEVEL_NOT_SET) || (loglevel >= DLT_LOG_MAX)) {
dlt_vlog(LOG_ERR, "Loglevel %d is outside valid range", loglevel);
return DLT_RETURN_WRONG_PARAMETER;
@@ -1264,6 +1275,10 @@ DltReturnValue dlt_register_context_llccb(DltContext *handle,
if ((handle == NULL) || (contextid == NULL) || (contextid[0] == '\0'))
return DLT_RETURN_WRONG_PARAMETER;
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
if (!dlt_user_initialised) {
if (dlt_init() < 0) {
dlt_vlog(LOG_ERR, "%s Failed to initialise dlt", __FUNCTION__);
@@ -1283,6 +1298,10 @@ DltReturnValue dlt_unregister_app(void)
{
DltReturnValue ret = DLT_RETURN_OK;
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
if (!dlt_user_initialised) {
dlt_vlog(LOG_WARNING, "%s dlt_user_initialised false\n", __FUNCTION__);
return DLT_RETURN_ERROR;
@@ -1310,6 +1329,10 @@ DltReturnValue dlt_unregister_app_flush_buffered_logs(void)
{
DltReturnValue ret = DLT_RETURN_OK;
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
if (!dlt_user_initialised) {
dlt_vlog(LOG_ERR, "%s dlt_user_initialised false\n", __func__);
return DLT_RETURN_ERROR;
@@ -1329,6 +1352,10 @@ DltReturnValue dlt_unregister_context(DltContext *handle)
DltContextData log;
DltReturnValue ret = DLT_RETURN_OK;
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
log.handle = NULL;
log.context_description = NULL;
@@ -1383,6 +1410,10 @@ DltReturnValue dlt_set_application_ll_ts_limit(DltLogLevelType loglevel, DltTrac
{
uint32_t i;
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
if ((loglevel < DLT_USER_LOG_LEVEL_NOT_SET) || (loglevel >= DLT_LOG_MAX)) {
dlt_vlog(LOG_ERR, "Loglevel %d is outside valid range", loglevel);
return DLT_RETURN_WRONG_PARAMETER;
@@ -1451,6 +1482,10 @@ int dlt_get_log_state()
DltReturnValue dlt_set_log_mode(DltUserLogMode mode)
{
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
if ((mode < DLT_USER_MODE_UNDEFINED) || (mode >= DLT_USER_MODE_MAX)) {
dlt_vlog(LOG_ERR, "User log mode %d is outside valid range", mode);
return DLT_RETURN_WRONG_PARAMETER;
@@ -1468,6 +1503,10 @@ DltReturnValue dlt_set_log_mode(DltUserLogMode mode)
int dlt_set_resend_timeout_atexit(uint32_t timeout_in_milliseconds)
{
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
if (dlt_user_initialised == 0) {
if (dlt_init() < 0)
return -1;
@@ -1486,6 +1525,10 @@ DltReturnValue dlt_forward_msg(void *msgdata, size_t size)
if ((msgdata == NULL) || (size == 0))
return DLT_RETURN_WRONG_PARAMETER;
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
if (dlt_user_set_userheader(&userheader, DLT_USER_MESSAGE_LOG) < DLT_RETURN_OK)
/* Type of internal user message; same value for Trace messages */
return DLT_RETURN_ERROR;
@@ -1598,6 +1641,10 @@ DltReturnValue dlt_user_log_write_start_id(DltContext *handle,
if ((handle == NULL) || (log == NULL))
return DLT_RETURN_WRONG_PARAMETER;
+ /* forbid dlt usage in child after fork */
+ if (g_dlt_is_child)
+ return DLT_RETURN_ERROR;
+
/* check log levels */
ret = dlt_user_is_logLevel_enabled(handle, loglevel);
@@ -4681,35 +4728,10 @@ void dlt_stop_threads()
}
}
-static void dlt_fork_pre_fork_handler()
-{
- dlt_stop_threads();
-}
-
-static void dlt_fork_parent_fork_handler()
-{
- if (dlt_user_initialised) {
- 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()
{
- if (dlt_user_initialised) {
- /* don't start anything else but cleanup everything and avoid blow-out of buffers*/
- dlt_user.dlt_log_handle = -1;
- dlt_log_free();
- dlt_free();
- /* the only thing that remains is the atexit-handler */
- }
+ g_dlt_is_child = 1;
+ dlt_user_initialised = false;
}
DltReturnValue dlt_user_log_out_error_handling(void *ptr1, size_t len1, void *ptr2, size_t len2, void *ptr3,
diff --git a/src/tests/dlt-test-fork-handler.c b/src/tests/dlt-test-fork-handler.c
index 4bd3321..118753b 100644
--- a/src/tests/dlt-test-fork-handler.c
+++ b/src/tests/dlt-test-fork-handler.c
@@ -25,6 +25,8 @@
*/
#include <unistd.h> /* for fork() */
+#include <time.h>
+#include <errno.h>
#include "dlt.h"
@@ -34,23 +36,31 @@
int main()
{
DltContext mainContext;
+ struct timespec timeout, r;
+
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 200000000L;
DLT_REGISTER_APP("PRNT", "Parent application");
DLT_REGISTER_CONTEXT(mainContext, "CTXP", "Parent context");
DLT_LOG(mainContext, DLT_LOG_WARN, DLT_STRING("First message before fork"));
- usleep(200000);
+ nanosleep(&timeout, &r);
pid_t pid = fork();
-
if (pid == 0) { /* child process */
/* this message should not be visible */
- /* DLT_LOG(mainContext, DLT_LOG_WARN, DLT_STRING("Child's first message after fork, pid: "), DLT_INT32(getpid())); */
- /* unfortunately, this message does arrive, I assume because it still has (locally) valid data ... */
+ DLT_LOG(mainContext, DLT_LOG_WARN, DLT_STRING("Child's first message after fork, pid: "), DLT_INT32(getpid()));
+ /* this will not register CHLD application */
DLT_REGISTER_APP("CHLD", "Child application");
+ /* this will not register CTXC context */
DLT_REGISTER_CONTEXT(mainContext, "CTXC", "Child context");
+ /* this will not log a message */
DLT_LOG(mainContext, DLT_LOG_WARN, DLT_STRING("Child's second message after fork, pid: "), DLT_INT32(getpid()));
- usleep(400000);
+ nanosleep(&timeout, &r);
+ if (execlp("dlt-example-user", "dlt-example-user", "-n 1",
+ "you should see this message", NULL))
+ return errno;
}
else if (pid == -1) /* error in fork */
{
@@ -58,7 +68,7 @@ int main()
}
else { /* parent */
DLT_LOG(mainContext, DLT_LOG_WARN, DLT_STRING("Parent's first message after fork, pid: "), DLT_INT32(getpid()));
- usleep(500000);
+ nanosleep(&timeout, &r);
}
DLT_UNREGISTER_APP()