ProcessInfo.h
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is a public header file, it must only include public header files.
#ifndef MUDUO_BASE_PROCESSINFO_H
#define MUDUO_BASE_PROCESSINFO_H
#include <muduo/base/StringPiece.h>
#include <muduo/base/Types.h>
#include <muduo/base/Timestamp.h>
#include <vector>
namespace muduo
{
namespace ProcessInfo
{
// 进程id
pid_t pid();
// 进程id的字符串形式
string pidString();
//返回实际用户的ID
uid_t uid();
// 进程的用户名
string username();
// 返回有效用户的ID。
uid_t euid();
// 进程开始时间
Timestamp startTime();
// 返回时钟频率
int clockTicksPerSecond();
// 返回内存页的大小
int pageSize();
// 是否以调试模式构建
bool isDebugBuild(); // constexpr
// 获取主机名称
string hostname();
// 获取进程名称
string procname();
StringPiece procname(const string& stat);
/// read /proc/self/status
string procStatus();
/// read /proc/self/stat
string procStat();
/// read /proc/self/task/tid/stat
string threadStat();
/// readlink /proc/self/exe
//
string exePath();
int openedFiles();
int maxOpenFiles();
struct CpuTime
{
double userSeconds;
double systemSeconds;
CpuTime() : userSeconds(0.0), systemSeconds(0.0) { }
};
CpuTime cpuTime();
int numThreads();
std::vector<pid_t> threads();
}
}
#endif // MUDUO_BASE_PROCESSINFO_H
ProcessInfo.cpp
// Copyright 2010, Shuo Chen. All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
#include <muduo/base/ProcessInfo.h>
#include <muduo/base/CurrentThread.h>
#include <muduo/base/FileUtil.h>
#include <algorithm>
#include <assert.h>
#include <dirent.h>
#include <pwd.h>
#include <stdio.h> // snprintf
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/times.h>
namespace muduo
{
namespace detail
{
__thread int t_numOpenedFiles = 0;
int fdDirFilter(const struct dirent* d)
{
if (::isdigit(d->d_name[0]))
{
++t_numOpenedFiles;
}
return 0;
}
__thread std::vector<pid_t>* t_pids = NULL;
int taskDirFilter(const struct dirent* d)
{
if (::isdigit(d->d_name[0]))
{
t_pids->push_back(atoi(d->d_name));
}
return 0;
}
int scanDir(const char *dirpath, int (*filter)(const struct dirent *))
{
struct dirent** namelist = NULL;
int result = ::scandir(dirpath, &namelist, filter, alphasort);
assert(namelist == NULL);
return result;
}
// 获取进程启动时间
Timestamp g_startTime = Timestamp::now();
// assume those won't change during the life time of a process.
// 获取时钟频率
int g_clockTicks = static_cast<int>(::sysconf(_SC_CLK_TCK));
// 获取内存页大小
int g_pageSize = static_cast<int>(::sysconf(_SC_PAGE_SIZE));
}
}
using namespace muduo;
using namespace muduo::detail;
//返回实际用户的ID
pid_t ProcessInfo::pid()
{
return ::getpid();
}
string ProcessInfo::pidString()
{
char buf[32];
snprintf(buf, sizeof buf, "%d", pid());
return buf;
}
uid_t ProcessInfo::uid()
{
return ::getuid();
}
// 进程的用户名
string ProcessInfo::username()
{
struct passwd pwd;
struct passwd* result = NULL;
char buf[8192];
const char* name = "unknownuser";
getpwuid_r(uid(), &pwd, buf, sizeof buf, &result);
if (result)
{
name = pwd.pw_name;
}
return name;
}
// 返回有效用户的ID。
uid_t ProcessInfo::euid()
{
return ::geteuid();
}
// 进程开始时间
Timestamp ProcessInfo::startTime()
{
return g_startTime;
}
// 一秒的时钟数
int ProcessInfo::clockTicksPerSecond()
{
return g_clockTicks;
}
// 返回内存页的大小
int ProcessInfo::pageSize()
{
return g_pageSize;
}
// 是否以调试模式构建
bool ProcessInfo::isDebugBuild()
{
#ifdef NDEBUG
return false;
#else
return true;
#endif
}
// 获取主机名称
string ProcessInfo::hostname()
{
// HOST_NAME_MAX 64
// _POSIX_HOST_NAME_MAX 255
char buf[256];
if (::gethostname(buf, sizeof buf) == 0)
{
buf[sizeof(buf)-1] = '\0';
return buf;
}
else
{
return "unknownhost";
}
}
// 获取进程名称
string ProcessInfo::procname()
{
return procname(procStat()).as_string();
}
StringPiece ProcessInfo::procname(const string& stat)
{
StringPiece name;
size_t lp = stat.find('(');
size_t rp = stat.rfind(')');
if (lp != string::npos && rp != string::npos && lp < rp)
{
name.set(stat.data()+lp+1, static_cast<int>(rp-lp-1));
}
return name;
}
// 通过/proc/进程id/status 文件 ,获取进程相关信息
string ProcessInfo::procStatus()
{
string result;
FileUtil::readFile("/proc/self/status", 65536, &result);
return result;
}
// 通过/proc/进程id/stat 文件 ,获取进程相关信息
string ProcessInfo::procStat()
{
string result;
FileUtil::readFile("/proc/self/stat", 65536, &result);
return result;
}
// 通过/proc/进程id/stat 文件 ,获取进程的线程相关信息
string ProcessInfo::threadStat()
{
char buf[64];
snprintf(buf, sizeof buf, "/proc/self/task/%d/stat", CurrentThread::tid());
string result;
FileUtil::readFile(buf, 65536, &result);
return result;
}
// 执行路径,从根目录开始的绝对路径。 通过命令readlink打开文件/proc/进程id/exe,可以进行查看
string ProcessInfo::exePath()
{
string result;
char buf[1024];
ssize_t n = ::readlink("/proc/self/exe", buf, sizeof buf);
if (n > 0)
{
result.assign(buf, n);
}
return result;
}
// 计算打开的文件描述符的数目,可以通过命令`ll /proc/进程id/fd | wc -l`来计算得到文件描述符的数目
int ProcessInfo::openedFiles()
{
t_numOpenedFiles = 0;
scanDir("/proc/self/fd", fdDirFilter);
return t_numOpenedFiles;
}
// 获取进程可以打开的最大文件描述符的数量
int ProcessInfo::maxOpenFiles()
{
struct rlimit rl;
if (::getrlimit(RLIMIT_NOFILE, &rl))
{
return openedFiles();
}
else
{
return static_cast<int>(rl.rlim_cur);
}
}
// 获取CPU时间
ProcessInfo::CpuTime ProcessInfo::cpuTime()
{
ProcessInfo::CpuTime t;
struct tms tms;
if (::times(&tms) >= 0)
{
const double hz = static_cast<double>(clockTicksPerSecond());
t.userSeconds = static_cast<double>(tms.tms_utime) / hz; // 用户时间
t.systemSeconds = static_cast<double>(tms.tms_stime) / hz; // 系统时间
}
return t;
}
// 线程数目,通过命令`cat /proc/进程id/status | grep 'Threads' 可以获得线程数目`
int ProcessInfo::numThreads()
{
int result = 0;
string status = procStatus();
size_t pos = status.find("Threads:");
if (pos != string::npos)
{
result = ::atoi(status.c_str() + pos + 8);
}
return result;
}
// 线程id,通过命令'ls /proc/进程id/task 可以获得进程中的线程号'
std::vector<pid_t> ProcessInfo::threads()
{
std::vector<pid_t> result;
t_pids = &result;
scanDir("/proc/self/task", taskDirFilter);
t_pids = NULL;
std::sort(result.begin(), result.end());
return result;
}
注意点
通过/proc/进程id/目录,可以获得众多进程相关的信息,这是系统提供的我们访问进程内核中参数的一个接口。