From b76eaf187a313c99fe008b069b8123b299752589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 1 Dec 2020 13:59:19 +0100 Subject: Dynamically load libsensors at runtime --- CPUMeter.c | 4 +- DisplayOptionsPanel.c | 4 +- Makefile.am | 2 + Settings.c | 6 +-- Settings.h | 2 +- configure.ac | 4 +- linux/LibSensors.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++ linux/LibSensors.h | 16 ++++++++ linux/LinuxProcessList.c | 46 +++------------------ linux/LinuxProcessList.h | 2 +- linux/Platform.c | 15 +++---- 11 files changed, 147 insertions(+), 59 deletions(-) create mode 100644 linux/LibSensors.c create mode 100644 linux/LibSensors.h diff --git a/CPUMeter.c b/CPUMeter.c index 61b33cb6..855d94bd 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -79,7 +79,7 @@ static void CPUMeter_updateValues(Meter* this, char* buffer, int size) { } } - #ifdef HAVE_LIBSENSORS + #ifdef HAVE_SENSORS_SENSORS_H if (this->pl->settings->showCPUTemperature) { double cpuTemperature = this->values[CPU_METER_TEMPERATURE]; if (isnan(cpuTemperature)) @@ -150,7 +150,7 @@ static void CPUMeter_display(const Object* cast, RichString* out) { } } - #ifdef HAVE_LIBSENSORS + #ifdef HAVE_SENSORS_SENSORS_H if (this->pl->settings->showCPUTemperature) { char cpuTemperatureBuffer[10]; double cpuTemperature = this->values[CPU_METER_TEMPERATURE]; diff --git a/DisplayOptionsPanel.c b/DisplayOptionsPanel.c index bf3fa584..e0d4cfd8 100644 --- a/DisplayOptionsPanel.c +++ b/DisplayOptionsPanel.c @@ -116,8 +116,8 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* Panel_add(super, (Object*) CheckItem_newByRef("Add guest time in CPU meter percentage", &(settings->accountGuestInCPUMeter))); Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU percentage numerically", &(settings->showCPUUsage))); Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU frequency", &(settings->showCPUFrequency))); - #ifdef HAVE_LIBSENSORS - Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU temperature", &(settings->showCPUTemperature))); + #ifdef HAVE_SENSORS_SENSORS_H + Panel_add(super, (Object*) CheckItem_newByRef("Also show CPU temperature (requires libsensors)", &(settings->showCPUTemperature))); Panel_add(super, (Object*) CheckItem_newByRef("- Show temperature in degree Fahrenheit instead of Celsius", &(settings->degreeFahrenheit))); #endif Panel_add(super, (Object*) CheckItem_newByRef("Enable the mouse", &(settings->enableMouse))); diff --git a/Makefile.am b/Makefile.am index 194783fa..6ef020c4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -126,6 +126,7 @@ myhtopheaders = \ linux_platform_headers = \ linux/IOPriority.h \ linux/IOPriorityPanel.h \ + linux/LibSensors.h \ linux/LinuxProcess.h \ linux/LinuxProcessList.h \ linux/Platform.h \ @@ -142,6 +143,7 @@ if HTOP_LINUX AM_LDFLAGS += -rdynamic myhtopplatsources = \ linux/IOPriorityPanel.c \ + linux/LibSensors.c \ linux/LinuxProcess.c \ linux/LinuxProcessList.c \ linux/Platform.c \ diff --git a/Settings.c b/Settings.c index f2019e9a..0b4d0ed6 100644 --- a/Settings.c +++ b/Settings.c @@ -183,7 +183,7 @@ static bool Settings_read(Settings* this, const char* fileName, int initialCpuCo this->showCPUUsage = atoi(option[1]); } else if (String_eq(option[0], "show_cpu_frequency")) { this->showCPUFrequency = atoi(option[1]); - #ifdef HAVE_LIBSENSORS + #ifdef HAVE_SENSORS_SENSORS_H } else if (String_eq(option[0], "show_cpu_temperature")) { this->showCPUTemperature = atoi(option[1]); } else if (String_eq(option[0], "degree_fahrenheit")) { @@ -292,7 +292,7 @@ bool Settings_write(Settings* this) { fprintf(fd, "cpu_count_from_one=%d\n", (int) this->countCPUsFromOne); fprintf(fd, "show_cpu_usage=%d\n", (int) this->showCPUUsage); fprintf(fd, "show_cpu_frequency=%d\n", (int) this->showCPUFrequency); - #ifdef HAVE_LIBSENSORS + #ifdef HAVE_SENSORS_SENSORS_H fprintf(fd, "show_cpu_temperature=%d\n", (int) this->showCPUTemperature); fprintf(fd, "degree_fahrenheit=%d\n", (int) this->degreeFahrenheit); #endif @@ -328,7 +328,7 @@ Settings* Settings_new(int initialCpuCount) { this->countCPUsFromOne = false; this->showCPUUsage = true; this->showCPUFrequency = false; - #ifdef HAVE_LIBSENSORS + #ifdef HAVE_SENSORS_SENSORS_H this->showCPUTemperature = false; this->degreeFahrenheit = false; #endif diff --git a/Settings.h b/Settings.h index b01ce23f..dab531f7 100644 --- a/Settings.h +++ b/Settings.h @@ -38,7 +38,7 @@ typedef struct Settings_ { bool detailedCPUTime; bool showCPUUsage; bool showCPUFrequency; - #ifdef HAVE_LIBSENSORS + #ifdef HAVE_SENSORS_SENSORS_H bool showCPUTemperature; bool degreeFahrenheit; #endif diff --git a/configure.ac b/configure.ac index edf7f366..30b2502b 100644 --- a/configure.ac +++ b/configure.ac @@ -307,13 +307,11 @@ then ]) fi -AC_ARG_ENABLE(sensors, [AS_HELP_STRING([--enable-sensors], [enable libsensors support for reading temperature data.])],, enable_sensors="check") +AC_ARG_ENABLE(sensors, [AS_HELP_STRING([--with-sensors], [Compile with libsensors support for reading temperature data. Only requires libsensors headers at compile time, at runtime libsensors is loaded via dlopen.])],, enable_sensors="check") if test "x$enable_sensors" = xyes; then - AC_CHECK_LIB([sensors], [sensors_get_value], [], [missing_libraries="$missing_libraries libsensors"]) AC_CHECK_HEADERS([sensors/sensors.h], [], [missing_headers="$missing_headers $ac_header"]) elif test "x$enable_sensors" = xcheck; then enable_sensors=yes - AC_CHECK_LIB([sensors], [sensors_get_value], [], [enable_sensors=no]) AC_CHECK_HEADERS([sensors/sensors.h], [], [enable_sensors=no]) fi diff --git a/linux/LibSensors.c b/linux/LibSensors.c new file mode 100644 index 00000000..1f3bd8de --- /dev/null +++ b/linux/LibSensors.c @@ -0,0 +1,105 @@ +#include "LibSensors.h" + +#ifdef HAVE_SENSORS_SENSORS_H + +#include +#include +#include +#include + +#include "XUtils.h" + + +static int (*sym_sensors_init)(FILE*); +static void (*sym_sensors_cleanup)(void); +static const sensors_chip_name* (*sym_sensors_get_detected_chips)(const sensors_chip_name*, int*); +static int (*sym_sensors_snprintf_chip_name)(char*, size_t, const sensors_chip_name*); +static const sensors_feature* (*sym_sensors_get_features)(const sensors_chip_name*, int*); +static const sensors_subfeature* (*sym_sensors_get_subfeature)(const sensors_chip_name*, const sensors_feature*, sensors_subfeature_type); +static int (*sym_sensors_get_value)(const sensors_chip_name*, int, double*); + +static void* dlopenHandle = NULL; + +int LibSensors_init(FILE* input) { + if (!dlopenHandle) { + dlopenHandle = dlopen("libsensors.so", RTLD_LAZY); + if (!dlopenHandle) + goto dlfailure; + + /* Clear any errors */ + dlerror(); + + #define resolve(symbolname) do { \ + *(void **)(&sym_##symbolname) = dlsym(dlopenHandle, #symbolname); \ + if (!sym_##symbolname || dlerror() != NULL) \ + goto dlfailure; \ + } while(0) + + resolve(sensors_init); + resolve(sensors_cleanup); + resolve(sensors_get_detected_chips); + resolve(sensors_snprintf_chip_name); + resolve(sensors_get_features); + resolve(sensors_get_subfeature); + resolve(sensors_get_value); + + #undef resolve + } + + return sym_sensors_init(input); + +dlfailure: + if (dlopenHandle) { + dlclose(dlopenHandle); + dlopenHandle = NULL; + } + return -1; +} + +void LibSensors_cleanup(void) { + if (dlopenHandle) { + sym_sensors_cleanup(); + + dlclose(dlopenHandle); + dlopenHandle = NULL; + } +} + +int LibSensors_getCPUTemperatures(CPUData* cpus, int cpuCount) { + if (!dlopenHandle) + return -ENOTSUP; + + int tempCount = 0; + + int n = 0; + for (const sensors_chip_name *chip = sym_sensors_get_detected_chips(NULL, &n); chip; chip = sym_sensors_get_detected_chips(NULL, &n)) { + char buffer[32]; + sym_sensors_snprintf_chip_name(buffer, sizeof(buffer), chip); + if (!String_startsWith(buffer, "coretemp") && !String_startsWith(buffer, "cpu_thermal")) + continue; + + int m = 0; + for (const sensors_feature *feature = sym_sensors_get_features(chip, &m); feature; feature = sym_sensors_get_features(chip, &m)) { + if (feature->type != SENSORS_FEATURE_TEMP) + continue; + + if (feature->number > cpuCount) + continue; + + const sensors_subfeature *sub_feature = sym_sensors_get_subfeature(chip, feature, SENSORS_SUBFEATURE_TEMP_INPUT); + if (sub_feature) { + double temp; + int r = sym_sensors_get_value(chip, sub_feature->number, &temp); + if (r != 0) + continue; + + cpus[feature->number].temperature = temp; + tempCount++; + } + } + } + + return tempCount; +} + +#endif /* HAVE_SENSORS_SENSORS_H */ diff --git a/linux/LibSensors.h b/linux/LibSensors.h new file mode 100644 index 00000000..ed9be7b0 --- /dev/null +++ b/linux/LibSensors.h @@ -0,0 +1,16 @@ +#ifndef HEADER_LibSensors +#define HEADER_LibSensors + +#include "config.h" // IWYU pragma: keep + +#include + +#include "LinuxProcessList.h" + + +int LibSensors_init(FILE* input); +void LibSensors_cleanup(void); + +int LibSensors_getCPUTemperatures(CPUData* cpus, int cpuCount); + +#endif /* HEADER_LibSensors */ diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index fd8f5aff..5d9ec87b 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -53,8 +53,8 @@ in the source distribution for its full text. #include #endif -#ifdef HAVE_LIBSENSORS -#include +#ifdef HAVE_SENSORS_SENSORS_H +#include "LibSensors.h" #endif @@ -1794,41 +1794,7 @@ static void LinuxProcessList_scanCPUFrequency(LinuxProcessList* this) { scanCPUFreqencyFromCPUinfo(this); } -#ifdef HAVE_LIBSENSORS -static int getCPUTemperatures(CPUData* cpus, int cpuCount) { - int tempCount = 0; - - int n = 0; - for (const sensors_chip_name *chip = sensors_get_detected_chips(NULL, &n); chip; chip = sensors_get_detected_chips(NULL, &n)) { - char buffer[32]; - sensors_snprintf_chip_name(buffer, sizeof(buffer), chip); - if (!String_startsWith(buffer, "coretemp") && !String_startsWith(buffer, "cpu_thermal")) - continue; - - int m = 0; - for (const sensors_feature *feature = sensors_get_features(chip, &m); feature; feature = sensors_get_features(chip, &m)) { - if (feature->type != SENSORS_FEATURE_TEMP) - continue; - - if (feature->number > cpuCount) - continue; - - const sensors_subfeature *sub_feature = sensors_get_subfeature(chip, feature, SENSORS_SUBFEATURE_TEMP_INPUT); - if (sub_feature) { - double temp; - int r = sensors_get_value(chip, sub_feature->number, &temp); - if (r != 0) - continue; - - cpus[feature->number].temperature = temp; - tempCount++; - } - } - } - - return tempCount; -} - +#ifdef HAVE_SENSORS_SENSORS_H static void LinuxProcessList_scanCPUTemperature(LinuxProcessList* this) { const int cpuCount = this->super.cpuCount; @@ -1836,10 +1802,10 @@ static void LinuxProcessList_scanCPUTemperature(LinuxProcessList* this) { this->cpus[i].temperature = NAN; } - int r = getCPUTemperatures(this->cpus, cpuCount); + int r = LibSensors_getCPUTemperatures(this->cpus, cpuCount); /* No temperature - nothing to do */ - if (r == 0) + if (r <= 0) return; /* Only package temperature - copy to all cpus */ @@ -1878,7 +1844,7 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { LinuxProcessList_scanCPUFrequency(this); } - #ifdef HAVE_LIBSENSORS + #ifdef HAVE_SENSORS_SENSORS_H if (settings->showCPUTemperature) LinuxProcessList_scanCPUTemperature(this); #endif diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h index 6ce9d029..09b84afa 100644 --- a/linux/LinuxProcessList.h +++ b/linux/LinuxProcessList.h @@ -48,7 +48,7 @@ typedef struct CPUData_ { double frequency; - #ifdef HAVE_LIBSENSORS + #ifdef HAVE_SENSORS_SENSORS_H double temperature; #endif } CPUData; diff --git a/linux/Platform.c b/linux/Platform.c index 1462f82e..833044b1 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -61,10 +61,11 @@ in the source distribution for its full text. #include "zfs/ZfsArcStats.h" #include "zfs/ZfsCompressedArcMeter.h" -#ifdef HAVE_LIBSENSORS -#include +#ifdef HAVE_SENSORS_SENSORS_H +#include "LibSensors.h" #endif + ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_VIRT, M_RESIDENT, (int)M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 }; int Platform_numberOfFields = LAST_PROCESSFIELD; @@ -119,14 +120,14 @@ void Platform_init(void) { exit(1); } -#ifdef HAVE_LIBSENSORS - sensors_init(NULL); +#ifdef HAVE_SENSORS_SENSORS_H + LibSensors_init(NULL); #endif } void Platform_done(void) { -#ifdef HAVE_LIBSENSORS - sensors_cleanup(); +#ifdef HAVE_SENSORS_SENSORS_H + LibSensors_cleanup(); #endif } @@ -271,7 +272,7 @@ double Platform_setCPUValues(Meter* this, int cpu) { v[CPU_METER_FREQUENCY] = cpuData->frequency; -#ifdef HAVE_LIBSENSORS +#ifdef HAVE_SENSORS_SENSORS_H v[CPU_METER_TEMPERATURE] = cpuData->temperature; #else v[CPU_METER_TEMPERATURE] = NAN; -- cgit v1.2.3