Files
pip/libs/main/core/piinit.cpp
peri4 3da94abb2a PIInit refactoring, iteration 2
add to PISystemInfo processorsCount<P|E> fields, now counts only for Windows
Introspection public API works without PIP_HAS_THREADS
2026-09-06 10:41:53 +03:00

553 lines
13 KiB
C++

/*
PIP - Platform Independent Primitives
Initialization
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piinit.h"
#include "piincludes_p.h"
// The full implementation needs the PIInit class (declared in piinit.h only
// with PIP_HAS_THREADS); without threads PIInit is absent altogether
#if !defined(_PIP_INIT_STUB_)
# include "pidir.h"
# include "piliterals_string.h"
# include "piobject.h"
# include "piprocess.h"
# include "piresourcesstorage.h"
# include "pisignals.h"
# include "pisysteminfo.h"
# include "pitime.h"
# ifdef ESP_PLATFORM
# include "esp_system.h"
# endif
# ifdef WINDOWS
# ifdef PIP_HAS_SOCKET
# include <winsock2.h>
# else
# include <windows.h>
# endif
extern FILETIME __pi_ftjan1970;
extern PINtQueryTimerResolution getTimerResolutionAddr;
extern PINtSetTimerResolution setTimerResolutionAddr;
void __PISetTimerResolution() {
if (setTimerResolutionAddr == NULL || getTimerResolutionAddr == NULL) return;
ULONG _max(0), _min(0), _cur(0);
// printf("getTimerResolution ...\n");
LONG q = getTimerResolutionAddr(&_max, &_min, &_cur);
// printf("getTimerResolution %d %lu %lu %lu\n", q, _min, _max, _cur);
if (q == 0) setTimerResolutionAddr(_min, TRUE, &_cur);
// printf("setTimerResolution %lu\n", cur);
}
# else
# include <pthread.h>
# include <pwd.h>
# include <sys/utsname.h>
# ifdef BLACKBERRY
# include <signal.h>
# else
# include <csignal>
# endif
# endif
# ifdef MAC_OS
# include <mach/clock.h>
# include <mach/mach.h>
# include <mach/mach_traps.h>
extern clock_serv_t __pi_mac_clock;
# endif
# ifdef PIP_ICU
# define U_NOEXCEPT
# include <unicode/uclean.h>
# include <unicode/ucnv.h>
# endif
# ifdef HAS_LOCALE
static locale_t currentLocale_t = 0;
# endif
PRIVATE_DEFINITION_START(PIInit)
# ifdef WINDOWS
HMODULE ntlib = nullptr;
# endif
bool delete_locs = false;
PRIVATE_DEFINITION_END(PIInit)
void __sighandler__(PISignals::Signal s) {
// piCout << Hex << int(s);
if (s == PISignals::StopTTYInput || s == PISignals::StopTTYOutput) piMSleep(10);
# if defined(PIP_INTROSPECTION) && defined(PIP_HAS_FILESYSTEM)
if (s == PISignals::UserDefined1) {
# ifdef PIP_HAS_PROCESS
int pid = PIProcess::currentPID();
# else
int pid = 0;
# endif
dumpApplicationToFile(PIDir::home().path() + PIDir::separator + PIStringAscii("_PIP_DUMP_") + PIString::fromNumber(pid));
}
# endif
}
void PIInit::initPlatform() {
# ifdef WINDOWS
# ifdef PIP_HAS_SOCKET
// WinSock inint
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
# endif
// Timers init
SYSTEMTIME jan1970 = {1970, 1, 4, 1, 0, 0, 0, 0};
SystemTimeToFileTime(&jan1970, &__pi_ftjan1970);
LARGE_INTEGER pf;
pf.QuadPart = -1;
if (QueryPerformanceFrequency(&pf) != 0) __pi_perf_freq = pf.QuadPart;
if (__pi_perf_freq == 0) __pi_perf_freq = -1;
// Sleep precision init
PRIVATE->ntlib = LoadLibraryA("ntdll.dll");
if (PRIVATE->ntlib) {
getTimerResolutionAddr = (PINtQueryTimerResolution)GetProcAddress(PRIVATE->ntlib, "NtQueryTimerResolution");
setTimerResolutionAddr = (PINtSetTimerResolution)GetProcAddress(PRIVATE->ntlib, "NtSetTimerResolution");
__PISetTimerResolution();
}
# endif
# ifdef MAC_OS
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &__pi_mac_clock);
# endif
}
void PIInit::initSignals() {
# ifndef ANDROID
PISignals::setSlot(__sighandler__);
PISignals::grabSignals(PISignals::UserDefined1);
# ifndef WINDOWS
PISignals::grabSignals(PISignals::StopTTYInput | PISignals::StopTTYOutput);
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGALRM);
sigprocmask(SIG_BLOCK, &ss, 0);
pthread_sigmask(SIG_BLOCK, &ss, 0);
signal(SIGPIPE, SIG_IGN);
# endif // WINDOWS
# endif // ANDROID
}
void PIInit::initLocale() {
# ifdef WINDOWS
// Windows branch
# ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
u_init(&e);
PRIVATE->delete_locs = true;
CPINFOEX cpinfo;
int l = 0;
GetCPInfoEx(CP_OEMCP, 0, &cpinfo);
for (l = 0; l < MAX_PATH; ++l)
if (cpinfo.CodePageName[l] == '\0' || cpinfo.CodePageName[l] == ' ') break;
__sysoemname__ = new char[256];
piZeroMemory(__sysoemname__, 256);
memcpy(__sysoemname__, "ibm-", 4);
memcpy(&(__sysoemname__[4]), cpinfo.CodePageName, l);
# else
__syslocname__ = (char *)CP_ACP;
__sysoemname__ = (char *)CP_OEMCP;
__utf8name__ = (char *)CP_UTF8;
# endif
# else // WINDOWS
// Non-Windows branch
# ifdef HAS_LOCALE
// std::cout << "has locale" << std::endl;
if (currentLocale_t != 0) {
freelocale(currentLocale_t);
currentLocale_t = 0;
}
currentLocale_t = newlocale(LC_ALL, setlocale(LC_ALL, "C"), 0);
setlocale(LC_CTYPE, "en_US.UTF-8");
# else // HAS_LOCALE
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C");
# endif // HAS_LOCALE
PRIVATE->delete_locs = false;
__syslocname__ = __sysoemname__ = 0;
__utf8name__ = const_cast<char *>("UTF-8");
# ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
u_init(&e);
# endif // PIP_ICU
# endif // WINDOWS
}
void PIInit::initPaths() {
# ifdef WINDOWS
// execute command
int argc_(0);
wchar_t ** argv_ = CommandLineToArgvW(GetCommandLineW(), &argc_);
if (argc_ > 0 && argv_ != 0) sinfo->execCommand = argv_[0];
LocalFree(argv_);
# else
# ifndef PIP_EMBEDDED
PIStringList ifpathes;
ifpathes << "/bin/ifconfig"_a << "/sbin/ifconfig"_a << "/usr/bin/ifconfig"_a
<< "/usr/sbin/ifconfig"_a;
for (const auto & i: ifpathes) {
if (fileExists(i)) {
sinfo->ifconfigPath = i;
break;
}
}
# endif // PIP_EMBEDDED
# endif // WINDOWS
}
void PIInit::initHostname() {
# ifdef PIP_HAS_SOCKET
char cbuff[1024];
piZeroMemory(cbuff, 1024);
if (gethostname(cbuff, 1023) == 0) {
sinfo->hostname = cbuff;
}
# endif
}
void PIInit::initUsername() {
# ifdef WINDOWS
char cbuff[1024];
piZeroMemory(cbuff, 1024);
ulong unlen = 1023;
if (GetUserNameA(cbuff, &unlen) != 0) sinfo->user = cbuff;
# else
# ifndef ESP_PLATFORM
passwd * ps = getpwuid(getuid());
if (ps)
sinfo->user = ps->pw_name;
else {
char cbuff[1024];
piZeroMemory(cbuff, 1024);
char * l = getlogin();
if (l) sinfo->user = l;
}
# endif // WINDOWS
# endif // WINDOWS
}
void PIInit::initOSname() {
# ifndef LINUX
sinfo->OS_name =
# ifdef WINDOWS
"Windows"_a;
# elif defined(QNX)
"QNX"_a;
# elif defined(MAC_OS)
"MacOS"_a;
# elif defined(ANDROID)
"Android"_a;
# elif defined(FREE_BSD)
"FreeBSD"_a;
# elif defined(FREERTOS)
"FreeRTOS"_a;
# else
"Unknown"_a;
# endif
# endif
}
void PIInit::initHWInfo() {
# ifdef WINDOWS
// OS version
DWORD dwVersion = GetVersion();
DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
DWORD dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
sinfo->OS_version = PIString::fromNumber(dwMajorVersion) + "." + PIString::fromNumber(dwMinorVersion);
// architecture
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
sinfo->processorsCount = sysinfo.dwNumberOfProcessors;
switch (sysinfo.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_AMD64: sinfo->architecture = "x86_64"_a; break;
case PROCESSOR_ARCHITECTURE_ARM: sinfo->architecture = "arm"_a; break;
case PROCESSOR_ARCHITECTURE_IA64: sinfo->architecture = "Intel Itanium-based"_a; break;
case PROCESSOR_ARCHITECTURE_INTEL: sinfo->architecture = "x86"_a; break;
case PROCESSOR_ARCHITECTURE_UNKNOWN:
default: sinfo->architecture = "unknown"_a; break;
}
// logical processors
DWORD procinfo_bytes = 0;
PIByteArray procinfo_buffer;
GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &procinfo_bytes);
piCout << procinfo_bytes;
if (procinfo_bytes > 0) {
int cntP = 0, cntE = 0;
procinfo_buffer.resize(procinfo_bytes);
GetLogicalProcessorInformationEx(RelationProcessorCore,
(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)procinfo_buffer.data(),
&procinfo_bytes);
DWORD offset = 0;
while (offset < procinfo_bytes) {
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)procinfo_buffer.data(offset);
offset += info->Size;
if (info->Processor.EfficiencyClass == 0)
cntE++;
else
cntP++;
}
sinfo->processorsCountP = cntP;
sinfo->processorsCountE = cntE;
} else {
printf("GetLogicalProcessorInformationEx error\n");
}
# else
# ifdef ESP_PLATFORM
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
sinfo->processorsCount = chip_info.cores;
sinfo->architecture = "Xtensa LX6";
// printf("silicon revision %d, ", chip_info.revision);
sinfo->OS_version = esp_get_idf_version();
# else
sinfo->processorsCount = piMaxi(1, int(sysconf(_SC_NPROCESSORS_ONLN)));
struct utsname uns;
if (uname(&uns) == 0) {
sinfo->OS_version = uns.release;
sinfo->architecture = uns.machine;
# ifdef LINUX
sinfo->OS_name = uns.sysname;
# endif
}
# endif
# endif // WINDOWS
}
void PIInit::initFinalize() {
if (sinfo->processorsCountP + sinfo->processorsCountE != sinfo->processorsCount) {
sinfo->processorsCountE = 0;
sinfo->processorsCountP = sinfo->processorsCount;
}
}
PIInit::PIInit() {
sinfo = PISystemInfo::instance();
sinfo->execDateTime = PIDateTime::current();
initPlatform();
initSignals();
initLocale();
initPaths();
initHostname();
initUsername();
initOSname();
initHWInfo();
initFinalize();
}
PIInit::~PIInit() {
PIResourcesStorage::instance()->clear();
# ifdef WINDOWS
# ifdef PIP_HAS_SOCKET
WSACleanup();
# endif
if (PRIVATE->ntlib) FreeLibrary(PRIVATE->ntlib);
PRIVATE->ntlib = nullptr;
# endif
# ifdef MAC_OS
mach_port_deallocate(mach_task_self(), __pi_mac_clock);
# endif
if (PRIVATE->delete_locs) {
if (__syslocname__) delete[] __syslocname__;
if (__sysoemname__) delete[] __sysoemname__;
}
# ifdef PIP_ICU
u_cleanup();
# endif
}
bool PIInit::isBuildOptionEnabled(PIInit::BuildOption o) {
switch (o) {
case boICU:
return
# ifdef PIP_ICU
true;
# else
false;
# endif
case boUSB:
return
# ifdef PIP_USB
true;
# else
false;
# endif
case boCrypt:
return
# ifdef PIP_CRYPT
true;
# else
false;
# endif
case boIntrospection:
return
# ifdef PIP_INTROSPECTION
true;
# else
false;
# endif
case boFFTW:
return
# ifdef PIP_FFTW
true;
# else
false;
# endif
case boCompress:
return
# ifdef PIP_COMPRESS
true;
# else
false;
# endif
case boOpenCL:
return
# ifdef PIP_OPENCL
true;
# else
false;
# endif
case boCloud:
return
# ifdef PIP_CLOUD
true;
# else
false;
# endif
case boConsole:
return
# ifdef PIP_CONSOLE
true;
# else
false;
# endif
default: return false;
}
return false;
}
PIStringList PIInit::buildOptions() {
PIStringList ret;
if (isBuildOptionEnabled(boICU)) ret << "ICU";
if (isBuildOptionEnabled(boUSB)) ret << "USB";
if (isBuildOptionEnabled(boCrypt)) ret << "Crypt";
if (isBuildOptionEnabled(boIntrospection)) ret << "Introspection";
if (isBuildOptionEnabled(boFFTW)) ret << "FFTW";
if (isBuildOptionEnabled(boCompress)) ret << "Compress";
if (isBuildOptionEnabled(boOpenCL)) ret << "OpenCL";
if (isBuildOptionEnabled(boCloud)) ret << "Cloud";
if (isBuildOptionEnabled(boConsole)) ret << "Console";
return ret;
}
bool PIInit::fileExists(const PIString & p) {
FILE * f = fopen(p.data(), "r");
if (f == 0) return false;
fclose(f);
return true;
}
int __PIInit_Initializer__::count_(0);
PIInit * __PIInit_Initializer__::__instance__(0);
__PIInit_Initializer__::__PIInit_Initializer__() {
count_++;
if (count_ > 1) return;
// piCout << "create PIInit";
__instance__ = new PIInit();
}
__PIInit_Initializer__::~__PIInit_Initializer__() {
count_--;
if (count_ > 0) return;
// piCout << "delete PIInit";
if (__instance__ != 0) {
delete __instance__;
__instance__ = 0;
}
}
#else
# include "pistring.h"
# include "pisysteminfo.h"
// stub: PIInit is never instantiated, __instance__ stays null
int __PIInit_Initializer__::count_(0);
PIInit * __PIInit_Initializer__::__instance__(0);
__PIInit_Initializer__::__PIInit_Initializer__() {
count_++;
if (count_ > 1) return;
__instance__ = nullptr;
PISystemInfo::instance()->OS_name = PIStringAscii("PIP Embedded");
}
__PIInit_Initializer__::~__PIInit_Initializer__() {
count_--;
if (count_ > 0) return;
if (__instance__ != 0) {
__instance__ = nullptr;
}
}
#endif // _PIP_INIT_STUB_