jolly has uploaded this change for review. (
https://gerrit.osmocom.org/c/libosmocore/+/37798?usp=email )
Change subject: After writing VTY config, run sync() in a different thread
......................................................................
After writing VTY config, run sync() in a different thread
Running sync() after writing VTY config causes the process to stop for
a fraction of a second. This may results in delayed processing that
causes buffer underruns, overflows and delays.
After writing VTY configuration to the config file, a new thread is
created. This thread runs the sync() command. Once it returns, the
thread will signal through a pipe to the main thread that the sync
process is complete. The main process will then output the completion
message on the VTY.
Related: OS#6438
Change-Id: I3cb2ee68b2e4c730f96522208c4abf00d0f49a44
---
M src/vty/command.c
1 file changed, 87 insertions(+), 7 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/98/37798/1
diff --git a/src/vty/command.c b/src/vty/command.c
index 1719690..a6c5d94 100644
--- a/src/vty/command.c
+++ b/src/vty/command.c
@@ -39,6 +39,7 @@
#include <time.h>
#include <limits.h>
#include <signal.h>
+#include <pthread.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -51,6 +52,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/utils.h>
+#include <osmocom/core/select.h>
#ifndef MAXPATHLEN
#define MAXPATHLEN 4096
@@ -3372,7 +3374,85 @@
return CMD_SUCCESS;
}
-static int write_config_file(const char *config_file, char **outpath)
+static struct osmo_fd sync_fd;
+static int sync_pipe_fd[2];
+
+static int sync_complete(struct osmo_fd *fd, unsigned int what)
+{
+ struct vty *vty = fd->data;
+
+ if (sync_pipe_fd[0])
+ close(sync_pipe_fd[0]);
+ if (sync_pipe_fd[1])
+ close(sync_pipe_fd[1]);
+ if (osmo_fd_is_registered(fd))
+ osmo_fd_unregister(fd);
+
+ /* Check if pointer to VTY session is still valid.
+ * If session closes before completion, prevent use-after-free condition.
+ */
+ if (vty && vty_is_active(vty)) {
+ vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out(vty, "Configuration saved to %s%s", host.config, VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+static void *sync_thread(void* arg)
+{
+ sync();
+ write(sync_pipe_fd[1], "", 1);
+
+ return NULL;
+}
+
+/* Run sync thread and setup pipe to signal completion. */
+static void do_sync(struct vty *vty)
+{
+ int rc;
+ pthread_t thread;
+
+ sync_pipe_fd[0] = 0;
+ sync_pipe_fd[1] = 0;
+
+ if (osmo_fd_is_registered(&sync_fd)) {
+ LOGP(DLGLOBAL, LOGL_INFO, "There is another ongoing sync, syncing without
thread.\n");
+ sync();
+ sync_complete(&sync_fd, 0);
+ return;
+ }
+
+ rc = pipe(sync_pipe_fd);
+ if (rc < 0) {
+ LOGP(DLGLOBAL, LOGL_INFO, "Failed to create pipe, syncing without
thread.\n");
+ sync();
+ sync_complete(&sync_fd, 0);
+ return;
+ }
+
+ sync_fd.data = vty;
+ sync_fd.fd = sync_pipe_fd[0];
+ sync_fd.when = OSMO_FD_READ;
+ sync_fd.cb = sync_complete;
+ rc = osmo_fd_register(&sync_fd);
+ if (rc < 0) {
+ LOGP(DLGLOBAL, LOGL_INFO, "Failed to register fd, syncing without
thread.\n");
+ sync();
+ sync_complete(&sync_fd, 0);
+ return;
+ }
+
+ rc = pthread_create(&thread, NULL, sync_thread, NULL);
+ if (rc < 0) {
+ LOGP(DLGLOBAL, LOGL_INFO, "Failed to create thread, syncing without
thread.\n");
+ sync();
+ sync_complete(&sync_fd, 0);
+ return;
+ }
+}
+
+static int write_config_file(struct vty *vty, const char *config_file, char **outpath)
{
unsigned int i;
int fd;
@@ -3451,12 +3531,12 @@
unlink(config_file_tmp);
return -3;
}
- sync();
if (unlink(config_file) != 0) {
*outpath = talloc_strdup(tall_vty_cmd_ctx, config_file);
talloc_free(config_file_sav);
talloc_free(config_file_tmp);
unlink(config_file_tmp);
+ do_sync(NULL);
return -4;
}
}
@@ -3465,10 +3545,11 @@
talloc_free(config_file_sav);
talloc_free(config_file_tmp);
unlink(config_file_tmp);
+ do_sync(NULL);
return -5;
}
unlink(config_file_tmp);
- sync();
+ do_sync(vty);
talloc_free(config_file_sav);
talloc_free(config_file_tmp);
@@ -3511,7 +3592,7 @@
return CMD_WARNING;
}
- rc = write_config_file(host.config, &failed_file);
+ rc = write_config_file(vty, host.config, &failed_file);
switch (rc) {
case -1:
vty_out(vty, "Can't open configuration file %s.%s",
@@ -3544,7 +3625,6 @@
rc = CMD_WARNING;
break;
default:
- vty_out(vty, "Configuration saved to %s%s", host.config, VTY_NEWLINE);
rc = CMD_SUCCESS;
break;
}
@@ -4377,7 +4457,7 @@
char *failed_file;
int rc;
- rc = write_config_file(filename, &failed_file);
+ rc = write_config_file(NULL, filename, &failed_file);
talloc_free(failed_file);
return rc;
}
@@ -4398,7 +4478,7 @@
if (host.config == NULL)
return -7;
- rc = write_config_file(host.config, &failed_file);
+ rc = write_config_file(NULL, host.config, &failed_file);
talloc_free(failed_file);
return rc;
}
--
To view, visit
https://gerrit.osmocom.org/c/libosmocore/+/37798?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: I3cb2ee68b2e4c730f96522208c4abf00d0f49a44
Gerrit-Change-Number: 37798
Gerrit-PatchSet: 1
Gerrit-Owner: jolly <andreas(a)eversberg.eu>