add isMobileApp util function to reduce ifdefs
Removed all MOBILEAPP preprocessor conditionals from Util.hpp/.cpp Added isMobileApp function to help remove further conditionals. Signed-off-by: Jaume Pujantell <jaume.pujantell@collabora.com> Change-Id: I038a4db47ec2a2c7bb10f5696df5571b13bd9a61pull/8593/head
parent
0241aa5aca
commit
3ba713aabf
14
Makefile.am
14
Makefile.am
|
@ -116,6 +116,7 @@ shared_sources = common/FileUtil.cpp \
|
|||
common/SpookyV2.cpp \
|
||||
common/Unit.cpp \
|
||||
common/Util.cpp \
|
||||
common/Util-desktop.cpp \
|
||||
common/ConfigUtil.cpp \
|
||||
common/Authorization.cpp \
|
||||
common/CommandControl.cpp \
|
||||
|
@ -180,7 +181,8 @@ connect_SOURCES = tools/Connect.cpp \
|
|||
common/Log.cpp \
|
||||
common/Protocol.cpp \
|
||||
common/StringVector.cpp \
|
||||
common/Util.cpp
|
||||
common/Util.cpp \
|
||||
common/Util-desktop.cpp
|
||||
|
||||
lokitclient_SOURCES = common/Log.cpp \
|
||||
common/DummyTraceEventEmitter.cpp \
|
||||
|
@ -188,7 +190,8 @@ lokitclient_SOURCES = common/Log.cpp \
|
|||
common/Protocol.cpp \
|
||||
common/StringVector.cpp \
|
||||
common/TraceEvent.cpp \
|
||||
common/Util.cpp
|
||||
common/Util.cpp \
|
||||
common/Util-desktop.cpp
|
||||
|
||||
noinst_LIBRARIES = libsimd.a
|
||||
libsimd_a_SOURCES = kit/DeltaSimd.c
|
||||
|
@ -265,7 +268,8 @@ clientnb_SOURCES = net/clientnb.cpp \
|
|||
common/DummyTraceEventEmitter.cpp \
|
||||
common/Log.cpp \
|
||||
common/StringVector.cpp \
|
||||
common/Util.cpp
|
||||
common/Util.cpp \
|
||||
common/Util-desktop.cpp
|
||||
|
||||
coolmount_SOURCES = tools/mount.cpp
|
||||
|
||||
|
@ -276,6 +280,7 @@ coolbench_SOURCES = tools/Benchmark.cpp \
|
|||
common/Log.cpp \
|
||||
common/StringVector.cpp \
|
||||
common/Util.cpp \
|
||||
common/Util-desktop.cpp \
|
||||
common/Simd.cpp
|
||||
coolbench_LDADD = libsimd.a
|
||||
|
||||
|
@ -292,7 +297,8 @@ coolconfig_SOURCES = tools/Config.cpp \
|
|||
common/Crypto.cpp \
|
||||
common/Log.cpp \
|
||||
common/StringVector.cpp \
|
||||
common/Util.cpp
|
||||
common/Util.cpp \
|
||||
common/Util-desktop.cpp
|
||||
|
||||
coolsocketdump_SOURCES = tools/WebSocketDump.cpp \
|
||||
common/DummyTraceEventEmitter.cpp \
|
||||
|
|
|
@ -20,6 +20,7 @@ add_library(androidapp SHARED
|
|||
../../../../../common/SpookyV2.cpp
|
||||
../../../../../common/Unit.cpp
|
||||
../../../../../common/Util.cpp
|
||||
../../../../../common/Util-mobile.cpp
|
||||
../../../../../kit/ChildSession.cpp
|
||||
../../../../../kit/DeltaSimd.c
|
||||
../../../../../kit/Kit.cpp
|
||||
|
|
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* Copyright the Collabora Online contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#include "Util.hpp"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/resource.h>
|
||||
#elif defined __FreeBSD__
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include <dirent.h>
|
||||
#include <spawn.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
bool isMobileApp() { return false; }
|
||||
|
||||
DirectoryCounter::DirectoryCounter(const char* procPath)
|
||||
: _tasks(opendir(procPath))
|
||||
{
|
||||
if (!_tasks)
|
||||
LOG_ERR("No proc mounted, can't count threads");
|
||||
}
|
||||
|
||||
DirectoryCounter::~DirectoryCounter() { closedir(reinterpret_cast<DIR*>(_tasks)); }
|
||||
|
||||
int DirectoryCounter::count()
|
||||
{
|
||||
auto dir = reinterpret_cast<DIR*>(_tasks);
|
||||
|
||||
if (!dir)
|
||||
return -1;
|
||||
|
||||
rewinddir(dir);
|
||||
|
||||
int tasks = 0;
|
||||
struct dirent* i;
|
||||
while ((i = readdir(dir)))
|
||||
{
|
||||
if (i->d_name[0] != '.')
|
||||
tasks++;
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
int spawnProcess(const std::string& cmd, const StringVector& args)
|
||||
{
|
||||
// Create a vector of zero-terminated strings.
|
||||
std::vector<std::string> argStrings;
|
||||
for (const auto& arg : args)
|
||||
argStrings.push_back(args.getParam(arg));
|
||||
|
||||
std::vector<char*> params;
|
||||
params.push_back(const_cast<char*>(cmd.c_str()));
|
||||
for (const auto& i : argStrings)
|
||||
params.push_back(const_cast<char*>(i.c_str()));
|
||||
params.push_back(nullptr);
|
||||
|
||||
pid_t pid = -1;
|
||||
int status = posix_spawn(&pid, params[0], nullptr, nullptr, params.data(), environ);
|
||||
if (status < 0)
|
||||
{
|
||||
LOG_ERR("Failed to posix_spawn for command '" << cmd);
|
||||
throw Poco::SystemException("Failed to fork posix_spawn command ", cmd);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
static const char* startsWith(const char* line, const char* tag, std::size_t tagLen)
|
||||
{
|
||||
assert(strlen(tag) == tagLen);
|
||||
|
||||
std::size_t len = tagLen;
|
||||
if (!strncmp(line, tag, len))
|
||||
{
|
||||
while (!isdigit(line[len]) && line[len] != '\0')
|
||||
++len;
|
||||
|
||||
return line + len;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string getHumanizedBytes(unsigned long nBytes)
|
||||
{
|
||||
constexpr unsigned factor = 1024;
|
||||
short count = 0;
|
||||
float val = nBytes;
|
||||
while (val >= factor && count < 4)
|
||||
{
|
||||
val /= factor;
|
||||
count++;
|
||||
}
|
||||
std::string unit;
|
||||
switch (count)
|
||||
{
|
||||
case 0:
|
||||
unit = "";
|
||||
break;
|
||||
case 1:
|
||||
unit = "ki";
|
||||
break;
|
||||
case 2:
|
||||
unit = "Mi";
|
||||
break;
|
||||
case 3:
|
||||
unit = "Gi";
|
||||
break;
|
||||
case 4:
|
||||
unit = "Ti";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
unit += 'B';
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::setprecision(1) << val << ' ' << unit;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::size_t getTotalSystemMemoryKb()
|
||||
{
|
||||
std::size_t totalMemKb = 0;
|
||||
FILE* file = fopen("/proc/meminfo", "r");
|
||||
if (file != nullptr)
|
||||
{
|
||||
char line[4096] = { 0 };
|
||||
// coverity[tainted_data_argument : FALSE] - we trust the kernel-provided data
|
||||
while (fgets(line, sizeof(line), file))
|
||||
{
|
||||
const char* value;
|
||||
if ((value = startsWith(line, "MemTotal:", 9)))
|
||||
{
|
||||
totalMemKb = atoll(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return totalMemKb;
|
||||
}
|
||||
|
||||
std::size_t getFromCGroup(const std::string& group, const std::string& key)
|
||||
{
|
||||
std::size_t num = 0;
|
||||
|
||||
std::string groupPath;
|
||||
FILE* cg = fopen("/proc/self/cgroup", "r");
|
||||
if (cg != nullptr)
|
||||
{
|
||||
char line[4096] = { 0 };
|
||||
while (fgets(line, sizeof(line), cg))
|
||||
{
|
||||
StringVector bits = StringVector::tokenize(line, strlen(line), ':');
|
||||
if (bits.size() > 2 && bits[1] == group)
|
||||
{
|
||||
groupPath = "/sys/fs/cgroup/" + group + bits[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG_TRC("control group path for " << group << " is " << groupPath);
|
||||
fclose(cg);
|
||||
}
|
||||
|
||||
if (groupPath.empty())
|
||||
return 0;
|
||||
|
||||
std::string path = groupPath + "/" + key;
|
||||
LOG_TRC("Read from " << path);
|
||||
FILE* file = fopen(path.c_str(), "r");
|
||||
if (file != nullptr)
|
||||
{
|
||||
char line[4096] = { 0 };
|
||||
if (fgets(line, sizeof(line), file))
|
||||
num = atoll(line);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
std::size_t getCGroupMemLimit()
|
||||
{
|
||||
#ifdef __linux__
|
||||
return getFromCGroup("memory", "memory.limit_in_bytes");
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::size_t getCGroupMemSoftLimit()
|
||||
{
|
||||
#ifdef __linux__
|
||||
return getFromCGroup("memory", "memory.soft_limit_in_bytes");
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::pair<std::size_t, std::size_t> getPssAndDirtyFromSMaps(FILE* file)
|
||||
{
|
||||
std::size_t numPSSKb = 0;
|
||||
std::size_t numDirtyKb = 0;
|
||||
if (file)
|
||||
{
|
||||
rewind(file);
|
||||
char line[4096] = { 0 };
|
||||
while (fgets(line, sizeof(line), file))
|
||||
{
|
||||
if (line[0] != 'P')
|
||||
continue;
|
||||
|
||||
const char* value;
|
||||
|
||||
// Shared_Dirty is accounted for by forkit's RSS
|
||||
if ((value = startsWith(line, "Private_Dirty:", 14)))
|
||||
{
|
||||
numDirtyKb += atoi(value);
|
||||
}
|
||||
else if ((value = startsWith(line, "Pss:", 4)))
|
||||
{
|
||||
numPSSKb += atoi(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(numPSSKb, numDirtyKb);
|
||||
}
|
||||
|
||||
std::string getMemoryStats(FILE* file)
|
||||
{
|
||||
const std::pair<std::size_t, std::size_t> pssAndDirtyKb = getPssAndDirtyFromSMaps(file);
|
||||
std::ostringstream oss;
|
||||
oss << "procmemstats: pid=" << getpid() << " pss=" << pssAndDirtyKb.first
|
||||
<< " dirty=" << pssAndDirtyKb.second;
|
||||
LOG_TRC("Collected " << oss.str());
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::size_t getMemoryUsagePSS(const pid_t pid)
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
// beautifully aggregated data in a single entry:
|
||||
const auto cmd_rollup = "/proc/" + std::to_string(pid) + "/smaps_rollup";
|
||||
FILE* fp = fopen(cmd_rollup.c_str(), "r");
|
||||
if (!fp)
|
||||
{
|
||||
const auto cmd = "/proc/" + std::to_string(pid) + "/smaps";
|
||||
fp = fopen(cmd.c_str(), "r");
|
||||
}
|
||||
|
||||
if (fp != nullptr)
|
||||
{
|
||||
const std::size_t pss = getPssAndDirtyFromSMaps(fp).first;
|
||||
fclose(fp);
|
||||
return pss;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t getMemoryUsageRSS(const pid_t pid)
|
||||
{
|
||||
static const int pageSizeBytes = getpagesize();
|
||||
std::size_t rss = 0;
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
rss = getStatFromPid(pid, 23);
|
||||
rss *= pageSizeBytes;
|
||||
rss /= 1024;
|
||||
return rss;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t getCurrentThreadCount()
|
||||
{
|
||||
DIR* dir = opendir("/proc/self/task");
|
||||
if (!dir)
|
||||
{
|
||||
LOG_TRC("Failed to open /proc/self/task");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t threads = 0;
|
||||
struct dirent* it;
|
||||
while ((it = readdir(dir)) != nullptr)
|
||||
{
|
||||
if (it->d_name[0] == '.')
|
||||
continue;
|
||||
threads++;
|
||||
}
|
||||
closedir(dir);
|
||||
LOG_TRC("We have " << threads << " threads");
|
||||
return threads;
|
||||
}
|
||||
|
||||
std::size_t getCpuUsage(const pid_t pid)
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
std::size_t totalJiffies = 0;
|
||||
totalJiffies += getStatFromPid(pid, 13);
|
||||
totalJiffies += getStatFromPid(pid, 14);
|
||||
return totalJiffies;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t getStatFromPid(const pid_t pid, int ind)
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
const auto cmd = "/proc/" + std::to_string(pid) + "/stat";
|
||||
FILE* fp = fopen(cmd.c_str(), "r");
|
||||
if (fp != nullptr)
|
||||
{
|
||||
char line[4096] = { 0 };
|
||||
if (fgets(line, sizeof(line), fp))
|
||||
{
|
||||
const std::string s(line);
|
||||
int index = 1;
|
||||
std::size_t pos = s.find(' ');
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
if (index == ind)
|
||||
{
|
||||
fclose(fp);
|
||||
return strtol(&s[pos], nullptr, 10);
|
||||
}
|
||||
++index;
|
||||
pos = s.find(' ', pos + 1);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setProcessAndThreadPriorities(const pid_t pid, int prio)
|
||||
{
|
||||
int res = setpriority(PRIO_PROCESS, pid, prio);
|
||||
LOG_TRC("Lowered kit [" << (int)pid << "] priority: " << prio << " with result: " << res);
|
||||
|
||||
#ifdef __linux__
|
||||
// rely on Linux thread-id priority setting to drop this thread' priority
|
||||
pid_t tid = getThreadId();
|
||||
res = setpriority(PRIO_PROCESS, tid, prio);
|
||||
LOG_TRC("Lowered own thread [" << (int)tid << "] priority: " << prio
|
||||
<< " with result: " << res);
|
||||
#endif
|
||||
}
|
||||
// If OS is not mobile, it must be Linux.
|
||||
std::string getLinuxVersion()
|
||||
{
|
||||
// Read operating system info. We can read "os-release" file, located in /etc.
|
||||
std::ifstream ifs("/etc/os-release");
|
||||
std::string str(std::istreambuf_iterator<char>{ ifs }, {});
|
||||
std::vector<std::string> infoList = Util::splitStringToVector(str, '\n');
|
||||
std::map<std::string, std::string> releaseInfo = Util::stringVectorToMap(infoList, '=');
|
||||
|
||||
auto it = releaseInfo.find("PRETTY_NAME");
|
||||
if (it != releaseInfo.end())
|
||||
{
|
||||
std::string name = it->second;
|
||||
|
||||
// See os-release(5). It says that the lines are "environment-like shell-compatible
|
||||
// variable assignments". What that means, *exactly*, is up for debate, but probably
|
||||
// of mainly academic interest. (It does say that variable expansion at least is not
|
||||
// supported, that is a relief.)
|
||||
|
||||
// The value of PRETTY_NAME might be quoted with double-quotes or
|
||||
// single-quotes.
|
||||
|
||||
// FIXME: In addition, it might contain backslash-escaped special
|
||||
// characters, but we ignore that possibility for now.
|
||||
|
||||
// FIXME: In addition, if it really does support shell syntax (except variable
|
||||
// expansion), it could for instance consist of multiple concatenated quoted strings (with no
|
||||
// whitespace inbetween), as in:
|
||||
// PRETTY_NAME="Foo "'bar'" mumble"
|
||||
// But I guess that is a pretty remote possibility and surely no other code that
|
||||
// reads /etc/os-release handles that like a proper shell, either.
|
||||
|
||||
if (name.length() >= 2 && ((name[0] == '"' && name[name.length() - 1] == '"') ||
|
||||
(name[0] == '\'' && name[name.length() - 1] == '\'')))
|
||||
name = name.substr(1, name.length() - 2);
|
||||
return name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BUILDING_TESTS)
|
||||
/// No-op implementation in the test programs
|
||||
void alertAllUsers(const std::string&) {}
|
||||
|
||||
/// No-op implementation in the test programs
|
||||
void alertAllUsers(const std::string&, const std::string&) {}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright the Collabora Online contributors.
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#include "Util.hpp"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
bool isMobileApp() { return true; }
|
||||
|
||||
/// No-op implementation of desktop only functions
|
||||
DirectoryCounter::DirectoryCounter(const char* procPath) {}
|
||||
DirectoryCounter::~DirectoryCounter() {}
|
||||
int DirectoryCounter::count() { return 0; }
|
||||
int spawnProcess(const std::string& cmd, const StringVector& args) { return 0; }
|
||||
|
||||
std::string getHumanizedBytes(unsigned long nBytes) { return std::string(); }
|
||||
size_t getTotalSystemMemoryKb() { return 0; }
|
||||
std::size_t getFromFile(const char* path) { return 0; }
|
||||
std::size_t getCGroupMemLimit() { return 0; }
|
||||
std::size_t getCGroupMemSoftLimit() { return 0; }
|
||||
size_t getMemoryUsagePSS(const pid_t pid) { return 0; }
|
||||
size_t getMemoryUsageRSS(const pid_t pid) { return 0; }
|
||||
size_t getCurrentThreadCount() { return 0; }
|
||||
std::string getMemoryStats(FILE* file) { return std::string(); }
|
||||
std::pair<size_t, size_t> getPssAndDirtyFromSMaps(FILE* file) { return std::make_pair(0, 0); }
|
||||
size_t getCpuUsage(const pid_t pid) { return 0; }
|
||||
size_t getStatFromPid(const pid_t pid, int ind) { return 0; }
|
||||
void setProcessAndThreadPriorities(const pid_t pid, int prio) {}
|
||||
|
||||
std::string getLinuxVersion() { return "unknown"; }
|
||||
|
||||
void alertAllUsers(const std::string&) {}
|
||||
void alertAllUsers(const std::string&, const std::string&) {}
|
||||
}
|
387
common/Util.cpp
387
common/Util.cpp
|
@ -190,65 +190,6 @@ namespace Util
|
|||
}
|
||||
}
|
||||
|
||||
#if !MOBILEAPP
|
||||
DirectoryCounter::DirectoryCounter(const char *procPath) :
|
||||
_tasks(opendir(procPath))
|
||||
{
|
||||
if (!_tasks)
|
||||
LOG_ERR("No proc mounted, can't count threads");
|
||||
}
|
||||
|
||||
DirectoryCounter::~DirectoryCounter()
|
||||
{
|
||||
closedir(reinterpret_cast<DIR *>(_tasks));
|
||||
}
|
||||
|
||||
int DirectoryCounter::count()
|
||||
{
|
||||
auto dir = reinterpret_cast<DIR *>(_tasks);
|
||||
|
||||
if (!dir)
|
||||
return -1;
|
||||
|
||||
rewinddir(dir);
|
||||
|
||||
int tasks = 0;
|
||||
struct dirent *i;
|
||||
while ((i = readdir(dir)))
|
||||
{
|
||||
if (i->d_name[0] != '.')
|
||||
tasks++;
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
int spawnProcess(const std::string &cmd, const StringVector &args)
|
||||
{
|
||||
// Create a vector of zero-terminated strings.
|
||||
std::vector<std::string> argStrings;
|
||||
for (const auto& arg : args)
|
||||
argStrings.push_back(args.getParam(arg));
|
||||
|
||||
std::vector<char *> params;
|
||||
params.push_back(const_cast<char *>(cmd.c_str()));
|
||||
for (const auto& i : argStrings)
|
||||
params.push_back(const_cast<char *>(i.c_str()));
|
||||
params.push_back(nullptr);
|
||||
|
||||
pid_t pid = -1;
|
||||
int status = posix_spawn(&pid, params[0], nullptr, nullptr, params.data(), environ);
|
||||
if (status < 0)
|
||||
{
|
||||
LOG_ERR("Failed to posix_spawn for command '" << cmd);
|
||||
throw Poco::SystemException("Failed to fork posix_spawn command ", cmd);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::string encodeId(const std::uint64_t number, const int padding)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
@ -274,290 +215,6 @@ namespace Util
|
|||
void setKitInProcess(bool value) { kitInProcess = value; }
|
||||
bool isKitInProcess() { return kitInProcess || isFuzzing(); }
|
||||
|
||||
#if !MOBILEAPP
|
||||
|
||||
static const char *startsWith(const char *line, const char *tag, std::size_t tagLen)
|
||||
{
|
||||
assert(strlen(tag) == tagLen);
|
||||
|
||||
std::size_t len = tagLen;
|
||||
if (!strncmp(line, tag, len))
|
||||
{
|
||||
while (!isdigit(line[len]) && line[len] != '\0')
|
||||
++len;
|
||||
|
||||
return line + len;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string getHumanizedBytes(unsigned long nBytes)
|
||||
{
|
||||
constexpr unsigned factor = 1024;
|
||||
short count = 0;
|
||||
float val = nBytes;
|
||||
while (val >= factor && count < 4) {
|
||||
val /= factor;
|
||||
count++;
|
||||
}
|
||||
std::string unit;
|
||||
switch (count)
|
||||
{
|
||||
case 0: unit = ""; break;
|
||||
case 1: unit = "ki"; break;
|
||||
case 2: unit = "Mi"; break;
|
||||
case 3: unit = "Gi"; break;
|
||||
case 4: unit = "Ti"; break;
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
unit += 'B';
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::setprecision(1) << val << ' ' << unit;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::size_t getTotalSystemMemoryKb()
|
||||
{
|
||||
std::size_t totalMemKb = 0;
|
||||
FILE* file = fopen("/proc/meminfo", "r");
|
||||
if (file != nullptr)
|
||||
{
|
||||
char line[4096] = { 0 };
|
||||
// coverity[tainted_data_argument : FALSE] - we trust the kernel-provided data
|
||||
while (fgets(line, sizeof(line), file))
|
||||
{
|
||||
const char* value;
|
||||
if ((value = startsWith(line, "MemTotal:", 9)))
|
||||
{
|
||||
totalMemKb = atoll(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return totalMemKb;
|
||||
}
|
||||
|
||||
std::size_t getFromCGroup(const std::string &group, const std::string &key)
|
||||
{
|
||||
std::size_t num = 0;
|
||||
|
||||
std::string groupPath;
|
||||
FILE* cg = fopen("/proc/self/cgroup", "r");
|
||||
if (cg != nullptr)
|
||||
{
|
||||
|
||||
char line[4096] = { 0 };
|
||||
while (fgets(line, sizeof(line), cg))
|
||||
{
|
||||
StringVector bits = StringVector::tokenize(line, strlen (line), ':');
|
||||
if (bits.size() > 2 && bits[1] == group)
|
||||
{
|
||||
groupPath = "/sys/fs/cgroup/" + group + bits[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG_TRC("control group path for " << group << " is " << groupPath);
|
||||
fclose(cg);
|
||||
}
|
||||
|
||||
if (groupPath.empty())
|
||||
return 0;
|
||||
|
||||
std::string path = groupPath + "/" + key;
|
||||
LOG_TRC("Read from " << path);
|
||||
FILE* file = fopen(path.c_str(), "r");
|
||||
if (file != nullptr)
|
||||
{
|
||||
char line[4096] = { 0 };
|
||||
if (fgets(line, sizeof(line), file))
|
||||
num = atoll(line);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
std::size_t getCGroupMemLimit()
|
||||
{
|
||||
#ifdef __linux__
|
||||
return getFromCGroup("memory", "memory.limit_in_bytes");
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::size_t getCGroupMemSoftLimit()
|
||||
{
|
||||
#ifdef __linux__
|
||||
return getFromCGroup("memory", "memory.soft_limit_in_bytes");
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::pair<std::size_t, std::size_t> getPssAndDirtyFromSMaps(FILE* file)
|
||||
{
|
||||
std::size_t numPSSKb = 0;
|
||||
std::size_t numDirtyKb = 0;
|
||||
if (file)
|
||||
{
|
||||
rewind(file);
|
||||
char line[4096] = { 0 };
|
||||
while (fgets(line, sizeof (line), file))
|
||||
{
|
||||
if (line[0] != 'P')
|
||||
continue;
|
||||
|
||||
const char *value;
|
||||
|
||||
// Shared_Dirty is accounted for by forkit's RSS
|
||||
if ((value = startsWith(line, "Private_Dirty:", 14)))
|
||||
{
|
||||
numDirtyKb += atoi(value);
|
||||
}
|
||||
else if ((value = startsWith(line, "Pss:", 4)))
|
||||
{
|
||||
numPSSKb += atoi(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(numPSSKb, numDirtyKb);
|
||||
}
|
||||
|
||||
std::string getMemoryStats(FILE* file)
|
||||
{
|
||||
const std::pair<std::size_t, std::size_t> pssAndDirtyKb = getPssAndDirtyFromSMaps(file);
|
||||
std::ostringstream oss;
|
||||
oss << "procmemstats: pid=" << getpid()
|
||||
<< " pss=" << pssAndDirtyKb.first
|
||||
<< " dirty=" << pssAndDirtyKb.second;
|
||||
LOG_TRC("Collected " << oss.str());
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::size_t getMemoryUsagePSS(const pid_t pid)
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
// beautifully aggregated data in a single entry:
|
||||
const auto cmd_rollup = "/proc/" + std::to_string(pid) + "/smaps_rollup";
|
||||
FILE* fp = fopen(cmd_rollup.c_str(), "r");
|
||||
if (!fp)
|
||||
{
|
||||
const auto cmd = "/proc/" + std::to_string(pid) + "/smaps";
|
||||
fp = fopen(cmd.c_str(), "r");
|
||||
}
|
||||
|
||||
if (fp != nullptr)
|
||||
{
|
||||
const std::size_t pss = getPssAndDirtyFromSMaps(fp).first;
|
||||
fclose(fp);
|
||||
return pss;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t getMemoryUsageRSS(const pid_t pid)
|
||||
{
|
||||
static const int pageSizeBytes = getpagesize();
|
||||
std::size_t rss = 0;
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
rss = getStatFromPid(pid, 23);
|
||||
rss *= pageSizeBytes;
|
||||
rss /= 1024;
|
||||
return rss;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t getCurrentThreadCount()
|
||||
{
|
||||
DIR *dir = opendir("/proc/self/task");
|
||||
if (!dir)
|
||||
{
|
||||
LOG_TRC("Failed to open /proc/self/task");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t threads = 0;
|
||||
struct dirent *it;
|
||||
while ((it = readdir(dir)) != nullptr) {
|
||||
if (it->d_name[0] == '.')
|
||||
continue;
|
||||
threads++;
|
||||
}
|
||||
closedir(dir);
|
||||
LOG_TRC("We have " << threads << " threads");
|
||||
return threads;
|
||||
}
|
||||
|
||||
std::size_t getCpuUsage(const pid_t pid)
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
std::size_t totalJiffies = 0;
|
||||
totalJiffies += getStatFromPid(pid, 13);
|
||||
totalJiffies += getStatFromPid(pid, 14);
|
||||
return totalJiffies;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t getStatFromPid(const pid_t pid, int ind)
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
const auto cmd = "/proc/" + std::to_string(pid) + "/stat";
|
||||
FILE* fp = fopen(cmd.c_str(), "r");
|
||||
if (fp != nullptr)
|
||||
{
|
||||
char line[4096] = { 0 };
|
||||
if (fgets(line, sizeof (line), fp))
|
||||
{
|
||||
const std::string s(line);
|
||||
int index = 1;
|
||||
std::size_t pos = s.find(' ');
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
if (index == ind)
|
||||
{
|
||||
fclose(fp);
|
||||
return strtol(&s[pos], nullptr, 10);
|
||||
}
|
||||
++index;
|
||||
pos = s.find(' ', pos + 1);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setProcessAndThreadPriorities(const pid_t pid, int prio)
|
||||
{
|
||||
int res = setpriority(PRIO_PROCESS, pid, prio);
|
||||
LOG_TRC("Lowered kit [" << (int)pid << "] priority: " << prio << " with result: " << res);
|
||||
|
||||
#ifdef __linux__
|
||||
// rely on Linux thread-id priority setting to drop this thread' priority
|
||||
pid_t tid = getThreadId();
|
||||
res = setpriority(PRIO_PROCESS, tid, prio);
|
||||
LOG_TRC("Lowered own thread [" << (int)tid << "] priority: " << prio << " with result: " << res);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // !MOBILEAPP
|
||||
|
||||
std::string replace(std::string result, const std::string& a, const std::string& b)
|
||||
{
|
||||
const std::size_t aSize = a.size();
|
||||
|
@ -1123,50 +780,6 @@ namespace Util
|
|||
return ApplicationPath;
|
||||
}
|
||||
|
||||
#if !MOBILEAPP
|
||||
// If OS is not mobile, it must be Linux.
|
||||
std::string getLinuxVersion(){
|
||||
// Read operating system info. We can read "os-release" file, located in /etc.
|
||||
std::ifstream ifs("/etc/os-release");
|
||||
std::string str(std::istreambuf_iterator<char>{ifs}, {});
|
||||
std::vector<std::string> infoList = Util::splitStringToVector(str, '\n');
|
||||
std::map<std::string, std::string> releaseInfo = Util::stringVectorToMap(infoList, '=');
|
||||
|
||||
auto it = releaseInfo.find("PRETTY_NAME");
|
||||
if (it != releaseInfo.end())
|
||||
{
|
||||
std::string name = it->second;
|
||||
|
||||
// See os-release(5). It says that the lines are "environment-like shell-compatible
|
||||
// variable assignments". What that means, *exactly*, is up for debate, but probably
|
||||
// of mainly academic interest. (It does say that variable expansion at least is not
|
||||
// supported, that is a relief.)
|
||||
|
||||
// The value of PRETTY_NAME might be quoted with double-quotes or
|
||||
// single-quotes.
|
||||
|
||||
// FIXME: In addition, it might contain backslash-escaped special
|
||||
// characters, but we ignore that possibility for now.
|
||||
|
||||
// FIXME: In addition, if it really does support shell syntax (except variable
|
||||
// expansion), it could for instance consist of multiple concatenated quoted strings (with no
|
||||
// whitespace inbetween), as in:
|
||||
// PRETTY_NAME="Foo "'bar'" mumble"
|
||||
// But I guess that is a pretty remote possibility and surely no other code that
|
||||
// reads /etc/os-release handles that like a proper shell, either.
|
||||
|
||||
if (name.length() >= 2 && ((name[0] == '"' && name[name.length()-1] == '"') ||
|
||||
(name[0] == '\'' && name[name.length()-1] == '\'')))
|
||||
name = name.substr(1, name.length()-2);
|
||||
return name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int safe_atoi(const char* p, int len)
|
||||
{
|
||||
long ret{};
|
||||
|
|
|
@ -131,7 +131,6 @@ namespace Util
|
|||
std::chrono::steady_clock::time_point _startTime;
|
||||
};
|
||||
|
||||
#if !MOBILEAPP
|
||||
class DirectoryCounter
|
||||
{
|
||||
void *_tasks;
|
||||
|
@ -159,8 +158,6 @@ namespace Util
|
|||
/// Spawn a process.
|
||||
int spawnProcess(const std::string &cmd, const StringVector &args);
|
||||
|
||||
#endif
|
||||
|
||||
/// Convert unsigned char data to hex.
|
||||
/// @buffer can be either std::vector<char> or std::string.
|
||||
/// @offset the offset within the buffer to start from.
|
||||
|
@ -214,8 +211,6 @@ namespace Util
|
|||
|
||||
bool windowingAvailable();
|
||||
|
||||
#if !defined(BUILDING_TESTS) && !MOBILEAPP
|
||||
|
||||
/// Send a message to all clients.
|
||||
void alertAllUsers(const std::string& msg);
|
||||
|
||||
|
@ -225,18 +220,6 @@ namespace Util
|
|||
/// coolwsd for redistribution. (This function must be implemented separately in each program
|
||||
/// that uses it, it is not in Util.cpp.)
|
||||
void alertAllUsers(const std::string& cmd, const std::string& kind);
|
||||
#else
|
||||
|
||||
/// No-op implementation in the test programs
|
||||
inline void alertAllUsers(const std::string&)
|
||||
{
|
||||
}
|
||||
|
||||
/// No-op implementation in the test programs
|
||||
inline void alertAllUsers(const std::string&, const std::string&)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Assert that a lock is already taken.
|
||||
template <typename T> void assertIsLocked([[maybe_unused]] const T& lock)
|
||||
|
@ -253,7 +236,6 @@ namespace Util
|
|||
#endif
|
||||
}
|
||||
|
||||
#if !MOBILEAPP
|
||||
/// Print given number of bytes in human-understandable form (KB,MB, etc.)
|
||||
std::string getHumanizedBytes(unsigned long nBytes);
|
||||
|
||||
|
@ -292,7 +274,6 @@ namespace Util
|
|||
|
||||
/// Sets priorities for a given pid & the current thread
|
||||
void setProcessAndThreadPriorities(const pid_t pid, int prio);
|
||||
#endif
|
||||
|
||||
/// Replace substring @a in string @s with string @b.
|
||||
std::string replace(std::string s, const std::string& a, const std::string& b);
|
||||
|
@ -1322,6 +1303,8 @@ int main(int argc, char**argv)
|
|||
*/
|
||||
bool isFuzzing();
|
||||
|
||||
bool isMobileApp();
|
||||
|
||||
void setKitInProcess(bool value);
|
||||
bool isKitInProcess();
|
||||
|
||||
|
@ -1354,10 +1337,8 @@ int main(int argc, char**argv)
|
|||
*/
|
||||
std::map<std::string, std::string> stringVectorToMap(const std::vector<std::string>& strvector, const char delimiter);
|
||||
|
||||
#if !MOBILEAPP
|
||||
// If OS is not mobile, it must be Linux.
|
||||
std::string getLinuxVersion();
|
||||
#endif
|
||||
|
||||
/// Convert a string to 32-bit signed int.
|
||||
/// Returns the parsed value and a boolean indicating success or failure.
|
||||
|
|
|
@ -31,7 +31,8 @@ common_sources = \
|
|||
../common/StringVector.cpp \
|
||||
../common/TraceEvent.cpp \
|
||||
../common/Unit.cpp \
|
||||
../common/Util.cpp
|
||||
../common/Util.cpp \
|
||||
../common/Util-mobile.cpp
|
||||
|
||||
kit_sources = ../kit/ChildSession.cpp \
|
||||
../kit/Kit.cpp \
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1F957DC22BA8229A006C9E78 /* Util-mobile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1F957DC12BA82296006C9E78 /* Util-mobile.cpp */; };
|
||||
1FCFA28A2B2AF13F007EE2DF /* coolwsd-fork.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1FCFA2892B2AF13C007EE2DF /* coolwsd-fork.cpp */; };
|
||||
3F3B54DD2A3928D100063C01 /* HttpRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F3B54DB2A39288500063C01 /* HttpRequest.cpp */; };
|
||||
3F3B54E02A392CCB00063C01 /* NetUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F3B54DE2A392C9C00063C01 /* NetUtil.cpp */; };
|
||||
|
@ -84,6 +85,7 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1F957DC12BA82296006C9E78 /* Util-mobile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "Util-mobile.cpp"; sourceTree = "<group>"; };
|
||||
1FCFA2892B2AF13C007EE2DF /* coolwsd-fork.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "coolwsd-fork.cpp"; sourceTree = "<group>"; };
|
||||
3F3B54DB2A39288500063C01 /* HttpRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HttpRequest.cpp; sourceTree = "<group>"; };
|
||||
3F3B54DC2A39288500063C01 /* HttpRequest.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = HttpRequest.hpp; sourceTree = "<group>"; };
|
||||
|
@ -2203,6 +2205,7 @@
|
|||
BEA28376214FFD8C00848631 /* Unit.cpp */,
|
||||
BEA283782150172600848631 /* Unit.hpp */,
|
||||
BE5EB5BC213FE29900E0826C /* Util.cpp */,
|
||||
1F957DC12BA82296006C9E78 /* Util-mobile.cpp */,
|
||||
BE58E12C217F295B00249358 /* Util.hpp */,
|
||||
);
|
||||
path = common;
|
||||
|
@ -3671,6 +3674,7 @@
|
|||
BE8D772F2136762500AC58EA /* DocumentBrowserViewController.mm in Sources */,
|
||||
BE9ADE3F265D046600BC034A /* TraceEvent.cpp in Sources */,
|
||||
BE5EB5D0213FE2D000E0826C /* TileCache.cpp in Sources */,
|
||||
1F957DC22BA8229A006C9E78 /* Util-mobile.cpp in Sources */,
|
||||
BE5EB5C5213FE29900E0826C /* MessageQueue.cpp in Sources */,
|
||||
BE7228E22417BC9F000ADABD /* StringVector.cpp in Sources */,
|
||||
BE55E0EB2653FCCB007DDF29 /* ConfigUtil.cpp in Sources */,
|
||||
|
|
|
@ -146,6 +146,7 @@ common_sources = \
|
|||
../common/Unit.cpp \
|
||||
../common/FileUtil.cpp \
|
||||
../common/Util.cpp \
|
||||
../common/Util-desktop.cpp \
|
||||
../common/StringVector.cpp \
|
||||
../common/TraceEvent.cpp \
|
||||
../common/Simd.cpp \
|
||||
|
@ -178,7 +179,7 @@ unit_base_la_LIBADD += -lssl -lcrypto
|
|||
endif
|
||||
|
||||
fakesockettest_CPPFLAGS = -g
|
||||
fakesockettest_SOURCES = fakesockettest.cpp ../net/FakeSocket.cpp ../common/DummyTraceEventEmitter.cpp ../common/Log.cpp ../common/Util.cpp
|
||||
fakesockettest_SOURCES = fakesockettest.cpp ../net/FakeSocket.cpp ../common/DummyTraceEventEmitter.cpp ../common/Log.cpp ../common/Util.cpp ../common/Util-desktop.cpp
|
||||
fakesockettest_LDADD = $(CPPUNIT_LIBS)
|
||||
|
||||
# old-style unit tests - bootstrapped via UnitClient
|
||||
|
|
|
@ -36,6 +36,7 @@ online_SOURCES = \
|
|||
../common/SpookyV2.cpp \
|
||||
../common/Unit.cpp \
|
||||
../common/Util.cpp \
|
||||
../common/Util-mobile.cpp \
|
||||
../kit/ChildSession.cpp \
|
||||
../kit/Kit.cpp \
|
||||
../kit/KitWebSocket.cpp \
|
||||
|
|
Loading…
Reference in New Issue