mirror of
https://github.com/netdata/netdata.git
synced 2025-04-02 20:48:06 +00:00
Run the agent as a Windows service. (#17766)
* Run the agent as a Windows service. This commit contains the boilerplate code for running the agent as a Windows service. We start the agent's main as a separate thread, although this is not strictly required based on my experiments. We need similar logic for calling netdata's exit function when someone wants to stop the agent. However, at this point we need to resolve the issue of gaps when running the agent as a service. It seems that sleeping for one second with `sleep(1)`, actually sleeps for 2 to 4 seconds on my setup. Once we resolve this, the work that remains concerns packaging: ie. installing the binaries at the proper places so that the relevant DLLs are found. To test this PR you need to: - Build the agent: ./packaging/utils/compile-on-windows.sh - Install the files: `ninja -C build/ install` - Copy the main binary: `cp ./build/netdata /usr/bin/` - (Only once) Create the netdata service: `sc.exe config Netdata binPath="C:\msys64\usr\bin\netdata"` - Start the service: `sc.exe start Netdata` A couple notes: - The health and the spawn client have been disabled for the time being. They will be re-enabled once we finish the agent-as-service issue and the packaging. - Last time I checked, the agent crashes after a while when using dbengine. In order to have something that works correctly, you should specify memory-mode ram in your netdata.conf. * Add windows version for sleep_usec_with_now * Split install prefix from runtime prefix These paths are always the same for non-Windows systems. On Windows, RFS is the top-level installation path. With the current setup, Netdata will be installed at C:\msys64\opt\netdata at packaging time. However, the layout of the application means that when the agent starts, it'll look as if everything was installed at /. * Do not use mold linker on Windows. * Use modern UI for installer. * Make the service delayed-auto * Use mutexes instead of spinlocks. * Update service handling logic. * Add proper ifdefs for spinlock implementation. * Initialize analytics spinlock * Add a macro to build the agent as regular cli tool. * Add makensis dependency * Let installer know it's installing Netdata. * Disable pluginsd on Windows When pluginsd is enabled, the agent freezes approximately 20% of the time during startup. * Add service description. * Return pthread_join result * Print tag when we fail to join a thread. * Do not use mutexes instead of spinlocks. * Assorted changes to service/main code. * Rework service functions. With the current implementation we are not getting any MUTEX_LOCK errors and thread joining succeeds. The only case where joining fails is the parallel initialization of dbengine threads, which we can easily avoid by serializing the initialization step. * Rework main functions This will allow someone to run the agent either as a service or as a command-line tool. * Change runtime prefix only when building for packaging. * Install binaries and dlls. * Make netdata claiming through UI work correctly. * Fix netdata path
This commit is contained in:
parent
a38e6eef93
commit
e99da8b64b
19 changed files with 616 additions and 87 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -199,3 +199,6 @@ src/go/collectors/go.d.plugin/mocks/springboot2/.gradle/
|
|||
src/go/collectors/go.d.plugin/mocks/tmp/*
|
||||
!src/go/collectors/go.d.plugin/mocks/tmp/.gitkeep
|
||||
src/go/collectors/go.d.plugin/vendor
|
||||
|
||||
# ignore nsis installer
|
||||
packaging/utils/netdata-installer.exe
|
||||
|
|
128
CMakeLists.txt
128
CMakeLists.txt
|
@ -92,6 +92,9 @@ set(OS_MACOS False)
|
|||
set(OS_WINDOWS False)
|
||||
set(ALLOW_PLATFORM_SENSITIVE_OPTIONS True)
|
||||
|
||||
set(NETDATA_RUNTIME_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
set(BINDIR usr/sbin)
|
||||
|
||||
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
||||
set(OS_MACOS True)
|
||||
find_library(IOKIT IOKit)
|
||||
|
@ -111,6 +114,16 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
|||
endif()
|
||||
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "MSYS" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
|
||||
set(OS_WINDOWS True)
|
||||
|
||||
if(NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "/opt/netdata")
|
||||
message(FATAL_ERROR "CMAKE_INSTALL_PREFIX must be set to /opt/netdata, but it is set to ${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
|
||||
if(BUILD_FOR_PACKAGING)
|
||||
set(NETDATA_RUNTIME_PREFIX "/")
|
||||
endif()
|
||||
|
||||
set(BINDIR usr/bin)
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
|
||||
if($ENV{CLION_IDE})
|
||||
|
@ -1434,6 +1447,7 @@ elseif(OS_FREEBSD)
|
|||
elseif(OS_WINDOWS)
|
||||
list(APPEND NETDATA_FILES
|
||||
src/daemon/static_threads_windows.c
|
||||
src/daemon/winsvc.cc
|
||||
${WINDOWS_PLUGIN_FILES}
|
||||
${INTERNAL_COLLECTORS_FILES}
|
||||
)
|
||||
|
@ -2279,7 +2293,7 @@ target_link_libraries(systemd-cat-native libnetdata)
|
|||
|
||||
install(TARGETS systemd-cat-native
|
||||
COMPONENT netdata
|
||||
DESTINATION usr/sbin)
|
||||
DESTINATION "${BINDIR}")
|
||||
|
||||
#
|
||||
# build log2journal
|
||||
|
@ -2314,7 +2328,7 @@ if(PCRE2_FOUND)
|
|||
|
||||
install(TARGETS log2journal
|
||||
COMPONENT netdata
|
||||
DESTINATION usr/sbin)
|
||||
DESTINATION "${BINDIR}")
|
||||
|
||||
install(DIRECTORY src/collectors/log2journal/log2journal.d
|
||||
COMPONENT netdata
|
||||
|
@ -2337,7 +2351,7 @@ target_link_libraries(netdatacli libnetdata)
|
|||
|
||||
install(TARGETS netdatacli
|
||||
COMPONENT netdata
|
||||
DESTINATION usr/sbin)
|
||||
DESTINATION "${BINDIR}")
|
||||
|
||||
#
|
||||
# Build go.d.plugin
|
||||
|
@ -2354,17 +2368,16 @@ endif()
|
|||
#
|
||||
# Generate config file
|
||||
#
|
||||
|
||||
if(NOT CMAKE_INSTALL_PREFIX STREQUAL "")
|
||||
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
if(NOT NETDATA_RUNTIME_PREFIX STREQUAL "")
|
||||
string(REGEX REPLACE "/$" "" NETDATA_RUNTIME_PREFIX "${NETDATA_RUNTIME_PREFIX}")
|
||||
endif()
|
||||
|
||||
set(CACHE_DIR "${CMAKE_INSTALL_PREFIX}/var/cache/netdata")
|
||||
set(CONFIG_DIR "${CMAKE_INSTALL_PREFIX}/etc/netdata")
|
||||
set(LIBCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/usr/lib/netdata/conf.d")
|
||||
set(LOG_DIR "${CMAKE_INSTALL_PREFIX}/var/log/netdata")
|
||||
set(PLUGINS_DIR "${CMAKE_INSTALL_PREFIX}/usr/libexec/netdata/plugins.d")
|
||||
set(VARLIB_DIR "${CMAKE_INSTALL_PREFIX}/var/lib/netdata")
|
||||
set(CACHE_DIR "${NETDATA_RUNTIME_PREFIX}/var/cache/netdata")
|
||||
set(CONFIG_DIR "${NETDATA_RUNTIME_PREFIX}/etc/netdata")
|
||||
set(LIBCONFIG_DIR "${NETDATA_RUNTIME_PREFIX}/usr/lib/netdata/conf.d")
|
||||
set(LOG_DIR "${NETDATA_RUNTIME_PREFIX}/var/log/netdata")
|
||||
set(PLUGINS_DIR "${NETDATA_RUNTIME_PREFIX}/usr/libexec/netdata/plugins.d")
|
||||
set(VARLIB_DIR "${NETDATA_RUNTIME_PREFIX}/var/lib/netdata")
|
||||
|
||||
# A non-default value is only used when building Debian packages (/var/lib/netdata/www)
|
||||
if(NOT DEFINED WEB_DIR)
|
||||
|
@ -2373,7 +2386,7 @@ else()
|
|||
string(REGEX REPLACE "^/" "" WEB_DIR "${WEB_DIR}")
|
||||
endif()
|
||||
set(WEB_DEST "${WEB_DIR}")
|
||||
set(WEB_DIR "${CMAKE_INSTALL_PREFIX}/${WEB_DEST}")
|
||||
set(WEB_DIR "${NETDATA_RUNTIME_PREFIX}/${WEB_DEST}")
|
||||
|
||||
|
||||
set(CONFIGURE_COMMAND "dummy-configure-command")
|
||||
|
@ -2387,7 +2400,7 @@ configure_file(packaging/cmake/config.cmake.h.in config.h)
|
|||
# install
|
||||
#
|
||||
|
||||
install(TARGETS netdata COMPONENT netdata DESTINATION usr/sbin)
|
||||
install(TARGETS netdata COMPONENT netdata DESTINATION "${BINDIR}")
|
||||
|
||||
install(DIRECTORY COMPONENT netdata DESTINATION var/cache/netdata)
|
||||
install(DIRECTORY COMPONENT netdata DESTINATION var/log/netdata)
|
||||
|
@ -2406,15 +2419,15 @@ install(DIRECTORY COMPONENT netdata DESTINATION usr/lib/netdata/conf.d/schema.d)
|
|||
install(DIRECTORY COMPONENT netdata DESTINATION usr/libexec/netdata/plugins.d)
|
||||
install(DIRECTORY COMPONENT netdata DESTINATION ${WEB_DEST})
|
||||
|
||||
set(libsysdir_POST "${CMAKE_INSTALL_PREFIX}/usr/lib/netdata/system")
|
||||
set(pkglibexecdir_POST "${CMAKE_INSTALL_PREFIX}/usr/libexec/netdata")
|
||||
set(localstatedir_POST "${CMAKE_INSTALL_PREFIX}/var")
|
||||
set(sbindir_POST "${CMAKE_INSTALL_PREFIX}/usr/sbin")
|
||||
set(configdir_POST "${CMAKE_INSTALL_PREFIX}/etc/netdata")
|
||||
set(libconfigdir_POST "${CMAKE_INSTALL_PREFIX}/usr/lib/netdata/conf.d")
|
||||
set(cachedir_POST "${CMAKE_INSTALL_PREFIX}/var/cache/netdata")
|
||||
set(registrydir_POST "${CMAKE_INSTALL_PREFIX}/var/lib/netdata/registry")
|
||||
set(varlibdir_POST "${CMAKE_INSTALL_PREFIX}/var/lib/netdata")
|
||||
set(libsysdir_POST "${NETDATA_RUNTIME_PREFIX}/usr/lib/netdata/system")
|
||||
set(pkglibexecdir_POST "${NETDATA_RUNTIME_PREFIX}/usr/libexec/netdata")
|
||||
set(localstatedir_POST "${NETDATA_RUNTIME_PREFIX}/var")
|
||||
set(sbindir_POST "${NETDATA_RUNTIME_PREFIX}/${BINDIR}")
|
||||
set(configdir_POST "${NETDATA_RUNTIME_PREFIX}/etc/netdata")
|
||||
set(libconfigdir_POST "${NETDATA_RUNTIME_PREFIX}/usr/lib/netdata/conf.d")
|
||||
set(cachedir_POST "${NETDATA_RUNTIME_PREFIX}/var/cache/netdata")
|
||||
set(registrydir_POST "${NETDATA_RUNTIME_PREFIX}/var/lib/netdata/registry")
|
||||
set(varlibdir_POST "${NETDATA_RUNTIME_PREFIX}/var/lib/netdata")
|
||||
set(netdata_user_POST "${NETDATA_USER}")
|
||||
|
||||
# netdata-claim.sh
|
||||
|
@ -2434,7 +2447,7 @@ configure_file(src/claim/netdata-claim.sh.in src/claim/netdata-claim.sh @ONLY)
|
|||
install(PROGRAMS
|
||||
${CMAKE_BINARY_DIR}/src/claim/netdata-claim.sh
|
||||
COMPONENT netdata
|
||||
DESTINATION usr/sbin)
|
||||
DESTINATION "${BINDIR}")
|
||||
|
||||
#
|
||||
# We don't check ENABLE_PLUGIN_CGROUP_NETWORK because rpm builds assume
|
||||
|
@ -3026,4 +3039,71 @@ if(NOT OS_WINDOWS)
|
|||
DESTINATION ${WEB_DEST}/v0)
|
||||
endif()
|
||||
|
||||
if(OS_WINDOWS)
|
||||
install(FILES /usr/bin/awk.exe
|
||||
/usr/bin/bash.exe
|
||||
/usr/bin/cat.exe
|
||||
/usr/bin/chown.exe
|
||||
/usr/bin/curl.exe
|
||||
/usr/bin/env.exe
|
||||
/usr/bin/grep.exe
|
||||
/usr/bin/mkdir.exe
|
||||
/usr/bin/openssl.exe
|
||||
/usr/bin/rm.exe
|
||||
/usr/bin/sed.exe
|
||||
/usr/bin/sh.exe
|
||||
/usr/bin/tail.exe
|
||||
/usr/bin/tr.exe
|
||||
/usr/bin/uuidgen.exe
|
||||
/usr/bin/whoami.exe
|
||||
DESTINATION "${BINDIR}")
|
||||
|
||||
install(FILES /usr/bin/msys-2.0.dll
|
||||
/usr/bin/msys-asn1-8.dll
|
||||
/usr/bin/msys-brotlicommon-1.dll
|
||||
/usr/bin/msys-brotlidec-1.dll
|
||||
/usr/bin/msys-brotlienc-1.dll
|
||||
/usr/bin/msys-com_err-1.dll
|
||||
/usr/bin/msys-crypt-2.dll
|
||||
/usr/bin/msys-crypto-3.dll
|
||||
/usr/bin/msys-curl-4.dll
|
||||
/usr/bin/msys-gcc_s-seh-1.dll
|
||||
/usr/bin/msys-gmp-10.dll
|
||||
/usr/bin/msys-gssapi-3.dll
|
||||
/usr/bin/msys-hcrypto-4.dll
|
||||
/usr/bin/msys-heimbase-1.dll
|
||||
/usr/bin/msys-heimntlm-0.dll
|
||||
/usr/bin/msys-hx509-5.dll
|
||||
/usr/bin/msys-iconv-2.dll
|
||||
/usr/bin/msys-idn2-0.dll
|
||||
/usr/bin/msys-intl-8.dll
|
||||
/usr/bin/msys-krb5-26.dll
|
||||
/usr/bin/msys-lz4-1.dll
|
||||
/usr/bin/msys-mpfr-6.dll
|
||||
/usr/bin/msys-ncursesw6.dll
|
||||
/usr/bin/msys-nghttp2-14.dll
|
||||
/usr/bin/msys-pcre-1.dll
|
||||
/usr/bin/msys-protobuf-32.dll
|
||||
/usr/bin/msys-psl-5.dll
|
||||
/usr/bin/msys-readline8.dll
|
||||
/usr/bin/msys-roken-18.dll
|
||||
/usr/bin/msys-sqlite3-0.dll
|
||||
/usr/bin/msys-ssh2-1.dll
|
||||
/usr/bin/msys-ssl-3.dll
|
||||
/usr/bin/msys-stdc++-6.dll
|
||||
/usr/bin/msys-unistring-5.dll
|
||||
/usr/bin/msys-uuid-1.dll
|
||||
/usr/bin/msys-uv-1.dll
|
||||
/usr/bin/msys-wind-0.dll
|
||||
/usr/bin/msys-z.dll
|
||||
/usr/bin/msys-zstd-1.dll
|
||||
DESTINATION "${BINDIR}")
|
||||
|
||||
# Make bash & netdata happy
|
||||
install(DIRECTORY DESTINATION tmp)
|
||||
|
||||
# Make curl work with ssl
|
||||
install(DIRECTORY /usr/ssl DESTINATION usr)
|
||||
endif()
|
||||
|
||||
include(Packaging)
|
||||
|
|
|
@ -16,7 +16,8 @@ install_dependencies() {
|
|||
msys/pcre2-devel mingw64/mingw-w64-x86_64-pcre2 ucrt64/mingw-w64-ucrt-x86_64-pcre2 \
|
||||
msys/brotli-devel mingw64/mingw-w64-x86_64-brotli ucrt64/mingw-w64-ucrt-x86_64-brotli \
|
||||
msys/ccache ucrt64/mingw-w64-ucrt-x86_64-ccache mingw64/mingw-w64-x86_64-ccache \
|
||||
mingw64/mingw-w64-x86_64-go ucrt64/mingw-w64-ucrt-x86_64-go
|
||||
mingw64/mingw-w64-x86_64-go ucrt64/mingw-w64-ucrt-x86_64-go \
|
||||
mingw64/mingw-w64-x86_64-nsis
|
||||
}
|
||||
|
||||
if [ "${1}" = "install" ]
|
||||
|
@ -52,7 +53,9 @@ fi
|
|||
-G Ninja \
|
||||
-DCMAKE_INSTALL_PREFIX="/opt/netdata" \
|
||||
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
|
||||
-DCMAKE_C_FLAGS="-O0 -ggdb -Wall -Wextra -Wno-char-subscripts -Wa,-mbig-obj -pipe -DNETDATA_INTERNAL_CHECKS=1 -D_FILE_OFFSET_BITS=64 -D__USE_MINGW_ANSI_STDIO=1" \
|
||||
-DCMAKE_C_FLAGS="-fstack-protector-all -O0 -ggdb -Wall -Wextra -Wno-char-subscripts -Wa,-mbig-obj -pipe -DNETDATA_INTERNAL_CHECKS=1 -D_FILE_OFFSET_BITS=64 -D__USE_MINGW_ANSI_STDIO=1" \
|
||||
-DBUILD_FOR_PACKAGING=On \
|
||||
-DUSE_MOLD=Off \
|
||||
-DNETDATA_USER="${USER}" \
|
||||
-DDEFAULT_FEATURE_STATE=Off \
|
||||
-DENABLE_H2O=Off \
|
||||
|
|
16
packaging/utils/find-dll-deps.sh
Normal file
16
packaging/utils/find-dll-deps.sh
Normal file
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "Usage: $0 <command1> <command2> ... <commandN>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
results=()
|
||||
|
||||
for arg in "$@"; do
|
||||
while IFS= read -r line; do
|
||||
results+=("$line")
|
||||
done < <(ldd "$arg" | grep /usr/bin | awk '{ print $3 }')
|
||||
done
|
||||
|
||||
printf "%s\n" "${results[@]}" | sort | uniq
|
|
@ -1,34 +1,58 @@
|
|||
Outfile "netdata-installer.exe"
|
||||
InstallDir "C:\netdata"
|
||||
!include "MUI2.nsh"
|
||||
|
||||
Name "Netdata"
|
||||
Outfile "netdata-installer.exe"
|
||||
InstallDir "$PROGRAMFILES\netdata"
|
||||
RequestExecutionLevel admin
|
||||
|
||||
Section
|
||||
SetOutPath $INSTDIR
|
||||
WriteUninstaller $INSTDIR\uninstaller.exe
|
||||
SectionEnd
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_UNABORTWARNING
|
||||
|
||||
Section "Install MSYS2 environment"
|
||||
SetOutPath $TEMP
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
SetCompress off
|
||||
File "C:\msys64\msys2-installer.exe"
|
||||
nsExec::ExecToLog 'cmd.exe /C "$TEMP\msys2-installer.exe" in --confirm-command --accept-messages --root $INSTDIR'
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
Delete "$TEMP\msys2-installer.exe"
|
||||
SectionEnd
|
||||
|
||||
Section "Install MSYS2 packages"
|
||||
ExecWait '"$INSTDIR\usr\bin\bash.exe" -lc "pacman -S --noconfirm msys/libuv msys/protobuf"'
|
||||
SectionEnd
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
Section "Install Netdata"
|
||||
SetOutPath $INSTDIR\opt\netdata
|
||||
|
||||
SetOutPath $INSTDIR
|
||||
SetCompress off
|
||||
|
||||
File /r "C:\msys64\opt\netdata\*.*"
|
||||
|
||||
ClearErrors
|
||||
ExecWait '"$SYSDIR\sc.exe" create Netdata binPath= "$INSTDIR\usr\bin\netdata.exe" start= delayed-auto'
|
||||
IfErrors 0 +2
|
||||
DetailPrint "Warning: Failed to create Netdata service."
|
||||
|
||||
ClearErrors
|
||||
ExecWait '"$SYSDIR\sc.exe" description Netdata "Real-time system monitoring service"'
|
||||
IfErrors 0 +2
|
||||
DetailPrint "Warning: Failed to add Netdata service description."
|
||||
|
||||
ClearErrors
|
||||
ExecWait '"$SYSDIR\sc.exe" start Netdata'
|
||||
IfErrors 0 +2
|
||||
DetailPrint "Warning: Failed to start Netdata service."
|
||||
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
SectionEnd
|
||||
|
||||
Section "Uninstall"
|
||||
nsExec::ExecToLog 'cmd.exe /C "$INSTDIR\uninstall.exe" pr --confirm-command'
|
||||
ClearErrors
|
||||
ExecWait '"$SYSDIR\sc.exe" stop Netdata'
|
||||
IfErrors 0 +2
|
||||
DetailPrint "Warning: Failed to stop Netdata service."
|
||||
|
||||
ClearErrors
|
||||
ExecWait '"$SYSDIR\sc.exe" delete Netdata'
|
||||
IfErrors 0 +2
|
||||
DetailPrint "Warning: Failed to delete Netdata service."
|
||||
|
||||
RMDir /r "$INSTDIR"
|
||||
SectionEnd
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "analytics.h"
|
||||
#include "common.h"
|
||||
#include "buildinfo.h"
|
||||
|
||||
|
@ -470,8 +471,6 @@ void analytics_alarms(void)
|
|||
*/
|
||||
void analytics_misc(void)
|
||||
{
|
||||
spinlock_init(&analytics_data.spinlock);
|
||||
|
||||
#ifdef ENABLE_ACLK
|
||||
analytics_set_data(&analytics_data.netdata_host_cloud_available, "true");
|
||||
analytics_set_data_str(&analytics_data.netdata_host_aclk_implementation, "Next Generation");
|
||||
|
@ -1081,3 +1080,8 @@ void analytics_statistic_send(const analytics_statistic_t *statistic) {
|
|||
|
||||
freez(command_to_run);
|
||||
}
|
||||
|
||||
void analytics_init(void)
|
||||
{
|
||||
spinlock_init(&analytics_data.spinlock);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ void analytics_log_dashboard(void);
|
|||
void analytics_gather_mutable_meta_data(void);
|
||||
void analytics_report_oom_score(long long int score);
|
||||
void get_system_timezone(void);
|
||||
void analytics_init(void);
|
||||
|
||||
typedef struct {
|
||||
const char *action;
|
||||
|
|
|
@ -496,6 +496,10 @@ void netdata_cleanup_and_exit(int ret, const char *action, const char *action_re
|
|||
watcher_shutdown_end();
|
||||
watcher_thread_stop();
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SENTRY
|
||||
if (ret)
|
||||
abort();
|
||||
|
@ -1460,7 +1464,11 @@ int unittest_prepare_rrd(char **user) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int netdata_main(int argc, char **argv)
|
||||
{
|
||||
analytics_init();
|
||||
string_init();
|
||||
|
||||
// initialize the system clocks
|
||||
clocks_init();
|
||||
netdata_start_time = now_realtime_sec();
|
||||
|
@ -1471,11 +1479,16 @@ int main(int argc, char **argv) {
|
|||
|
||||
int i;
|
||||
int config_loaded = 0;
|
||||
int dont_fork = 0;
|
||||
bool close_open_fds = true;
|
||||
size_t default_stacksize;
|
||||
char *user = NULL;
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
int dont_fork = 1;
|
||||
#else
|
||||
int dont_fork = 0;
|
||||
#endif
|
||||
|
||||
static_threads = static_threads_get();
|
||||
|
||||
netdata_ready = false;
|
||||
|
@ -2214,7 +2227,10 @@ int main(int argc, char **argv) {
|
|||
|
||||
// fork the spawn server
|
||||
delta_startup_time("fork the spawn server");
|
||||
|
||||
#ifndef OS_WINDOWS
|
||||
spawn_init();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Libuv uv_spawn() uses SIGCHLD internally:
|
||||
|
@ -2357,22 +2373,21 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// initialize WebRTC
|
||||
|
||||
webrtc_initialize();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// unblock signals
|
||||
|
||||
signals_unblock();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Handle signals
|
||||
return 10;
|
||||
}
|
||||
|
||||
#ifndef OS_WINDOWS
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rc = netdata_main(argc, argv);
|
||||
if (rc != 10)
|
||||
return rc;
|
||||
|
||||
signals_handle();
|
||||
|
||||
// should never reach this point
|
||||
// but we need it for rpmlint #2752
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -30,7 +30,7 @@ const struct netdata_static_thread static_threads_common[] = {
|
|||
.name = "HEALTH",
|
||||
.config_section = NULL,
|
||||
.config_name = NULL,
|
||||
.enabled = 1,
|
||||
.enabled = 0,
|
||||
.thread = NULL,
|
||||
.init_routine = NULL,
|
||||
.start_routine = health_main
|
||||
|
@ -70,7 +70,11 @@ const struct netdata_static_thread static_threads_common[] = {
|
|||
.name = "PLUGINSD",
|
||||
.config_section = NULL,
|
||||
.config_name = NULL,
|
||||
#ifdef OS_WINDOWS
|
||||
.enabled = 0,
|
||||
#else
|
||||
.enabled = 1,
|
||||
#endif
|
||||
.thread = NULL,
|
||||
.init_routine = NULL,
|
||||
.start_routine = pluginsd_main
|
||||
|
|
252
src/daemon/winsvc.cc
Normal file
252
src/daemon/winsvc.cc
Normal file
|
@ -0,0 +1,252 @@
|
|||
extern "C" {
|
||||
|
||||
#include "daemon.h"
|
||||
#include "libnetdata/libnetdata.h"
|
||||
|
||||
int netdata_main(int argc, char *argv[]);
|
||||
void signals_handle(void);
|
||||
|
||||
}
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
static void netdata_service_log(const char *fmt, ...)
|
||||
{
|
||||
char path[FILENAME_MAX + 1];
|
||||
snprintfz(path, FILENAME_MAX, "%s/service.log", LOG_DIR);
|
||||
|
||||
FILE *fp = fopen(path, "a");
|
||||
if (fp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
SYSTEMTIME time;
|
||||
GetSystemTime(&time);
|
||||
fprintf(fp, "%d:%d:%d - ", time.wHour, time.wMinute, time.wSecond);
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(fp, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static SERVICE_STATUS_HANDLE svc_status_handle = nullptr;
|
||||
static SERVICE_STATUS svc_status = {};
|
||||
|
||||
static HANDLE svc_stop_event_handle = nullptr;
|
||||
|
||||
static ND_THREAD *cleanup_thread = nullptr;
|
||||
|
||||
static bool ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint, DWORD dwControlsAccepted)
|
||||
{
|
||||
static DWORD dwCheckPoint = 1;
|
||||
svc_status.dwCurrentState = dwCurrentState;
|
||||
svc_status.dwWin32ExitCode = dwWin32ExitCode;
|
||||
svc_status.dwWaitHint = dwWaitHint;
|
||||
svc_status.dwControlsAccepted = dwControlsAccepted;
|
||||
|
||||
if (dwCurrentState == SERVICE_RUNNING || dwCurrentState == SERVICE_STOPPED)
|
||||
{
|
||||
svc_status.dwCheckPoint = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
svc_status.dwCheckPoint = dwCheckPoint++;
|
||||
}
|
||||
|
||||
if (!SetServiceStatus(svc_status_handle, &svc_status)) {
|
||||
netdata_service_log("@ReportSvcStatus: SetServiceStatusFailed (%d)", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static HANDLE CreateEventHandle(const char *msg)
|
||||
{
|
||||
HANDLE h = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (!h)
|
||||
{
|
||||
netdata_service_log(msg);
|
||||
|
||||
if (!ReportSvcStatus(SERVICE_STOPPED, GetLastError(), 1000, 0))
|
||||
{
|
||||
netdata_service_log("Failed to set service status to stopped.");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static void *call_netdata_cleanup(void *arg)
|
||||
{
|
||||
UNUSED(arg);
|
||||
|
||||
// Wait until we have to stop the service
|
||||
netdata_service_log("Cleanup thread waiting for stop event...");
|
||||
WaitForSingleObject(svc_stop_event_handle, INFINITE);
|
||||
|
||||
// Stop the agent
|
||||
netdata_service_log("Running netdata cleanup...");
|
||||
netdata_cleanup_and_exit(0, NULL, NULL, NULL);
|
||||
|
||||
// Close event handle
|
||||
netdata_service_log("Closing stop event handle...");
|
||||
CloseHandle(svc_stop_event_handle);
|
||||
|
||||
// Set status to stopped
|
||||
netdata_service_log("Reporting the service as stopped...");
|
||||
ReportSvcStatus(SERVICE_STOPPED, 0, 0, 0);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void WINAPI ServiceControlHandler(DWORD controlCode)
|
||||
{
|
||||
switch (controlCode)
|
||||
{
|
||||
case SERVICE_CONTROL_STOP:
|
||||
{
|
||||
if (svc_status.dwCurrentState != SERVICE_RUNNING)
|
||||
return;
|
||||
|
||||
// Set service status to stop-pending
|
||||
netdata_service_log("Setting service status to stop-pending...");
|
||||
if (!ReportSvcStatus(SERVICE_STOP_PENDING, 0, 5000, 0))
|
||||
return;
|
||||
|
||||
// Create cleanup thread
|
||||
netdata_service_log("Creating cleanup thread...");
|
||||
char tag[NETDATA_THREAD_TAG_MAX + 1];
|
||||
snprintfz(tag, NETDATA_THREAD_TAG_MAX, "%s", "CLEANUP");
|
||||
cleanup_thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_JOINABLE, call_netdata_cleanup, NULL);
|
||||
|
||||
// Signal the stop request
|
||||
netdata_service_log("Signalling the cleanup thread...");
|
||||
SetEvent(svc_stop_event_handle);
|
||||
break;
|
||||
}
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
{
|
||||
ReportSvcStatus(svc_status.dwCurrentState, svc_status.dwWin32ExitCode, svc_status.dwWaitHint, svc_status.dwControlsAccepted);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WINAPI ServiceMain(DWORD argc, LPSTR* argv)
|
||||
{
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
// Create service status handle
|
||||
netdata_service_log("Creating service status handle...");
|
||||
svc_status_handle = RegisterServiceCtrlHandler("Netdata", ServiceControlHandler);
|
||||
if (!svc_status_handle)
|
||||
{
|
||||
netdata_service_log("@ServiceMain() - RegisterServiceCtrlHandler() failed...");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set status to start-pending
|
||||
netdata_service_log("Setting service status to start-pending...");
|
||||
svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
svc_status.dwServiceSpecificExitCode = 0;
|
||||
svc_status.dwCheckPoint = 0;
|
||||
if (!ReportSvcStatus(SERVICE_START_PENDING, 0, 5000, 0))
|
||||
{
|
||||
netdata_service_log("Failed to set service status to start pending.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create stop service event handle
|
||||
netdata_service_log("Creating stop service event handle...");
|
||||
svc_stop_event_handle = CreateEventHandle("Failed to create stop event handle");
|
||||
if (!svc_stop_event_handle)
|
||||
return;
|
||||
|
||||
// Set status to running
|
||||
netdata_service_log("Setting service status to running...");
|
||||
if (!ReportSvcStatus(SERVICE_RUNNING, 0, 5000, SERVICE_ACCEPT_STOP))
|
||||
{
|
||||
netdata_service_log("Failed to set service status to running.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Run the agent
|
||||
netdata_service_log("Running the agent...");
|
||||
netdata_main(argc, argv);
|
||||
|
||||
netdata_service_log("Agent has been started...");
|
||||
}
|
||||
|
||||
static bool update_path() {
|
||||
const char *old_path = getenv("PATH");
|
||||
|
||||
if (!old_path) {
|
||||
if (setenv("PATH", "/usr/bin", 1) != 0) {
|
||||
netdata_service_log("Failed to set PATH to /usr/bin");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t new_path_length = strlen(old_path) + strlen("/usr/bin") + 2;
|
||||
char *new_path = (char *) callocz(new_path_length, sizeof(char));
|
||||
snprintfz(new_path, new_path_length, "/usr/bin:%s", old_path);
|
||||
|
||||
if (setenv("PATH", new_path, 1) != 0) {
|
||||
netdata_service_log("Failed to add /usr/bin to PATH");
|
||||
freez(new_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
freez(new_path);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
bool tty = isatty(fileno(stdout)) == 1;
|
||||
|
||||
if (!update_path()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (tty)
|
||||
{
|
||||
int rc = netdata_main(argc, argv);
|
||||
if (rc != 10)
|
||||
return rc;
|
||||
|
||||
signals_handle();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
SERVICE_TABLE_ENTRY serviceTable[] = {
|
||||
{ strdupz("Netdata"), ServiceMain },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
if (!StartServiceCtrlDispatcher(serviceTable))
|
||||
{
|
||||
netdata_service_log("@main() - StartServiceCtrlDispatcher() failed...");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -935,7 +935,13 @@ void dbengine_init(char *hostname) {
|
|||
config_set_number(CONFIG_SECTION_DB, "dbengine tier 0 disk space MB", default_multidb_disk_quota_mb);
|
||||
}
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
// FIXME: for whatever reason joining the initialization threads
|
||||
// fails on Windows.
|
||||
bool parallel_initialization = false;
|
||||
#else
|
||||
bool parallel_initialization = (storage_tiers <= (size_t)get_netdata_cpus()) ? true : false;
|
||||
#endif
|
||||
|
||||
struct dbengine_initialization tiers_init[RRD_STORAGE_TIERS] = {};
|
||||
|
||||
|
|
|
@ -368,6 +368,35 @@ usec_t heartbeat_next(heartbeat_t *hb, usec_t tick) {
|
|||
return dt;
|
||||
}
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
void sleep_usec_with_now(usec_t usec, usec_t started_ut)
|
||||
{
|
||||
if (!started_ut)
|
||||
started_ut = now_realtime_usec();
|
||||
|
||||
usec_t end_ut = started_ut + usec;
|
||||
usec_t remaining_ut = usec;
|
||||
|
||||
timeBeginPeriod(1);
|
||||
|
||||
while (remaining_ut >= 1000)
|
||||
{
|
||||
DWORD sleep_ms = (DWORD) (remaining_ut / USEC_PER_MS);
|
||||
Sleep(sleep_ms);
|
||||
|
||||
usec_t now_ut = now_realtime_usec();
|
||||
if (now_ut >= end_ut)
|
||||
break;
|
||||
|
||||
remaining_ut = end_ut - now_ut;
|
||||
}
|
||||
|
||||
timeEndPeriod(1);
|
||||
}
|
||||
#else
|
||||
void sleep_usec_with_now(usec_t usec, usec_t started_ut) {
|
||||
// we expect microseconds (1.000.000 per second)
|
||||
// but timespec is nanoseconds (1.000.000.000 per second)
|
||||
|
@ -411,6 +440,7 @@ void sleep_usec_with_now(usec_t usec, usec_t started_ut) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline collected_number uptime_from_boottime(void) {
|
||||
#ifdef CLOCK_BOOTTIME_IS_AVAILABLE
|
||||
|
|
|
@ -451,7 +451,12 @@ typedef enum {
|
|||
} OPEN_FD_EXCLUDE;
|
||||
void for_each_open_fd(OPEN_FD_ACTION action, OPEN_FD_EXCLUDE excluded_fds);
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
void netdata_cleanup_and_exit(int ret, const char *action, const char *action_result, const char *action_data);
|
||||
#else
|
||||
void netdata_cleanup_and_exit(int ret, const char *action, const char *action_result, const char *action_data) NORETURN;
|
||||
#endif
|
||||
|
||||
extern char *netdata_configured_host_prefix;
|
||||
|
||||
#include "os/os.h"
|
||||
|
|
|
@ -224,24 +224,35 @@ int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
|
|||
// spinlock implementation
|
||||
// https://www.youtube.com/watch?v=rmGJc9PXpuE&t=41s
|
||||
|
||||
void spinlock_init(SPINLOCK *spinlock) {
|
||||
#ifdef SPINLOCK_IMPL_WITH_MUTEX
|
||||
void spinlock_init(SPINLOCK *spinlock)
|
||||
{
|
||||
netdata_mutex_init(&spinlock->inner);
|
||||
}
|
||||
#else
|
||||
void spinlock_init(SPINLOCK *spinlock)
|
||||
{
|
||||
memset(spinlock, 0, sizeof(SPINLOCK));
|
||||
}
|
||||
|
||||
static inline void spinlock_lock_internal(SPINLOCK *spinlock) {
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
size_t spins = 0;
|
||||
#endif
|
||||
|
||||
#ifndef SPINLOCK_IMPL_WITH_MUTEX
|
||||
static inline void spinlock_lock_internal(SPINLOCK *spinlock)
|
||||
{
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
size_t spins = 0;
|
||||
#endif
|
||||
|
||||
for(int i = 1;
|
||||
__atomic_load_n(&spinlock->locked, __ATOMIC_RELAXED) ||
|
||||
__atomic_test_and_set(&spinlock->locked, __ATOMIC_ACQUIRE)
|
||||
; i++
|
||||
) {
|
||||
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
spins++;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(unlikely(i == 8)) {
|
||||
i = 0;
|
||||
tinysleep();
|
||||
|
@ -250,23 +261,29 @@ static inline void spinlock_lock_internal(SPINLOCK *spinlock) {
|
|||
|
||||
// we have the lock
|
||||
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
spinlock->spins += spins;
|
||||
spinlock->locker_pid = gettid_cached();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
nd_thread_spinlock_locked();
|
||||
}
|
||||
#endif // SPINLOCK_IMPL_WITH_MUTEX
|
||||
|
||||
static inline void spinlock_unlock_internal(SPINLOCK *spinlock) {
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
#ifndef SPINLOCK_IMPL_WITH_MUTEX
|
||||
static inline void spinlock_unlock_internal(SPINLOCK *spinlock)
|
||||
{
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
spinlock->locker_pid = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__atomic_clear(&spinlock->locked, __ATOMIC_RELEASE);
|
||||
|
||||
nd_thread_spinlock_unlocked();
|
||||
}
|
||||
#endif // SPINLOCK_IMPL_WITH_MUTEX
|
||||
|
||||
#ifndef SPINLOCK_IMPL_WITH_MUTEX
|
||||
static inline bool spinlock_trylock_internal(SPINLOCK *spinlock) {
|
||||
if(!__atomic_load_n(&spinlock->locked, __ATOMIC_RELAXED) &&
|
||||
!__atomic_test_and_set(&spinlock->locked, __ATOMIC_ACQUIRE)) {
|
||||
|
@ -277,36 +294,79 @@ static inline bool spinlock_trylock_internal(SPINLOCK *spinlock) {
|
|||
|
||||
return false;
|
||||
}
|
||||
#endif // SPINLOCK_IMPL_WITH_MUTEX
|
||||
|
||||
#ifdef SPINLOCK_IMPL_WITH_MUTEX
|
||||
void spinlock_lock(SPINLOCK *spinlock)
|
||||
{
|
||||
netdata_mutex_lock(&spinlock->inner);
|
||||
}
|
||||
#else
|
||||
void spinlock_lock(SPINLOCK *spinlock)
|
||||
{
|
||||
spinlock_lock_internal(spinlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SPINLOCK_IMPL_WITH_MUTEX
|
||||
void spinlock_unlock(SPINLOCK *spinlock)
|
||||
{
|
||||
netdata_mutex_unlock(&spinlock->inner);
|
||||
}
|
||||
#else
|
||||
void spinlock_unlock(SPINLOCK *spinlock)
|
||||
{
|
||||
spinlock_unlock_internal(spinlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SPINLOCK_IMPL_WITH_MUTEX
|
||||
bool spinlock_trylock(SPINLOCK *spinlock)
|
||||
{
|
||||
return netdata_mutex_trylock(&spinlock->inner) == 0;
|
||||
}
|
||||
#else
|
||||
bool spinlock_trylock(SPINLOCK *spinlock)
|
||||
{
|
||||
return spinlock_trylock_internal(spinlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SPINLOCK_IMPL_WITH_MUTEX
|
||||
void spinlock_lock_cancelable(SPINLOCK *spinlock)
|
||||
{
|
||||
netdata_mutex_lock(&spinlock->inner);
|
||||
}
|
||||
#else
|
||||
void spinlock_lock_cancelable(SPINLOCK *spinlock)
|
||||
{
|
||||
spinlock_lock_internal(spinlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SPINLOCK_IMPL_WITH_MUTEX
|
||||
void spinlock_unlock_cancelable(SPINLOCK *spinlock)
|
||||
{
|
||||
netdata_mutex_unlock(&spinlock->inner);
|
||||
}
|
||||
#else
|
||||
void spinlock_unlock_cancelable(SPINLOCK *spinlock)
|
||||
{
|
||||
spinlock_unlock_internal(spinlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SPINLOCK_IMPL_WITH_MUTEX
|
||||
bool spinlock_trylock_cancelable(SPINLOCK *spinlock)
|
||||
{
|
||||
return netdata_mutex_trylock(&spinlock->inner) == 0;
|
||||
}
|
||||
#else
|
||||
bool spinlock_trylock_cancelable(SPINLOCK *spinlock)
|
||||
{
|
||||
return spinlock_trylock_internal(spinlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// rw_spinlock implementation
|
||||
|
|
|
@ -6,19 +6,34 @@
|
|||
#include "../libnetdata.h"
|
||||
#include "../clocks/clocks.h"
|
||||
|
||||
// #ifdef OS_WINDOWS
|
||||
// #define SPINLOCK_IMPL_WITH_MUTEX
|
||||
// #endif
|
||||
|
||||
typedef pthread_mutex_t netdata_mutex_t;
|
||||
#define NETDATA_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
||||
|
||||
typedef struct netdata_spinlock {
|
||||
bool locked;
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
pid_t locker_pid;
|
||||
size_t spins;
|
||||
#ifdef SPINLOCK_IMPL_WITH_MUTEX
|
||||
typedef struct netdata_spinlock
|
||||
{
|
||||
netdata_mutex_t inner;
|
||||
} SPINLOCK;
|
||||
#else
|
||||
typedef struct netdata_spinlock
|
||||
{
|
||||
bool locked;
|
||||
#ifdef NETDATA_INTERNAL_CHECKS
|
||||
pid_t locker_pid;
|
||||
size_t spins;
|
||||
#endif
|
||||
} SPINLOCK;
|
||||
#endif
|
||||
} SPINLOCK;
|
||||
|
||||
#define NETDATA_SPINLOCK_INITIALIZER \
|
||||
{ .locked = false }
|
||||
#ifdef SPINLOCK_IMPL_WITH_MUTEX
|
||||
#define NETDATA_SPINLOCK_INITIALIZER { .inner = PTHREAD_MUTEX_INITIALIZER }
|
||||
#else
|
||||
#define NETDATA_SPINLOCK_INITIALIZER { .locked = false }
|
||||
#endif
|
||||
|
||||
void spinlock_init(SPINLOCK *spinlock);
|
||||
void spinlock_lock(SPINLOCK *spinlock);
|
||||
|
|
|
@ -702,3 +702,8 @@ int string_unittest(size_t entries) {
|
|||
fprintf(stderr, "\n%zu errors found\n", errors);
|
||||
return errors ? 1 : 0;
|
||||
}
|
||||
|
||||
void string_init(void) {
|
||||
for (size_t i = 0; i != STRING_PARTITIONS; i++)
|
||||
rw_spinlock_init(&string_base[i].spinlock);
|
||||
}
|
||||
|
|
|
@ -34,4 +34,6 @@ void string_statistics(size_t *inserts, size_t *deletes, size_t *searches, size_
|
|||
|
||||
int string_unittest(size_t entries);
|
||||
|
||||
void string_init(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -418,12 +418,14 @@ bool nd_thread_signaled_to_cancel(void) {
|
|||
// ----------------------------------------------------------------------------
|
||||
// nd_thread_join
|
||||
|
||||
void nd_thread_join(ND_THREAD *nti) {
|
||||
if(!nti) return;
|
||||
int nd_thread_join(ND_THREAD *nti) {
|
||||
if(!nti)
|
||||
return ESRCH;
|
||||
|
||||
int ret = pthread_join(nti->thread, NULL);
|
||||
if(ret != 0)
|
||||
nd_log(NDLS_DAEMON, NDLP_WARNING, "cannot join thread. pthread_join() failed with code %d.", ret);
|
||||
if(ret != 0) {
|
||||
nd_log(NDLS_DAEMON, NDLP_WARNING, "cannot join thread. pthread_join() failed with code %d. (tag=%s)", ret, nti->tag);
|
||||
}
|
||||
else {
|
||||
nd_thread_status_set(nti, NETDATA_THREAD_STATUS_JOINED);
|
||||
|
||||
|
@ -434,4 +436,6 @@ void nd_thread_join(ND_THREAD *nti) {
|
|||
|
||||
freez(nti);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ void netdata_threads_init_after_fork(size_t stacksize);
|
|||
void netdata_threads_init_for_external_plugins(size_t stacksize);
|
||||
|
||||
ND_THREAD *nd_thread_create(const char *tag, NETDATA_THREAD_OPTIONS options, void *(*start_routine) (void *), void *arg);
|
||||
void nd_thread_join(ND_THREAD * nti);
|
||||
int nd_thread_join(ND_THREAD * nti);
|
||||
ND_THREAD *nd_thread_self(void);
|
||||
bool nd_thread_is_me(ND_THREAD *nti);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue