summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authormdm@chromium.org <mdm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-10 18:02:17 +0000
committermdm@chromium.org <mdm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-10 18:02:17 +0000
commit7f113f39afed41b39d5c937039879c5d822c6b5e (patch)
treedb014b39bf9cdc6daf6aae947a16c4c5ff5d1721 /base
parente4e3caed74ecfe1ef1da4c7ba8fc076f59a53ef1 (diff)
downloadchromium_src-7f113f39afed41b39d5c937039879c5d822c6b5e.zip
chromium_src-7f113f39afed41b39d5c937039879c5d822c6b5e.tar.gz
chromium_src-7f113f39afed41b39d5c937039879c5d822c6b5e.tar.bz2
Linux: set the process title (that shows in "ps" etc.) of renderers correctly when using the zygote.
BUG=none TEST=none Review URL: http://codereview.chromium.org/196009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25877 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/base.gyp16
-rw-r--r--base/command_line.cc31
-rw-r--r--base/command_line.h10
-rw-r--r--base/setproctitle_linux.c112
-rw-r--r--base/setproctitle_linux.h25
5 files changed, 191 insertions, 3 deletions
diff --git a/base/base.gyp b/base/base.gyp
index f6a7192..8c0ed39 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -261,6 +261,8 @@
'scoped_variant_win.cc',
'scoped_variant_win.h',
'scoped_vector.h',
+ 'setproctitle_linux.c',
+ 'setproctitle_linux.h',
'sha2.cc',
'sha2.h',
'shared_memory.h',
@@ -398,8 +400,8 @@
'cflags': [
'-Wno-write-strings',
],
- 'link_settings': {
- 'libraries': [
+ 'link_settings': {
+ 'libraries': [
# We need rt for clock_gettime().
'-lrt',
],
@@ -424,7 +426,15 @@
'nss_init.h',
'time_posix.cc',
],
- }
+ },
+ ],
+ [ 'OS != "linux"', {
+ 'sources!': [
+ # Not automatically excluded by the *linux.cc rules.
+ 'setproctitle_linux.c',
+ 'setproctitle_linux.h',
+ ],
+ },
],
[ 'GENERATOR == "quentin"', {
# Quentin builds don't have a recent enough glibc to include the
diff --git a/base/command_line.cc b/base/command_line.cc
index 43b068c..04c1ece 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -7,6 +7,9 @@
#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
+#elif defined(OS_FREEBSD)
+#include <stdlib.h>
+#include <unistd.h>
#endif
#include <algorithm>
@@ -17,6 +20,11 @@
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
+#if defined(OS_LINUX)
+// Linux/glibc doesn't natively have setproctitle().
+#include "base/setproctitle_linux.h"
+#endif
+
CommandLine* CommandLine::current_process_commandline_ = NULL;
// Since we use a lazy match, make sure that longer versions (like L"--")
@@ -194,6 +202,29 @@ void CommandLine::Init(const std::vector<std::string>& argv) {
#endif
}
+#if defined(OS_LINUX) || defined(OS_FREEBSD)
+// static
+void CommandLine::SetProcTitle() {
+ // Build a single string which consists of all the arguments separated
+ // by spaces. We can't actually keep them separate due to the way the
+ // setproctitle() function works.
+ std::string title;
+ for (size_t i = 1; i < current_process_commandline_->argv_.size(); ++i) {
+ if (!title.empty())
+ title += " ";
+ title += current_process_commandline_->argv_[i];
+ }
+ setproctitle("%s", title.c_str());
+}
+
+// static
+void CommandLine::SetTrueArgv(char** argv) {
+#if defined(OS_LINUX)
+ setproctitle_init(argv);
+#endif
+}
+#endif
+
void CommandLine::Terminate() {
DCHECK(current_process_commandline_ != NULL);
delete current_process_commandline_;
diff --git a/base/command_line.h b/base/command_line.h
index 121eb8c..78f3862 100644
--- a/base/command_line.h
+++ b/base/command_line.h
@@ -55,6 +55,16 @@ class CommandLine {
static void Init(int argc, const char* const* argv);
static void Init(const std::vector<std::string>& argv);
+#if defined(OS_LINUX) || defined(OS_FREEBSD)
+ // Sets the current process' arguments that show in "ps" etc. to those
+ // in |current_process_commandline_|. Used by the zygote host so that
+ // renderers show up with --type=renderer.
+ static void SetProcTitle();
+
+ // Needed to support SetProcTitle() on Linux. Should be called by main().
+ static void SetTrueArgv(char** argv);
+#endif
+
// Destroys the current process CommandLine singleton. This is necessary if
// you want to reset the base library to its initial state (for example in an
// outer library that needs to be able to terminate, and be re-initialized).
diff --git a/base/setproctitle_linux.c b/base/setproctitle_linux.c
new file mode 100644
index 0000000..205be2b
--- /dev/null
+++ b/base/setproctitle_linux.c
@@ -0,0 +1,112 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file implements BSD-style setproctitle() for Linux.
+// It is written such that it can easily be compiled outside Chromium.
+//
+// The Linux kernel sets up two locations in memory to pass arguments and
+// environment variables to processes. First, there are two char* arrays stored
+// one after another: argv and environ. A pointer to argv is passed to main(),
+// while glibc sets the global variable |environ| to point at the latter. Both
+// of these arrays are terminated by a NULL pointer; the environment array is
+// also followed by some empty space to allow additional variables to be added.
+//
+// These arrays contain pointers to a second location in memory, where the
+// strings themselves are stored one after another: first all the arguments,
+// then the environment variables. The kernel will allocate a single page of
+// memory for this purpose, so the end of the page containing argv[0] is the
+// end of the storage potentially available to store the process title.
+//
+// When the kernel reads the command line arguments for a process, it looks at
+// the range of memory within this page that it initially used for the argument
+// list. If the terminating '\0' character is still where it expects, nothing
+// further is done. If it has been overwritten, the kernel will scan up to the
+// size of a page looking for another. (Note, however, that in general not that
+// much space is actually mapped, since argv[0] is rarely page-aligned and only
+// one page is mapped.)
+//
+// Thus to change the process title, we must move any environment variables out
+// of the way to make room for a potentially longer title, and then overwrite
+// the memory pointed to by argv[0] with a single replacement string, making
+// sure its size does not exceed the available space.
+//
+// It is perhaps worth noting that patches to add a system call to Linux for
+// this, like in BSD, have never made it in: this is the "official" way to do
+// this on Linux. Presumably it is not in glibc due to some disagreement over
+// this position within the glibc project, leaving applications caught in the
+// middle. (Also, only a very few applications need or want this anyway.)
+
+#include "base/setproctitle_linux.h"
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+extern char** environ;
+
+static char** g_main_argv = NULL;
+static char* g_orig_argv0 = NULL;
+
+void setproctitle(const char* fmt, ...) {
+ va_list ap;
+ size_t i, avail_size;
+ uintptr_t page_size, page, page_end;
+ // Sanity check before we try and set the process title.
+ // The BSD version allows fmt == NULL to restore the original title.
+ if (!g_main_argv || !environ || !fmt)
+ return;
+ if (!g_orig_argv0) {
+ // Save the original argv[0].
+ g_orig_argv0 = strdup(g_main_argv[0]);
+ if (!g_orig_argv0)
+ return;
+ }
+ page_size = sysconf(_SC_PAGESIZE);
+ // Get the page on which the argument list and environment live.
+ page = (uintptr_t) g_main_argv[0];
+ page -= page % page_size;
+ page_end = page + page_size;
+ // Move the environment out of the way. Note that we are moving the values,
+ // not the environment array itself (which may not be on the page we need
+ // to overwrite anyway).
+ for (i = 0; environ[i]; ++i) {
+ uintptr_t env_i = (uintptr_t) environ[i];
+ // Only move the value if it's actually in the way. This avoids
+ // leaking copies of the values if this function is called again.
+ if (page <= env_i && env_i < page_end) {
+ char* copy = strdup(environ[i]);
+ // Be paranoid. Check for allocation failure and bail out.
+ if (!copy)
+ return;
+ environ[i] = copy;
+ }
+ }
+ // Put the title in argv[0]. We have to zero out the space first since the
+ // kernel doesn't actually look for a null terminator unless we make the
+ // argument list longer than it started.
+ avail_size = page_end - (uintptr_t) g_main_argv[0];
+ memset(g_main_argv[0], 0, avail_size);
+ va_start(ap, fmt);
+ if (fmt[0] == '-') {
+ vsnprintf(g_main_argv[0], avail_size, fmt, ap);
+ } else {
+ size_t size = snprintf(g_main_argv[0], avail_size, "%s ", g_orig_argv0);
+ if (size < avail_size)
+ vsnprintf(g_main_argv[0] + size, avail_size - size, fmt, ap);
+ }
+ va_end(ap);
+ g_main_argv[1] = NULL;
+}
+
+// A version of this built into glibc would not need this function, since
+// it could stash the argv pointer in __libc_start_main(). But we need it.
+void setproctitle_init(char** main_argv) {
+ uintptr_t page_size = sysconf(_SC_PAGESIZE);
+ // Check that the argv array is in fact on the same page of memory
+ // as the environment array just as an added measure of protection.
+ if (((uintptr_t) environ) / page_size == ((uintptr_t) main_argv) / page_size)
+ g_main_argv = main_argv;
+}
diff --git a/base/setproctitle_linux.h b/base/setproctitle_linux.h
new file mode 100644
index 0000000..32cc297
--- /dev/null
+++ b/base/setproctitle_linux.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SETPROCTITLE_LINUX_H_
+#define BASE_SETPROCTITLE_LINUX_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Set the process title that will show in "ps" and similar tools. Takes
+// printf-style format string and arguments. After calling setproctitle()
+// the original main() argv[] array should not be used.
+void setproctitle(const char* fmt, ...);
+
+// Initialize state needed for setproctitle() on Linux. Pass the argv pointer
+// from main() to setproctitle_init() before calling setproctitle().
+void setproctitle_init(char** main_argv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BASE_SETPROCTITLE_LINUX_H_