Commit 1e2d716f authored by Zhangyi Chen's avatar Zhangyi Chen

Shrink butil

parent fd9a6e94
......@@ -9,9 +9,14 @@
*.pb.cc
*.pb.h
*.prof
*.so
/output
/test/output
#ignore hidden files
.*
*.swp
#ignore auto-generated files
config.mk
src/butil/config.h
......@@ -52,15 +52,12 @@ BUTIL_SOURCES = \
src/butil/at_exit.cc \
src/butil/atomicops_internals_x86_gcc.cc \
src/butil/barrier_closure.cc \
src/butil/base_paths.cc \
src/butil/base_paths_posix.cc \
src/butil/base64.cc \
src/butil/base_switches.cc \
src/butil/big_endian.cc \
src/butil/bind_helpers.cc \
src/butil/callback_helpers.cc \
src/butil/callback_internal.cc \
src/butil/command_line.cc \
src/butil/cpu.cc \
src/butil/debug/alias.cc \
src/butil/debug/asan_invalid_access.cc \
......@@ -94,29 +91,10 @@ BUTIL_SOURCES = \
src/butil/memory/aligned_memory.cc \
src/butil/memory/ref_counted.cc \
src/butil/memory/ref_counted_memory.cc \
src/butil/memory/shared_memory_posix.cc \
src/butil/memory/singleton.cc \
src/butil/memory/weak_ptr.cc \
src/butil/nix/mime_util_xdg.cc \
src/butil/nix/xdg_util.cc \
src/butil/path_service.cc \
src/butil/posix/file_descriptor_shuffle.cc \
src/butil/posix/global_descriptors.cc \
src/butil/process/internal_linux.cc \
src/butil/process/kill.cc \
src/butil/process/kill_posix.cc \
src/butil/process/launch.cc \
src/butil/process/launch_posix.cc \
src/butil/process/process_handle_linux.cc \
src/butil/process/process_handle_posix.cc \
src/butil/process/process_info_linux.cc \
src/butil/process/process_iterator.cc \
src/butil/process/process_iterator_linux.cc \
src/butil/process/process_linux.cc \
src/butil/process/process_metrics.cc \
src/butil/process/process_metrics_linux.cc \
src/butil/process/process_metrics_posix.cc \
src/butil/process/process_posix.cc \
src/butil/rand_util.cc \
src/butil/rand_util_posix.cc \
src/butil/fast_rand.cpp \
......@@ -139,9 +117,6 @@ BUTIL_SOURCES = \
src/butil/synchronization/cancellation_flag.cc \
src/butil/synchronization/condition_variable_posix.cc \
src/butil/synchronization/waitable_event_posix.cc \
src/butil/sys_info.cc \
src/butil/sys_info_linux.cc \
src/butil/sys_info_posix.cc \
src/butil/threading/non_thread_safe_impl.cc \
src/butil/threading/platform_thread_linux.cc \
src/butil/threading/platform_thread_posix.cc \
......
// Copyright (c) 2012 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_BASE_PATHS_H_
#define BASE_BASE_PATHS_H_
// This file declares path keys for the base module. These can be used with
// the PathService to access various special directories and files.
#include "butil/build_config.h"
#if defined(OS_WIN)
#include "butil/base_paths_win.h"
#elif defined(OS_MACOSX)
#include "butil/base_paths_mac.h"
#elif defined(OS_ANDROID)
#include "butil/base_paths_android.h"
#endif
#if defined(OS_POSIX)
#include "butil/base_paths_posix.h"
#endif
namespace butil {
enum BasePathKey {
PATH_START = 0,
DIR_CURRENT, // Current directory.
DIR_EXE, // Directory containing FILE_EXE.
DIR_MODULE, // Directory containing FILE_MODULE.
DIR_TEMP, // Temporary directory.
DIR_HOME, // User's root home directory. On Windows this will look
// like "C:\Users\you" (or on XP
// "C:\Document and Settings\you") which isn't necessarily
// a great place to put files.
FILE_EXE, // Path and filename of the current executable.
FILE_MODULE, // Path and filename of the module containing the code for
// the PathService (which could differ from FILE_EXE if the
// PathService were compiled into a shared object, for
// example).
DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
// for tests that need to locate various resources. It
// should not be used outside of test code.
DIR_USER_DESKTOP, // The current user's Desktop.
DIR_TEST_DATA, // Used only for testing.
PATH_END
};
} // namespace butil
#endif // BASE_BASE_PATHS_H_
// Copyright (c) 2012 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_BASE_PATHS_ANDROID_H_
#define BASE_BASE_PATHS_ANDROID_H_
// This file declares Android-specific path keys for the base module.
// These can be used with the PathService to access various special
// directories and files.
namespace butil {
enum {
PATH_ANDROID_START = 300,
DIR_ANDROID_APP_DATA, // Directory where to put Android app's data.
DIR_ANDROID_EXTERNAL_STORAGE, // Android external storage directory.
PATH_ANDROID_END
};
} // namespace butil
#endif // BASE_BASE_PATHS_ANDROID_H_
// Copyright (c) 2006-2008 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_BASE_PATHS_MAC_H_
#define BASE_BASE_PATHS_MAC_H_
// This file declares Mac-specific path keys for the base module.
// These can be used with the PathService to access various special
// directories and files.
namespace butil {
enum {
PATH_MAC_START = 200,
DIR_APP_DATA, // ~/Library/Application Support
PATH_MAC_END
};
} // namespace butil
#endif // BASE_BASE_PATHS_MAC_H_
// Copyright (c) 2012 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.
// Defines base::PathProviderMac which replaces base::PathProviderPosix for Mac
// in base/path_service.cc.
#include <dlfcn.h>
#import <Foundation/Foundation.h>
#include <mach-o/dyld.h>
#include "base/base_paths.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/build_config.h"
namespace {
void GetNSExecutablePath(base::FilePath* path) {
DCHECK(path);
// Executable path can have relative references ("..") depending on
// how the app was launched.
uint32_t executable_length = 0;
_NSGetExecutablePath(NULL, &executable_length);
DCHECK_GT(executable_length, 1u);
std::string executable_path;
int rv = _NSGetExecutablePath(WriteInto(&executable_path, executable_length),
&executable_length);
DCHECK_EQ(rv, 0);
// _NSGetExecutablePath may return paths containing ./ or ../ which makes
// FilePath::DirName() work incorrectly, convert it to absolute path so that
// paths such as DIR_SOURCE_ROOT can work, since we expect absolute paths to
// be returned here.
*path = base::MakeAbsoluteFilePath(base::FilePath(executable_path));
}
// Returns true if the module for |address| is found. |path| will contain
// the path to the module. Note that |path| may not be absolute.
bool GetModulePathForAddress(base::FilePath* path,
const void* address) WARN_UNUSED_RESULT;
bool GetModulePathForAddress(base::FilePath* path, const void* address) {
Dl_info info;
if (dladdr(address, &info) == 0)
return false;
*path = base::FilePath(info.dli_fname);
return true;
}
} // namespace
namespace base {
bool PathProviderMac(int key, base::FilePath* result) {
switch (key) {
case base::FILE_EXE:
GetNSExecutablePath(result);
return true;
case base::FILE_MODULE:
return GetModulePathForAddress(result,
reinterpret_cast<const void*>(&base::PathProviderMac));
case base::DIR_APP_DATA: {
bool success = base::mac::GetUserDirectory(NSApplicationSupportDirectory,
result);
#if defined(OS_IOS)
// On IOS, this directory does not exist unless it is created explicitly.
if (success && !base::PathExists(*result))
success = base::CreateDirectory(*result);
#endif // defined(OS_IOS)
return success;
}
case base::DIR_SOURCE_ROOT:
// Go through PathService to catch overrides.
if (!PathService::Get(base::FILE_EXE, result))
return false;
// Start with the executable's directory.
*result = result->DirName();
#if !defined(OS_IOS)
if (base::mac::AmIBundled()) {
// The bundled app executables (Chromium, TestShell, etc) live five
// levels down, eg:
// src/xcodebuild/{Debug|Release}/Chromium.app/Contents/MacOS/Chromium
*result = result->DirName().DirName().DirName().DirName().DirName();
} else {
// Unit tests execute two levels deep from the source root, eg:
// src/xcodebuild/{Debug|Release}/base_unittests
*result = result->DirName().DirName();
}
#endif
return true;
case base::DIR_USER_DESKTOP:
#if defined(OS_IOS)
// iOS does not have desktop directories.
NOTIMPLEMENTED();
return false;
#else
return base::mac::GetUserDirectory(NSDesktopDirectory, result);
#endif
case base::DIR_CACHE:
return base::mac::GetUserDirectory(NSCachesDirectory, result);
default:
return false;
}
}
} // namespace base
// Copyright (c) 2012 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.
// Defines butil::PathProviderPosix, default path provider on POSIX OSes that
// don't have their own base_paths_OS.cc implementation (i.e. all but Mac and
// Android).
#include <ostream>
#include <string>
#include "butil/base_paths.h"
#include "butil/environment.h"
#include "butil/file_util.h"
#include "butil/files/file_path.h"
#include "butil/logging.h"
#include "butil/memory/scoped_ptr.h"
#include "butil/nix/xdg_util.h"
#include "butil/path_service.h"
#include "butil/process/process_metrics.h"
#include "butil/build_config.h"
#if defined(OS_FREEBSD)
#include <sys/param.h>
#include <sys/sysctl.h>
#elif defined(OS_SOLARIS)
#include <stdlib.h>
#endif
namespace butil {
bool PathProviderPosix(int key, FilePath* result) {
FilePath path;
switch (key) {
case butil::FILE_EXE:
case butil::FILE_MODULE: { // TODO(evanm): is this correct?
#if defined(OS_LINUX)
FilePath bin_dir;
if (!ReadSymbolicLink(FilePath(kProcSelfExe), &bin_dir)) {
NOTREACHED() << "Unable to resolve " << kProcSelfExe << ".";
return false;
}
*result = bin_dir;
return true;
#elif defined(OS_FREEBSD)
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
char bin_dir[PATH_MAX + 1];
size_t length = sizeof(bin_dir);
// Upon return, |length| is the number of bytes written to |bin_dir|
// including the string terminator.
int error = sysctl(name, 4, bin_dir, &length, NULL, 0);
if (error < 0 || length <= 1) {
NOTREACHED() << "Unable to resolve path.";
return false;
}
*result = FilePath(FilePath::StringType(bin_dir, length - 1));
return true;
#elif defined(OS_SOLARIS)
char bin_dir[PATH_MAX + 1];
if (realpath(getexecname(), bin_dir) == NULL) {
NOTREACHED() << "Unable to resolve " << getexecname() << ".";
return false;
}
*result = FilePath(bin_dir);
return true;
#elif defined(OS_OPENBSD)
// There is currently no way to get the executable path on OpenBSD
char* cpath;
if ((cpath = getenv("CHROME_EXE_PATH")) != NULL)
*result = FilePath(cpath);
else
*result = FilePath("/usr/local/chrome/chrome");
return true;
#endif
}
case butil::DIR_SOURCE_ROOT: {
// Allow passing this in the environment, for more flexibility in build
// tree configurations (sub-project builds, gyp --output_dir, etc.)
scoped_ptr<butil::Environment> env(butil::Environment::Create());
std::string cr_source_root;
if (env->GetVar("CR_SOURCE_ROOT", &cr_source_root)) {
path = FilePath(cr_source_root);
if (butil::PathExists(path)) {
*result = path;
return true;
} else {
DLOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not "
<< "point to a directory.";
}
}
// On POSIX, unit tests execute two levels deep from the source root.
// For example: out/{Debug|Release}/net_unittest
if (PathService::Get(butil::DIR_EXE, &path)) {
*result = path.DirName().DirName();
return true;
}
DLOG(ERROR) << "Couldn't find your source root. "
<< "Try running from your chromium/src directory.";
return false;
}
case butil::DIR_USER_DESKTOP:
*result = butil::nix::GetXDGUserDirectory("DESKTOP", "Desktop");
return true;
case butil::DIR_CACHE: {
scoped_ptr<butil::Environment> env(butil::Environment::Create());
FilePath cache_dir(butil::nix::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
".cache"));
*result = cache_dir;
return true;
}
}
return false;
}
} // namespace butil
// Copyright (c) 2012 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_BASE_PATHS_POSIX_H_
#define BASE_BASE_PATHS_POSIX_H_
// This file declares windows-specific path keys for the base module.
// These can be used with the PathService to access various special
// directories and files.
namespace butil {
enum {
PATH_POSIX_START = 400,
DIR_CACHE, // Directory where to put cache data. Note this is
// *not* where the browser cache lives, but the
// browser cache can be a subdirectory.
// This is $XDG_CACHE_HOME on Linux and
// ~/Library/Caches on Mac.
PATH_POSIX_END
};
} // namespace butil
#endif // BASE_BASE_PATHS_POSIX_H_
This diff is collapsed.
// Copyright (c) 2012 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 class works with command lines: building and parsing.
// Arguments with prefixes ('--', '-', and on Windows, '/') are switches.
// Switches will precede all other arguments without switch prefixes.
// Switches can optionally have values, delimited by '=', e.g., "-switch=value".
// An argument of "--" will terminate switch parsing during initialization,
// interpreting subsequent tokens as non-switch arguments, regardless of prefix.
// There is a singleton read-only CommandLine that represents the command line
// that the current process was started with. It must be initialized in main().
#ifndef BASE_COMMAND_LINE_H_
#define BASE_COMMAND_LINE_H_
#include <stddef.h>
#include <map>
#include <string>
#include <vector>
#include "butil/base_export.h"
#include "butil/build_config.h"
namespace butil {
class FilePath;
class BASE_EXPORT CommandLine {
public:
#if defined(OS_WIN)
// The native command line string type.
typedef std::wstring StringType;
#elif defined(OS_POSIX)
typedef std::string StringType;
#endif
typedef StringType::value_type CharType;
typedef std::vector<StringType> StringVector;
typedef std::map<std::string, StringType> SwitchMap;
// A constructor for CommandLines that only carry switches and arguments.
enum NoProgram { NO_PROGRAM };
explicit CommandLine(NoProgram no_program);
// Construct a new command line with |program| as argv[0].
explicit CommandLine(const FilePath& program);
// Construct a new command line from an argument list.
CommandLine(int argc, const CharType* const* argv);
explicit CommandLine(const StringVector& argv);
~CommandLine();
#if defined(OS_WIN)
// By default this class will treat command-line arguments beginning with
// slashes as switches on Windows, but not other platforms.
//
// If this behavior is inappropriate for your application, you can call this
// function BEFORE initializing the current process' global command line
// object and the behavior will be the same as Posix systems (only hyphens
// begin switches, everything else will be an arg).
static void set_slash_is_not_a_switch();
#endif
// Initialize the current process CommandLine singleton. On Windows, ignores
// its arguments (we instead parse GetCommandLineW() directly) because we
// don't trust the CRT's parsing of the command line, but it still must be
// called to set up the command line. Returns false if initialization has
// already occurred, and true otherwise. Only the caller receiving a 'true'
// return value should take responsibility for calling Reset.
static bool Init(int argc, const char* const* argv);
// 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).
// If Init is called only once, as in main(), Reset() is not necessary.
static void Reset();
// Get the singleton CommandLine representing the current process's
// command line. Note: returned value is mutable, but not thread safe;
// only mutate if you know what you're doing!
static CommandLine* ForCurrentProcess();
// Returns true if the CommandLine has been initialized for the given process.
static bool InitializedForCurrentProcess();
#if defined(OS_WIN)
static CommandLine FromString(const std::wstring& command_line);
#endif
// Initialize from an argv vector.
void InitFromArgv(int argc, const CharType* const* argv);
void InitFromArgv(const StringVector& argv);
// Constructs and returns the represented command line string.
// CAUTION! This should be avoided on POSIX because quoting behavior is
// unclear.
StringType GetCommandLineString() const;
// Constructs and returns the represented arguments string.
// CAUTION! This should be avoided on POSIX because quoting behavior is
// unclear.
StringType GetArgumentsString() const;
// Returns the original command line string as a vector of strings.
const StringVector& argv() const { return argv_; }
// Get and Set the program part of the command line string (the first item).
FilePath GetProgram() const;
void SetProgram(const FilePath& program);
// Returns true if this command line contains the given switch.
// (Switch names are case-insensitive).
bool HasSwitch(const std::string& switch_string) const;
// Returns the value associated with the given switch. If the switch has no
// value or isn't present, this method returns the empty string.
std::string GetSwitchValueASCII(const std::string& switch_string) const;
FilePath GetSwitchValuePath(const std::string& switch_string) const;
StringType GetSwitchValueNative(const std::string& switch_string) const;
// Get a copy of all switches, along with their values.
const SwitchMap& GetSwitches() const { return switches_; }
// Append a switch [with optional value] to the command line.
// Note: Switches will precede arguments regardless of appending order.
void AppendSwitch(const std::string& switch_string);
void AppendSwitchPath(const std::string& switch_string,
const FilePath& path);
void AppendSwitchNative(const std::string& switch_string,
const StringType& value);
void AppendSwitchASCII(const std::string& switch_string,
const std::string& value);
// Copy a set of switches (and any values) from another command line.
// Commonly used when launching a subprocess.
void CopySwitchesFrom(const CommandLine& source,
const char* const switches[],
size_t count);
// Get the remaining arguments to the command.
StringVector GetArgs() const;
// Append an argument to the command line. Note that the argument is quoted
// properly such that it is interpreted as one argument to the target command.
// AppendArg is primarily for ASCII; non-ASCII input is interpreted as UTF-8.
// Note: Switches will precede arguments regardless of appending order.
void AppendArg(const std::string& value);
void AppendArgPath(const FilePath& value);
void AppendArgNative(const StringType& value);
// Append the switches and arguments from another command line to this one.
// If |include_program| is true, include |other|'s program as well.
void AppendArguments(const CommandLine& other, bool include_program);
// Insert a command before the current command.
// Common for debuggers, like "valgrind" or "gdb --args".
void PrependWrapper(const StringType& wrapper);
#if defined(OS_WIN)
// Initialize by parsing the given command line string.
// The program name is assumed to be the first item in the string.
void ParseFromString(const std::wstring& command_line);
#endif
private:
// Disallow default constructor; a program name must be explicitly specified.
CommandLine();
// Allow the copy constructor. A common pattern is to copy of the current
// process's command line and then add some flags to it. For example:
// CommandLine cl(*CommandLine::ForCurrentProcess());
// cl.AppendSwitch(...);
// The singleton CommandLine representing the current process's command line.
static CommandLine* current_process_commandline_;
// The argv array: { program, [(--|-|/)switch[=value]]*, [--], [argument]* }
StringVector argv_;
// Parsed-out switch keys and values.
SwitchMap switches_;
// The index after the program and switches, any arguments start here.
size_t begin_args_;
};
} // namespace butil
// TODO(brettw) remove once all callers specify the namespace properly.
using butil::CommandLine;
#endif // BASE_COMMAND_LINE_H_
......@@ -43,7 +43,6 @@
#include "butil/strings/stringprintf.h"
#include "butil/strings/sys_string_conversions.h"
#include "butil/strings/utf_string_conversions.h"
#include "butil/sys_info.h"
#include "butil/threading/thread_restrictions.h"
#include "butil/time/time.h"
......
......@@ -60,7 +60,6 @@ typedef pthread_mutex_t* MutexHandle;
#include <string>
#include "butil/file_util.h"
#include "butil/command_line.h"
#include "butil/debug/alias.h"
#include "butil/debug/debugger.h"
#include "butil/debug/stack_trace.h"
......
This diff is collapsed.
This diff is collapsed.
// Copyright (c) 2012 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.
#include "butil/path_service.h"
#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#endif
#include "butil/containers/hash_tables.h"
#include "butil/file_util.h"
#include "butil/files/file_path.h"
#include "butil/lazy_instance.h"
#include "butil/logging.h"
#include "butil/synchronization/lock.h"
using butil::FilePath;
using butil::MakeAbsoluteFilePath;
namespace butil {
bool PathProvider(int key, FilePath* result);
#if defined(OS_WIN)
bool PathProviderWin(int key, FilePath* result);
#elif defined(OS_MACOSX)
bool PathProviderMac(int key, FilePath* result);
#elif defined(OS_ANDROID)
bool PathProviderAndroid(int key, FilePath* result);
#elif defined(OS_POSIX)
// PathProviderPosix is the default path provider on POSIX OSes other than
// Mac and Android.
bool PathProviderPosix(int key, FilePath* result);
#endif
}
namespace {
typedef butil::hash_map<int, FilePath> PathMap;
// We keep a linked list of providers. In a debug build we ensure that no two
// providers claim overlapping keys.
struct Provider {
PathService::ProviderFunc func;
struct Provider* next;
#ifndef NDEBUG
int key_start;
int key_end;
#endif
bool is_static;
};
Provider base_provider = {
butil::PathProvider,
NULL,
#ifndef NDEBUG
butil::PATH_START,
butil::PATH_END,
#endif
true
};
#if defined(OS_WIN)
Provider base_provider_win = {
butil::PathProviderWin,
&base_provider,
#ifndef NDEBUG
butil::PATH_WIN_START,
butil::PATH_WIN_END,
#endif
true
};
#endif
#if defined(OS_MACOSX)
Provider base_provider_mac = {
butil::PathProviderMac,
&base_provider,
#ifndef NDEBUG
butil::PATH_MAC_START,
butil::PATH_MAC_END,
#endif
true
};
#endif
#if defined(OS_ANDROID)
Provider base_provider_android = {
butil::PathProviderAndroid,
&base_provider,
#ifndef NDEBUG
butil::PATH_ANDROID_START,
butil::PATH_ANDROID_END,
#endif
true
};
#endif
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
Provider base_provider_posix = {
butil::PathProviderPosix,
&base_provider,
#ifndef NDEBUG
butil::PATH_POSIX_START,
butil::PATH_POSIX_END,
#endif
true
};
#endif
struct PathData {
butil::Lock lock;
PathMap cache; // Cache mappings from path key to path value.
PathMap overrides; // Track path overrides.
Provider* providers; // Linked list of path service providers.
bool cache_disabled; // Don't use cache if true;
PathData() : cache_disabled(false) {
#if defined(OS_WIN)
providers = &base_provider_win;
#elif defined(OS_MACOSX)
providers = &base_provider_mac;
#elif defined(OS_ANDROID)
providers = &base_provider_android;
#elif defined(OS_POSIX)
providers = &base_provider_posix;
#endif
}
~PathData() {
Provider* p = providers;
while (p) {
Provider* next = p->next;
if (!p->is_static)
delete p;
p = next;
}
}
};
static butil::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
static PathData* GetPathData() {
return g_path_data.Pointer();
}
// Tries to find |key| in the cache. |path_data| should be locked by the caller!
bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) {
if (path_data->cache_disabled)
return false;
// check for a cached version
PathMap::const_iterator it = path_data->cache.find(key);
if (it != path_data->cache.end()) {
*result = it->second;
return true;
}
return false;
}
// Tries to find |key| in the overrides map. |path_data| should be locked by the
// caller!
bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) {
// check for an overridden version.
PathMap::const_iterator it = path_data->overrides.find(key);
if (it != path_data->overrides.end()) {
if (!path_data->cache_disabled)
path_data->cache[key] = it->second;
*result = it->second;
return true;
}
return false;
}
} // namespace
// TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
// characters). This isn't supported very well by Windows right now, so it is
// moot, but we should keep this in mind for the future.
// static
bool PathService::Get(int key, FilePath* result) {
PathData* path_data = GetPathData();
DCHECK(path_data);
DCHECK(result);
DCHECK_GE(key, butil::DIR_CURRENT);
// special case the current directory because it can never be cached
if (key == butil::DIR_CURRENT)
return butil::GetCurrentDirectory(result);
Provider* provider = NULL;
{
butil::AutoLock scoped_lock(path_data->lock);
if (LockedGetFromCache(key, path_data, result))
return true;
if (LockedGetFromOverrides(key, path_data, result))
return true;
// Get the beginning of the list while it is still locked.
provider = path_data->providers;
}
FilePath path;
// Iterating does not need the lock because only the list head might be
// modified on another thread.
while (provider) {
if (provider->func(key, &path))
break;
DCHECK(path.empty()) << "provider should not have modified path";
provider = provider->next;
}
if (path.empty())
return false;
if (path.ReferencesParent()) {
// Make sure path service never returns a path with ".." in it.
path = MakeAbsoluteFilePath(path);
if (path.empty())
return false;
}
*result = path;
butil::AutoLock scoped_lock(path_data->lock);
if (!path_data->cache_disabled)
path_data->cache[key] = path;
return true;
}
// static
bool PathService::Override(int key, const FilePath& path) {
// Just call the full function with true for the value of |create|, and
// assume that |path| may not be absolute yet.
return OverrideAndCreateIfNeeded(key, path, false, true);
}
// static
bool PathService::OverrideAndCreateIfNeeded(int key,
const FilePath& path,
bool is_absolute,
bool create) {
PathData* path_data = GetPathData();
DCHECK(path_data);
DCHECK_GT(key, butil::DIR_CURRENT) << "invalid path key";
FilePath file_path = path;
// For some locations this will fail if called from inside the sandbox there-
// fore we protect this call with a flag.
if (create) {
// Make sure the directory exists. We need to do this before we translate
// this to the absolute path because on POSIX, MakeAbsoluteFilePath fails
// if called on a non-existent path.
if (!butil::PathExists(file_path) &&
!butil::CreateDirectory(file_path))
return false;
}
// We need to have an absolute path.
if (!is_absolute) {
file_path = MakeAbsoluteFilePath(file_path);
if (file_path.empty())
return false;
}
DCHECK(file_path.IsAbsolute());
butil::AutoLock scoped_lock(path_data->lock);
// Clear the cache now. Some of its entries could have depended
// on the value we are overriding, and are now out of sync with reality.
path_data->cache.clear();
path_data->overrides[key] = file_path;
return true;
}
// static
bool PathService::RemoveOverride(int key) {
PathData* path_data = GetPathData();
DCHECK(path_data);
butil::AutoLock scoped_lock(path_data->lock);
if (path_data->overrides.find(key) == path_data->overrides.end())
return false;
// Clear the cache now. Some of its entries could have depended on the value
// we are going to remove, and are now out of sync.
path_data->cache.clear();
path_data->overrides.erase(key);
return true;
}
// static
void PathService::RegisterProvider(ProviderFunc func, int key_start,
int key_end) {
PathData* path_data = GetPathData();
DCHECK(path_data);
DCHECK_GT(key_end, key_start);
Provider* p;
p = new Provider;
p->is_static = false;
p->func = func;
#ifndef NDEBUG
p->key_start = key_start;
p->key_end = key_end;
#endif
butil::AutoLock scoped_lock(path_data->lock);
#ifndef NDEBUG
Provider *iter = path_data->providers;
while (iter) {
DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) <<
"path provider collision";
iter = iter->next;
}
#endif
p->next = path_data->providers;
path_data->providers = p;
}
// static
void PathService::DisableCache() {
PathData* path_data = GetPathData();
DCHECK(path_data);
butil::AutoLock scoped_lock(path_data->lock);
path_data->cache.clear();
path_data->cache_disabled = true;
}
// Copyright (c) 2012 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_PATH_SERVICE_H_
#define BASE_PATH_SERVICE_H_
#include <string>
#include "butil/base_export.h"
#include "butil/base_paths.h"
#include "butil/gtest_prod_util.h"
#include "butil/build_config.h"
namespace butil {
class FilePath;
class ScopedPathOverride;
} // namespace
// The path service is a global table mapping keys to file system paths. It is
// OK to use this service from multiple threads.
//
class BASE_EXPORT PathService {
public:
// Retrieves a path to a special directory or file and places it into the
// string pointed to by 'path'. If you ask for a directory it is guaranteed
// to NOT have a path separator at the end. For example, "c:\windows\temp"
// Directories are also guaranteed to exist when this function succeeds.
//
// Returns true if the directory or file was successfully retrieved. On
// failure, 'path' will not be changed.
static bool Get(int key, butil::FilePath* path);
// Overrides the path to a special directory or file. This cannot be used to
// change the value of DIR_CURRENT, but that should be obvious. Also, if the
// path specifies a directory that does not exist, the directory will be
// created by this method. This method returns true if successful.
//
// If the given path is relative, then it will be resolved against
// DIR_CURRENT.
//
// WARNING: Consumers of PathService::Get may expect paths to be constant
// over the lifetime of the app, so this method should be used with caution.
//
// Unit tests generally should use ScopedPathOverride instead. Overrides from
// one test should not carry over to another.
static bool Override(int key, const butil::FilePath& path);
// This function does the same as PathService::Override but it takes extra
// parameters:
// - |is_absolute| indicates that |path| has already been expanded into an
// absolute path, otherwise MakeAbsoluteFilePath() will be used. This is
// useful to override paths that may not exist yet, since MakeAbsoluteFilePath
// fails for those. Note that MakeAbsoluteFilePath also expands symbolic
// links, even if path.IsAbsolute() is already true.
// - |create| guides whether the directory to be overriden must
// be created in case it doesn't exist already.
static bool OverrideAndCreateIfNeeded(int key,
const butil::FilePath& path,
bool is_absolute,
bool create);
// To extend the set of supported keys, you can register a path provider,
// which is just a function mirroring PathService::Get. The ProviderFunc
// returns false if it cannot provide a non-empty path for the given key.
// Otherwise, true is returned.
//
// WARNING: This function could be called on any thread from which the
// PathService is used, so a the ProviderFunc MUST BE THREADSAFE.
//
typedef bool (*ProviderFunc)(int, butil::FilePath*);
// Call to register a path provider. You must specify the range "[key_start,
// key_end)" of supported path keys.
static void RegisterProvider(ProviderFunc provider,
int key_start,
int key_end);
// Disable internal cache.
static void DisableCache();
private:
friend class butil::ScopedPathOverride;
FRIEND_TEST_ALL_PREFIXES(PathServiceTest, RemoveOverride);
// Removes an override for a special directory or file. Returns true if there
// was an override to remove or false if none was present.
// NOTE: This function is intended to be used by tests only!
static bool RemoveOverride(int key);
};
#endif // BASE_PATH_SERVICE_H_
// Copyright (c) 2012 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.
#include "butil/process/internal_linux.h"
#include <unistd.h>
#include <map>
#include <string>
#include <vector>
#include "butil/file_util.h"
#include "butil/logging.h"
#include "butil/strings/string_number_conversions.h"
#include "butil/strings/string_split.h"
#include "butil/strings/string_util.h"
#include "butil/threading/thread_restrictions.h"
#include "butil/time/time.h"
namespace butil {
namespace internal {
const char kProcDir[] = "/proc";
const char kStatFile[] = "stat";
butil::FilePath GetProcPidDir(pid_t pid) {
return butil::FilePath(kProcDir).Append(IntToString(pid));
}
pid_t ProcDirSlotToPid(const char* d_name) {
int i;
for (i = 0; i < NAME_MAX && d_name[i]; ++i) {
if (!IsAsciiDigit(d_name[i])) {
return 0;
}
}
if (i == NAME_MAX)
return 0;
// Read the process's command line.
pid_t pid;
std::string pid_string(d_name);
if (!StringToInt(pid_string, &pid)) {
NOTREACHED();
return 0;
}
return pid;
}
bool ReadProcFile(const FilePath& file, std::string* buffer) {
buffer->clear();
// Synchronously reading files in /proc is safe.
ThreadRestrictions::ScopedAllowIO allow_io;
if (!ReadFileToString(file, buffer)) {
DLOG(WARNING) << "Failed to read " << file.MaybeAsASCII();
return false;
}
return !buffer->empty();
}
bool ReadProcStats(pid_t pid, std::string* buffer) {
FilePath stat_file = internal::GetProcPidDir(pid).Append(kStatFile);
return ReadProcFile(stat_file, buffer);
}
bool ParseProcStats(const std::string& stats_data,
std::vector<std::string>* proc_stats) {
// |stats_data| may be empty if the process disappeared somehow.
// e.g. http://crbug.com/145811
if (stats_data.empty())
return false;
// The stat file is formatted as:
// pid (process name) data1 data2 .... dataN
// Look for the closing paren by scanning backwards, to avoid being fooled by
// processes with ')' in the name.
size_t open_parens_idx = stats_data.find(" (");
size_t close_parens_idx = stats_data.rfind(") ");
if (open_parens_idx == std::string::npos ||
close_parens_idx == std::string::npos ||
open_parens_idx > close_parens_idx) {
DLOG(WARNING) << "Failed to find matched parens in '" << stats_data << "'";
NOTREACHED();
return false;
}
open_parens_idx++;
proc_stats->clear();
// PID.
proc_stats->push_back(stats_data.substr(0, open_parens_idx));
// Process name without parentheses.
proc_stats->push_back(
stats_data.substr(open_parens_idx + 1,
close_parens_idx - (open_parens_idx + 1)));
// Split the rest.
std::vector<std::string> other_stats;
SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats);
for (size_t i = 0; i < other_stats.size(); ++i)
proc_stats->push_back(other_stats[i]);
return true;
}
typedef std::map<std::string, std::string> ProcStatMap;
void ParseProcStat(const std::string& contents, ProcStatMap* output) {
typedef std::pair<std::string, std::string> StringPair;
std::vector<StringPair> key_value_pairs;
SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs);
for (size_t i = 0; i < key_value_pairs.size(); ++i) {
const StringPair& key_value_pair = key_value_pairs[i];
output->insert(key_value_pair);
}
}
int64_t GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
ProcStatsFields field_num) {
DCHECK_GE(field_num, VM_PPID);
CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
int64_t value;
return StringToInt64(proc_stats[field_num], &value) ? value : 0;
}
size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
ProcStatsFields field_num) {
DCHECK_GE(field_num, VM_PPID);
CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
size_t value;
return StringToSizeT(proc_stats[field_num], &value) ? value : 0;
}
int64_t ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num) {
std::string stats_data;
if (!ReadProcStats(pid, &stats_data))
return 0;
std::vector<std::string> proc_stats;
if (!ParseProcStats(stats_data, &proc_stats))
return 0;
return GetProcStatsFieldAsInt64(proc_stats, field_num);
}
size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid,
ProcStatsFields field_num) {
std::string stats_data;
if (!ReadProcStats(pid, &stats_data))
return 0;
std::vector<std::string> proc_stats;
if (!ParseProcStats(stats_data, &proc_stats))
return 0;
return GetProcStatsFieldAsSizeT(proc_stats, field_num);
}
Time GetBootTime() {
FilePath path("/proc/stat");
std::string contents;
if (!ReadProcFile(path, &contents))
return Time();
ProcStatMap proc_stat;
ParseProcStat(contents, &proc_stat);
ProcStatMap::const_iterator btime_it = proc_stat.find("btime");
if (btime_it == proc_stat.end())
return Time();
int btime;
if (!StringToInt(btime_it->second, &btime))
return Time();
return Time::FromTimeT(btime);
}
TimeDelta ClockTicksToTimeDelta(int clock_ticks) {
// This queries the /proc-specific scaling factor which is
// conceptually the system hertz. To dump this value on another
// system, try
// od -t dL /proc/self/auxv
// and look for the number after 17 in the output; mine is
// 0000040 17 100 3 134512692
// which means the answer is 100.
// It may be the case that this value is always 100.
static const int kHertz = sysconf(_SC_CLK_TCK);
return TimeDelta::FromMicroseconds(
Time::kMicrosecondsPerSecond * clock_ticks / kHertz);
}
} // namespace internal
} // namespace butil
// Copyright (c) 2013 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 contains internal routines that are called by other files in
// butil/process/.
#ifndef BASE_PROCESS_LINUX_INTERNAL_H_
#define BASE_PROCESS_LINUX_INTERNAL_H_
#include <unistd.h>
#include "butil/files/file_path.h"
namespace butil {
class Time;
class TimeDelta;
namespace internal {
// "/proc"
extern const char kProcDir[];
// "stat"
extern const char kStatFile[];
// Returns a FilePath to "/proc/pid".
butil::FilePath GetProcPidDir(pid_t pid);
// Take a /proc directory entry named |d_name|, and if it is the directory for
// a process, convert it to a pid_t.
// Returns 0 on failure.
// e.g. /proc/self/ will return 0, whereas /proc/1234 will return 1234.
pid_t ProcDirSlotToPid(const char* d_name);
// Reads /proc/<pid>/stat into |buffer|. Returns true if the file can be read
// and is non-empty.
bool ReadProcStats(pid_t pid, std::string* buffer);
// Takes |stats_data| and populates |proc_stats| with the values split by
// spaces. Taking into account the 2nd field may, in itself, contain spaces.
// Returns true if successful.
bool ParseProcStats(const std::string& stats_data,
std::vector<std::string>* proc_stats);
// Fields from /proc/<pid>/stat, 0-based. See man 5 proc.
// If the ordering ever changes, carefully review functions that use these
// values.
enum ProcStatsFields {
VM_COMM = 1, // Filename of executable, without parentheses.
VM_STATE = 2, // Letter indicating the state of the process.
VM_PPID = 3, // PID of the parent.
VM_PGRP = 4, // Process group id.
VM_UTIME = 13, // Time scheduled in user mode in clock ticks.
VM_STIME = 14, // Time scheduled in kernel mode in clock ticks.
VM_NUMTHREADS = 19, // Number of threads.
VM_STARTTIME = 21, // The time the process started in clock ticks.
VM_VSIZE = 22, // Virtual memory size in bytes.
VM_RSS = 23, // Resident Set Size in pages.
};
// Reads the |field_num|th field from |proc_stats|. Returns 0 on failure.
// This version does not handle the first 3 values, since the first value is
// simply |pid|, and the next two values are strings.
int64_t GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
ProcStatsFields field_num);
// Same as GetProcStatsFieldAsInt64(), but for size_t values.
size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
ProcStatsFields field_num);
// Convenience wrapper around GetProcStatsFieldAsInt64(), ParseProcStats() and
// ReadProcStats(). See GetProcStatsFieldAsInt64() for details.
int64_t ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num);
// Same as ReadProcStatsAndGetFieldAsInt64() but for size_t values.
size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid,
ProcStatsFields field_num);
// Returns the time that the OS started. Clock ticks are relative to this.
Time GetBootTime();
// Converts Linux clock ticks to a wall time delta.
TimeDelta ClockTicksToTimeDelta(int clock_ticks);
} // namespace internal
} // namespace butil
#endif // BASE_PROCESS_LINUX_INTERNAL_H_
// Copyright (c) 2013 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.
#include "butil/process/kill.h"
#include "butil/process/process_iterator.h"
namespace butil {
bool KillProcesses(const FilePath::StringType& executable_name,
int exit_code,
const ProcessFilter* filter) {
bool result = true;
NamedProcessIterator iter(executable_name, filter);
while (const ProcessEntry* entry = iter.NextProcessEntry()) {
#if defined(OS_WIN)
result &= KillProcessById(entry->pid(), exit_code, true);
#else
result &= KillProcess(entry->pid(), exit_code, true);
#endif
}
return result;
}
} // namespace butil
// Copyright (c) 2013 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 contains routines to kill processes and get the exit code and
// termination status.
#ifndef BASE_PROCESS_KILL_H_
#define BASE_PROCESS_KILL_H_
#include "butil/files/file_path.h"
#include "butil/process/process_handle.h"
#include "butil/time/time.h"
namespace butil {
class ProcessFilter;
// Return status values from GetTerminationStatus. Don't use these as
// exit code arguments to KillProcess*(), use platform/application
// specific values instead.
enum TerminationStatus {
TERMINATION_STATUS_NORMAL_TERMINATION, // zero exit status
TERMINATION_STATUS_ABNORMAL_TERMINATION, // non-zero exit status
TERMINATION_STATUS_PROCESS_WAS_KILLED, // e.g. SIGKILL or task manager kill
TERMINATION_STATUS_PROCESS_CRASHED, // e.g. Segmentation fault
TERMINATION_STATUS_STILL_RUNNING, // child hasn't exited yet
#if defined(OS_ANDROID)
// On Android processes are spawned from the system Zygote and we do not get
// the termination status. We can't know if the termination was a crash or an
// oom kill for sure, but we can use status of the strong process bindings as
// a hint.
TERMINATION_STATUS_OOM_PROTECTED, // child was protected from oom kill
#endif
TERMINATION_STATUS_MAX_ENUM
};
// Attempts to kill all the processes on the current machine that were launched
// from the given executable name, ending them with the given exit code. If
// filter is non-null, then only processes selected by the filter are killed.
// Returns true if all processes were able to be killed off, false if at least
// one couldn't be killed.
BASE_EXPORT bool KillProcesses(const FilePath::StringType& executable_name,
int exit_code,
const ProcessFilter* filter);
// Attempts to kill the process identified by the given process
// entry structure, giving it the specified exit code. If |wait| is true, wait
// for the process to be actually terminated before returning.
// Returns true if this is successful, false otherwise.
BASE_EXPORT bool KillProcess(ProcessHandle process, int exit_code, bool wait);
#if defined(OS_POSIX)
// Attempts to kill the process group identified by |process_group_id|. Returns
// true on success.
BASE_EXPORT bool KillProcessGroup(ProcessHandle process_group_id);
#endif // defined(OS_POSIX)
#if defined(OS_WIN)
BASE_EXPORT bool KillProcessById(ProcessId process_id,
int exit_code,
bool wait);
#endif // defined(OS_WIN)
// Get the termination status of the process by interpreting the
// circumstances of the child process' death. |exit_code| is set to
// the status returned by waitpid() on POSIX, and from
// GetExitCodeProcess() on Windows. |exit_code| may be NULL if the
// caller is not interested in it. Note that on Linux, this function
// will only return a useful result the first time it is called after
// the child exits (because it will reap the child and the information
// will no longer be available).
BASE_EXPORT TerminationStatus GetTerminationStatus(ProcessHandle handle,
int* exit_code);
#if defined(OS_POSIX)
// Send a kill signal to the process and then wait for the process to exit
// and get the termination status.
//
// This is used in situations where it is believed that the process is dead
// or dying (because communication with the child process has been cut).
// In order to avoid erroneously returning that the process is still running
// because the kernel is still cleaning it up, this will wait for the process
// to terminate. In order to avoid the risk of hanging while waiting for the
// process to terminate, send a SIGKILL to the process before waiting for the
// termination status.
//
// Note that it is not an option to call WaitForExitCode and then
// GetTerminationStatus as the child will be reaped when WaitForExitCode
// returns, and this information will be lost.
//
BASE_EXPORT TerminationStatus GetKnownDeadTerminationStatus(
ProcessHandle handle, int* exit_code);
#endif // defined(OS_POSIX)
// Waits for process to exit. On POSIX systems, if the process hasn't been
// signaled then puts the exit code in |exit_code|; otherwise it's considered
// a failure. On Windows |exit_code| is always filled. Returns true on success,
// and closes |handle| in any case.
BASE_EXPORT bool WaitForExitCode(ProcessHandle handle, int* exit_code);
// Waits for process to exit. If it did exit within |timeout_milliseconds|,
// then puts the exit code in |exit_code|, and returns true.
// In POSIX systems, if the process has been signaled then |exit_code| is set
// to -1. Returns false on failure (the caller is then responsible for closing
// |handle|).
// The caller is always responsible for closing the |handle|.
BASE_EXPORT bool WaitForExitCodeWithTimeout(ProcessHandle handle,
int* exit_code,
butil::TimeDelta timeout);
// Wait for all the processes based on the named executable to exit. If filter
// is non-null, then only processes selected by the filter are waited on.
// Returns after all processes have exited or wait_milliseconds have expired.
// Returns true if all the processes exited, false otherwise.
BASE_EXPORT bool WaitForProcessesToExit(
const FilePath::StringType& executable_name,
butil::TimeDelta wait,
const ProcessFilter* filter);
// Wait for a single process to exit. Return true if it exited cleanly within
// the given time limit. On Linux |handle| must be a child process, however
// on Mac and Windows it can be any process.
BASE_EXPORT bool WaitForSingleProcess(ProcessHandle handle,
butil::TimeDelta wait);
// Waits a certain amount of time (can be 0) for all the processes with a given
// executable name to exit, then kills off any of them that are still around.
// If filter is non-null, then only processes selected by the filter are waited
// on. Killed processes are ended with the given exit code. Returns false if
// any processes needed to be killed, true if they all exited cleanly within
// the wait_milliseconds delay.
BASE_EXPORT bool CleanupProcesses(const FilePath::StringType& executable_name,
butil::TimeDelta wait,
int exit_code,
const ProcessFilter* filter);
// This method ensures that the specified process eventually terminates, and
// then it closes the given process handle.
//
// It assumes that the process has already been signalled to exit, and it
// begins by waiting a small amount of time for it to exit. If the process
// does not appear to have exited, then this function starts to become
// aggressive about ensuring that the process terminates.
//
// On Linux this method does not block the calling thread.
// On OS X this method may block for up to 2 seconds.
//
// NOTE: The process handle must have been opened with the PROCESS_TERMINATE
// and SYNCHRONIZE permissions.
//
BASE_EXPORT void EnsureProcessTerminated(ProcessHandle process_handle);
#if defined(OS_POSIX) && !defined(OS_MACOSX)
// The nicer version of EnsureProcessTerminated() that is patient and will
// wait for |process_handle| to finish and then reap it.
BASE_EXPORT void EnsureProcessGetsReaped(ProcessHandle process_handle);
#endif
} // namespace butil
#endif // BASE_PROCESS_KILL_H_
// Copyright (c) 2013 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.
#include "butil/process/kill.h"
#include <signal.h>
#include <sys/event.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "butil/file_util.h"
#include "butil/files/scoped_file.h"
#include "butil/logging.h"
#include "butil/posix/eintr_wrapper.h"
namespace butil {
namespace {
const int kWaitBeforeKillSeconds = 2;
// Reap |child| process. This call blocks until completion.
void BlockingReap(pid_t child) {
const pid_t result = HANDLE_EINTR(waitpid(child, NULL, 0));
if (result == -1) {
DPLOG(ERROR) << "waitpid(" << child << ", NULL, 0)";
}
}
// Waits for |timeout| seconds for the given |child| to exit and reap it. If
// the child doesn't exit within the time specified, kills it.
//
// This function takes two approaches: first, it tries to use kqueue to
// observe when the process exits. kevent can monitor a kqueue with a
// timeout, so this method is preferred to wait for a specified period of
// time. Once the kqueue indicates the process has exited, waitpid will reap
// the exited child. If the kqueue doesn't provide an exit event notification,
// before the timeout expires, or if the kqueue fails or misbehaves, the
// process will be mercilessly killed and reaped.
//
// A child process passed to this function may be in one of several states:
// running, terminated and not yet reaped, and (apparently, and unfortunately)
// terminated and already reaped. Normally, a process will at least have been
// asked to exit before this function is called, but this is not required.
// If a process is terminating and unreaped, there may be a window between the
// time that kqueue will no longer recognize it and when it becomes an actual
// zombie that a non-blocking (WNOHANG) waitpid can reap. This condition is
// detected when kqueue indicates that the process is not running and a
// non-blocking waitpid fails to reap the process but indicates that it is
// still running. In this event, a blocking attempt to reap the process
// collects the known-dying child, preventing zombies from congregating.
//
// In the event that the kqueue misbehaves entirely, as it might under a
// EMFILE condition ("too many open files", or out of file descriptors), this
// function will forcibly kill and reap the child without delay. This
// eliminates another potential zombie vector. (If you're out of file
// descriptors, you're probably deep into something else, but that doesn't
// mean that zombies be allowed to kick you while you're down.)
//
// The fact that this function seemingly can be called to wait on a child
// that's not only already terminated but already reaped is a bit of a
// problem: a reaped child's pid can be reclaimed and may refer to a distinct
// process in that case. The fact that this function can seemingly be called
// to wait on a process that's not even a child is also a problem: kqueue will
// work in that case, but waitpid won't, and killing a non-child might not be
// the best approach.
void WaitForChildToDie(pid_t child, int timeout) {
DCHECK(child > 0);
DCHECK(timeout > 0);
// DON'T ADD ANY EARLY RETURNS TO THIS FUNCTION without ensuring that
// |child| has been reaped. Specifically, even if a kqueue, kevent, or other
// call fails, this function should fall back to the last resort of trying
// to kill and reap the process. Not observing this rule will resurrect
// zombies.
int result;
ScopedFD kq(HANDLE_EINTR(kqueue()));
if (!kq.is_valid()) {
DPLOG(ERROR) << "kqueue()";
} else {
struct kevent change = {0};
EV_SET(&change, child, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
if (result == -1) {
if (errno != ESRCH) {
DPLOG(ERROR) << "kevent (setup " << child << ")";
} else {
// At this point, one of the following has occurred:
// 1. The process has died but has not yet been reaped.
// 2. The process has died and has already been reaped.
// 3. The process is in the process of dying. It's no longer
// kqueueable, but it may not be waitable yet either. Mark calls
// this case the "zombie death race".
result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
if (result != 0) {
// A positive result indicates case 1. waitpid succeeded and reaped
// the child. A result of -1 indicates case 2. The child has already
// been reaped. In both of these cases, no further action is
// necessary.
return;
}
// |result| is 0, indicating case 3. The process will be waitable in
// short order. Fall back out of the kqueue code to kill it (for good
// measure) and reap it.
}
} else {
// Keep track of the elapsed time to be able to restart kevent if it's
// interrupted.
TimeDelta remaining_delta = TimeDelta::FromSeconds(timeout);
TimeTicks deadline = TimeTicks::Now() + remaining_delta;
result = -1;
struct kevent event = {0};
while (remaining_delta.InMilliseconds() > 0) {
const struct timespec remaining_timespec = remaining_delta.ToTimeSpec();
result = kevent(kq.get(), NULL, 0, &event, 1, &remaining_timespec);
if (result == -1 && errno == EINTR) {
remaining_delta = deadline - TimeTicks::Now();
result = 0;
} else {
break;
}
}
if (result == -1) {
DPLOG(ERROR) << "kevent (wait " << child << ")";
} else if (result > 1) {
DLOG(ERROR) << "kevent (wait " << child << "): unexpected result "
<< result;
} else if (result == 1) {
if ((event.fflags & NOTE_EXIT) &&
(event.ident == static_cast<uintptr_t>(child))) {
// The process is dead or dying. This won't block for long, if at
// all.
BlockingReap(child);
return;
} else {
DLOG(ERROR) << "kevent (wait " << child
<< "): unexpected event: fflags=" << event.fflags
<< ", ident=" << event.ident;
}
}
}
}
// The child is still alive, or is very freshly dead. Be sure by sending it
// a signal. This is safe even if it's freshly dead, because it will be a
// zombie (or on the way to zombiedom) and kill will return 0 even if the
// signal is not delivered to a live process.
result = kill(child, SIGKILL);
if (result == -1) {
DPLOG(ERROR) << "kill(" << child << ", SIGKILL)";
} else {
// The child is definitely on the way out now. BlockingReap won't need to
// wait for long, if at all.
BlockingReap(child);
}
}
} // namespace
void EnsureProcessTerminated(ProcessHandle process) {
WaitForChildToDie(process, kWaitBeforeKillSeconds);
}
} // namespace butil
This diff is collapsed.
// Copyright (c) 2013 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.
#include "butil/process/launch.h"
namespace butil {
LaunchOptions::LaunchOptions()
: wait(false),
#if defined(OS_WIN)
start_hidden(false),
handles_to_inherit(NULL),
inherit_handles(false),
as_user(NULL),
empty_desktop_name(false),
job_handle(NULL),
stdin_handle(NULL),
stdout_handle(NULL),
stderr_handle(NULL),
force_breakaway_from_job_(false)
#else
clear_environ(false),
fds_to_remap(NULL),
maximize_rlimits(NULL),
new_process_group(false)
#if defined(OS_LINUX)
, clone_flags(0)
, allow_new_privs(false)
#endif // OS_LINUX
#if defined(OS_CHROMEOS)
, ctrl_terminal_fd(-1)
#endif // OS_CHROMEOS
#endif // !defined(OS_WIN)
{
}
LaunchOptions::~LaunchOptions() {
}
LaunchOptions LaunchOptionsForTest() {
LaunchOptions options;
#if defined(OS_LINUX)
// To prevent accidental privilege sharing to an untrusted child, processes
// are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this
// new child will be used for testing only.
options.allow_new_privs = true;
#endif
return options;
}
} // namespace butil
This diff is collapsed.
// Copyright (c) 2012 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.
#include "butil/process/launch.h"
#include <mach/mach.h>
#include <servers/bootstrap.h>
#include "butil/logging.h"
namespace butil {
void RestoreDefaultExceptionHandler() {
// This function is tailored to remove the Breakpad exception handler.
// exception_mask matches s_exception_mask in
// breakpad/src/client/mac/handler/exception_handler.cc
const exception_mask_t exception_mask = EXC_MASK_BAD_ACCESS |
EXC_MASK_BAD_INSTRUCTION |
EXC_MASK_ARITHMETIC |
EXC_MASK_BREAKPOINT;
// Setting the exception port to MACH_PORT_NULL may not be entirely
// kosher to restore the default exception handler, but in practice,
// it results in the exception port being set to Apple Crash Reporter,
// the desired behavior.
task_set_exception_ports(mach_task_self(), exception_mask, MACH_PORT_NULL,
EXCEPTION_DEFAULT, THREAD_STATE_NONE);
}
void ReplaceBootstrapPort(const std::string& new_bootstrap_name) {
// This function is called between fork() and exec(), so it should take care
// to run properly in that situation.
mach_port_t port = MACH_PORT_NULL;
kern_return_t kr = bootstrap_look_up(bootstrap_port,
new_bootstrap_name.c_str(), &port);
if (kr != KERN_SUCCESS) {
RAW_LOG(FATAL, "Failed to look up replacement bootstrap port.");
}
kr = task_set_bootstrap_port(mach_task_self(), port);
if (kr != KERN_SUCCESS) {
RAW_LOG(FATAL, "Failed to replace bootstrap port.");
}
}
} // namespace butil
This diff is collapsed.
// Copyright 2014 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.
#include "butil/process/memory.h"
namespace butil {
// Defined in memory_mac.mm for Mac.
#if !defined(OS_MACOSX)
bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
const size_t alloc_size = num_items * size;
// Overflow check
if (size && ((alloc_size / size) != num_items)) {
*result = NULL;
return false;
}
if (!UncheckedMalloc(alloc_size, result))
return false;
memset(*result, 0, alloc_size);
return true;
}
#endif
}
// Copyright (c) 2013 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_PROCESS_MEMORY_H_
#define BASE_PROCESS_MEMORY_H_
#include "butil/base_export.h"
#include "butil/basictypes.h"
#include "butil/process/process_handle.h"
#include "butil/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
#ifdef PVALLOC_AVAILABLE
// Build config explicitly tells us whether or not pvalloc is available.
#elif defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
#define PVALLOC_AVAILABLE 1
#else
#define PVALLOC_AVAILABLE 0
#endif
namespace butil {
// Enables low fragmentation heap (LFH) for every heaps of this process. This
// won't have any effect on heaps created after this function call. It will not
// modify data allocated in the heaps before calling this function. So it is
// better to call this function early in initialization and again before
// entering the main loop.
// Note: Returns true on Windows 2000 without doing anything.
BASE_EXPORT bool EnableLowFragmentationHeap();
// Enables 'terminate on heap corruption' flag. Helps protect against heap
// overflow. Has no effect if the OS doesn't provide the necessary facility.
BASE_EXPORT void EnableTerminationOnHeapCorruption();
// Turns on process termination if memory runs out.
BASE_EXPORT void EnableTerminationOnOutOfMemory();
#if defined(OS_WIN)
// Returns the module handle to which an address belongs. The reference count
// of the module is not incremented.
BASE_EXPORT HMODULE GetModuleFromAddress(void* address);
#endif
#if defined(OS_LINUX) || defined(OS_ANDROID)
BASE_EXPORT extern size_t g_oom_size;
// The maximum allowed value for the OOM score.
const int kMaxOomScore = 1000;
// This adjusts /proc/<pid>/oom_score_adj so the Linux OOM killer will
// prefer to kill certain process types over others. The range for the
// adjustment is [-1000, 1000], with [0, 1000] being user accessible.
// If the Linux system doesn't support the newer oom_score_adj range
// of [0, 1000], then we revert to using the older oom_adj, and
// translate the given value into [0, 15]. Some aliasing of values
// may occur in that case, of course.
BASE_EXPORT bool AdjustOOMScore(ProcessId process, int score);
#endif
// Special allocator functions for callers that want to check for OOM.
// These will not abort if the allocation fails even if
// EnableTerminationOnOutOfMemory has been called.
// This can be useful for huge and/or unpredictable size memory allocations.
// Please only use this if you really handle the case when the allocation
// fails. Doing otherwise would risk security.
// These functions may still crash on OOM when running under memory tools,
// specifically ASan and other sanitizers.
// Return value tells whether the allocation succeeded. If it fails |result| is
// set to NULL, otherwise it holds the memory address.
BASE_EXPORT WARN_UNUSED_RESULT bool UncheckedMalloc(size_t size,
void** result);
BASE_EXPORT WARN_UNUSED_RESULT bool UncheckedCalloc(size_t num_items,
size_t size,
void** result);
} // namespace butil
#endif // BASE_PROCESS_MEMORY_H_
// Copyright (c) 2013 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.
#include "butil/process/memory.h"
#include <new>
#include "butil/file_util.h"
#include "butil/files/file_path.h"
#include "butil/logging.h"
#include "butil/process/internal_linux.h"
#include "butil/strings/string_number_conversions.h"
#if defined(USE_TCMALLOC)
// Used by UncheckedMalloc. If tcmalloc is linked to the executable
// this will be replaced by a strong symbol that actually implement
// the semantics and don't call new handler in case the allocation fails.
extern "C" {
__attribute__((weak, visibility("default")))
void* tc_malloc_skip_new_handler_weak(size_t size);
void* tc_malloc_skip_new_handler_weak(size_t size) {
return malloc(size);
}
}
#endif
namespace butil {
size_t g_oom_size = 0U;
namespace {
#if !defined(OS_ANDROID)
void OnNoMemorySize(size_t size) {
g_oom_size = size;
if (size != 0)
LOG(FATAL) << "Out of memory, size = " << size;
LOG(FATAL) << "Out of memory.";
}
void OnNoMemory() {
OnNoMemorySize(0);
}
#endif // !defined(OS_ANDROID)
} // namespace
#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
!defined(THREAD_SANITIZER) && !defined(LEAK_SANITIZER)
#if defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
extern "C" {
void* __libc_malloc(size_t size);
void* __libc_realloc(void* ptr, size_t size);
void* __libc_calloc(size_t nmemb, size_t size);
void* __libc_valloc(size_t size);
#if PVALLOC_AVAILABLE == 1
void* __libc_pvalloc(size_t size);
#endif
void* __libc_memalign(size_t alignment, size_t size);
// Overriding the system memory allocation functions:
//
// For security reasons, we want malloc failures to be fatal. Too much code
// doesn't check for a NULL return value from malloc and unconditionally uses
// the resulting pointer. If the first offset that they try to access is
// attacker controlled, then the attacker can direct the code to access any
// part of memory.
//
// Thus, we define all the standard malloc functions here and mark them as
// visibility 'default'. This means that they replace the malloc functions for
// all Chromium code and also for all code in shared libraries. There are tests
// for this in process_util_unittest.cc.
//
// If we are using tcmalloc, then the problem is moot since tcmalloc handles
// this for us. Thus this code is in a !defined(USE_TCMALLOC) block.
//
// If we are testing the binary with AddressSanitizer, we should not
// redefine malloc and let AddressSanitizer do it instead.
//
// We call the real libc functions in this code by using __libc_malloc etc.
// Previously we tried using dlsym(RTLD_NEXT, ...) but that failed depending on
// the link order. Since ld.so needs calloc during symbol resolution, it
// defines its own versions of several of these functions in dl-minimal.c.
// Depending on the runtime library order, dlsym ended up giving us those
// functions and bad things happened. See crbug.com/31809
//
// This means that any code which calls __libc_* gets the raw libc versions of
// these functions.
#define DIE_ON_OOM_1(function_name) \
void* function_name(size_t) __attribute__ ((visibility("default"))); \
\
void* function_name(size_t size) { \
void* ret = __libc_##function_name(size); \
if (ret == NULL && size != 0) \
OnNoMemorySize(size); \
return ret; \
}
#define DIE_ON_OOM_2(function_name, arg1_type) \
void* function_name(arg1_type, size_t) \
__attribute__ ((visibility("default"))); \
\
void* function_name(arg1_type arg1, size_t size) { \
void* ret = __libc_##function_name(arg1, size); \
if (ret == NULL && size != 0) \
OnNoMemorySize(size); \
return ret; \
}
DIE_ON_OOM_1(malloc)
DIE_ON_OOM_1(valloc)
#if PVALLOC_AVAILABLE == 1
DIE_ON_OOM_1(pvalloc)
#endif
DIE_ON_OOM_2(calloc, size_t)
DIE_ON_OOM_2(realloc, void*)
DIE_ON_OOM_2(memalign, size_t)
// posix_memalign has a unique signature and doesn't have a __libc_ variant.
int posix_memalign(void** ptr, size_t alignment, size_t size)
__attribute__ ((visibility("default")));
int posix_memalign(void** ptr, size_t alignment, size_t size) {
// This will use the safe version of memalign, above.
*ptr = memalign(alignment, size);
return 0;
}
} // extern C
#else
// TODO(mostynb@opera.com): dlsym dance
#endif // LIBC_GLIBC && !USE_TCMALLOC
#endif // !*_SANITIZER
void EnableTerminationOnHeapCorruption() {
// On Linux, there nothing to do AFAIK.
}
void EnableTerminationOnOutOfMemory() {
#if defined(OS_ANDROID)
// Android doesn't support setting a new handler.
DLOG(WARNING) << "Not feasible.";
#else
// Set the new-out of memory handler.
std::set_new_handler(&OnNoMemory);
// If we're using glibc's allocator, the above functions will override
// malloc and friends and make them die on out of memory.
#endif
}
// NOTE: This is not the only version of this function in the source:
// the setuid sandbox (in process_util_linux.c, in the sandbox source)
// also has its own C version.
bool AdjustOOMScore(ProcessId process, int score) {
if (score < 0 || score > kMaxOomScore)
return false;
FilePath oom_path(internal::GetProcPidDir(process));
// Attempt to write the newer oom_score_adj file first.
FilePath oom_file = oom_path.AppendASCII("oom_score_adj");
if (PathExists(oom_file)) {
std::string score_str = IntToString(score);
DVLOG(1) << "Adjusting oom_score_adj of " << process << " to "
<< score_str;
int score_len = static_cast<int>(score_str.length());
return (score_len == WriteFile(oom_file, score_str.c_str(), score_len));
}
// If the oom_score_adj file doesn't exist, then we write the old
// style file and translate the oom_adj score to the range 0-15.
oom_file = oom_path.AppendASCII("oom_adj");
if (PathExists(oom_file)) {
// Max score for the old oom_adj range. Used for conversion of new
// values to old values.
const int kMaxOldOomScore = 15;
int converted_score = score * kMaxOldOomScore / kMaxOomScore;
std::string score_str = IntToString(converted_score);
DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str;
int score_len = static_cast<int>(score_str.length());
return (score_len == WriteFile(oom_file, score_str.c_str(), score_len));
}
return false;
}
bool UncheckedMalloc(size_t size, void** result) {
#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) || \
(!defined(LIBC_GLIBC) && !defined(USE_TCMALLOC))
*result = malloc(size);
#elif defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
*result = __libc_malloc(size);
#elif defined(USE_TCMALLOC)
*result = tc_malloc_skip_new_handler_weak(size);
#endif
return *result != NULL;
}
} // namespace butil
This diff is collapsed.
// Copyright (c) 2013 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.
#include "butil/process/memory.h"
namespace butil {
void EnableTerminationOnOutOfMemory() {
}
void EnableTerminationOnHeapCorruption() {
}
bool AdjustOOMScore(ProcessId process, int score) {
return false;
}
} // namespace butil
// Copyright (c) 2011 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_PROCESS_PROCESS_PROCESS_H_
#define BASE_PROCESS_PROCESS_PROCESS_H_
#include "butil/base_export.h"
#include "butil/basictypes.h"
#include "butil/process/process_handle.h"
#include "butil/build_config.h"
namespace butil {
class BASE_EXPORT Process {
public:
Process() : process_(kNullProcessHandle) {
}
explicit Process(ProcessHandle handle) : process_(handle) {
}
// A handle to the current process.
static Process Current();
static bool CanBackgroundProcesses();
// Get/Set the handle for this process. The handle will be 0 if the process
// is no longer running.
ProcessHandle handle() const { return process_; }
void set_handle(ProcessHandle handle) {
process_ = handle;
}
// Get the PID for this process.
ProcessId pid() const;
// Is the this process the current process.
bool is_current() const;
// Close the process handle. This will not terminate the process.
void Close();
// Terminates the process with extreme prejudice. The given result code will
// be the exit code of the process. If the process has already exited, this
// will do nothing.
void Terminate(int result_code);
// A process is backgrounded when it's priority is lower than normal.
// Return true if this process is backgrounded, false otherwise.
bool IsProcessBackgrounded() const;
// Set a process as backgrounded. If value is true, the priority
// of the process will be lowered. If value is false, the priority
// of the process will be made "normal" - equivalent to default
// process priority.
// Returns true if the priority was changed, false otherwise.
bool SetProcessBackgrounded(bool value);
// Returns an integer representing the priority of a process. The meaning
// of this value is OS dependent.
int GetPriority() const;
private:
ProcessHandle process_;
};
} // namespace butil
#endif // BASE_PROCESS_PROCESS_PROCESS_H_
// Copyright (c) 2013 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_PROCESS_PROCESS_HANDLE_H_
#define BASE_PROCESS_PROCESS_HANDLE_H_
#include "butil/base_export.h"
#include "butil/basictypes.h"
#include "butil/files/file_path.h"
#include "butil/build_config.h"
#include <sys/types.h>
#if defined(OS_WIN)
#include <windows.h>
#endif
namespace butil {
// ProcessHandle is a platform specific type which represents the underlying OS
// handle to a process.
// ProcessId is a number which identifies the process in the OS.
#if defined(OS_WIN)
typedef HANDLE ProcessHandle;
typedef DWORD ProcessId;
typedef HANDLE UserTokenHandle;
const ProcessHandle kNullProcessHandle = NULL;
const ProcessId kNullProcessId = 0;
#elif defined(OS_POSIX)
// On POSIX, our ProcessHandle will just be the PID.
typedef pid_t ProcessHandle;
typedef pid_t ProcessId;
const ProcessHandle kNullProcessHandle = 0;
const ProcessId kNullProcessId = 0;
#endif // defined(OS_WIN)
// Returns the id of the current process.
BASE_EXPORT ProcessId GetCurrentProcId();
// Returns the ProcessHandle of the current process.
BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
// Converts a PID to a process handle. This handle must be closed by
// CloseProcessHandle when you are done with it. Returns true on success.
BASE_EXPORT bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle);
// Converts a PID to a process handle. On Windows the handle is opened
// with more access rights and must only be used by trusted code.
// You have to close returned handle using CloseProcessHandle. Returns true
// on success.
// TODO(sanjeevr): Replace all calls to OpenPrivilegedProcessHandle with the
// more specific OpenProcessHandleWithAccess method and delete this.
BASE_EXPORT bool OpenPrivilegedProcessHandle(ProcessId pid,
ProcessHandle* handle);
// Converts a PID to a process handle using the desired access flags. Use a
// combination of the kProcessAccess* flags defined above for |access_flags|.
BASE_EXPORT bool OpenProcessHandleWithAccess(ProcessId pid,
uint32_t access_flags,
ProcessHandle* handle);
// Closes the process handle opened by OpenProcessHandle.
BASE_EXPORT void CloseProcessHandle(ProcessHandle process);
// Returns the unique ID for the specified process. This is functionally the
// same as Windows' GetProcessId(), but works on versions of Windows before
// Win XP SP1 as well.
BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
#if defined(OS_WIN)
enum IntegrityLevel {
INTEGRITY_UNKNOWN,
LOW_INTEGRITY,
MEDIUM_INTEGRITY,
HIGH_INTEGRITY,
};
// Determine the integrity level of the specified process. Returns false
// if the system does not support integrity levels (pre-Vista) or in the case
// of an underlying system failure.
BASE_EXPORT bool GetProcessIntegrityLevel(ProcessHandle process,
IntegrityLevel* level);
#endif
#if defined(OS_POSIX)
// Returns the path to the executable of the given process.
BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
// Returns the ID for the parent of the given process.
BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
#endif
} // namespace butil
#endif // BASE_PROCESS_PROCESS_HANDLE_H_
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -81,10 +81,12 @@ TEST(EndPointTest, endpoint) {
ASSERT_EQ(0, hostname2endpoint("localhost:65535", &p5)) << berror();
ASSERT_EQ(0, hostname2endpoint("localhost:0", &p5));
#ifdef BAIDU_INTERNAL
butil::EndPoint p6;
ASSERT_EQ(0, hostname2endpoint("tc-cm-et21.tc: 289 ", &p6));
ASSERT_STREQ("10.23.249.73", butil::ip2str(p6.ip).c_str());
ASSERT_EQ(289, p6.port);
#endif
}
TEST(EndPointTest, hash_table) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment