tp: switch unix rpc server to use base::Daemonize (#6333)
Needs slight change to daemonize to allow custom printing instead
of just printing the pid.
diff --git a/include/perfetto/ext/base/utils.h b/include/perfetto/ext/base/utils.h
index 58bbb4f..c43b296 100644
--- a/include/perfetto/ext/base/utils.h
+++ b/include/perfetto/ext/base/utils.h
@@ -120,10 +120,10 @@
uid_t GetCurrentUserId();
// Forks the process.
-// Parent: prints the PID of the child, calls |parent_cb| and exits from the
-// process with its return value.
+// Parent: calls |parent_cb| with the child's PID and exits with its return
+// value. The callback owns any startup output (e.g. printing the PID).
// Child: redirects stdio onto /dev/null, chdirs into / and returns.
-void Daemonize(std::function<int()> parent_cb);
+void Daemonize(std::function<int(pid_t)> parent_cb);
// Returns the path of the current executable, e.g. /foo/bar/exe.
std::string GetCurExecutablePath();
diff --git a/src/base/utils.cc b/src/base/utils.cc
index 682c702..2134b12 100644
--- a/src/base/utils.cc
+++ b/src/base/utils.cc
@@ -243,7 +243,7 @@
#endif
}
-void Daemonize(std::function<int()> parent_cb) {
+void Daemonize(std::function<int(pid_t)> parent_cb) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
@@ -279,8 +279,7 @@
pipe.wr.reset();
char one = '\0';
PERFETTO_CHECK(Read(*pipe.rd, &one, sizeof(one)) == 1 && one == '1');
- printf("%d\n", pid);
- int err = parent_cb();
+ int err = parent_cb(pid);
exit(err);
}
}
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 87aac1c..7903398 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -888,7 +888,8 @@
}
PERFETTO_CHECK(snapshot_threads_.empty()); // No threads before Daemonize.
- base::Daemonize([this]() -> int {
+ base::Daemonize([this](pid_t pid) -> int {
+ printf("%d\n", pid);
background_wait_pipe_.wr.reset();
if (background_wait_) {
diff --git a/src/profiling/perf/traced_perf.cc b/src/profiling/perf/traced_perf.cc
index a00d048..c67057a 100644
--- a/src/profiling/perf/traced_perf.cc
+++ b/src/profiling/perf/traced_perf.cc
@@ -78,7 +78,10 @@
}
if (background) {
- base::Daemonize([] { return 0; });
+ base::Daemonize([](pid_t pid) {
+ printf("%d\n", pid);
+ return 0;
+ });
}
base::MaybeLockFreeTaskRunner task_runner;
diff --git a/src/trace_processor/rpc/session_paths.cc b/src/trace_processor/rpc/session_paths.cc
index 62fa65e..96ee91f 100644
--- a/src/trace_processor/rpc/session_paths.cc
+++ b/src/trace_processor/rpc/session_paths.cc
@@ -25,6 +25,13 @@
#include "perfetto/base/build_config.h"
#include "perfetto/base/proc_utils.h"
#include "perfetto/base/time.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <direct.h> // _getcwd()
+#else
+#include <unistd.h> // getcwd()
+#endif
+
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/murmur_hash.h"
#include "perfetto/ext/base/status_macros.h"
@@ -160,6 +167,20 @@
return base::OkStatus();
}
+std::string MakeAbsolutePath(const std::string& path) {
+ if (path.empty() || IsAbsolutePath(path))
+ return path;
+ char cwd[4096];
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if (!_getcwd(cwd, sizeof(cwd)))
+ return path;
+#else
+ if (!getcwd(cwd, sizeof(cwd)))
+ return path;
+#endif
+ return std::string(cwd) + kPathSep + path;
+}
+
base::StatusOr<uint32_t> ParseDurationMs(const std::string& s) {
if (s.empty())
return base::ErrStatus("Empty duration");
diff --git a/src/trace_processor/rpc/session_paths.h b/src/trace_processor/rpc/session_paths.h
index 8d69ea3..0a5a7b4 100644
--- a/src/trace_processor/rpc/session_paths.h
+++ b/src/trace_processor/rpc/session_paths.h
@@ -61,6 +61,11 @@
// Returns an error if |path| does not fit within the AF_UNIX sun_path limit.
base::Status ValidateAfUnixPathLength(const std::string& path);
+// Resolves |path| against the cwd if relative; returns it unchanged if already
+// absolute (or empty, or cwd is unavailable). Daemonizing chdirs to "/", so the
+// socket/pid paths must be absolute to survive the fork.
+std::string MakeAbsolutePath(const std::string& path);
+
// Parses a human duration into milliseconds. Accepts a bare integer (seconds),
// or a value suffixed with 's' (seconds), 'm' (minutes) or 'h' (hours). "0",
// "never" and "off" all parse to 0 (meaning "no timeout").
diff --git a/src/trace_processor/rpc/unixd.cc b/src/trace_processor/rpc/unixd.cc
index 720f7be..8fe6518 100644
--- a/src/trace_processor/rpc/unixd.cc
+++ b/src/trace_processor/rpc/unixd.cc
@@ -31,6 +31,7 @@
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/lock_free_task_runner.h"
#include "perfetto/ext/base/unix_socket.h"
+#include "perfetto/ext/base/utils.h"
#include "perfetto/ext/protozero/proto_ring_buffer.h"
#include "perfetto/protozero/proto_utils.h"
#include "src/trace_processor/rpc/rpc.h"
@@ -42,10 +43,7 @@
PERFETTO_BUILDFLAG(PERFETTO_OS_FREEBSD) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
#define PERFETTO_TP_UNIXD_POSIX() 1
-#include <fcntl.h>
#include <unistd.h>
-#include "perfetto/ext/base/pipe.h"
-#include "perfetto/ext/base/scoped_file.h"
#else
#define PERFETTO_TP_UNIXD_POSIX() 0
#endif
@@ -165,36 +163,6 @@
}
#endif // PERFETTO_TP_UNIXD_CTRL_C()
-#if PERFETTO_TP_UNIXD_POSIX()
-// Forks into the background. The parent prints the startup record (it knows the
-// child pid) and exits; the child detaches (setsid + redirect std fds) and
-// returns to keep serving. The socket is already bound before this is called,
-// so the record the parent prints is accurate.
-void DaemonizeAndPrintRecord(const UnixServerArgs& args) {
- base::Pipe pipe = base::Pipe::Create(base::Pipe::kBothBlock);
- pid_t pid = fork();
- PERFETTO_CHECK(pid != -1);
- if (pid > 0) {
- // Parent: wait for the child to detach, print the record, exit.
- pipe.wr.reset();
- char c = '\0';
- base::ignore_result(base::Read(*pipe.rd, &c, 1));
- PrintStartupRecord(stdout, pid, args.session_name, args.socket_path,
- args.idle_timeout_ms);
- _exit(0);
- }
- // Child: detach from the controlling terminal and silence std fds.
- PERFETTO_CHECK(setsid() != -1);
- base::ScopedFile null = base::OpenFile("/dev/null", O_RDWR);
- if (null) {
- base::ignore_result(dup2(*null, STDIN_FILENO));
- base::ignore_result(dup2(*null, STDOUT_FILENO));
- base::ignore_result(dup2(*null, STDERR_FILENO));
- }
- base::ignore_result(base::WriteAll(*pipe.wr, "1", 1));
-}
-#endif // PERFETTO_TP_UNIXD_POSIX()
-
base::Status UnixRpcServer::Run() {
if (args_.daemonize && !PERFETTO_TP_UNIXD_POSIX()) {
return base::ErrStatus("--daemonize is not supported on this platform yet");
@@ -235,7 +203,15 @@
bool printed_record = false;
#if PERFETTO_TP_UNIXD_POSIX()
if (args_.daemonize) {
- DaemonizeAndPrintRecord(args_); // Parent exits inside; child returns.
+ // base::Daemonize forks: the parent prints the record via the callback and
+ // exits; the child detaches and keeps serving. The socket is already bound,
+ // so the printed record is accurate.
+ const UnixServerArgs& args = args_;
+ base::Daemonize([&args](pid_t pid) -> int {
+ PrintStartupRecord(stdout, pid, args.session_name, args.socket_path,
+ args.idle_timeout_ms);
+ return 0;
+ });
printed_record = true;
}
#endif
diff --git a/src/trace_processor/shell/server_subcommand.cc b/src/trace_processor/shell/server_subcommand.cc
index 5ea21c2..d695ce2 100644
--- a/src/trace_processor/shell/server_subcommand.cc
+++ b/src/trace_processor/shell/server_subcommand.cc
@@ -334,6 +334,8 @@
}
ASSIGN_OR_RETURN(socket_path, session::SessionSocketPath(session_name));
} else {
+ // Anchor a relative --path before binding: daemonizing chdirs to "/".
+ socket_path = session::MakeAbsolutePath(socket_path);
RETURN_IF_ERROR(session::ValidateAfUnixPathLength(socket_path));
if (session_name.empty())
session_name = socket_path;
diff --git a/src/traced/probes/probes.cc b/src/traced/probes/probes.cc
index a70b6ab..04ee6e3 100644
--- a/src/traced/probes/probes.cc
+++ b/src/traced/probes/probes.cc
@@ -89,7 +89,10 @@
}
if (background) {
- base::Daemonize([] { return 0; });
+ base::Daemonize([](pid_t pid) {
+ printf("%d\n", pid);
+ return 0;
+ });
}
PERFETTO_LOG("Starting %s service", argv[0]);
diff --git a/src/traced/service/service.cc b/src/traced/service/service.cc
index 027c2d5..25776c6 100644
--- a/src/traced/service/service.cc
+++ b/src/traced/service/service.cc
@@ -146,7 +146,10 @@
}
if (background) {
- base::Daemonize([] { return 0; });
+ base::Daemonize([](pid_t pid) {
+ printf("%d\n", pid);
+ return 0;
+ });
}
base::MaybeLockFreeTaskRunner task_runner;
diff --git a/src/traced_relay/relay_service.cc b/src/traced_relay/relay_service.cc
index 4ef4ee9..c4b9400 100644
--- a/src/traced_relay/relay_service.cc
+++ b/src/traced_relay/relay_service.cc
@@ -565,7 +565,10 @@
}
if (background) {
- base::Daemonize([] { return 0; });
+ base::Daemonize([](pid_t pid) {
+ printf("%d\n", pid);
+ return 0;
+ });
}
base::MaybeLockFreeTaskRunner task_runner;