@cryptotaxi247 / netdata-1 / commits / fe06e8495

Windows Support Phase 1 (#17497)

* abstraction layer for O/S * updates * updates * updates * temp fix for protobuf * emulated waitid() * fix * fix * compatibility layer * fix for idtype * fix for missing includes * fix for missing includes * added missing includes * added missing includes * added missing includes * added missing includes * added missing includes * added missing includes * UUID renamed to ND_UUID to avoid conflict with windows.h * include libnetdata.h always - no conflicts * simplify abstraction headers * fix missing functions * fix missing functions * fix missing functions * fix missing functions * rename MSYS to WINDOWS * moved byteorder.h * structure for an internal windows plugin * 1st windows plugin * working plugin * fix printf * Special case windows for protobuf * remove cygwin, compile both as windows * log windows libraries used * fix cmake * fix protobuf * compilation * updated compilation script * added system.ram * windows uptime * perflib * working perflibdump * minify dump * updates to windows plugins, enable ML * minor compatibility fixes for cygwin and msys * perflib-dump to its own file * perflib now indexes names * improvements to the library; disks module WIP * API for selectively traversing the metrics * first working perflib chart: disk.space * working chart on logical and physical disks * added windows protocols * fix datatypes for loops * tinysleep for native smallest sleep support * remove libuuid dependency on windows * fix uuid functions for macos compilation * fix uuid comparison function * do not overwrite uuid library functions, define them as aliases to our own * fixed uuid_unparse functions * fixed typo * added perflib processor charts * updates for compiling without posix emulation * gather common contexts together * fix includes on linux * perflib-memory * windows mem.available * Update variable names for protobuf * network traffic * add network adapters that have traffic as virtual interfaces * add -pipe to windows compilation * reset or overflow flag is now per dimension * dpc is now counted separately * verified all perflib fields are processed and no text fields are present in the data * more common contexts * fix crash * do not add system.net multiple times * install deps update and shortcut * all threads are now joinable behind the scenes * fix threads cleanup * prepare for abstracting threads API * netdata threads full abstraction from pthreads * more threads abstraction and cleanup * more compatibility changes * fix compiler warnings * add base-devel to packages * removed duplicate base-devel * check for strndup * check headers in quotes * fix linux compilation * fix attribute gnu_printf on macos * fix for threads on macos * mingw64 compatibility * enable compilation on windows clion * added instructions * enable cloud * compatibility fixes * compatibility fixes * compatibility fixes * clion works on windows * support both MSYSTEM=MSYS and MSYSTEM=MINGW64 for configure * cleanup and docs * rename uuid_t to nd_uuid_t to avoid conflict with windows uuid_t * leftovers uuid_t * do not include uuid.h on macos * threads signaled cancellations * do not install v0 dashboard on windows * script to install openssh server on windows * update openssh installation script * update openssh installation script * update openssh installation script * update openssh installation script * update openssh installation script * update openssh installation script * update openssh installation script * update openssh installation script * update openssh installation script * use cleanup variable instead of pthreads push and pop * replace all calls to netdata_thread_cleanup_push() and netdata_thread_cleanup_pop() with __attribute__((cleanup(...))) * remove left-over freez * make sure there are no locks acquired at thread exit * add missing parameter * stream receivers and senders are now voluntarily cancelled * plugins.d now voluntarily exits its threads * uuid_t may not be aligned to word boundaries - fix the uuid_t functions to work on unaligned objects too. * collectors evloop is now using the new threading cancellation; ml is now not using pthread_cancel; more fixes * eliminate threads cancellability from the code base * fix exit timings and logs; fix uv_threads tags * use SSL_has_pending() only when it is available * do not use SSL_has_pending() * dyncfg files on windows escape collon and pipe characters * fix compilation on older systems * fix compilation on older systems * Create windows installer. The installer will install everything under C:\netdata by default. It will: - Install msys2 at C:\netdata - Install netdata dependencies with pacman - Install the agent itself under C:\netdata\opt You can start the agent by running an MSYS shell with C:\netdata\msys2_shell.cmd and then start the agent normally with: /opt/netdata/usr/sbin/netdata -D There are a more couple things to work on: - Verify publisher. - Install all deps not just libuv & protobuf. - Figure out how we want to auto-start the agent as a service. - Check how to uninstall things. * fixed typo * code cleanup * Create uninstaller --------- Co-authored-by: vkalintiris <vasilis@netdata.cloud>

Costa Tsaousis committed May 16, 2024 at 13:33 UTC fe06e8495ff85a5938d2fa6544302723e14eab1f
283 files changed +7449 -2824
CMakeLists.txt
+134 -18
@@ -225,23 +225,51 @@ endif()
225 # detect OS
226 #
227
228 -set(LINUX False)
229 -set(FREEBSD False)
230 -set(MACOS False)
228 +set(LINUX False)
229 +set(FREEBSD False)
230 +set(MACOS False)
231 +set(WINDOWS False)
232 +set(FOREIGN_OS False)
233
232 -if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
234 +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
235 set(MACOS True)
236 set(COMPILED_FOR_MACOS True)
235 -
237 find_library(IOKIT IOKit)
238 find_library(FOUNDATION Foundation)
238 -elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
239 + message(INFO " Compiling for MacOS... ")
240 +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD")
241 set(FREEBSD True)
242 set(COMPILED_FOR_FREEBSD True)
241 -else()
243 + message(INFO " Compiling for FreeBSD... ")
244 +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
245 set(LINUX True)
246 set(COMPILED_FOR_LINUX True)
247 add_definitions(-D_GNU_SOURCE)
248 + message(INFO " Compiling for Linux... ")
249 +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "MSYS" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
250 + set(WINDOWS True)
251 + set(COMPILED_FOR_WINDOWS True)
252 + add_definitions(-D_GNU_SOURCE)
253 +
254 + if($ENV{CLION_IDE})
255 + # clion needs these to find the includes
256 + if("${CMAKE_SYSTEM_NAME}" STREQUAL "MSYS" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
257 + if("$ENV{MSYSTEM}" STREQUAL "MSYS")
258 + include_directories(c:/msys64/usr/include)
259 + include_directories(c:/msys64/usr/include/w32api)
260 + elseif("$ENV{MSYSTEM}" STREQUAL "MINGW64")
261 + include_directories(c:/msys64/mingw64/include)
262 + elseif("$ENV{MSYSTEM}" STREQUAL "UCRT64")
263 + include_directories(c:/msys64/ucrt64/include)
264 + endif()
265 + endif()
266 + endif()
267 +
268 + message(INFO " Compiling for Windows (${CMAKE_SYSTEM_NAME}, MSYSTEM=$ENV{MSYSTEM})... ")
269 +else()
270 + set(FOREIGN_OS True)
271 + set(COMPILED_FOR_FOREIGN_OS True)
272 + message(WARNING " Compiling for Unknown O/S... (${CMAKE_SYSTEM_NAME})")
273 endif()
274
275 if(ENABLE_PLUGIN_EBPF)
@@ -326,6 +354,20 @@ check_include_file("sys/statvfs.h" HAVE_SYS_STATVFS_H)
354 check_include_file("inttypes.h" HAVE_INTTYPES_H)
355 check_include_file("stdint.h" HAVE_STDINT_H)
356 check_include_file("sys/capability.h" HAVE_SYS_CAPABILITY_H)
357 +check_include_file("arpa/inet.h" HAVE_ARPA_INET_H)
358 +check_include_file("netinet/tcp.h" HAVE_NETINET_TCP_H)
359 +check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H)
360 +check_include_file("grp.h" HAVE_GRP_H)
361 +check_include_file("pwd.h" HAVE_PWD_H)
362 +check_include_file("net/if.h" HAVE_NET_IF_H)
363 +check_include_file("poll.h" HAVE_POLL_H)
364 +check_include_file("syslog.h" HAVE_SYSLOG_H)
365 +check_include_file("sys/mman.h" HAVE_SYS_MMAN_H)
366 +check_include_file("sys/resource.h" HAVE_SYS_RESOURCE_H)
367 +check_include_file("sys/socket.h" HAVE_SYS_SOCKET_H)
368 +check_include_file("sys/wait.h" HAVE_SYS_WAIT_H)
369 +check_include_file("sys/un.h" HAVE_SYS_UN_H)
370 +check_include_file("spawn.h" HAVE_SPAWN_H)
371
372 #
373 # check symbols
@@ -340,9 +382,15 @@ check_symbol_exists(finite "math.h" HAVE_FINITE)
382 check_symbol_exists(isfinite "math.h" HAVE_ISFINITE)
383 check_symbol_exists(dlsym "dlfcn.h" HAVE_DLSYM)
384
385 +check_function_exists(pthread_getthreadid_np HAVE_PTHREAD_GETTHREADID_NP)
386 +check_function_exists(pthread_threadid_np HAVE_PTHREAD_THREADID_NP)
387 +check_function_exists(gettid HAVE_GETTID)
388 +check_function_exists(waitid HAVE_WAITID)
389 check_function_exists(nice HAVE_NICE)
390 check_function_exists(recvmmsg HAVE_RECVMMSG)
391 check_function_exists(getpriority HAVE_GETPRIORITY)
392 +check_function_exists(setenv HAVE_SETENV)
393 +check_function_exists(strndup HAVE_STRNDUP)
394
395 check_function_exists(sched_getscheduler HAVE_SCHED_GETSCHEDULER)
396 check_function_exists(sched_setscheduler HAVE_SCHED_SETSCHEDULER)
@@ -624,10 +672,10 @@ set(LIBNETDATA_FILES
672 src/libnetdata/log/journal.h
673 src/libnetdata/log/log.c
674 src/libnetdata/log/log.h
627 - src/libnetdata/os.c
628 - src/libnetdata/os.h
675 + src/libnetdata/os/os.c
676 + src/libnetdata/os/os.h
677 src/libnetdata/simple_hashtable.h
630 - src/libnetdata/byteorder.h
678 + src/libnetdata/os/byteorder.h
679 src/libnetdata/onewayalloc/onewayalloc.c
680 src/libnetdata/onewayalloc/onewayalloc.h
681 src/libnetdata/popen/popen.c
@@ -682,6 +730,34 @@ set(LIBNETDATA_FILES
730 src/libnetdata/linked-lists.h
731 src/libnetdata/storage-point.h
732 src/libnetdata/bitmap64.h
733 + src/libnetdata/os/waitid.c
734 + src/libnetdata/os/waitid.h
735 + src/libnetdata/os/gettid.c
736 + src/libnetdata/os/gettid.h
737 + src/libnetdata/os/adjtimex.c
738 + src/libnetdata/os/adjtimex.h
739 + src/libnetdata/os/setresuid.c
740 + src/libnetdata/os/setresuid.h
741 + src/libnetdata/os/setresgid.c
742 + src/libnetdata/os/setresgid.h
743 + src/libnetdata/os/getgrouplist.c
744 + src/libnetdata/os/getgrouplist.h
745 + src/libnetdata/os/get_pid_max.c
746 + src/libnetdata/os/get_pid_max.h
747 + src/libnetdata/os/os-freebsd-wrappers.c
748 + src/libnetdata/os/os-freebsd-wrappers.h
749 + src/libnetdata/os/os-macos-wrappers.c
750 + src/libnetdata/os/os-macos-wrappers.h
751 + src/libnetdata/os/get_system_cpus.c
752 + src/libnetdata/os/get_system_cpus.h
753 + src/libnetdata/os/tinysleep.c
754 + src/libnetdata/os/tinysleep.h
755 + src/libnetdata/os/uuid_generate.c
756 + src/libnetdata/os/uuid_generate.h
757 + src/libnetdata/os/setenv.c
758 + src/libnetdata/os/setenv.h
759 + src/libnetdata/os/strndup.c
760 + src/libnetdata/os/strndup.h
761 )
762
763 if(ENABLE_PLUGIN_EBPF)
@@ -956,6 +1032,16 @@ else()
1032 )
1033 endif()
1034
1035 +set(INTERNAL_COLLECTORS_FILES
1036 + src/collectors/common-contexts/common-contexts.h
1037 + src/collectors/common-contexts/disk.io.h
1038 + src/collectors/common-contexts/system.io.h
1039 + src/collectors/common-contexts/system.ram.h
1040 + src/collectors/common-contexts/mem.swap.h
1041 + src/collectors/common-contexts/mem.pgfaults.h
1042 + src/collectors/common-contexts/mem.available.h
1043 +)
1044 +
1045 set(PLUGINSD_PLUGIN_FILES
1046 src/collectors/plugins.d/plugins_d.c
1047 src/collectors/plugins.d/plugins_d.h
@@ -1197,6 +1283,24 @@ set(FREEBSD_PLUGIN_FILES
1283 src/collectors/proc.plugin/zfs_common.h
1284 )
1285
1286 +set(WINDOWS_PLUGIN_FILES
1287 + src/collectors/windows.plugin/windows_plugin.c
1288 + src/collectors/windows.plugin/windows_plugin.h
1289 + src/collectors/windows.plugin/GetSystemUptime.c
1290 + src/collectors/windows.plugin/GetSystemRAM.c
1291 + src/collectors/windows.plugin/GetSystemCPU.c
1292 + src/collectors/windows.plugin/perflib.c
1293 + src/collectors/windows.plugin/perflib.h
1294 + src/collectors/windows.plugin/perflib-rrd.c
1295 + src/collectors/windows.plugin/perflib-rrd.h
1296 + src/collectors/windows.plugin/perflib-names.c
1297 + src/collectors/windows.plugin/perflib-dump.c
1298 + src/collectors/windows.plugin/perflib-storage.c
1299 + src/collectors/windows.plugin/perflib-processor.c
1300 + src/collectors/windows.plugin/perflib-network.c
1301 + src/collectors/windows.plugin/perflib-memory.c
1302 +)
1303 +
1304 set(PROC_PLUGIN_FILES
1305 src/collectors/proc.plugin/ipc.c
1306 src/collectors/proc.plugin/plugin_proc.c
@@ -1315,6 +1419,7 @@ if(LINUX)
1419 ${PROC_PLUGIN_FILES}
1420 ${TC_PLUGIN_FILES}
1421 ${TIMEX_PLUGIN_FILES}
1422 + ${INTERNAL_COLLECTORS_FILES}
1423 )
1424
1425 if(ENABLE_SENTRY)
@@ -1327,12 +1432,20 @@ elseif(MACOS)
1432 src/daemon/static_threads_macos.c
1433 ${MACOS_PLUGIN_FILES}
1434 ${TIMEX_PLUGIN_FILES}
1435 + ${INTERNAL_COLLECTORS_FILES}
1436 )
1437 elseif(FREEBSD)
1438 list(APPEND NETDATA_FILES
1439 src/daemon/static_threads_freebsd.c
1440 ${FREEBSD_PLUGIN_FILES}
1441 ${TIMEX_PLUGIN_FILES}
1442 + ${INTERNAL_COLLECTORS_FILES}
1443 + )
1444 +elseif(WINDOWS)
1445 + list(APPEND NETDATA_FILES
1446 + src/daemon/static_threads_windows.c
1447 + ${WINDOWS_PLUGIN_FILES}
1448 + ${INTERNAL_COLLECTORS_FILES}
1449 )
1450 endif()
1451
@@ -1518,6 +1631,7 @@ target_include_directories(libnetdata BEFORE PUBLIC ${CONFIG_H_DIR} ${CMAKE_SOUR
1631 target_link_libraries(libnetdata PUBLIC
1632 "$<$<NOT:$<BOOL:${HAVE_BUILTIN_ATOMICS}>>:atomic>"
1633 "$<$<OR:$<BOOL:${LINUX}>,$<BOOL:${FREEBSD}>>:pthread;rt>"
1634 + "$<$<BOOL:${WINDOWS}>:kernel32;advapi32;winmm;rpcrt4>"
1635 "$<$<BOOL:${LINK_LIBM}>:m>"
1636 "${SYSTEMD_LDFLAGS}")
1637
@@ -1578,7 +1692,7 @@ if(LIBBROTLI_FOUND)
1692 endif()
1693
1694 # uuid
1581 -if(MACOS)
1695 +if(MACOS OR WINDOWS)
1696 # UUID functionality is part of the system libraries here, so no extra
1697 # stuff needed.
1698 else()
@@ -1879,9 +1993,9 @@ endif()
1993
1994 if(ENABLE_PLUGIN_CUPS)
1995 pkg_check_modules(CUPS libcups)
1882 - if(NOT CUPS_LIBRARIES)
1996 + if(NOT CUPS_FOUND)
1997 pkg_check_modules(CUPS cups)
1884 - if(NOT CUPS_LIBRARIES)
1998 + if(NOT CUPS_FOUND)
1999 find_program(CUPS_CONFIG cups-config)
2000 if(CUPS_CONFIG)
2001 execute_process(COMMAND ${CUPS_CONFIG} --api-version OUTPUT_VARIABLE CUPS_API_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -2914,10 +3028,12 @@ install(FILES
3028 COMPONENT netdata
3029 DESTINATION ${WEB_DEST}/.well-known/dnt)
3030
2917 -# v0 dashboard
2918 -install(FILES
2919 - src/web/gui/v0/index.html
2920 - COMPONENT netdata
2921 - DESTINATION ${WEB_DEST}/v0)
3031 +if(NOT WINDOWS)
3032 + # v0 dashboard
3033 + install(FILES
3034 + src/web/gui/v0/index.html
3035 + COMPONENT netdata
3036 + DESTINATION ${WEB_DEST}/v0)
3037 +endif()
3038
3039 include(Packaging)
packaging/cmake/Modules/NetdataProtobuf.cmake
+55 -42
@@ -56,54 +56,67 @@ endfunction()
56
57 # Handle detection of Protobuf
58 macro(netdata_detect_protobuf)
59 - if(NOT ENABLE_BUNDLED_PROTOBUF)
60 - if (NOT BUILD_SHARED_LIBS)
61 - set(Protobuf_USE_STATIC_LIBS On)
59 + if(COMPILED_FOR_WINDOWS)
60 + set(PROTOBUF_PROTOC_EXECUTABLE "$ENV{PROTOBUF_PROTOC_EXECUTABLE}")
61 + if(NOT PROTOBUF_PROTOC_EXECUTABLE)
62 + set(PROTOBUF_PROTOC_EXECUTABLE "/bin/protoc")
63 endif()
63 -
64 - # The FindProtobuf CMake module shipped by upstream CMake is
65 - # broken for Protobuf version 22.0 and newer because it does
66 - # not correctly pull in the new Abseil dependencies. Protobuf
67 - # itself sometimes ships a CMake Package Configuration module
68 - # that _does_ work correctly, so use that in preference to the
69 - # Find module shipped with CMake.
70 - #
71 - # The code below works by first attempting to use find_package
72 - # in config mode, and then checking for the existence of the
73 - # target we actually use that gets defined by the protobuf
74 - # CMake Package Configuration Module to determine if that
75 - # worked. A bit of extra logic is required in the case of the
76 - # config mode working, because some systems ship compatibility
77 - # logic for the old FindProtobuf module while others do not.
78 - #
79 - # Upstream bug reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24321
80 - find_package(Protobuf CONFIG)
81 -
82 - if(NOT TARGET protobuf::libprotobuf)
83 - message(STATUS "Could not find Protobuf using Config mode, falling back to Module mode")
84 - find_package(Protobuf REQUIRED)
64 + set(PROTOBUF_CFLAGS_OTHER "")
65 + set(PROTOBUF_INCLUDE_DIRS "")
66 + set(PROTOBUF_LIBRARIES "-lprotobuf")
67 +
68 + set(ENABLE_PROTOBUF True)
69 + set(HAVE_PROTOBUF True)
70 + else()
71 + if(NOT ENABLE_BUNDLED_PROTOBUF)
72 + if (NOT BUILD_SHARED_LIBS)
73 + set(Protobuf_USE_STATIC_LIBS On)
74 + endif()
75 +
76 + # The FindProtobuf CMake module shipped by upstream CMake is
77 + # broken for Protobuf version 22.0 and newer because it does
78 + # not correctly pull in the new Abseil dependencies. Protobuf
79 + # itself sometimes ships a CMake Package Configuration module
80 + # that _does_ work correctly, so use that in preference to the
81 + # Find module shipped with CMake.
82 + #
83 + # The code below works by first attempting to use find_package
84 + # in config mode, and then checking for the existence of the
85 + # target we actually use that gets defined by the protobuf
86 + # CMake Package Configuration Module to determine if that
87 + # worked. A bit of extra logic is required in the case of the
88 + # config mode working, because some systems ship compatibility
89 + # logic for the old FindProtobuf module while others do not.
90 + #
91 + # Upstream bug reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24321
92 + find_package(Protobuf CONFIG)
93 +
94 + if(NOT TARGET protobuf::libprotobuf)
95 + message(STATUS "Could not find Protobuf using Config mode, falling back to Module mode")
96 + find_package(Protobuf REQUIRED)
97 + endif()
98 endif()
86 - endif()
99
88 - if(TARGET protobuf::libprotobuf)
89 - if(NOT Protobuf_PROTOC_EXECUTABLE AND TARGET protobuf::protoc)
90 - set(Protobuf_PROTOC_EXECUTABLE protobuf::protoc)
100 + if(TARGET protobuf::libprotobuf)
101 + if(NOT Protobuf_PROTOC_EXECUTABLE AND TARGET protobuf::protoc)
102 + set(Protobuf_PROTOC_EXECUTABLE protobuf::protoc)
103 + endif()
104 +
105 + # It is technically possible that this may still not
106 + # be set by this point, so we need to check it and
107 + # fail noisily if it isn't because the build won't
108 + # work without it.
109 + if(NOT Protobuf_PROTOC_EXECUTABLE)
110 + message(FATAL_ERROR "Could not determine the location of the protobuf compiler for the detected version of protobuf.")
111 + endif()
112 +
113 + set(PROTOBUF_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE})
114 + set(PROTOBUF_LIBRARIES protobuf::libprotobuf)
115 endif()
116
93 - # It is technically possible that this may still not
94 - # be set by this point, so we need to check it and
95 - # fail noisily if it isn't because the build won't
96 - # work without it.
97 - if(NOT Protobuf_PROTOC_EXECUTABLE)
98 - message(FATAL_ERROR "Could not determine the location of the protobuf compiler for the detected version of protobuf.")
99 - endif()
100 -
101 - set(PROTOBUF_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE})
102 - set(PROTOBUF_LIBRARIES protobuf::libprotobuf)
117 + set(ENABLE_PROTOBUF True)
118 + set(HAVE_PROTOBUF True)
119 endif()
104 -
105 - set(ENABLE_PROTOBUF True)
106 - set(HAVE_PROTOBUF True)
120 endmacro()
121
122 # Helper function to compile protocol definitions into C++ code.
packaging/cmake/config.cmake.h.in
+23
@@ -12,6 +12,8 @@
12 #cmakedefine COMPILED_FOR_FREEBSD
13 #cmakedefine COMPILED_FOR_LINUX
14 #cmakedefine COMPILED_FOR_MACOS
15 +#cmakedefine COMPILED_FOR_WINDOWS
16 +#cmakedefine COMPILED_FOR_FOREIGN_OS
17
18 // checked headers
19
@@ -28,6 +30,20 @@
30 #cmakedefine HAVE_INTTYPES_H
31 #cmakedefine HAVE_STDINT_H
32 #cmakedefine HAVE_SYS_CAPABILITY_H
33 +#cmakedefine HAVE_ARPA_INET_H
34 +#cmakedefine HAVE_NETINET_TCP_H
35 +#cmakedefine HAVE_SYS_IOCTL_H
36 +#cmakedefine HAVE_GRP_H
37 +#cmakedefine HAVE_PWD_H
38 +#cmakedefine HAVE_NET_IF_H
39 +#cmakedefine HAVE_POLL_H
40 +#cmakedefine HAVE_SYSLOG_H
41 +#cmakedefine HAVE_SYS_MMAN_H
42 +#cmakedefine HAVE_SYS_RESOURCE_H
43 +#cmakedefine HAVE_SYS_SOCKET_H
44 +#cmakedefine HAVE_SYS_WAIT_H
45 +#cmakedefine HAVE_SYS_UN_H
46 +#cmakedefine HAVE_SPAWN_H
47
48 #cmakedefine HAVE_CAPABILITY
49 #cmakedefine HAVE_PROTOBUF
@@ -44,8 +60,13 @@
60 #cmakedefine HAVE_FINITE
61 #cmakedefine HAVE_ISFINITE
62 #cmakedefine HAVE_RECVMMSG
63 +#cmakedefine HAVE_PTHREAD_GETTHREADID_NP
64 +#cmakedefine HAVE_PTHREAD_THREADID_NP
65 +#cmakedefine HAVE_GETTID
66 +#cmakedefine HAVE_WAITID
67 #cmakedefine HAVE_NICE
68 #cmakedefine HAVE_GETPRIORITY
69 +#cmakedefine HAVE_SETENV
70 #cmakedefine HAVE_DLSYM
71
72 #cmakedefine HAVE_BACKTRACE
@@ -70,6 +91,8 @@
91 #cmakedefine HAVE_C__GENERIC
92 #cmakedefine HAVE_C_MALLOPT
93 #cmakedefine HAVE_SETNS
94 +#cmakedefine HAVE_STRNDUP
95 +#cmakedefine SSL_HAS_PENDING
96
97 #cmakedefine HAVE_FUNC_ATTRIBUTE_FORMAT
98 #cmakedefine HAVE_FUNC_ATTRIBUTE_MALLOC
packaging/utils/bash_execute.sh new
+19
@@ -0,0 +1,19 @@
1 +#!/usr/bin/bash
2 +
3 +convert_path() {
4 + local ARG="$1"
5 + ARG="${ARG//C:\\//c/}"
6 + ARG="${ARG//c:\\//c/}"
7 + ARG="${ARG//C:\///c/}"
8 + ARG="${ARG//c:\///c/}"
9 +
10 + echo "$ARG"
11 +}
12 +
13 +declare params=()
14 +for x in "${@}"
15 +do
16 + params+=("$(convert_path "${x}")")
17 +done
18 +
19 +"${params[@]}"
packaging/utils/clion-msys-mingw64-environment.bat new
+17
@@ -0,0 +1,17 @@
1 +@echo off
2 +:: In Clion Toolchains
3 +:: 1. Add a MinGW profile
4 +:: 2. Set Toolset to C:\msys64\mingw64
5 +:: 3. Add environment and set the full path to this file, like:
6 +:: C:\msys64\home\costa\src\netdata-ktsaou.git\packaging\utils\clion-mingw64-environment.bat
7 +:: 4. Let everything else to Bundled and auto-detected
8 +::
9 +set "batch_dir=%~dp0"
10 +set "batch_dir=%batch_dir:\=/%"
11 +set MSYSTEM=MINGW64
12 +set GOROOT=C:\msys64\mingw64
13 +set PATH="%PATH%;C:\msys64\mingw64\bin;C:\msys64\usr\bin;C:\msys64\bin"
14 +::set PKG_CONFIG_EXECUTABLE=C:\msys64\mingw64\bin\pkg-config.exe
15 +::set CMAKE_C_COMPILER=C:\msys64\mingw64\bin\gcc.exe
16 +::set CMAKE_CC_COMPILER=C:\msys64\mingw64\bin\g++.exe
17 +set PROTOBUF_PROTOC_EXECUTABLE=C:/msys64/mingw64/bin/protoc.exe
packaging/utils/clion-msys-msys-environment.bat new
+20
@@ -0,0 +1,20 @@
1 +@echo off
2 +:: In Clion Toolchains
3 +:: 1. Add a MinGW profile
4 +:: 2. Set Toolset to C:\msys64\mingw64
5 +:: 3. Add environment and set the full path to this file, like:
6 +:: C:\msys64\home\costa\src\netdata-ktsaou.git\packaging\utils\clion-mingw64-environment.bat
7 +:: 4. Let everything else to Bundled and auto-detected
8 +::
9 +set "batch_dir=%~dp0"
10 +set "batch_dir=%batch_dir:\=/%"
11 +set MSYSTEM=MSYS
12 +
13 +:: go exists only mingw64 / ucrt64 / etc, not under msys profile
14 +set GOROOT=C:\msys64\mingw64
15 +
16 +set PATH="%PATH%;C:\msys64\usr\bin;C:\msys64\bin;C:\msys64\mingw64\bin"
17 +::set PKG_CONFIG_EXECUTABLE=C:\msys64\mingw64\bin\pkg-config.exe
18 +::set CMAKE_C_COMPILER=C:\msys64\mingw64\bin\gcc.exe
19 +::set CMAKE_CC_COMPILER=C:\msys64\mingw64\bin\g++.exe
20 +set PROTOBUF_PROTOC_EXECUTABLE=%batch_dir%/protoc.bat
packaging/utils/compile-on-windows.sh new
+71
@@ -0,0 +1,71 @@
1 +#!/bin/sh
2 +
3 +# On MSYS2, install these dependencies to build netdata:
4 +install_dependencies() {
5 + pacman -S \
6 + git cmake ninja base-devel msys2-devel \
7 + libyaml-devel libzstd-devel libutil-linux libutil-linux-devel \
8 + mingw-w64-x86_64-toolchain mingw-w64-ucrt-x86_64-toolchain \
9 + mingw64/mingw-w64-x86_64-mold ucrt64/mingw-w64-ucrt-x86_64-mold \
10 + msys/gdb ucrt64/mingw-w64-ucrt-x86_64-gdb mingw64/mingw-w64-x86_64-gdb \
11 + msys/zlib-devel mingw64/mingw-w64-x86_64-zlib ucrt64/mingw-w64-ucrt-x86_64-zlib \
12 + msys/libuv-devel ucrt64/mingw-w64-ucrt-x86_64-libuv mingw64/mingw-w64-x86_64-libuv \
13 + liblz4-devel mingw64/mingw-w64-x86_64-lz4 ucrt64/mingw-w64-ucrt-x86_64-lz4 \
14 + openssl-devel mingw64/mingw-w64-x86_64-openssl ucrt64/mingw-w64-ucrt-x86_64-openssl \
15 + protobuf-devel mingw64/mingw-w64-x86_64-protobuf ucrt64/mingw-w64-ucrt-x86_64-protobuf \
16 + msys/pcre2-devel mingw64/mingw-w64-x86_64-pcre2 ucrt64/mingw-w64-ucrt-x86_64-pcre2 \
17 + msys/brotli-devel mingw64/mingw-w64-x86_64-brotli ucrt64/mingw-w64-ucrt-x86_64-brotli \
18 + msys/ccache ucrt64/mingw-w64-ucrt-x86_64-ccache mingw64/mingw-w64-x86_64-ccache \
19 + mingw64/mingw-w64-x86_64-go ucrt64/mingw-w64-ucrt-x86_64-go
20 +}
21 +
22 +if [ "${1}" = "install" ]
23 +then
24 + install_dependencies || exit 1
25 + exit 0
26 +fi
27 +
28 +export PATH="/usr/local/bin:${PATH}"
29 +
30 +WT_ROOT="$(pwd)"
31 +BUILD_TYPE="Debug"
32 +NULL=""
33 +
34 +if [ -z "${MSYSTEM}" ]; then
35 + build="${WT_ROOT}/build-${OSTYPE}"
36 +else
37 + build="${WT_ROOT}/build-${OSTYPE}-${MSYSTEM}"
38 +fi
39 +
40 +if [ "$USER" = "vk" ]; then
41 + build="${WT_ROOT}/build"
42 +fi
43 +
44 +set -exu -o pipefail
45 +
46 +if [ -d "${build}" ]
47 +then
48 + rm -rf "${build}"
49 +fi
50 +
51 +/usr/bin/cmake -S "${WT_ROOT}" -B "${build}" \
52 + -G Ninja \
53 + -DCMAKE_INSTALL_PREFIX="/opt/netdata" \
54 + -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
55 + -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" \
56 + -DNETDATA_USER="${USER}" \
57 + -DDEFAULT_FEATURE_STATE=Off \
58 + -DENABLE_H2O=Off \
59 + -DENABLE_LOGS_MANAGEMENT_TESTS=Off \
60 + -DENABLE_ACLK=On \
61 + -DENABLE_CLOUD=On \
62 + -DENABLE_ML=On \
63 + -DENABLE_BUNDLED_JSONC=On \
64 + -DENABLE_BUNDLED_PROTOBUF=Off \
65 + ${NULL}
66 +
67 +ninja -v -C "${build}" || ninja -v -C "${build}" -j 1
68 +
69 +echo
70 +echo "Compile with:"
71 +echo "ninja -v -C \"${build}\" || ninja -v -C \"${build}\" -j 1"
packaging/utils/installer.nsi new
+34
@@ -0,0 +1,34 @@
1 +Outfile "netdata-installer.exe"
2 +InstallDir "C:\netdata"
3 +
4 +RequestExecutionLevel admin
5 +
6 +Section
7 + SetOutPath $INSTDIR
8 + WriteUninstaller $INSTDIR\uninstaller.exe
9 +SectionEnd
10 +
11 +Section "Install MSYS2 environment"
12 + SetOutPath $TEMP
13 +
14 + SetCompress off
15 + File "C:\msys64\msys2-installer.exe"
16 + nsExec::ExecToLog 'cmd.exe /C "$TEMP\msys2-installer.exe" in --confirm-command --accept-messages --root $INSTDIR'
17 +
18 + Delete "$TEMP\msys2-installer.exe"
19 +SectionEnd
20 +
21 +Section "Install MSYS2 packages"
22 + ExecWait '"$INSTDIR\usr\bin\bash.exe" -lc "pacman -S --noconfirm msys/libuv msys/protobuf"'
23 +SectionEnd
24 +
25 +Section "Install Netdata"
26 + SetOutPath $INSTDIR\opt\netdata
27 +
28 + SetCompress off
29 + File /r "C:\msys64\opt\netdata\*.*"
30 +SectionEnd
31 +
32 +Section "Uninstall"
33 + nsExec::ExecToLog 'cmd.exe /C "$INSTDIR\uninstall.exe" pr --confirm-command'
34 +SectionEnd
packaging/utils/package-windows.sh new
+27
@@ -0,0 +1,27 @@
1 +#!/bin/sh
2 +
3 +export PATH="/usr/local/bin:${PATH}"
4 +
5 +WT_ROOT="$(pwd)"
6 +NULL=""
7 +
8 +if [ -z "${MSYSTEM}" ]; then
9 + build="${WT_ROOT}/build-${OSTYPE}"
10 +else
11 + build="${WT_ROOT}/build-${OSTYPE}-${MSYSTEM}"
12 +fi
13 +
14 +if [ "$USER" = "vk" ]; then
15 + build="${WT_ROOT}/build"
16 +fi
17 +
18 +set -exu -o pipefail
19 +
20 +ninja -v -C "${build}" install
21 +
22 +if [ ! -f "/msys2-installer.exe" ]; then
23 + wget -O /msys2-installer.exe \
24 + "https://github.com/msys2/msys2-installer/releases/download/2024-05-07/msys2-x86_64-20240507.exe"
25 +fi
26 +
27 +makensis "${WT_ROOT}/packaging/utils/installer.nsi"
packaging/utils/protoc.bat new
+9
@@ -0,0 +1,9 @@
1 +@echo off
2 +::
3 +:: The problem with /usr/bin/protoc is that it accepts colon separated (:) paths at its parameters.
4 +:: This makes C:/ being parsed as 2 paths: C and /, which of course both fail.
5 +:: To overcome this problem, we use bash_execute.sh, which replaces all occurences of C: with /c.
6 +::
7 +set "batch_dir=%~dp0"
8 +set "batch_dir=%batch_dir:\=/%"
9 +C:\msys64\usr\bin\bash.exe %batch_dir%/bash_execute.sh protoc %*
packaging/utils/windows-openssh-to-msys.bat new
+118
@@ -0,0 +1,118 @@
1 +@echo off
2 +::
3 +:: This script will:
4 +::
5 +:: 1. install the windows OpenSSH server (either via dsim or download it)
6 +:: 2. activate the windows OpenSSH service
7 +:: 3. open OpenSSH TCP port at windows firewall
8 +:: 4. create a small batch file to start an MSYS session
9 +:: 5. Set the default OpenSSH startup script to start the MSYS session
10 +::
11 +:: Problems:
12 +:: On older windows versions, terminal emulation is broken.
13 +:: So, on windows 10 or windows server before 2019, the ssh session
14 +:: will not have proper terminal emulation and will be not be able to
15 +:: be used for editing files.
16 +:: For more info check:
17 +:: https://github.com/PowerShell/Win32-OpenSSH/issues/1260
18 +::
19 +
20 +:: Check if OpenSSH Server is already installed
21 +sc query sshd >nul 2>&1
22 +if %errorlevel% neq 0 (
23 + echo "OpenSSH Server not found. Attempting to install via dism..."
24 + goto :install_openssh_dism
25 +) else (
26 + echo "OpenSSH Server is already installed."
27 + goto :configure_openssh
28 +)
29 +
30 +:: Install OpenSSH using dism
31 +:install_openssh_dism
32 +dism /online /Enable-Feature /FeatureName:OpenSSH-Client /All >nul 2>&1
33 +dism /online /Enable-Feature /FeatureName:OpenSSH-Server /All >nul 2>&1
34 +
35 +:: Check if dism succeeded in installing OpenSSH
36 +sc query sshd >nul 2>&1
37 +if %errorlevel% neq 0 (
38 + echo "OpenSSH installation via dism failed or is unavailable."
39 + goto :install_openssh_manual
40 +) else (
41 + echo "OpenSSH installed successfully using dism."
42 + goto :configure_openssh
43 +)
44 +
45 +:: Function to Install OpenSSH manually if dism fails
46 +:install_openssh_manual
47 +echo "Installing OpenSSH manually..."
48 +
49 +:: Download the latest OpenSSH release
50 +set DOWNLOAD_URL=https://github.com/PowerShell/Win32-OpenSSH/releases/download/v9.5.0.0p1-Beta/OpenSSH-Win64.zip
51 +set DOWNLOAD_FILE=%temp%\OpenSSH-Win64.zip
52 +set INSTALL_DIR=C:\Program Files\OpenSSH-Win64
53 +
54 +:: Create the installation directory if it doesn't exist
55 +if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
56 +
57 +:: Attempt to download OpenSSH using Invoke-WebRequest and TLS configuration
58 +powershell -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; try { Invoke-WebRequest -Uri '%DOWNLOAD_URL%' -OutFile '%DOWNLOAD_FILE%' -UseBasicParsing; exit 0 } catch { exit 1 }"
59 +if %errorlevel% neq 0 (
60 + echo "Invoke-WebRequest download failed. Attempting to download using curl..."
61 + curl -L -o "%DOWNLOAD_FILE%" "%DOWNLOAD_URL%"
62 + if %errorlevel% neq 0 (
63 + echo "Failed to download OpenSSH using curl. Exiting..."
64 + exit /b 1
65 + )
66 +)
67 +
68 +:: Unzip directly to INSTALL_DIR (flatten the folder structure)
69 +powershell -Command "Expand-Archive -Path '%DOWNLOAD_FILE%' -DestinationPath '%INSTALL_DIR%' -Force"
70 +if %errorlevel% neq 0 (
71 + echo "Failed to unzip OpenSSH package."
72 + exit /b 1
73 +)
74 +
75 +:: Move inner contents to INSTALL_DIR if nested OpenSSH-Win64 folder exists
76 +if exist "%INSTALL_DIR%\OpenSSH-Win64" (
77 + xcopy "%INSTALL_DIR%\OpenSSH-Win64\*" "%INSTALL_DIR%\" /s /e /y
78 + rmdir "%INSTALL_DIR%\OpenSSH-Win64" /s /q
79 +)
80 +
81 +:: Add the OpenSSH binaries to the system PATH
82 +setx /M PATH "%INSTALL_DIR%;%PATH%"
83 +
84 +:: Register OpenSSH utilities as services using PowerShell
85 +powershell -ExecutionPolicy Bypass -Command "& '%INSTALL_DIR%\install-sshd.ps1'"
86 +
87 +:: Verify if manual installation succeeded
88 +sc query sshd >nul 2>&1
89 +if %errorlevel% neq 0 (
90 + echo "Manual OpenSSH installation failed. Exiting..."
91 + exit /b 1
92 +) else (
93 + echo "OpenSSH installed successfully manually."
94 + goto :configure_openssh
95 +)
96 +
97 +:configure_openssh
98 +:: Ensure OpenSSH Server service is set to start automatically and start the service
99 +sc config sshd start= auto
100 +net start sshd
101 +
102 +:: Create msys2.bat file with specific content
103 +set MSYS2_PATH=C:\msys64
104 +if not exist "%MSYS2_PATH%" (
105 + echo "Error: %MSYS2_PATH% does not exist."
106 + exit /b 1
107 +)
108 +
109 +echo @%MSYS2_PATH%\msys2_shell.cmd -defterm -here -no-start -msys > %MSYS2_PATH%\msys2.bat
110 +
111 +:: Run PowerShell command to set default shell
112 +powershell -Command "New-ItemProperty -Path 'HKLM:\SOFTWARE\OpenSSH' -Name 'DefaultShell' -Value '%MSYS2_PATH%\msys2.bat' -PropertyType String -Force"
113 +
114 +:: Open the Windows Firewall for sshd (using PowerShell)
115 +powershell -Command "New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd) Incoming' -Description 'Allow incoming SSH traffic via OpenSSH server' -Enabled True -Direction Inbound -Protocol TCP -LocalPort 22 -Action Allow"
116 +
117 +echo "OpenSSH has been successfully configured with MSYS2 as the default shell, and the firewall has been opened for sshd."
118 +pause
src/aclk/aclk.c
+5 -13
@@ -817,10 +817,6 @@ void *aclk_main(void *ptr)
817
818 unsigned int proto_hdl_cnt = aclk_init_rx_msg_handlers();
819
820 - // This thread is unusual in that it cannot be cancelled by cancel_main_threads()
821 - // as it must notify the far end that it shutdown gracefully and avoid the LWT.
822 - netdata_thread_disable_cancelability();
823 -
820 #if defined( DISABLE_CLOUD ) || !defined( ENABLE_ACLK )
821 nd_log(NDLS_DAEMON, NDLP_INFO,
822 "Killing ACLK thread -> cloud functionality has been disabled");
@@ -861,13 +857,10 @@ void *aclk_main(void *ptr)
857 aclk_stats_enabled = config_get_boolean(CONFIG_SECTION_CLOUD, "statistics", global_statistics_enabled);
858 if (aclk_stats_enabled) {
859 stats_thread = callocz(1, sizeof(struct aclk_stats_thread));
864 - stats_thread->thread = mallocz(sizeof(netdata_thread_t));
860 stats_thread->query_thread_count = query_threads.count;
861 stats_thread->client = mqttwss_client;
862 aclk_stats_thread_prepare(query_threads.count, proto_hdl_cnt);
868 - netdata_thread_create(
869 - stats_thread->thread, "ACLK_STATS", NETDATA_THREAD_OPTION_JOINABLE, aclk_stats_main_thread,
870 - stats_thread);
863 + stats_thread->thread = nd_thread_create("ACLK_STATS", NETDATA_THREAD_OPTION_JOINABLE, aclk_stats_main_thread, stats_thread);
864 }
865
866 // Keep reconnecting and talking until our time has come
@@ -901,9 +894,8 @@ exit_full:
894 aclk_query_threads_cleanup(&query_threads);
895
896 if (aclk_stats_enabled) {
904 - netdata_thread_join(*stats_thread->thread, NULL);
897 + nd_thread_join(stats_thread->thread);
898 aclk_stats_thread_cleanup();
906 - freez(stats_thread->thread);
899 freez(stats_thread);
900 }
901 free_topic_cache();
@@ -919,7 +911,7 @@ exit:
911
912 void aclk_host_state_update(RRDHOST *host, int cmd, int queryable)
913 {
922 - uuid_t node_id;
914 + nd_uuid_t node_id;
915 int ret = 0;
916
917 if (!aclk_connected)
@@ -1165,7 +1157,7 @@ char *aclk_state(void)
1157 buffer_strcat(wb, "\n\tAlert Streaming Status:");
1158 fill_alert_status_for_host(wb, host);
1159 }
1168 - rrd_unlock();
1160 + rrd_rdunlock();
1161 }
1162
1163 ret = strdupz(buffer_tostring(wb));
@@ -1315,7 +1307,7 @@ char *aclk_state_json(void)
1307
1308 json_object_array_add(grp, nodeinstance);
1309 }
1318 - rrd_unlock();
1310 + rrd_rdunlock();
1311 json_object_object_add(msg, "node-instances", grp);
1312
1313 char *str = strdupz(json_object_to_json_string_ext(msg, JSON_C_TO_STRING_PLAIN));
src/aclk/aclk_query.c
+6 -3
@@ -351,8 +351,11 @@ void aclk_query_threads_start(struct aclk_query_threads *query_threads, mqtt_wss
351
352 if(unlikely(snprintfz(thread_name, TASK_LEN_MAX, "ACLK_QRY[%d]", i) < 0))
353 netdata_log_error("snprintf encoding error");
354 - netdata_thread_create(
355 - &query_threads->thread_list[i].thread, thread_name, NETDATA_THREAD_OPTION_JOINABLE, aclk_query_main_thread,
354 +
355 + query_threads->thread_list[i].thread = nd_thread_create(
356 + thread_name,
357 + NETDATA_THREAD_OPTION_JOINABLE,
358 + aclk_query_main_thread,
359 &query_threads->thread_list[i]);
360 }
361 }
@@ -361,7 +364,7 @@ void aclk_query_threads_cleanup(struct aclk_query_threads *query_threads)
364 {
365 if (query_threads && query_threads->thread_list) {
366 for (int i = 0; i < query_threads->count; i++) {
364 - netdata_thread_join(query_threads->thread_list[i].thread, NULL);
367 + nd_thread_join(query_threads->thread_list[i].thread);
368 }
369 freez(query_threads->thread_list);
370 }
src/aclk/aclk_query.h
+1 -1
@@ -18,7 +18,7 @@ extern pthread_mutex_t query_lock_wait;
18 //extern volatile int aclk_connected;
19
20 struct aclk_query_thread {
21 - netdata_thread_t thread;
21 + ND_THREAD *thread;
22 int idx;
23 mqtt_wss_client client;
24 };
src/aclk/aclk_rx_msgs.c
+1 -1
@@ -255,7 +255,7 @@ int create_node_instance_result(const char *msg, size_t msg_len)
255
256 netdata_log_debug(D_ACLK, "CreateNodeInstanceResult: guid:%s nodeid:%s", res.machine_guid, res.node_id);
257
258 - uuid_t host_id, node_id;
258 + nd_uuid_t host_id, node_id;
259 if (uuid_parse(res.machine_guid, host_id)) {
260 netdata_log_error("Error parsing machine_guid provided by CreateNodeInstanceResult");
261 freez(res.machine_guid);
src/aclk/aclk_stats.c
+2 -1
@@ -387,11 +387,12 @@ void *aclk_stats_main_thread(void *ptr)
387 struct aclk_metrics permanent;
388
389 while (service_running(SERVICE_ACLK | SERVICE_COLLECTORS)) {
390 - netdata_thread_testcancel();
390 +
391 // ------------------------------------------------------------------------
392 // Wait for the next iteration point.
393
394 heartbeat_next(&hb, step_ut);
395 +
396 if (!service_running(SERVICE_ACLK | SERVICE_COLLECTORS)) break;
397
398 ACLK_STATS_LOCK;
src/aclk/aclk_stats.h
+1 -1
@@ -19,7 +19,7 @@ extern netdata_mutex_t aclk_stats_mutex;
19 int aclk_cloud_req_http_type_to_idx(const char *name);
20
21 struct aclk_stats_thread {
22 - netdata_thread_t *thread;
22 + ND_THREAD *thread;
23 int query_thread_count;
24 mqtt_wss_client client;
25 };
src/aclk/aclk_tx_msgs.c
+1 -1
@@ -101,7 +101,7 @@ static int aclk_send_message_with_bin_payload(mqtt_wss_client client, json_objec
101 */
102 static struct json_object *create_hdr(const char *type, const char *msg_id, time_t ts_secs, usec_t ts_us, int version)
103 {
104 - uuid_t uuid;
104 + nd_uuid_t uuid;
105 char uuid_str[36 + 1];
106 json_object *tmp;
107 json_object *obj = json_object_new_object();
src/claim/claim.c
+5 -5
@@ -150,7 +150,7 @@ void load_claiming_state(void)
150 #if defined( DISABLE_CLOUD ) || !defined( ENABLE_ACLK )
151 netdata_cloud_enabled = false;
152 #else
153 - uuid_t uuid;
153 + nd_uuid_t uuid;
154
155 // Propagate into aclk and registry. Be kind of atomic...
156 appconfig_get(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", DEFAULT_CLOUD_BASE_URL);
@@ -240,7 +240,7 @@ void load_cloud_conf(int silent)
240 }
241
242 static char *netdata_random_session_id_filename = NULL;
243 -static uuid_t netdata_random_session_id = { 0 };
243 +static nd_uuid_t netdata_random_session_id = { 0 };
244
245 bool netdata_random_session_id_generate(void) {
246 static char guid[UUID_STR_LEN] = "";
@@ -291,7 +291,7 @@ bool netdata_random_session_id_matches(const char *guid) {
291 if(uuid_is_null(netdata_random_session_id))
292 return false;
293
294 - uuid_t uuid;
294 + nd_uuid_t uuid;
295
296 if(uuid_parse(guid, uuid))
297 return false;
@@ -306,7 +306,7 @@ static bool check_claim_param(const char *s) {
306 if(!s || !*s) return true;
307
308 do {
309 - if(isalnum(*s) || *s == '.' || *s == ',' || *s == '-' || *s == ':' || *s == '/' || *s == '_')
309 + if(isalnum((uint8_t)*s) || *s == '.' || *s == ',' || *s == '-' || *s == ':' || *s == '/' || *s == '_')
310 ;
311 else
312 return false;
@@ -393,7 +393,7 @@ int api_v2_claim(struct web_client *w, char *url) {
393 appconfig_set_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", CONFIG_BOOLEAN_AUTO);
394 appconfig_set(&cloud_config, CONFIG_SECTION_GLOBAL, "cloud base url", base_url);
395
396 - uuid_t claimed_id;
396 + nd_uuid_t claimed_id;
397 uuid_generate_random(claimed_id);
398 char claimed_id_str[UUID_STR_LEN];
399 uuid_unparse_lower(claimed_id, claimed_id_str);
src/collectors/all.h
+3
@@ -286,6 +286,7 @@
286 #define NETDATA_CHART_PRIO_IPV4_BCAST_PACKETS 5105
287 #define NETDATA_CHART_PRIO_IPV4_MCAST 5150
288 #define NETDATA_CHART_PRIO_IPV4_MCAST_PACKETS 5155
289 +#define NETDATA_CHART_PRIO_IPV4_TCP_PACKETS 5170
290 #define NETDATA_CHART_PRIO_IPV4_TCP_SOCKETS 5180
291 #define NETDATA_CHART_PRIO_IPV4_TCP_SOCKETS_MEM 5185
292 #define NETDATA_CHART_PRIO_IPV4_ICMP_PACKETS 5200
@@ -311,7 +312,9 @@
312 #define NETDATA_CHART_PRIO_IPV6_BCAST 6050
313 #define NETDATA_CHART_PRIO_IPV6_MCAST 6100
314 #define NETDATA_CHART_PRIO_IPV6_MCAST_PACKETS 6105
315 +#define NETDATA_CHART_PRIO_IPV6_TCP_PACKETS 6130
316 #define NETDATA_CHART_PRIO_IPV6_TCP_SOCKETS 6140
317 +#define NETDATA_CHART_PRIO_IPV6_ICMP_PACKETS 6145
318 #define NETDATA_CHART_PRIO_IPV6_ICMP 6150
319 #define NETDATA_CHART_PRIO_IPV6_ICMP_REDIR 6155
320 #define NETDATA_CHART_PRIO_IPV6_ICMP_ERRORS 6160
src/collectors/apps.plugin/apps_plugin.c
+4 -4
@@ -552,7 +552,7 @@ static void normalize_utilization(struct target *root) {
552 // here we try to eliminate them by disabling childs processing either for specific dimensions
553 // or entirely. Of course, either way, we disable it just a single iteration.
554
555 - kernel_uint_t max_time = get_system_cpus() * time_factor * RATES_DETAIL;
555 + kernel_uint_t max_time = os_get_system_cpus() * time_factor * RATES_DETAIL;
556 kernel_uint_t utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
557
558 if(global_utime > max_time) global_utime = max_time;
@@ -1013,7 +1013,7 @@ int main(int argc, char **argv) {
1013
1014 procfile_adaptive_initial_allocation = 1;
1015
1016 - get_system_HZ();
1016 + os_get_system_HZ();
1017 #if defined(__FreeBSD__)
1018 time_factor = 1000000ULL / RATES_DETAIL; // FreeBSD uses usecs
1019 #endif
@@ -1025,8 +1025,8 @@ int main(int argc, char **argv) {
1025 time_factor = system_hz; // Linux uses clock ticks
1026 #endif
1027
1028 - get_system_pid_max();
1029 - get_system_cpus_uncached();
1028 + os_get_system_pid_max();
1029 + os_get_system_cpus_uncached();
1030
1031 parse_args(argc, argv);
1032
src/collectors/cgroups.plugin/cgroup-discovery.c
+2 -1
@@ -1261,7 +1261,7 @@ static inline void discovery_find_all_cgroups() {
1261 discovery_find_all_cgroups_v2();
1262 }
1263
1264 - for (struct cgroup *cg = discovered_cgroup_root; cg; cg = cg->discovered_next) {
1264 + for (struct cgroup *cg = discovered_cgroup_root; cg && service_running(SERVICE_COLLECTORS); cg = cg->discovered_next) {
1265 worker_is_busy(WORKER_DISCOVERY_PROCESS);
1266 discovery_process_cgroup(cg);
1267 }
@@ -1289,6 +1289,7 @@ static inline void discovery_find_all_cgroups() {
1289 void cgroup_discovery_worker(void *ptr)
1290 {
1291 UNUSED(ptr);
1292 + uv_thread_set_name_np("P[cgroupsdisc]");
1293
1294 worker_register("CGROUPSDISC");
1295 worker_register_job_name(WORKER_DISCOVERY_INIT, "init");
src/collectors/cgroups.plugin/cgroup-network.c
-6
@@ -3,12 +3,6 @@
3 #include "libnetdata/libnetdata.h"
4 #include "libnetdata/required_dummies.h"
5
6 -#ifdef HAVE_SETNS
7 -#ifndef _GNU_SOURCE
8 -#define _GNU_SOURCE /* See feature_test_macros(7) */
9 -#endif
10 -#endif
11 -
6 char env_netdata_host_prefix[FILENAME_MAX + 50] = "";
7 char env_netdata_log_method[FILENAME_MAX + 50] = "";
8 char env_netdata_log_format[FILENAME_MAX + 50] = "";
src/collectors/cgroups.plugin/sys_fs_cgroup.c
+9 -12
@@ -1158,7 +1158,7 @@ static inline void update_cpu_limits(char **filename, unsigned long long *value,
1158 int ret = -1;
1159
1160 if(value == &cg->cpuset_cpus) {
1161 - unsigned long ncpus = read_cpuset_cpus(*filename, get_system_cpus());
1161 + unsigned long ncpus = os_read_cpuset_cpus(*filename, os_get_system_cpus());
1162 if(ncpus) {
1163 *value = ncpus;
1164 ret = 0;
@@ -1199,7 +1199,7 @@ static inline void update_cpu_limits2(struct cgroup *cg) {
1199 }
1200
1201 cg->cpu_cfs_period = str2ull(procfile_lineword(ff, 0, 1), NULL);
1202 - cg->cpuset_cpus = get_system_cpus();
1202 + cg->cpuset_cpus = os_get_system_cpus();
1203
1204 char *s = "max\n\0";
1205 if(strcmp(s, procfile_lineword(ff, 0, 0)) == 0){
@@ -1513,13 +1513,14 @@ void update_cgroup_charts() {
1513 // ----------------------------------------------------------------------------
1514 // cgroups main
1515
1516 -static void cgroup_main_cleanup(void *ptr) {
1517 - worker_unregister();
1516 +static void cgroup_main_cleanup(void *pptr) {
1517 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
1518 + if(!static_thread) return;
1519
1519 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
1520 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
1521
1522 collector_info("cleaning up...");
1523 + worker_unregister();
1524
1525 usec_t max = 2 * USEC_PER_SEC, step = 50000;
1526
@@ -1554,13 +1555,13 @@ void cgroup_read_host_total_ram() {
1555 }
1556
1557 void *cgroups_main(void *ptr) {
1558 + CLEANUP_FUNCTION_REGISTER(cgroup_main_cleanup) cleanup_ptr = ptr;
1559 +
1560 worker_register("CGROUPS");
1561 worker_register_job_name(WORKER_CGROUPS_LOCK, "lock");
1562 worker_register_job_name(WORKER_CGROUPS_READ, "read");
1563 worker_register_job_name(WORKER_CGROUPS_CHART, "chart");
1564
1562 - netdata_thread_cleanup_push(cgroup_main_cleanup, ptr);
1563 -
1565 if (getenv("KUBERNETES_SERVICE_HOST") != NULL && getenv("KUBERNETES_SERVICE_PORT") != NULL) {
1566 is_inside_k8s = 1;
1567 cgroup_enable_cpuacct_cpu_shares = CONFIG_BOOLEAN_YES;
@@ -1592,8 +1593,6 @@ void *cgroups_main(void *ptr) {
1593 goto exit;
1594 }
1595
1595 - uv_thread_set_name_np(discovery_thread.thread, "P[cgroups]");
1596 -
1596 // we register this only on localhost
1597 // for the other nodes, the origin server should register it
1598 cgroup_netdev_link_init();
@@ -1613,12 +1612,11 @@ void *cgroups_main(void *ptr) {
1612 usec_t step = cgroup_update_every * USEC_PER_SEC;
1613 usec_t find_every = cgroup_check_for_new_every * USEC_PER_SEC, find_dt = 0;
1614
1616 - netdata_thread_disable_cancelability();
1617 -
1615 while(service_running(SERVICE_COLLECTORS)) {
1616 worker_is_idle();
1617
1618 usec_t hb_dt = heartbeat_next(&hb, step);
1619 +
1620 if (unlikely(!service_running(SERVICE_COLLECTORS)))
1621 break;
1622
@@ -1658,6 +1656,5 @@ void *cgroups_main(void *ptr) {
1656 }
1657
1658 exit:
1661 - netdata_thread_cleanup_pop(1);
1659 return NULL;
1660 }
src/collectors/common-contexts/common-contexts.h new
+28
@@ -0,0 +1,28 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_COMMON_CONTEXTS_H
4 +#define NETDATA_COMMON_CONTEXTS_H
5 +
6 +#include "../../libnetdata/libnetdata.h"
7 +#include "../../database/rrd.h"
8 +
9 +#ifndef _COMMON_PLUGIN_NAME
10 +#error You need to set _COMMON_PLUGIN_NAME before including common-contexts.h
11 +#endif
12 +
13 +#ifndef _COMMON_PLUGIN_MODULE_NAME
14 +#error You need to set _COMMON_PLUGIN_MODULE_NAME before including common-contexts.h
15 +#endif
16 +
17 +#define _COMMON_CONFIG_SECTION "plugin:" _COMMON_PLUGIN_NAME ":" _COMMON_PLUGIN_MODULE_NAME
18 +
19 +typedef void (*instance_labels_cb_t)(RRDSET *st, void *data);
20 +
21 +#include "system.io.h"
22 +#include "system.ram.h"
23 +#include "mem.swap.h"
24 +#include "mem.pgfaults.h"
25 +#include "mem.available.h"
26 +#include "disk.io.h"
27 +
28 +#endif //NETDATA_COMMON_CONTEXTS_H
src/collectors/common-contexts/disk.io.h new
+44
@@ -0,0 +1,44 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_DISK_IO_H
4 +#define NETDATA_DISK_IO_H
5 +
6 +#include "common-contexts.h"
7 +
8 +typedef struct {
9 + RRDSET *st_io;
10 + RRDDIM *rd_io_reads;
11 + RRDDIM *rd_io_writes;
12 +} ND_DISK_IO;
13 +
14 +static inline void common_disk_io(ND_DISK_IO *d, const char *id, const char *name, uint64_t bytes_read, uint64_t bytes_write, int update_every, instance_labels_cb_t cb, void *data) {
15 + if(unlikely(!d->st_io)) {
16 + d->st_io = rrdset_create_localhost(
17 + "disk"
18 + , id
19 + , name
20 + , "io"
21 + , "disk.io"
22 + , "Disk I/O Bandwidth"
23 + , "KiB/s"
24 + , _COMMON_PLUGIN_NAME
25 + , _COMMON_PLUGIN_MODULE_NAME
26 + , NETDATA_CHART_PRIO_DISK_IO
27 + , update_every
28 + , RRDSET_TYPE_AREA
29 + );
30 +
31 + d->rd_io_reads = rrddim_add(d->st_io, "reads", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
32 + d->rd_io_writes = rrddim_add(d->st_io, "writes", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
33 +
34 + if(cb)
35 + cb(d->st_io, data);
36 + }
37 +
38 + // this always have to be in base units, so that exporting sends base units to other time-series db
39 + rrddim_set_by_pointer(d->st_io, d->rd_io_reads, (collected_number)bytes_read);
40 + rrddim_set_by_pointer(d->st_io, d->rd_io_writes, (collected_number)bytes_write);
41 + rrdset_done(d->st_io);
42 +}
43 +
44 +#endif //NETDATA_DISK_IO_H
src/collectors/common-contexts/mem.available.h new
+35
@@ -0,0 +1,35 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_MEM_AVAILABLE_H
4 +#define NETDATA_MEM_AVAILABLE_H
5 +#include "common-contexts.h"
6 +
7 +static inline void common_mem_available(uint64_t available_bytes, int update_every) {
8 + static RRDSET *st_mem_available = NULL;
9 + static RRDDIM *rd_avail = NULL;
10 +
11 + if(unlikely(!st_mem_available)) {
12 + st_mem_available = rrdset_create_localhost(
13 + "mem"
14 + , "available"
15 + , NULL
16 + , "overview"
17 + , NULL
18 + , "Available RAM for applications"
19 + , "MiB"
20 + , _COMMON_PLUGIN_NAME
21 + , _COMMON_PLUGIN_MODULE_NAME
22 + , NETDATA_CHART_PRIO_MEM_SYSTEM_AVAILABLE
23 + , update_every
24 + , RRDSET_TYPE_AREA
25 + );
26 +
27 + rd_avail = rrddim_add(st_mem_available, "avail", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
28 + }
29 +
30 + // this always have to be in base units, so that exporting sends base units to other time-series db
31 + rrddim_set_by_pointer(st_mem_available, rd_avail, (collected_number)available_bytes);
32 + rrdset_done(st_mem_available);
33 +}
34 +
35 +#endif //NETDATA_MEM_AVAILABLE_H
src/collectors/common-contexts/mem.pgfaults.h new
+40
@@ -0,0 +1,40 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_MEM_PGFAULTS_H
4 +#define NETDATA_MEM_PGFAULTS_H
5 +
6 +#include "common-contexts.h"
7 +
8 +static inline void common_mem_pgfaults(uint64_t minor, uint64_t major, int update_every) {
9 + static RRDSET *st_pgfaults = NULL;
10 + static RRDDIM *rd_minor = NULL, *rd_major = NULL;
11 +
12 + if(unlikely(!st_pgfaults)) {
13 + st_pgfaults = rrdset_create_localhost(
14 + "mem"
15 + , "pgfaults"
16 + , NULL
17 + , "page faults"
18 + , NULL
19 + , "Memory Page Faults"
20 + , "faults/s"
21 + , _COMMON_PLUGIN_NAME
22 + , _COMMON_PLUGIN_MODULE_NAME
23 + , NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS
24 + , update_every
25 + , RRDSET_TYPE_LINE
26 + );
27 +
28 + rrdset_flag_set(st_pgfaults, RRDSET_FLAG_DETAIL);
29 +
30 + rd_minor = rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
31 + rd_major = rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
32 + }
33 +
34 + // this always have to be in base units, so that exporting sends base units to other time-series db
35 + rrddim_set_by_pointer(st_pgfaults, rd_minor, minor);
36 + rrddim_set_by_pointer(st_pgfaults, rd_major, major);
37 + rrdset_done(st_pgfaults);
38 +}
39 +
40 +#endif //NETDATA_MEM_PGFAULTS_H
src/collectors/common-contexts/mem.swap.h new
+35
@@ -0,0 +1,35 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "common-contexts.h"
4 +
5 +static inline void common_mem_swap(uint64_t free_bytes, uint64_t used_bytes, int update_every) {
6 + static RRDSET *st_system_swap = NULL;
7 + static RRDDIM *rd_free = NULL, *rd_used = NULL;
8 +
9 + if(unlikely(!st_system_swap)) {
10 + st_system_swap = rrdset_create_localhost(
11 + "mem"
12 + , "swap"
13 + , NULL
14 + , "swap"
15 + , NULL
16 + , "System Swap"
17 + , "MiB"
18 + , _COMMON_PLUGIN_NAME
19 + , _COMMON_PLUGIN_MODULE_NAME
20 + , NETDATA_CHART_PRIO_MEM_SWAP
21 + , update_every
22 + , RRDSET_TYPE_STACKED
23 + );
24 +
25 + rrdset_flag_set(st_system_swap, RRDSET_FLAG_DETAIL);
26 +
27 + rd_free = rrddim_add(st_system_swap, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
28 + rd_used = rrddim_add(st_system_swap, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
29 + }
30 +
31 + // this always have to be in base units, so that exporting sends base units to other time-series db
32 + rrddim_set_by_pointer(st_system_swap, rd_used, (collected_number)used_bytes);
33 + rrddim_set_by_pointer(st_system_swap, rd_free, (collected_number)free_bytes);
34 + rrdset_done(st_system_swap);
35 +}
src/collectors/common-contexts/system.io.h new
+38
@@ -0,0 +1,38 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_SYSTEM_IO_H
4 +#define NETDATA_SYSTEM_IO_H
5 +
6 +#include "common-contexts.h"
7 +
8 +static inline void common_system_io(uint64_t read_bytes, uint64_t write_bytes, int update_every) {
9 + static RRDSET *st_io = NULL;
10 + static RRDDIM *rd_in = NULL, *rd_out = NULL;
11 +
12 + if(unlikely(!st_io)) {
13 + st_io = rrdset_create_localhost(
14 + "system"
15 + , "io"
16 + , NULL
17 + , "disk"
18 + , NULL
19 + , "Disk I/O"
20 + , "KiB/s"
21 + , _COMMON_PLUGIN_NAME
22 + , _COMMON_PLUGIN_MODULE_NAME
23 + , NETDATA_CHART_PRIO_SYSTEM_IO
24 + , update_every
25 + , RRDSET_TYPE_AREA
26 + );
27 +
28 + rd_in = rrddim_add(st_io, "in", "reads", 1, 1024, RRD_ALGORITHM_INCREMENTAL);
29 + rd_out = rrddim_add(st_io, "out", "writes", -1, 1024, RRD_ALGORITHM_INCREMENTAL);
30 + }
31 +
32 + // this always have to be in base units, so that exporting sends base units to other time-series db
33 + rrddim_set_by_pointer(st_io, rd_in, (collected_number)read_bytes);
34 + rrddim_set_by_pointer(st_io, rd_out, (collected_number)write_bytes);
35 + rrdset_done(st_io);
36 +}
37 +
38 +#endif //NETDATA_SYSTEM_IO_H
src/collectors/common-contexts/system.ram.h new
+68
@@ -0,0 +1,68 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_SYSTEM_RAM_H
4 +#define NETDATA_SYSTEM_RAM_H
5 +
6 +#include "common-contexts.h"
7 +
8 +#define _system_ram_chart() \
9 + rrdset_create_localhost( \
10 + "system" \
11 + , "ram" \
12 + , NULL \
13 + , "ram" \
14 + , NULL \
15 + , "System RAM" \
16 + , "MiB" \
17 + , _COMMON_PLUGIN_NAME \
18 + , _COMMON_PLUGIN_MODULE_NAME \
19 + , NETDATA_CHART_PRIO_SYSTEM_RAM \
20 + , update_every \
21 + , RRDSET_TYPE_STACKED \
22 + )
23 +
24 +#if defined(COMPILED_FOR_WINDOWS)
25 +static inline void common_system_ram(uint64_t free_bytes, uint64_t used_bytes, int update_every) {
26 + static RRDSET *st_system_ram = NULL;
27 + static RRDDIM *rd_free = NULL;
28 + static RRDDIM *rd_used = NULL;
29 +
30 + if(unlikely(!st_system_ram)) {
31 + st_system_ram = _system_ram_chart();
32 + rd_free = rrddim_add(st_system_ram, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
33 + rd_used = rrddim_add(st_system_ram, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
34 + }
35 +
36 + // this always have to be in base units, so that exporting sends base units to other time-series db
37 + rrddim_set_by_pointer(st_system_ram, rd_free, (collected_number)free_bytes);
38 + rrddim_set_by_pointer(st_system_ram, rd_used, (collected_number)used_bytes);
39 + rrdset_done(st_system_ram);
40 +}
41 +#endif
42 +
43 +#if defined(COMPILED_FOR_LINUX)
44 +static inline void common_system_ram(uint64_t free_bytes, uint64_t used_bytes, uint64_t cached_bytes, uint64_t buffers_bytes, int update_every) {
45 + static RRDSET *st_system_ram = NULL;
46 + static RRDDIM *rd_free = NULL;
47 + static RRDDIM *rd_used = NULL;
48 + static RRDDIM *rd_cached = NULL;
49 + static RRDDIM *rd_buffers = NULL;
50 +
51 + if(unlikely(!st_system_ram)) {
52 + st_system_ram = _system_ram_chart();
53 + rd_free = rrddim_add(st_system_ram, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
54 + rd_used = rrddim_add(st_system_ram, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
55 + rd_cached = rrddim_add(st_system_ram, "cached", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
56 + rd_buffers = rrddim_add(st_system_ram, "buffers", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
57 + }
58 +
59 + // this always have to be in base units, so that exporting sends base units to other time-series db
60 + rrddim_set_by_pointer(st_system_ram, rd_free, (collected_number)free_bytes);
61 + rrddim_set_by_pointer(st_system_ram, rd_used, (collected_number)used_bytes);
62 + rrddim_set_by_pointer(st_system_ram, rd_cached, (collected_number)cached_bytes);
63 + rrddim_set_by_pointer(st_system_ram, rd_buffers, (collected_number)buffers_bytes);
64 + rrdset_done(st_system_ram);
65 +}
66 +#endif
67 +
68 +#endif //NETDATA_SYSTEM_RAM_H
src/collectors/diskspace.plugin/plugin_diskspace.c
+18 -28
@@ -14,7 +14,7 @@
14 #define MAX_STAT_USEC 10000LU
15 #define SLOW_UPDATE_EVERY 5
16
17 -static netdata_thread_t *diskspace_slow_thread = NULL;
17 +static ND_THREAD *diskspace_slow_thread = NULL;
18
19 static struct mountinfo *disk_mountinfo_root = NULL;
20 static int check_for_new_mountpoints_every = 15;
@@ -513,9 +513,9 @@ cleanup:
513 dictionary_acquired_item_release(dict_mountpoints, item);
514 }
515
516 -static void diskspace_slow_worker_cleanup(void *ptr)
517 -{
518 - UNUSED(ptr);
516 +static void diskspace_slow_worker_cleanup(void *pptr) {
517 + struct slow_worker_data *data = CLEANUP_FUNCTION_GET_PTR(pptr);
518 + if(data) return;
519
520 collector_info("cleaning up...");
521
@@ -526,14 +526,14 @@ static void diskspace_slow_worker_cleanup(void *ptr)
526 #define WORKER_JOB_SLOW_CLEANUP 1
527
528 struct slow_worker_data {
529 - netdata_thread_t *slow_thread;
529 int update_every;
530 };
531
532 void *diskspace_slow_worker(void *ptr)
533 {
534 struct slow_worker_data *data = (struct slow_worker_data *)ptr;
536 -
535 + CLEANUP_FUNCTION_REGISTER(diskspace_slow_worker_cleanup) cleanup_ptr = data;
536 +
537 worker_register("DISKSPACE_SLOW");
538 worker_register_job_name(WORKER_JOB_SLOW_MOUNTPOINT, "mountpoint");
539 worker_register_job_name(WORKER_JOB_SLOW_CLEANUP, "cleanup");
@@ -542,8 +542,6 @@ void *diskspace_slow_worker(void *ptr)
542
543 int slow_update_every = data->update_every > SLOW_UPDATE_EVERY ? data->update_every : SLOW_UPDATE_EVERY;
544
545 - netdata_thread_cleanup_push(diskspace_slow_worker_cleanup, data->slow_thread);
546 -
545 usec_t step = slow_update_every * USEC_PER_SEC;
546 usec_t real_step = USEC_PER_SEC;
547 heartbeat_t hb;
@@ -600,26 +598,24 @@ void *diskspace_slow_worker(void *ptr)
598 }
599 }
600
603 - netdata_thread_cleanup_pop(1);
604 -
601 free_basic_mountinfo_list(slow_mountinfo_root);
602
603 return NULL;
604 }
605
610 -static void diskspace_main_cleanup(void *ptr) {
611 - rrd_collector_finished();
612 - worker_unregister();
606 +static void diskspace_main_cleanup(void *pptr) {
607 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
608 + if(!static_thread) return;
609
614 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
610 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
611
612 collector_info("cleaning up...");
613
619 - if (diskspace_slow_thread) {
620 - netdata_thread_join(*diskspace_slow_thread, NULL);
621 - freez(diskspace_slow_thread);
622 - }
614 + rrd_collector_finished();
615 + worker_unregister();
616 +
617 + if (diskspace_slow_thread)
618 + nd_thread_join(diskspace_slow_thread);
619
620 free_basic_mountinfo_list(slow_mountinfo_tmp_root);
621
@@ -846,6 +842,8 @@ int diskspace_function_mount_points(BUFFER *wb, const char *function __maybe_unu
842 }
843
844 void *diskspace_main(void *ptr) {
845 + CLEANUP_FUNCTION_REGISTER(diskspace_main_cleanup) cleanup_ptr = ptr;
846 +
847 worker_register("DISKSPACE");
848 worker_register_job_name(WORKER_JOB_MOUNTINFO, "mountinfo");
849 worker_register_job_name(WORKER_JOB_MOUNTPOINT, "mountpoint");
@@ -856,8 +854,6 @@ void *diskspace_main(void *ptr) {
854 "top", HTTP_ACCESS_ANONYMOUS_DATA,
855 diskspace_function_mount_points);
856
859 - netdata_thread_cleanup_push(diskspace_main_cleanup, ptr);
860 -
857 cleanup_mount_points = config_get_boolean(CONFIG_SECTION_DISKSPACE, "remove charts of unmounted disks" , cleanup_mount_points);
858
859 int update_every = (int)config_get_number(CONFIG_SECTION_DISKSPACE, "update every", localhost->rrd_update_every);
@@ -870,12 +866,9 @@ void *diskspace_main(void *ptr) {
866
867 netdata_mutex_init(&slow_mountinfo_mutex);
868
873 - diskspace_slow_thread = mallocz(sizeof(netdata_thread_t));
874 -
875 - struct slow_worker_data slow_worker_data = {.slow_thread = diskspace_slow_thread, .update_every = update_every};
869 + struct slow_worker_data slow_worker_data = { .update_every = update_every };
870
877 - netdata_thread_create(
878 - diskspace_slow_thread,
871 + diskspace_slow_thread = nd_thread_create(
872 "P[diskspace slow]",
873 NETDATA_THREAD_OPTION_JOINABLE,
874 diskspace_slow_worker,
@@ -926,8 +919,5 @@ void *diskspace_main(void *ptr) {
919 mount_points_cleanup(false);
920 }
921 }
929 - worker_unregister();
930 -
931 - netdata_thread_cleanup_pop(1);
922 return NULL;
923 }
src/collectors/ebpf.plugin/ebpf.c
+13 -12
@@ -927,7 +927,7 @@ void ebpf_stop_threads(int sig)
927
928 // Child thread should be closed by itself.
929 pthread_mutex_lock(&ebpf_exit_cleanup);
930 - if (main_thread_id != gettid() || only_one) {
930 + if (main_thread_id != gettid_cached() || only_one) {
931 pthread_mutex_unlock(&ebpf_exit_cleanup);
932 return;
933 }
@@ -935,7 +935,7 @@ void ebpf_stop_threads(int sig)
935 int i;
936 for (i = 0; ebpf_modules[i].info.thread_name != NULL; i++) {
937 if (ebpf_modules[i].enabled < NETDATA_THREAD_EBPF_STOPPING) {
938 - netdata_thread_cancel(*ebpf_modules[i].thread->thread);
938 + nd_thread_signal_cancel(ebpf_modules[i].thread->thread);
939 #ifdef NETDATA_DEV_MODE
940 netdata_log_info("Sending cancel for thread %s", ebpf_modules[i].info.thread_name);
941 #endif
@@ -945,13 +945,13 @@ void ebpf_stop_threads(int sig)
945
946 for (i = 0; ebpf_modules[i].info.thread_name != NULL; i++) {
947 if (ebpf_threads[i].thread)
948 - netdata_thread_join(*ebpf_threads[i].thread, NULL);
948 + nd_thread_join(ebpf_threads[i].thread);
949 }
950
951 ebpf_plugin_exit = true;
952
953 pthread_mutex_lock(&mutex_cgroup_shm);
954 - netdata_thread_cancel(*cgroup_integration_thread.thread);
954 + nd_thread_signal_cancel(cgroup_integration_thread.thread);
955 #ifdef NETDATA_DEV_MODE
956 netdata_log_info("Sending cancel for thread %s", cgroup_integration_thread.name);
957 #endif
@@ -3040,7 +3040,7 @@ void set_global_variables()
3040 }
3041
3042 isrh = get_redhat_release();
3043 - pid_max = get_system_pid_max();
3043 + pid_max = os_get_system_pid_max();
3044 running_on_kernel = ebpf_get_kernel_version();
3045 }
3046
@@ -3974,7 +3974,7 @@ int main(int argc, char **argv)
3974 clocks_init();
3975 nd_log_initialize_for_external_plugins(NETDATA_EBPF_PLUGIN_NAME);
3976
3977 - main_thread_id = gettid();
3977 + main_thread_id = gettid_cached();
3978
3979 set_global_variables();
3980 ebpf_parse_args(argc, argv);
@@ -4010,11 +4010,13 @@ int main(int argc, char **argv)
4010
4011 ebpf_set_static_routine();
4012
4013 - cgroup_integration_thread.thread = mallocz(sizeof(netdata_thread_t));
4013 cgroup_integration_thread.start_routine = ebpf_cgroup_integration;
4014
4016 - netdata_thread_create(cgroup_integration_thread.thread, cgroup_integration_thread.name,
4017 - NETDATA_THREAD_OPTION_DEFAULT, ebpf_cgroup_integration, NULL);
4015 + cgroup_integration_thread.thread = nd_thread_create(
4016 + cgroup_integration_thread.name,
4017 + NETDATA_THREAD_OPTION_DEFAULT,
4018 + ebpf_cgroup_integration,
4019 + NULL);
4020
4021 int i;
4022 for (i = 0; ebpf_threads[i].name != NULL; i++) {
@@ -4024,10 +4026,9 @@ int main(int argc, char **argv)
4026 em->thread = st;
4027 em->thread_id = i;
4028 if (em->enabled != NETDATA_THREAD_EBPF_NOT_RUNNING) {
4027 - st->thread = mallocz(sizeof(netdata_thread_t));
4029 em->enabled = NETDATA_THREAD_EBPF_RUNNING;
4030 em->lifetime = EBPF_NON_FUNCTION_LIFE_TIME;
4030 - netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_JOINABLE, st->start_routine, em);
4031 + st->thread = nd_thread_create(st->name, NETDATA_THREAD_OPTION_JOINABLE, st->start_routine, em);
4032 } else {
4033 em->lifetime = EBPF_DEFAULT_LIFETIME;
4034 }
@@ -4041,7 +4042,7 @@ int main(int argc, char **argv)
4042 int update_apps_list = update_apps_every - 1;
4043 int process_maps_per_core = ebpf_modules[EBPF_MODULE_PROCESS_IDX].maps_per_core;
4044 //Plugin will be killed when it receives a signal
4044 - for ( ; !ebpf_plugin_exit; global_iterations_counter++) {
4045 + for ( ; !ebpf_plugin_stop(); global_iterations_counter++) {
4046 (void)heartbeat_next(&hb, step);
4047
4048 if (global_iterations_counter % EBPF_DEFAULT_UPDATE_EVERY == 0) {
src/collectors/ebpf.plugin/ebpf.h
+5
@@ -389,6 +389,11 @@ void ebpf_read_local_addresses_unsafe();
389 extern ebpf_filesystem_partitions_t localfs[];
390 extern ebpf_sync_syscalls_t local_syscalls[];
391 extern bool ebpf_plugin_exit;
392 +
393 +static inline bool ebpf_plugin_stop(void) {
394 + return ebpf_plugin_exit || nd_thread_signaled_to_cancel();
395 +}
396 +
397 void ebpf_stop_threads(int sig);
398 extern netdata_ebpf_judy_pid_t ebpf_judy_pid;
399
src/collectors/ebpf.plugin/ebpf_cachestat.c
+16 -19
@@ -523,12 +523,13 @@ void ebpf_obsolete_cachestat_apps_charts(struct ebpf_module *em)
523 *
524 * @param ptr thread data.
525 */
526 -static void ebpf_cachestat_exit(void *ptr)
526 +static void ebpf_cachestat_exit(void *pptr)
527 {
528 - ebpf_module_t *em = (ebpf_module_t *)ptr;
528 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
529 + if(!em) return;
530
531 if (ebpf_read_cachestat.thread)
531 - netdata_thread_cancel(*ebpf_read_cachestat.thread);
532 + nd_thread_signal_cancel(ebpf_read_cachestat.thread);
533
534 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
535 pthread_mutex_lock(&lock);
@@ -840,13 +841,11 @@ void *ebpf_read_cachestat_thread(void *ptr)
841 uint32_t lifetime = em->lifetime;
842 uint32_t running_time = 0;
843 usec_t period = update_every * USEC_PER_SEC;
843 - while (!ebpf_plugin_exit && running_time < lifetime) {
844 + while (!ebpf_plugin_stop() && running_time < lifetime) {
845 (void)heartbeat_next(&hb, period);
845 - if (ebpf_plugin_exit || ++counter != update_every)
846 + if (ebpf_plugin_stop() || ++counter != update_every)
847 continue;
848
848 - netdata_thread_disable_cancelability();
849 -
849 pthread_mutex_lock(&collect_data_mutex);
850 ebpf_read_cachestat_apps_table(maps_per_core, max_period);
851 ebpf_resume_apps_data();
@@ -862,7 +861,6 @@ void *ebpf_read_cachestat_thread(void *ptr)
861
862 em->running_time = running_time;
863 pthread_mutex_unlock(&ebpf_exit_cleanup);
865 - netdata_thread_enable_cancelability();
864 }
865
866 return NULL;
@@ -1402,10 +1400,10 @@ static void cachestat_collector(ebpf_module_t *em)
1400 uint32_t lifetime = em->lifetime;
1401 netdata_idx_t *stats = em->hash_table_stats;
1402 memset(stats, 0, sizeof(em->hash_table_stats));
1405 - while (!ebpf_plugin_exit && running_time < lifetime) {
1403 + while (!ebpf_plugin_stop() && running_time < lifetime) {
1404 (void)heartbeat_next(&hb, USEC_PER_SEC);
1405
1408 - if (ebpf_plugin_exit || ++counter != update_every)
1406 + if (ebpf_plugin_stop() || ++counter != update_every)
1407 continue;
1408
1409 counter = 0;
@@ -1593,9 +1591,10 @@ static int ebpf_cachestat_load_bpf(ebpf_module_t *em)
1591 */
1592 void *ebpf_cachestat_thread(void *ptr)
1593 {
1596 - netdata_thread_cleanup_push(ebpf_cachestat_exit, ptr);
1597 -
1594 ebpf_module_t *em = (ebpf_module_t *)ptr;
1595 +
1596 + CLEANUP_FUNCTION_REGISTER(ebpf_cachestat_exit) cleanup_ptr = em;
1597 +
1598 em->maps = cachestat_maps;
1599
1600 ebpf_update_pid_table(&cachestat_maps[NETDATA_CACHESTAT_PID_STATS], em);
@@ -1628,18 +1627,16 @@ void *ebpf_cachestat_thread(void *ptr)
1627
1628 pthread_mutex_unlock(&lock);
1629
1631 - ebpf_read_cachestat.thread = mallocz(sizeof(netdata_thread_t));
1632 - netdata_thread_create(ebpf_read_cachestat.thread,
1633 - ebpf_read_cachestat.name,
1634 - NETDATA_THREAD_OPTION_DEFAULT,
1635 - ebpf_read_cachestat_thread,
1636 - em);
1630 + ebpf_read_cachestat.thread = nd_thread_create(
1631 + ebpf_read_cachestat.name,
1632 + NETDATA_THREAD_OPTION_DEFAULT,
1633 + ebpf_read_cachestat_thread,
1634 + em);
1635
1636 cachestat_collector(em);
1637
1638 endcachestat:
1639 ebpf_update_disabled_plugin_stats(em);
1640
1643 - netdata_thread_cleanup_pop(1);
1641 return NULL;
1642 }
src/collectors/ebpf.plugin/ebpf_cgroup.c
+2 -17
@@ -348,18 +348,6 @@ void ebpf_create_charts_on_systemd(ebpf_systemd_args_t *chart)
348 // --------------------------------------------------------------------------------------------------------------------
349 // Cgroup main thread
350
351 -/**
352 - * CGROUP exit
353 - *
354 - * Clean up the main thread.
355 - *
356 - * @param ptr thread data.
357 - */
358 -static void ebpf_cgroup_exit(void *ptr)
359 -{
360 - UNUSED(ptr);
361 -}
362 -
351 /**
352 * Cgroup integratin
353 *
@@ -369,16 +357,14 @@ static void ebpf_cgroup_exit(void *ptr)
357 *
358 * @return It always returns NULL.
359 */
372 -void *ebpf_cgroup_integration(void *ptr)
360 +void *ebpf_cgroup_integration(void *ptr __maybe_unused)
361 {
374 - netdata_thread_cleanup_push(ebpf_cgroup_exit, ptr);
375 -
362 usec_t step = USEC_PER_SEC;
363 int counter = NETDATA_EBPF_CGROUP_UPDATE - 1;
364 heartbeat_t hb;
365 heartbeat_init(&hb);
366 //Plugin will be killed when it receives a signal
381 - while (!ebpf_plugin_exit) {
367 + while (!ebpf_plugin_stop()) {
368 (void)heartbeat_next(&hb, step);
369
370 // We are using a small heartbeat time to wake up thread,
@@ -392,6 +378,5 @@ void *ebpf_cgroup_integration(void *ptr)
378 }
379 }
380
395 - netdata_thread_cleanup_pop(1);
381 return NULL;
382 }
src/collectors/ebpf.plugin/ebpf_dcstat.c
+12 -19
@@ -451,12 +451,13 @@ static void ebpf_obsolete_dc_global(ebpf_module_t *em)
451 *
452 * @param ptr thread data.
453 */
454 -static void ebpf_dcstat_exit(void *ptr)
454 +static void ebpf_dcstat_exit(void *pptr)
455 {
456 - ebpf_module_t *em = (ebpf_module_t *)ptr;
456 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
457 + if(!em) return;
458
459 if (ebpf_read_dcstat.thread)
459 - netdata_thread_cancel(*ebpf_read_dcstat.thread);
460 + nd_thread_signal_cancel(ebpf_read_dcstat.thread);
461
462 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
463 pthread_mutex_lock(&lock);
@@ -641,13 +642,11 @@ void *ebpf_read_dcstat_thread(void *ptr)
642 uint32_t running_time = 0;
643 usec_t period = update_every * USEC_PER_SEC;
644 int max_period = update_every * EBPF_CLEANUP_FACTOR;
644 - while (!ebpf_plugin_exit && running_time < lifetime) {
645 + while (!ebpf_plugin_stop() && running_time < lifetime) {
646 (void)heartbeat_next(&hb, period);
646 - if (ebpf_plugin_exit || ++counter != update_every)
647 + if (ebpf_plugin_stop() || ++counter != update_every)
648 continue;
649
649 - netdata_thread_disable_cancelability();
650 -
650 pthread_mutex_lock(&collect_data_mutex);
651 ebpf_read_dc_apps_table(maps_per_core, max_period);
652 ebpf_dc_resume_apps_data();
@@ -663,7 +662,6 @@ void *ebpf_read_dcstat_thread(void *ptr)
662
663 em->running_time = running_time;
664 pthread_mutex_unlock(&ebpf_exit_cleanup);
666 - netdata_thread_enable_cancelability();
665 }
666
667 return NULL;
@@ -1261,10 +1259,10 @@ static void dcstat_collector(ebpf_module_t *em)
1259 uint32_t lifetime = em->lifetime;
1260 netdata_idx_t *stats = em->hash_table_stats;
1261 memset(stats, 0, sizeof(em->hash_table_stats));
1264 - while (!ebpf_plugin_exit && running_time < lifetime) {
1262 + while (!ebpf_plugin_stop() && running_time < lifetime) {
1263 (void)heartbeat_next(&hb, USEC_PER_SEC);
1264
1267 - if (ebpf_plugin_exit || ++counter != update_every)
1265 + if (ebpf_plugin_stop() || ++counter != update_every)
1266 continue;
1267
1268 counter = 0;
@@ -1403,9 +1401,9 @@ static int ebpf_dcstat_load_bpf(ebpf_module_t *em)
1401 */
1402 void *ebpf_dcstat_thread(void *ptr)
1403 {
1406 - netdata_thread_cleanup_push(ebpf_dcstat_exit, ptr);
1407 -
1404 ebpf_module_t *em = (ebpf_module_t *)ptr;
1405 + CLEANUP_FUNCTION_REGISTER(ebpf_dcstat_exit) cleanup_ptr = em;
1406 +
1407 em->maps = dcstat_maps;
1408
1409 ebpf_update_pid_table(&dcstat_maps[NETDATA_DCSTAT_PID_STATS], em);
@@ -1437,18 +1435,13 @@ void *ebpf_dcstat_thread(void *ptr)
1435
1436 pthread_mutex_unlock(&lock);
1437
1440 - ebpf_read_dcstat.thread = mallocz(sizeof(netdata_thread_t));
1441 - netdata_thread_create(ebpf_read_dcstat.thread,
1442 - ebpf_read_dcstat.name,
1443 - NETDATA_THREAD_OPTION_DEFAULT,
1444 - ebpf_read_dcstat_thread,
1445 - em);
1438 + ebpf_read_dcstat.thread = nd_thread_create(ebpf_read_dcstat.name, NETDATA_THREAD_OPTION_DEFAULT,
1439 + ebpf_read_dcstat_thread, em);
1440
1441 dcstat_collector(em);
1442
1443 enddcstat:
1444 ebpf_update_disabled_plugin_stats(em);
1445
1452 - netdata_thread_cleanup_pop(1);
1446 return NULL;
1447 }
src/collectors/ebpf.plugin/ebpf_disk.c
+8 -8
@@ -506,9 +506,10 @@ static void ebpf_obsolete_disk_global(ebpf_module_t *em)
506 *
507 * @param ptr thread data.
508 */
509 -static void ebpf_disk_exit(void *ptr)
509 +static void ebpf_disk_exit(void *pptr)
510 {
511 - ebpf_module_t *em = (ebpf_module_t *)ptr;
511 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
512 + if(!em) return;
513
514 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
515 pthread_mutex_lock(&lock);
@@ -779,10 +780,10 @@ static void disk_collector(ebpf_module_t *em)
780 int maps_per_core = em->maps_per_core;
781 uint32_t running_time = 0;
782 uint32_t lifetime = em->lifetime;
782 - while (!ebpf_plugin_exit && running_time < lifetime) {
783 + while (!ebpf_plugin_stop() && running_time < lifetime) {
784 (void)heartbeat_next(&hb, USEC_PER_SEC);
785
785 - if (ebpf_plugin_exit || ++counter != update_every)
786 + if (ebpf_plugin_stop() || ++counter != update_every)
787 continue;
788
789 counter = 0;
@@ -890,9 +891,10 @@ static int ebpf_disk_load_bpf(ebpf_module_t *em)
891 */
892 void *ebpf_disk_thread(void *ptr)
893 {
893 - netdata_thread_cleanup_push(ebpf_disk_exit, ptr);
894 -
894 ebpf_module_t *em = (ebpf_module_t *)ptr;
895 +
896 + CLEANUP_FUNCTION_REGISTER(ebpf_disk_exit) cleanup_ptr = em;
897 +
898 em->maps = disk_maps;
899
900 if (ebpf_disk_enable_tracepoints()) {
@@ -934,7 +936,5 @@ void *ebpf_disk_thread(void *ptr)
936 enddisk:
937 ebpf_update_disabled_plugin_stats(em);
938
937 - netdata_thread_cleanup_pop(1);
938 -
939 return NULL;
940 }
src/collectors/ebpf.plugin/ebpf_fd.c
+12 -19
@@ -546,12 +546,13 @@ static void ebpf_obsolete_fd_global(ebpf_module_t *em)
546 *
547 * @param ptr thread data.
548 */
549 -static void ebpf_fd_exit(void *ptr)
549 +static void ebpf_fd_exit(void *pptr)
550 {
551 - ebpf_module_t *em = (ebpf_module_t *)ptr;
551 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
552 + if(!em) return;
553
554 if (ebpf_read_fd.thread)
554 - netdata_thread_cancel(*ebpf_read_fd.thread);
555 + nd_thread_signal_cancel(ebpf_read_fd.thread);
556
557 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
558 pthread_mutex_lock(&lock);
@@ -773,13 +774,11 @@ void *ebpf_read_fd_thread(void *ptr)
774 uint32_t running_time = 0;
775 usec_t period = update_every * USEC_PER_SEC;
776 int max_period = update_every * EBPF_CLEANUP_FACTOR;
776 - while (!ebpf_plugin_exit && running_time < lifetime) {
777 + while (!ebpf_plugin_stop() && running_time < lifetime) {
778 (void)heartbeat_next(&hb, period);
778 - if (ebpf_plugin_exit || ++counter != update_every)
779 + if (ebpf_plugin_stop() || ++counter != update_every)
780 continue;
781
781 - netdata_thread_disable_cancelability();
782 -
782 pthread_mutex_lock(&collect_data_mutex);
783 ebpf_read_fd_apps_table(maps_per_core, max_period);
784 ebpf_fd_resume_apps_data();
@@ -795,7 +794,6 @@ void *ebpf_read_fd_thread(void *ptr)
794
795 em->running_time = running_time;
796 pthread_mutex_unlock(&ebpf_exit_cleanup);
798 - netdata_thread_enable_cancelability();
797 }
798
799 return NULL;
@@ -1205,10 +1203,10 @@ static void fd_collector(ebpf_module_t *em)
1203 uint32_t lifetime = em->lifetime;
1204 netdata_idx_t *stats = em->hash_table_stats;
1205 memset(stats, 0, sizeof(em->hash_table_stats));
1208 - while (!ebpf_plugin_exit && running_time < lifetime) {
1206 + while (!ebpf_plugin_stop() && running_time < lifetime) {
1207 (void)heartbeat_next(&hb, USEC_PER_SEC);
1208
1211 - if (ebpf_plugin_exit || ++counter != update_every)
1209 + if (ebpf_plugin_stop() || ++counter != update_every)
1210 continue;
1211
1212 counter = 0;
@@ -1439,9 +1437,10 @@ static int ebpf_fd_load_bpf(ebpf_module_t *em)
1437 */
1438 void *ebpf_fd_thread(void *ptr)
1439 {
1442 - netdata_thread_cleanup_push(ebpf_fd_exit, ptr);
1443 -
1440 ebpf_module_t *em = (ebpf_module_t *)ptr;
1441 +
1442 + CLEANUP_FUNCTION_REGISTER(ebpf_fd_exit) cleanup_ptr = em;
1443 +
1444 em->maps = fd_maps;
1445
1446 #ifdef LIBBPF_MAJOR_VERSION
@@ -1467,18 +1466,12 @@ void *ebpf_fd_thread(void *ptr)
1466
1467 pthread_mutex_unlock(&lock);
1468
1470 - ebpf_read_fd.thread = mallocz(sizeof(netdata_thread_t));
1471 - netdata_thread_create(ebpf_read_fd.thread,
1472 - ebpf_read_fd.name,
1473 - NETDATA_THREAD_OPTION_DEFAULT,
1474 - ebpf_read_fd_thread,
1475 - em);
1469 + ebpf_read_fd.thread = nd_thread_create(ebpf_read_fd.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_read_fd_thread, em);
1470
1471 fd_collector(em);
1472
1473 endfd:
1474 ebpf_update_disabled_plugin_stats(em);
1475
1482 - netdata_thread_cleanup_pop(1);
1476 return NULL;
1477 }
src/collectors/ebpf.plugin/ebpf_filesystem.c
+8 -7
@@ -724,9 +724,10 @@ static void ebpf_obsolete_filesystem_global(ebpf_module_t *em)
724 *
725 * @param ptr thread data.
726 */
727 -static void ebpf_filesystem_exit(void *ptr)
727 +static void ebpf_filesystem_exit(void *pptr)
728 {
729 - ebpf_module_t *em = (ebpf_module_t *)ptr;
729 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
730 + if(!em) return;
731
732 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
733 pthread_mutex_lock(&lock);
@@ -915,10 +916,10 @@ static void filesystem_collector(ebpf_module_t *em)
916 int counter = update_every - 1;
917 uint32_t running_time = 0;
918 uint32_t lifetime = em->lifetime;
918 - while (!ebpf_plugin_exit && running_time < lifetime) {
919 + while (!ebpf_plugin_stop() && running_time < lifetime) {
920 (void)heartbeat_next(&hb, USEC_PER_SEC);
921
921 - if (ebpf_plugin_exit || ++counter != update_every)
922 + if (ebpf_plugin_stop() || ++counter != update_every)
923 continue;
924
925 counter = 0;
@@ -990,9 +991,10 @@ static void ebpf_set_maps()
991 */
992 void *ebpf_filesystem_thread(void *ptr)
993 {
993 - netdata_thread_cleanup_push(ebpf_filesystem_exit, ptr);
994 -
994 ebpf_module_t *em = (ebpf_module_t *)ptr;
995 +
996 + CLEANUP_FUNCTION_REGISTER(ebpf_filesystem_exit) cleanup_ptr = em;
997 +
998 ebpf_set_maps();
999 ebpf_update_filesystem();
1000
@@ -1024,6 +1026,5 @@ void *ebpf_filesystem_thread(void *ptr)
1026 endfilesystem:
1027 ebpf_update_disabled_plugin_stats(em);
1028
1027 - netdata_thread_cleanup_pop(1);
1029 return NULL;
1030 }
src/collectors/ebpf.plugin/ebpf_functions.c
+5 -7
@@ -20,13 +20,10 @@ static int ebpf_function_start_thread(ebpf_module_t *em, int period)
20 {
21 struct netdata_static_thread *st = em->thread;
22 // another request for thread that already ran, cleanup and restart
23 - if (st->thread)
24 - freez(st->thread);
25 -
23 if (period <= 0)
24 period = EBPF_DEFAULT_LIFETIME;
25
29 - st->thread = mallocz(sizeof(netdata_thread_t));
26 + st->thread = NULL;
27 em->enabled = NETDATA_THREAD_EBPF_FUNCTION_RUNNING;
28 em->lifetime = period;
29
@@ -34,7 +31,8 @@ static int ebpf_function_start_thread(ebpf_module_t *em, int period)
31 netdata_log_info("Starting thread %s with lifetime = %d", em->info.thread_name, period);
32 #endif
33
37 - return netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, em);
34 + st->thread = nd_thread_create(st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, em);
35 + return st->thread ? 0 : 1;
36 }
37
38 /*****************************************************************
@@ -714,10 +712,10 @@ void *ebpf_function_thread(void *ptr)
712
713 heartbeat_t hb;
714 heartbeat_init(&hb);
717 - while(!ebpf_plugin_exit) {
715 + while(!ebpf_plugin_stop()) {
716 (void)heartbeat_next(&hb, USEC_PER_SEC);
717
720 - if (ebpf_plugin_exit) {
718 + if (ebpf_plugin_stop()) {
719 break;
720 }
721 }
src/collectors/ebpf.plugin/ebpf_hardirq.c
+8 -8
@@ -244,9 +244,10 @@ static void ebpf_obsolete_hardirq_global(ebpf_module_t *em)
244 *
245 * @param ptr thread data.
246 */
247 -static void hardirq_exit(void *ptr)
247 +static void hardirq_exit(void *pptr)
248 {
249 - ebpf_module_t *em = (ebpf_module_t *)ptr;
249 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
250 + if(!em) return;
251
252 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
253 pthread_mutex_lock(&lock);
@@ -581,10 +582,10 @@ static void hardirq_collector(ebpf_module_t *em)
582 //This will be cancelled by its parent
583 uint32_t running_time = 0;
584 uint32_t lifetime = em->lifetime;
584 - while (!ebpf_plugin_exit && running_time < lifetime) {
585 + while (!ebpf_plugin_stop() && running_time < lifetime) {
586 (void)heartbeat_next(&hb, USEC_PER_SEC);
587
587 - if (ebpf_plugin_exit || ++counter != update_every)
588 + if (ebpf_plugin_stop() || ++counter != update_every)
589 continue;
590
591 counter = 0;
@@ -658,9 +659,10 @@ static int ebpf_hardirq_load_bpf(ebpf_module_t *em)
659 */
660 void *ebpf_hardirq_thread(void *ptr)
661 {
661 - netdata_thread_cleanup_push(hardirq_exit, ptr);
662 -
662 ebpf_module_t *em = (ebpf_module_t *)ptr;
663 +
664 + CLEANUP_FUNCTION_REGISTER(hardirq_exit) cleanup_ptr = em;
665 +
666 em->maps = hardirq_maps;
667
668 if (ebpf_enable_tracepoints(hardirq_tracepoints) == 0) {
@@ -680,7 +682,5 @@ void *ebpf_hardirq_thread(void *ptr)
682 endhardirq:
683 ebpf_update_disabled_plugin_stats(em);
684
683 - netdata_thread_cleanup_pop(1);
684 -
685 return NULL;
686 }
src/collectors/ebpf.plugin/ebpf_mdflush.c
+7 -8
@@ -157,9 +157,10 @@ static void ebpf_obsolete_mdflush_global(ebpf_module_t *em)
157 *
158 * @param ptr thread data.
159 */
160 -static void mdflush_exit(void *ptr)
160 +static void mdflush_exit(void *pptr)
161 {
162 - ebpf_module_t *em = (ebpf_module_t *)ptr;
162 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
163 + if(!em) return;
164
165 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
166 pthread_mutex_lock(&lock);
@@ -346,10 +347,10 @@ static void mdflush_collector(ebpf_module_t *em)
347 int maps_per_core = em->maps_per_core;
348 uint32_t running_time = 0;
349 uint32_t lifetime = em->lifetime;
349 - while (!ebpf_plugin_exit && running_time < lifetime) {
350 + while (!ebpf_plugin_stop() && running_time < lifetime) {
351 (void)heartbeat_next(&hb, USEC_PER_SEC);
352
352 - if (ebpf_plugin_exit || ++counter != update_every)
353 + if (ebpf_plugin_stop() || ++counter != update_every)
354 continue;
355
356 counter = 0;
@@ -424,9 +425,9 @@ static int ebpf_mdflush_load_bpf(ebpf_module_t *em)
425 */
426 void *ebpf_mdflush_thread(void *ptr)
427 {
427 - netdata_thread_cleanup_push(mdflush_exit, ptr);
428 -
428 ebpf_module_t *em = (ebpf_module_t *)ptr;
429 + CLEANUP_FUNCTION_REGISTER(mdflush_exit) cleanup_ptr = em;
430 +
431 em->maps = mdflush_maps;
432
433 char *md_flush_request = ebpf_find_symbol("md_flush_request");
@@ -450,7 +451,5 @@ endmdflush:
451 freez(md_flush_request);
452 ebpf_update_disabled_plugin_stats(em);
453
453 - netdata_thread_cleanup_pop(1);
454 -
454 return NULL;
455 }
src/collectors/ebpf.plugin/ebpf_mount.c
+7 -7
@@ -261,9 +261,10 @@ static void ebpf_obsolete_mount_global(ebpf_module_t *em)
261 *
262 * @param ptr thread data.
263 */
264 -static void ebpf_mount_exit(void *ptr)
264 +static void ebpf_mount_exit(void *pptr)
265 {
266 - ebpf_module_t *em = (ebpf_module_t *)ptr;
266 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
267 + if(!em) return;
268
269 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
270 pthread_mutex_lock(&lock);
@@ -369,9 +370,9 @@ static void mount_collector(ebpf_module_t *em)
370 int maps_per_core = em->maps_per_core;
371 uint32_t running_time = 0;
372 uint32_t lifetime = em->lifetime;
372 - while (!ebpf_plugin_exit && running_time < lifetime) {
373 + while (!ebpf_plugin_stop() && running_time < lifetime) {
374 (void)heartbeat_next(&hb, USEC_PER_SEC);
374 - if (ebpf_plugin_exit || ++counter != update_every)
375 + if (ebpf_plugin_stop() || ++counter != update_every)
376 continue;
377
378 counter = 0;
@@ -484,9 +485,9 @@ static int ebpf_mount_load_bpf(ebpf_module_t *em)
485 */
486 void *ebpf_mount_thread(void *ptr)
487 {
487 - netdata_thread_cleanup_push(ebpf_mount_exit, ptr);
488 + ebpf_module_t *em = ptr;
489 + CLEANUP_FUNCTION_REGISTER(ebpf_mount_exit) cleanup_ptr = em;
490
489 - ebpf_module_t *em = (ebpf_module_t *)ptr;
491 em->maps = mount_maps;
492
493 #ifdef LIBBPF_MAJOR_VERSION
@@ -512,6 +513,5 @@ void *ebpf_mount_thread(void *ptr)
513 endmount:
514 ebpf_update_disabled_plugin_stats(em);
515
515 - netdata_thread_cleanup_pop(1);
516 return NULL;
517 }
src/collectors/ebpf.plugin/ebpf_oomkill.c
+8 -8
@@ -128,9 +128,10 @@ static void ebpf_obsolete_oomkill_apps(ebpf_module_t *em)
128 *
129 * @param ptr thread data.
130 */
131 -static void oomkill_cleanup(void *ptr)
131 +static void oomkill_cleanup(void *pptr)
132 {
133 - ebpf_module_t *em = (ebpf_module_t *)ptr;
133 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
134 + if(!em) return;
135
136 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
137 pthread_mutex_lock(&lock);
@@ -457,9 +458,9 @@ static void oomkill_collector(ebpf_module_t *em)
458 uint32_t running_time = 0;
459 uint32_t lifetime = em->lifetime;
460 netdata_idx_t *stats = em->hash_table_stats;
460 - while (!ebpf_plugin_exit && running_time < lifetime) {
461 + while (!ebpf_plugin_stop() && running_time < lifetime) {
462 (void)heartbeat_next(&hb, USEC_PER_SEC);
462 - if (ebpf_plugin_exit || ++counter != update_every)
463 + if (ebpf_plugin_stop() || ++counter != update_every)
464 continue;
465
466 counter = 0;
@@ -532,9 +533,10 @@ void ebpf_oomkill_create_apps_charts(struct ebpf_module *em, void *ptr)
533 */
534 void *ebpf_oomkill_thread(void *ptr)
535 {
535 - netdata_thread_cleanup_push(oomkill_cleanup, ptr);
536 -
536 ebpf_module_t *em = (ebpf_module_t *)ptr;
537 +
538 + CLEANUP_FUNCTION_REGISTER(oomkill_cleanup) cleanup_ptr = em;
539 +
540 em->maps = oomkill_maps;
541
542 #define NETDATA_DEFAULT_OOM_DISABLED_MSG "Disabling OOMKILL thread, because"
@@ -578,7 +580,5 @@ void *ebpf_oomkill_thread(void *ptr)
580 endoomkill:
581 ebpf_update_disabled_plugin_stats(em);
582
581 - netdata_thread_cleanup_pop(1);
582 -
583 return NULL;
584 }
src/collectors/ebpf.plugin/ebpf_process.c
+8 -7
@@ -689,9 +689,10 @@ static void ebpf_process_disable_tracepoints()
689 *
690 * @param ptr thread data.
691 */
692 -static void ebpf_process_exit(void *ptr)
692 +static void ebpf_process_exit(void *pptr)
693 {
694 - ebpf_module_t *em = (ebpf_module_t *)ptr;
694 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
695 + if(!em) return;
696
697 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
698 pthread_mutex_lock(&lock);
@@ -1135,10 +1136,10 @@ static void process_collector(ebpf_module_t *em)
1136 uint32_t lifetime = em->lifetime;
1137 netdata_idx_t *stats = em->hash_table_stats;
1138 memset(stats, 0, sizeof(em->hash_table_stats));
1138 - while (!ebpf_plugin_exit && running_time < lifetime) {
1139 + while (!ebpf_plugin_stop() && running_time < lifetime) {
1140 usec_t dt = heartbeat_next(&hb, USEC_PER_SEC);
1141 (void)dt;
1141 - if (ebpf_plugin_exit)
1142 + if (ebpf_plugin_stop())
1143 break;
1144
1145 if (++counter == update_every) {
@@ -1279,9 +1280,10 @@ static int ebpf_process_enable_tracepoints()
1280 */
1281 void *ebpf_process_thread(void *ptr)
1282 {
1282 - netdata_thread_cleanup_push(ebpf_process_exit, ptr);
1283 -
1283 ebpf_module_t *em = (ebpf_module_t *)ptr;
1284 +
1285 + CLEANUP_FUNCTION_REGISTER(ebpf_process_exit) cleanup_ptr = em;
1286 +
1287 em->maps = process_maps;
1288
1289 pthread_mutex_lock(&ebpf_exit_cleanup);
@@ -1322,6 +1324,5 @@ void *ebpf_process_thread(void *ptr)
1324 ebpf_update_disabled_plugin_stats(em);
1325 pthread_mutex_unlock(&ebpf_exit_cleanup);
1326
1325 - netdata_thread_cleanup_pop(1);
1327 return NULL;
1328 }
src/collectors/ebpf.plugin/ebpf_shm.c
+12 -19
@@ -448,12 +448,13 @@ static void ebpf_obsolete_shm_global(ebpf_module_t *em)
448 *
449 * @param ptr thread data.
450 */
451 -static void ebpf_shm_exit(void *ptr)
451 +static void ebpf_shm_exit(void *pptr)
452 {
453 - ebpf_module_t *em = (ebpf_module_t *)ptr;
453 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
454 + if(!em) return;
455
456 if (ebpf_read_shm.thread)
456 - netdata_thread_cancel(*ebpf_read_shm.thread);
457 + nd_thread_signal_cancel(ebpf_read_shm.thread);
458
459 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
460 pthread_mutex_lock(&lock);
@@ -1066,13 +1067,11 @@ void *ebpf_read_shm_thread(void *ptr)
1067 uint32_t running_time = 0;
1068 usec_t period = update_every * USEC_PER_SEC;
1069 int max_period = update_every * EBPF_CLEANUP_FACTOR;
1069 - while (!ebpf_plugin_exit && running_time < lifetime) {
1070 + while (!ebpf_plugin_stop() && running_time < lifetime) {
1071 (void)heartbeat_next(&hb, period);
1071 - if (ebpf_plugin_exit || ++counter != update_every)
1072 + if (ebpf_plugin_stop() || ++counter != update_every)
1073 continue;
1074
1074 - netdata_thread_disable_cancelability();
1075 -
1075 pthread_mutex_lock(&collect_data_mutex);
1076 ebpf_read_shm_apps_table(maps_per_core, max_period);
1077 ebpf_shm_resume_apps_data();
@@ -1088,7 +1087,6 @@ void *ebpf_read_shm_thread(void *ptr)
1087
1088 em->running_time = running_time;
1089 pthread_mutex_unlock(&ebpf_exit_cleanup);
1091 - netdata_thread_enable_cancelability();
1090 }
1091
1092 return NULL;
@@ -1109,9 +1107,9 @@ static void shm_collector(ebpf_module_t *em)
1107 uint32_t lifetime = em->lifetime;
1108 netdata_idx_t *stats = em->hash_table_stats;
1109 memset(stats, 0, sizeof(em->hash_table_stats));
1112 - while (!ebpf_plugin_exit && running_time < lifetime) {
1110 + while (!ebpf_plugin_stop() && running_time < lifetime) {
1111 (void)heartbeat_next(&hb, USEC_PER_SEC);
1114 - if (ebpf_plugin_exit || ++counter != update_every)
1112 + if (ebpf_plugin_stop() || ++counter != update_every)
1113 continue;
1114
1115 counter = 0;
@@ -1327,9 +1325,10 @@ static int ebpf_shm_load_bpf(ebpf_module_t *em)
1325 */
1326 void *ebpf_shm_thread(void *ptr)
1327 {
1330 - netdata_thread_cleanup_push(ebpf_shm_exit, ptr);
1331 -
1328 ebpf_module_t *em = (ebpf_module_t *)ptr;
1329 +
1330 + CLEANUP_FUNCTION_REGISTER(ebpf_shm_exit) cleanup_ptr = em;
1331 +
1332 em->maps = shm_maps;
1333
1334 ebpf_update_pid_table(&shm_maps[NETDATA_PID_SHM_TABLE], em);
@@ -1364,18 +1363,12 @@ void *ebpf_shm_thread(void *ptr)
1363 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1364 pthread_mutex_unlock(&lock);
1365
1367 - ebpf_read_shm.thread = mallocz(sizeof(netdata_thread_t));
1368 - netdata_thread_create(ebpf_read_shm.thread,
1369 - ebpf_read_shm.name,
1370 - NETDATA_THREAD_OPTION_DEFAULT,
1371 - ebpf_read_shm_thread,
1372 - em);
1366 + ebpf_read_shm.thread = nd_thread_create(ebpf_read_shm.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_read_shm_thread, em);
1367
1368 shm_collector(em);
1369
1370 endshm:
1371 ebpf_update_disabled_plugin_stats(em);
1372
1379 - netdata_thread_cleanup_pop(1);
1373 return NULL;
1374 }
src/collectors/ebpf.plugin/ebpf_socket.c
+13 -19
@@ -881,12 +881,13 @@ static void ebpf_socket_obsolete_global_charts(ebpf_module_t *em)
881 *
882 * @param ptr thread data.
883 */
884 -static void ebpf_socket_exit(void *ptr)
884 +static void ebpf_socket_exit(void *pptr)
885 {
886 - ebpf_module_t *em = (ebpf_module_t *)ptr;
886 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
887 + if(!em) return;
888
889 if (ebpf_read_socket.thread)
889 - netdata_thread_cancel(*ebpf_read_socket.thread);
890 + nd_thread_signal_cancel(ebpf_read_socket.thread);
891
892 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
893 pthread_mutex_lock(&lock);
@@ -1678,7 +1679,6 @@ static void ebpf_socket_translate(netdata_socket_plus_t *dst, netdata_socket_idx
1679 */
1680 static void ebpf_update_array_vectors(ebpf_module_t *em)
1681 {
1681 - netdata_thread_disable_cancelability();
1682 netdata_socket_idx_t key = {};
1683 netdata_socket_idx_t next_key = {};
1684
@@ -1776,7 +1776,6 @@ end_socket_loop:
1776 memset(values, 0, length);
1777 memcpy(&key, &next_key, sizeof(key));
1778 }
1779 - netdata_thread_enable_cancelability();
1779 }
1780 /**
1781 * Resume apps data
@@ -1838,9 +1837,9 @@ void *ebpf_read_socket_thread(void *ptr)
1837 uint32_t running_time = 0;
1838 uint32_t lifetime = em->lifetime;
1839 usec_t period = update_every * USEC_PER_SEC;
1841 - while (!ebpf_plugin_exit && running_time < lifetime) {
1840 + while (!ebpf_plugin_stop() && running_time < lifetime) {
1841 (void)heartbeat_next(&hb, period);
1843 - if (ebpf_plugin_exit || ++counter != update_every)
1842 + if (ebpf_plugin_stop() || ++counter != update_every)
1843 continue;
1844
1845 pthread_mutex_lock(&collect_data_mutex);
@@ -2653,9 +2652,9 @@ static void socket_collector(ebpf_module_t *em)
2652 uint32_t lifetime = em->lifetime;
2653 netdata_idx_t *stats = em->hash_table_stats;
2654 memset(stats, 0, sizeof(em->hash_table_stats));
2656 - while (!ebpf_plugin_exit && running_time < lifetime) {
2655 + while (!ebpf_plugin_stop() && running_time < lifetime) {
2656 (void)heartbeat_next(&hb, USEC_PER_SEC);
2658 - if (ebpf_plugin_exit || ++counter != update_every)
2657 + if (ebpf_plugin_stop() || ++counter != update_every)
2658 continue;
2659
2660 counter = 0;
@@ -2876,9 +2875,10 @@ static int ebpf_socket_load_bpf(ebpf_module_t *em)
2875 */
2876 void *ebpf_socket_thread(void *ptr)
2877 {
2879 - netdata_thread_cleanup_push(ebpf_socket_exit, ptr);
2880 -
2878 ebpf_module_t *em = (ebpf_module_t *)ptr;
2879 +
2880 + CLEANUP_FUNCTION_REGISTER(ebpf_socket_exit) cleanup_ptr = em;
2881 +
2882 if (em->enabled > NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
2883 collector_error("There is already a thread %s running", em->info.thread_name);
2884 return NULL;
@@ -2918,12 +2918,8 @@ void *ebpf_socket_thread(void *ptr)
2918 socket_aggregated_data, socket_publish_aggregated, socket_dimension_names, socket_id_names,
2919 algorithms, NETDATA_MAX_SOCKET_VECTOR);
2920
2921 - ebpf_read_socket.thread = mallocz(sizeof(netdata_thread_t));
2922 - netdata_thread_create(ebpf_read_socket.thread,
2923 - ebpf_read_socket.name,
2924 - NETDATA_THREAD_OPTION_DEFAULT,
2925 - ebpf_read_socket_thread,
2926 - em);
2921 + ebpf_read_socket.thread = nd_thread_create(ebpf_read_socket.name, NETDATA_THREAD_OPTION_DEFAULT,
2922 + ebpf_read_socket_thread, em);
2923
2924 pthread_mutex_lock(&lock);
2925 ebpf_socket_create_global_charts(em);
@@ -2937,7 +2933,5 @@ void *ebpf_socket_thread(void *ptr)
2933
2934 endsocket:
2935 ebpf_update_disabled_plugin_stats(em);
2940 -
2941 - netdata_thread_cleanup_pop(1);
2936 return NULL;
2937 }
src/collectors/ebpf.plugin/ebpf_softirq.c
+8 -8
@@ -88,9 +88,10 @@ static void ebpf_obsolete_softirq_global(ebpf_module_t *em)
88 *
89 * @param ptr thread data.
90 */
91 -static void softirq_cleanup(void *ptr)
91 +static void softirq_cleanup(void *pptr)
92 {
93 - ebpf_module_t *em = (ebpf_module_t *)ptr;
93 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
94 + if(!em) return;
95
96 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
97 pthread_mutex_lock(&lock);
@@ -219,9 +220,9 @@ static void softirq_collector(ebpf_module_t *em)
220 //This will be cancelled by its parent
221 uint32_t running_time = 0;
222 uint32_t lifetime = em->lifetime;
222 - while (!ebpf_plugin_exit && running_time < lifetime) {
223 + while (!ebpf_plugin_stop() && running_time < lifetime) {
224 (void)heartbeat_next(&hb, USEC_PER_SEC);
224 - if (ebpf_plugin_exit || ++counter != update_every)
225 + if (ebpf_plugin_stop() || ++counter != update_every)
226 continue;
227
228 counter = 0;
@@ -258,9 +259,10 @@ static void softirq_collector(ebpf_module_t *em)
259 */
260 void *ebpf_softirq_thread(void *ptr)
261 {
261 - netdata_thread_cleanup_push(softirq_cleanup, ptr);
262 + ebpf_module_t *em = ptr;
263 +
264 + CLEANUP_FUNCTION_REGISTER(softirq_cleanup) cleanup_ptr = em;
265
263 - ebpf_module_t *em = (ebpf_module_t *)ptr;
266 em->maps = softirq_maps;
267
268 if (ebpf_enable_tracepoints(softirq_tracepoints) == 0) {
@@ -280,7 +282,5 @@ void *ebpf_softirq_thread(void *ptr)
282 endsoftirq:
283 ebpf_update_disabled_plugin_stats(em);
284
283 - netdata_thread_cleanup_pop(1);
284 -
285 return NULL;
286 }
src/collectors/ebpf.plugin/ebpf_swap.c
+10 -17
@@ -394,7 +394,7 @@ static void ebpf_swap_exit(void *ptr)
394 ebpf_module_t *em = (ebpf_module_t *)ptr;
395
396 if (ebpf_read_swap.thread)
397 - netdata_thread_cancel(*ebpf_read_swap.thread);
397 + nd_thread_signal_cancel(ebpf_read_swap.thread);
398
399 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
400 pthread_mutex_lock(&lock);
@@ -595,13 +595,11 @@ void *ebpf_read_swap_thread(void *ptr)
595 usec_t period = update_every * USEC_PER_SEC;
596 int max_period = update_every * EBPF_CLEANUP_FACTOR;
597
598 - while (!ebpf_plugin_exit && running_time < lifetime) {
598 + while (!ebpf_plugin_stop() && running_time < lifetime) {
599 (void)heartbeat_next(&hb, period);
600 - if (ebpf_plugin_exit || ++counter != update_every)
600 + if (ebpf_plugin_stop() || ++counter != update_every)
601 continue;
602
603 - netdata_thread_disable_cancelability();
604 -
603 pthread_mutex_lock(&collect_data_mutex);
604 ebpf_read_swap_apps_table(maps_per_core, max_period);
605 ebpf_swap_resume_apps_data();
@@ -617,7 +615,6 @@ void *ebpf_read_swap_thread(void *ptr)
615
616 em->running_time = running_time;
617 pthread_mutex_unlock(&ebpf_exit_cleanup);
620 - netdata_thread_enable_cancelability();
618 }
619
620 return NULL;
@@ -920,9 +917,9 @@ static void swap_collector(ebpf_module_t *em)
917 uint32_t lifetime = em->lifetime;
918 netdata_idx_t *stats = em->hash_table_stats;
919 memset(stats, 0, sizeof(em->hash_table_stats));
923 - while (!ebpf_plugin_exit && running_time < lifetime) {
920 + while (!ebpf_plugin_stop() && running_time < lifetime) {
921 (void)heartbeat_next(&hb, USEC_PER_SEC);
925 - if (ebpf_plugin_exit || ++counter != update_every)
922 + if (ebpf_plugin_stop() || ++counter != update_every)
923 continue;
924
925 counter = 0;
@@ -1131,9 +1128,10 @@ static int ebpf_swap_set_internal_value()
1128 */
1129 void *ebpf_swap_thread(void *ptr)
1130 {
1134 - netdata_thread_cleanup_push(ebpf_swap_exit, ptr);
1135 -
1131 ebpf_module_t *em = (ebpf_module_t *)ptr;
1132 +
1133 + CLEANUP_FUNCTION_REGISTER(ebpf_swap_exit) cleanup_ptr = em;
1134 +
1135 em->maps = swap_maps;
1136
1137 ebpf_update_pid_table(&swap_maps[NETDATA_PID_SWAP_TABLE], em);
@@ -1161,18 +1159,13 @@ void *ebpf_swap_thread(void *ptr)
1159 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1160 pthread_mutex_unlock(&lock);
1161
1164 - ebpf_read_swap.thread = mallocz(sizeof(netdata_thread_t));
1165 - netdata_thread_create(ebpf_read_swap.thread,
1166 - ebpf_read_swap.name,
1167 - NETDATA_THREAD_OPTION_DEFAULT,
1168 - ebpf_read_swap_thread,
1169 - em);
1162 + ebpf_read_swap.thread = nd_thread_create(ebpf_read_swap.name, NETDATA_THREAD_OPTION_DEFAULT,
1163 + ebpf_read_swap_thread, em);
1164
1165 swap_collector(em);
1166
1167 endswap:
1168 ebpf_update_disabled_plugin_stats(em);
1169
1176 - netdata_thread_cleanup_pop(1);
1170 return NULL;
1171 }
src/collectors/ebpf.plugin/ebpf_sync.c
+7 -7
@@ -351,9 +351,10 @@ static void ebpf_obsolete_sync_global(ebpf_module_t *em)
351 *
352 * @param ptr thread data.
353 */
354 -static void ebpf_sync_exit(void *ptr)
354 +static void ebpf_sync_exit(void *pptr)
355 {
356 - ebpf_module_t *em = (ebpf_module_t *)ptr;
356 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
357 + if(!em) return;
358
359 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
360 pthread_mutex_lock(&lock);
@@ -564,9 +565,9 @@ static void sync_collector(ebpf_module_t *em)
565 int maps_per_core = em->maps_per_core;
566 uint32_t running_time = 0;
567 uint32_t lifetime = em->lifetime;
567 - while (!ebpf_plugin_exit && running_time < lifetime) {
568 + while (!ebpf_plugin_stop() && running_time < lifetime) {
569 (void)heartbeat_next(&hb, USEC_PER_SEC);
569 - if (ebpf_plugin_exit || ++counter != update_every)
570 + if (ebpf_plugin_stop() || ++counter != update_every)
571 continue;
572
573 counter = 0;
@@ -703,10 +704,10 @@ static void ebpf_set_sync_maps()
704 */
705 void *ebpf_sync_thread(void *ptr)
706 {
706 - netdata_thread_cleanup_push(ebpf_sync_exit, ptr);
707 -
707 ebpf_module_t *em = (ebpf_module_t *)ptr;
708
709 + CLEANUP_FUNCTION_REGISTER(ebpf_sync_exit) cleanup_ptr = em;
710 +
711 ebpf_set_sync_maps();
712 ebpf_sync_parse_syscalls();
713
@@ -734,6 +735,5 @@ void *ebpf_sync_thread(void *ptr)
735 endsync:
736 ebpf_update_disabled_plugin_stats(em);
737
737 - netdata_thread_cleanup_pop(1);
738 return NULL;
739 }
src/collectors/ebpf.plugin/ebpf_vfs.c
+12 -19
@@ -881,12 +881,13 @@ static void ebpf_obsolete_vfs_global(ebpf_module_t *em)
881 *
882 * @param ptr thread data.
883 **/
884 -static void ebpf_vfs_exit(void *ptr)
884 +static void ebpf_vfs_exit(void *pptr)
885 {
886 - ebpf_module_t *em = (ebpf_module_t *)ptr;
886 + ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
887 + if(!em) return;
888
889 if (ebpf_read_vfs.thread)
889 - netdata_thread_cancel(*ebpf_read_vfs.thread);
890 + nd_thread_signal_cancel(ebpf_read_vfs.thread);
891
892 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
893 pthread_mutex_lock(&lock);
@@ -2049,13 +2050,11 @@ void *ebpf_read_vfs_thread(void *ptr)
2050 uint32_t running_time = 0;
2051 usec_t period = update_every * USEC_PER_SEC;
2052 int max_period = update_every * EBPF_CLEANUP_FACTOR;
2052 - while (!ebpf_plugin_exit && running_time < lifetime) {
2053 + while (!ebpf_plugin_stop() && running_time < lifetime) {
2054 (void)heartbeat_next(&hb, period);
2054 - if (ebpf_plugin_exit || ++counter != update_every)
2055 + if (ebpf_plugin_stop() || ++counter != update_every)
2056 continue;
2057
2057 - netdata_thread_disable_cancelability();
2058 -
2058 pthread_mutex_lock(&collect_data_mutex);
2059 ebpf_vfs_read_apps(maps_per_core, max_period);
2060 ebpf_vfs_resume_apps_data();
@@ -2071,7 +2070,6 @@ void *ebpf_read_vfs_thread(void *ptr)
2070
2071 em->running_time = running_time;
2072 pthread_mutex_unlock(&ebpf_exit_cleanup);
2074 - netdata_thread_enable_cancelability();
2073 }
2074
2075 return NULL;
@@ -2095,9 +2093,9 @@ static void vfs_collector(ebpf_module_t *em)
2093 uint32_t lifetime = em->lifetime;
2094 netdata_idx_t *stats = em->hash_table_stats;
2095 memset(stats, 0, sizeof(em->hash_table_stats));
2098 - while (!ebpf_plugin_exit && running_time < lifetime) {
2096 + while (!ebpf_plugin_stop() && running_time < lifetime) {
2097 (void)heartbeat_next(&hb, USEC_PER_SEC);
2100 - if (ebpf_plugin_exit || ++counter != update_every)
2098 + if (ebpf_plugin_stop() || ++counter != update_every)
2099 continue;
2100
2101 counter = 0;
@@ -2606,9 +2604,10 @@ static int ebpf_vfs_load_bpf(ebpf_module_t *em)
2604 */
2605 void *ebpf_vfs_thread(void *ptr)
2606 {
2609 - netdata_thread_cleanup_push(ebpf_vfs_exit, ptr);
2610 -
2607 ebpf_module_t *em = (ebpf_module_t *)ptr;
2608 +
2609 + CLEANUP_FUNCTION_REGISTER(ebpf_vfs_exit) cleanup_ptr = em;
2610 +
2611 em->maps = vfs_maps;
2612
2613 ebpf_update_pid_table(&vfs_maps[NETDATA_VFS_PID], em);
@@ -2637,18 +2636,12 @@ void *ebpf_vfs_thread(void *ptr)
2636
2637 pthread_mutex_unlock(&lock);
2638
2640 - ebpf_read_vfs.thread = mallocz(sizeof(netdata_thread_t));
2641 - netdata_thread_create(ebpf_read_vfs.thread,
2642 - ebpf_read_vfs.name,
2643 - NETDATA_THREAD_OPTION_DEFAULT,
2644 - ebpf_read_vfs_thread,
2645 - em);
2639 + ebpf_read_vfs.thread = nd_thread_create(ebpf_read_vfs.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_read_vfs_thread, em);
2640
2641 vfs_collector(em);
2642
2643 endvfs:
2644 ebpf_update_disabled_plugin_stats(em);
2645
2652 - netdata_thread_cleanup_pop(1);
2646 return NULL;
2647 }
src/collectors/freebsd.plugin/plugin_freebsd.c
+6 -6
@@ -71,23 +71,24 @@ static struct freebsd_module {
71 #error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 33
72 #endif
73
74 -static void freebsd_main_cleanup(void *ptr)
74 +static void freebsd_main_cleanup(void *pptr)
75 {
76 - worker_unregister();
76 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
77 + if(!static_thread) return;
78
78 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
79 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
80
81 collector_info("cleaning up...");
82 + worker_unregister();
83
84 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
85 }
86
87 void *freebsd_main(void *ptr)
88 {
88 - worker_register("FREEBSD");
89 + CLEANUP_FUNCTION_REGISTER(freebsd_main_cleanup) cleanup_ptr = ptr;
90
90 - netdata_thread_cleanup_push(freebsd_main_cleanup, ptr);
91 + worker_register("FREEBSD");
92
93 // initialize FreeBSD plugin
94 if (freebsd_plugin_init())
@@ -131,6 +132,5 @@ void *freebsd_main(void *ptr)
132 }
133 }
134
134 - netdata_thread_cleanup_pop(1);
135 return NULL;
136 }
src/collectors/freeipmi.plugin/freeipmi_plugin.c
+2 -5
@@ -1977,12 +1977,9 @@ int main (int argc, char **argv) {
1977 },
1978 };
1979
1980 - netdata_thread_t sensors_thread = 0, sel_thread = 0;
1981 -
1982 - netdata_thread_create(&sensors_thread, "IPMI[sensors]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sensors_data);
1983 -
1980 + nd_thread_create("IPMI[sensors]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sensors_data);
1981 if(netdata_do_sel)
1985 - netdata_thread_create(&sel_thread, "IPMI[sel]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sel_data);
1982 + nd_thread_create("IPMI[sel]", NETDATA_THREAD_OPTION_DONT_LOG, netdata_ipmi_collection_thread, &sel_data);
1983
1984 // ------------------------------------------------------------------------
1985 // the main loop
src/collectors/idlejitter.plugin/plugin_idlejitter.c
+6 -6
@@ -4,23 +4,24 @@
4
5 #define CPU_IDLEJITTER_SLEEP_TIME_MS 20
6
7 -static void cpuidlejitter_main_cleanup(void *ptr) {
8 - worker_unregister();
7 +static void cpuidlejitter_main_cleanup(void *pptr) {
8 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
9 + if(!pptr) return;
10
10 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
11 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
12
13 collector_info("cleaning up...");
14 + worker_unregister();
15
16 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
17 }
18
19 void *cpuidlejitter_main(void *ptr) {
20 + CLEANUP_FUNCTION_REGISTER(cpuidlejitter_main_cleanup) cleanup_ptr = ptr;
21 +
22 worker_register("IDLEJITTER");
23 worker_register_job_name(0, "measurements");
24
22 - netdata_thread_cleanup_push(cpuidlejitter_main_cleanup, ptr);
23 -
25 usec_t sleep_ut = config_get_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS) * USEC_PER_MS;
26 if(sleep_ut <= 0) {
27 config_set_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
@@ -85,7 +86,6 @@ void *cpuidlejitter_main(void *ptr) {
86 }
87 }
88
88 - netdata_thread_cleanup_pop(1);
89 return NULL;
90 }
91
src/collectors/log2journal/log2journal-yaml.c
+1 -1
@@ -48,7 +48,7 @@ static const char *yaml_event_name(yaml_event_type_t type) {
48 }
49
50 #define yaml_error(parser, event, fmt, args...) yaml_error_with_trace(parser, event, __LINE__, __FUNCTION__, __FILE__, fmt, ##args)
51 -static void yaml_error_with_trace(yaml_parser_t *parser, yaml_event_t *event, size_t line, const char *function, const char *file, const char *format, ...) __attribute__ ((format(__printf__, 6, 7)));
51 +static void yaml_error_with_trace(yaml_parser_t *parser, yaml_event_t *event, size_t line, const char *function, const char *file, const char *format, ...) PRINTFLIKE(6, 7);
52 static void yaml_error_with_trace(yaml_parser_t *parser, yaml_event_t *event, size_t line, const char *function, const char *file, const char *format, ...) {
53 char buf[1024] = ""; // Initialize buf to an empty string
54 const char *type = "";
src/collectors/log2journal/log2journal.c
+1 -1
@@ -277,7 +277,7 @@ static inline void send_key_value_constant(LOG_JOB *jb __maybe_unused, HASHED_KE
277 // fprintf(stderr, "SET %s=%.*s\n", ht_key->key, (int)ht_key->value.len, ht_key->value.txt);
278 }
279
280 -static inline void send_key_value_error(LOG_JOB *jb, HASHED_KEY *key, const char *format, ...) __attribute__ ((format(__printf__, 3, 4)));
280 +static inline void send_key_value_error(LOG_JOB *jb, HASHED_KEY *key, const char *format, ...) PRINTFLIKE(3, 4);
281 static inline void send_key_value_error(LOG_JOB *jb, HASHED_KEY *key, const char *format, ...) {
282 HASHED_KEY *ht_key = get_key_from_hashtable(jb, key);
283
src/collectors/log2journal/log2journal.h
+24 -1
@@ -17,11 +17,34 @@
17 #include <stdarg.h>
18 #include <assert.h>
19
20 +// ----------------------------------------------------------------------------
21 +// compatibility
22 +
23 +#ifndef HAVE_STRNDUP
24 +// strndup() is not available on Windows
25 +static inline char *os_strndup( const char *s1, size_t n)
26 +{
27 + char *copy= (char*)malloc( n+1 );
28 + memcpy( copy, s1, n );
29 + copy[n] = 0;
30 + return copy;
31 +};
32 +#define strndup(s, n) os_strndup(s, n)
33 +#endif
34 +
35 +#if defined(HAVE_FUNC_ATTRIBUTE_FORMAT) && !defined(COMPILED_FOR_MACOS)
36 +#define PRINTFLIKE(f, a) __attribute__ ((format(gnu_printf, f, a)))
37 +#elif defined(HAVE_FUNC_ATTRIBUTE_FORMAT)
38 +#define PRINTFLIKE(f, a) __attribute__ ((format(printf, f, a)))
39 +#else
40 +#define PRINTFLIKE(f, a)
41 +#endif
42 +
43 // ----------------------------------------------------------------------------
44 // logging
45
46 // enable the compiler to check for printf like errors on our log2stderr() function
24 -static inline void log2stderr(const char *format, ...) __attribute__ ((format(__printf__, 1, 2)));
47 +static inline void log2stderr(const char *format, ...) PRINTFLIKE(1, 2);
48 static inline void log2stderr(const char *format, ...) {
49 va_list args;
50 va_start(args, format);
src/collectors/macos.plugin/plugin_macos.c
+6 -6
@@ -25,23 +25,24 @@ static struct macos_module {
25 #error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 3
26 #endif
27
28 -static void macos_main_cleanup(void *ptr)
28 +static void macos_main_cleanup(void *pptr)
29 {
30 - worker_unregister();
30 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
31 + if(!static_thread) return;
32
32 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
33 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
34
35 collector_info("cleaning up...");
36 + worker_unregister();
37
38 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
39 }
40
41 void *macos_main(void *ptr)
42 {
42 - worker_register("MACOS");
43 + CLEANUP_FUNCTION_REGISTER(macos_main_cleanup) cleanup_ptr = ptr;
44
44 - netdata_thread_cleanup_push(macos_main_cleanup, ptr);
45 + worker_register("MACOS");
46
47 // check the enabled status for each module
48 for (int i = 0; macos_modules[i].name; i++) {
@@ -76,6 +77,5 @@ void *macos_main(void *ptr)
77 }
78 }
79
79 - netdata_thread_cleanup_pop(1);
80 return NULL;
81 }
src/collectors/network-viewer.plugin/network-viewer.c
+1 -1
@@ -739,7 +739,7 @@ close_and_send:
739
740 int main(int argc __maybe_unused, char **argv __maybe_unused) {
741 clocks_init();
742 - netdata_thread_set_tag("NETWORK-VIEWER");
742 + nd_thread_tag_set("NETWORK-VIEWER");
743 nd_log_initialize_for_external_plugins("network-viewer.plugin");
744
745 netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
src/collectors/perf.plugin/perf_plugin.c
+1 -1
@@ -246,7 +246,7 @@ static int perf_init() {
246 struct perf_event *current_event = NULL;
247 unsigned long flags = 0;
248
249 - number_of_cpus = (int)get_system_cpus();
249 + number_of_cpus = (int)os_get_system_cpus();
250
251 // initialize all perf event file descriptors
252 for(current_event = &perf_events[0]; current_event->id != EV_ID_END; current_event++) {
src/collectors/plugins.d/ndsudo.c
+2 -2
@@ -332,8 +332,8 @@ int main(int argc, char *argv[]) {
332 return 3;
333 }
334
335 - char new_path[] = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin";
336 - setenv("PATH", new_path, 1);
335 + char new_path[] = "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin";
336 + putenv(new_path);
337
338 bool found = false;
339 char filename[FILENAME_MAX];
src/collectors/plugins.d/plugins_d.c
+71 -64
@@ -6,6 +6,16 @@
6 char *plugin_directories[PLUGINSD_MAX_DIRECTORIES] = { [0] = PLUGINS_DIR, };
7 struct plugind *pluginsd_root = NULL;
8
9 +static inline void pluginsd_sleep(const int seconds) {
10 + int timeout_ms = seconds * 1000;
11 + int waited_ms = 0;
12 + while(waited_ms < timeout_ms) {
13 + if(!service_running(SERVICE_COLLECTORS)) break;
14 + sleep_usec(ND_CHECK_CANCELLABILITY_WHILE_WAITING_EVERY_MS * USEC_PER_MS);
15 + waited_ms += ND_CHECK_CANCELLABILITY_WHILE_WAITING_EVERY_MS;
16 + }
17 +}
18 +
19 inline size_t pluginsd_initialize_plugin_directories()
20 {
21 char plugins_dirs[(FILENAME_MAX * 2) + 1];
@@ -47,8 +57,9 @@ static inline bool plugin_is_running(struct plugind *cd) {
57 return ret;
58 }
59
50 -static void pluginsd_worker_thread_cleanup(void *arg) {
51 - struct plugind *cd = (struct plugind *)arg;
60 +static void pluginsd_worker_thread_cleanup(void *pptr) {
61 + struct plugind *cd = CLEANUP_FUNCTION_GET_PTR(pptr);
62 + if(!cd) return;
63
64 worker_unregister();
65
@@ -79,7 +90,7 @@ static void pluginsd_worker_thread_cleanup(void *arg) {
90 #define SERIAL_FAILURES_THRESHOLD 10
91 static void pluginsd_worker_thread_handle_success(struct plugind *cd) {
92 if (likely(cd->successful_collections)) {
82 - sleep((unsigned int)cd->update_every);
93 + pluginsd_sleep(cd->update_every);
94 return;
95 }
96
@@ -88,7 +99,7 @@ static void pluginsd_worker_thread_handle_success(struct plugind *cd) {
99 rrdhost_hostname(cd->host), cd->fullfilename, cd->unsafe.pid,
100 plugin_is_enabled(cd) ? "Waiting a bit before starting it again." : "Will not start it again - it is now disabled.");
101
91 - sleep((unsigned int)(cd->update_every * 10));
102 + pluginsd_sleep(cd->update_every * 10);
103 return;
104 }
105
@@ -121,7 +132,8 @@ static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_r
132 netdata_log_error("PLUGINSD: 'host:%s', '%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times). %s",
133 rrdhost_hostname(cd->host), cd->fullfilename, cd->unsafe.pid, worker_ret_code, cd->successful_collections,
134 plugin_is_enabled(cd) ? "Waiting a bit before starting it again." : "Will not start it again - it is disabled.");
124 - sleep((unsigned int)(cd->update_every * 10));
135 +
136 + pluginsd_sleep(cd->update_every * 10);
137 return;
138 }
139
@@ -138,73 +150,73 @@ static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_r
150 #undef SERIAL_FAILURES_THRESHOLD
151
152 static void *pluginsd_worker_thread(void *arg) {
153 + struct plugind *cd = (struct plugind *) arg;
154 + CLEANUP_FUNCTION_REGISTER(pluginsd_worker_thread_cleanup) cleanup_ptr = cd;
155 +
156 worker_register("PLUGINSD");
157
143 - netdata_thread_cleanup_push(pluginsd_worker_thread_cleanup, arg)
144 - {
145 - struct plugind *cd = (struct plugind *) arg;
146 - plugin_set_running(cd);
158 + plugin_set_running(cd);
159
148 - size_t count = 0;
160 + size_t count = 0;
161
150 - while(service_running(SERVICE_COLLECTORS)) {
151 - FILE *fp_child_input = NULL;
152 - FILE *fp_child_output = netdata_popen(cd->cmd, &cd->unsafe.pid, &fp_child_input);
162 + while(service_running(SERVICE_COLLECTORS)) {
163 + FILE *fp_child_input = NULL;
164 + FILE *fp_child_output = netdata_popen(cd->cmd, &cd->unsafe.pid, &fp_child_input);
165
154 - if(unlikely(!fp_child_input || !fp_child_output)) {
155 - netdata_log_error("PLUGINSD: 'host:%s', cannot popen(\"%s\", \"r\").",
156 - rrdhost_hostname(cd->host), cd->cmd);
157 - break;
158 - }
166 + if(unlikely(!fp_child_input || !fp_child_output)) {
167 + netdata_log_error("PLUGINSD: 'host:%s', cannot popen(\"%s\", \"r\").",
168 + rrdhost_hostname(cd->host), cd->cmd);
169 + break;
170 + }
171
160 - nd_log(NDLS_DAEMON, NDLP_DEBUG,
161 - "PLUGINSD: 'host:%s' connected to '%s' running on pid %d",
162 - rrdhost_hostname(cd->host),
163 - cd->fullfilename, cd->unsafe.pid);
172 + nd_log(NDLS_DAEMON, NDLP_DEBUG,
173 + "PLUGINSD: 'host:%s' connected to '%s' running on pid %d",
174 + rrdhost_hostname(cd->host),
175 + cd->fullfilename, cd->unsafe.pid);
176
165 - const char *plugin = strrchr(cd->fullfilename, '/');
166 - if(plugin)
167 - plugin++;
168 - else
169 - plugin = cd->fullfilename;
177 + const char *plugin = strrchr(cd->fullfilename, '/');
178 + if(plugin)
179 + plugin++;
180 + else
181 + plugin = cd->fullfilename;
182
171 - char module[100];
172 - snprintfz(module, sizeof(module), "plugins.d[%s]", plugin);
173 - ND_LOG_STACK lgs[] = {
174 - ND_LOG_FIELD_TXT(NDF_MODULE, module),
175 - ND_LOG_FIELD_TXT(NDF_NIDL_NODE, rrdhost_hostname(cd->host)),
176 - ND_LOG_FIELD_TXT(NDF_SRC_TRANSPORT, "pluginsd"),
177 - ND_LOG_FIELD_END(),
178 - };
179 - ND_LOG_STACK_PUSH(lgs);
183 + char module[100];
184 + snprintfz(module, sizeof(module), "plugins.d[%s]", plugin);
185 + ND_LOG_STACK lgs[] = {
186 + ND_LOG_FIELD_TXT(NDF_MODULE, module),
187 + ND_LOG_FIELD_TXT(NDF_NIDL_NODE, rrdhost_hostname(cd->host)),
188 + ND_LOG_FIELD_TXT(NDF_SRC_TRANSPORT, "pluginsd"),
189 + ND_LOG_FIELD_END(),
190 + };
191 + ND_LOG_STACK_PUSH(lgs);
192
181 - count = pluginsd_process(cd->host, cd, fp_child_input, fp_child_output, 0);
193 + count = pluginsd_process(cd->host, cd, fp_child_input, fp_child_output, 0);
194
183 - nd_log(NDLS_DAEMON, NDLP_DEBUG,
184 - "PLUGINSD: 'host:%s', '%s' (pid %d) disconnected after %zu successful data collections (ENDs).",
185 - rrdhost_hostname(cd->host), cd->fullfilename, cd->unsafe.pid, count);
195 + nd_log(NDLS_DAEMON, NDLP_DEBUG,
196 + "PLUGINSD: 'host:%s', '%s' (pid %d) disconnected after %zu successful data collections (ENDs).",
197 + rrdhost_hostname(cd->host), cd->fullfilename, cd->unsafe.pid, count);
198
187 - killpid(cd->unsafe.pid);
199 + killpid(cd->unsafe.pid);
200
189 - int worker_ret_code = netdata_pclose(fp_child_input, fp_child_output, cd->unsafe.pid);
201 + int worker_ret_code = netdata_pclose(fp_child_input, fp_child_output, cd->unsafe.pid);
202
191 - if(likely(worker_ret_code == 0))
192 - pluginsd_worker_thread_handle_success(cd);
193 - else
194 - pluginsd_worker_thread_handle_error(cd, worker_ret_code);
203 + if(likely(worker_ret_code == 0))
204 + pluginsd_worker_thread_handle_success(cd);
205 + else
206 + pluginsd_worker_thread_handle_error(cd, worker_ret_code);
207
196 - cd->unsafe.pid = 0;
208 + cd->unsafe.pid = 0;
209
198 - if(unlikely(!plugin_is_enabled(cd)))
199 - break;
200 - }
210 + if(unlikely(!plugin_is_enabled(cd)))
211 + break;
212 }
202 - netdata_thread_cleanup_pop(1);
213 return NULL;
214 }
215
206 -static void pluginsd_main_cleanup(void *data) {
207 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
216 +static void pluginsd_main_cleanup(void *pptr) {
217 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
218 + if(!static_thread) return;
219 +
220 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
221 netdata_log_info("PLUGINSD: cleaning up...");
222
@@ -215,7 +227,7 @@ static void pluginsd_main_cleanup(void *data) {
227 netdata_log_info("PLUGINSD: 'host:%s', stopping plugin thread: %s",
228 rrdhost_hostname(cd->host), cd->id);
229
218 - netdata_thread_cancel(cd->unsafe.thread);
230 + nd_thread_signal_cancel(cd->unsafe.thread);
231 }
232 spinlock_unlock(&cd->unsafe.spinlock);
233 }
@@ -226,9 +238,8 @@ static void pluginsd_main_cleanup(void *data) {
238 worker_unregister();
239 }
240
229 -void *pluginsd_main(void *ptr)
230 -{
231 - netdata_thread_cleanup_push(pluginsd_main_cleanup, ptr);
241 +void *pluginsd_main(void *ptr) {
242 + CLEANUP_FUNCTION_REGISTER(pluginsd_main_cleanup) cleanup_ptr = ptr;
243
244 int automatic_run = config_get_boolean(CONFIG_SECTION_PLUGINS, "enable running new plugins", 1);
245 int scan_frequency = (int)config_get_number(CONFIG_SECTION_PLUGINS, "check for new plugins every", 60);
@@ -340,11 +351,8 @@ void *pluginsd_main(void *ptr)
351 snprintfz(tag, NETDATA_THREAD_TAG_MAX, "PD[%s]", pluginname);
352
353 // spawn a new thread for it
343 - netdata_thread_create(&cd->unsafe.thread,
344 - tag,
345 - NETDATA_THREAD_OPTION_DEFAULT,
346 - pluginsd_worker_thread,
347 - cd);
354 + cd->unsafe.thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_DEFAULT,
355 + pluginsd_worker_thread, cd);
356 }
357 }
358 }
@@ -352,9 +360,8 @@ void *pluginsd_main(void *ptr)
360 closedir(dir);
361 }
362
355 - sleep((unsigned int)scan_frequency);
363 + pluginsd_sleep(scan_frequency);
364 }
365
358 - netdata_thread_cleanup_pop(1);
366 return NULL;
367 }
src/collectors/plugins.d/plugins_d.h
+2 -2
@@ -33,7 +33,7 @@ struct plugind {
33 SPINLOCK spinlock;
34 bool running; // do not touch this structure after setting this to 1
35 bool enabled; // if this is enabled or not
36 - netdata_thread_t thread;
36 + ND_THREAD *thread;
37 pid_t pid;
38 } unsafe;
39
@@ -46,7 +46,7 @@ struct plugind {
46 extern struct plugind *pluginsd_root;
47
48 size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp_plugin_input, FILE *fp_plugin_output, int trust_durations);
49 -void pluginsd_process_thread_cleanup(void *ptr);
49 +void pluginsd_process_thread_cleanup(void *pptr);
50
51 size_t pluginsd_initialize_plugin_directories();
52
src/collectors/plugins.d/pluginsd_functions.h
+1 -1
@@ -6,7 +6,7 @@
6 #include "pluginsd_internals.h"
7
8 struct inflight_function {
9 - uuid_t transaction;
9 + nd_uuid_t transaction;
10
11 int code;
12 int timeout_s;
src/collectors/plugins.d/pluginsd_internals.h
+1 -1
@@ -88,7 +88,7 @@ static inline void pluginsd_clear_scope_chart(PARSER *parser, const char *keywor
88 static inline bool pluginsd_set_scope_chart(PARSER *parser, RRDSET *st, const char *keyword) {
89 RRDSET *old_st = parser->user.st;
90 pid_t old_collector_tid = (old_st) ? old_st->pluginsd.collector_tid : 0;
91 - pid_t my_collector_tid = gettid();
91 + pid_t my_collector_tid = gettid_cached();
92
93 if(unlikely(old_collector_tid)) {
94 if(old_collector_tid != my_collector_tid) {
src/collectors/plugins.d/pluginsd_parser.c
+40 -44
@@ -121,7 +121,7 @@ static void pluginsd_host_define_cleanup(PARSER *parser) {
121 parser->user.host_define.parsing_host = false;
122 }
123
124 -static inline bool pluginsd_validate_machine_guid(const char *guid, uuid_t *uuid, char *output) {
124 +static inline bool pluginsd_validate_machine_guid(const char *guid, nd_uuid_t *uuid, char *output) {
125 if(uuid_parse(guid, *uuid))
126 return false;
127
@@ -231,7 +231,7 @@ static inline PARSER_RC pluginsd_host(char **words, size_t num_words, PARSER *pa
231 return PARSER_RC_OK;
232 }
233
234 - uuid_t uuid;
234 + nd_uuid_t uuid;
235 char uuid_str[UUID_STR_LEN];
236 if(!pluginsd_validate_machine_guid(guid, &uuid, uuid_str))
237 return PLUGINSD_DISABLE_PLUGIN(parser, PLUGINSD_KEYWORD_HOST, "cannot parse MACHINE_GUID - is it a valid UUID?");
@@ -1088,7 +1088,7 @@ static inline PARSER_RC streaming_claimed_id(char **words, size_t num_words, PAR
1088 return PARSER_RC_ERROR;
1089 }
1090
1091 - uuid_t uuid;
1091 + nd_uuid_t uuid;
1092 RRDHOST *host = parser->user.host;
1093
1094 // We don't need the parsed UUID
@@ -1130,8 +1130,9 @@ void pluginsd_cleanup_v2(PARSER *parser) {
1130 pluginsd_clear_scope_chart(parser, "THREAD CLEANUP");
1131 }
1132
1133 -void pluginsd_process_thread_cleanup(void *ptr) {
1134 - PARSER *parser = (PARSER *)ptr;
1133 +void pluginsd_process_thread_cleanup(void *pptr) {
1134 + PARSER *parser = CLEANUP_FUNCTION_GET_PTR(pptr);
1135 + if(!parser) return;
1136
1137 pluginsd_cleanup_v2(parser);
1138 pluginsd_host_define_cleanup(parser);
@@ -1218,54 +1219,49 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp_plugi
1219
1220 size_t count = 0;
1221
1221 - // this keeps the parser with its current value
1222 - // so, parser needs to be allocated before pushing it
1223 - netdata_thread_cleanup_push(pluginsd_process_thread_cleanup, parser)
1224 - {
1225 - ND_LOG_STACK lgs[] = {
1226 - ND_LOG_FIELD_CB(NDF_REQUEST, line_splitter_reconstruct_line, &parser->line),
1227 - ND_LOG_FIELD_CB(NDF_NIDL_NODE, parser_reconstruct_node, parser),
1228 - ND_LOG_FIELD_CB(NDF_NIDL_INSTANCE, parser_reconstruct_instance, parser),
1229 - ND_LOG_FIELD_CB(NDF_NIDL_CONTEXT, parser_reconstruct_context, parser),
1230 - ND_LOG_FIELD_END(),
1231 - };
1232 - ND_LOG_STACK_PUSH(lgs);
1233 -
1234 - buffered_reader_init(&parser->reader);
1235 - CLEAN_BUFFER *buffer = buffer_create(sizeof(parser->reader.read_buffer) + 2, NULL);
1236 - while(likely(service_running(SERVICE_COLLECTORS))) {
1237 -
1238 - if(unlikely(!buffered_reader_next_line(&parser->reader, buffer))) {
1239 - buffered_reader_ret_t ret = buffered_reader_read_timeout(
1240 - &parser->reader,
1241 - fileno((FILE *) parser->fp_input),
1242 - 2 * 60 * MSEC_PER_SEC, true
1243 - );
1222 + ND_LOG_STACK lgs[] = {
1223 + ND_LOG_FIELD_CB(NDF_REQUEST, line_splitter_reconstruct_line, &parser->line),
1224 + ND_LOG_FIELD_CB(NDF_NIDL_NODE, parser_reconstruct_node, parser),
1225 + ND_LOG_FIELD_CB(NDF_NIDL_INSTANCE, parser_reconstruct_instance, parser),
1226 + ND_LOG_FIELD_CB(NDF_NIDL_CONTEXT, parser_reconstruct_context, parser),
1227 + ND_LOG_FIELD_END(),
1228 + };
1229 + ND_LOG_STACK_PUSH(lgs);
1230
1245 - if(unlikely(ret != BUFFERED_READER_READ_OK))
1246 - break;
1231 + CLEANUP_FUNCTION_REGISTER(pluginsd_process_thread_cleanup) cleanup_parser = parser;
1232 + buffered_reader_init(&parser->reader);
1233 + CLEAN_BUFFER *buffer = buffer_create(sizeof(parser->reader.read_buffer) + 2, NULL);
1234 + while(likely(service_running(SERVICE_COLLECTORS))) {
1235
1248 - continue;
1249 - }
1236 + if(unlikely(!buffered_reader_next_line(&parser->reader, buffer))) {
1237 + buffered_reader_ret_t ret = buffered_reader_read_timeout(
1238 + &parser->reader,
1239 + fileno((FILE *) parser->fp_input),
1240 + 2 * 60 * MSEC_PER_SEC, true
1241 + );
1242
1251 - if(unlikely(parser_action(parser, buffer->buffer)))
1243 + if(unlikely(ret != BUFFERED_READER_READ_OK))
1244 break;
1245
1254 - buffer->len = 0;
1255 - buffer->buffer[0] = '\0';
1246 + continue;
1247 }
1248
1258 - cd->unsafe.enabled = parser->user.enabled;
1259 - count = parser->user.data_collections_count;
1249 + if(unlikely(parser_action(parser, buffer->buffer)))
1250 + break;
1251
1261 - if(likely(count)) {
1262 - cd->successful_collections += count;
1263 - cd->serial_failures = 0;
1264 - }
1265 - else
1266 - cd->serial_failures++;
1252 + buffer->len = 0;
1253 + buffer->buffer[0] = '\0';
1254 }
1268 - netdata_thread_cleanup_pop(1); // free parser with the pop function
1255 +
1256 + cd->unsafe.enabled = parser->user.enabled;
1257 + count = parser->user.data_collections_count;
1258 +
1259 + if(likely(count)) {
1260 + cd->successful_collections += count;
1261 + cd->serial_failures = 0;
1262 + }
1263 + else
1264 + cd->serial_failures++;
1265
1266 return count;
1267 }
src/collectors/plugins.d/pluginsd_parser.h
+1 -1
@@ -65,7 +65,7 @@ typedef struct parser_user_object {
65
66 struct {
67 bool parsing_host;
68 - uuid_t machine_guid;
68 + nd_uuid_t machine_guid;
69 char machine_guid_str[UUID_STR_LEN];
70 STRING *hostname;
71 RRDLABELS *rrdlabels;
src/collectors/proc.plugin/plugin_proc.c
+44 -49
@@ -84,23 +84,21 @@ static struct proc_module {
84 #error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 36
85 #endif
86
87 -static netdata_thread_t *netdev_thread = NULL;
87 +static ND_THREAD *netdev_thread = NULL;
88
89 -static void proc_main_cleanup(void *ptr)
89 +static void proc_main_cleanup(void *pptr)
90 {
91 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
91 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
92 + if(!static_thread) return;
93 +
94 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
95
96 collector_info("cleaning up...");
97
96 - if (netdev_thread) {
97 - netdata_thread_join(*netdev_thread, NULL);
98 - freez(netdev_thread);
99 - }
98 + nd_thread_join(netdev_thread);
99 + worker_unregister();
100
101 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
102 -
103 - worker_unregister();
102 }
103
104 bool inside_lxc_container = false;
@@ -146,70 +144,67 @@ static bool log_proc_module(BUFFER *wb, void *data) {
144
145 void *proc_main(void *ptr)
146 {
147 + CLEANUP_FUNCTION_REGISTER(proc_main_cleanup) cleanup_ptr = ptr;
148 +
149 worker_register("PROC");
150
151 rrd_collector_started();
152
153 if (config_get_boolean("plugin:proc", "/proc/net/dev", CONFIG_BOOLEAN_YES)) {
154 - netdev_thread = mallocz(sizeof(netdata_thread_t));
154 netdata_log_debug(D_SYSTEM, "Starting thread %s.", THREAD_NETDEV_NAME);
156 - netdata_thread_create(
157 - netdev_thread, THREAD_NETDEV_NAME, NETDATA_THREAD_OPTION_JOINABLE, netdev_main, netdev_thread);
155 + netdev_thread = nd_thread_create(THREAD_NETDEV_NAME, NETDATA_THREAD_OPTION_JOINABLE, netdev_main, NULL);
156 }
157
160 - netdata_thread_cleanup_push(proc_main_cleanup, ptr)
161 - {
162 - config_get_boolean("plugin:proc", "/proc/pagetypeinfo", CONFIG_BOOLEAN_NO);
163 - config_get_boolean("plugin:proc", "/proc/spl/kstat/zfs/pool/state", CONFIG_BOOLEAN_NO);
158 + config_get_boolean("plugin:proc", "/proc/pagetypeinfo", CONFIG_BOOLEAN_NO);
159 + config_get_boolean("plugin:proc", "/proc/spl/kstat/zfs/pool/state", CONFIG_BOOLEAN_NO);
160
165 - // check the enabled status for each module
166 - int i;
167 - for(i = 0; proc_modules[i].name; i++) {
168 - struct proc_module *pm = &proc_modules[i];
161 + // check the enabled status for each module
162 + int i;
163 + for(i = 0; proc_modules[i].name; i++) {
164 + struct proc_module *pm = &proc_modules[i];
165
170 - pm->enabled = config_get_boolean("plugin:proc", pm->name, CONFIG_BOOLEAN_YES);
171 - pm->rd = NULL;
166 + pm->enabled = config_get_boolean("plugin:proc", pm->name, CONFIG_BOOLEAN_YES);
167 + pm->rd = NULL;
168
173 - worker_register_job_name(i, proc_modules[i].dim);
174 - }
169 + worker_register_job_name(i, proc_modules[i].dim);
170 + }
171
176 - usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
177 - heartbeat_t hb;
178 - heartbeat_init(&hb);
172 + usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
173 + heartbeat_t hb;
174 + heartbeat_init(&hb);
175
180 - inside_lxc_container = is_lxcfs_proc_mounted();
176 + inside_lxc_container = is_lxcfs_proc_mounted();
177
178 #define LGS_MODULE_ID 0
179
184 - ND_LOG_STACK lgs[] = {
185 - [LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, "proc.plugin"),
186 - ND_LOG_FIELD_END(),
187 - };
188 - ND_LOG_STACK_PUSH(lgs);
180 + ND_LOG_STACK lgs[] = {
181 + [LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, "proc.plugin"),
182 + ND_LOG_FIELD_END(),
183 + };
184 + ND_LOG_STACK_PUSH(lgs);
185
190 - while(service_running(SERVICE_COLLECTORS)) {
191 - worker_is_idle();
192 - usec_t hb_dt = heartbeat_next(&hb, step);
186 + while(service_running(SERVICE_COLLECTORS)) {
187 + worker_is_idle();
188 + usec_t hb_dt = heartbeat_next(&hb, step);
189
190 + if(unlikely(!service_running(SERVICE_COLLECTORS)))
191 + break;
192 +
193 + for(i = 0; proc_modules[i].name; i++) {
194 if(unlikely(!service_running(SERVICE_COLLECTORS)))
195 break;
196
197 - for(i = 0; proc_modules[i].name; i++) {
198 - if(unlikely(!service_running(SERVICE_COLLECTORS)))
199 - break;
200 -
201 - struct proc_module *pm = &proc_modules[i];
202 - if(unlikely(!pm->enabled))
203 - continue;
197 + struct proc_module *pm = &proc_modules[i];
198 + if(unlikely(!pm->enabled))
199 + continue;
200
205 - worker_is_busy(i);
206 - lgs[LGS_MODULE_ID] = ND_LOG_FIELD_CB(NDF_MODULE, log_proc_module, pm);
207 - pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
208 - lgs[LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, "proc.plugin");
209 - }
201 + worker_is_busy(i);
202 + lgs[LGS_MODULE_ID] = ND_LOG_FIELD_CB(NDF_MODULE, log_proc_module, pm);
203 + pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
204 + lgs[LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, "proc.plugin");
205 }
206 }
212 - netdata_thread_cleanup_pop(1);
207 +
208 return NULL;
209 }
210
src/collectors/proc.plugin/plugin_proc.h
+1 -1
@@ -9,7 +9,7 @@
9 #define PLUGIN_PROC_NAME PLUGIN_PROC_CONFIG_NAME ".plugin"
10
11 #define THREAD_NETDEV_NAME "P[proc netdev]"
12 -void *netdev_main(void *ptr);
12 +void *netdev_main(void *ptr_is_null);
13
14 int do_proc_net_wireless(int update_every, usec_t dt);
15 int do_proc_diskstats(int update_every, usec_t dt);
src/collectors/proc.plugin/proc_diskstats.c
+24 -58
@@ -2,10 +2,13 @@
2
3 #include "plugin_proc.h"
4
5 -#define RRD_TYPE_DISK "disk"
5 #define PLUGIN_PROC_MODULE_DISKSTATS_NAME "/proc/diskstats"
6 #define CONFIG_SECTION_PLUGIN_PROC_DISKSTATS "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_DISKSTATS_NAME
7
8 +#define _COMMON_PLUGIN_NAME PLUGIN_PROC_CONFIG_NAME
9 +#define _COMMON_PLUGIN_MODULE_NAME PLUGIN_PROC_MODULE_DISKSTATS_NAME
10 +#include "../common-contexts/common-contexts.h"
11 +
12 #define RRDFUNCTIONS_DISKSTATS_HELP "View block device statistics"
13
14 #define DISK_TYPE_UNKNOWN 0
@@ -75,9 +78,7 @@ static struct disk {
78 usec_t bcache_priority_stats_update_every_usec;
79 usec_t bcache_priority_stats_elapsed_usec;
80
78 - RRDSET *st_io;
79 - RRDDIM *rd_io_reads;
80 - RRDDIM *rd_io_writes;
81 + ND_DISK_IO disk_io;
82
83 RRDSET *st_ext_io;
84 RRDDIM *rd_io_discards;
@@ -1033,6 +1034,10 @@ static void add_labels_to_disk(struct disk *d, RRDSET *st) {
1034 rrdlabels_add(st->rrdlabels, "device_type", get_disk_type_string(d->type), RRDLABEL_SRC_AUTO);
1035 }
1036
1037 +static void disk_labels_cb(RRDSET *st, void *data) {
1038 + add_labels_to_disk(data, st);
1039 +}
1040 +
1041 static int diskstats_function_block_devices(BUFFER *wb, const char *function __maybe_unused) {
1042 buffer_flush(wb);
1043 wb->content_type = CT_APPLICATION_JSON;
@@ -1076,8 +1081,8 @@ static int diskstats_function_block_devices(BUFFER *wb, const char *function __m
1081 buffer_json_add_array_item_string(wb, d->serial);
1082
1083 // IO
1079 - double io_reads = rrddim_get_last_stored_value(d->rd_io_reads, &max_io_reads, 1024.0);
1080 - double io_writes = rrddim_get_last_stored_value(d->rd_io_writes, &max_io_writes, 1024.0);
1084 + double io_reads = rrddim_get_last_stored_value(d->disk_io.rd_io_reads, &max_io_reads, 1024.0);
1085 + double io_writes = rrddim_get_last_stored_value(d->disk_io.rd_io_writes, &max_io_writes, 1024.0);
1086 double io_total = NAN;
1087 if (!isnan(io_reads) && !isnan(io_writes)) {
1088 io_total = io_reads + io_writes;
@@ -1328,7 +1333,7 @@ static void diskstats_cleanup_disks() {
1333 rrdset_obsolete_and_pointer_null(d->st_ext_await);
1334 rrdset_obsolete_and_pointer_null(d->st_backlog);
1335 rrdset_obsolete_and_pointer_null(d->st_busy);
1331 - rrdset_obsolete_and_pointer_null(d->st_io);
1336 + rrdset_obsolete_and_pointer_null(d->disk_io.st_io);
1337 rrdset_obsolete_and_pointer_null(d->st_ext_io);
1338 rrdset_obsolete_and_pointer_null(d->st_iotime);
1339 rrdset_obsolete_and_pointer_null(d->st_ext_iotime);
@@ -1616,31 +1621,17 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1621 netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
1622 d->do_io = CONFIG_BOOLEAN_YES;
1623
1619 - if(unlikely(!d->st_io)) {
1620 - d->st_io = rrdset_create_localhost(
1621 - RRD_TYPE_DISK
1622 - , d->chart_id
1623 - , d->disk
1624 - , family
1625 - , "disk.io"
1626 - , "Disk I/O Bandwidth"
1627 - , "KiB/s"
1628 - , PLUGIN_PROC_NAME
1629 - , PLUGIN_PROC_MODULE_DISKSTATS_NAME
1630 - , NETDATA_CHART_PRIO_DISK_IO
1631 - , update_every
1632 - , RRDSET_TYPE_AREA
1633 - );
1634 -
1635 - d->rd_io_reads = rrddim_add(d->st_io, "reads", NULL, d->sector_size, 1024, RRD_ALGORITHM_INCREMENTAL);
1636 - d->rd_io_writes = rrddim_add(d->st_io, "writes", NULL, d->sector_size * -1, 1024, RRD_ALGORITHM_INCREMENTAL);
1637 -
1638 - add_labels_to_disk(d, d->st_io);
1639 - }
1640 -
1641 - last_readsectors = rrddim_set_by_pointer(d->st_io, d->rd_io_reads, readsectors);
1642 - last_writesectors = rrddim_set_by_pointer(d->st_io, d->rd_io_writes, writesectors);
1643 - rrdset_done(d->st_io);
1624 + last_readsectors = d->disk_io.rd_io_reads ? d->disk_io.rd_io_reads->collector.last_collected_value : 0;
1625 + last_writesectors = d->disk_io.rd_io_writes ? d->disk_io.rd_io_writes->collector.last_collected_value : 0;
1626 +
1627 + common_disk_io(&d->disk_io,
1628 + d->chart_id,
1629 + d->disk,
1630 + readsectors * d->sector_size,
1631 + writesectors * d->sector_size,
1632 + update_every,
1633 + disk_labels_cb,
1634 + d);
1635 }
1636
1637 if (do_dc_stats && d->do_io == CONFIG_BOOLEAN_YES && d->do_ext != CONFIG_BOOLEAN_NO) {
@@ -2468,32 +2459,7 @@ int do_proc_diskstats(int update_every, usec_t dt) {
2459 if(global_do_io == CONFIG_BOOLEAN_YES || (global_do_io == CONFIG_BOOLEAN_AUTO &&
2460 (system_read_kb || system_write_kb ||
2461 netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
2471 - static RRDSET *st_io = NULL;
2472 - static RRDDIM *rd_in = NULL, *rd_out = NULL;
2473 -
2474 - if(unlikely(!st_io)) {
2475 - st_io = rrdset_create_localhost(
2476 - "system"
2477 - , "io"
2478 - , NULL
2479 - , "disk"
2480 - , NULL
2481 - , "Disk I/O"
2482 - , "KiB/s"
2483 - , PLUGIN_PROC_NAME
2484 - , PLUGIN_PROC_MODULE_DISKSTATS_NAME
2485 - , NETDATA_CHART_PRIO_SYSTEM_IO
2486 - , update_every
2487 - , RRDSET_TYPE_AREA
2488 - );
2489 -
2490 - rd_in = rrddim_add(st_io, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2491 - rd_out = rrddim_add(st_io, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2492 - }
2493 -
2494 - rrddim_set_by_pointer(st_io, rd_in, system_read_kb);
2495 - rrddim_set_by_pointer(st_io, rd_out, system_write_kb);
2496 - rrdset_done(st_io);
2462 + common_system_io(system_read_kb * 1024, system_write_kb * 1024, update_every);
2463 }
2464
2465 return 0;
src/collectors/proc.plugin/proc_loadavg.c
+1 -1
@@ -48,7 +48,7 @@ int do_proc_loadavg(int update_every, usec_t dt) {
48 unsigned long long active_processes = str2ull(procfile_lineword(ff, 0, 4), NULL);
49
50 //get system pid_max
51 - unsigned long long max_processes = get_system_pid_max();
51 + unsigned long long max_processes = os_get_system_pid_max();
52 //
53 //unsigned long long next_pid = str2ull(procfile_lineword(ff, 0, 5));
54
src/collectors/proc.plugin/proc_meminfo.c
+8 -87
@@ -5,6 +5,10 @@
5 #define PLUGIN_PROC_MODULE_MEMINFO_NAME "/proc/meminfo"
6 #define CONFIG_SECTION_PLUGIN_PROC_MEMINFO "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_MEMINFO_NAME
7
8 +#define _COMMON_PLUGIN_NAME PLUGIN_PROC_NAME
9 +#define _COMMON_PLUGIN_MODULE_NAME PLUGIN_PROC_MODULE_MEMINFO_NAME
10 +#include "../common-contexts/common-contexts.h"
11 +
12 int do_proc_meminfo(int update_every, usec_t dt) {
13 (void)dt;
14
@@ -242,65 +246,10 @@ int do_proc_meminfo(int update_every, usec_t dt) {
246 }
247
248 if(do_ram) {
245 - {
246 - static RRDSET *st_system_ram = NULL;
247 - static RRDDIM *rd_free = NULL, *rd_used = NULL, *rd_cached = NULL, *rd_buffers = NULL;
248 -
249 - if(unlikely(!st_system_ram)) {
250 - st_system_ram = rrdset_create_localhost(
251 - "system"
252 - , "ram"
253 - , NULL
254 - , "ram"
255 - , NULL
256 - , "System RAM"
257 - , "MiB"
258 - , PLUGIN_PROC_NAME
259 - , PLUGIN_PROC_MODULE_MEMINFO_NAME
260 - , NETDATA_CHART_PRIO_SYSTEM_RAM
261 - , update_every
262 - , RRDSET_TYPE_STACKED
263 - );
264 -
265 - rd_free = rrddim_add(st_system_ram, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
266 - rd_used = rrddim_add(st_system_ram, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
267 - rd_cached = rrddim_add(st_system_ram, "cached", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
268 - rd_buffers = rrddim_add(st_system_ram, "buffers", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
269 - }
270 -
271 - rrddim_set_by_pointer(st_system_ram, rd_free, MemFree);
272 - rrddim_set_by_pointer(st_system_ram, rd_used, MemUsed);
273 - rrddim_set_by_pointer(st_system_ram, rd_cached, MemCached);
274 - rrddim_set_by_pointer(st_system_ram, rd_buffers, Buffers);
275 - rrdset_done(st_system_ram);
276 - }
277 -
278 - if(arl_memavailable->flags & ARL_ENTRY_FLAG_FOUND) {
279 - static RRDSET *st_mem_available = NULL;
280 - static RRDDIM *rd_avail = NULL;
281 -
282 - if(unlikely(!st_mem_available)) {
283 - st_mem_available = rrdset_create_localhost(
284 - "mem"
285 - , "available"
286 - , NULL
287 - , "overview"
288 - , NULL
289 - , "Available RAM for applications"
290 - , "MiB"
291 - , PLUGIN_PROC_NAME
292 - , PLUGIN_PROC_MODULE_MEMINFO_NAME
293 - , NETDATA_CHART_PRIO_MEM_SYSTEM_AVAILABLE
294 - , update_every
295 - , RRDSET_TYPE_AREA
296 - );
297 -
298 - rd_avail = rrddim_add(st_mem_available, "MemAvailable", "avail", 1, 1024, RRD_ALGORITHM_ABSOLUTE);
299 - }
249 + common_system_ram(MemFree * 1024, MemUsed * 1024, MemCached * 1024, Buffers * 1024, update_every);
250
301 - rrddim_set_by_pointer(st_mem_available, rd_avail, MemAvailable);
302 - rrdset_done(st_mem_available);
303 - }
251 + if(arl_memavailable->flags & ARL_ENTRY_FLAG_FOUND)
252 + common_mem_available(MemAvailable * 1024, update_every);
253 }
254
255 unsigned long long SwapUsed = SwapTotal - SwapFree;
@@ -309,35 +258,7 @@ int do_proc_meminfo(int update_every, usec_t dt) {
258 (SwapTotal || SwapUsed || SwapFree ||
259 netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
260 do_swap = CONFIG_BOOLEAN_YES;
312 -
313 - static RRDSET *st_system_swap = NULL;
314 - static RRDDIM *rd_free = NULL, *rd_used = NULL;
315 -
316 - if(unlikely(!st_system_swap)) {
317 - st_system_swap = rrdset_create_localhost(
318 - "mem"
319 - , "swap"
320 - , NULL
321 - , "swap"
322 - , NULL
323 - , "System Swap"
324 - , "MiB"
325 - , PLUGIN_PROC_NAME
326 - , PLUGIN_PROC_MODULE_MEMINFO_NAME
327 - , NETDATA_CHART_PRIO_MEM_SWAP
328 - , update_every
329 - , RRDSET_TYPE_STACKED
330 - );
331 -
332 - rrdset_flag_set(st_system_swap, RRDSET_FLAG_DETAIL);
333 -
334 - rd_free = rrddim_add(st_system_swap, "free", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
335 - rd_used = rrddim_add(st_system_swap, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
336 - }
337 -
338 - rrddim_set_by_pointer(st_system_swap, rd_used, SwapUsed);
339 - rrddim_set_by_pointer(st_system_swap, rd_free, SwapFree);
340 - rrdset_done(st_system_swap);
261 + common_mem_swap(SwapFree * 1024, SwapUsed * 1024, update_every);
262
263 {
264 static RRDSET *st_mem_swap_cached = NULL;
src/collectors/proc.plugin/proc_net_dev.c
+20 -21
@@ -1738,17 +1738,19 @@ int do_proc_net_dev(int update_every, usec_t dt) {
1738 return 0;
1739 }
1740
1741 -static void netdev_main_cleanup(void *ptr)
1742 -{
1743 - UNUSED(ptr);
1741 +static void netdev_main_cleanup(void *pptr) {
1742 + if(CLEANUP_FUNCTION_GET_PTR(pptr) != (void *)0x01)
1743 + return;
1744
1745 collector_info("cleaning up...");
1746
1747 worker_unregister();
1748 }
1749
1750 -void *netdev_main(void *ptr)
1750 +void *netdev_main(void *ptr_is_null __maybe_unused)
1751 {
1752 + CLEANUP_FUNCTION_REGISTER(netdev_main_cleanup) cleanup_ptr = (void *)0x01;
1753 +
1754 worker_register("NETDEV");
1755 worker_register_job_name(0, "netdev");
1756
@@ -1760,29 +1762,26 @@ void *netdev_main(void *ptr)
1762 "top", HTTP_ACCESS_ANONYMOUS_DATA,
1763 netdev_function_net_interfaces);
1764
1763 - netdata_thread_cleanup_push(netdev_main_cleanup, ptr) {
1764 - usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
1765 - heartbeat_t hb;
1766 - heartbeat_init(&hb);
1765 + usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
1766 + heartbeat_t hb;
1767 + heartbeat_init(&hb);
1768
1768 - while (service_running(SERVICE_COLLECTORS)) {
1769 - worker_is_idle();
1770 - usec_t hb_dt = heartbeat_next(&hb, step);
1769 + while (service_running(SERVICE_COLLECTORS)) {
1770 + worker_is_idle();
1771 + usec_t hb_dt = heartbeat_next(&hb, step);
1772
1772 - if (unlikely(!service_running(SERVICE_COLLECTORS)))
1773 - break;
1773 + if (unlikely(!service_running(SERVICE_COLLECTORS)))
1774 + break;
1775
1775 - cgroup_netdev_reset_all();
1776 + cgroup_netdev_reset_all();
1777
1777 - worker_is_busy(0);
1778 + worker_is_busy(0);
1779
1779 - netdata_mutex_lock(&netdev_mutex);
1780 - if (do_proc_net_dev(localhost->rrd_update_every, hb_dt))
1781 - break;
1782 - netdata_mutex_unlock(&netdev_mutex);
1783 - }
1780 + netdata_mutex_lock(&netdev_mutex);
1781 + if (do_proc_net_dev(localhost->rrd_update_every, hb_dt))
1782 + break;
1783 + netdata_mutex_unlock(&netdev_mutex);
1784 }
1785 - netdata_thread_cleanup_pop(1);
1785
1786 return NULL;
1787 }
src/collectors/proc.plugin/proc_net_netstat.c
+47 -47
@@ -400,8 +400,8 @@ static void do_proc_net_snmp6(int update_every) {
400 , RRDSET_TYPE_AREA
401 );
402
403 - rd_received = rrddim_add(st, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
404 - rd_sent = rrddim_add(st, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
403 + rd_received = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
404 + rd_sent = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
405 }
406
407 rrddim_set_by_pointer(st, rd_received, Ip6InOctets);
@@ -438,10 +438,10 @@ static void do_proc_net_snmp6(int update_every) {
438 , RRDSET_TYPE_LINE
439 );
440
441 - rd_received = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
442 - rd_sent = rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
443 - rd_forwarded = rrddim_add(st, "OutForwDatagrams", "forwarded", -1, 1, RRD_ALGORITHM_INCREMENTAL);
444 - rd_delivers = rrddim_add(st, "InDelivers", "delivers", 1, 1, RRD_ALGORITHM_INCREMENTAL);
441 + rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
442 + rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
443 + rd_forwarded = rrddim_add(st, "forwarded", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
444 + rd_delivers = rrddim_add(st, "delivered", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
445 }
446
447 rrddim_set_by_pointer(st, rd_received, Ip6InReceives);
@@ -619,8 +619,8 @@ static void do_proc_net_snmp6(int update_every) {
619 , RRDSET_TYPE_LINE
620 );
621
622 - rd_received = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
623 - rd_sent = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
622 + rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
623 + rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
624 }
625
626 rrddim_set_by_pointer(st, rd_received, Udp6InDatagrams);
@@ -703,8 +703,8 @@ static void do_proc_net_snmp6(int update_every) {
703 , RRDSET_TYPE_LINE
704 );
705
706 - rd_received = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
707 - rd_sent = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
706 + rd_received = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
707 + rd_sent = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
708 }
709
710 rrddim_set_by_pointer(st, rd_received, UdpLite6InDatagrams);
@@ -786,8 +786,8 @@ static void do_proc_net_snmp6(int update_every) {
786 );
787 rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
788
789 - rd_Ip6InMcastOctets = rrddim_add(st, "InMcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
790 - rd_Ip6OutMcastOctets = rrddim_add(st, "OutMcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
789 + rd_Ip6InMcastOctets = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
790 + rd_Ip6OutMcastOctets = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
791 }
792
793 rrddim_set_by_pointer(st, rd_Ip6InMcastOctets, Ip6InMcastOctets);
@@ -821,8 +821,8 @@ static void do_proc_net_snmp6(int update_every) {
821 );
822 rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
823
824 - rd_Ip6InBcastOctets = rrddim_add(st, "InBcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
825 - rd_Ip6OutBcastOctets = rrddim_add(st, "OutBcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
824 + rd_Ip6InBcastOctets = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
825 + rd_Ip6OutBcastOctets = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
826 }
827
828 rrddim_set_by_pointer(st, rd_Ip6InBcastOctets, Ip6InBcastOctets);
@@ -856,8 +856,8 @@ static void do_proc_net_snmp6(int update_every) {
856 );
857 rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
858
859 - rd_Ip6InMcastPkts = rrddim_add(st, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
860 - rd_Ip6OutMcastPkts = rrddim_add(st, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
859 + rd_Ip6InMcastPkts = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
860 + rd_Ip6OutMcastPkts = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
861 }
862
863 rrddim_set_by_pointer(st, rd_Ip6InMcastPkts, Ip6InMcastPkts);
@@ -890,8 +890,8 @@ static void do_proc_net_snmp6(int update_every) {
890 , RRDSET_TYPE_LINE
891 );
892
893 - rd_Icmp6InMsgs = rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
894 - rd_Icmp6OutMsgs = rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
893 + rd_Icmp6InMsgs = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
894 + rd_Icmp6OutMsgs = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
895 }
896
897 rrddim_set_by_pointer(st, rd_Icmp6InMsgs, Icmp6InMsgs);
@@ -924,8 +924,8 @@ static void do_proc_net_snmp6(int update_every) {
924 , RRDSET_TYPE_LINE
925 );
926
927 - rd_Icmp6InRedirects = rrddim_add(st, "InRedirects", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
928 - rd_Icmp6OutRedirects = rrddim_add(st, "OutRedirects", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
927 + rd_Icmp6InRedirects = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
928 + rd_Icmp6OutRedirects = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
929 }
930
931 rrddim_set_by_pointer(st, rd_Icmp6InRedirects, Icmp6InRedirects);
@@ -1203,8 +1203,8 @@ static void do_proc_net_snmp6(int update_every) {
1203 , RRDSET_TYPE_LINE
1204 );
1205
1206 - rd_InMLDv2Reports = rrddim_add(st, "InMLDv2Reports", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
1207 - rd_OutMLDv2Reports = rrddim_add(st, "OutMLDv2Reports", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
1206 + rd_InMLDv2Reports = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1207 + rd_OutMLDv2Reports = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1208 }
1209
1210 rrddim_set_by_pointer(st, rd_InMLDv2Reports, Icmp6InMLDv2Reports);
@@ -1865,8 +1865,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
1865 , RRDSET_TYPE_AREA
1866 );
1867
1868 - rd_in = rrddim_add(st_system_ip, "InOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1869 - rd_out = rrddim_add(st_system_ip, "OutOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1868 + rd_in = rrddim_add(st_system_ip, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1869 + rd_out = rrddim_add(st_system_ip, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1870 }
1871
1872 rrddim_set_by_pointer(st_system_ip, rd_in, ipext_InOctets);
@@ -1900,8 +1900,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
1900
1901 rrdset_flag_set(st_ip_mcast, RRDSET_FLAG_DETAIL);
1902
1903 - rd_in = rrddim_add(st_ip_mcast, "InMcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1904 - rd_out = rrddim_add(st_ip_mcast, "OutMcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1903 + rd_in = rrddim_add(st_ip_mcast, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1904 + rd_out = rrddim_add(st_ip_mcast, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1905 }
1906
1907 rrddim_set_by_pointer(st_ip_mcast, rd_in, ipext_InMcastOctets);
@@ -1939,8 +1939,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
1939
1940 rrdset_flag_set(st_ip_bcast, RRDSET_FLAG_DETAIL);
1941
1942 - rd_in = rrddim_add(st_ip_bcast, "InBcastOctets", "received", 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1943 - rd_out = rrddim_add(st_ip_bcast, "OutBcastOctets", "sent", -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1942 + rd_in = rrddim_add(st_ip_bcast, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1943 + rd_out = rrddim_add(st_ip_bcast, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
1944 }
1945
1946 rrddim_set_by_pointer(st_ip_bcast, rd_in, ipext_InBcastOctets);
@@ -1978,8 +1978,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
1978
1979 rrdset_flag_set(st_ip_mcastpkts, RRDSET_FLAG_DETAIL);
1980
1981 - rd_in = rrddim_add(st_ip_mcastpkts, "InMcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
1982 - rd_out = rrddim_add(st_ip_mcastpkts, "OutMcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
1981 + rd_in = rrddim_add(st_ip_mcastpkts, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1982 + rd_out = rrddim_add(st_ip_mcastpkts, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1983 }
1984
1985 rrddim_set_by_pointer(st_ip_mcastpkts, rd_in, ipext_InMcastPkts);
@@ -2014,8 +2014,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
2014
2015 rrdset_flag_set(st_ip_bcastpkts, RRDSET_FLAG_DETAIL);
2016
2017 - rd_in = rrddim_add(st_ip_bcastpkts, "InBcastPkts", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2018 - rd_out = rrddim_add(st_ip_bcastpkts, "OutBcastPkts", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
2017 + rd_in = rrddim_add(st_ip_bcastpkts, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2018 + rd_out = rrddim_add(st_ip_bcastpkts, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2019 }
2020
2021 rrddim_set_by_pointer(st_ip_bcastpkts, rd_in, ipext_InBcastPkts);
@@ -2253,9 +2253,9 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
2253 , RRDSET_TYPE_LINE
2254 );
2255
2256 - rd_received = rrddim_add(st_syncookies, "SyncookiesRecv", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2257 - rd_sent = rrddim_add(st_syncookies, "SyncookiesSent", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
2258 - rd_failed = rrddim_add(st_syncookies, "SyncookiesFailed", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
2256 + rd_received = rrddim_add(st_syncookies, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2257 + rd_sent = rrddim_add(st_syncookies, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2258 + rd_failed = rrddim_add(st_syncookies, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2259 }
2260
2261 rrddim_set_by_pointer(st_syncookies, rd_received, tcpext_SyncookiesRecv);
@@ -2369,10 +2369,10 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
2369 , RRDSET_TYPE_LINE
2370 );
2371
2372 - rd_InReceives = rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2373 - rd_OutRequests = rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
2374 - rd_ForwDatagrams = rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2375 - rd_InDelivers = rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2372 + rd_InReceives = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2373 + rd_OutRequests = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2374 + rd_ForwDatagrams = rrddim_add(st, "forwarded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2375 + rd_InDelivers = rrddim_add(st, "delivered", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2376 }
2377
2378 rrddim_set_by_pointer(st, rd_OutRequests, (collected_number)snmp_root.ip_OutRequests);
@@ -2557,8 +2557,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
2557 , RRDSET_TYPE_LINE
2558 );
2559
2560 - rd_InMsgs = rrddim_add(st_packets, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2561 - rd_OutMsgs = rrddim_add(st_packets, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
2560 + rd_InMsgs = rrddim_add(st_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2561 + rd_OutMsgs = rrddim_add(st_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2562 }
2563
2564 rrddim_set_by_pointer(st_packets, rd_InMsgs, (collected_number)snmp_root.icmp_InMsgs);
@@ -2773,8 +2773,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
2773 , RRDSET_TYPE_LINE
2774 );
2775
2776 - rd_InSegs = rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2777 - rd_OutSegs = rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
2776 + rd_InSegs = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2777 + rd_OutSegs = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2778 }
2779
2780 rrddim_set_by_pointer(st, rd_InSegs, (collected_number)snmp_root.tcp_InSegs);
@@ -2932,8 +2932,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
2932 , RRDSET_TYPE_LINE
2933 );
2934
2935 - rd_InDatagrams = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
2936 - rd_OutDatagrams = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
2935 + rd_InDatagrams = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2936 + rd_OutDatagrams = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
2937 }
2938
2939 rrddim_set_by_pointer(st, rd_InDatagrams, (collected_number)snmp_root.udp_InDatagrams);
@@ -3030,8 +3030,8 @@ int do_proc_net_netstat(int update_every, usec_t dt) {
3030 , RRDSET_TYPE_LINE
3031 );
3032
3033 - rd_InDatagrams = rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
3034 - rd_OutDatagrams = rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
3033 + rd_InDatagrams = rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3034 + rd_OutDatagrams = rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
3035 }
3036
3037 rrddim_set_by_pointer(st, rd_InDatagrams, (collected_number)snmp_root.udplite_InDatagrams);
src/collectors/proc.plugin/proc_stat.c
+3 -3
@@ -484,7 +484,7 @@ int do_proc_stat(int update_every, usec_t dt) {
484 *time_in_state_filename = NULL, *schedstat_filename = NULL, *cpuidle_name_filename = NULL, *cpuidle_time_filename = NULL;
485 static const RRDVAR_ACQUIRED *cpus_var = NULL;
486 static int accurate_freq_avail = 0, accurate_freq_is_used = 0;
487 - size_t cores_found = (size_t)get_system_cpus();
487 + size_t cores_found = (size_t)os_get_system_cpus();
488
489 if(unlikely(do_cpu == -1)) {
490 do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", CONFIG_BOOLEAN_YES);
@@ -495,7 +495,7 @@ int do_proc_stat(int update_every, usec_t dt) {
495 do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", CONFIG_BOOLEAN_YES);
496
497 // give sane defaults based on the number of processors
498 - if(unlikely(get_system_cpus() > 128)) {
498 + if(unlikely(os_get_system_cpus() > 128)) {
499 // the system has too many processors
500 keep_per_core_fds_open = CONFIG_BOOLEAN_NO;
501 do_core_throttle_count = CONFIG_BOOLEAN_NO;
@@ -511,7 +511,7 @@ int do_proc_stat(int update_every, usec_t dt) {
511 do_cpu_freq = CONFIG_BOOLEAN_YES;
512 do_cpuidle = CONFIG_BOOLEAN_NO;
513 }
514 - if(unlikely(get_system_cpus() > 24)) {
514 + if(unlikely(os_get_system_cpus() > 24)) {
515 // the system has too many processors
516 keep_cpuidle_fds_open = CONFIG_BOOLEAN_NO;
517 }
src/collectors/proc.plugin/proc_vmstat.c
+5 -28
@@ -6,6 +6,10 @@
6
7 #define OOM_KILL_STRING "oom_kill"
8
9 +#define _COMMON_PLUGIN_NAME PLUGIN_PROC_NAME
10 +#define _COMMON_PLUGIN_MODULE_NAME PLUGIN_PROC_MODULE_VMSTAT_NAME
11 +#include "../common-contexts/common-contexts.h"
12 +
13 int do_proc_vmstat(int update_every, usec_t dt) {
14 (void)dt;
15
@@ -328,34 +332,7 @@ int do_proc_vmstat(int update_every, usec_t dt) {
332 // --------------------------------------------------------------------
333
334 if(do_pgfaults) {
331 - static RRDSET *st_pgfaults = NULL;
332 - static RRDDIM *rd_minor = NULL, *rd_major = NULL;
333 -
334 - if(unlikely(!st_pgfaults)) {
335 - st_pgfaults = rrdset_create_localhost(
336 - "mem"
337 - , "pgfaults"
338 - , NULL
339 - , "page faults"
340 - , NULL
341 - , "Memory Page Faults"
342 - , "faults/s"
343 - , PLUGIN_PROC_NAME
344 - , PLUGIN_PROC_MODULE_VMSTAT_NAME
345 - , NETDATA_CHART_PRIO_MEM_SYSTEM_PGFAULTS
346 - , update_every
347 - , RRDSET_TYPE_LINE
348 - );
349 -
350 - rrdset_flag_set(st_pgfaults, RRDSET_FLAG_DETAIL);
351 -
352 - rd_minor = rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
353 - rd_major = rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
354 - }
355 -
356 - rrddim_set_by_pointer(st_pgfaults, rd_minor, pgfault);
357 - rrddim_set_by_pointer(st_pgfaults, rd_major, pgmajfault);
358 - rrdset_done(st_pgfaults);
335 + common_mem_pgfaults(pgfault, pgmajfault, update_every);
336 }
337
338 // --------------------------------------------------------------------
src/collectors/profile.plugin/plugin_profile.cc
+9 -7
@@ -180,8 +180,10 @@ static void *subprofile_main(void* Arg) {
180 return nullptr;
181 }
182
183 -static void profile_main_cleanup(void *ptr) {
184 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *) ptr;
183 +static void profile_main_cleanup(void *pptr) {
184 + struct netdata_static_thread *static_thread = (struct netdata_static_thread *)CLEANUP_FUNCTION_GET_PTR(pptr);
185 + if(!static_thread) return;
186 +
187 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
188
189 netdata_log_info("cleaning up...");
@@ -190,7 +192,7 @@ static void profile_main_cleanup(void *ptr) {
192 }
193
194 extern "C" void *profile_main(void *ptr) {
193 - netdata_thread_cleanup_push(profile_main_cleanup, ptr);
195 + CLEANUP_FUNCTION_REGISTER(profile_main_cleanup) cleanup_ptr = ptr;
196
197 int UpdateEvery = (int) config_get_number(CONFIG_SECTION_PROFILE, "update every", 1);
198 if (UpdateEvery < localhost->rrd_update_every)
@@ -209,18 +211,18 @@ extern "C" void *profile_main(void *ptr) {
211 Profilers.push_back(P);
212 }
213
212 - std::vector<netdata_thread_t> Threads(NumThreads);
214 + std::vector<ND_THREAD *> Threads(NumThreads);
215
216 for (size_t Idx = 0; Idx != NumThreads; Idx++) {
217 char Tag[NETDATA_THREAD_TAG_MAX + 1];
218
219 snprintfz(Tag, NETDATA_THREAD_TAG_MAX, "PROFILER[%zu]", Idx);
218 - netdata_thread_create(&Threads[Idx], Tag, NETDATA_THREAD_OPTION_JOINABLE, subprofile_main, static_cast<void *>(&Profilers[Idx]));
220 + Threads[Idx] = nd_thread_create(Tag, NETDATA_THREAD_OPTION_JOINABLE,
221 + subprofile_main, static_cast<void *>(&Profilers[Idx]));
222 }
223
224 for (size_t Idx = 0; Idx != NumThreads; Idx++)
222 - netdata_thread_join(Threads[Idx], nullptr);
225 + nd_thread_join(Threads[Idx]);
226
224 - netdata_thread_cleanup_pop(1);
227 return NULL;
228 }
src/collectors/statsd.plugin/statsd.c
+20 -16
@@ -237,7 +237,7 @@ struct collection_thread_status {
237 bool running;
238 uint32_t max_sockets;
239
240 - netdata_thread_t thread;
240 + ND_THREAD *thread;
241 };
242
243 static struct statsd {
@@ -1078,8 +1078,10 @@ static int statsd_snd_callback(POLLINFO *pi, short int *events) {
1078 // --------------------------------------------------------------------------------------------------------------------
1079 // statsd child thread to collect metrics from network
1080
1081 -void statsd_collector_thread_cleanup(void *data) {
1082 - struct statsd_udp *d = data;
1081 +void statsd_collector_thread_cleanup(void *pptr) {
1082 + struct statsd_udp *d = CLEANUP_FUNCTION_GET_PTR(pptr);
1083 + if(!d) return;
1084 +
1085 spinlock_lock(&d->status->spinlock);
1086 d->status->running = false;
1087 spinlock_unlock(&d->status->spinlock);
@@ -1115,12 +1117,12 @@ void *statsd_collector_thread(void *ptr) {
1117 worker_register_job_name(WORKER_JOB_TYPE_RCV_DATA, "receive");
1118 worker_register_job_name(WORKER_JOB_TYPE_SND_DATA, "send");
1119
1118 - collector_info("STATSD collector thread started with taskid %d", gettid());
1120 + collector_info("STATSD collector thread started with taskid %d", gettid_cached());
1121
1122 struct statsd_udp *d = callocz(sizeof(struct statsd_udp), 1);
1123 d->status = status;
1124
1123 - netdata_thread_cleanup_push(statsd_collector_thread_cleanup, d);
1125 + CLEANUP_FUNCTION_REGISTER(statsd_collector_thread_cleanup) cleanup_ptr = d;
1126
1127 #ifdef HAVE_RECVMMSG
1128 d->type = STATSD_SOCKET_DATA_TYPE_UDP;
@@ -1154,7 +1156,6 @@ void *statsd_collector_thread(void *ptr) {
1156 , status->max_sockets
1157 );
1158
1157 - netdata_thread_cleanup_pop(1);
1159 return NULL;
1160 }
1161
@@ -2393,8 +2394,10 @@ static int statsd_listen_sockets_setup(void) {
2394 return listen_sockets_setup(&statsd.sockets);
2395 }
2396
2396 -static void statsd_main_cleanup(void *data) {
2397 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
2397 +static void statsd_main_cleanup(void *pptr) {
2398 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
2399 + if(!static_thread) return;
2400 +
2401 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
2402 collector_info("cleaning up...");
2403
@@ -2402,13 +2405,14 @@ static void statsd_main_cleanup(void *data) {
2405 int i;
2406 for (i = 0; i < statsd.threads; i++) {
2407 spinlock_lock(&statsd.collection_threads_status[i].spinlock);
2408 +
2409 if(statsd.collection_threads_status[i].running) {
2406 - collector_info("STATSD: stopping data collection thread %d...", i + 1);
2407 - netdata_thread_cancel(statsd.collection_threads_status[i].thread);
2410 + collector_info("STATSD: signalling data collection thread %d to stop...", i + 1);
2411 + nd_thread_signal_cancel(statsd.collection_threads_status[i].thread);
2412 }
2409 - else {
2413 + else
2414 collector_info("STATSD: data collection thread %d found stopped.", i + 1);
2411 - }
2415 +
2416 spinlock_unlock(&statsd.collection_threads_status[i].spinlock);
2417 }
2418 }
@@ -2445,6 +2449,8 @@ static void statsd_main_cleanup(void *data) {
2449 #endif
2450
2451 void *statsd_main(void *ptr) {
2452 + CLEANUP_FUNCTION_REGISTER(statsd_main_cleanup) cleanup_ptr = ptr;
2453 +
2454 worker_register("STATSDFLUSH");
2455 worker_register_job_name(WORKER_STATSD_FLUSH_GAUGES, "gauges");
2456 worker_register_job_name(WORKER_STATSD_FLUSH_COUNTERS, "counters");
@@ -2455,8 +2461,6 @@ void *statsd_main(void *ptr) {
2461 worker_register_job_name(WORKER_STATSD_FLUSH_DICTIONARIES, "dictionaries");
2462 worker_register_job_name(WORKER_STATSD_FLUSH_STATS, "statistics");
2463
2458 - netdata_thread_cleanup_push(statsd_main_cleanup, ptr);
2459 -
2464 statsd.gauges.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2465 statsd.meters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2466 statsd.counters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
@@ -2585,7 +2589,8 @@ void *statsd_main(void *ptr) {
2589 char tag[NETDATA_THREAD_TAG_MAX + 1];
2590 snprintfz(tag, NETDATA_THREAD_TAG_MAX, "STATSD_IN[%d]", i + 1);
2591 spinlock_init(&statsd.collection_threads_status[i].spinlock);
2588 - netdata_thread_create(&statsd.collection_threads_status[i].thread, tag, NETDATA_THREAD_OPTION_DEFAULT, statsd_collector_thread, &statsd.collection_threads_status[i]);
2592 + statsd.collection_threads_status[i].thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_DEFAULT,
2593 + statsd_collector_thread, &statsd.collection_threads_status[i]);
2594 }
2595
2596 // ----------------------------------------------------------------------------------------------------------------
@@ -2887,6 +2892,5 @@ void *statsd_main(void *ptr) {
2892 }
2893
2894 cleanup: ; // added semi-colon to prevent older gcc error: label at end of compound statement
2890 - netdata_thread_cleanup_pop(1);
2895 return NULL;
2896 }
src/collectors/systemd-journal.plugin/systemd-main.c
+2 -4
@@ -19,7 +19,7 @@ static bool journal_data_directories_exist() {
19
20 int main(int argc __maybe_unused, char **argv __maybe_unused) {
21 clocks_init();
22 - netdata_thread_set_tag("sd-jrnl.plugin");
22 + nd_thread_tag_set("sd-jrnl.plugin");
23 nd_log_initialize_for_external_plugins("systemd-journal.plugin");
24
25 netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
@@ -67,9 +67,7 @@ int main(int argc __maybe_unused, char **argv __maybe_unused) {
67 // ------------------------------------------------------------------------
68 // watcher thread
69
70 - netdata_thread_t watcher_thread;
71 - netdata_thread_create(&watcher_thread, "SDWATCH",
72 - NETDATA_THREAD_OPTION_DONT_LOG, journal_watcher_main, NULL);
70 + nd_thread_create("SDWATCH", NETDATA_THREAD_OPTION_DONT_LOG, journal_watcher_main, NULL);
71
72 // ------------------------------------------------------------------------
73 // the event loop for functions
src/collectors/tc.plugin/plugin_tc.c
+6 -8
@@ -848,12 +848,13 @@ static inline void tc_split_words(char *str, char **words, int max_words) {
848
849 static pid_t tc_child_pid = 0;
850
851 -static void tc_main_cleanup(void *ptr) {
852 - worker_unregister();
851 +static void tc_main_cleanup(void *pptr) {
852 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
853 + if(!static_thread) return;
854
855 + worker_unregister();
856 tc_device_index_destroy();
857
856 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
858 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
859
860 collector_info("cleaning up...");
@@ -892,6 +893,8 @@ static void tc_main_cleanup(void *ptr) {
893 #endif
894
895 void *tc_main(void *ptr) {
896 + CLEANUP_FUNCTION_REGISTER(tc_main_cleanup) cleanup_ptr = ptr;
897 +
898 worker_register("TC");
899 worker_register_job_name(WORKER_TC_CLASS, "class");
900 worker_register_job_name(WORKER_TC_BEGIN, "begin");
@@ -909,7 +912,6 @@ void *tc_main(void *ptr) {
912 worker_register_job_custom_metric(WORKER_TC_CLASSES, "number of classes", "classes", WORKER_METRIC_ABSOLUTE);
913
914 tc_device_index_init();
912 - netdata_thread_cleanup_push(tc_main_cleanup, ptr);
915
916 char command[FILENAME_MAX + 1];
917 char *words[PLUGINSD_MAX_WORDS] = { NULL };
@@ -1036,10 +1038,8 @@ void *tc_main(void *ptr) {
1038 // netdata_log_debug(D_TC_LOOP, "END line");
1039
1040 if(likely(device)) {
1039 - netdata_thread_disable_cancelability();
1041 tc_device_commit(device);
1042 // tc_device_free(device);
1042 - netdata_thread_enable_cancelability();
1043 }
1044
1045 device = NULL;
@@ -1177,7 +1177,5 @@ void *tc_main(void *ptr) {
1177 }
1178
1179 cleanup: ; // added semi-colon to prevent older gcc error: label at end of compound statement
1180 - worker_unregister();
1181 - netdata_thread_cleanup_pop(1);
1180 return NULL;
1181 }
src/collectors/timex.plugin/plugin_timex.c
+7 -8
@@ -1,7 +1,7 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "daemon/common.h"
4 -#include "libnetdata/os.h"
4 +#include "libnetdata/os/os.h"
5
6 #define PLUGIN_TIMEX_NAME "timex.plugin"
7
@@ -30,25 +30,25 @@ struct status_codes {
30 {NULL, 0, NULL},
31 };
32
33 -static void timex_main_cleanup(void *ptr)
33 +static void timex_main_cleanup(void *pptr)
34 {
35 - worker_unregister();
35 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
36
37 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
37 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
38
39 netdata_log_info("cleaning up...");
40 + worker_unregister();
41
42 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
43 }
44
45 void *timex_main(void *ptr)
46 {
47 + CLEANUP_FUNCTION_REGISTER(timex_main_cleanup) cleanup_ptr = ptr;
48 +
49 worker_register("TIMEX");
50 worker_register_job_name(0, "clock check");
51
50 - netdata_thread_cleanup_push(timex_main_cleanup, ptr);
51 -
52 int update_every = (int)config_get_number(CONFIG_SECTION_TIMEX, "update every", 10);
53 if (update_every < localhost->rrd_update_every)
54 update_every = localhost->rrd_update_every;
@@ -73,7 +73,7 @@ void *timex_main(void *ptr)
73 int sync_state = 0;
74 static int prev_sync_state = 0;
75
76 - sync_state = ADJUST_TIMEX(&timex_buf);
76 + sync_state = os_adjtimex(&timex_buf);
77
78 int non_seq_failure = (sync_state == -1 && prev_sync_state != -1);
79 prev_sync_state = sync_state;
@@ -171,6 +171,5 @@ void *timex_main(void *ptr)
171 }
172
173 exit:
174 - netdata_thread_cleanup_pop(1);
174 return NULL;
175 }
src/collectors/windows.plugin/GetSystemCPU.c new
+51
@@ -0,0 +1,51 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows_plugin.h"
4 +#include "windows-internals.h"
5 +
6 +int do_GetSystemCPU(int update_every, usec_t dt __maybe_unused) {
7 + FILETIME idleTime, kernelTime, userTime;
8 +
9 + if(GetSystemTimes(&idleTime, &kernelTime, &userTime) == 0) {
10 + netdata_log_error("GetSystemTimes() failed.");
11 + return 1;
12 + }
13 +
14 + ULONGLONG idle = FileTimeToULL(idleTime);
15 + ULONGLONG kernel = FileTimeToULL(kernelTime);
16 + ULONGLONG user = FileTimeToULL(userTime);
17 +
18 + // kernel includes idle
19 + kernel -= idle;
20 +
21 + static RRDSET *st = NULL;
22 + static RRDDIM *rd_user = NULL, *rd_kernel = NULL, *rd_idle = NULL;
23 + if(!st) {
24 + st = rrdset_create_localhost(
25 + "system"
26 + , "cpu"
27 + , NULL
28 + , "cpu"
29 + , "system.cpu"
30 + , "Total CPU utilization"
31 + , "percentage"
32 + , PLUGIN_WINDOWS_NAME
33 + , "GetSystemTimes"
34 + , NETDATA_CHART_PRIO_SYSTEM_CPU
35 + , update_every
36 + , RRDSET_TYPE_STACKED
37 + );
38 +
39 + rd_user = rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
40 + rd_kernel = rrddim_add(st, "system", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
41 + rd_idle = rrddim_add(st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
42 + rrddim_hide(st, "idle");
43 + }
44 +
45 + rrddim_set_by_pointer(st, rd_user, (collected_number )user);
46 + rrddim_set_by_pointer(st, rd_kernel, (collected_number )kernel);
47 + rrddim_set_by_pointer(st, rd_idle, (collected_number )idle);
48 + rrdset_done(st);
49 +
50 + return 0;
51 +}
src/collectors/windows.plugin/GetSystemRAM.c new
+34
@@ -0,0 +1,34 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows_plugin.h"
4 +#include "windows-internals.h"
5 +
6 +#define _COMMON_PLUGIN_NAME "windows.plugin"
7 +#define _COMMON_PLUGIN_MODULE_NAME "GetSystemRam"
8 +#include "../common-contexts/common-contexts.h"
9 +
10 +int do_GetSystemRAM(int update_every, usec_t dt __maybe_unused) {
11 + MEMORYSTATUSEX memStat = { 0 };
12 + memStat.dwLength = sizeof(memStat);
13 +
14 + if (!GlobalMemoryStatusEx(&memStat)) {
15 + netdata_log_error("GlobalMemoryStatusEx() failed.");
16 + return 1;
17 + }
18 +
19 + {
20 + ULONGLONG total_bytes = memStat.ullTotalPhys;
21 + ULONGLONG free_bytes = memStat.ullAvailPhys;
22 + ULONGLONG used_bytes = total_bytes - free_bytes;
23 + common_system_ram(free_bytes, used_bytes, update_every);
24 + }
25 +
26 + {
27 + DWORDLONG total_bytes = memStat.ullTotalPageFile;
28 + DWORDLONG free_bytes = memStat.ullAvailPageFile;
29 + DWORDLONG used_bytes = total_bytes - free_bytes;
30 + common_mem_swap(free_bytes, used_bytes, update_every);
31 + }
32 +
33 + return 0;
34 +}
src/collectors/windows.plugin/GetSystemUptime.c new
+34
@@ -0,0 +1,34 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows_plugin.h"
4 +#include "windows-internals.h"
5 +
6 +int do_GetSystemUptime(int update_every, usec_t dt __maybe_unused) {
7 + ULONGLONG uptime = GetTickCount64(); // in milliseconds
8 +
9 + static RRDSET *st = NULL;
10 + static RRDDIM *rd_uptime = NULL;
11 + if (!st) {
12 + st = rrdset_create_localhost(
13 + "system"
14 + , "uptime"
15 + , NULL
16 + , "uptime"
17 + , "system.uptime"
18 + , "System Uptime"
19 + , "seconds"
20 + , PLUGIN_WINDOWS_NAME
21 + , "GetSystemUptime"
22 + , NETDATA_CHART_PRIO_SYSTEM_UPTIME
23 + , update_every
24 + , RRDSET_TYPE_LINE
25 + );
26 +
27 + rd_uptime = rrddim_add(st, "uptime", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
28 + }
29 +
30 + rrddim_set_by_pointer(st, rd_uptime, (collected_number)uptime);
31 + rrdset_done(st);
32 +
33 + return 0;
34 +}
src/collectors/windows.plugin/perflib-dump.c new
+529
@@ -0,0 +1,529 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "perflib.h"
4 +#include "windows-internals.h"
5 +
6 +static const char *getCounterType(DWORD CounterType) {
7 + switch (CounterType) {
8 + case PERF_COUNTER_COUNTER:
9 + return "PERF_COUNTER_COUNTER";
10 +
11 + case PERF_COUNTER_TIMER:
12 + return "PERF_COUNTER_TIMER";
13 +
14 + case PERF_COUNTER_QUEUELEN_TYPE:
15 + return "PERF_COUNTER_QUEUELEN_TYPE";
16 +
17 + case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
18 + return "PERF_COUNTER_LARGE_QUEUELEN_TYPE";
19 +
20 + case PERF_COUNTER_100NS_QUEUELEN_TYPE:
21 + return "PERF_COUNTER_100NS_QUEUELEN_TYPE";
22 +
23 + case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
24 + return "PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE";
25 +
26 + case PERF_COUNTER_BULK_COUNT:
27 + return "PERF_COUNTER_BULK_COUNT";
28 +
29 + case PERF_COUNTER_TEXT:
30 + return "PERF_COUNTER_TEXT";
31 +
32 + case PERF_COUNTER_RAWCOUNT:
33 + return "PERF_COUNTER_RAWCOUNT";
34 +
35 + case PERF_COUNTER_LARGE_RAWCOUNT:
36 + return "PERF_COUNTER_LARGE_RAWCOUNT";
37 +
38 + case PERF_COUNTER_RAWCOUNT_HEX:
39 + return "PERF_COUNTER_RAWCOUNT_HEX";
40 +
41 + case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
42 + return "PERF_COUNTER_LARGE_RAWCOUNT_HEX";
43 +
44 + case PERF_SAMPLE_FRACTION:
45 + return "PERF_SAMPLE_FRACTION";
46 +
47 + case PERF_SAMPLE_COUNTER:
48 + return "PERF_SAMPLE_COUNTER";
49 +
50 + case PERF_COUNTER_NODATA:
51 + return "PERF_COUNTER_NODATA";
52 +
53 + case PERF_COUNTER_TIMER_INV:
54 + return "PERF_COUNTER_TIMER_INV";
55 +
56 + case PERF_SAMPLE_BASE:
57 + return "PERF_SAMPLE_BASE";
58 +
59 + case PERF_AVERAGE_TIMER:
60 + return "PERF_AVERAGE_TIMER";
61 +
62 + case PERF_AVERAGE_BASE:
63 + return "PERF_AVERAGE_BASE";
64 +
65 + case PERF_AVERAGE_BULK:
66 + return "PERF_AVERAGE_BULK";
67 +
68 + case PERF_OBJ_TIME_TIMER:
69 + return "PERF_OBJ_TIME_TIMER";
70 +
71 + case PERF_100NSEC_TIMER:
72 + return "PERF_100NSEC_TIMER";
73 +
74 + case PERF_100NSEC_TIMER_INV:
75 + return "PERF_100NSEC_TIMER_INV";
76 +
77 + case PERF_COUNTER_MULTI_TIMER:
78 + return "PERF_COUNTER_MULTI_TIMER";
79 +
80 + case PERF_COUNTER_MULTI_TIMER_INV:
81 + return "PERF_COUNTER_MULTI_TIMER_INV";
82 +
83 + case PERF_COUNTER_MULTI_BASE:
84 + return "PERF_COUNTER_MULTI_BASE";
85 +
86 + case PERF_100NSEC_MULTI_TIMER:
87 + return "PERF_100NSEC_MULTI_TIMER";
88 +
89 + case PERF_100NSEC_MULTI_TIMER_INV:
90 + return "PERF_100NSEC_MULTI_TIMER_INV";
91 +
92 + case PERF_RAW_FRACTION:
93 + return "PERF_RAW_FRACTION";
94 +
95 + case PERF_LARGE_RAW_FRACTION:
96 + return "PERF_LARGE_RAW_FRACTION";
97 +
98 + case PERF_RAW_BASE:
99 + return "PERF_RAW_BASE";
100 +
101 + case PERF_LARGE_RAW_BASE:
102 + return "PERF_LARGE_RAW_BASE";
103 +
104 + case PERF_ELAPSED_TIME:
105 + return "PERF_ELAPSED_TIME";
106 +
107 + case PERF_COUNTER_HISTOGRAM_TYPE:
108 + return "PERF_COUNTER_HISTOGRAM_TYPE";
109 +
110 + case PERF_COUNTER_DELTA:
111 + return "PERF_COUNTER_DELTA";
112 +
113 + case PERF_COUNTER_LARGE_DELTA:
114 + return "PERF_COUNTER_LARGE_DELTA";
115 +
116 + case PERF_PRECISION_SYSTEM_TIMER:
117 + return "PERF_PRECISION_SYSTEM_TIMER";
118 +
119 + case PERF_PRECISION_100NS_TIMER:
120 + return "PERF_PRECISION_100NS_TIMER";
121 +
122 + case PERF_PRECISION_OBJECT_TIMER:
123 + return "PERF_PRECISION_OBJECT_TIMER";
124 +
125 + default:
126 + return "UNKNOWN_COUNTER_TYPE";
127 + }
128 +}
129 +
130 +static const char *getCounterDescription(DWORD CounterType) {
131 + switch (CounterType) {
132 + case PERF_COUNTER_COUNTER:
133 + return "32-bit Counter. Divide delta by delta time. Display suffix: \"/sec\"";
134 +
135 + case PERF_COUNTER_TIMER:
136 + return "64-bit Timer. Divide delta by delta time. Display suffix: \"%\"";
137 +
138 + case PERF_COUNTER_QUEUELEN_TYPE:
139 + case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
140 + return "Queue Length Space-Time Product. Divide delta by delta time. No Display Suffix";
141 +
142 + case PERF_COUNTER_100NS_QUEUELEN_TYPE:
143 + return "Queue Length Space-Time Product using 100 Ns timebase. Divide delta by delta time. No Display Suffix";
144 +
145 + case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
146 + return "Queue Length Space-Time Product using Object specific timebase. Divide delta by delta time. No Display Suffix.";
147 +
148 + case PERF_COUNTER_BULK_COUNT:
149 + return "64-bit Counter. Divide delta by delta time. Display Suffix: \"/sec\"";
150 +
151 + case PERF_COUNTER_TEXT:
152 + return "Unicode text Display as text.";
153 +
154 + case PERF_COUNTER_RAWCOUNT:
155 + case PERF_COUNTER_LARGE_RAWCOUNT:
156 + return "A counter which should not be time averaged on display (such as an error counter on a serial line). Display as is. No Display Suffix.";
157 +
158 + case PERF_COUNTER_RAWCOUNT_HEX:
159 + case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
160 + return "Special case for RAWCOUNT which should be displayed in hex. A counter which should not be time averaged on display (such as an error counter on a serial line). Display as is. No Display Suffix.";
161 +
162 + case PERF_SAMPLE_FRACTION:
163 + return "A count which is either 1 or 0 on each sampling interrupt (% busy). Divide delta by delta base. Display Suffix: \"%\"";
164 +
165 + case PERF_SAMPLE_COUNTER:
166 + return "A count which is sampled on each sampling interrupt (queue length). Divide delta by delta time. No Display Suffix.";
167 +
168 + case PERF_COUNTER_NODATA:
169 + return "A label: no data is associated with this counter (it has 0 length). Do not display.";
170 +
171 + case PERF_COUNTER_TIMER_INV:
172 + return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 - delta divided by delta time. Display suffix: \"%\"";
173 +
174 + case PERF_SAMPLE_BASE:
175 + return "The divisor for a sample, used with the previous counter to form a sampled %. You must check for >0 before dividing by this! This counter will directly follow the numerator counter. It should not be displayed to the user.";
176 +
177 + case PERF_AVERAGE_TIMER:
178 + return "A timer which, when divided by an average base, produces a time in seconds which is the average time of some operation. This timer times total operations, and the base is the number of operations. Display Suffix: \"sec\"";
179 +
180 + case PERF_AVERAGE_BASE:
181 + return "Used as the denominator in the computation of time or count averages. Must directly follow the numerator counter. Not displayed to the user.";
182 +
183 + case PERF_AVERAGE_BULK:
184 + return "A bulk count which, when divided (typically) by the number of operations, gives (typically) the number of bytes per operation. No Display Suffix.";
185 +
186 + case PERF_OBJ_TIME_TIMER:
187 + return "64-bit Timer in object specific units. Display delta divided by delta time as returned in the object type header structure. Display suffix: \"%\"";
188 +
189 + case PERF_100NSEC_TIMER:
190 + return "64-bit Timer in 100 nsec units. Display delta divided by delta time. Display suffix: \"%\"";
191 +
192 + case PERF_100NSEC_TIMER_INV:
193 + return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 - delta divided by delta time. Display suffix: \"%\"";
194 +
195 + case PERF_COUNTER_MULTI_TIMER:
196 + return "64-bit Timer. Divide delta by delta time. Display suffix: \"%\". Timer for multiple instances, so result can exceed 100%.";
197 +
198 + case PERF_COUNTER_MULTI_TIMER_INV:
199 + return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 * _MULTI_BASE - delta divided by delta time. Display suffix: \"%\" Timer for multiple instances, so result can exceed 100%. Followed by a counter of type _MULTI_BASE.";
200 +
201 + case PERF_COUNTER_MULTI_BASE:
202 + return "Number of instances to which the preceding _MULTI_..._INV counter applies. Used as a factor to get the percentage.";
203 +
204 + case PERF_100NSEC_MULTI_TIMER:
205 + return "64-bit Timer in 100 nsec units. Display delta divided by delta time. Display suffix: \"%\" Timer for multiple instances, so result can exceed 100%.";
206 +
207 + case PERF_100NSEC_MULTI_TIMER_INV:
208 + return "64-bit Timer inverse (e.g., idle is measured, but display busy %). Display 100 * _MULTI_BASE - delta divided by delta time. Display suffix: \"%\" Timer for multiple instances, so result can exceed 100%. Followed by a counter of type _MULTI_BASE.";
209 +
210 + case PERF_LARGE_RAW_FRACTION:
211 + case PERF_RAW_FRACTION:
212 + return "Indicates the data is a fraction of the following counter which should not be time averaged on display (such as free space over total space.) Display as is. Display the quotient as \"%\"";
213 +
214 + case PERF_RAW_BASE:
215 + case PERF_LARGE_RAW_BASE:
216 + return "Indicates the data is a base for the preceding counter which should not be time averaged on display (such as free space over total space.)";
217 +
218 + case PERF_ELAPSED_TIME:
219 + return "The data collected in this counter is actually the start time of the item being measured. For display, this data is subtracted from the sample time to yield the elapsed time as the difference between the two. In the definition below, the PerfTime field of the Object contains the sample time as indicated by the PERF_OBJECT_TIMER bit and the difference is scaled by the PerfFreq of the Object to convert the time units into seconds.";
220 +
221 + case PERF_COUNTER_HISTOGRAM_TYPE:
222 + return "Counter type can be used with the preceding types to define a range of values to be displayed in a histogram.";
223 +
224 + case PERF_COUNTER_DELTA:
225 + case PERF_COUNTER_LARGE_DELTA:
226 + return "This counter is used to display the difference from one sample to the next. The counter value is a constantly increasing number and the value displayed is the difference between the current value and the previous value. Negative numbers are not allowed which shouldn't be a problem as long as the counter value is increasing or unchanged.";
227 +
228 + case PERF_PRECISION_SYSTEM_TIMER:
229 + return "The precision counters are timers that consist of two counter values:\r\n\t1) the count of elapsed time of the event being monitored\r\n\t2) the \"clock\" time in the same units\r\nthe precision timers are used where the standard system timers are not precise enough for accurate readings. It's assumed that the service providing the data is also providing a timestamp at the same time which will eliminate any error that may occur since some small and variable time elapses between the time the system timestamp is captured and when the data is collected from the performance DLL. Only in extreme cases has this been observed to be problematic.\r\nwhen using this type of timer, the definition of the PERF_PRECISION_TIMESTAMP counter must immediately follow the definition of the PERF_PRECISION_*_TIMER in the Object header\r\nThe timer used has the same frequency as the System Performance Timer";
230 +
231 + case PERF_PRECISION_100NS_TIMER:
232 + return "The precision counters are timers that consist of two counter values:\r\n\t1) the count of elapsed time of the event being monitored\r\n\t2) the \"clock\" time in the same units\r\nthe precision timers are used where the standard system timers are not precise enough for accurate readings. It's assumed that the service providing the data is also providing a timestamp at the same time which will eliminate any error that may occur since some small and variable time elapses between the time the system timestamp is captured and when the data is collected from the performance DLL. Only in extreme cases has this been observed to be problematic.\r\nwhen using this type of timer, the definition of the PERF_PRECISION_TIMESTAMP counter must immediately follow the definition of the PERF_PRECISION_*_TIMER in the Object header\r\nThe timer used has the same frequency as the 100 NanoSecond Timer";
233 +
234 + case PERF_PRECISION_OBJECT_TIMER:
235 + return "The precision counters are timers that consist of two counter values:\r\n\t1) the count of elapsed time of the event being monitored\r\n\t2) the \"clock\" time in the same units\r\nthe precision timers are used where the standard system timers are not precise enough for accurate readings. It's assumed that the service providing the data is also providing a timestamp at the same time which will eliminate any error that may occur since some small and variable time elapses between the time the system timestamp is captured and when the data is collected from the performance DLL. Only in extreme cases has this been observed to be problematic.\r\nwhen using this type of timer, the definition of the PERF_PRECISION_TIMESTAMP counter must immediately follow the definition of the PERF_PRECISION_*_TIMER in the Object header\r\nThe timer used is of the frequency specified in the Object header's. PerfFreq field (PerfTime is ignored)";
236 +
237 + default:
238 + return "";
239 + }
240 +}
241 +
242 +static const char *getCounterAlgorithm(DWORD CounterType) {
243 + switch (CounterType)
244 + {
245 + case PERF_COUNTER_COUNTER:
246 + case PERF_SAMPLE_COUNTER:
247 + case PERF_COUNTER_BULK_COUNT:
248 + return "(data1 - data0) / ((time1 - time0) / frequency)";
249 +
250 + case PERF_COUNTER_QUEUELEN_TYPE:
251 + case PERF_COUNTER_100NS_QUEUELEN_TYPE:
252 + case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
253 + case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
254 + case PERF_AVERAGE_BULK: // normally not displayed
255 + return "(data1 - data0) / (time1 - time0)";
256 +
257 + case PERF_OBJ_TIME_TIMER:
258 + case PERF_COUNTER_TIMER:
259 + case PERF_100NSEC_TIMER:
260 + case PERF_PRECISION_SYSTEM_TIMER:
261 + case PERF_PRECISION_100NS_TIMER:
262 + case PERF_PRECISION_OBJECT_TIMER:
263 + case PERF_SAMPLE_FRACTION:
264 + return "100 * (data1 - data0) / (time1 - time0)";
265 +
266 + case PERF_COUNTER_TIMER_INV:
267 + return "100 * (1 - ((data1 - data0) / (time1 - time0)))";
268 +
269 + case PERF_100NSEC_TIMER_INV:
270 + return "100 * (1- (data1 - data0) / (time1 - time0))";
271 +
272 + case PERF_COUNTER_MULTI_TIMER:
273 + return "100 * ((data1 - data0) / ((time1 - time0) / frequency1)) / multi1";
274 +
275 + case PERF_100NSEC_MULTI_TIMER:
276 + return "100 * ((data1 - data0) / (time1 - time0)) / multi1";
277 +
278 + case PERF_COUNTER_MULTI_TIMER_INV:
279 + case PERF_100NSEC_MULTI_TIMER_INV:
280 + return "100 * (multi1 - ((data1 - data0) / (time1 - time0)))";
281 +
282 + case PERF_COUNTER_RAWCOUNT:
283 + case PERF_COUNTER_LARGE_RAWCOUNT:
284 + return "data0";
285 +
286 + case PERF_COUNTER_RAWCOUNT_HEX:
287 + case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
288 + return "hex(data0)";
289 +
290 + case PERF_COUNTER_DELTA:
291 + case PERF_COUNTER_LARGE_DELTA:
292 + return "data1 - data0";
293 +
294 + case PERF_RAW_FRACTION:
295 + case PERF_LARGE_RAW_FRACTION:
296 + return "100 * data0 / time0";
297 +
298 + case PERF_AVERAGE_TIMER:
299 + return "((data1 - data0) / frequency1) / (time1 - time0)";
300 +
301 + case PERF_ELAPSED_TIME:
302 + return "(time0 - data0) / frequency0";
303 +
304 + case PERF_COUNTER_TEXT:
305 + case PERF_SAMPLE_BASE:
306 + case PERF_AVERAGE_BASE:
307 + case PERF_COUNTER_MULTI_BASE:
308 + case PERF_RAW_BASE:
309 + case PERF_COUNTER_NODATA:
310 + case PERF_PRECISION_TIMESTAMP:
311 + default:
312 + return "";
313 + }
314 +}
315 +
316 +void dumpSystemTime(BUFFER *wb, SYSTEMTIME *st) {
317 + buffer_json_member_add_uint64(wb, "Year", st->wYear);
318 + buffer_json_member_add_uint64(wb, "Month", st->wMonth);
319 + buffer_json_member_add_uint64(wb, "DayOfWeek", st->wDayOfWeek);
320 + buffer_json_member_add_uint64(wb, "Day", st->wDay);
321 + buffer_json_member_add_uint64(wb, "Hour", st->wHour);
322 + buffer_json_member_add_uint64(wb, "Minute", st->wMinute);
323 + buffer_json_member_add_uint64(wb, "Second", st->wSecond);
324 + buffer_json_member_add_uint64(wb, "Milliseconds", st->wMilliseconds);
325 +}
326 +
327 +bool dumpDataCb(PERF_DATA_BLOCK *pDataBlock, void *data) {
328 + char name[4096];
329 + if(!getSystemName(pDataBlock, name, sizeof(name)))
330 + strncpyz(name, "[failed]", sizeof(name) - 1);
331 +
332 + BUFFER *wb = data;
333 + buffer_json_member_add_string(wb, "SystemName", name);
334 +
335 + // Number of types of objects being reported
336 + // Type: DWORD
337 + buffer_json_member_add_int64(wb, "NumObjectTypes", pDataBlock->NumObjectTypes);
338 +
339 + buffer_json_member_add_int64(wb, "LittleEndian", pDataBlock->LittleEndian);
340 +
341 + // Version and Revision of these data structures.
342 + // Version starts at 1.
343 + // Revision starts at 0 for each Version.
344 + // Type: DWORD
345 + buffer_json_member_add_int64(wb, "Version", pDataBlock->Version);
346 + buffer_json_member_add_int64(wb, "Revision", pDataBlock->Revision);
347 +
348 + // Object Title Index of default object to display when data from this system is retrieved
349 + // (-1 = none, but this is not expected to be used)
350 + // Type: LONG
351 + buffer_json_member_add_int64(wb, "DefaultObject", pDataBlock->DefaultObject);
352 +
353 + // Performance counter frequency at the system under measurement
354 + // Type: LARGE_INTEGER
355 + buffer_json_member_add_int64(wb, "PerfFreq", pDataBlock->PerfFreq.QuadPart);
356 +
357 + // Performance counter value at the system under measurement
358 + // Type: LARGE_INTEGER
359 + buffer_json_member_add_int64(wb, "PerfTime", pDataBlock->PerfTime.QuadPart);
360 +
361 + // Performance counter time in 100 nsec units at the system under measurement
362 + // Type: LARGE_INTEGER
363 + buffer_json_member_add_int64(wb, "PerfTime100nSec", pDataBlock->PerfTime100nSec.QuadPart);
364 +
365 + // Time at the system under measurement in UTC
366 + // Type: SYSTEMTIME
367 + buffer_json_member_add_object(wb, "SystemTime");
368 + dumpSystemTime(wb, &pDataBlock->SystemTime);
369 + buffer_json_object_close(wb);
370 +
371 + if(pDataBlock->NumObjectTypes)
372 + buffer_json_member_add_array(wb, "Objects");
373 +
374 + return true;
375 +}
376 +
377 +static const char *GetDetailLevel(DWORD num) {
378 + switch (num) {
379 + case 100:
380 + return "Novice (100)";
381 + case 200:
382 + return "Advanced (200)";
383 + case 300:
384 + return "Expert (300)";
385 + case 400:
386 + return "Wizard (400)";
387 +
388 + default:
389 + return "Unknown";
390 + }
391 +}
392 +
393 +bool dumpObjectCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, void *data) {
394 + (void)pDataBlock;
395 + BUFFER *wb = data;
396 + if(!pObjectType) {
397 + buffer_json_array_close(wb); // instances or counters
398 + buffer_json_object_close(wb); // objectType
399 + return true;
400 + }
401 +
402 + buffer_json_add_array_item_object(wb); // objectType
403 + buffer_json_member_add_int64(wb, "NameId", pObjectType->ObjectNameTitleIndex);
404 + buffer_json_member_add_string(wb, "Name", RegistryFindNameByID(pObjectType->ObjectNameTitleIndex));
405 + buffer_json_member_add_int64(wb, "HelpId", pObjectType->ObjectHelpTitleIndex);
406 + buffer_json_member_add_string(wb, "Help", RegistryFindHelpByID(pObjectType->ObjectHelpTitleIndex));
407 + buffer_json_member_add_int64(wb, "NumInstances", pObjectType->NumInstances);
408 + buffer_json_member_add_int64(wb, "NumCounters", pObjectType->NumCounters);
409 + buffer_json_member_add_int64(wb, "PerfTime", pObjectType->PerfTime.QuadPart);
410 + buffer_json_member_add_int64(wb, "PerfFreq", pObjectType->PerfFreq.QuadPart);
411 + buffer_json_member_add_int64(wb, "CodePage", pObjectType->CodePage);
412 + buffer_json_member_add_int64(wb, "DefaultCounter", pObjectType->DefaultCounter);
413 + buffer_json_member_add_string(wb, "DetailLevel", GetDetailLevel(pObjectType->DetailLevel));
414 +
415 + if(ObjectTypeHasInstances(pDataBlock, pObjectType))
416 + buffer_json_member_add_array(wb, "Instances");
417 + else
418 + buffer_json_member_add_array(wb, "Counters");
419 +
420 + return true;
421 +}
422 +
423 +bool dumpInstanceCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, void *data) {
424 + (void)pDataBlock;
425 + BUFFER *wb = data;
426 + if(!pInstance) {
427 + buffer_json_array_close(wb); // counters
428 + buffer_json_object_close(wb); // instance
429 + return true;
430 + }
431 +
432 + char name[4096];
433 + if(!getInstanceName(pDataBlock, pObjectType, pInstance, name, sizeof(name)))
434 + strncpyz(name, "[failed]", sizeof(name) - 1);
435 +
436 + buffer_json_add_array_item_object(wb);
437 + buffer_json_member_add_string(wb, "Instance", name);
438 + buffer_json_member_add_int64(wb, "UniqueID", pInstance->UniqueID);
439 + buffer_json_member_add_array(wb, "Labels");
440 + {
441 + buffer_json_add_array_item_object(wb);
442 + {
443 + buffer_json_member_add_string(wb, "key", RegistryFindNameByID(pObjectType->ObjectNameTitleIndex));
444 + buffer_json_member_add_string(wb, "value", name);
445 + }
446 + buffer_json_object_close(wb);
447 +
448 + if(pInstance->ParentObjectTitleIndex) {
449 + PERF_INSTANCE_DEFINITION *pi = pInstance;
450 + while(pi->ParentObjectTitleIndex) {
451 + PERF_OBJECT_TYPE *po = getObjectTypeByIndex(pDataBlock, pInstance->ParentObjectTitleIndex);
452 + pi = getInstanceByPosition(pDataBlock, po, pi->ParentObjectInstance);
453 +
454 + if(!getInstanceName(pDataBlock, po, pi, name, sizeof(name)))
455 + strncpyz(name, "[failed]", sizeof(name) - 1);
456 +
457 + buffer_json_add_array_item_object(wb);
458 + {
459 + buffer_json_member_add_string(wb, "key", RegistryFindNameByID(po->ObjectNameTitleIndex));
460 + buffer_json_member_add_string(wb, "value", name);
461 + }
462 + buffer_json_object_close(wb);
463 + }
464 + }
465 + }
466 + buffer_json_array_close(wb); // rrdlabels
467 +
468 + buffer_json_member_add_array(wb, "Counters");
469 + return true;
470 +}
471 +
472 +void dumpSample(BUFFER *wb, RAW_DATA *d) {
473 + buffer_json_member_add_object(wb, "Value");
474 + buffer_json_member_add_uint64(wb, "data", d->Data);
475 + buffer_json_member_add_int64(wb, "time", d->Time);
476 + buffer_json_member_add_uint64(wb, "type", d->CounterType);
477 + buffer_json_member_add_int64(wb, "multi", d->MultiCounterData);
478 + buffer_json_member_add_int64(wb, "frequency", d->Frequency);
479 + buffer_json_object_close(wb);
480 +}
481 +
482 +bool dumpCounterCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_COUNTER_DEFINITION *pCounter, RAW_DATA *sample, void *data) {
483 + (void)pDataBlock;
484 + (void)pObjectType;
485 + BUFFER *wb = data;
486 + buffer_json_add_array_item_object(wb);
487 + buffer_json_member_add_string(wb, "Counter", RegistryFindNameByID(pCounter->CounterNameTitleIndex));
488 + dumpSample(wb, sample);
489 + buffer_json_member_add_string(wb, "Help", RegistryFindHelpByID(pCounter->CounterHelpTitleIndex));
490 + buffer_json_member_add_string(wb, "Type", getCounterType(pCounter->CounterType));
491 + buffer_json_member_add_string(wb, "Algorithm", getCounterAlgorithm(pCounter->CounterType));
492 + buffer_json_member_add_string(wb, "Description", getCounterDescription(pCounter->CounterType));
493 + buffer_json_object_close(wb);
494 + return true;
495 +}
496 +
497 +bool dumpInstanceCounterCb(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, PERF_COUNTER_DEFINITION *pCounter, RAW_DATA *sample, void *data) {
498 + (void)pInstance;
499 + return dumpCounterCb(pDataBlock, pObjectType, pCounter, sample, data);
500 +}
501 +
502 +
503 +int windows_perflib_dump(const char *key) {
504 + if(key && !*key)
505 + key = NULL;
506 +
507 + PerflibNamesRegistryInitialize();
508 +
509 + DWORD id = 0;
510 + if(key) {
511 + id = RegistryFindIDByName(key);
512 + if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND) {
513 + fprintf(stderr, "Cannot find key '%s' in Windows Performance Counters Registry.\n", key);
514 + exit(1);
515 + }
516 + }
517 +
518 + CLEAN_BUFFER *wb = buffer_create(0, NULL);
519 + buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
520 +
521 + perflibQueryAndTraverse(id, dumpDataCb, dumpObjectCb, dumpInstanceCb, dumpInstanceCounterCb, dumpCounterCb, wb);
522 +
523 + buffer_json_finalize(wb);
524 + printf("\n%s\n", buffer_tostring(wb));
525 +
526 + perflibFreePerformanceData();
527 +
528 + return 0;
529 +}
src/collectors/windows.plugin/perflib-memory.c new
+65
@@ -0,0 +1,65 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows_plugin.h"
4 +#include "windows-internals.h"
5 +
6 +#define _COMMON_PLUGIN_NAME "windows.plugin"
7 +#define _COMMON_PLUGIN_MODULE_NAME "PerflibMemory"
8 +#include "../common-contexts/common-contexts.h"
9 +
10 +static void initialize(void) {
11 + ;
12 +}
13 +
14 +static bool do_memory(PERF_DATA_BLOCK *pDataBlock, int update_every) {
15 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "Memory");
16 + if (!pObjectType)
17 + return false;
18 +
19 + static COUNTER_DATA pagesPerSec = { .key = "Pages/sec" };
20 + static COUNTER_DATA pageFaultsPerSec = { .key = "Page Faults/sec" };
21 +
22 + if(perflibGetObjectCounter(pDataBlock, pObjectType, &pageFaultsPerSec) &&
23 + perflibGetObjectCounter(pDataBlock, pObjectType, &pagesPerSec)) {
24 + ULONGLONG total = pageFaultsPerSec.current.Data;
25 + ULONGLONG major = pagesPerSec.current.Data;
26 + ULONGLONG minor = (total > major) ? total - major : 0;
27 + common_mem_pgfaults(minor, major, update_every);
28 + }
29 +
30 + static COUNTER_DATA availableBytes = { .key = "Available Bytes" };
31 + static COUNTER_DATA availableKBytes = { .key = "Available KBytes" };
32 + static COUNTER_DATA availableMBytes = { .key = "Available MBytes" };
33 + ULONGLONG available_bytes = 0;
34 +
35 + if(perflibGetObjectCounter(pDataBlock, pObjectType, &availableBytes))
36 + available_bytes = availableBytes.current.Data;
37 + else if(perflibGetObjectCounter(pDataBlock, pObjectType, &availableKBytes))
38 + available_bytes = availableKBytes.current.Data * 1024;
39 + else if(perflibGetObjectCounter(pDataBlock, pObjectType, &availableMBytes))
40 + available_bytes = availableMBytes.current.Data * 1024;
41 +
42 + common_mem_available(available_bytes, update_every);
43 +
44 + return true;
45 +}
46 +
47 +int do_PerflibMemory(int update_every, usec_t dt __maybe_unused) {
48 + static bool initialized = false;
49 +
50 + if(unlikely(!initialized)) {
51 + initialize();
52 + initialized = true;
53 + }
54 +
55 + DWORD id = RegistryFindIDByName("Memory");
56 + if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
57 + return -1;
58 +
59 + PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
60 + if(!pDataBlock) return -1;
61 +
62 + do_memory(pDataBlock, update_every);
63 +
64 + return 0;
65 +}
src/collectors/windows.plugin/perflib-names.c new
+242
@@ -0,0 +1,242 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "perflib.h"
4 +
5 +#define REGISTRY_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"
6 +
7 +typedef struct perflib_registry {
8 + DWORD id;
9 + char *key;
10 + char *help;
11 +} perfLibRegistryEntry;
12 +
13 +static inline bool compare_perfLibRegistryEntry(const char *k1, const char *k2) {
14 + return strcmp(k1, k2) == 0;
15 +}
16 +
17 +static inline const char *value2key_perfLibRegistryEntry(perfLibRegistryEntry *entry) {
18 + return entry->key;
19 +}
20 +
21 +#define SIMPLE_HASHTABLE_COMPARE_KEYS_FUNCTION compare_perfLibRegistryEntry
22 +#define SIMPLE_HASHTABLE_VALUE2KEY_FUNCTION value2key_perfLibRegistryEntry
23 +#define SIMPLE_HASHTABLE_KEY_TYPE const char
24 +#define SIMPLE_HASHTABLE_VALUE_TYPE perfLibRegistryEntry
25 +#define SIMPLE_HASHTABLE_NAME _PERFLIB
26 +#include "libnetdata/simple_hashtable.h"
27 +
28 +static struct {
29 + SPINLOCK spinlock;
30 + size_t size;
31 + perfLibRegistryEntry **array;
32 + struct simple_hashtable_PERFLIB hashtable;
33 + FILETIME lastWriteTime;
34 +} names_globals = {
35 + .spinlock = NETDATA_SPINLOCK_INITIALIZER,
36 + .size = 0,
37 + .array = NULL,
38 +};
39 +
40 +DWORD RegistryFindIDByName(const char *name) {
41 + DWORD rc = PERFLIB_REGISTRY_NAME_NOT_FOUND;
42 +
43 + spinlock_lock(&names_globals.spinlock);
44 + XXH64_hash_t hash = XXH3_64bits((void *)name, strlen(name));
45 + SIMPLE_HASHTABLE_SLOT_PERFLIB *sl = simple_hashtable_get_slot_PERFLIB(&names_globals.hashtable, hash, name, false);
46 + perfLibRegistryEntry *e = SIMPLE_HASHTABLE_SLOT_DATA(sl);
47 + if(e) rc = e->id;
48 + spinlock_unlock(&names_globals.spinlock);
49 +
50 + return rc;
51 +}
52 +
53 +static inline void RegistryAddToHashTable_unsafe(perfLibRegistryEntry *entry) {
54 + XXH64_hash_t hash = XXH3_64bits((void *)entry->key, strlen(entry->key));
55 + SIMPLE_HASHTABLE_SLOT_PERFLIB *sl = simple_hashtable_get_slot_PERFLIB(&names_globals.hashtable, hash, entry->key, true);
56 + perfLibRegistryEntry *e = SIMPLE_HASHTABLE_SLOT_DATA(sl);
57 + if(!e || e->id > entry->id)
58 + simple_hashtable_set_slot_PERFLIB(&names_globals.hashtable, sl, hash, entry);
59 +}
60 +
61 +static void RegistrySetData_unsafe(DWORD id, const char *key, const char *help) {
62 + if(id >= names_globals.size) {
63 + // increase the size of the array
64 +
65 + size_t old_size = names_globals.size;
66 +
67 + if(!names_globals.size)
68 + names_globals.size = 20000;
69 + else
70 + names_globals.size *= 2;
71 +
72 + names_globals.array = reallocz(names_globals.array, names_globals.size * sizeof(perfLibRegistryEntry *));
73 +
74 + memset(names_globals.array + old_size, 0, (names_globals.size - old_size) * sizeof(perfLibRegistryEntry *));
75 + }
76 +
77 + perfLibRegistryEntry *entry = names_globals.array[id];
78 + if(!entry)
79 + entry = names_globals.array[id] = (perfLibRegistryEntry *)calloc(1, sizeof(perfLibRegistryEntry));
80 +
81 + bool add_to_hash = false;
82 + if(key && !entry->key) {
83 + entry->key = strdup(key);
84 + add_to_hash = true;
85 + }
86 +
87 + if(help && !entry->help)
88 + entry->help = strdup(help);
89 +
90 + entry->id = id;
91 +
92 + if(add_to_hash)
93 + RegistryAddToHashTable_unsafe(entry);
94 +}
95 +
96 +const char *RegistryFindNameByID(DWORD id) {
97 + const char *s = "";
98 + spinlock_lock(&names_globals.spinlock);
99 +
100 + if(id < names_globals.size) {
101 + perfLibRegistryEntry *titleEntry = names_globals.array[id];
102 + if(titleEntry && titleEntry->key)
103 + s = titleEntry->key;
104 + }
105 +
106 + spinlock_unlock(&names_globals.spinlock);
107 + return s;
108 +}
109 +
110 +const char *RegistryFindHelpByID(DWORD id) {
111 + const char *s = "";
112 + spinlock_lock(&names_globals.spinlock);
113 +
114 + if(id < names_globals.size) {
115 + perfLibRegistryEntry *titleEntry = names_globals.array[id];
116 + if(titleEntry && titleEntry->help)
117 + s = titleEntry->help;
118 + }
119 +
120 + spinlock_unlock(&names_globals.spinlock);
121 + return s;
122 +}
123 +
124 +// ----------------------------------------------------------
125 +
126 +static inline void readRegistryKeys_unsafe(BOOL helps) {
127 + TCHAR *pData = NULL;
128 +
129 + HKEY hKey;
130 + DWORD dwType;
131 + DWORD dwSize = 0;
132 + LONG lStatus;
133 +
134 + LPCSTR valueName;
135 + if(helps)
136 + valueName = TEXT("help");
137 + else
138 + valueName = TEXT("CounterDefinition");
139 +
140 + // Open the key for the English counters
141 + lStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(REGISTRY_KEY), 0, KEY_READ, &hKey);
142 + if (lStatus != ERROR_SUCCESS) {
143 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
144 + "Failed to open registry key HKEY_LOCAL_MACHINE, subkey '%s', error %ld\n", REGISTRY_KEY, (long)lStatus);
145 + return;
146 + }
147 +
148 + // Get the size of the 'Counters' data
149 + lStatus = RegQueryValueEx(hKey, valueName, NULL, &dwType, NULL, &dwSize);
150 + if (lStatus != ERROR_SUCCESS) {
151 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
152 + "Failed to get registry key HKEY_LOCAL_MACHINE, subkey '%s', value '%s', size of data, error %ld\n",
153 + REGISTRY_KEY, (const char *)valueName, (long)lStatus);
154 + goto cleanup;
155 + }
156 +
157 + // Allocate memory for the data
158 + pData = mallocz(dwSize);
159 +
160 + // Read the 'Counters' data
161 + lStatus = RegQueryValueEx(hKey, valueName, NULL, &dwType, (LPBYTE)pData, &dwSize);
162 + if (lStatus != ERROR_SUCCESS || dwType != REG_MULTI_SZ) {
163 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
164 + "Failed to get registry key HKEY_LOCAL_MACHINE, subkey '%s', value '%s', data, error %ld\n",
165 + REGISTRY_KEY, (const char *)valueName, (long)lStatus);
166 + goto cleanup;
167 + }
168 +
169 + // Process the counter data
170 + TCHAR *ptr = pData;
171 + while (*ptr) {
172 + TCHAR *sid = ptr; // First string is the ID
173 + ptr += lstrlen(ptr) + 1; // Move to the next string
174 + TCHAR *name = ptr; // Second string is the name
175 + ptr += lstrlen(ptr) + 1; // Move to the next pair
176 +
177 + DWORD id = strtoul(sid, NULL, 10);
178 +
179 + if(helps)
180 + RegistrySetData_unsafe(id, NULL, name);
181 + else
182 + RegistrySetData_unsafe(id, name, NULL);
183 + }
184 +
185 +cleanup:
186 + if(pData) freez(pData);
187 + RegCloseKey(hKey);
188 +}
189 +
190 +static BOOL RegistryKeyModification(FILETIME *lastWriteTime) {
191 + HKEY hKey;
192 + LONG lResult;
193 + BOOL ret = FALSE;
194 +
195 + // Open the registry key
196 + lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(REGISTRY_KEY), 0, KEY_READ, &hKey);
197 + if (lResult != ERROR_SUCCESS) {
198 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
199 + "Failed to open registry key HKEY_LOCAL_MACHINE, subkey '%s', error %ld\n", REGISTRY_KEY, (long)lResult);
200 + return FALSE;
201 + }
202 +
203 + // Get the last write time
204 + lResult = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, lastWriteTime);
205 + if (lResult != ERROR_SUCCESS) {
206 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
207 + "Failed to query registry key HKEY_LOCAL_MACHINE, subkey '%s', last write time, error %ld\n", REGISTRY_KEY, (long)lResult);
208 + ret = FALSE;
209 + }
210 + else
211 + ret = TRUE;
212 +
213 + RegCloseKey(hKey);
214 + return ret;
215 +}
216 +
217 +static inline void RegistryFetchAll_unsafe(void) {
218 + readRegistryKeys_unsafe(FALSE);
219 + readRegistryKeys_unsafe(TRUE);
220 +}
221 +
222 +void PerflibNamesRegistryInitialize(void) {
223 + spinlock_lock(&names_globals.spinlock);
224 + simple_hashtable_init_PERFLIB(&names_globals.hashtable, 20000);
225 + RegistryKeyModification(&names_globals.lastWriteTime);
226 + RegistryFetchAll_unsafe();
227 + spinlock_unlock(&names_globals.spinlock);
228 +}
229 +
230 +void PerflibNamesRegistryUpdate(void) {
231 + FILETIME lastWriteTime = { 0 };
232 + RegistryKeyModification(&lastWriteTime);
233 +
234 + if(CompareFileTime(&lastWriteTime, &names_globals.lastWriteTime) > 0) {
235 + spinlock_lock(&names_globals.spinlock);
236 + if(CompareFileTime(&lastWriteTime, &names_globals.lastWriteTime) > 0) {
237 + names_globals.lastWriteTime = lastWriteTime;
238 + RegistryFetchAll_unsafe();
239 + }
240 + spinlock_unlock(&names_globals.spinlock);
241 + }
242 +}
src/collectors/windows.plugin/perflib-network.c new
+453
@@ -0,0 +1,453 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows_plugin.h"
4 +#include "windows-internals.h"
5 +
6 +// --------------------------------------------------------------------------------------------------------------------
7 +// network protocols
8 +
9 +struct network_protocol {
10 + const char *protocol;
11 +
12 + struct {
13 + COUNTER_DATA received;
14 + COUNTER_DATA sent;
15 + COUNTER_DATA delivered;
16 + COUNTER_DATA forwarded;
17 + RRDSET *st;
18 + RRDDIM *rd_received;
19 + RRDDIM *rd_sent;
20 + RRDDIM *rd_forwarded;
21 + RRDDIM *rd_delivered;
22 + const char *type;
23 + const char *id;
24 + const char *family;
25 + const char *context;
26 + const char *title;
27 + long priority;
28 + } packets;
29 +
30 +} networks[] = {
31 + {
32 + .protocol = "IPv4",
33 + .packets = {
34 + .received = { .key = "Datagrams Received/sec" },
35 + .sent = { .key = "Datagrams Sent/sec" },
36 + .delivered = { .key = "Datagrams Received Delivered/sec" },
37 + .forwarded = { .key = "Datagrams Forwarded/sec" },
38 + .type = "ipv4",
39 + .id = "packets",
40 + .family = "packets",
41 + .context = "ipv4.packets",
42 + .title = "IPv4 Packets",
43 + .priority = NETDATA_CHART_PRIO_IPV4_PACKETS,
44 + },
45 + },
46 + {
47 + .protocol = "IPv6",
48 + .packets = {
49 + .received = { .key = "Datagrams Received/sec" },
50 + .sent = { .key = "Datagrams Sent/sec" },
51 + .delivered = { .key = "Datagrams Received Delivered/sec" },
52 + .forwarded = { .key = "Datagrams Forwarded/sec" },
53 + .type = "ipv6",
54 + .id = "packets",
55 + .family = "packets",
56 + .context = "ip6.packets",
57 + .title = "IPv6 Packets",
58 + .priority = NETDATA_CHART_PRIO_IPV6_PACKETS,
59 + },
60 + },
61 + {
62 + .protocol = "TCPv4",
63 + .packets = {
64 + .received = { .key = "Segments Received/sec" },
65 + .sent = { .key = "Segments Sent/sec" },
66 + .type = "ipv4",
67 + .id = "tcppackets",
68 + .family = "tcp",
69 + .context = "ipv4.tcppackets",
70 + .title = "IPv4 TCP Packets",
71 + .priority = NETDATA_CHART_PRIO_IPV4_TCP_PACKETS,
72 + },
73 + },
74 + {
75 + .protocol = "TCPv6",
76 + .packets = {
77 + .received = { .key = "Segments Received/sec" },
78 + .sent = { .key = "Segments Sent/sec" },
79 + .type = "ipv6",
80 + .id = "tcppackets",
81 + .family = "tcp6",
82 + .context = "ipv6.tcppackets",
83 + .title = "IPv6 TCP Packets",
84 + .priority = NETDATA_CHART_PRIO_IPV6_TCP_PACKETS,
85 + },
86 + },
87 + {
88 + .protocol = "UDPv4",
89 + .packets = {
90 + .received = { .key = "Datagrams Received/sec" },
91 + .sent = { .key = "Datagrams Sent/sec" },
92 + .type = "ipv4",
93 + .id = "udppackets",
94 + .family = "udp",
95 + .context = "ipv4.udppackets",
96 + .title = "IPv4 UDP Packets",
97 + .priority = NETDATA_CHART_PRIO_IPV4_UDP_PACKETS,
98 + },
99 + },
100 + {
101 + .protocol = "UDPv6",
102 + .packets = {
103 + .received = { .key = "Datagrams Received/sec" },
104 + .sent = { .key = "Datagrams Sent/sec" },
105 + .type = "ipv6",
106 + .id = "udppackets",
107 + .family = "udp6",
108 + .context = "ipv6.udppackets",
109 + .title = "IPv6 UDP Packets",
110 + .priority = NETDATA_CHART_PRIO_IPV6_UDP_PACKETS,
111 + },
112 + },
113 + {
114 + .protocol = "ICMP",
115 + .packets = {
116 + .received = { .key = "Messages Received/sec" },
117 + .sent = { .key = "Messages Sent/sec" },
118 + .type = "ipv4",
119 + .id = "icmp",
120 + .family = "icmp",
121 + .context = "ipv4.icmp",
122 + .title = "IPv4 ICMP Packets",
123 + .priority = NETDATA_CHART_PRIO_IPV4_ICMP_PACKETS,
124 + },
125 + },
126 + {
127 + .protocol = "ICMPv6",
128 + .packets = {
129 + .received = { .key = "Messages Received/sec" },
130 + .sent = { .key = "Messages Sent/sec" },
131 + .type = "ipv6",
132 + .id = "icmp",
133 + .family = "icmp6",
134 + .context = "ipv6.icmp",
135 + .title = "IPv6 ICMP Packets",
136 + .priority = NETDATA_CHART_PRIO_IPV6_ICMP_PACKETS,
137 + },
138 + },
139 +
140 + // terminator
141 + {
142 + .protocol = NULL,
143 + }
144 +};
145 +
146 +struct network_protocol tcp46 = {
147 + .packets = {
148 + .type = "ip",
149 + .id = "tcppackets",
150 + .family = "tcp",
151 + .context = "ip.tcppackets",
152 + .title = "TCP Packets",
153 + .priority = NETDATA_CHART_PRIO_IP_TCP_PACKETS,
154 + }
155 +};
156 +
157 +static void protocol_packets_chart_update(struct network_protocol *p, int update_every) {
158 + if(!p->packets.st) {
159 + p->packets.st = rrdset_create_localhost(
160 + p->packets.type
161 + , p->packets.id
162 + , NULL
163 + , p->packets.family
164 + , NULL
165 + , p->packets.title
166 + , "packets/s"
167 + , PLUGIN_WINDOWS_NAME
168 + , "PerflibNetwork"
169 + , p->packets.priority
170 + , update_every
171 + , RRDSET_TYPE_AREA
172 + );
173 +
174 + p->packets.rd_received = rrddim_add(p->packets.st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
175 + p->packets.rd_sent = rrddim_add(p->packets.st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
176 +
177 + if(p->packets.forwarded.key)
178 + p->packets.rd_forwarded = rrddim_add(p->packets.st, "forwarded", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
179 +
180 + if(p->packets.delivered.key)
181 + p->packets.rd_delivered = rrddim_add(p->packets.st, "delivered", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
182 + }
183 +
184 + if(p->packets.received.updated)
185 + rrddim_set_by_pointer(p->packets.st, p->packets.rd_received, (collected_number)p->packets.received.current.Data);
186 +
187 + if(p->packets.sent.updated)
188 + rrddim_set_by_pointer(p->packets.st, p->packets.rd_sent, (collected_number)p->packets.sent.current.Data);
189 +
190 + if(p->packets.forwarded.key && p->packets.forwarded.updated)
191 + rrddim_set_by_pointer(p->packets.st, p->packets.rd_forwarded, (collected_number)p->packets.forwarded.current.Data);
192 +
193 + if(p->packets.delivered.key && p->packets.delivered.updated)
194 + rrddim_set_by_pointer(p->packets.st, p->packets.rd_delivered, (collected_number)p->packets.delivered.current.Data);
195 +
196 + rrdset_done(p->packets.st);
197 +}
198 +
199 +static bool do_network_protocol(PERF_DATA_BLOCK *pDataBlock, int update_every, struct network_protocol *p) {
200 + if(!p || !p->protocol) return false;
201 +
202 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, p->protocol);
203 + if(!pObjectType) return false;
204 +
205 + size_t packets = 0;
206 + if(p->packets.received.key)
207 + packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.received) ? 1 : 0;
208 +
209 + if(p->packets.sent.key)
210 + packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.sent) ? 1 : 0;
211 +
212 + if(p->packets.delivered.key)
213 + packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.delivered) ? 1 :0;
214 +
215 + if(p->packets.forwarded.key)
216 + packets += perflibGetObjectCounter(pDataBlock, pObjectType, &p->packets.forwarded) ? 1 : 0;
217 +
218 + if(packets)
219 + protocol_packets_chart_update(p, update_every);
220 +
221 + return true;
222 +}
223 +
224 +// --------------------------------------------------------------------------------------------------------------------
225 +// network interfaces
226 +
227 +struct network_interface {
228 + bool collected_metadata;
229 +
230 + struct {
231 + COUNTER_DATA received;
232 + COUNTER_DATA sent;
233 +
234 + RRDSET *st;
235 + RRDDIM *rd_received;
236 + RRDDIM *rd_sent;
237 + } packets;
238 +
239 + struct {
240 + COUNTER_DATA received;
241 + COUNTER_DATA sent;
242 +
243 + RRDSET *st;
244 + RRDDIM *rd_received;
245 + RRDDIM *rd_sent;
246 + } traffic;
247 +};
248 +
249 +static DICTIONARY *physical_interfaces = NULL, *virtual_interfaces = NULL;
250 +
251 +static void network_interface_init(struct network_interface *ni) {
252 + ni->packets.received.key = "Packets Received/sec";
253 + ni->packets.sent.key = "Packets Sent/sec";
254 +
255 + ni->traffic.received.key = "Bytes Received/sec";
256 + ni->traffic.sent.key = "Bytes Sent/sec";
257 +}
258 +
259 +void dict_interface_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
260 + struct network_interface *ni = value;
261 + network_interface_init(ni);
262 +}
263 +
264 +static void initialize(void) {
265 + physical_interfaces = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
266 + DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct network_interface));
267 +
268 + virtual_interfaces = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
269 + DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct network_interface));
270 +
271 + dictionary_register_insert_callback(physical_interfaces, dict_interface_insert_cb, NULL);
272 + dictionary_register_insert_callback(virtual_interfaces, dict_interface_insert_cb, NULL);
273 +}
274 +
275 +static void add_interface_labels(RRDSET *st, const char *name, bool physical) {
276 + rrdlabels_add(st->rrdlabels, "device", name, RRDLABEL_SRC_AUTO);
277 + rrdlabels_add(st->rrdlabels, "interface_type", physical ? "real" : "virtual", RRDLABEL_SRC_AUTO);
278 +}
279 +
280 +static bool is_physical_interface(const char *name) {
281 + void *d = dictionary_get(physical_interfaces, name);
282 + return d ? true : false;
283 +}
284 +
285 +static bool do_network_interface(PERF_DATA_BLOCK *pDataBlock, int update_every, bool physical) {
286 + DICTIONARY *dict = physical_interfaces;
287 +
288 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, physical ? "Network Interface" : "Network Adapter");
289 + if(!pObjectType) return false;
290 +
291 + uint64_t total_received = 0, total_sent = 0;
292 +
293 + PERF_INSTANCE_DEFINITION *pi = NULL;
294 + for(LONG i = 0; i < pObjectType->NumInstances ; i++) {
295 + pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
296 + if(!pi) break;
297 +
298 + if(!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
299 + strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
300 +
301 + if(strcasecmp(windows_shared_buffer, "_Total") == 0)
302 + continue;
303 +
304 + if(!physical && is_physical_interface(windows_shared_buffer))
305 + // this virtual interface is already reported as physical interface
306 + continue;
307 +
308 + struct network_interface *d = dictionary_set(dict, windows_shared_buffer, NULL, sizeof(*d));
309 +
310 + if(!d->collected_metadata) {
311 + // TODO - get metadata about the network interface
312 + d->collected_metadata = true;
313 + }
314 +
315 + if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->traffic.received) ||
316 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->traffic.sent)) {
317 +
318 + if(d->traffic.received.current.Data == 0 && d->traffic.sent.current.Data == 0)
319 + // this interface has not received or sent any traffic
320 + continue;
321 +
322 + if (unlikely(!d->traffic.st)) {
323 + d->traffic.st = rrdset_create_localhost(
324 + "net",
325 + windows_shared_buffer,
326 + NULL,
327 + windows_shared_buffer,
328 + "net.net",
329 + "Bandwidth",
330 + "kilobits/s",
331 + PLUGIN_WINDOWS_NAME,
332 + "PerflibNetwork",
333 + NETDATA_CHART_PRIO_FIRST_NET_IFACE,
334 + update_every,
335 + RRDSET_TYPE_AREA);
336 +
337 + rrdset_flag_set(d->traffic.st, RRDSET_FLAG_DETAIL);
338 +
339 + add_interface_labels(d->traffic.st, windows_shared_buffer, physical);
340 +
341 + d->traffic.rd_received = rrddim_add(d->traffic.st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
342 + d->traffic.rd_sent = rrddim_add(d->traffic.st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
343 + }
344 +
345 + total_received += d->traffic.received.current.Data;
346 + total_sent += d->traffic.sent.current.Data;
347 +
348 + rrddim_set_by_pointer(d->traffic.st, d->traffic.rd_received, (collected_number)d->traffic.received.current.Data);
349 + rrddim_set_by_pointer(d->traffic.st, d->traffic.rd_sent, (collected_number)d->traffic.sent.current.Data);
350 + rrdset_done(d->traffic.st);
351 + }
352 +
353 + if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->packets.received) ||
354 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->packets.sent)) {
355 +
356 + if (unlikely(!d->packets.st)) {
357 + d->packets.st = rrdset_create_localhost(
358 + "net_packets",
359 + windows_shared_buffer,
360 + NULL,
361 + windows_shared_buffer,
362 + "net.packets",
363 + "Packets",
364 + "packets/s",
365 + PLUGIN_WINDOWS_NAME,
366 + "PerflibNetwork",
367 + NETDATA_CHART_PRIO_FIRST_NET_IFACE + 1,
368 + update_every,
369 + RRDSET_TYPE_LINE);
370 +
371 + rrdset_flag_set(d->packets.st, RRDSET_FLAG_DETAIL);
372 +
373 + add_interface_labels(d->traffic.st, windows_shared_buffer, physical);
374 +
375 + d->packets.rd_received = rrddim_add(d->packets.st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
376 + d->packets.rd_sent = rrddim_add(d->packets.st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
377 + }
378 +
379 + rrddim_set_by_pointer(d->packets.st, d->packets.rd_received, (collected_number)d->packets.received.current.Data);
380 + rrddim_set_by_pointer(d->packets.st, d->packets.rd_sent, (collected_number)d->packets.sent.current.Data);
381 + rrdset_done(d->packets.st);
382 + }
383 + }
384 +
385 + if(physical) {
386 + static RRDSET *st = NULL;
387 + static RRDDIM *rd_received = NULL, *rd_sent = NULL;
388 +
389 + if (unlikely(!st)) {
390 + st = rrdset_create_localhost(
391 + "system",
392 + "net",
393 + NULL,
394 + "network",
395 + "system.net",
396 + "Physical Network Interfaces Aggregated Bandwidth",
397 + "kilobits/s",
398 + PLUGIN_WINDOWS_NAME,
399 + "PerflibNetwork",
400 + NETDATA_CHART_PRIO_SYSTEM_NET,
401 + update_every,
402 + RRDSET_TYPE_AREA);
403 +
404 + rd_received = rrddim_add(st, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
405 + rd_sent = rrddim_add(st, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
406 + }
407 +
408 + rrddim_set_by_pointer(st, rd_received, (collected_number)total_received);
409 + rrddim_set_by_pointer(st, rd_sent, (collected_number)total_sent);
410 + rrdset_done(st);
411 + }
412 +
413 + return true;
414 +}
415 +
416 +int do_PerflibNetwork(int update_every, usec_t dt __maybe_unused) {
417 + static bool initialized = false;
418 +
419 + if(unlikely(!initialized)) {
420 + initialize();
421 + initialized = true;
422 + }
423 +
424 + DWORD id = RegistryFindIDByName("Network Interface");
425 + if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
426 + return -1;
427 +
428 + PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
429 + if(!pDataBlock) return -1;
430 +
431 + do_network_interface(pDataBlock, update_every, true);
432 + do_network_interface(pDataBlock, update_every, false);
433 +
434 + struct network_protocol *tcp4 = NULL, *tcp6 = NULL;
435 + for(size_t i = 0; networks[i].protocol ;i++) {
436 + do_network_protocol(pDataBlock, update_every, &networks[i]);
437 +
438 + if(!tcp4 && strcmp(networks[i].protocol, "TCPv4") == 0)
439 + tcp4 = &networks[i];
440 + if(!tcp6 && strcmp(networks[i].protocol, "TCPv6") == 0)
441 + tcp6 = &networks[i];
442 + }
443 +
444 + if(tcp4 && tcp6) {
445 + tcp46.packets.received = tcp4->packets.received;
446 + tcp46.packets.sent = tcp4->packets.sent;
447 + tcp46.packets.received.current.Data += tcp6->packets.received.current.Data;
448 + tcp46.packets.sent.current.Data += tcp6->packets.sent.current.Data;
449 + protocol_packets_chart_update(&tcp46, update_every);
450 + }
451 +
452 + return 0;
453 +}
src/collectors/windows.plugin/perflib-processor.c new
+191
@@ -0,0 +1,191 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows_plugin.h"
4 +#include "windows-internals.h"
5 +
6 +struct processor {
7 + bool collected_metadata;
8 +
9 + RRDSET *st;
10 + RRDDIM *rd_user;
11 + RRDDIM *rd_system;
12 + RRDDIM *rd_irq;
13 + RRDDIM *rd_dpc;
14 + RRDDIM *rd_idle;
15 +
16 +// RRDSET *st2;
17 +// RRDDIM *rd2_busy;
18 +
19 + COUNTER_DATA percentProcessorTime;
20 + COUNTER_DATA percentUserTime;
21 + COUNTER_DATA percentPrivilegedTime;
22 + COUNTER_DATA percentDPCTime;
23 + COUNTER_DATA percentInterruptTime;
24 + COUNTER_DATA percentIdleTime;
25 +};
26 +
27 +struct processor total = { 0 };
28 +
29 +void initialize_processor_keys(struct processor *p) {
30 + p->percentProcessorTime.key = "% Processor Time";
31 + p->percentUserTime.key = "% User Time";
32 + p->percentPrivilegedTime.key = "% Privileged Time";
33 + p->percentDPCTime.key = "% DPC Time";
34 + p->percentInterruptTime.key = "% Interrupt Time";
35 + p->percentIdleTime.key = "% Idle Time";
36 +}
37 +
38 +void dict_processor_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
39 + struct processor *p = value;
40 + initialize_processor_keys(p);
41 +}
42 +
43 +static DICTIONARY *processors = NULL;
44 +
45 +static void initialize(void) {
46 + initialize_processor_keys(&total);
47 +
48 + processors = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
49 + DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct processor));
50 +
51 + dictionary_register_insert_callback(processors, dict_processor_insert_cb, NULL);
52 +}
53 +
54 +static bool do_processors(PERF_DATA_BLOCK *pDataBlock, int update_every) {
55 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "Processor");
56 + if(!pObjectType) return false;
57 +
58 + static const RRDVAR_ACQUIRED *cpus_var = NULL;
59 + int cores_found = 0;
60 +
61 + PERF_INSTANCE_DEFINITION *pi = NULL;
62 + for(LONG i = 0; i < pObjectType->NumInstances ; i++) {
63 + pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
64 + if(!pi) break;
65 +
66 + if(!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
67 + strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
68 +
69 + bool is_total = false;
70 + struct processor *p;
71 + int cpu = -1;
72 + if(strcasecmp(windows_shared_buffer, "_Total") == 0) {
73 + p = &total;
74 + is_total = true;
75 + cpu = -1;
76 + }
77 + else {
78 + p = dictionary_set(processors, windows_shared_buffer, NULL, sizeof(*p));
79 + is_total = false;
80 + cpu = str2i(windows_shared_buffer);
81 + snprintfz(windows_shared_buffer, sizeof(windows_shared_buffer), "cpu%d", cpu);
82 +
83 + if(cpu + 1 > cores_found)
84 + cores_found = cpu + 1;
85 + }
86 +
87 + if(!is_total && !p->collected_metadata) {
88 + // TODO collect processor metadata
89 + p->collected_metadata = true;
90 + }
91 +
92 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentProcessorTime);
93 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentUserTime);
94 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentPrivilegedTime);
95 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentDPCTime);
96 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentInterruptTime);
97 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &p->percentIdleTime);
98 +
99 + if(!p->st) {
100 + p->st = rrdset_create_localhost(
101 + is_total ? "system" : "cpu"
102 + , is_total ? "cpu" : windows_shared_buffer, NULL
103 + , is_total ? "cpu" : "utilization"
104 + , is_total ? "system.cpu" : "cpu.cpu"
105 + , is_total ? "Total CPU Utilization" : "Core Utilization"
106 + , "percentage"
107 + , PLUGIN_WINDOWS_NAME
108 + , "PerflibProcessor"
109 + , is_total ? NETDATA_CHART_PRIO_SYSTEM_CPU : NETDATA_CHART_PRIO_CPU_PER_CORE
110 + , update_every
111 + , RRDSET_TYPE_STACKED
112 + );
113 +
114 + p->rd_irq = rrddim_add(p->st, "interrupts", "irq", 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
115 + p->rd_user = rrddim_add(p->st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
116 + p->rd_system = rrddim_add(p->st, "privileged", "system", 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
117 + p->rd_dpc = rrddim_add(p->st, "dpc", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
118 + p->rd_idle = rrddim_add(p->st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
119 + rrddim_hide(p->st, "idle");
120 +
121 + if(!is_total)
122 + rrdlabels_add(p->st->rrdlabels, "cpu", windows_shared_buffer, RRDLABEL_SRC_AUTO);
123 + else
124 + cpus_var = rrdvar_host_variable_add_and_acquire(localhost, "active_processors");
125 + }
126 +
127 + uint64_t user = p->percentUserTime.current.Data;
128 + uint64_t system = p->percentPrivilegedTime.current.Data;
129 + uint64_t dpc = p->percentDPCTime.current.Data;
130 + uint64_t irq = p->percentInterruptTime.current.Data;
131 + uint64_t idle = p->percentIdleTime.current.Data;
132 +
133 + rrddim_set_by_pointer(p->st, p->rd_user, (collected_number)user);
134 + rrddim_set_by_pointer(p->st, p->rd_system, (collected_number)system);
135 + rrddim_set_by_pointer(p->st, p->rd_irq, (collected_number)irq);
136 + rrddim_set_by_pointer(p->st, p->rd_dpc, (collected_number)dpc);
137 + rrddim_set_by_pointer(p->st, p->rd_idle, (collected_number)idle);
138 + rrdset_done(p->st);
139 +
140 +// if(!p->st2) {
141 +// p->st2 = rrdset_create_localhost(
142 +// is_total ? "system" : "cpu2"
143 +// , is_total ? "cpu3" : buffer
144 +// , NULL
145 +// , is_total ? "utilization" : buffer
146 +// , is_total ? "system.cpu3" : "cpu2.cpu"
147 +// , is_total ? "Total CPU Utilization" : "Core Utilization"
148 +// , "percentage"
149 +// , PLUGIN_WINDOWS_NAME
150 +// , "PerflibProcessor"
151 +// , is_total ? NETDATA_CHART_PRIO_SYSTEM_CPU : NETDATA_CHART_PRIO_CPU_PER_CORE
152 +// , update_every
153 +// , RRDSET_TYPE_STACKED
154 +// );
155 +//
156 +// p->rd2_busy = perflib_rrddim_add(p->st2, "busy", NULL, 1, 1, &p->percentProcessorTime);
157 +// rrddim_hide(p->st2, "idle");
158 +//
159 +// if(!is_total)
160 +// rrdlabels_add(p->st->rrdlabels, "cpu", buffer, RRDLABEL_SRC_AUTO);
161 +// }
162 +//
163 +// perflib_rrddim_set_by_pointer(p->st2, p->rd2_busy, &p->percentProcessorTime);
164 +// rrdset_done(p->st2);
165 + }
166 +
167 + if(cpus_var)
168 + rrdvar_host_variable_set(localhost, cpus_var, cores_found);
169 +
170 + return true;
171 +}
172 +
173 +int do_PerflibProcessor(int update_every, usec_t dt __maybe_unused) {
174 + static bool initialized = false;
175 +
176 + if(unlikely(!initialized)) {
177 + initialize();
178 + initialized = true;
179 + }
180 +
181 + DWORD id = RegistryFindIDByName("Processor");
182 + if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
183 + return -1;
184 +
185 + PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
186 + if(!pDataBlock) return -1;
187 +
188 + do_processors(pDataBlock, update_every);
189 +
190 + return 0;
191 +}
src/collectors/windows.plugin/perflib-rrd.c new
+411
@@ -0,0 +1,411 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "perflib-rrd.h"
4 +
5 +#define COLLECTED_NUMBER_PRECISION 10000
6 +
7 +RRDDIM *perflib_rrddim_add(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divider, COUNTER_DATA *cd) {
8 + RRD_ALGORITHM algorithm = RRD_ALGORITHM_ABSOLUTE;
9 +
10 + switch (cd->current.CounterType) {
11 + case PERF_COUNTER_COUNTER:
12 + case PERF_SAMPLE_COUNTER:
13 + case PERF_COUNTER_BULK_COUNT:
14 + // (N1 - N0) / ((D1 - D0) / F)
15 + // multiplier *= cd->current.Frequency / 10000000;
16 + // tested, the frequency is not that useful for netdata
17 + // we get right results without it.
18 + algorithm = RRD_ALGORITHM_INCREMENTAL;
19 + break;
20 +
21 + case PERF_COUNTER_QUEUELEN_TYPE:
22 + case PERF_COUNTER_100NS_QUEUELEN_TYPE:
23 + case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
24 + case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
25 + case PERF_AVERAGE_BULK: // normally not displayed
26 + // (N1 - N0) / (D1 - D0)
27 + algorithm = RRD_ALGORITHM_INCREMENTAL;
28 + break;
29 +
30 + case PERF_OBJ_TIME_TIMER:
31 + case PERF_COUNTER_TIMER:
32 + case PERF_100NSEC_TIMER:
33 + case PERF_PRECISION_SYSTEM_TIMER:
34 + case PERF_PRECISION_100NS_TIMER:
35 + case PERF_PRECISION_OBJECT_TIMER:
36 + case PERF_SAMPLE_FRACTION:
37 + // 100 * (N1 - N0) / (D1 - D0)
38 + multiplier *= 100;
39 + algorithm = RRD_ALGORITHM_INCREMENTAL;
40 + break;
41 +
42 + case PERF_COUNTER_TIMER_INV:
43 + case PERF_100NSEC_TIMER_INV:
44 + // 100 * (1 - ((N1 - N0) / (D1 - D0)))
45 + divider *= COLLECTED_NUMBER_PRECISION;
46 + algorithm = RRD_ALGORITHM_ABSOLUTE;
47 + break;
48 +
49 + case PERF_COUNTER_MULTI_TIMER:
50 + // 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
51 + divider *= COLLECTED_NUMBER_PRECISION;
52 + algorithm = RRD_ALGORITHM_ABSOLUTE;
53 + break;
54 +
55 + case PERF_100NSEC_MULTI_TIMER:
56 + // 100 * ((N1 - N0) / (D1 - D0)) / B1
57 + divider *= COLLECTED_NUMBER_PRECISION;
58 + algorithm = RRD_ALGORITHM_ABSOLUTE;
59 + break;
60 +
61 + case PERF_COUNTER_MULTI_TIMER_INV:
62 + case PERF_100NSEC_MULTI_TIMER_INV:
63 + // 100 * (B1 - ((N1 - N0) / (D1 - D0)))
64 + divider *= COLLECTED_NUMBER_PRECISION;
65 + algorithm = RRD_ALGORITHM_ABSOLUTE;
66 + break;
67 +
68 + case PERF_COUNTER_RAWCOUNT:
69 + case PERF_COUNTER_LARGE_RAWCOUNT:
70 + // N as decimal
71 + algorithm = RRD_ALGORITHM_ABSOLUTE;
72 + break;
73 +
74 + case PERF_COUNTER_RAWCOUNT_HEX:
75 + case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
76 + // N as hexadecimal
77 + algorithm = RRD_ALGORITHM_ABSOLUTE;
78 + break;
79 +
80 + case PERF_COUNTER_DELTA:
81 + case PERF_COUNTER_LARGE_DELTA:
82 + // N1 - N0
83 + algorithm = RRD_ALGORITHM_ABSOLUTE;
84 + break;
85 +
86 + case PERF_RAW_FRACTION:
87 + case PERF_LARGE_RAW_FRACTION:
88 + // 100 * N / B
89 + algorithm = RRD_ALGORITHM_ABSOLUTE;
90 + divider *= COLLECTED_NUMBER_PRECISION;
91 + break;
92 +
93 + case PERF_AVERAGE_TIMER:
94 + // ((N1 - N0) / TB) / (B1 - B0)
95 + // divider *= cd->current.Frequency / 10000000;
96 + algorithm = RRD_ALGORITHM_INCREMENTAL;
97 + break;
98 +
99 + case PERF_ELAPSED_TIME:
100 + // (D0 - N0) / F
101 + algorithm = RRD_ALGORITHM_ABSOLUTE;
102 + break;
103 +
104 + case PERF_COUNTER_TEXT:
105 + case PERF_SAMPLE_BASE:
106 + case PERF_AVERAGE_BASE:
107 + case PERF_COUNTER_MULTI_BASE:
108 + case PERF_RAW_BASE:
109 + case PERF_COUNTER_NODATA:
110 + case PERF_PRECISION_TIMESTAMP:
111 + default:
112 + break;
113 + }
114 +
115 + return rrddim_add(st, id, name, multiplier, divider, algorithm);
116 +}
117 +
118 +#define VALID_DELTA(cd) \
119 + ((cd)->previous.Time > 0 && (cd)->current.Data >= (cd)->previous.Data && (cd)->current.Time > (cd)->previous.Time)
120 +
121 +collected_number perflib_rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, COUNTER_DATA *cd) {
122 + ULONGLONG numerator = 0;
123 + LONGLONG denominator = 0;
124 + double doubleValue = 0.0;
125 + collected_number value;
126 +
127 + switch(cd->current.CounterType) {
128 + case PERF_COUNTER_COUNTER:
129 + case PERF_SAMPLE_COUNTER:
130 + case PERF_COUNTER_BULK_COUNT:
131 + // (N1 - N0) / ((D1 - D0) / F)
132 + value = (collected_number)cd->current.Data;
133 + break;
134 +
135 + case PERF_COUNTER_QUEUELEN_TYPE:
136 + case PERF_COUNTER_100NS_QUEUELEN_TYPE:
137 + case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
138 + case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
139 + case PERF_AVERAGE_BULK: // normally not displayed
140 + // (N1 - N0) / (D1 - D0)
141 + value = (collected_number)cd->current.Data;
142 + break;
143 +
144 + case PERF_OBJ_TIME_TIMER:
145 + case PERF_COUNTER_TIMER:
146 + case PERF_100NSEC_TIMER:
147 + case PERF_PRECISION_SYSTEM_TIMER:
148 + case PERF_PRECISION_100NS_TIMER:
149 + case PERF_PRECISION_OBJECT_TIMER:
150 + case PERF_SAMPLE_FRACTION:
151 + // 100 * (N1 - N0) / (D1 - D0)
152 + value = (collected_number)cd->current.Data;
153 + break;
154 +
155 + case PERF_COUNTER_TIMER_INV:
156 + case PERF_100NSEC_TIMER_INV:
157 + // 100 * (1 - ((N1 - N0) / (D1 - D0)))
158 + if(!VALID_DELTA(cd)) return 0;
159 + numerator = cd->current.Data - cd->previous.Data;
160 + denominator = cd->current.Time - cd->previous.Time;
161 + doubleValue = 100.0 * (1.0 - ((double)numerator / (double)denominator));
162 + // printf("Display value is (timer-inv): %f%%\n", doubleValue);
163 + value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
164 + break;
165 +
166 + case PERF_COUNTER_MULTI_TIMER:
167 + // 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
168 + if(!VALID_DELTA(cd)) return 0;
169 + numerator = cd->current.Data - cd->previous.Data;
170 + denominator = cd->current.Time - cd->previous.Time;
171 + denominator /= cd->current.Frequency;
172 + doubleValue = 100.0 * ((double)numerator / (double)denominator) / cd->current.MultiCounterData;
173 + // printf("Display value is (multi-timer): %f%%\n", doubleValue);
174 + value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
175 + break;
176 +
177 + case PERF_100NSEC_MULTI_TIMER:
178 + // 100 * ((N1 - N0) / (D1 - D0)) / B1
179 + if(!VALID_DELTA(cd)) return 0;
180 + numerator = cd->current.Data - cd->previous.Data;
181 + denominator = cd->current.Time - cd->previous.Time;
182 + doubleValue = 100.0 * ((double)numerator / (double)denominator) / (double)cd->current.MultiCounterData;
183 + // printf("Display value is (100ns multi-timer): %f%%\n", doubleValue);
184 + value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
185 + break;
186 +
187 + case PERF_COUNTER_MULTI_TIMER_INV:
188 + case PERF_100NSEC_MULTI_TIMER_INV:
189 + // 100 * (B1 - ((N1 - N0) / (D1 - D0)))
190 + if(!VALID_DELTA(cd)) return 0;
191 + numerator = cd->current.Data - cd->previous.Data;
192 + denominator = cd->current.Time - cd->previous.Time;
193 + doubleValue = 100.0 * ((double)cd->current.MultiCounterData - ((double)numerator / (double)denominator));
194 + // printf("Display value is (multi-timer-inv): %f%%\n", doubleValue);
195 + value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
196 + break;
197 +
198 + case PERF_COUNTER_RAWCOUNT:
199 + case PERF_COUNTER_LARGE_RAWCOUNT:
200 + // N as decimal
201 + value = (collected_number)cd->current.Data;
202 + break;
203 +
204 + case PERF_COUNTER_RAWCOUNT_HEX:
205 + case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
206 + // N as hexadecimal
207 + value = (collected_number)cd->current.Data;
208 + break;
209 +
210 + case PERF_COUNTER_DELTA:
211 + case PERF_COUNTER_LARGE_DELTA:
212 + if(!VALID_DELTA(cd)) return 0;
213 + value = (collected_number)(cd->current.Data - cd->previous.Data);
214 + break;
215 +
216 + case PERF_RAW_FRACTION:
217 + case PERF_LARGE_RAW_FRACTION:
218 + // 100 * N / B
219 + if(!cd->current.Time) return 0;
220 + doubleValue = 100.0 * (double)cd->current.Data / (double)cd->current.Time;
221 + // printf("Display value is (fraction): %f%%\n", doubleValue);
222 + value = (collected_number)(doubleValue * COLLECTED_NUMBER_PRECISION);
223 + break;
224 +
225 + default:
226 + return 0;
227 + }
228 +
229 + return rrddim_set_by_pointer(st, rd, value);
230 +}
231 +
232 +/*
233 +double perflibCalculateValue(RAW_DATA *current, RAW_DATA *previous) {
234 + ULONGLONG numerator = 0;
235 + LONGLONG denominator = 0;
236 + double doubleValue = 0.0;
237 + DWORD dwordValue = 0;
238 +
239 + if (NULL == previous) {
240 + // Return error if the counter type requires two samples to calculate the value.
241 + switch (current->CounterType) {
242 + default:
243 + if (PERF_DELTA_COUNTER != (current->CounterType & PERF_DELTA_COUNTER))
244 + break;
245 + __fallthrough;
246 + // fallthrough
247 +
248 + case PERF_AVERAGE_TIMER: // Special case.
249 + case PERF_AVERAGE_BULK: // Special case.
250 + // printf(" > The counter type requires two samples but only one sample was provided.\n");
251 + return NAN;
252 + }
253 + }
254 + else {
255 + if (current->CounterType != previous->CounterType) {
256 + // printf(" > The samples have inconsistent counter types.\n");
257 + return NAN;
258 + }
259 +
260 + // Check for integer overflow or bad data from provider (the data from
261 + // sample 2 must be greater than the data from sample 1).
262 + if (current->Data < previous->Data)
263 + {
264 + // Can happen for various reasons. Commonly occurs with the Process counterset when
265 + // multiple processes have the same name and one of them starts or stops.
266 + // Normally you'll just drop the older sample and continue.
267 + // printf("> current (%llu) is smaller than previous (%llu).\n", current->Data, previous->Data);
268 + return NAN;
269 + }
270 + }
271 +
272 + switch (current->CounterType) {
273 + case PERF_COUNTER_COUNTER:
274 + case PERF_SAMPLE_COUNTER:
275 + case PERF_COUNTER_BULK_COUNT:
276 + // (N1 - N0) / ((D1 - D0) / F)
277 + numerator = current->Data - previous->Data;
278 + denominator = current->Time - previous->Time;
279 + dwordValue = (DWORD)(numerator / ((double)denominator / current->Frequency));
280 + //printf("Display value is (counter): %lu%s\n", (unsigned long)dwordValue,
281 + // (previous->CounterType == PERF_SAMPLE_COUNTER) ? "" : "/sec");
282 + return (double)dwordValue;
283 +
284 + case PERF_COUNTER_QUEUELEN_TYPE:
285 + case PERF_COUNTER_100NS_QUEUELEN_TYPE:
286 + case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
287 + case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
288 + case PERF_AVERAGE_BULK: // normally not displayed
289 + // (N1 - N0) / (D1 - D0)
290 + numerator = current->Data - previous->Data;
291 + denominator = current->Time - previous->Time;
292 + doubleValue = (double)numerator / denominator;
293 + if (previous->CounterType != PERF_AVERAGE_BULK) {
294 + // printf("Display value is (queuelen): %f\n", doubleValue);
295 + return doubleValue;
296 + }
297 + return NAN;
298 +
299 + case PERF_OBJ_TIME_TIMER:
300 + case PERF_COUNTER_TIMER:
301 + case PERF_100NSEC_TIMER:
302 + case PERF_PRECISION_SYSTEM_TIMER:
303 + case PERF_PRECISION_100NS_TIMER:
304 + case PERF_PRECISION_OBJECT_TIMER:
305 + case PERF_SAMPLE_FRACTION:
306 + // 100 * (N1 - N0) / (D1 - D0)
307 + numerator = current->Data - previous->Data;
308 + denominator = current->Time - previous->Time;
309 + doubleValue = (double)(100 * numerator) / denominator;
310 + // printf("Display value is (timer): %f%%\n", doubleValue);
311 + return doubleValue;
312 +
313 + case PERF_COUNTER_TIMER_INV:
314 + // 100 * (1 - ((N1 - N0) / (D1 - D0)))
315 + numerator = current->Data - previous->Data;
316 + denominator = current->Time - previous->Time;
317 + doubleValue = 100 * (1 - ((double)numerator / denominator));
318 + // printf("Display value is (timer-inv): %f%%\n", doubleValue);
319 + return doubleValue;
320 +
321 + case PERF_100NSEC_TIMER_INV:
322 + // 100 * (1- (N1 - N0) / (D1 - D0))
323 + numerator = current->Data - previous->Data;
324 + denominator = current->Time - previous->Time;
325 + doubleValue = 100 * (1 - (double)numerator / denominator);
326 + // printf("Display value is (100ns-timer-inv): %f%%\n", doubleValue);
327 + return doubleValue;
328 +
329 + case PERF_COUNTER_MULTI_TIMER:
330 + // 100 * ((N1 - N0) / ((D1 - D0) / TB)) / B1
331 + numerator = current->Data - previous->Data;
332 + denominator = current->Time - previous->Time;
333 + denominator /= current->Frequency;
334 + doubleValue = 100 * ((double)numerator / denominator) / current->MultiCounterData;
335 + // printf("Display value is (multi-timer): %f%%\n", doubleValue);
336 + return doubleValue;
337 +
338 + case PERF_100NSEC_MULTI_TIMER:
339 + // 100 * ((N1 - N0) / (D1 - D0)) / B1
340 + numerator = current->Data - previous->Data;
341 + denominator = current->Time - previous->Time;
342 + doubleValue = 100 * ((double)numerator / (double)denominator) / (double)current->MultiCounterData;
343 + // printf("Display value is (100ns multi-timer): %f%%\n", doubleValue);
344 + return doubleValue;
345 +
346 + case PERF_COUNTER_MULTI_TIMER_INV:
347 + case PERF_100NSEC_MULTI_TIMER_INV:
348 + // 100 * (B1 - ((N1 - N0) / (D1 - D0)))
349 + numerator = current->Data - previous->Data;
350 + denominator = current->Time - previous->Time;
351 + doubleValue = 100.0 * ((double)current->MultiCounterData - ((double)numerator / (double)denominator));
352 + // printf("Display value is (multi-timer-inv): %f%%\n", doubleValue);
353 + return doubleValue;
354 +
355 + case PERF_COUNTER_RAWCOUNT:
356 + case PERF_COUNTER_LARGE_RAWCOUNT:
357 + // N as decimal
358 + // printf("Display value is (rawcount): %llu\n", current->Data);
359 + return (double)current->Data;
360 +
361 + case PERF_COUNTER_RAWCOUNT_HEX:
362 + case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
363 + // N as hexadecimal
364 + // printf("Display value is (hex): 0x%llx\n", current->Data);
365 + return (double)current->Data;
366 +
367 + case PERF_COUNTER_DELTA:
368 + case PERF_COUNTER_LARGE_DELTA:
369 + // N1 - N0
370 + // printf("Display value is (delta): %llu\n", current->Data - previous->Data);
371 + return (double)(current->Data - previous->Data);
372 +
373 + case PERF_RAW_FRACTION:
374 + case PERF_LARGE_RAW_FRACTION:
375 + // 100 * N / B
376 + doubleValue = 100.0 * (double)current->Data / (double)current->Time;
377 + // printf("Display value is (fraction): %f%%\n", doubleValue);
378 + return doubleValue;
379 +
380 + case PERF_AVERAGE_TIMER:
381 + // ((N1 - N0) / TB) / (B1 - B0)
382 + numerator = current->Data - previous->Data;
383 + denominator = current->Time - previous->Time;
384 + doubleValue = (double)numerator / (double)current->Frequency / (double)denominator;
385 + // printf("Display value is (average timer): %f seconds\n", doubleValue);
386 + return doubleValue;
387 +
388 + case PERF_ELAPSED_TIME:
389 + // (D0 - N0) / F
390 + doubleValue = (double)(current->Time - current->Data) / (double)current->Frequency;
391 + // printf("Display value is (elapsed time): %f seconds\n", doubleValue);
392 + return doubleValue;
393 +
394 + case PERF_COUNTER_TEXT:
395 + case PERF_SAMPLE_BASE:
396 + case PERF_AVERAGE_BASE:
397 + case PERF_COUNTER_MULTI_BASE:
398 + case PERF_RAW_BASE:
399 + case PERF_COUNTER_NODATA:
400 + case PERF_PRECISION_TIMESTAMP:
401 + // printf(" > Non-printing counter type: 0x%08x\n", current->CounterType);
402 + return NAN;
403 + break;
404 +
405 + default:
406 + // printf(" > Unrecognized counter type: 0x%08x\n", current->CounterType);
407 + return NAN;
408 + break;
409 + }
410 +}
411 +*/
src/collectors/windows.plugin/perflib-rrd.h new
+12
@@ -0,0 +1,12 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_PERFLIB_RRD_H
4 +#define NETDATA_PERFLIB_RRD_H
5 +
6 +#include "perflib.h"
7 +#include "database/rrd.h"
8 +
9 +RRDDIM *perflib_rrddim_add(RRDSET *st, const char *id, const char *name, collected_number multiplier, collected_number divider, COUNTER_DATA *cd);
10 +collected_number perflib_rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, COUNTER_DATA *cd);
11 +
12 +#endif //NETDATA_PERFLIB_RRD_H
src/collectors/windows.plugin/perflib-storage.c new
+317
@@ -0,0 +1,317 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows_plugin.h"
4 +#include "windows-internals.h"
5 +
6 +#define _COMMON_PLUGIN_NAME PLUGIN_WINDOWS_NAME
7 +#define _COMMON_PLUGIN_MODULE_NAME "PerflibStorage"
8 +#include "../common-contexts/common-contexts.h"
9 +
10 +struct logical_disk {
11 + bool collected_metadata;
12 +
13 + STRING *filesystem;
14 +
15 + RRDSET *st_disk_space;
16 + RRDDIM *rd_disk_space_used;
17 + RRDDIM *rd_disk_space_free;
18 +
19 + COUNTER_DATA percentDiskFree;
20 + // COUNTER_DATA freeMegabytes;
21 +};
22 +
23 +struct physical_disk {
24 + bool collected_metadata;
25 +
26 + STRING *device;
27 + STRING *mount_point;
28 +
29 + ND_DISK_IO disk_io;
30 + COUNTER_DATA diskReadBytesPerSec;
31 + COUNTER_DATA diskWriteBytesPerSec;
32 +
33 + COUNTER_DATA percentIdleTime;
34 + COUNTER_DATA percentDiskTime;
35 + COUNTER_DATA percentDiskReadTime;
36 + COUNTER_DATA percentDiskWriteTime;
37 + COUNTER_DATA currentDiskQueueLength;
38 + COUNTER_DATA averageDiskQueueLength;
39 + COUNTER_DATA averageDiskReadQueueLength;
40 + COUNTER_DATA averageDiskWriteQueueLength;
41 + COUNTER_DATA averageDiskSecondsPerTransfer;
42 + COUNTER_DATA averageDiskSecondsPerRead;
43 + COUNTER_DATA averageDiskSecondsPerWrite;
44 + COUNTER_DATA diskTransfersPerSec;
45 + COUNTER_DATA diskReadsPerSec;
46 + COUNTER_DATA diskWritesPerSec;
47 + COUNTER_DATA diskBytesPerSec;
48 + COUNTER_DATA averageDiskBytesPerTransfer;
49 + COUNTER_DATA averageDiskBytesPerRead;
50 + COUNTER_DATA averageDiskBytesPerWrite;
51 + COUNTER_DATA splitIoPerSec;
52 +};
53 +
54 +struct physical_disk system_physical_total = {
55 + .collected_metadata = true,
56 +};
57 +
58 +void dict_logical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
59 + struct logical_disk *ld = value;
60 +
61 + ld->percentDiskFree.key = "% Free Space";
62 + // ld->freeMegabytes.key = "Free Megabytes";
63 +}
64 +
65 +void initialize_physical_disk(struct physical_disk *pd) {
66 + pd->percentIdleTime.key = "% Idle Time";
67 + pd->percentDiskTime.key = "% Disk Time";
68 + pd->percentDiskReadTime.key = "% Disk Read Time";
69 + pd->percentDiskWriteTime.key = "% Disk Write Time";
70 + pd->currentDiskQueueLength.key = "Current Disk Queue Length";
71 + pd->averageDiskQueueLength.key = "Avg. Disk Queue Length";
72 + pd->averageDiskReadQueueLength.key = "Avg. Disk Read Queue Length";
73 + pd->averageDiskWriteQueueLength.key = "Avg. Disk Write Queue Length";
74 + pd->averageDiskSecondsPerTransfer.key = "Avg. Disk sec/Transfer";
75 + pd->averageDiskSecondsPerRead.key = "Avg. Disk sec/Read";
76 + pd->averageDiskSecondsPerWrite.key = "Avg. Disk sec/Write";
77 + pd->diskTransfersPerSec.key = "Disk Transfers/sec";
78 + pd->diskReadsPerSec.key = "Disk Reads/sec";
79 + pd->diskWritesPerSec.key = "Disk Writes/sec";
80 + pd->diskBytesPerSec.key = "Disk Bytes/sec";
81 + pd->diskReadBytesPerSec.key = "Disk Read Bytes/sec";
82 + pd->diskWriteBytesPerSec.key = "Disk Write Bytes/sec";
83 + pd->averageDiskBytesPerTransfer.key = "Avg. Disk Bytes/Transfer";
84 + pd->averageDiskBytesPerRead.key = "Avg. Disk Bytes/Read";
85 + pd->averageDiskBytesPerWrite.key = "Avg. Disk Bytes/Write";
86 + pd->splitIoPerSec.key = "Split IO/Sec";
87 +}
88 +
89 +void dict_physical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
90 + struct physical_disk *pd = value;
91 + initialize_physical_disk(pd);
92 +}
93 +
94 +static DICTIONARY *logicalDisks = NULL, *physicalDisks = NULL;
95 +static void initialize(void) {
96 + initialize_physical_disk(&system_physical_total);
97 +
98 + logicalDisks = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
99 + DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct logical_disk));
100 +
101 + dictionary_register_insert_callback(logicalDisks, dict_logical_disk_insert_cb, NULL);
102 +
103 + physicalDisks = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
104 + DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct physical_disk));
105 +
106 + dictionary_register_insert_callback(physicalDisks, dict_physical_disk_insert_cb, NULL);
107 +}
108 +
109 +static STRING *getFileSystemType(const char* diskName) {
110 + if (!diskName || !*diskName) return NULL;
111 +
112 + char fileSystemNameBuffer[128] = {0}; // Buffer for file system name
113 + char pathBuffer[256] = {0}; // Path buffer to accommodate different formats
114 + DWORD serialNumber = 0;
115 + DWORD maxComponentLength = 0;
116 + DWORD fileSystemFlags = 0;
117 + BOOL success;
118 +
119 + // Check if the input is likely a drive letter (e.g., "C:")
120 + if (isalpha((uint8_t)diskName[0]) && diskName[1] == ':' && diskName[2] == '\0')
121 + snprintf(pathBuffer, sizeof(pathBuffer), "%s\\", diskName); // Format as "C:\\"
122 + else
123 + // Assume it's a Volume GUID path or a device path
124 + snprintf(pathBuffer, sizeof(pathBuffer), "\\\\.\\%s", diskName); // Format as "\\.\HarddiskVolume1"
125 +
126 + // Attempt to get the volume information
127 + success = GetVolumeInformation(
128 + pathBuffer, // Path to the disk
129 + NULL, // We don't need the volume name
130 + 0, // Size of volume name buffer is 0
131 + &serialNumber, // Volume serial number
132 + &maxComponentLength, // Maximum component length
133 + &fileSystemFlags, // File system flags
134 + fileSystemNameBuffer, // File system name buffer
135 + sizeof(fileSystemNameBuffer) // Size of file system name buffer
136 + );
137 +
138 + if (success && fileSystemNameBuffer[0]) {
139 + char *s = fileSystemNameBuffer;
140 + while(*s) { *s = tolower((uint8_t)*s); s++; }
141 + return string_strdupz(fileSystemNameBuffer); // Duplicate the file system name
142 + }
143 + else
144 + return NULL;
145 +}
146 +
147 +static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
148 + DICTIONARY *dict = logicalDisks;
149 +
150 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "LogicalDisk");
151 + if(!pObjectType) return false;
152 +
153 + PERF_INSTANCE_DEFINITION *pi = NULL;
154 + for(LONG i = 0; i < pObjectType->NumInstances ; i++) {
155 + pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
156 + if(!pi) break;
157 +
158 + if(!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
159 + strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
160 +
161 + if(strcasecmp(windows_shared_buffer, "_Total") == 0)
162 + continue;
163 +
164 + struct logical_disk *d = dictionary_set(dict, windows_shared_buffer, NULL, sizeof(*d));
165 +
166 + if(!d->collected_metadata) {
167 + d->filesystem = getFileSystemType(windows_shared_buffer);
168 + d->collected_metadata = true;
169 + }
170 +
171 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskFree);
172 + // perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->freeMegabytes);
173 +
174 + if(!d->st_disk_space) {
175 + d->st_disk_space = rrdset_create_localhost(
176 + "disk_space"
177 + , windows_shared_buffer, NULL
178 + , windows_shared_buffer, "disk.space"
179 + , "Disk Space Usage"
180 + , "GiB"
181 + , PLUGIN_WINDOWS_NAME
182 + , "PerflibStorage"
183 + , NETDATA_CHART_PRIO_DISKSPACE_SPACE
184 + , update_every
185 + , RRDSET_TYPE_STACKED
186 + );
187 +
188 + rrdlabels_add(d->st_disk_space->rrdlabels, "mount_point", windows_shared_buffer, RRDLABEL_SRC_AUTO);
189 + // rrdlabels_add(d->st->rrdlabels, "mount_root", name, RRDLABEL_SRC_AUTO);
190 +
191 + if(d->filesystem)
192 + rrdlabels_add(d->st_disk_space->rrdlabels, "filesystem", string2str(d->filesystem), RRDLABEL_SRC_AUTO);
193 +
194 + d->rd_disk_space_free = rrddim_add(d->st_disk_space, "avail", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
195 + d->rd_disk_space_used = rrddim_add(d->st_disk_space, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
196 + }
197 +
198 + // percentDiskFree has the free space in Data and the size of the disk in Time, in MiB.
199 + rrddim_set_by_pointer(d->st_disk_space, d->rd_disk_space_free, (collected_number)d->percentDiskFree.current.Data);
200 + rrddim_set_by_pointer(d->st_disk_space, d->rd_disk_space_used, (collected_number)(d->percentDiskFree.current.Time - d->percentDiskFree.current.Data));
201 + rrdset_done(d->st_disk_space);
202 + }
203 +
204 + return true;
205 +}
206 +
207 +static void physical_disk_labels(RRDSET *st, void *data) {
208 + struct physical_disk *d = data;
209 +
210 + if(d->device)
211 + rrdlabels_add(st->rrdlabels, "device", string2str(d->device), RRDLABEL_SRC_AUTO);
212 +
213 + if (d->mount_point)
214 + rrdlabels_add(st->rrdlabels, "mount_point", string2str(d->mount_point), RRDLABEL_SRC_AUTO);
215 +}
216 +
217 +static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
218 + DICTIONARY *dict = physicalDisks;
219 +
220 + PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "PhysicalDisk");
221 + if(!pObjectType) return false;
222 +
223 + PERF_INSTANCE_DEFINITION *pi = NULL;
224 + for (LONG i = 0; i < pObjectType->NumInstances; i++) {
225 + pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
226 + if (!pi)
227 + break;
228 +
229 + if (!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
230 + strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
231 +
232 + char *device = windows_shared_buffer;
233 + char *mount_point = NULL;
234 +
235 + if((mount_point = strchr(device, ' '))) {
236 + *mount_point = '\0';
237 + mount_point++;
238 + }
239 +
240 + struct physical_disk *d;
241 + bool is_system;
242 + if (strcasecmp(windows_shared_buffer, "_Total") == 0) {
243 + d = &system_physical_total;
244 + is_system = true;
245 + }
246 + else {
247 + d = dictionary_set(dict, device, NULL, sizeof(*d));
248 + is_system = false;
249 + }
250 +
251 + if (!d->collected_metadata) {
252 + // TODO collect metadata - device_type, serial, id
253 + d->device = string_strdupz(device);
254 + d->mount_point = string_strdupz(mount_point);
255 + d->collected_metadata = true;
256 + }
257 +
258 + if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskReadBytesPerSec) &&
259 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskWriteBytesPerSec)) {
260 + if(is_system)
261 + common_system_io(d->diskReadBytesPerSec.current.Data, d->diskWriteBytesPerSec.current.Data, update_every);
262 + else
263 + common_disk_io(
264 + &d->disk_io,
265 + device,
266 + NULL,
267 + d->diskReadBytesPerSec.current.Data,
268 + d->diskWriteBytesPerSec.current.Data,
269 + update_every,
270 + physical_disk_labels,
271 + d);
272 + }
273 +
274 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentIdleTime);
275 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskTime);
276 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskReadTime);
277 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskWriteTime);
278 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->currentDiskQueueLength);
279 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskQueueLength);
280 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskReadQueueLength);
281 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskWriteQueueLength);
282 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerTransfer);
283 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerRead);
284 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerWrite);
285 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskTransfersPerSec);
286 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskReadsPerSec);
287 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskWritesPerSec);
288 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskBytesPerSec);
289 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerTransfer);
290 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerRead);
291 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerWrite);
292 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->splitIoPerSec);
293 + }
294 +
295 + return true;
296 +}
297 +
298 +int do_PerflibStorage(int update_every, usec_t dt __maybe_unused) {
299 + static bool initialized = false;
300 +
301 + if(unlikely(!initialized)) {
302 + initialize();
303 + initialized = true;
304 + }
305 +
306 + DWORD id = RegistryFindIDByName("LogicalDisk");
307 + if(id == PERFLIB_REGISTRY_NAME_NOT_FOUND)
308 + return -1;
309 +
310 + PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
311 + if(!pDataBlock) return -1;
312 +
313 + do_logical_disk(pDataBlock, update_every);
314 + do_physical_disk(pDataBlock, update_every);
315 +
316 + return 0;
317 +}
src/collectors/windows.plugin/perflib.c new
+671
@@ -0,0 +1,671 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "perflib.h"
4 +
5 +// --------------------------------------------------------------------------------
6 +
7 +// Retrieve a buffer that contains the specified performance data.
8 +// The pwszSource parameter determines the data that GetRegistryBuffer returns.
9 +//
10 +// Typically, when calling RegQueryValueEx, you can specify zero for the size of the buffer
11 +// and the RegQueryValueEx will set your size variable to the required buffer size. However,
12 +// if the source is "Global" or one or more object index values, you will need to increment
13 +// the buffer size in a loop until RegQueryValueEx does not return ERROR_MORE_DATA.
14 +static LPBYTE getPerformanceData(const char *pwszSource) {
15 + static __thread DWORD size = 0;
16 + static __thread LPBYTE buffer = NULL;
17 +
18 + if(pwszSource == (const char *)0x01) {
19 + freez(buffer);
20 + buffer = NULL;
21 + size = 0;
22 + return NULL;
23 + }
24 +
25 + if(!size) {
26 + size = 32 * 1024;
27 + buffer = mallocz(size);
28 + }
29 +
30 + LONG status = ERROR_SUCCESS;
31 + while ((status = RegQueryValueEx(HKEY_PERFORMANCE_DATA, pwszSource,
32 + NULL, NULL, buffer, &size)) == ERROR_MORE_DATA) {
33 + size *= 2;
34 + buffer = reallocz(buffer, size);
35 + }
36 +
37 + if (status != ERROR_SUCCESS) {
38 + nd_log(NDLS_COLLECTORS, NDLP_ERR, "RegQueryValueEx failed with 0x%x.\n", status);
39 + return NULL;
40 + }
41 +
42 + return buffer;
43 +}
44 +
45 +void perflibFreePerformanceData(void) {
46 + getPerformanceData((const char *)0x01);
47 +}
48 +
49 +// --------------------------------------------------------------------------------------------------------------------
50 +
51 +// Retrieve the raw counter value and any supporting data needed to calculate
52 +// a displayable counter value. Use the counter type to determine the information
53 +// needed to calculate the value.
54 +
55 +static BOOL getCounterData(
56 + PERF_DATA_BLOCK *pDataBlock,
57 + PERF_OBJECT_TYPE* pObject,
58 + PERF_COUNTER_DEFINITION* pCounter,
59 + PERF_COUNTER_BLOCK* pCounterDataBlock,
60 + PRAW_DATA pRawData)
61 +{
62 + PVOID pData = NULL;
63 + UNALIGNED ULONGLONG* pullData = NULL;
64 + PERF_COUNTER_DEFINITION* pBaseCounter = NULL;
65 + BOOL fSuccess = TRUE;
66 +
67 + //Point to the raw counter data.
68 + pData = (PVOID)((LPBYTE)pCounterDataBlock + pCounter->CounterOffset);
69 +
70 + //Now use the PERF_COUNTER_DEFINITION.CounterType value to figure out what
71 + //other information you need to calculate a displayable value.
72 + switch (pCounter->CounterType) {
73 +
74 + case PERF_COUNTER_COUNTER:
75 + case PERF_COUNTER_QUEUELEN_TYPE:
76 + case PERF_SAMPLE_COUNTER:
77 + pRawData->Data = (ULONGLONG)(*(DWORD*)pData);
78 + pRawData->Time = pDataBlock->PerfTime.QuadPart;
79 + if (PERF_COUNTER_COUNTER == pCounter->CounterType || PERF_SAMPLE_COUNTER == pCounter->CounterType)
80 + pRawData->Frequency = pDataBlock->PerfFreq.QuadPart;
81 + break;
82 +
83 + case PERF_OBJ_TIME_TIMER:
84 + pRawData->Data = (ULONGLONG)(*(DWORD*)pData);
85 + pRawData->Time = pObject->PerfTime.QuadPart;
86 + break;
87 +
88 + case PERF_COUNTER_100NS_QUEUELEN_TYPE:
89 + pRawData->Data = *(UNALIGNED ULONGLONG *)pData;
90 + pRawData->Time = pDataBlock->PerfTime100nSec.QuadPart;
91 + break;
92 +
93 + case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
94 + pRawData->Data = *(UNALIGNED ULONGLONG *)pData;
95 + pRawData->Time = pObject->PerfTime.QuadPart;
96 + break;
97 +
98 + case PERF_COUNTER_TIMER:
99 + case PERF_COUNTER_TIMER_INV:
100 + case PERF_COUNTER_BULK_COUNT:
101 + case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
102 + pullData = (UNALIGNED ULONGLONG *)pData;
103 + pRawData->Data = *pullData;
104 + pRawData->Time = pDataBlock->PerfTime.QuadPart;
105 + if (pCounter->CounterType == PERF_COUNTER_BULK_COUNT)
106 + pRawData->Frequency = pDataBlock->PerfFreq.QuadPart;
107 + break;
108 +
109 + case PERF_COUNTER_MULTI_TIMER:
110 + case PERF_COUNTER_MULTI_TIMER_INV:
111 + pullData = (UNALIGNED ULONGLONG *)pData;
112 + pRawData->Data = *pullData;
113 + pRawData->Frequency = pDataBlock->PerfFreq.QuadPart;
114 + pRawData->Time = pDataBlock->PerfTime.QuadPart;
115 +
116 + //These counter types have a second counter value that is adjacent to
117 + //this counter value in the counter data block. The value is needed for
118 + //the calculation.
119 + if ((pCounter->CounterType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
120 + ++pullData;
121 + pRawData->MultiCounterData = *(DWORD*)pullData;
122 + }
123 + break;
124 +
125 + //These counters do not use any time reference.
126 + case PERF_COUNTER_RAWCOUNT:
127 + case PERF_COUNTER_RAWCOUNT_HEX:
128 + case PERF_COUNTER_DELTA:
129 + // some counters in these categories, have CounterSize = sizeof(ULONGLONG)
130 + // but the official documentation always uses them as sizeof(DWORD)
131 + pRawData->Data = (ULONGLONG)(*(DWORD*)pData);
132 + pRawData->Time = 0;
133 + break;
134 +
135 + case PERF_COUNTER_LARGE_RAWCOUNT:
136 + case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
137 + case PERF_COUNTER_LARGE_DELTA:
138 + pRawData->Data = *(UNALIGNED ULONGLONG*)pData;
139 + pRawData->Time = 0;
140 + break;
141 +
142 + //These counters use the 100ns time base in their calculation.
143 + case PERF_100NSEC_TIMER:
144 + case PERF_100NSEC_TIMER_INV:
145 + case PERF_100NSEC_MULTI_TIMER:
146 + case PERF_100NSEC_MULTI_TIMER_INV:
147 + pullData = (UNALIGNED ULONGLONG*)pData;
148 + pRawData->Data = *pullData;
149 + pRawData->Time = pDataBlock->PerfTime100nSec.QuadPart;
150 +
151 + //These counter types have a second counter value that is adjacent to
152 + //this counter value in the counter data block. The value is needed for
153 + //the calculation.
154 + if ((pCounter->CounterType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
155 + ++pullData;
156 + pRawData->MultiCounterData = *(DWORD*)pullData;
157 + }
158 + break;
159 +
160 + //These counters use two data points, this value and one from this counter's
161 + //base counter. The base counter should be the next counter in the object's
162 + //list of counters.
163 + case PERF_SAMPLE_FRACTION:
164 + case PERF_RAW_FRACTION:
165 + pRawData->Data = (ULONGLONG)(*(DWORD*)pData);
166 + pBaseCounter = pCounter + 1; //Get base counter
167 + if ((pBaseCounter->CounterType & PERF_COUNTER_BASE) == PERF_COUNTER_BASE) {
168 + pData = (PVOID)((LPBYTE)pCounterDataBlock + pBaseCounter->CounterOffset);
169 + pRawData->Time = (LONGLONG)(*(DWORD*)pData);
170 + }
171 + else
172 + fSuccess = FALSE;
173 + break;
174 +
175 + case PERF_LARGE_RAW_FRACTION:
176 + case PERF_PRECISION_SYSTEM_TIMER:
177 + case PERF_PRECISION_100NS_TIMER:
178 + case PERF_PRECISION_OBJECT_TIMER:
179 + pRawData->Data = *(UNALIGNED ULONGLONG*)pData;
180 + pBaseCounter = pCounter + 1;
181 + if ((pBaseCounter->CounterType & PERF_COUNTER_BASE) == PERF_COUNTER_BASE) {
182 + pData = (PVOID)((LPBYTE)pCounterDataBlock + pBaseCounter->CounterOffset);
183 + pRawData->Time = *(LONGLONG*)pData;
184 + }
185 + else
186 + fSuccess = FALSE;
187 + break;
188 +
189 + case PERF_AVERAGE_TIMER:
190 + case PERF_AVERAGE_BULK:
191 + pRawData->Data = *(UNALIGNED ULONGLONG*)pData;
192 + pBaseCounter = pCounter+1;
193 + if ((pBaseCounter->CounterType & PERF_COUNTER_BASE) == PERF_COUNTER_BASE) {
194 + pData = (PVOID)((LPBYTE)pCounterDataBlock + pBaseCounter->CounterOffset);
195 + pRawData->Time = *(DWORD*)pData;
196 + }
197 + else
198 + fSuccess = FALSE;
199 +
200 + if (pCounter->CounterType == PERF_AVERAGE_TIMER)
201 + pRawData->Frequency = pDataBlock->PerfFreq.QuadPart;
202 + break;
203 +
204 + //These are base counters and are used in calculations for other counters.
205 + //This case should never be entered.
206 + case PERF_SAMPLE_BASE:
207 + case PERF_AVERAGE_BASE:
208 + case PERF_COUNTER_MULTI_BASE:
209 + case PERF_RAW_BASE:
210 + case PERF_LARGE_RAW_BASE:
211 + pRawData->Data = 0;
212 + pRawData->Time = 0;
213 + fSuccess = FALSE;
214 + break;
215 +
216 + case PERF_ELAPSED_TIME:
217 + pRawData->Data = *(UNALIGNED ULONGLONG*)pData;
218 + pRawData->Time = pObject->PerfTime.QuadPart;
219 + pRawData->Frequency = pObject->PerfFreq.QuadPart;
220 + break;
221 +
222 + //These counters are currently not supported.
223 + case PERF_COUNTER_TEXT:
224 + case PERF_COUNTER_NODATA:
225 + case PERF_COUNTER_HISTOGRAM_TYPE:
226 + default: // unknown counter types
227 + pRawData->Data = 0;
228 + pRawData->Time = 0;
229 + fSuccess = FALSE;
230 + break;
231 + }
232 +
233 + return fSuccess;
234 +}
235 +
236 +// --------------------------------------------------------------------------------------------------------------------
237 +
238 +static inline BOOL isValidPointer(PERF_DATA_BLOCK *pDataBlock __maybe_unused, void *ptr __maybe_unused) {
239 +#ifdef NETDATA_INTERNAL_CHECKS
240 + return (PBYTE)ptr >= (PBYTE)pDataBlock + pDataBlock->TotalByteLength ? FALSE : TRUE;
241 +#else
242 + return TRUE;
243 +#endif
244 +}
245 +
246 +static inline BOOL isValidStructure(PERF_DATA_BLOCK *pDataBlock __maybe_unused, void *ptr __maybe_unused, size_t length __maybe_unused) {
247 +#ifdef NETDATA_INTERNAL_CHECKS
248 + return (PBYTE)ptr + length > (PBYTE)pDataBlock + pDataBlock->TotalByteLength ? FALSE : TRUE;
249 +#else
250 + return TRUE;
251 +#endif
252 +}
253 +
254 +static inline PERF_DATA_BLOCK *getDataBlock(BYTE *pBuffer) {
255 + PERF_DATA_BLOCK *pDataBlock = (PERF_DATA_BLOCK *)pBuffer;
256 +
257 + static WCHAR signature[] = { 'P', 'E', 'R', 'F' };
258 +
259 + if(memcmp(pDataBlock->Signature, signature, sizeof(signature)) != 0) {
260 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
261 + "WINDOWS: PERFLIB: Invalid data block signature.");
262 + return NULL;
263 + }
264 +
265 + if(!isValidPointer(pDataBlock, (PBYTE)pDataBlock + pDataBlock->SystemNameOffset) ||
266 + !isValidStructure(pDataBlock, (PBYTE)pDataBlock + pDataBlock->SystemNameOffset, pDataBlock->SystemNameLength)) {
267 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
268 + "WINDOWS: PERFLIB: Invalid system name array.");
269 + return NULL;
270 + }
271 +
272 + return pDataBlock;
273 +}
274 +
275 +static inline PERF_OBJECT_TYPE *getObjectType(PERF_DATA_BLOCK* pDataBlock, PERF_OBJECT_TYPE *lastObjectType) {
276 + PERF_OBJECT_TYPE* pObjectType = NULL;
277 +
278 + if(!lastObjectType)
279 + pObjectType = (PERF_OBJECT_TYPE *)((PBYTE)pDataBlock + pDataBlock->HeaderLength);
280 + else if (lastObjectType->TotalByteLength != 0)
281 + pObjectType = (PERF_OBJECT_TYPE *)((PBYTE)lastObjectType + lastObjectType->TotalByteLength);
282 +
283 + if(pObjectType && (!isValidPointer(pDataBlock, pObjectType) || !isValidStructure(pDataBlock, pObjectType, pObjectType->TotalByteLength))) {
284 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
285 + "WINDOWS: PERFLIB: Invalid ObjectType!");
286 + pObjectType = NULL;
287 + }
288 +
289 + return pObjectType;
290 +}
291 +
292 +inline PERF_OBJECT_TYPE *getObjectTypeByIndex(PERF_DATA_BLOCK *pDataBlock, DWORD ObjectNameTitleIndex) {
293 + PERF_OBJECT_TYPE *po = NULL;
294 + for(DWORD o = 0; o < pDataBlock->NumObjectTypes ; o++) {
295 + po = getObjectType(pDataBlock, po);
296 + if(po->ObjectNameTitleIndex == ObjectNameTitleIndex)
297 + return po;
298 + }
299 +
300 + return NULL;
301 +}
302 +
303 +static inline PERF_INSTANCE_DEFINITION *getInstance(
304 + PERF_DATA_BLOCK *pDataBlock,
305 + PERF_OBJECT_TYPE *pObjectType,
306 + PERF_COUNTER_BLOCK *lastCounterBlock
307 +) {
308 + PERF_INSTANCE_DEFINITION *pInstance;
309 +
310 + if(!lastCounterBlock)
311 + pInstance = (PERF_INSTANCE_DEFINITION *)((PBYTE)pObjectType + pObjectType->DefinitionLength);
312 + else
313 + pInstance = (PERF_INSTANCE_DEFINITION *)((PBYTE)lastCounterBlock + lastCounterBlock->ByteLength);
314 +
315 + if(pInstance && (!isValidPointer(pDataBlock, pInstance) || !isValidStructure(pDataBlock, pInstance, pInstance->ByteLength))) {
316 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
317 + "WINDOWS: PERFLIB: Invalid Instance Definition!");
318 + pInstance = NULL;
319 + }
320 +
321 + return pInstance;
322 +}
323 +
324 +static inline PERF_COUNTER_BLOCK *getObjectTypeCounterBlock(
325 + PERF_DATA_BLOCK *pDataBlock,
326 + PERF_OBJECT_TYPE *pObjectType
327 +) {
328 + PERF_COUNTER_BLOCK *pCounterBlock = (PERF_COUNTER_BLOCK *)((PBYTE)pObjectType + pObjectType->DefinitionLength);
329 +
330 + if(pCounterBlock && (!isValidPointer(pDataBlock, pCounterBlock) || !isValidStructure(pDataBlock, pCounterBlock, pCounterBlock->ByteLength))) {
331 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
332 + "WINDOWS: PERFLIB: Invalid ObjectType CounterBlock!");
333 + pCounterBlock = NULL;
334 + }
335 +
336 + return pCounterBlock;
337 +}
338 +
339 +static inline PERF_COUNTER_BLOCK *getInstanceCounterBlock(
340 + PERF_DATA_BLOCK *pDataBlock,
341 + PERF_OBJECT_TYPE *pObjectType,
342 + PERF_INSTANCE_DEFINITION *pInstance
343 +) {
344 + (void)pObjectType;
345 + PERF_COUNTER_BLOCK *pCounterBlock = (PERF_COUNTER_BLOCK *)((PBYTE)pInstance + pInstance->ByteLength);
346 +
347 + if(pCounterBlock && (!isValidPointer(pDataBlock, pCounterBlock) || !isValidStructure(pDataBlock, pCounterBlock, pCounterBlock->ByteLength))) {
348 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
349 + "WINDOWS: PERFLIB: Invalid Instance CounterBlock!");
350 + pCounterBlock = NULL;
351 + }
352 +
353 + return pCounterBlock;
354 +}
355 +
356 +inline PERF_INSTANCE_DEFINITION *getInstanceByPosition(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, DWORD instancePosition) {
357 + PERF_INSTANCE_DEFINITION *pi = NULL;
358 + PERF_COUNTER_BLOCK *pc = NULL;
359 + for(DWORD i = 0; i <= instancePosition ;i++) {
360 + pi = getInstance(pDataBlock, pObjectType, pc);
361 + pc = getInstanceCounterBlock(pDataBlock, pObjectType, pi);
362 + }
363 + return pi;
364 +}
365 +
366 +static inline PERF_COUNTER_DEFINITION *getCounterDefinition(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_COUNTER_DEFINITION *lastCounterDefinition) {
367 + PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
368 +
369 + if(!lastCounterDefinition)
370 + pCounterDefinition = (PERF_COUNTER_DEFINITION *)((PBYTE)pObjectType + pObjectType->HeaderLength);
371 + else
372 + pCounterDefinition = (PERF_COUNTER_DEFINITION *)((PBYTE)lastCounterDefinition + lastCounterDefinition->ByteLength);
373 +
374 + if(pCounterDefinition && (!isValidPointer(pDataBlock, pCounterDefinition) || !isValidStructure(pDataBlock, pCounterDefinition, pCounterDefinition->ByteLength))) {
375 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
376 + "WINDOWS: PERFLIB: Invalid Counter Definition!");
377 + pCounterDefinition = NULL;
378 + }
379 +
380 + return pCounterDefinition;
381 +}
382 +
383 +// --------------------------------------------------------------------------------------------------------------------
384 +
385 +static inline BOOL getEncodedStringToUTF8(char *dst, size_t dst_len, DWORD CodePage, char *start, DWORD length) {
386 + WCHAR *tempBuffer; // Temporary buffer for Unicode data
387 + DWORD charsCopied = 0;
388 + BOOL free_tempBuffer;
389 +
390 + if (CodePage == 0) {
391 + // Input is already Unicode (UTF-16)
392 + tempBuffer = (WCHAR *)start;
393 + charsCopied = length / sizeof(WCHAR); // Convert byte length to number of WCHARs
394 + free_tempBuffer = FALSE;
395 + }
396 + else {
397 + // Convert the multi-byte instance name to Unicode (UTF-16)
398 + // Calculate maximum possible characters in UTF-16
399 +
400 + int charCount = MultiByteToWideChar(CodePage, 0, start, (int)length, NULL, 0);
401 + tempBuffer = (WCHAR *)malloc(charCount * sizeof(WCHAR));
402 + if (!tempBuffer) return FALSE;
403 +
404 + charsCopied = MultiByteToWideChar(CodePage, 0, start, (int)length, tempBuffer, charCount);
405 + if (charsCopied == 0) {
406 + free(tempBuffer);
407 + dst[0] = '\0';
408 + return FALSE;
409 + }
410 +
411 + free_tempBuffer = TRUE;
412 + }
413 +
414 + // Now convert from Unicode (UTF-16) to UTF-8
415 + int bytesCopied = WideCharToMultiByte(CP_UTF8, 0, tempBuffer, (int)charsCopied, dst, (int)dst_len, NULL, NULL);
416 + if (bytesCopied == 0) {
417 + if (free_tempBuffer) free(tempBuffer);
418 + dst[0] = '\0'; // Ensure the buffer is null-terminated even on failure
419 + return FALSE;
420 + }
421 +
422 + dst[bytesCopied] = '\0'; // Ensure buffer is null-terminated
423 + if (free_tempBuffer) free(tempBuffer); // Free temporary buffer if used
424 + return TRUE;
425 +}
426 +
427 +inline BOOL getInstanceName(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance,
428 + char *buffer, size_t bufferLen) {
429 + (void)pDataBlock;
430 + if (!pInstance || !buffer || !bufferLen) return FALSE;
431 +
432 + return getEncodedStringToUTF8(buffer, bufferLen, pObjectType->CodePage,
433 + ((char *)pInstance + pInstance->NameOffset), pInstance->NameLength);
434 +}
435 +
436 +inline BOOL getSystemName(PERF_DATA_BLOCK *pDataBlock, char *buffer, size_t bufferLen) {
437 + return getEncodedStringToUTF8(buffer, bufferLen, 0,
438 + ((char *)pDataBlock + pDataBlock->SystemNameOffset), pDataBlock->SystemNameLength);
439 +}
440 +
441 +inline bool ObjectTypeHasInstances(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType) {
442 + (void)pDataBlock;
443 + return pObjectType->NumInstances != PERF_NO_INSTANCES && pObjectType->NumInstances > 0;
444 +}
445 +
446 +PERF_OBJECT_TYPE *perflibFindObjectTypeByName(PERF_DATA_BLOCK *pDataBlock, const char *name) {
447 + PERF_OBJECT_TYPE* pObjectType = NULL;
448 + for(DWORD o = 0; o < pDataBlock->NumObjectTypes; o++) {
449 + pObjectType = getObjectType(pDataBlock, pObjectType);
450 + if(strcmp(name, RegistryFindNameByID(pObjectType->ObjectNameTitleIndex)) == 0)
451 + return pObjectType;
452 + }
453 +
454 + return NULL;
455 +}
456 +
457 +PERF_INSTANCE_DEFINITION *perflibForEachInstance(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *lastInstance) {
458 + if(!ObjectTypeHasInstances(pDataBlock, pObjectType))
459 + return NULL;
460 +
461 + return getInstance(pDataBlock, pObjectType,
462 + lastInstance ?
463 + getInstanceCounterBlock(pDataBlock, pObjectType, lastInstance) :
464 + NULL );
465 +}
466 +
467 +bool perflibGetInstanceCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, COUNTER_DATA *cd) {
468 + PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
469 + for(DWORD c = 0; c < pObjectType->NumCounters ;c++) {
470 + pCounterDefinition = getCounterDefinition(pDataBlock, pObjectType, pCounterDefinition);
471 + if(!pCounterDefinition) {
472 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
473 + "WINDOWS: PERFLIB: Cannot read counter definition No %u (out of %u)",
474 + c, pObjectType->NumCounters);
475 + break;
476 + }
477 +
478 + if(cd->id) {
479 + if(cd->id != pCounterDefinition->CounterNameTitleIndex)
480 + continue;
481 + }
482 + else {
483 + if(strcmp(RegistryFindNameByID(pCounterDefinition->CounterNameTitleIndex), cd->key) != 0)
484 + continue;
485 +
486 + cd->id = pCounterDefinition->CounterNameTitleIndex;
487 + }
488 +
489 + cd->current.CounterType = cd->OverwriteCounterType ? cd->OverwriteCounterType : pCounterDefinition->CounterType;
490 + PERF_COUNTER_BLOCK *pCounterBlock = getInstanceCounterBlock(pDataBlock, pObjectType, pInstance);
491 +
492 + cd->previous = cd->current;
493 + cd->updated = getCounterData(pDataBlock, pObjectType, pCounterDefinition, pCounterBlock, &cd->current);
494 + return cd->updated;
495 + }
496 +
497 + cd->previous = cd->current;
498 + cd->current = RAW_DATA_EMPTY;
499 + cd->updated = false;
500 + return false;
501 +}
502 +
503 +bool perflibGetObjectCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, COUNTER_DATA *cd) {
504 + PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
505 + for(DWORD c = 0; c < pObjectType->NumCounters ;c++) {
506 + pCounterDefinition = getCounterDefinition(pDataBlock, pObjectType, pCounterDefinition);
507 + if(!pCounterDefinition) {
508 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
509 + "WINDOWS: PERFLIB: Cannot read counter definition No %u (out of %u)",
510 + c, pObjectType->NumCounters);
511 + break;
512 + }
513 +
514 + if(cd->id) {
515 + if(cd->id != pCounterDefinition->CounterNameTitleIndex)
516 + continue;
517 + }
518 + else {
519 + if(strcmp(RegistryFindNameByID(pCounterDefinition->CounterNameTitleIndex), cd->key) != 0)
520 + continue;
521 +
522 + cd->id = pCounterDefinition->CounterNameTitleIndex;
523 + }
524 +
525 + cd->current.CounterType = cd->OverwriteCounterType ? cd->OverwriteCounterType : pCounterDefinition->CounterType;
526 + PERF_COUNTER_BLOCK *pCounterBlock = getObjectTypeCounterBlock(pDataBlock, pObjectType);
527 +
528 + cd->previous = cd->current;
529 + cd->updated = getCounterData(pDataBlock, pObjectType, pCounterDefinition, pCounterBlock, &cd->current);
530 + return cd->updated;
531 + }
532 +
533 + cd->previous = cd->current;
534 + cd->current = RAW_DATA_EMPTY;
535 + cd->updated = false;
536 + return false;
537 +}
538 +
539 +PERF_DATA_BLOCK *perflibGetPerformanceData(DWORD id) {
540 + char source[24];
541 + snprintfz(source, sizeof(source), "%u", id);
542 +
543 + LPBYTE pData = (LPBYTE)getPerformanceData((id > 0) ? source : NULL);
544 + if (!pData) return NULL;
545 +
546 + PERF_DATA_BLOCK *pDataBlock = getDataBlock(pData);
547 + if(!pDataBlock) return NULL;
548 +
549 + return pDataBlock;
550 +}
551 +
552 +int perflibQueryAndTraverse(DWORD id,
553 + perflib_data_cb dataCb,
554 + perflib_object_cb objectCb,
555 + perflib_instance_cb instanceCb,
556 + perflib_instance_counter_cb instanceCounterCb,
557 + perflib_counter_cb counterCb,
558 + void *data) {
559 + int counters = -1;
560 +
561 + PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
562 + if(!pDataBlock) goto cleanup;
563 +
564 + bool do_data = true;
565 + if(dataCb)
566 + do_data = dataCb(pDataBlock, data);
567 +
568 + PERF_OBJECT_TYPE* pObjectType = NULL;
569 + for(DWORD o = 0; do_data && o < pDataBlock->NumObjectTypes; o++) {
570 + pObjectType = getObjectType(pDataBlock, pObjectType);
571 + if(!pObjectType) {
572 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
573 + "WINDOWS: PERFLIB: Cannot read object type No %d (out of %d)",
574 + o, pDataBlock->NumObjectTypes);
575 + break;
576 + }
577 +
578 + bool do_object = true;
579 + if(objectCb)
580 + do_object = objectCb(pDataBlock, pObjectType, data);
581 +
582 + if(!do_object)
583 + continue;
584 +
585 + if(ObjectTypeHasInstances(pDataBlock, pObjectType)) {
586 + PERF_INSTANCE_DEFINITION *pInstance = NULL;
587 + PERF_COUNTER_BLOCK *pCounterBlock = NULL;
588 + for(LONG i = 0; i < pObjectType->NumInstances ;i++) {
589 + pInstance = getInstance(pDataBlock, pObjectType, pCounterBlock);
590 + if(!pInstance) {
591 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
592 + "WINDOWS: PERFLIB: Cannot read Instance No %d (out of %d)",
593 + i, pObjectType->NumInstances);
594 + break;
595 + }
596 +
597 + pCounterBlock = getInstanceCounterBlock(pDataBlock, pObjectType, pInstance);
598 + if(!pCounterBlock) {
599 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
600 + "WINDOWS: PERFLIB: Cannot read CounterBlock of instance No %d (out of %d)",
601 + i, pObjectType->NumInstances);
602 + break;
603 + }
604 +
605 + bool do_instance = true;
606 + if(instanceCb)
607 + do_instance = instanceCb(pDataBlock, pObjectType, pInstance, data);
608 +
609 + if(!do_instance)
610 + continue;
611 +
612 + PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
613 + for(DWORD c = 0; c < pObjectType->NumCounters ;c++) {
614 + pCounterDefinition = getCounterDefinition(pDataBlock, pObjectType, pCounterDefinition);
615 + if(!pCounterDefinition) {
616 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
617 + "WINDOWS: PERFLIB: Cannot read counter definition No %u (out of %u)",
618 + c, pObjectType->NumCounters);
619 + break;
620 + }
621 +
622 + RAW_DATA sample = {
623 + .CounterType = pCounterDefinition->CounterType,
624 + };
625 + if(getCounterData(pDataBlock, pObjectType, pCounterDefinition, pCounterBlock, &sample)) {
626 + // DisplayCalculatedValue(&sample, &sample);
627 +
628 + if(instanceCounterCb) {
629 + instanceCounterCb(pDataBlock, pObjectType, pInstance, pCounterDefinition, &sample, data);
630 + counters++;
631 + }
632 + }
633 + }
634 +
635 + if(instanceCb)
636 + instanceCb(pDataBlock, pObjectType, NULL, data);
637 + }
638 + }
639 + else {
640 + PERF_COUNTER_BLOCK *pCounterBlock = getObjectTypeCounterBlock(pDataBlock, pObjectType);
641 + PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
642 + for(DWORD c = 0; c < pObjectType->NumCounters ;c++) {
643 + pCounterDefinition = getCounterDefinition(pDataBlock, pObjectType, pCounterDefinition);
644 + if(!pCounterDefinition) {
645 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
646 + "WINDOWS: PERFLIB: Cannot read counter definition No %u (out of %u)",
647 + c, pObjectType->NumCounters);
648 + break;
649 + }
650 +
651 + RAW_DATA sample = {
652 + .CounterType = pCounterDefinition->CounterType,
653 + };
654 + if(getCounterData(pDataBlock, pObjectType, pCounterDefinition, pCounterBlock, &sample)) {
655 + // DisplayCalculatedValue(&sample, &sample);
656 +
657 + if(counterCb) {
658 + counterCb(pDataBlock, pObjectType, pCounterDefinition, &sample, data);
659 + counters++;
660 + }
661 + }
662 + }
663 + }
664 +
665 + if(objectCb)
666 + objectCb(pDataBlock, NULL, data);
667 + }
668 +
669 +cleanup:
670 + return counters;
671 +}
src/collectors/windows.plugin/perflib.h new
+72
@@ -0,0 +1,72 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_PERFLIB_H
4 +#define NETDATA_PERFLIB_H
5 +
6 +#include "libnetdata/libnetdata.h"
7 +#include <windows.h>
8 +
9 +const char *RegistryFindNameByID(DWORD id);
10 +const char *RegistryFindHelpByID(DWORD id);
11 +DWORD RegistryFindIDByName(const char *name);
12 +#define PERFLIB_REGISTRY_NAME_NOT_FOUND (DWORD)-1
13 +
14 +PERF_DATA_BLOCK *perflibGetPerformanceData(DWORD id);
15 +void perflibFreePerformanceData(void);
16 +PERF_OBJECT_TYPE *perflibFindObjectTypeByName(PERF_DATA_BLOCK *pDataBlock, const char *name);
17 +PERF_INSTANCE_DEFINITION *perflibForEachInstance(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *lastInstance);
18 +
19 +typedef struct _rawdata {
20 + DWORD CounterType;
21 + DWORD MultiCounterData; // Second raw counter value for multi-valued counters
22 + ULONGLONG Data; // Raw counter data
23 + LONGLONG Time; // Is a time value or a base value
24 + LONGLONG Frequency;
25 +} RAW_DATA, *PRAW_DATA;
26 +
27 +typedef struct _counterdata {
28 + DWORD id;
29 + bool updated;
30 + const char *key;
31 + DWORD OverwriteCounterType; // if set, the counter type will be overwritten once read
32 + RAW_DATA current;
33 + RAW_DATA previous;
34 +} COUNTER_DATA;
35 +
36 +#define RAW_DATA_EMPTY (RAW_DATA){ 0 }
37 +
38 +bool perflibGetInstanceCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, COUNTER_DATA *cd);
39 +bool perflibGetObjectCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, COUNTER_DATA *cd);
40 +
41 +typedef bool (*perflib_data_cb)(PERF_DATA_BLOCK *pDataBlock, void *data);
42 +typedef bool (*perflib_object_cb)(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, void *data);
43 +typedef bool (*perflib_instance_cb)(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, void *data);
44 +typedef bool (*perflib_instance_counter_cb)(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, PERF_COUNTER_DEFINITION *pCounter, RAW_DATA *sample, void *data);
45 +typedef bool (*perflib_counter_cb)(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_COUNTER_DEFINITION *pCounter, RAW_DATA *sample, void *data);
46 +
47 +int perflibQueryAndTraverse(DWORD id,
48 + perflib_data_cb dataCb,
49 + perflib_object_cb objectCb,
50 + perflib_instance_cb instanceCb,
51 + perflib_instance_counter_cb instanceCounterCb,
52 + perflib_counter_cb counterCb,
53 + void *data);
54 +
55 +bool ObjectTypeHasInstances(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType);
56 +
57 +BOOL getInstanceName(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance,
58 + char *buffer, size_t bufferLen);
59 +
60 +BOOL getSystemName(PERF_DATA_BLOCK *pDataBlock, char *buffer, size_t bufferLen);
61 +
62 +PERF_OBJECT_TYPE *getObjectTypeByIndex(PERF_DATA_BLOCK *pDataBlock, DWORD ObjectNameTitleIndex);
63 +
64 +PERF_INSTANCE_DEFINITION *getInstanceByPosition(
65 + PERF_DATA_BLOCK *pDataBlock,
66 + PERF_OBJECT_TYPE *pObjectType,
67 + DWORD instancePosition);
68 +
69 +void PerflibNamesRegistryInitialize(void);
70 +void PerflibNamesRegistryUpdate(void);
71 +
72 +#endif //NETDATA_PERFLIB_H
src/collectors/windows.plugin/windows-internals.h new
+18
@@ -0,0 +1,18 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_WINDOWS_INTERNALS_H
4 +#define NETDATA_WINDOWS_INTERNALS_H
5 +
6 +#include <windows.h>
7 +
8 +static inline ULONGLONG FileTimeToULL(FILETIME ft) {
9 + ULARGE_INTEGER ul;
10 + ul.LowPart = ft.dwLowDateTime;
11 + ul.HighPart = ft.dwHighDateTime;
12 + return ul.QuadPart;
13 +}
14 +
15 +#include "perflib.h"
16 +#include "perflib-rrd.h"
17 +
18 +#endif //NETDATA_WINDOWS_INTERNALS_H
src/collectors/windows.plugin/windows_plugin.c new
+109
@@ -0,0 +1,109 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "windows_plugin.h"
4 +
5 +char windows_shared_buffer[8192];
6 +
7 +static struct proc_module {
8 + const char *name;
9 + const char *dim;
10 + int enabled;
11 + int (*func)(int update_every, usec_t dt);
12 + RRDDIM *rd;
13 +} win_modules[] = {
14 +
15 + // system metrics
16 + {.name = "GetSystemUptime", .dim = "GetSystemUptime", .func = do_GetSystemUptime},
17 + {.name = "GetSystemRAM", .dim = "GetSystemRAM", .func = do_GetSystemRAM},
18 +
19 + // the same is provided by PerflibProcessor, with more detailed analysis
20 + //{.name = "GetSystemCPU", .dim = "GetSystemCPU", .func = do_GetSystemCPU},
21 +
22 + {.name = "PerflibProcessor", .dim = "PerflibProcessor", .func = do_PerflibProcessor},
23 + {.name = "PerflibMemory", .dim = "PerflibMemory", .func = do_PerflibMemory},
24 + {.name = "PerflibStorage", .dim = "PerflibStorage", .func = do_PerflibStorage},
25 + {.name = "PerflibNetwork", .dim = "PerflibNetwork", .func = do_PerflibNetwork},
26 +
27 + // the terminator of this array
28 + {.name = NULL, .dim = NULL, .func = NULL}
29 +};
30 +
31 +#if WORKER_UTILIZATION_MAX_JOB_TYPES < 36
32 +#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 36
33 +#endif
34 +
35 +static void windows_main_cleanup(void *pptr) {
36 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
37 + if(!static_thread) return;
38 +
39 + static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
40 +
41 + collector_info("cleaning up...");
42 +
43 + static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
44 +
45 + worker_unregister();
46 +}
47 +
48 +static bool log_windows_module(BUFFER *wb, void *data) {
49 + struct proc_module *pm = data;
50 + buffer_sprintf(wb, PLUGIN_WINDOWS_NAME "[%s]", pm->name);
51 + return true;
52 +}
53 +
54 +void *win_plugin_main(void *ptr) {
55 + worker_register("WIN");
56 +
57 + rrd_collector_started();
58 + PerflibNamesRegistryInitialize();
59 +
60 + CLEANUP_FUNCTION_REGISTER(windows_main_cleanup) cleanup_ptr = ptr;
61 +
62 + // check the enabled status for each module
63 + int i;
64 + for(i = 0; win_modules[i].name; i++) {
65 + struct proc_module *pm = &win_modules[i];
66 +
67 + pm->enabled = config_get_boolean("plugin:windows", pm->name, CONFIG_BOOLEAN_YES);
68 + pm->rd = NULL;
69 +
70 + worker_register_job_name(i, win_modules[i].dim);
71 + }
72 +
73 + usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
74 + heartbeat_t hb;
75 + heartbeat_init(&hb);
76 +
77 +#define LGS_MODULE_ID 0
78 +
79 + ND_LOG_STACK lgs[] = {
80 + [LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, PLUGIN_WINDOWS_NAME),
81 + ND_LOG_FIELD_END(),
82 + };
83 + ND_LOG_STACK_PUSH(lgs);
84 +
85 + while(service_running(SERVICE_COLLECTORS)) {
86 + worker_is_idle();
87 + usec_t hb_dt = heartbeat_next(&hb, step);
88 +
89 + if(unlikely(!service_running(SERVICE_COLLECTORS)))
90 + break;
91 +
92 + PerflibNamesRegistryUpdate();
93 +
94 + for(i = 0; win_modules[i].name; i++) {
95 + if(unlikely(!service_running(SERVICE_COLLECTORS)))
96 + break;
97 +
98 + struct proc_module *pm = &win_modules[i];
99 + if(unlikely(!pm->enabled))
100 + continue;
101 +
102 + worker_is_busy(i);
103 + lgs[LGS_MODULE_ID] = ND_LOG_FIELD_CB(NDF_MODULE, log_windows_module, pm);
104 + pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
105 + lgs[LGS_MODULE_ID] = ND_LOG_FIELD_TXT(NDF_MODULE, PLUGIN_WINDOWS_NAME);
106 + }
107 + }
108 + return NULL;
109 +}
src/collectors/windows.plugin/windows_plugin.h new
+24
@@ -0,0 +1,24 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_WINDOWS_PLUGIN_H
4 +#define NETDATA_WINDOWS_PLUGIN_H
5 +
6 +#include "daemon/common.h"
7 +
8 +#define PLUGIN_WINDOWS_NAME "windows.plugin"
9 +
10 +void *win_plugin_main(void *ptr);
11 +
12 +extern char windows_shared_buffer[8192];
13 +
14 +int do_GetSystemUptime(int update_every, usec_t dt);
15 +int do_GetSystemRAM(int update_every, usec_t dt);
16 +int do_GetSystemCPU(int update_every, usec_t dt);
17 +int do_PerflibStorage(int update_every, usec_t dt);
18 +int do_PerflibNetwork(int update_every, usec_t dt);
19 +int do_PerflibProcessor(int update_every, usec_t dt);
20 +int do_PerflibMemory(int update_every, usec_t dt);
21 +
22 +#include "perflib.h"
23 +
24 +#endif //NETDATA_WINDOWS_PLUGIN_H
src/daemon/analytics.c
+11 -10
@@ -223,7 +223,7 @@ void analytics_mirrored_hosts(void)
223
224 count++;
225 }
226 - rrd_unlock();
226 + rrd_rdunlock();
227
228 snprintfz(b, sizeof(b) - 1, "%zu", count);
229 analytics_set_data(&analytics_data.netdata_mirrored_host_count, b);
@@ -562,9 +562,11 @@ void analytics_gather_mutable_meta_data(void)
562 }
563 }
564
565 -void analytics_main_cleanup(void *ptr)
565 +void analytics_main_cleanup(void *pptr)
566 {
567 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
567 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
568 + if(!static_thread) return;
569 +
570 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
571
572 netdata_log_debug(D_ANALYTICS, "Cleaning up...");
@@ -581,7 +583,7 @@ void analytics_main_cleanup(void *ptr)
583 */
584 void *analytics_main(void *ptr)
585 {
584 - netdata_thread_cleanup_push(analytics_main_cleanup, ptr);
586 + CLEANUP_FUNCTION_REGISTER(analytics_main_cleanup) cleanup_ptr = ptr;
587 unsigned int sec = 0;
588 heartbeat_t hb;
589 heartbeat_init(&hb);
@@ -626,7 +628,6 @@ void *analytics_main(void *ptr)
628 }
629
630 cleanup:
629 - netdata_thread_cleanup_pop(1);
631 return NULL;
632 }
633
@@ -777,7 +778,7 @@ void get_system_timezone(void)
778 *d = '\0';
779
780 while (*timezone) {
780 - if (isalnum(*timezone) || *timezone == '_' || *timezone == '/')
781 + if (isalnum((uint8_t)*timezone) || *timezone == '_' || *timezone == '/')
782 *d++ = *timezone++;
783 else
784 timezone++;
@@ -816,11 +817,11 @@ void get_system_timezone(void)
817 } else {
818 sign[0] = zone[0] == '-' || zone[0] == '+' ? zone[0] : '0';
819 sign[1] = '\0';
819 - hh[0] = isdigit(zone[1]) ? zone[1] : '0';
820 - hh[1] = isdigit(zone[2]) ? zone[2] : '0';
820 + hh[0] = isdigit((uint8_t)zone[1]) ? zone[1] : '0';
821 + hh[1] = isdigit((uint8_t)zone[2]) ? zone[2] : '0';
822 hh[2] = '\0';
822 - mm[0] = isdigit(zone[3]) ? zone[3] : '0';
823 - mm[1] = isdigit(zone[4]) ? zone[4] : '0';
823 + mm[0] = isdigit((uint8_t)zone[3]) ? zone[3] : '0';
824 + mm[1] = isdigit((uint8_t)zone[4]) ? zone[4] : '0';
825 mm[2] = '\0';
826
827 netdata_configured_utc_offset = (str2i(hh) * 3600) + (str2i(mm) * 60);
src/daemon/buildinfo.c
+10
@@ -1058,6 +1058,16 @@ __attribute__((constructor)) void initialize_build_info(void) {
1058 build_info_set_value(BIB_FEATURE_BUILT_FOR, "MacOS");
1059 build_info_set_status(BIB_PLUGIN_MACOS, true);
1060 #endif
1061 +#ifdef COMPILED_FOR_WINDOWS
1062 + build_info_set_status(BIB_FEATURE_BUILT_FOR, true);
1063 +#if defined(__CYGWIN__) && defined(__MSYS__)
1064 + build_info_set_value(BIB_FEATURE_BUILT_FOR, "Windows (MSYS)");
1065 +#elif defined(__CYGWIN__)
1066 + build_info_set_value(BIB_FEATURE_BUILT_FOR, "Windows (CYGWIN)");
1067 +#else
1068 + build_info_set_value(BIB_FEATURE_BUILT_FOR, "Windows");
1069 +#endif
1070 +#endif
1071
1072 #ifdef ENABLE_ACLK
1073 build_info_set_status(BIB_FEATURE_CLOUD, true);
src/daemon/commands.c
+6 -6
@@ -483,15 +483,15 @@ static void parse_commands(struct command_context *cmd_ctx)
483 status = CMD_STATUS_FAILURE;
484
485 /* Skip white-space characters */
486 - for (pos = cmd_ctx->command_string ; isspace(*pos) && ('\0' != *pos) ; ++pos) ;
486 + for (pos = cmd_ctx->command_string ; isspace((uint8_t)*pos) && ('\0' != *pos) ; ++pos) ;
487 for (i = 0 ; i < CMD_TOTAL_COMMANDS ; ++i) {
488 if (!strncmp(pos, command_info_array[i].cmd_str, strlen(command_info_array[i].cmd_str))) {
489 if (CMD_EXIT == i) {
490 /* musl C does not like libuv workqueues calling exit() */
491 execute_command(CMD_EXIT, NULL, NULL);
492 }
493 - for (lstrip=pos + strlen(command_info_array[i].cmd_str); isspace(*lstrip) && ('\0' != *lstrip); ++lstrip) ;
494 - for (rstrip=lstrip+strlen(lstrip)-1; rstrip>lstrip && isspace(*rstrip); *(rstrip--) = 0 ) ;
493 + for (lstrip=pos + strlen(command_info_array[i].cmd_str); isspace((uint8_t)*lstrip) && ('\0' != *lstrip); ++lstrip) ;
494 + for (rstrip=lstrip+strlen(lstrip)-1; rstrip>lstrip && isspace((uint8_t)*rstrip); *(rstrip--) = 0 ) ;
495
496 cmd_ctx->work.data = cmd_ctx;
497 cmd_ctx->idx = i;
@@ -596,8 +596,9 @@ static void async_cb(uv_async_t *handle)
596 uv_stop(handle->loop);
597 }
598
599 -static void command_thread(void *arg)
600 -{
599 +static void command_thread(void *arg) {
600 + uv_thread_set_name_np("DAEMON_COMMAND");
601 +
602 int ret;
603 uv_fs_t req;
604
@@ -714,7 +715,6 @@ void commands_init(void)
715 /* wait for worker thread to initialize */
716 completion_wait_for(&completion);
717 completion_destroy(&completion);
717 - uv_thread_set_name_np(thread, "DAEMON_COMMAND");
718
719 if (command_thread_error) {
720 error = uv_thread_join(&thread);
src/daemon/common.c
+3 -3
@@ -31,9 +31,9 @@ long get_netdata_cpus(void) {
31 if(processors)
32 return processors;
33
34 - long cores_proc_stat = get_system_cpus_with_cache(false, true);
35 - long cores_cpuset_v1 = (long)read_cpuset_cpus("/sys/fs/cgroup/cpuset/cpuset.cpus", cores_proc_stat);
36 - long cores_cpuset_v2 = (long)read_cpuset_cpus("/sys/fs/cgroup/cpuset.cpus", cores_proc_stat);
34 + long cores_proc_stat = os_get_system_cpus_cached(false, true);
35 + long cores_cpuset_v1 = (long)os_read_cpuset_cpus("/sys/fs/cgroup/cpuset/cpuset.cpus", cores_proc_stat);
36 + long cores_cpuset_v2 = (long)os_read_cpuset_cpus("/sys/fs/cgroup/cpuset.cpus", cores_proc_stat);
37
38 if(cores_cpuset_v2)
39 processors = cores_cpuset_v2;
src/daemon/config/dyncfg-files.c
+14 -3
@@ -226,16 +226,27 @@ static bool dyncfg_read_file_to_buffer(const char *filename, BUFFER *dst) {
226 return true;
227 }
228
229 -bool dyncfg_get_schema(const char *id, BUFFER *dst) {
229 +static bool dyncfg_get_schema_from(const char *dir, const char *id, BUFFER *dst) {
230 char filename[FILENAME_MAX + 1];
231
232 - snprintfz(filename, sizeof(filename), "%s/schema.d/%s.json", netdata_configured_user_config_dir, id);
232 + snprintfz(filename, sizeof(filename), "%s/schema.d/%s.json", dir, id);
233 if(dyncfg_read_file_to_buffer(filename, dst))
234 return true;
235
236 - snprintfz(filename, sizeof(filename), "%s/schema.d/%s.json", netdata_configured_stock_config_dir, id);
236 + CLEAN_CHAR_P *escaped_id = dyncfg_escape_id_for_filename(id);
237 + snprintfz(filename, sizeof(filename), "%s/schema.d/%s.json", dir, escaped_id);
238 if(dyncfg_read_file_to_buffer(filename, dst))
239 return true;
240
241 return false;
242 }
243 +
244 +bool dyncfg_get_schema(const char *id, BUFFER *dst) {
245 + if(dyncfg_get_schema_from(netdata_configured_user_config_dir, id, dst))
246 + return true;
247 +
248 + if(dyncfg_get_schema_from(netdata_configured_stock_config_dir, id, dst))
249 + return true;
250 +
251 + return false;
252 +}
src/daemon/config/dyncfg-internals.h
+2 -2
@@ -10,7 +10,7 @@
10 #include "database/rrdcollector-internals.h"
11
12 typedef struct dyncfg {
13 - UUID host_uuid;
13 + ND_UUID host_uuid;
14 STRING *function;
15 STRING *template;
16 STRING *path;
@@ -80,7 +80,7 @@ const DICTIONARY_ITEM *dyncfg_get_template_of_new_job(const char *job_id);
80
81 bool dyncfg_is_user_disabled(const char *id);
82
83 -RRDHOST *dyncfg_rrdhost_by_uuid(UUID *uuid);
83 +RRDHOST *dyncfg_rrdhost_by_uuid(ND_UUID *uuid);
84 RRDHOST *dyncfg_rrdhost(DYNCFG *df);
85
86 static inline void dyncfg_copy_dyncfg_source_to_current(DYNCFG *df) {
src/daemon/config/dyncfg-tree.c
+1 -1
@@ -71,7 +71,7 @@ static void dyncfg_tree_for_host(RRDHOST *host, BUFFER *wb, const char *path, co
71 if(id && *id)
72 template = string_strdupz(id);
73
74 - UUID host_uuid = uuid2UUID(host->host_uuid);
74 + ND_UUID host_uuid = uuid2UUID(host->host_uuid);
75
76 size_t path_len = strlen(path);
77 DYNCFG *df;
src/daemon/config/dyncfg-unittest.c
+8 -10
@@ -165,8 +165,8 @@ static int dyncfg_unittest_action(struct dyncfg_unittest_action *a) {
165 return rc;
166 }
167
168 -static void *dyncfg_unittest_thread_action(void *ptr __maybe_unused) {
169 - while(1) {
168 +static void *dyncfg_unittest_thread_action(void *ptr) {
169 + while(!nd_thread_signaled_to_cancel()) {
170 struct dyncfg_unittest_action *a = NULL;
171 spinlock_lock(&dyncfg_unittest_data.spinlock);
172 a = dyncfg_unittest_data.queue;
@@ -179,6 +179,8 @@ static void *dyncfg_unittest_thread_action(void *ptr __maybe_unused) {
179 else
180 sleep_usec(10 * USEC_PER_MS);
181 }
182 +
183 + return ptr;
184 }
185
186 static int dyncfg_unittest_execute_cb(struct rrd_function_execute *rfe, void *data) {
@@ -300,8 +302,7 @@ static bool dyncfg_unittest_check(TEST *t, DYNCFG_CMDS c, const char *cmd, bool
302
303 usec_t give_up_ut = now_monotonic_usec() + 2 * USEC_PER_SEC;
304 while(!__atomic_load_n(&t->finished, __ATOMIC_RELAXED)) {
303 - static const struct timespec ns = { .tv_sec = 0, .tv_nsec = 1 };
304 - nanosleep(&ns, NULL);
305 + tinysleep();
306
307 if(now_monotonic_usec() > give_up_ut) {
308 fprintf(stderr, "\n - gave up waiting for the plugin to process this!");
@@ -579,9 +580,7 @@ int dyncfg_unittest(void) {
580 // ------------------------------------------------------------------------
581 // create the thread for testing async communication
582
582 - netdata_thread_t thread;
583 - netdata_thread_create(&thread, "unittest", NETDATA_THREAD_OPTION_JOINABLE,
584 - dyncfg_unittest_thread_action, NULL);
583 + ND_THREAD *thread = nd_thread_create("unittest", NETDATA_THREAD_OPTION_JOINABLE, dyncfg_unittest_thread_action, NULL);
584
585 // ------------------------------------------------------------------------
586 // single
@@ -791,9 +790,8 @@ int dyncfg_unittest(void) {
790 // if(rc == HTTP_RESP_OK)
791 // fprintf(stderr, "%s\n", buffer_tostring(wb));
792
794 - void *ptr;
795 - netdata_thread_cancel(thread);
796 - netdata_thread_join(thread, &ptr);
793 + nd_thread_signal_cancel(thread);
794 + nd_thread_join(thread);
795 dyncfg_unittest_cleanup_files();
796 dictionary_destroy(dyncfg_unittest_data.nodes);
797 buffer_free(wb);
src/daemon/config/dyncfg.c
+2 -2
@@ -5,7 +5,7 @@
5
6 struct dyncfg_globals dyncfg_globals = { 0 };
7
8 -RRDHOST *dyncfg_rrdhost_by_uuid(UUID *uuid) {
8 +RRDHOST *dyncfg_rrdhost_by_uuid(ND_UUID *uuid) {
9 char uuid_str[UUID_STR_LEN];
10 uuid_unparse_lower(uuid->uuid, uuid_str);
11
@@ -438,7 +438,7 @@ void dyncfg_add_streaming(BUFFER *wb) {
438 , 120
439 , "Dynamic configuration"
440 , "config"
441 - , HTTP_ACCESS_ANONYMOUS_DATA
441 + , (unsigned)HTTP_ACCESS_ANONYMOUS_DATA
442 , 1000
443 );
444 }
src/daemon/daemon.c
+4 -16
@@ -121,11 +121,7 @@ static int become_user(const char *username, int pid_fd) {
121 gid_t *supplementary_groups = NULL;
122 if(ngroups > 0) {
123 supplementary_groups = mallocz(sizeof(gid_t) * ngroups);
124 -#ifdef __APPLE__
125 - if(getgrouplist(username, gid, (int *)supplementary_groups, &ngroups) == -1) {
126 -#else
127 - if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
128 -#endif /* __APPLE__ */
124 + if(os_getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
125 if(am_i_root)
126 netdata_log_error("Cannot get supplementary groups of user '%s'.", username);
127
@@ -149,20 +145,12 @@ static int become_user(const char *username, int pid_fd) {
145 if(supplementary_groups)
146 freez(supplementary_groups);
147
152 -#ifdef __APPLE__
153 - if(setregid(gid, gid) != 0) {
154 -#else
155 - if(setresgid(gid, gid, gid) != 0) {
156 -#endif /* __APPLE__ */
148 + if(os_setresgid(gid, gid, gid) != 0) {
149 netdata_log_error("Cannot switch to user's %s group (gid: %u).", username, gid);
150 return -1;
151 }
152
161 -#ifdef __APPLE__
162 - if(setreuid(uid, uid) != 0) {
163 -#else
164 - if(setresuid(uid, uid, uid) != 0) {
165 -#endif /* __APPLE__ */
153 + if(os_setresuid(uid, uid, uid) != 0) {
154 netdata_log_error("Cannot switch to user %s (uid: %u).", username, uid);
155 return -1;
156 }
@@ -218,7 +206,7 @@ static void oom_score_adj(void) {
206
207 // check netdata.conf configuration
208 s = config_get(CONFIG_SECTION_GLOBAL, "OOM score", s);
221 - if(s && *s && (isdigit(*s) || *s == '-' || *s == '+'))
209 + if(s && *s && (isdigit((uint8_t)*s) || *s == '-' || *s == '+'))
210 wanted_score = atoll(s);
211 else if(s && !strcmp(s, "keep")) {
212 netdata_log_info("Out-Of-Memory (OOM) kept as-is (running with %d)", (int) old_score);
src/daemon/event_loop.c
+1 -1
@@ -62,5 +62,5 @@ void register_libuv_worker_jobs() {
62
63 char buf[NETDATA_THREAD_TAG_MAX + 1];
64 snprintfz(buf, NETDATA_THREAD_TAG_MAX, "UV_WORKER[%d]", worker_id);
65 - uv_thread_set_name_np(pthread_self(), buf);
65 + uv_thread_set_name_np(buf);
66 }
src/daemon/global_statistics.c
+46 -50
@@ -2576,7 +2576,7 @@ static void dbengine2_statistics_charts(void) {
2576 }
2577 }
2578 }
2579 - rrd_unlock();
2579 + rrd_rdunlock();
2580
2581 if (dbengine_contexts) {
2582 /* deduplicate global statistics by getting the ones from the last context */
@@ -3520,6 +3520,7 @@ static struct worker_utilization all_workers_utilization[] = {
3520 { .name = "STATSD", .family = "workers plugin statsd", .priority = 1000000 },
3521 { .name = "STATSDFLUSH", .family = "workers plugin statsd flush", .priority = 1000000 },
3522 { .name = "PROC", .family = "workers plugin proc", .priority = 1000000 },
3523 + { .name = "WIN", .family = "workers plugin windows", .priority = 1000000 },
3524 { .name = "NETDEV", .family = "workers plugin proc netdev", .priority = 1000000 },
3525 { .name = "FREEBSD", .family = "workers plugin freebsd", .priority = 1000000 },
3526 { .name = "MACOS", .family = "workers plugin macos", .priority = 1000000 },
@@ -4155,17 +4156,13 @@ static void worker_utilization_charts(void) {
4156 for(int i = 0; all_workers_utilization[i].name ;i++) {
4157 workers_utilization_reset_statistics(&all_workers_utilization[i]);
4158
4158 - netdata_thread_disable_cancelability();
4159 workers_foreach(all_workers_utilization[i].name, worker_utilization_charts_callback, &all_workers_utilization[i]);
4160 - netdata_thread_enable_cancelability();
4160
4161 // skip the first iteration, so that we don't accumulate startup utilization to our charts
4162 if(likely(iterations > 1))
4163 workers_utilization_update_chart(&all_workers_utilization[i]);
4164
4166 - netdata_thread_disable_cancelability();
4165 workers_threads_cleanup(&all_workers_utilization[i]);
4168 - netdata_thread_enable_cancelability();
4166 }
4167
4168 workers_total_cpu_utilization_chart();
@@ -4215,13 +4212,14 @@ static void global_statistics_register_workers(void) {
4212 worker_register_job_name(WORKER_JOB_SQLITE3, "sqlite3");
4213 }
4214
4218 -static void global_statistics_cleanup(void *ptr)
4215 +static void global_statistics_cleanup(void *pptr)
4216 {
4220 - worker_unregister();
4217 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
4218 + if(!static_thread) return;
4219
4222 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
4220 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
4221
4222 + worker_unregister();
4223 netdata_log_info("cleaning up...");
4224
4225 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
@@ -4229,9 +4227,9 @@ static void global_statistics_cleanup(void *ptr)
4227
4228 void *global_statistics_main(void *ptr)
4229 {
4232 - global_statistics_register_workers();
4230 + CLEANUP_FUNCTION_REGISTER(global_statistics_cleanup) cleanup_ptr = ptr;
4231
4234 - netdata_thread_cleanup_push(global_statistics_cleanup, ptr);
4232 + global_statistics_register_workers();
4233
4234 int update_every =
4235 (int)config_get_number(CONFIG_SECTION_GLOBAL_STATISTICS, "update every", localhost->rrd_update_every);
@@ -4280,7 +4278,6 @@ void *global_statistics_main(void *ptr)
4278 #endif
4279 }
4280
4283 - netdata_thread_cleanup_pop(1);
4281 return NULL;
4282 }
4283
@@ -4288,15 +4285,16 @@ void *global_statistics_main(void *ptr)
4285 // ---------------------------------------------------------------------------------------------------------------------
4286 // workers thread
4287
4291 -static void global_statistics_workers_cleanup(void *ptr)
4288 +static void global_statistics_workers_cleanup(void *pptr)
4289 {
4293 - worker_unregister();
4290 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
4291 + if(!static_thread) return;
4292
4295 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
4293 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
4294
4295 netdata_log_info("cleaning up...");
4296
4297 + worker_unregister();
4298 worker_utilization_finish();
4299
4300 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
@@ -4304,41 +4302,41 @@ static void global_statistics_workers_cleanup(void *ptr)
4302
4303 void *global_statistics_workers_main(void *ptr)
4304 {
4305 + CLEANUP_FUNCTION_REGISTER(global_statistics_workers_cleanup) cleanup_ptr = ptr;
4306 +
4307 global_statistics_register_workers();
4308
4309 - netdata_thread_cleanup_push(global_statistics_workers_cleanup, ptr)
4310 - {
4311 - int update_every =
4312 - (int)config_get_number(CONFIG_SECTION_GLOBAL_STATISTICS, "update every", localhost->rrd_update_every);
4313 - if (update_every < localhost->rrd_update_every)
4314 - update_every = localhost->rrd_update_every;
4309 + int update_every =
4310 + (int)config_get_number(CONFIG_SECTION_GLOBAL_STATISTICS, "update every", localhost->rrd_update_every);
4311 + if (update_every < localhost->rrd_update_every)
4312 + update_every = localhost->rrd_update_every;
4313
4316 - usec_t step = update_every * USEC_PER_SEC;
4317 - heartbeat_t hb;
4318 - heartbeat_init(&hb);
4314 + usec_t step = update_every * USEC_PER_SEC;
4315 + heartbeat_t hb;
4316 + heartbeat_init(&hb);
4317
4320 - while (service_running(SERVICE_COLLECTORS)) {
4321 - worker_is_idle();
4322 - heartbeat_next(&hb, step);
4318 + while (service_running(SERVICE_COLLECTORS)) {
4319 + worker_is_idle();
4320 + heartbeat_next(&hb, step);
4321
4324 - worker_is_busy(WORKER_JOB_WORKERS);
4325 - worker_utilization_charts();
4326 - }
4322 + worker_is_busy(WORKER_JOB_WORKERS);
4323 + worker_utilization_charts();
4324 }
4328 - netdata_thread_cleanup_pop(1);
4325 +
4326 return NULL;
4327 }
4328
4329 // ---------------------------------------------------------------------------------------------------------------------
4330 // sqlite3 thread
4331
4335 -static void global_statistics_sqlite3_cleanup(void *ptr)
4332 +static void global_statistics_sqlite3_cleanup(void *pptr)
4333 {
4337 - worker_unregister();
4334 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
4335 + if(!static_thread) return;
4336
4339 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
4337 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
4338
4339 + worker_unregister();
4340 netdata_log_info("cleaning up...");
4341
4342 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
@@ -4346,29 +4344,27 @@ static void global_statistics_sqlite3_cleanup(void *ptr)
4344
4345 void *global_statistics_sqlite3_main(void *ptr)
4346 {
4349 - global_statistics_register_workers();
4347 + CLEANUP_FUNCTION_REGISTER(global_statistics_sqlite3_cleanup) cleanup_ptr = ptr;
4348
4351 - netdata_thread_cleanup_push(global_statistics_sqlite3_cleanup, ptr)
4352 - {
4349 + global_statistics_register_workers();
4350
4354 - int update_every =
4355 - (int)config_get_number(CONFIG_SECTION_GLOBAL_STATISTICS, "update every", localhost->rrd_update_every);
4356 - if (update_every < localhost->rrd_update_every)
4357 - update_every = localhost->rrd_update_every;
4351 + int update_every =
4352 + (int)config_get_number(CONFIG_SECTION_GLOBAL_STATISTICS, "update every", localhost->rrd_update_every);
4353 + if (update_every < localhost->rrd_update_every)
4354 + update_every = localhost->rrd_update_every;
4355
4359 - usec_t step = update_every * USEC_PER_SEC;
4360 - heartbeat_t hb;
4361 - heartbeat_init(&hb);
4356 + usec_t step = update_every * USEC_PER_SEC;
4357 + heartbeat_t hb;
4358 + heartbeat_init(&hb);
4359
4363 - while (service_running(SERVICE_COLLECTORS)) {
4364 - worker_is_idle();
4365 - heartbeat_next(&hb, step);
4360 + while (service_running(SERVICE_COLLECTORS)) {
4361 + worker_is_idle();
4362 + heartbeat_next(&hb, step);
4363
4367 - worker_is_busy(WORKER_JOB_SQLITE3);
4368 - sqlite3_statistics_charts();
4369 - }
4364 + worker_is_busy(WORKER_JOB_SQLITE3);
4365 + sqlite3_statistics_charts();
4366 }
4371 - netdata_thread_cleanup_pop(1);
4367 +
4368 return NULL;
4369 }
4370
src/daemon/main.c
+40 -22
@@ -42,12 +42,12 @@ typedef struct service_thread {
42 pid_t tid;
43 SERVICE_THREAD_TYPE type;
44 SERVICE_TYPE services;
45 - char name[NETDATA_THREAD_NAME_MAX + 1];
45 + char name[ND_THREAD_TAG_MAX + 1];
46 bool stop_immediately;
47 bool cancelled;
48
49 union {
50 - netdata_thread_t netdata_thread;
50 + ND_THREAD *netdata_thread;
51 uv_thread_t uv_thread;
52 };
53
@@ -65,7 +65,7 @@ struct service_globals {
65
66 SERVICE_THREAD *service_register(SERVICE_THREAD_TYPE thread_type, request_quit_t request_quit_callback, force_quit_t force_quit_callback, void *data, bool update __maybe_unused) {
67 SERVICE_THREAD *sth = NULL;
68 - pid_t tid = gettid();
68 + pid_t tid = gettid_cached();
69
70 spinlock_lock(&service_globals.lock);
71 Pvoid_t *PValue = JudyLIns(&service_globals.pid_judy, tid, PJE0);
@@ -76,13 +76,12 @@ SERVICE_THREAD *service_register(SERVICE_THREAD_TYPE thread_type, request_quit_t
76 sth->request_quit_callback = request_quit_callback;
77 sth->force_quit_callback = force_quit_callback;
78 sth->data = data;
79 - os_thread_get_current_name_np(sth->name);
79 *PValue = sth;
80
81 switch(thread_type) {
82 default:
83 case SERVICE_THREAD_TYPE_NETDATA:
85 - sth->netdata_thread = netdata_thread_self();
84 + sth->netdata_thread = nd_thread_self();
85 break;
86
87 case SERVICE_THREAD_TYPE_EVENT_LOOP:
@@ -90,6 +89,10 @@ SERVICE_THREAD *service_register(SERVICE_THREAD_TYPE thread_type, request_quit_t
89 sth->uv_thread = uv_thread_self();
90 break;
91 }
92 +
93 + const char *name = nd_thread_tag();
94 + if(!name) name = "";
95 + strncpyz(sth->name, name, sizeof(sth->name) - 1);
96 }
97 else {
98 sth = *PValue;
@@ -100,7 +103,7 @@ SERVICE_THREAD *service_register(SERVICE_THREAD_TYPE thread_type, request_quit_t
103 }
104
105 void service_exits(void) {
103 - pid_t tid = gettid();
106 + pid_t tid = gettid_cached();
107
108 spinlock_lock(&service_globals.lock);
109 Pvoid_t *PValue = JudyLGet(service_globals.pid_judy, tid, PJE0);
@@ -119,7 +122,7 @@ bool service_running(SERVICE_TYPE service) {
122
123 sth->services |= service;
124
122 - return !(sth->stop_immediately || netdata_exit);
125 + return !sth->stop_immediately && !netdata_exit && !nd_thread_signaled_to_cancel();
126 }
127
128 void service_signal_exit(SERVICE_TYPE service) {
@@ -134,6 +137,9 @@ void service_signal_exit(SERVICE_TYPE service) {
137 if((sth->services & service)) {
138 sth->stop_immediately = true;
139
140 + // this does not harm - it just raises a flag
141 + nd_thread_signal_cancel(sth->netdata_thread);
142 +
143 if(sth->request_quit_callback) {
144 spinlock_unlock(&service_globals.lock);
145 sth->request_quit_callback(sth->data);
@@ -196,13 +202,13 @@ static bool service_wait_exit(SERVICE_TYPE service, usec_t timeout_ut) {
202 bool first = true;
203 while((PValue = JudyLFirstThenNext(service_globals.pid_judy, &tid, &first))) {
204 SERVICE_THREAD *sth = *PValue;
199 - if(sth->services & service && sth->tid != gettid() && !sth->cancelled) {
205 + if(sth->services & service && sth->tid != gettid_cached() && !sth->cancelled) {
206 sth->cancelled = true;
207
208 switch(sth->type) {
209 default:
210 case SERVICE_THREAD_TYPE_NETDATA:
205 - netdata_thread_cancel(sth->netdata_thread);
211 + nd_thread_signal_cancel(sth->netdata_thread);
212 break;
213
214 case SERVICE_THREAD_TYPE_EVENT_LOOP:
@@ -253,7 +259,7 @@ static bool service_wait_exit(SERVICE_TYPE service, usec_t timeout_ut) {
259 bool first = true;
260 while((PValue = JudyLFirstThenNext(service_globals.pid_judy, &tid, &first))) {
261 SERVICE_THREAD *sth = *PValue;
256 - if(sth->services & service && sth->tid != gettid()) {
262 + if(sth->services & service && sth->tid != gettid_cached()) {
263 if(running)
264 buffer_strcat(thread_list, ", ");
265
@@ -667,7 +673,7 @@ void cancel_main_threads() {
673 if (static_threads[i].enabled == NETDATA_MAIN_THREAD_RUNNING) {
674 if (static_threads[i].thread) {
675 netdata_log_info("EXIT: Stopping main thread: %s", static_threads[i].name);
670 - netdata_thread_cancel(*static_threads[i].thread);
676 + nd_thread_signal_cancel(static_threads[i].thread);
677 } else {
678 netdata_log_info("EXIT: No thread running (marking as EXITED): %s", static_threads[i].name);
679 static_threads[i].enabled = NETDATA_MAIN_THREAD_EXITED;
@@ -688,7 +694,7 @@ void cancel_main_threads() {
694 continue;
695
696 // Don't wait ourselves.
691 - if (static_threads[i].thread && (*static_threads[i].thread == pthread_self()))
697 + if (nd_thread_is_me(static_threads[i].thread))
698 continue;
699
700 found++;
@@ -704,9 +710,6 @@ void cancel_main_threads() {
710 else
711 netdata_log_info("All threads finished.");
712
707 - for (i = 0; static_threads[i].name != NULL ; i++)
708 - freez(static_threads[i].thread);
709 -
713 freez(static_threads);
714 static_threads = NULL;
715 }
@@ -821,6 +824,10 @@ int help(int exitcode) {
824 " Check if string matches pattern and exit.\n\n"
825 " -W \"claim -token=TOKEN -rooms=ROOM1,ROOM2\"\n"
826 " Claim the agent to the workspace rooms pointed to by TOKEN and ROOM*.\n\n"
827 +#ifdef COMPILED_FOR_WINDOWS
828 + " -W perflibdump [key]\n"
829 + " Dump the Windows Performance Counters Registry in JSON.\n\n"
830 +#endif
831 );
832
833 fprintf(stream, "\n Signals netdata handles:\n\n"
@@ -1254,9 +1261,9 @@ static void get_netdata_configured_variables() {
1261 // --------------------------------------------------------------------
1262 // get various system parameters
1263
1257 - get_system_HZ();
1258 - get_system_cpus_uncached();
1259 - get_system_pid_max();
1264 + os_get_system_HZ();
1265 + os_get_system_cpus_uncached();
1266 + os_get_system_pid_max();
1267
1268
1269 }
@@ -1383,6 +1390,10 @@ int uuid_unittest(void);
1390 int progress_unittest(void);
1391 int dyncfg_unittest(void);
1392
1393 +#ifdef COMPILED_FOR_WINDOWS
1394 +int windows_perflib_dump(const char *key);
1395 +#endif
1396 +
1397 int unittest_prepare_rrd(char **user) {
1398 post_conf_load(user);
1399 get_netdata_configured_variables();
@@ -1590,6 +1601,11 @@ int main(int argc, char **argv) {
1601 unittest_running = true;
1602 return uuid_unittest();
1603 }
1604 +#ifdef COMPILED_FOR_WINDOWS
1605 + else if(strcmp(optarg, "perflibdump") == 0) {
1606 + return windows_perflib_dump(optind + 1 > argc ? NULL : argv[optind]);
1607 + }
1608 +#endif
1609 #ifdef ENABLE_DBENGINE
1610 else if(strcmp(optarg, "mctest") == 0) {
1611 unittest_running = true;
@@ -2110,9 +2126,13 @@ int main(int argc, char **argv) {
2126
2127 delta_startup_time("become daemon");
2128
2129 +#if defined(COMPILED_FOR_LINUX) || defined(COMPILED_FOR_MACOS) || defined(COMPILED_FOR_FREEBSD)
2130 // fork, switch user, create pid file, set process priority
2131 if(become_daemon(dont_fork, user) == -1)
2132 fatal("Cannot daemonize myself.");
2133 +#else
2134 + (void)dont_fork;
2135 +#endif
2136
2137 watcher_thread_start();
2138
@@ -2228,9 +2248,8 @@ int main(int argc, char **argv) {
2248 struct netdata_static_thread *st = &static_threads[i];
2249
2250 if(st->enabled) {
2231 - st->thread = mallocz(sizeof(netdata_thread_t));
2251 netdata_log_debug(D_SYSTEM, "Starting thread %s.", st->name);
2233 - netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, st);
2252 + st->thread = nd_thread_create(st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, st);
2253 }
2254 else
2255 netdata_log_debug(D_SYSTEM, "Not starting thread %s.", st->name);
@@ -2266,10 +2285,9 @@ int main(int argc, char **argv) {
2285 for (i = 0; static_threads[i].name != NULL; i++) {
2286 if (!strncmp(static_threads[i].name, "ANALYTICS", 9)) {
2287 struct netdata_static_thread *st = &static_threads[i];
2269 - st->thread = mallocz(sizeof(netdata_thread_t));
2288 st->enabled = 1;
2289 netdata_log_debug(D_SYSTEM, "Starting thread %s.", st->name);
2272 - netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, st);
2290 + st->thread = nd_thread_create(st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, st);
2291 }
2292 }
2293 }
src/daemon/service.c
+8 -6
@@ -218,7 +218,7 @@ static void svc_rrd_cleanup_obsolete_charts_from_all_hosts() {
218 netdata_mutex_unlock(&host->receiver_lock);
219 }
220
221 - rrd_unlock();
221 + rrd_rdunlock();
222 }
223
224 static void svc_rrdhost_cleanup_orphan_hosts(RRDHOST *protected_host) {
@@ -259,12 +259,14 @@ restart_after_removal:
259 goto restart_after_removal;
260 }
261
262 - rrd_unlock();
262 + rrd_wrunlock();
263 }
264
265 -static void service_main_cleanup(void *ptr)
265 +static void service_main_cleanup(void *pptr)
266 {
267 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
267 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
268 + if(!static_thread) return;
269 +
270 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
271
272 netdata_log_debug(D_SYSTEM, "Cleaning up...");
@@ -294,7 +296,8 @@ void *service_main(void *ptr)
296 worker_register_job_name(WORKER_JOB_PGC_OPEN_EVICT, "open cache evictions");
297 worker_register_job_name(WORKER_JOB_PGC_OPEN_FLUSH, "open cache flushes");
298
297 - netdata_thread_cleanup_push(service_main_cleanup, ptr);
299 + CLEANUP_FUNCTION_REGISTER(service_main_cleanup) cleanup_ptr = ptr;
300 +
301 heartbeat_t hb;
302 heartbeat_init(&hb);
303 usec_t step = USEC_PER_SEC * SERVICE_HEARTBEAT;
@@ -317,6 +320,5 @@ void *service_main(void *ptr)
320 svc_rrdhost_cleanup_orphan_hosts(localhost);
321 }
322
320 - netdata_thread_cleanup_pop(1);
323 return NULL;
324 }
src/daemon/static_threads.c
+3
@@ -105,6 +105,8 @@ const struct netdata_static_thread static_threads_common[] = {
105 .init_routine = NULL,
106 .start_routine = statsd_main
107 },
108 +#ifndef COMPILED_FOR_WINDOWS
109 + // this crashes the debugger under windows
110 {
111 .name = "EXPORTING",
112 .config_section = NULL,
@@ -114,6 +116,7 @@ const struct netdata_static_thread static_threads_common[] = {
116 .init_routine = NULL,
117 .start_routine = exporting_main
118 },
119 +#endif
120 {
121 .name = "SNDR[localhost]",
122 .config_section = NULL,
src/daemon/static_threads.h
-3
@@ -6,9 +6,6 @@
6 #include "common.h"
7
8 extern const struct netdata_static_thread static_threads_common[];
9 -extern const struct netdata_static_thread static_threads_linux[];
10 -extern const struct netdata_static_thread static_threads_freebsd[];
11 -extern const struct netdata_static_thread static_threads_macos[];
9
10 struct netdata_static_thread *
11 static_threads_concat(const struct netdata_static_thread *lhs,
src/daemon/static_threads_freebsd.c
+3 -11
@@ -2,10 +2,10 @@
2
3 #include "common.h"
4
5 -extern void *freebsd_main(void *ptr);
6 -extern void *timex_main(void *ptr);
5 +void *freebsd_main(void *ptr);
6 +void *timex_main(void *ptr);
7
8 -const struct netdata_static_thread static_threads_freebsd[] = {
8 +static const struct netdata_static_thread static_threads_freebsd[] = {
9 {
10 .name = "P[freebsd]",
11 .config_section = CONFIG_SECTION_PLUGINS,
@@ -28,14 +28,6 @@ const struct netdata_static_thread static_threads_freebsd[] = {
28 {NULL, NULL, NULL, 0, NULL, NULL, NULL}
29 };
30
31 -const struct netdata_static_thread static_threads_linux[] = {
32 - {NULL, NULL, NULL, 0, NULL, NULL, NULL}
33 -};
34 -
35 -const struct netdata_static_thread static_threads_macos[] = {
36 - {NULL, NULL, NULL, 0, NULL, NULL, NULL}
37 -};
38 -
31 struct netdata_static_thread *static_threads_get() {
32 return static_threads_concat(static_threads_common, static_threads_freebsd);
33 }
src/daemon/static_threads_linux.c
+6 -34
@@ -2,13 +2,13 @@
2
3 #include "common.h"
4
5 -extern void *cgroups_main(void *ptr);
6 -extern void *proc_main(void *ptr);
7 -extern void *diskspace_main(void *ptr);
8 -extern void *tc_main(void *ptr);
9 -extern void *timex_main(void *ptr);
5 +void *cgroups_main(void *ptr);
6 +void *proc_main(void *ptr);
7 +void *diskspace_main(void *ptr);
8 +void *tc_main(void *ptr);
9 +void *timex_main(void *ptr);
10
11 -const struct netdata_static_thread static_threads_linux[] = {
11 +static const struct netdata_static_thread static_threads_linux[] = {
12 {
13 .name = "P[tc]",
14 .config_section = CONFIG_SECTION_PLUGINS,
@@ -68,34 +68,6 @@ const struct netdata_static_thread static_threads_linux[] = {
68 }
69 };
70
71 -const struct netdata_static_thread static_threads_freebsd[] = {
72 - // terminator
73 - {
74 - .name = NULL,
75 - .config_section = NULL,
76 - .config_name = NULL,
77 - .env_name = NULL,
78 - .enabled = 0,
79 - .thread = NULL,
80 - .init_routine = NULL,
81 - .start_routine = NULL
82 - }
83 -};
84 -
85 -const struct netdata_static_thread static_threads_macos[] = {
86 - // terminator
87 - {
88 - .name = NULL,
89 - .config_section = NULL,
90 - .config_name = NULL,
91 - .env_name = NULL,
92 - .enabled = 0,
93 - .thread = NULL,
94 - .init_routine = NULL,
95 - .start_routine = NULL
96 - }
97 -};
98 -
71 struct netdata_static_thread *static_threads_get() {
72 return static_threads_concat(static_threads_common, static_threads_linux);
73 }
src/daemon/static_threads_macos.c
+3 -11
@@ -2,10 +2,10 @@
2
3 #include "common.h"
4
5 -extern void *macos_main(void *ptr);
6 -extern void *timex_main(void *ptr);
5 +void *macos_main(void *ptr);
6 +void *timex_main(void *ptr);
7
8 -const struct netdata_static_thread static_threads_macos[] = {
8 +static const struct netdata_static_thread static_threads_macos[] = {
9 {
10 .name = "P[timex]",
11 .config_section = CONFIG_SECTION_PLUGINS,
@@ -30,14 +30,6 @@ const struct netdata_static_thread static_threads_macos[] = {
30 {NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL}
31 };
32
33 -const struct netdata_static_thread static_threads_freebsd[] = {
34 - {NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL}
35 -};
36 -
37 -const struct netdata_static_thread static_threads_linux[] = {
38 - {NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL}
39 -};
40 -
33 struct netdata_static_thread *static_threads_get() {
34 return static_threads_concat(static_threads_common, static_threads_macos);
35 }
src/daemon/static_threads_windows.c new
+33
@@ -0,0 +1,33 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "common.h"
4 +
5 +void *win_plugin_main(void *ptr);
6 +
7 +static const struct netdata_static_thread static_threads_windows[] = {
8 + {
9 + .name = "P[windows]",
10 + .config_section = CONFIG_SECTION_PLUGINS,
11 + .config_name = "windows",
12 + .enabled = 1,
13 + .thread = NULL,
14 + .init_routine = NULL,
15 + .start_routine = win_plugin_main
16 + },
17 +
18 + // terminator
19 + {
20 + .name = NULL,
21 + .config_section = NULL,
22 + .config_name = NULL,
23 + .env_name = NULL,
24 + .enabled = 0,
25 + .thread = NULL,
26 + .init_routine = NULL,
27 + .start_routine = NULL
28 + }
29 +};
30 +
31 +struct netdata_static_thread *static_threads_get() {
32 + return static_threads_concat(static_threads_common, static_threads_windows);
33 +}
src/daemon/watcher.c
+5 -5
@@ -6,7 +6,7 @@ watcher_step_t *watcher_steps;
6
7 static struct completion shutdown_begin_completion;
8 static struct completion shutdown_end_completion;
9 -static netdata_thread_t watcher_thread;
9 +static ND_THREAD *watcher_thread;
10
11 void watcher_shutdown_begin(void) {
12 completion_mark_complete(&shutdown_begin_completion);
@@ -39,13 +39,13 @@ static void watcher_wait_for_step(const watcher_step_id_t step_id)
39
40 if (ok) {
41 netdata_log_info("shutdown step: [%d/%d] - '%s' finished in %llu milliseconds",
42 - step_id + 1, WATCHER_STEP_ID_MAX,
42 + (int)step_id + 1, (int)WATCHER_STEP_ID_MAX,
43 watcher_steps[step_id].msg, step_duration / USEC_PER_MS);
44 } else {
45 // Do not call fatal() because it will try to execute the exit
46 // sequence twice.
47 netdata_log_error("shutdown step: [%d/%d] - '%s' took more than %u seconds (ie. %llu milliseconds)",
48 - step_id + 1, WATCHER_STEP_ID_MAX, watcher_steps[step_id].msg,
48 + (int)step_id + 1, (int)WATCHER_STEP_ID_MAX, watcher_steps[step_id].msg,
49 timeout, step_duration / USEC_PER_MS);
50
51 abort();
@@ -161,11 +161,11 @@ void watcher_thread_start() {
161 completion_init(&shutdown_begin_completion);
162 completion_init(&shutdown_end_completion);
163
164 - netdata_thread_create(&watcher_thread, "P[WATCHER]", NETDATA_THREAD_OPTION_JOINABLE, watcher_main, NULL);
164 + watcher_thread = nd_thread_create("P[WATCHER]", NETDATA_THREAD_OPTION_JOINABLE, watcher_main, NULL);
165 }
166
167 void watcher_thread_stop() {
168 - netdata_thread_join(watcher_thread, NULL);
168 + nd_thread_join(watcher_thread);
169
170 for (size_t i = 0; i != WATCHER_STEP_ID_MAX; i++) {
171 completion_destroy(&watcher_steps[i].p);
src/database/contexts/api_v2.c
+3 -3
@@ -1580,9 +1580,9 @@ static void contexts_v2_alerts_to_json(BUFFER *wb, struct rrdcontext_to_json_v2_
1580
1581 struct sql_alert_transition_fixed_size {
1582 usec_t global_id;
1583 - uuid_t transition_id;
1584 - uuid_t host_id;
1585 - uuid_t config_hash_id;
1583 + nd_uuid_t transition_id;
1584 + nd_uuid_t host_id;
1585 + nd_uuid_t config_hash_id;
1586 uint32_t alarm_id;
1587 char alert_name[SQL_TRANSITION_DATA_SMALL_STRING];
1588 char chart[RRD_ID_LENGTH_MAX];
src/database/contexts/instance.c
+2 -2
@@ -137,7 +137,7 @@ static bool rrdinstance_conflict_callback(const DICTIONARY_ITEM *item __maybe_un
137 "RRDINSTANCE: '%s' cannot change id to '%s'",
138 string2str(ri->id), string2str(ri_new->id));
139
140 - if(uuid_memcmp(&ri->uuid, &ri_new->uuid) != 0) {
140 + if(!uuid_eq(ri->uuid, ri_new->uuid)) {
141 #ifdef NETDATA_INTERNAL_CHECKS
142 char uuid1[UUID_STR_LEN], uuid2[UUID_STR_LEN];
143 uuid_unparse(ri->uuid, uuid1);
@@ -156,7 +156,7 @@ static bool rrdinstance_conflict_callback(const DICTIONARY_ITEM *item __maybe_un
156 }
157
158 #ifdef NETDATA_INTERNAL_CHECKS
159 - if(ri->rrdset && uuid_memcmp(&ri->uuid, &ri->rrdset->chart_uuid) != 0) {
159 + if(ri->rrdset && !uuid_eq(ri->uuid, ri->rrdset->chart_uuid)) {
160 char uuid1[UUID_STR_LEN], uuid2[UUID_STR_LEN];
161 uuid_unparse(ri->uuid, uuid1);
162 uuid_unparse(ri->rrdset->chart_uuid, uuid2);
src/database/contexts/internal.h
+2 -2
@@ -198,7 +198,7 @@ rrd_flag_add_remove_atomic(RRD_FLAGS *flags, RRD_FLAGS check, RRD_FLAGS conditio
198
199
200 typedef struct rrdmetric {
201 - uuid_t uuid;
201 + nd_uuid_t uuid;
202
203 STRING *id;
204 STRING *name;
@@ -213,7 +213,7 @@ typedef struct rrdmetric {
213 } RRDMETRIC;
214
215 typedef struct rrdinstance {
216 - uuid_t uuid;
216 + nd_uuid_t uuid;
217
218 STRING *id;
219 STRING *name;
src/database/contexts/metric.c
+2 -2
@@ -108,7 +108,7 @@ static bool rrdmetric_conflict_callback(const DICTIONARY_ITEM *item __maybe_unus
108 "RRDMETRIC: '%s' cannot change id to '%s'",
109 string2str(rm->id), string2str(rm_new->id));
110
111 - if(uuid_memcmp(&rm->uuid, &rm_new->uuid) != 0) {
111 + if(!uuid_eq(rm->uuid, rm_new->uuid)) {
112 #ifdef NETDATA_INTERNAL_CHECKS
113 char uuid1[UUID_STR_LEN], uuid2[UUID_STR_LEN];
114 uuid_unparse(rm->uuid, uuid1);
@@ -150,7 +150,7 @@ static bool rrdmetric_conflict_callback(const DICTIONARY_ITEM *item __maybe_unus
150 }
151
152 #ifdef NETDATA_INTERNAL_CHECKS
153 - if(rm->rrddim && uuid_memcmp(&rm->uuid, &rm->rrddim->metric_uuid) != 0) {
153 + if(rm->rrddim && !uuid_eq(rm->uuid, rm->rrddim->metric_uuid)) {
154 char uuid1[UUID_STR_LEN], uuid2[UUID_STR_LEN];
155 uuid_unparse(rm->uuid, uuid1);
156 uuid_unparse(rm_new->uuid, uuid2);
src/database/contexts/rrdcontext.c
+4 -21
@@ -105,7 +105,7 @@ void rrdcontext_db_rotation(void) {
105 rrdcontext_next_db_rotation_ut = now_realtime_usec() + FULL_RETENTION_SCAN_DELAY_AFTER_DB_ROTATION_SECS * USEC_PER_SEC;
106 }
107
108 -int rrdcontext_find_dimension_uuid(RRDSET *st, const char *id, uuid_t *store_uuid) {
108 +int rrdcontext_find_dimension_uuid(RRDSET *st, const char *id, nd_uuid_t *store_uuid) {
109 if(!st->rrdhost) return 1;
110 if(!st->context) return 2;
111
@@ -139,7 +139,7 @@ int rrdcontext_find_dimension_uuid(RRDSET *st, const char *id, uuid_t *store_uui
139 return 0;
140 }
141
142 -int rrdcontext_find_chart_uuid(RRDSET *st, uuid_t *store_uuid) {
142 +int rrdcontext_find_chart_uuid(RRDSET *st, nd_uuid_t *store_uuid) {
143 if(!st->rrdhost) return 1;
144 if(!st->context) return 2;
145
@@ -203,23 +203,6 @@ static bool rrdhost_check_our_claim_id(const char *claim_id) {
203 return (strcasecmp(claim_id, localhost->aclk_state.claimed_id) == 0) ? true : false;
204 }
205
206 -static RRDHOST *rrdhost_find_by_node_id(const char *node_id) {
207 - uuid_t uuid;
208 - if (uuid_parse(node_id, uuid))
209 - return NULL;
210 -
211 - RRDHOST *host = NULL;
212 - dfe_start_read(rrdhost_root_index, host) {
213 - if(!host->node_id) continue;
214 -
215 - if(uuid_memcmp(&uuid, host->node_id) == 0)
216 - break;
217 - }
218 - dfe_done(host);
219 -
220 - return host;
221 -}
222 -
206 void rrdcontext_hub_checkpoint_command(void *ptr) {
207 struct ctxs_checkpoint *cmd = ptr;
208
@@ -234,7 +217,7 @@ void rrdcontext_hub_checkpoint_command(void *ptr) {
217 return;
218 }
219
237 - RRDHOST *host = rrdhost_find_by_node_id(cmd->node_id);
220 + RRDHOST *host = find_host_by_node_id(cmd->node_id);
221 if(!host) {
222 nd_log(NDLS_DAEMON, NDLP_WARNING,
223 "RRDCONTEXT: received checkpoint command for claim id '%s', node id '%s', "
@@ -308,7 +291,7 @@ void rrdcontext_hub_stop_streaming_command(void *ptr) {
291 return;
292 }
293
311 - RRDHOST *host = rrdhost_find_by_node_id(cmd->node_id);
294 + RRDHOST *host = find_host_by_node_id(cmd->node_id);
295 if(!host) {
296 nd_log(NDLS_DAEMON, NDLP_WARNING,
297 "RRDCONTEXT: received stop streaming command for claim id '%s', node id '%s', "
src/database/contexts/rrdcontext.h
+14 -14
@@ -99,7 +99,7 @@ void rrdcontext_updated_rrddim_multiplier(RRDDIM *rd);
99 void rrdcontext_updated_rrddim_divisor(RRDDIM *rd);
100 void rrdcontext_updated_rrddim_flags(RRDDIM *rd);
101 void rrdcontext_collected_rrddim(RRDDIM *rd);
102 -int rrdcontext_find_dimension_uuid(RRDSET *st, const char *id, uuid_t *store_uuid);
102 +int rrdcontext_find_dimension_uuid(RRDSET *st, const char *id, nd_uuid_t *store_uuid);
103
104 // ----------------------------------------------------------------------------
105 // public API for rrdsets
@@ -110,7 +110,7 @@ void rrdcontext_updated_rrdset_name(RRDSET *st);
110 void rrdcontext_updated_rrdset_flags(RRDSET *st);
111 void rrdcontext_updated_retention_rrdset(RRDSET *st);
112 void rrdcontext_collected_rrdset(RRDSET *st);
113 -int rrdcontext_find_chart_uuid(RRDSET *st, uuid_t *store_uuid);
113 +int rrdcontext_find_chart_uuid(RRDSET *st, nd_uuid_t *store_uuid);
114
115 // ----------------------------------------------------------------------------
116 // public API for ACLK
@@ -165,7 +165,7 @@ typedef struct query_alerts_counts { // counts the number of alerts related t
165 size_t other; // number of alerts in any other state
166 } QUERY_ALERTS_COUNTS;
167
168 -typedef struct query_node {
168 +typedef struct _query_node {
169 uint32_t slot;
170 RRDHOST *rrdhost;
171 char node_id[UUID_STR_LEN];
@@ -177,7 +177,7 @@ typedef struct query_node {
177 QUERY_ALERTS_COUNTS alerts;
178 } QUERY_NODE;
179
180 -typedef struct query_context {
180 +typedef struct _query_context {
181 uint32_t slot;
182 RRDCONTEXT_ACQUIRED *rca;
183
@@ -187,7 +187,7 @@ typedef struct query_context {
187 QUERY_ALERTS_COUNTS alerts;
188 } QUERY_CONTEXT;
189
190 -typedef struct query_instance {
190 +typedef struct _query_instance {
191 uint32_t slot;
192 uint32_t query_host_id;
193 RRDINSTANCE_ACQUIRED *ria;
@@ -199,14 +199,14 @@ typedef struct query_instance {
199 QUERY_ALERTS_COUNTS alerts;
200 } QUERY_INSTANCE;
201
202 -typedef struct query_dimension {
202 +typedef struct _query_dimension {
203 uint32_t slot;
204 uint32_t priority;
205 RRDMETRIC_ACQUIRED *rma;
206 QUERY_STATUS status;
207 } QUERY_DIMENSION;
208
209 -typedef struct query_metric {
209 +typedef struct _query_metric {
210 RRDR_DIMENSION_FLAGS status;
211
212 struct query_metric_tier {
@@ -300,7 +300,7 @@ typedef struct query_target_request {
300 qt_interrupt_callback_t interrupt_callback;
301 void *interrupt_callback_data;
302
303 - uuid_t *transaction;
303 + nd_uuid_t *transaction;
304 } QUERY_TARGET_REQUEST;
305
306 #define GROUP_BY_MAX_LABEL_KEYS 10
@@ -421,9 +421,9 @@ typedef struct query_target {
421
422 struct sql_alert_transition_data {
423 usec_t global_id;
424 - uuid_t *transition_id;
425 - uuid_t *host_id;
426 - uuid_t *config_hash_id;
424 + nd_uuid_t *transition_id;
425 + nd_uuid_t *host_id;
426 + nd_uuid_t *config_hash_id;
427 uint32_t alarm_id;
428 const char *alert_name;
429 const char *chart;
@@ -454,7 +454,7 @@ struct sql_alert_transition_data {
454 };
455
456 struct sql_alert_config_data {
457 - uuid_t *config_hash_id;
457 + nd_uuid_t *config_hash_id;
458 const char *name;
459
460 struct {
@@ -539,9 +539,9 @@ struct sql_alert_instance_v2_entry {
539 time_t last_updated;
540 time_t last_status_change;
541 NETDATA_DOUBLE last_status_change_value;
542 - uuid_t config_hash_id;
542 + nd_uuid_t config_hash_id;
543 usec_t global_id;
544 - uuid_t last_transition_id;
544 + nd_uuid_t last_transition_id;
545 uint32_t alarm_id;
546 RRDHOST *host;
547 size_t ni;
src/database/contexts/worker.c
+72 -71
@@ -1060,8 +1060,10 @@ static void rrdcontext_dispatch_queued_contexts_to_hub(RRDHOST *host, usec_t now
1060 // ----------------------------------------------------------------------------
1061 // worker thread
1062
1063 -static void rrdcontext_main_cleanup(void *ptr) {
1064 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
1063 +static void rrdcontext_main_cleanup(void *pptr) {
1064 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
1065 + if(!static_thread) return;
1066 +
1067 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
1068
1069 // custom code
@@ -1071,83 +1073,82 @@ static void rrdcontext_main_cleanup(void *ptr) {
1073 }
1074
1075 void *rrdcontext_main(void *ptr) {
1074 - netdata_thread_cleanup_push(rrdcontext_main_cleanup, ptr);
1075 -
1076 - worker_register("RRDCONTEXT");
1077 - worker_register_job_name(WORKER_JOB_HOSTS, "hosts");
1078 - worker_register_job_name(WORKER_JOB_CHECK, "dedup checks");
1079 - worker_register_job_name(WORKER_JOB_SEND, "sent contexts");
1080 - worker_register_job_name(WORKER_JOB_DEQUEUE, "deduplicated contexts");
1081 - worker_register_job_name(WORKER_JOB_RETENTION, "metrics retention");
1082 - worker_register_job_name(WORKER_JOB_QUEUED, "queued contexts");
1083 - worker_register_job_name(WORKER_JOB_CLEANUP, "cleanups");
1084 - worker_register_job_name(WORKER_JOB_CLEANUP_DELETE, "deletes");
1085 - worker_register_job_name(WORKER_JOB_PP_METRIC, "check metrics");
1086 - worker_register_job_name(WORKER_JOB_PP_INSTANCE, "check instances");
1087 - worker_register_job_name(WORKER_JOB_PP_CONTEXT, "check contexts");
1088 -
1089 - worker_register_job_custom_metric(WORKER_JOB_HUB_QUEUE_SIZE, "hub queue size", "contexts", WORKER_METRIC_ABSOLUTE);
1090 - worker_register_job_custom_metric(WORKER_JOB_PP_QUEUE_SIZE, "post processing queue size", "contexts", WORKER_METRIC_ABSOLUTE);
1091 -
1092 - heartbeat_t hb;
1093 - heartbeat_init(&hb);
1094 - usec_t step = RRDCONTEXT_WORKER_THREAD_HEARTBEAT_USEC;
1095 -
1096 - while (service_running(SERVICE_CONTEXT)) {
1097 - worker_is_idle();
1098 - heartbeat_next(&hb, step);
1099 -
1100 - if(unlikely(!service_running(SERVICE_CONTEXT))) break;
1101 -
1102 - usec_t now_ut = now_realtime_usec();
1103 -
1104 - if(rrdcontext_next_db_rotation_ut && now_ut > rrdcontext_next_db_rotation_ut) {
1105 - rrdcontext_recalculate_retention_all_hosts();
1106 - rrdcontext_garbage_collect_for_all_hosts();
1107 - rrdcontext_next_db_rotation_ut = 0;
1108 - }
1109 -
1110 - size_t hub_queued_contexts_for_all_hosts = 0;
1111 - size_t pp_queued_contexts_for_all_hosts = 0;
1076 + CLEANUP_FUNCTION_REGISTER(rrdcontext_main_cleanup) cleanup_ptr = ptr;
1077 +
1078 + worker_register("RRDCONTEXT");
1079 + worker_register_job_name(WORKER_JOB_HOSTS, "hosts");
1080 + worker_register_job_name(WORKER_JOB_CHECK, "dedup checks");
1081 + worker_register_job_name(WORKER_JOB_SEND, "sent contexts");
1082 + worker_register_job_name(WORKER_JOB_DEQUEUE, "deduplicated contexts");
1083 + worker_register_job_name(WORKER_JOB_RETENTION, "metrics retention");
1084 + worker_register_job_name(WORKER_JOB_QUEUED, "queued contexts");
1085 + worker_register_job_name(WORKER_JOB_CLEANUP, "cleanups");
1086 + worker_register_job_name(WORKER_JOB_CLEANUP_DELETE, "deletes");
1087 + worker_register_job_name(WORKER_JOB_PP_METRIC, "check metrics");
1088 + worker_register_job_name(WORKER_JOB_PP_INSTANCE, "check instances");
1089 + worker_register_job_name(WORKER_JOB_PP_CONTEXT, "check contexts");
1090 +
1091 + worker_register_job_custom_metric(WORKER_JOB_HUB_QUEUE_SIZE, "hub queue size", "contexts", WORKER_METRIC_ABSOLUTE);
1092 + worker_register_job_custom_metric(WORKER_JOB_PP_QUEUE_SIZE, "post processing queue size", "contexts", WORKER_METRIC_ABSOLUTE);
1093 +
1094 + heartbeat_t hb;
1095 + heartbeat_init(&hb);
1096 + usec_t step = RRDCONTEXT_WORKER_THREAD_HEARTBEAT_USEC;
1097 +
1098 + while (service_running(SERVICE_CONTEXT)) {
1099 + worker_is_idle();
1100 + heartbeat_next(&hb, step);
1101 +
1102 + if(unlikely(!service_running(SERVICE_CONTEXT))) break;
1103 +
1104 + usec_t now_ut = now_realtime_usec();
1105 +
1106 + if(rrdcontext_next_db_rotation_ut && now_ut > rrdcontext_next_db_rotation_ut) {
1107 + rrdcontext_recalculate_retention_all_hosts();
1108 + rrdcontext_garbage_collect_for_all_hosts();
1109 + rrdcontext_next_db_rotation_ut = 0;
1110 + }
1111
1113 - RRDHOST *host;
1114 - dfe_start_reentrant(rrdhost_root_index, host) {
1115 - if(unlikely(!service_running(SERVICE_CONTEXT))) break;
1112 + size_t hub_queued_contexts_for_all_hosts = 0;
1113 + size_t pp_queued_contexts_for_all_hosts = 0;
1114
1117 - worker_is_busy(WORKER_JOB_HOSTS);
1115 + RRDHOST *host;
1116 + dfe_start_reentrant(rrdhost_root_index, host) {
1117 + if(unlikely(!service_running(SERVICE_CONTEXT))) break;
1118
1119 - if(host->rrdctx.pp_queue) {
1120 - pp_queued_contexts_for_all_hosts += dictionary_entries(host->rrdctx.pp_queue);
1121 - rrdcontext_post_process_queued_contexts(host);
1122 - dictionary_garbage_collect(host->rrdctx.pp_queue);
1123 - }
1119 + worker_is_busy(WORKER_JOB_HOSTS);
1120
1125 - if(host->rrdctx.hub_queue) {
1126 - hub_queued_contexts_for_all_hosts += dictionary_entries(host->rrdctx.hub_queue);
1127 - rrdcontext_dispatch_queued_contexts_to_hub(host, now_ut);
1128 - dictionary_garbage_collect(host->rrdctx.hub_queue);
1129 - }
1121 + if(host->rrdctx.pp_queue) {
1122 + pp_queued_contexts_for_all_hosts += dictionary_entries(host->rrdctx.pp_queue);
1123 + rrdcontext_post_process_queued_contexts(host);
1124 + dictionary_garbage_collect(host->rrdctx.pp_queue);
1125 + }
1126
1131 - if (host->rrdctx.contexts)
1132 - dictionary_garbage_collect(host->rrdctx.contexts);
1127 + if(host->rrdctx.hub_queue) {
1128 + hub_queued_contexts_for_all_hosts += dictionary_entries(host->rrdctx.hub_queue);
1129 + rrdcontext_dispatch_queued_contexts_to_hub(host, now_ut);
1130 + dictionary_garbage_collect(host->rrdctx.hub_queue);
1131 + }
1132
1134 - // calculate the number of metrics and instances in the host
1135 - RRDCONTEXT *rc;
1136 - uint32_t metrics = 0, instances = 0;
1137 - dfe_start_read(host->rrdctx.contexts, rc) {
1138 - metrics += rc->stats.metrics;
1139 - instances += dictionary_entries(rc->rrdinstances);
1140 - }
1141 - dfe_done(rc);
1142 - host->rrdctx.metrics = metrics;
1143 - host->rrdctx.instances = instances;
1144 - }
1145 - dfe_done(host);
1133 + if (host->rrdctx.contexts)
1134 + dictionary_garbage_collect(host->rrdctx.contexts);
1135
1147 - worker_set_metric(WORKER_JOB_HUB_QUEUE_SIZE, (NETDATA_DOUBLE)hub_queued_contexts_for_all_hosts);
1148 - worker_set_metric(WORKER_JOB_PP_QUEUE_SIZE, (NETDATA_DOUBLE)pp_queued_contexts_for_all_hosts);
1136 + // calculate the number of metrics and instances in the host
1137 + RRDCONTEXT *rc;
1138 + uint32_t metrics = 0, instances = 0;
1139 + dfe_start_read(host->rrdctx.contexts, rc) {
1140 + metrics += rc->stats.metrics;
1141 + instances += dictionary_entries(rc->rrdinstances);
1142 }
1143 + dfe_done(rc);
1144 + host->rrdctx.metrics = metrics;
1145 + host->rrdctx.instances = instances;
1146 + }
1147 + dfe_done(host);
1148 +
1149 + worker_set_metric(WORKER_JOB_HUB_QUEUE_SIZE, (NETDATA_DOUBLE)hub_queued_contexts_for_all_hosts);
1150 + worker_set_metric(WORKER_JOB_PP_QUEUE_SIZE, (NETDATA_DOUBLE)pp_queued_contexts_for_all_hosts);
1151 + }
1152
1151 - netdata_thread_cleanup_pop(1);
1153 return NULL;
1154 }
src/database/engine/cache.c
+8 -19
@@ -1300,8 +1300,7 @@ static PGC_PAGE *page_add(PGC *cache, PGC_ENTRY *entry, bool *added) {
1300 if(unlikely(!page)) {
1301 // now that we don't have the lock,
1302 // give it some time for the old page to go away
1303 - struct timespec ns = { .tv_sec = 0, .tv_nsec = 1 };
1304 - nanosleep(&ns, NULL);
1303 + tinysleep();
1304 }
1305 }
1306
@@ -2026,8 +2025,6 @@ void pgc_page_hot_set_end_time_s(PGC *cache __maybe_unused, PGC_PAGE *page, time
2025 }
2026
2027 PGC_PAGE *pgc_page_get_and_acquire(PGC *cache, Word_t section, Word_t metric_id, time_t start_time_s, PGC_SEARCH method) {
2029 - static const struct timespec ns = { .tv_sec = 0, .tv_nsec = 1 };
2030 -
2028 PGC_PAGE *page = NULL;
2029
2030 __atomic_add_fetch(&cache->stats.workers_search, 1, __ATOMIC_RELAXED);
@@ -2053,7 +2050,7 @@ PGC_PAGE *pgc_page_get_and_acquire(PGC *cache, Word_t section, Word_t metric_id,
2050 if(page || !retry)
2051 break;
2052
2056 - nanosleep(&ns, NULL);
2053 + tinysleep();
2054 }
2055
2056 if(page) {
@@ -2374,8 +2371,6 @@ void *unittest_stress_test_collector(void *ptr) {
2371 while(!__atomic_load_n(&pgc_uts.stop, __ATOMIC_RELAXED)) {
2372 // netdata_log_info("COLLECTOR %zu: collecting metrics %zu to %zu, from %ld to %lu", id, metric_start, metric_end, start_time_t, start_time_t + pgc_uts.points_per_page);
2373
2377 - netdata_thread_disable_cancelability();
2378 -
2374 for (size_t i = metric_start; i < metric_end; i++) {
2375 bool added;
2376
@@ -2416,8 +2411,6 @@ void *unittest_stress_test_collector(void *ptr) {
2411 pgc_page_hot_to_dirty_and_release(pgc_uts.cache, pgc_uts.metrics[i], false);
2412 }
2413 }
2419 -
2420 - netdata_thread_enable_cancelability();
2414 }
2415
2416 return ptr;
@@ -2431,8 +2424,6 @@ void *unittest_stress_test_queries(void *ptr) {
2424 size_t end = pgc_uts.clean_metrics + pgc_uts.hot_metrics;
2425
2426 while(!__atomic_load_n(&pgc_uts.stop, __ATOMIC_RELAXED)) {
2434 - netdata_thread_disable_cancelability();
2435 -
2427 int32_t random_number;
2428 random_r(random_data, &random_number);
2429
@@ -2482,8 +2473,6 @@ void *unittest_stress_test_queries(void *ptr) {
2473 pgc_page_release(pgc_uts.cache, array[i]);
2474 array[i] = NULL;
2475 }
2485 -
2486 - netdata_thread_enable_cancelability();
2476 }
2477
2478 return ptr;
@@ -2527,7 +2516,7 @@ void unittest_stress_test(void) {
2516 pgc_uts.metrics = callocz(pgc_uts.clean_metrics + pgc_uts.hot_metrics, sizeof(PGC_PAGE *));
2517
2518 pthread_t service_thread;
2530 - netdata_thread_create(&service_thread, "SERVICE",
2519 + nd_thread_create(&service_thread, "SERVICE",
2520 NETDATA_THREAD_OPTION_JOINABLE | NETDATA_THREAD_OPTION_DONT_LOG,
2521 unittest_stress_test_service, NULL);
2522
@@ -2537,7 +2526,7 @@ void unittest_stress_test(void) {
2526 collect_thread_ids[i] = i;
2527 char buffer[100 + 1];
2528 snprintfz(buffer, sizeof(buffer) - 1, "COLLECT_%zu", i);
2540 - netdata_thread_create(&collect_threads[i], buffer,
2529 + nd_thread_create(&collect_threads[i], buffer,
2530 NETDATA_THREAD_OPTION_JOINABLE | NETDATA_THREAD_OPTION_DONT_LOG,
2531 unittest_stress_test_collector, &collect_thread_ids[i]);
2532 }
@@ -2550,7 +2539,7 @@ void unittest_stress_test(void) {
2539 char buffer[100 + 1];
2540 snprintfz(buffer, sizeof(buffer) - 1, "QUERY_%zu", i);
2541 initstate_r(1, pgc_uts.rand_statebufs, 1024, &pgc_uts.random_data[i]);
2553 - netdata_thread_create(&queries_threads[i], buffer,
2542 + nd_thread_create(&queries_threads[i], buffer,
2543 NETDATA_THREAD_OPTION_JOINABLE | NETDATA_THREAD_OPTION_DONT_LOG,
2544 unittest_stress_test_queries, &query_thread_ids[i]);
2545 }
@@ -2671,13 +2660,13 @@ void unittest_stress_test(void) {
2660 netdata_log_info("Waiting for threads to stop...");
2661 __atomic_store_n(&pgc_uts.stop, true, __ATOMIC_RELAXED);
2662
2674 - netdata_thread_join(service_thread, NULL);
2663 + nd_thread_join(service_thread, NULL);
2664
2665 for(size_t i = 0; i < pgc_uts.collect_threads ;i++)
2677 - netdata_thread_join(collect_threads[i],NULL);
2666 + nd_thread_join(collect_threads[i],NULL);
2667
2668 for(size_t i = 0; i < pgc_uts.query_threads ;i++)
2680 - netdata_thread_join(queries_threads[i],NULL);
2669 + nd_thread_join(queries_threads[i],NULL);
2670
2671 pgc_destroy(pgc_uts.cache);
2672
src/database/engine/datafile.c
-1
@@ -526,7 +526,6 @@ int init_data_files(struct rrdengine_instance *ctx)
526 {
527 int ret;
528
529 - fatal_assert(0 == uv_rwlock_init(&ctx->datafiles.rwlock));
529 ret = scan_data_files(ctx);
530 if (ret < 0) {
531 netdata_log_error("DBENGINE: failed to scan path \"%s\".", ctx->config.dbfiles_path);
src/database/engine/dbengine-stresstest.c
+2 -2
@@ -186,7 +186,7 @@ void generate_dbengine_dataset(unsigned history_seconds)
186 freez(thread_info);
187 rrd_wrlock();
188 rrdhost_free___while_having_rrd_wrlock(localhost, true);
189 - rrd_unlock();
189 + rrd_wrunlock();
190 }
191
192 struct dbengine_query_thread {
@@ -450,7 +450,7 @@ void dbengine_stress_test(unsigned TEST_DURATION_SEC, unsigned DSET_CHARTS, unsi
450 rrdeng_prepare_exit((struct rrdengine_instance *)host->db[0].si);
451 rrdeng_exit((struct rrdengine_instance *)host->db[0].si);
452 rrdeng_enq_cmd(NULL, RRDENG_OPCODE_SHUTDOWN_EVLOOP, NULL, NULL, STORAGE_PRIORITY_BEST_EFFORT, NULL, NULL);
453 - rrd_unlock();
453 + rrd_wrunlock();
454 }
455
456 #endif
\ No newline at end of file
src/database/engine/dbengine-unittest.c
+1 -1
@@ -411,7 +411,7 @@ int test_dbengine(void) {
411 rrdeng_prepare_exit((struct rrdengine_instance *)host->db[0].si);
412 rrdeng_exit((struct rrdengine_instance *)host->db[0].si);
413 rrdeng_enq_cmd(NULL, RRDENG_OPCODE_SHUTDOWN_EVLOOP, NULL, NULL, STORAGE_PRIORITY_BEST_EFFORT, NULL, NULL);
414 - rrd_unlock();
414 + rrd_wrunlock();
415
416 return (int)(errors + value_errors + time_errors);
417 }
src/database/engine/journalfile.c
+3 -3
@@ -670,7 +670,7 @@ static void journalfile_restore_extent_metadata(struct rrdengine_instance *ctx,
670
671 time_t now_s = max_acceptable_collected_time();
672 for (i = 0; i < count ; ++i) {
673 - uuid_t *temp_id;
673 + nd_uuid_t *temp_id;
674 uint8_t page_type = jf_metric_data->descr[i].type;
675
676 if (page_type > RRDENG_PAGE_TYPE_MAX) {
@@ -681,7 +681,7 @@ static void journalfile_restore_extent_metadata(struct rrdengine_instance *ctx,
681 continue;
682 }
683
684 - temp_id = (uuid_t *)jf_metric_data->descr[i].uuid;
684 + temp_id = (nd_uuid_t *)jf_metric_data->descr[i].uuid;
685 METRIC *metric = mrg_metric_get_and_acquire(main_mrg, temp_id, (Word_t) ctx);
686
687 struct rrdeng_extent_page_descr *descr = &jf_metric_data->descr[i];
@@ -1145,7 +1145,7 @@ static int journalfile_metric_compare (const void *item1, const void *item2)
1145 const struct jv2_metrics_info *metric1 = ((struct journal_metric_list_to_sort *) item1)->metric_info;
1146 const struct jv2_metrics_info *metric2 = ((struct journal_metric_list_to_sort *) item2)->metric_info;
1147
1148 - return memcmp(metric1->uuid, metric2->uuid, sizeof(uuid_t));
1148 + return memcmp(metric1->uuid, metric2->uuid, sizeof(nd_uuid_t));
1149 }
1150
1151
src/database/engine/journalfile.h
+2 -2
@@ -84,7 +84,7 @@ struct journal_page_header {
84 };
85 uint32_t uuid_offset; // Points back to the UUID list which should point here (UUIDs should much)
86 uint32_t entries; // Entries
87 - uuid_t uuid; // Which UUID this is
87 + nd_uuid_t uuid; // Which UUID this is
88 };
89
90 // 20 bytes
@@ -100,7 +100,7 @@ struct journal_page_list {
100 // UUID_LIST
101 // 36 bytes
102 struct journal_metric_list {
103 - uuid_t uuid;
103 + nd_uuid_t uuid;
104 uint32_t entries; // Number of entries
105 uint32_t page_offset; // OFFSET that contains entries * struct( journal_page_list )
106 uint32_t delta_start_s; // Min time of metric
src/database/engine/metric.c
+21 -23
@@ -8,7 +8,7 @@ typedef int32_t REFCOUNT;
8 #define REFCOUNT_DELETING (-100)
9
10 struct metric {
11 - uuid_t uuid; // never changes
11 + nd_uuid_t uuid; // never changes
12 Word_t section; // never changes
13
14 time_t first_time_s; // the timestamp of the oldest point in the database
@@ -98,14 +98,14 @@ static inline void mrg_stats_size_judyl_change(MRG *mrg, size_t mem_before_judyl
98 }
99
100 static inline void mrg_stats_size_judyhs_added_uuid(MRG *mrg, size_t partition) {
101 - __atomic_add_fetch(&mrg->index[partition].stats.size, JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(uuid_t)), __ATOMIC_RELAXED);
101 + __atomic_add_fetch(&mrg->index[partition].stats.size, JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(nd_uuid_t)), __ATOMIC_RELAXED);
102 }
103
104 static inline void mrg_stats_size_judyhs_removed_uuid(MRG *mrg, size_t partition) {
105 - __atomic_sub_fetch(&mrg->index[partition].stats.size, JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(uuid_t)), __ATOMIC_RELAXED);
105 + __atomic_sub_fetch(&mrg->index[partition].stats.size, JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(nd_uuid_t)), __ATOMIC_RELAXED);
106 }
107
108 -static inline size_t uuid_partition(MRG *mrg __maybe_unused, uuid_t *uuid) {
108 +static inline size_t uuid_partition(MRG *mrg __maybe_unused, nd_uuid_t *uuid) {
109 uint8_t *u = (uint8_t *)uuid;
110
111 size_t n;
@@ -167,7 +167,7 @@ static inline void acquired_for_deletion_metric_delete(MRG *mrg, METRIC *metric)
167
168 mrg_index_write_lock(mrg, partition);
169
170 - Pvoid_t *sections_judy_pptr = JudyHSGet(mrg->index[partition].uuid_judy, &metric->uuid, sizeof(uuid_t));
170 + Pvoid_t *sections_judy_pptr = JudyHSGet(mrg->index[partition].uuid_judy, &metric->uuid, sizeof(nd_uuid_t));
171 if(unlikely(!sections_judy_pptr || !*sections_judy_pptr)) {
172 MRG_STATS_DELETE_MISS(mrg, partition);
173 mrg_index_write_unlock(mrg, partition);
@@ -186,7 +186,7 @@ static inline void acquired_for_deletion_metric_delete(MRG *mrg, METRIC *metric)
186 }
187
188 if(!*sections_judy_pptr) {
189 - rc = JudyHSDel(&mrg->index[partition].uuid_judy, &metric->uuid, sizeof(uuid_t), PJE0);
189 + rc = JudyHSDel(&mrg->index[partition].uuid_judy, &metric->uuid, sizeof(nd_uuid_t), PJE0);
190 if(unlikely(!rc))
191 fatal("DBENGINE METRIC: cannot delete UUID from JudyHS");
192 mrg_stats_size_judyhs_removed_uuid(mrg, partition);
@@ -264,7 +264,7 @@ static inline METRIC *metric_add_and_acquire(MRG *mrg, MRG_ENTRY *entry, bool *r
264
265 size_t mem_before_judyl, mem_after_judyl;
266
267 - Pvoid_t *sections_judy_pptr = JudyHSIns(&mrg->index[partition].uuid_judy, entry->uuid, sizeof(uuid_t), PJE0);
267 + Pvoid_t *sections_judy_pptr = JudyHSIns(&mrg->index[partition].uuid_judy, entry->uuid, sizeof(nd_uuid_t), PJE0);
268 if (unlikely(!sections_judy_pptr || sections_judy_pptr == PJERR))
269 fatal("DBENGINE METRIC: corrupted UUIDs JudyHS array");
270
@@ -323,13 +323,13 @@ static inline METRIC *metric_add_and_acquire(MRG *mrg, MRG_ENTRY *entry, bool *r
323 return metric;
324 }
325
326 -static inline METRIC *metric_get_and_acquire(MRG *mrg, uuid_t *uuid, Word_t section) {
326 +static inline METRIC *metric_get_and_acquire(MRG *mrg, nd_uuid_t *uuid, Word_t section) {
327 size_t partition = uuid_partition(mrg, uuid);
328
329 while(1) {
330 mrg_index_read_lock(mrg, partition);
331
332 - Pvoid_t *sections_judy_pptr = JudyHSGet(mrg->index[partition].uuid_judy, uuid, sizeof(uuid_t));
332 + Pvoid_t *sections_judy_pptr = JudyHSGet(mrg->index[partition].uuid_judy, uuid, sizeof(nd_uuid_t));
333 if (unlikely(!sections_judy_pptr)) {
334 mrg_index_read_unlock(mrg, partition);
335 MRG_STATS_SEARCH_MISS(mrg, partition);
@@ -404,7 +404,7 @@ inline METRIC *mrg_metric_add_and_acquire(MRG *mrg, MRG_ENTRY entry, bool *ret)
404 return metric_add_and_acquire(mrg, &entry, ret);
405 }
406
407 -inline METRIC *mrg_metric_get_and_acquire(MRG *mrg, uuid_t *uuid, Word_t section) {
407 +inline METRIC *mrg_metric_get_and_acquire(MRG *mrg, nd_uuid_t *uuid, Word_t section) {
408 return metric_get_and_acquire(mrg, uuid, section);
409 }
410
@@ -425,7 +425,7 @@ inline Word_t mrg_metric_id(MRG *mrg __maybe_unused, METRIC *metric) {
425 return (Word_t)metric;
426 }
427
428 -inline uuid_t *mrg_metric_uuid(MRG *mrg __maybe_unused, METRIC *metric) {
428 +inline nd_uuid_t *mrg_metric_uuid(MRG *mrg __maybe_unused, METRIC *metric) {
429 return &metric->uuid;
430 }
431
@@ -600,7 +600,7 @@ inline uint32_t mrg_metric_get_update_every_s(MRG *mrg __maybe_unused, METRIC *m
600
601 inline bool mrg_metric_set_writer(MRG *mrg, METRIC *metric) {
602 pid_t expected = __atomic_load_n(&metric->writer, __ATOMIC_RELAXED);
603 - pid_t wanted = gettid();
603 + pid_t wanted = gettid_cached();
604 bool done = true;
605
606 do {
@@ -639,7 +639,7 @@ inline bool mrg_metric_clear_writer(MRG *mrg, METRIC *metric) {
639 }
640
641 inline void mrg_update_metric_retention_and_granularity_by_uuid(
642 - MRG *mrg, Word_t section, uuid_t *uuid,
642 + MRG *mrg, Word_t section, nd_uuid_t *uuid,
643 time_t first_time_s, time_t last_time_s,
644 uint32_t update_every_s, time_t now_s)
645 {
@@ -736,7 +736,7 @@ inline void mrg_get_statistics(MRG *mrg, struct mrg_statistics *s) {
736 // unit test
737
738 struct mrg_stress_entry {
739 - uuid_t uuid;
739 + nd_uuid_t uuid;
740 time_t after;
741 time_t before;
742 };
@@ -757,13 +757,13 @@ static void *mrg_stress(void *ptr) {
757 ssize_t end = (ssize_t)t->entries;
758 ssize_t step = 1;
759
760 - if(gettid() % 2) {
760 + if(gettid_cached() % 2) {
761 start = (ssize_t)t->entries - 1;
762 end = -1;
763 step = -1;
764 }
765
766 - while(!__atomic_load_n(&t->stop, __ATOMIC_RELAXED)) {
766 + while(!__atomic_load_n(&t->stop, __ATOMIC_RELAXED) && !nd_thread_signaled_to_cancel()) {
767 for (ssize_t i = start; i != end; i += step) {
768 struct mrg_stress_entry *e = &t->array[i];
769
@@ -791,7 +791,7 @@ int mrg_unittest(void) {
791 METRIC *m1_t1, *m2_t1, *m3_t1, *m4_t1;
792 bool ret;
793
794 - uuid_t test_uuid;
794 + nd_uuid_t test_uuid;
795 uuid_generate(test_uuid);
796 MRG_ENTRY entry = {
797 .uuid = &test_uuid,
@@ -902,23 +902,21 @@ int mrg_unittest(void) {
902
903 usec_t started_ut = now_monotonic_usec();
904
905 - pthread_t th[threads];
905 + ND_THREAD *th[threads];
906 for(size_t i = 0; i < threads ; i++) {
907 char buf[15 + 1];
908 snprintfz(buf, sizeof(buf) - 1, "TH[%zu]", i);
909 - netdata_thread_create(&th[i], buf,
910 - NETDATA_THREAD_OPTION_JOINABLE | NETDATA_THREAD_OPTION_DONT_LOG,
911 - mrg_stress, &t);
909 + th[i] = nd_thread_create(buf, NETDATA_THREAD_OPTION_JOINABLE | NETDATA_THREAD_OPTION_DONT_LOG, mrg_stress, &t);
910 }
911
912 sleep_usec(run_for_secs * USEC_PER_SEC);
913 __atomic_store_n(&t.stop, true, __ATOMIC_RELAXED);
914
915 for(size_t i = 0; i < threads ; i++)
918 - netdata_thread_cancel(th[i]);
916 + nd_thread_signal_cancel(th[i]);
917
918 for(size_t i = 0; i < threads ; i++)
921 - netdata_thread_join(th[i], NULL);
919 + nd_thread_join(th[i]);
920
921 usec_t ended_ut = now_monotonic_usec();
922
src/database/engine/metric.h
+4 -4
@@ -10,7 +10,7 @@ typedef struct metric METRIC;
10 typedef struct mrg MRG;
11
12 typedef struct mrg_entry {
13 - uuid_t *uuid;
13 + nd_uuid_t *uuid;
14 Word_t section;
15 time_t first_time_s;
16 time_t last_time_s;
@@ -55,11 +55,11 @@ METRIC *mrg_metric_dup(MRG *mrg, METRIC *metric);
55 void mrg_metric_release(MRG *mrg, METRIC *metric);
56
57 METRIC *mrg_metric_add_and_acquire(MRG *mrg, MRG_ENTRY entry, bool *ret);
58 -METRIC *mrg_metric_get_and_acquire(MRG *mrg, uuid_t *uuid, Word_t section);
58 +METRIC *mrg_metric_get_and_acquire(MRG *mrg, nd_uuid_t *uuid, Word_t section);
59 bool mrg_metric_release_and_delete(MRG *mrg, METRIC *metric);
60
61 Word_t mrg_metric_id(MRG *mrg, METRIC *metric);
62 -uuid_t *mrg_metric_uuid(MRG *mrg, METRIC *metric);
62 +nd_uuid_t *mrg_metric_uuid(MRG *mrg, METRIC *metric);
63 Word_t mrg_metric_section(MRG *mrg, METRIC *metric);
64
65 bool mrg_metric_set_first_time_s(MRG *mrg, METRIC *metric, time_t first_time_s);
@@ -88,7 +88,7 @@ size_t mrg_aral_overhead(void);
88
89
90 void mrg_update_metric_retention_and_granularity_by_uuid(
91 - MRG *mrg, Word_t section, uuid_t *uuid,
91 + MRG *mrg, Word_t section, nd_uuid_t *uuid,
92 time_t first_time_s, time_t last_time_s,
93 uint32_t update_every_s, time_t now_s);
94
src/database/engine/page.c
+1 -1
@@ -183,7 +183,7 @@ PGD *pgd_create(uint8_t type, uint32_t slots)
183 pg->slots = 8 * RRDENG_GORILLA_32BIT_BUFFER_SLOTS;
184
185 // allocate new gorilla writer
186 - pg->gorilla.aral_index = gettid() % 4;
186 + pg->gorilla.aral_index = gettid_cached() % 4;
187 pg->gorilla.writer = aral_mallocz(pgd_alloc_globals.aral_gorilla_writer[pg->gorilla.aral_index]);
188
189 // allocate new gorilla buffer
src/database/engine/pagecache.c
+1 -1
@@ -491,7 +491,7 @@ static size_t list_has_time_gaps(
491
492 typedef void (*page_found_callback_t)(PGC_PAGE *page, void *data);
493 static size_t get_page_list_from_journal_v2(struct rrdengine_instance *ctx, METRIC *metric, usec_t start_time_ut, usec_t end_time_ut, page_found_callback_t callback, void *callback_data) {
494 - uuid_t *uuid = mrg_metric_uuid(main_mrg, metric);
494 + nd_uuid_t *uuid = mrg_metric_uuid(main_mrg, metric);
495 Word_t metric_id = mrg_metric_id(main_mrg, metric);
496
497 time_t wanted_start_time_s = (time_t)(start_time_ut / USEC_PER_SEC);
src/database/engine/pagecache.h
+1 -1
@@ -18,7 +18,7 @@ struct rrdengine_instance;
18 extern struct rrdeng_cache_efficiency_stats rrdeng_cache_efficiency_stats;
19
20 struct page_descr_with_data {
21 - uuid_t *id;
21 + nd_uuid_t *id;
22 Word_t metric_id;
23 usec_t start_time_ut;
24 usec_t end_time_ut;
src/database/engine/pdc.c
+3 -3
@@ -651,7 +651,7 @@ inline VALIDATED_PAGE_DESCRIPTOR validate_extent_page_descr(const struct rrdeng_
651 }
652
653 return validate_page(
654 - (uuid_t *)descr->uuid,
654 + (nd_uuid_t *)descr->uuid,
655 start_time_s,
656 end_time_s,
657 0,
@@ -665,7 +665,7 @@ inline VALIDATED_PAGE_DESCRIPTOR validate_extent_page_descr(const struct rrdeng_
665 }
666
667 VALIDATED_PAGE_DESCRIPTOR validate_page(
668 - uuid_t *uuid,
668 + nd_uuid_t *uuid,
669 time_t start_time_s,
670 time_t end_time_s,
671 uint32_t update_every_s, // can be zero, if unknown
@@ -898,7 +898,7 @@ static void epdl_extent_loading_error_log(struct rrdengine_instance *ctx, EPDL *
898 start_time_s = pd->first_time_s;
899 end_time_s = pd->last_time_s;
900 METRIC *metric = (METRIC *)pd->metric_id;
901 - uuid_t *u = mrg_metric_uuid(main_mrg, metric);
901 + nd_uuid_t *u = mrg_metric_uuid(main_mrg, metric);
902 uuid_unparse_lower(*u, uuid);
903 used_epdl = true;
904 }
src/database/engine/rrdengine.c
+6 -6
@@ -111,7 +111,7 @@ static void sanity_check(void)
111 /* Data file super-block cannot be larger than RRDENG_BLOCK_SIZE */
112 BUILD_BUG_ON(RRDENG_DF_SB_PADDING_SZ < 0);
113
114 - BUILD_BUG_ON(sizeof(uuid_t) != UUID_SZ); /* check UUID size */
114 + BUILD_BUG_ON(sizeof(nd_uuid_t) != UUID_SZ); /* check UUID size */
115
116 /* page count must fit in 8 bits */
117 BUILD_BUG_ON(MAX_PAGES_PER_EXTENT > 255);
@@ -233,7 +233,7 @@ static void after_work_standard_callback(uv_work_t* req, int status) {
233 static bool work_dispatch(struct rrdengine_instance *ctx, void *data, struct completion *completion, enum rrdeng_opcode opcode, work_cb do_work_cb, after_work_cb do_after_work_cb) {
234 struct rrdeng_work *work_request = NULL;
235
236 - internal_fatal(rrdeng_main.tid != gettid(), "work_dispatch() can only be run from the event loop thread");
236 + internal_fatal(rrdeng_main.tid != gettid_cached(), "work_dispatch() can only be run from the event loop thread");
237
238 work_request = aral_mallocz(rrdeng_main.work_cmd.ar);
239 memset(work_request, 0, sizeof(struct rrdeng_work));
@@ -824,7 +824,7 @@ static struct extent_io_descriptor *datafile_extent_build(struct rrdengine_insta
824 for (i = 0 ; i < count ; ++i) {
825 descr = xt_io_descr->descr_array[i];
826 header->descr[i].type = descr->type;
827 - uuid_copy(*(uuid_t *)header->descr[i].uuid, *descr->id);
827 + uuid_copy(*(nd_uuid_t *)header->descr[i].uuid, *descr->id);
828 header->descr[i].page_length = descr->page_length;
829 header->descr[i].start_time_ut = descr->start_time_ut;
830
@@ -935,7 +935,7 @@ static void after_database_rotate(struct rrdengine_instance *ctx __maybe_unused,
935 }
936
937 struct uuid_first_time_s {
938 - uuid_t *uuid;
938 + nd_uuid_t *uuid;
939 time_t first_time_s;
940 METRIC *metric;
941 size_t pages_found;
@@ -1690,7 +1690,7 @@ static inline void worker_dispatch_query_prep(struct rrdeng_cmd cmd, bool from_w
1690
1691 void dbengine_event_loop(void* arg) {
1692 sanity_check();
1693 - uv_thread_set_name_np(pthread_self(), "DBENGINE");
1693 + uv_thread_set_name_np("DBENGINE");
1694 service_register(SERVICE_THREAD_TYPE_EVENT_LOOP, NULL, NULL, NULL, true);
1695
1696 worker_register("DBENGINE");
@@ -1734,7 +1734,7 @@ void dbengine_event_loop(void* arg) {
1734 struct rrdeng_main *main = arg;
1735 enum rrdeng_opcode opcode;
1736 struct rrdeng_cmd cmd;
1737 - main->tid = gettid();
1737 + main->tid = gettid_cached();
1738
1739 fatal_assert(0 == uv_timer_start(&main->timer, timer_cb, TIMER_PERIOD_MS, TIMER_PERIOD_MS));
1740
src/database/engine/rrdengine.h
+13 -6
@@ -3,9 +3,6 @@
3 #ifndef NETDATA_RRDENGINE_H
4 #define NETDATA_RRDENGINE_H
5
6 -#ifndef _GNU_SOURCE
7 -#define _GNU_SOURCE
8 -#endif
6 #include <fcntl.h>
7 #include <lz4.h>
8 #include <Judy.h>
@@ -143,7 +140,7 @@ struct jv2_extents_info {
140 };
141
142 struct jv2_metrics_info {
146 - uuid_t *uuid;
143 + nd_uuid_t *uuid;
144 uint32_t page_list_header;
145 time_t first_time_s;
146 time_t last_time_s;
@@ -497,7 +494,7 @@ typedef struct validated_page_descriptor {
494 #define page_entries_by_size(page_length_in_bytes, point_size_in_bytes) \
495 ((page_length_in_bytes) / (point_size_in_bytes))
496
500 -VALIDATED_PAGE_DESCRIPTOR validate_page(uuid_t *uuid,
497 +VALIDATED_PAGE_DESCRIPTOR validate_page(nd_uuid_t *uuid,
498 time_t start_time_s,
499 time_t end_time_s,
500 uint32_t update_every_s,
@@ -526,8 +523,18 @@ static inline time_t max_acceptable_collected_time(void) {
523
524 void datafile_delete(struct rrdengine_instance *ctx, struct rrdengine_datafile *datafile, bool update_retention, bool worker);
525
526 +// --------------------------------------------------------------------------------------------------------------------
527 +// the following functions are used to sort UUIDs in the journal files
528 +// DO NOT CHANGE, as this will break backwards compatibility with the data files users have.
529 +
530 +static inline int journal_uuid_memcmp(const nd_uuid_t *uu1, const nd_uuid_t *uu2) {
531 + return memcmp(uu1, uu2, sizeof(nd_uuid_t));
532 +}
533 +
534 static inline int journal_metric_uuid_compare(const void *key, const void *metric) {
530 - return uuid_memcmp((uuid_t *)key, &(((struct journal_metric_list *) metric)->uuid));
535 + return journal_uuid_memcmp((const nd_uuid_t *)key, (const nd_uuid_t *)&(((struct journal_metric_list *) metric)->uuid));
536 }
537
538 +// --------------------------------------------------------------------------------------------------------------------
539 +
540 #endif /* NETDATA_RRDENGINE_H */
src/database/engine/rrdengineapi.c
+30 -25
@@ -5,18 +5,18 @@
5 #include "dbengine-compression.h"
6
7 /* Default global database instance */
8 -struct rrdengine_instance multidb_ctx_storage_tier0;
9 -struct rrdengine_instance multidb_ctx_storage_tier1;
10 -struct rrdengine_instance multidb_ctx_storage_tier2;
11 -struct rrdengine_instance multidb_ctx_storage_tier3;
12 -struct rrdengine_instance multidb_ctx_storage_tier4;
8 +struct rrdengine_instance multidb_ctx_storage_tier0 = { 0 };
9 +struct rrdengine_instance multidb_ctx_storage_tier1 = { 0 };
10 +struct rrdengine_instance multidb_ctx_storage_tier2 = { 0 };
11 +struct rrdengine_instance multidb_ctx_storage_tier3 = { 0 };
12 +struct rrdengine_instance multidb_ctx_storage_tier4 = { 0 };
13
14 #define mrg_metric_ctx(metric) (struct rrdengine_instance *)mrg_metric_section(main_mrg, metric)
15
16 #if RRD_STORAGE_TIERS != 5
17 #error RRD_STORAGE_TIERS is not 5 - you need to add allocations here
18 #endif
19 -struct rrdengine_instance *multidb_ctx[RRD_STORAGE_TIERS];
19 +struct rrdengine_instance *multidb_ctx[RRD_STORAGE_TIERS] = { 0 };
20 uint8_t tier_page_type[RRD_STORAGE_TIERS] = {
21 RRDENG_PAGE_TYPE_GORILLA_32BIT,
22 RRDENG_PAGE_TYPE_ARRAY_TIER1,
@@ -40,12 +40,21 @@ size_t page_type_size[256] = {
40 [RRDENG_PAGE_TYPE_GORILLA_32BIT] = sizeof(storage_number)
41 };
42
43 +static inline void initialize_single_ctx(struct rrdengine_instance *ctx) {
44 + memset(ctx, 0, sizeof(*ctx));
45 + uv_rwlock_init(&ctx->datafiles.rwlock);
46 + rw_spinlock_init(&ctx->njfv2idx.spinlock);
47 +}
48 +
49 __attribute__((constructor)) void initialize_multidb_ctx(void) {
50 multidb_ctx[0] = &multidb_ctx_storage_tier0;
51 multidb_ctx[1] = &multidb_ctx_storage_tier1;
52 multidb_ctx[2] = &multidb_ctx_storage_tier2;
53 multidb_ctx[3] = &multidb_ctx_storage_tier3;
54 multidb_ctx[4] = &multidb_ctx_storage_tier4;
55 +
56 + for(int i = 0; i < RRD_STORAGE_TIERS ; i++)
57 + initialize_single_ctx(multidb_ctx[i]);
58 }
59
60 int db_engine_journal_check = 0;
@@ -80,7 +89,7 @@ static inline bool rrdeng_page_alignment_release(struct pg_alignment *pa) {
89 }
90
91 // charts call this
83 -STORAGE_METRICS_GROUP *rrdeng_metrics_group_get(STORAGE_INSTANCE *si __maybe_unused, uuid_t *uuid __maybe_unused) {
92 +STORAGE_METRICS_GROUP *rrdeng_metrics_group_get(STORAGE_INSTANCE *si __maybe_unused, nd_uuid_t *uuid __maybe_unused) {
93 struct pg_alignment *pa = callocz(1, sizeof(struct pg_alignment));
94 rrdeng_page_alignment_acquire(pa);
95 return (STORAGE_METRICS_GROUP *)pa;
@@ -98,17 +107,17 @@ void rrdeng_metrics_group_release(STORAGE_INSTANCE *si __maybe_unused, STORAGE_M
107 // metric handle for legacy dbs
108
109 /* This UUID is not unique across hosts */
101 -void rrdeng_generate_unittest_uuid(const char *dim_id, const char *chart_id, uuid_t *ret_uuid)
110 +void rrdeng_generate_unittest_uuid(const char *dim_id, const char *chart_id, nd_uuid_t *ret_uuid)
111 {
112 CLEAN_BUFFER *wb = buffer_create(100, NULL);
113 buffer_sprintf(wb,"%s.%s", dim_id, chart_id);
105 - UUID uuid = UUID_generate_from_hash(buffer_tostring(wb), buffer_strlen(wb));
114 + ND_UUID uuid = UUID_generate_from_hash(buffer_tostring(wb), buffer_strlen(wb));
115 uuid_copy(*ret_uuid, uuid.uuid);
116 }
117
118 static METRIC *rrdeng_metric_unittest(STORAGE_INSTANCE *si, const char *rd_id, const char *st_id) {
119 struct rrdengine_instance *ctx = (struct rrdengine_instance *)si;
111 - uuid_t legacy_uuid;
120 + nd_uuid_t legacy_uuid;
121 rrdeng_generate_unittest_uuid(rd_id, st_id, &legacy_uuid);
122 return mrg_metric_get_and_acquire(main_mrg, &legacy_uuid, (Word_t) ctx);
123 }
@@ -126,12 +135,12 @@ STORAGE_METRIC_HANDLE *rrdeng_metric_dup(STORAGE_METRIC_HANDLE *smh) {
135 return (STORAGE_METRIC_HANDLE *) mrg_metric_dup(main_mrg, metric);
136 }
137
129 -STORAGE_METRIC_HANDLE *rrdeng_metric_get(STORAGE_INSTANCE *si, uuid_t *uuid) {
138 +STORAGE_METRIC_HANDLE *rrdeng_metric_get(STORAGE_INSTANCE *si, nd_uuid_t *uuid) {
139 struct rrdengine_instance *ctx = (struct rrdengine_instance *)si;
140 return (STORAGE_METRIC_HANDLE *) mrg_metric_get_and_acquire(main_mrg, uuid, (Word_t) ctx);
141 }
142
134 -static METRIC *rrdeng_metric_create(STORAGE_INSTANCE *si, uuid_t *uuid) {
143 +static METRIC *rrdeng_metric_create(STORAGE_INSTANCE *si, nd_uuid_t *uuid) {
144 internal_fatal(!si, "DBENGINE: STORAGE_INSTANCE is NULL");
145
146 struct rrdengine_instance *ctx = (struct rrdengine_instance *)si;
@@ -168,7 +177,7 @@ STORAGE_METRIC_HANDLE *rrdeng_metric_get_or_create(RRDDIM *rd, STORAGE_INSTANCE
177 }
178
179 #ifdef NETDATA_INTERNAL_CHECKS
171 - if(uuid_memcmp(&rd->metric_uuid, mrg_metric_uuid(main_mrg, metric)) != 0) {
180 + if(!uuid_eq(rd->metric_uuid, *mrg_metric_uuid(main_mrg, metric))) {
181 char uuid1[UUID_STR_LEN + 1];
182 char uuid2[UUID_STR_LEN + 1];
183
@@ -208,7 +217,7 @@ static inline bool check_completed_page_consistency(struct rrdeng_collect_handle
217
218 struct rrdengine_instance *ctx = mrg_metric_ctx(handle->metric);
219
211 - uuid_t *uuid = mrg_metric_uuid(main_mrg, handle->metric);
220 + nd_uuid_t *uuid = mrg_metric_uuid(main_mrg, handle->metric);
221 time_t start_time_s = pgc_page_start_time_s(handle->pgc_page);
222 time_t end_time_s = pgc_page_end_time_s(handle->pgc_page);
223 uint32_t update_every_s = pgc_page_update_every_s(handle->pgc_page);
@@ -687,7 +696,7 @@ void rrdeng_store_metric_change_collection_frequency(STORAGE_COLLECT_HANDLE *sch
696 SPINLOCK global_query_handle_spinlock = NETDATA_SPINLOCK_INITIALIZER;
697 static struct rrdeng_query_handle *global_query_handle_ll = NULL;
698 static void register_query_handle(struct rrdeng_query_handle *handle) {
690 - handle->query_pid = gettid();
699 + handle->query_pid = gettid_cached();
700 handle->started_time_s = now_realtime_sec();
701
702 spinlock_lock(&global_query_handle_spinlock);
@@ -720,8 +729,6 @@ void rrdeng_load_metric_init(STORAGE_METRIC_HANDLE *smh,
729 {
730 usec_t started_ut = now_monotonic_usec();
731
723 - netdata_thread_disable_cancelability();
724 -
732 METRIC *metric = (METRIC *)smh;
733 struct rrdengine_instance *ctx = mrg_metric_ctx(metric);
734 struct rrdeng_query_handle *handle;
@@ -911,7 +918,6 @@ void rrdeng_load_metric_finalize(struct storage_engine_query_handle *seqh)
918 unregister_query_handle(handle);
919 rrdeng_query_handle_release(handle);
920 seqh->handle = NULL;
914 - netdata_thread_enable_cancelability();
921 }
922
923 time_t rrdeng_load_align_to_optimal_before(struct storage_engine_query_handle *seqh) {
@@ -946,7 +952,7 @@ time_t rrdeng_metric_oldest_time(STORAGE_METRIC_HANDLE *smh) {
952 return oldest_time_s;
953 }
954
949 -bool rrdeng_metric_retention_by_uuid(STORAGE_INSTANCE *si, uuid_t *dim_uuid, time_t *first_entry_s, time_t *last_entry_s)
955 +bool rrdeng_metric_retention_by_uuid(STORAGE_INSTANCE *si, nd_uuid_t *dim_uuid, time_t *first_entry_s, time_t *last_entry_s)
956 {
957 struct rrdengine_instance *ctx = (struct rrdengine_instance *)si;
958 if (unlikely(!ctx)) {
@@ -1143,12 +1149,12 @@ int rrdeng_init(struct rrdengine_instance **ctxp, const char *dbfiles_path,
1149 return UV_EMFILE;
1150 }
1151
1146 - if(ctxp)
1147 - *ctxp = ctx = callocz(1, sizeof(*ctx));
1148 - else {
1149 - ctx = multidb_ctx[tier];
1150 - memset(ctx, 0, sizeof(*ctx));
1152 + if(ctxp) {
1153 + *ctxp = ctx = mallocz(sizeof(*ctx));
1154 + initialize_single_ctx(ctx);
1155 }
1156 + else
1157 + ctx = multidb_ctx[tier];
1158
1159 ctx->config.tier = (int)tier;
1160 ctx->config.page_type = tier_page_type[tier];
@@ -1162,7 +1168,6 @@ int rrdeng_init(struct rrdengine_instance **ctxp, const char *dbfiles_path,
1168 ctx->atomic.transaction_id = 1;
1169 ctx->quiesce.enabled = false;
1170
1165 - rw_spinlock_init(&ctx->njfv2idx.spinlock);
1171 ctx->atomic.first_time_s = LONG_MAX;
1172 ctx->atomic.metrics = 0;
1173 ctx->atomic.samples = 0;
src/database/engine/rrdengineapi.h
+3 -3
@@ -25,7 +25,7 @@ extern uint8_t tier_page_type[];
25 #define CTX_POINT_SIZE_BYTES(ctx) page_type_size[(ctx)->config.page_type]
26
27 STORAGE_METRIC_HANDLE *rrdeng_metric_get_or_create(RRDDIM *rd, STORAGE_INSTANCE *si);
28 -STORAGE_METRIC_HANDLE *rrdeng_metric_get(STORAGE_INSTANCE *si, uuid_t *uuid);
28 +STORAGE_METRIC_HANDLE *rrdeng_metric_get(STORAGE_INSTANCE *si, nd_uuid_t *uuid);
29 void rrdeng_metric_release(STORAGE_METRIC_HANDLE *smh);
30 STORAGE_METRIC_HANDLE *rrdeng_metric_dup(STORAGE_METRIC_HANDLE *smh);
31
@@ -62,9 +62,9 @@ void rrdeng_exit_mode(struct rrdengine_instance *ctx);
62
63 int rrdeng_exit(struct rrdengine_instance *ctx);
64 void rrdeng_prepare_exit(struct rrdengine_instance *ctx);
65 -bool rrdeng_metric_retention_by_uuid(STORAGE_INSTANCE *si, uuid_t *dim_uuid, time_t *first_entry_s, time_t *last_entry_s);
65 +bool rrdeng_metric_retention_by_uuid(STORAGE_INSTANCE *si, nd_uuid_t *dim_uuid, time_t *first_entry_s, time_t *last_entry_s);
66
67 -extern STORAGE_METRICS_GROUP *rrdeng_metrics_group_get(STORAGE_INSTANCE *si, uuid_t *uuid);
67 +extern STORAGE_METRICS_GROUP *rrdeng_metrics_group_get(STORAGE_INSTANCE *si, nd_uuid_t *uuid);
68 extern void rrdeng_metrics_group_release(STORAGE_INSTANCE *si, STORAGE_METRICS_GROUP *smg);
69
70 typedef struct rrdengine_size_statistics {
src/database/ram/rrddim_mem.c
+11 -11
@@ -9,7 +9,7 @@ static netdata_rwlock_t rrddim_JudyHS_rwlock = NETDATA_RWLOCK_INITIALIZER;
9 // ----------------------------------------------------------------------------
10 // metrics groups
11
12 -STORAGE_METRICS_GROUP *rrddim_metrics_group_get(STORAGE_INSTANCE *si __maybe_unused, uuid_t *uuid __maybe_unused) {
12 +STORAGE_METRICS_GROUP *rrddim_metrics_group_get(STORAGE_INSTANCE *si __maybe_unused, nd_uuid_t *uuid __maybe_unused) {
13 return NULL;
14 }
15
@@ -52,7 +52,7 @@ rrddim_metric_get_or_create(RRDDIM *rd, STORAGE_INSTANCE *si __maybe_unused) {
52 struct mem_metric_handle *mh = (struct mem_metric_handle *)rrddim_metric_get(si, &rd->metric_uuid);
53 while(!mh) {
54 netdata_rwlock_wrlock(&rrddim_JudyHS_rwlock);
55 - Pvoid_t *PValue = JudyHSIns(&rrddim_JudyHS_array, &rd->metric_uuid, sizeof(uuid_t), PJE0);
55 + Pvoid_t *PValue = JudyHSIns(&rrddim_JudyHS_array, &rd->metric_uuid, sizeof(nd_uuid_t), PJE0);
56 mh = *PValue;
57 if(!mh) {
58 mh = callocz(1, sizeof(struct mem_metric_handle));
@@ -60,13 +60,13 @@ rrddim_metric_get_or_create(RRDDIM *rd, STORAGE_INSTANCE *si __maybe_unused) {
60 mh->refcount = 1;
61 update_metric_handle_from_rrddim(mh, rd);
62 *PValue = mh;
63 - __atomic_add_fetch(&rrddim_db_memory_size, sizeof(struct mem_metric_handle) + JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(uuid_t)), __ATOMIC_RELAXED);
63 + __atomic_add_fetch(&rrddim_db_memory_size, sizeof(struct mem_metric_handle) + JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(nd_uuid_t)), __ATOMIC_RELAXED);
64 }
65 else {
66 if(__atomic_add_fetch(&mh->refcount, 1, __ATOMIC_RELAXED) <= 0)
67 mh = NULL;
68 }
69 - netdata_rwlock_unlock(&rrddim_JudyHS_rwlock);
69 + netdata_rwlock_wrunlock(&rrddim_JudyHS_rwlock);
70 }
71
72 internal_fatal(mh->rd != rd, "RRDDIM_MEM: incorrect pointer returned from index.");
@@ -75,16 +75,16 @@ rrddim_metric_get_or_create(RRDDIM *rd, STORAGE_INSTANCE *si __maybe_unused) {
75 }
76
77 STORAGE_METRIC_HANDLE *
78 -rrddim_metric_get(STORAGE_INSTANCE *si __maybe_unused, uuid_t *uuid) {
78 +rrddim_metric_get(STORAGE_INSTANCE *si __maybe_unused, nd_uuid_t *uuid) {
79 struct mem_metric_handle *mh = NULL;
80 netdata_rwlock_rdlock(&rrddim_JudyHS_rwlock);
81 - Pvoid_t *PValue = JudyHSGet(rrddim_JudyHS_array, uuid, sizeof(uuid_t));
81 + Pvoid_t *PValue = JudyHSGet(rrddim_JudyHS_array, uuid, sizeof(nd_uuid_t));
82 if (likely(NULL != PValue)) {
83 mh = *PValue;
84 if(__atomic_add_fetch(&mh->refcount, 1, __ATOMIC_RELAXED) <= 0)
85 mh = NULL;
86 }
87 - netdata_rwlock_unlock(&rrddim_JudyHS_rwlock);
87 + netdata_rwlock_rdunlock(&rrddim_JudyHS_rwlock);
88
89 return (STORAGE_METRIC_HANDLE *)mh;
90 }
@@ -107,16 +107,16 @@ void rrddim_metric_release(STORAGE_METRIC_HANDLE *smh __maybe_unused) {
107
108 RRDDIM *rd = mh->rd;
109 netdata_rwlock_wrlock(&rrddim_JudyHS_rwlock);
110 - JudyHSDel(&rrddim_JudyHS_array, &rd->metric_uuid, sizeof(uuid_t), PJE0);
111 - netdata_rwlock_unlock(&rrddim_JudyHS_rwlock);
110 + JudyHSDel(&rrddim_JudyHS_array, &rd->metric_uuid, sizeof(nd_uuid_t), PJE0);
111 + netdata_rwlock_wrunlock(&rrddim_JudyHS_rwlock);
112
113 freez(mh);
114 - __atomic_sub_fetch(&rrddim_db_memory_size, sizeof(struct mem_metric_handle) + JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(uuid_t)), __ATOMIC_RELAXED);
114 + __atomic_sub_fetch(&rrddim_db_memory_size, sizeof(struct mem_metric_handle) + JUDYHS_INDEX_SIZE_ESTIMATE(sizeof(nd_uuid_t)), __ATOMIC_RELAXED);
115 }
116 }
117 }
118
119 -bool rrddim_metric_retention_by_uuid(STORAGE_INSTANCE *si __maybe_unused, uuid_t *uuid, time_t *first_entry_s, time_t *last_entry_s) {
119 +bool rrddim_metric_retention_by_uuid(STORAGE_INSTANCE *si __maybe_unused, nd_uuid_t *uuid, time_t *first_entry_s, time_t *last_entry_s) {
120 STORAGE_METRIC_HANDLE *smh = rrddim_metric_get(si, uuid);
121 if(!smh)
122 return false;
src/database/ram/rrddim_mem.h
+3 -3
@@ -23,13 +23,13 @@ struct mem_query_handle {
23 };
24
25 STORAGE_METRIC_HANDLE *rrddim_metric_get_or_create(RRDDIM *rd, STORAGE_INSTANCE *si);
26 -STORAGE_METRIC_HANDLE *rrddim_metric_get(STORAGE_INSTANCE *si, uuid_t *uuid);
26 +STORAGE_METRIC_HANDLE *rrddim_metric_get(STORAGE_INSTANCE *si, nd_uuid_t *uuid);
27 STORAGE_METRIC_HANDLE *rrddim_metric_dup(STORAGE_METRIC_HANDLE *smh);
28 void rrddim_metric_release(STORAGE_METRIC_HANDLE *smh);
29
30 -bool rrddim_metric_retention_by_uuid(STORAGE_INSTANCE *si, uuid_t *uuid, time_t *first_entry_s, time_t *last_entry_s);
30 +bool rrddim_metric_retention_by_uuid(STORAGE_INSTANCE *si, nd_uuid_t *uuid, time_t *first_entry_s, time_t *last_entry_s);
31
32 -STORAGE_METRICS_GROUP *rrddim_metrics_group_get(STORAGE_INSTANCE *si, uuid_t *uuid);
32 +STORAGE_METRICS_GROUP *rrddim_metrics_group_get(STORAGE_INSTANCE *si, nd_uuid_t *uuid);
33 void rrddim_metrics_group_release(STORAGE_INSTANCE *si, STORAGE_METRICS_GROUP *smg);
34
35 STORAGE_COLLECT_HANDLE *rrddim_collect_init(STORAGE_METRIC_HANDLE *smh, uint32_t update_every, STORAGE_METRICS_GROUP *smg);
src/database/rrd.h
+14 -13
@@ -270,7 +270,7 @@ void rrdr_fill_tier_gap_from_smaller_tiers(RRDDIM *rd, size_t tier, time_t now_s
270 // RRD DIMENSION - this is a metric
271
272 struct rrddim {
273 - uuid_t metric_uuid; // global UUID for this metric (unique_across hosts)
273 + nd_uuid_t metric_uuid; // global UUID for this metric (unique_across hosts)
274
275 // ------------------------------------------------------------------------
276 // dimension definition
@@ -361,9 +361,9 @@ size_t rrddim_size(void);
361 // ------------------------------------------------------------------------
362 // DATA COLLECTION STORAGE OPS
363
364 -STORAGE_METRICS_GROUP *rrdeng_metrics_group_get(STORAGE_INSTANCE *si, uuid_t *uuid);
365 -STORAGE_METRICS_GROUP *rrddim_metrics_group_get(STORAGE_INSTANCE *si, uuid_t *uuid);
366 -static inline STORAGE_METRICS_GROUP *storage_engine_metrics_group_get(STORAGE_ENGINE_BACKEND seb __maybe_unused, STORAGE_INSTANCE *si, uuid_t *uuid) {
364 +STORAGE_METRICS_GROUP *rrdeng_metrics_group_get(STORAGE_INSTANCE *si, nd_uuid_t *uuid);
365 +STORAGE_METRICS_GROUP *rrddim_metrics_group_get(STORAGE_INSTANCE *si, nd_uuid_t *uuid);
366 +static inline STORAGE_METRICS_GROUP *storage_engine_metrics_group_get(STORAGE_ENGINE_BACKEND seb __maybe_unused, STORAGE_INSTANCE *si, nd_uuid_t *uuid) {
367 internal_fatal(!is_valid_backend(seb), "STORAGE: invalid backend");
368
369 #ifdef ENABLE_DBENGINE
@@ -635,11 +635,11 @@ static inline time_t storage_engine_align_to_optimal_before(struct storage_engin
635 // function pointers for all APIs provided by a storage engine
636 typedef struct storage_engine_api {
637 // metric management
638 - STORAGE_METRIC_HANDLE *(*metric_get)(STORAGE_INSTANCE *si, uuid_t *uuid);
638 + STORAGE_METRIC_HANDLE *(*metric_get)(STORAGE_INSTANCE *si, nd_uuid_t *uuid);
639 STORAGE_METRIC_HANDLE *(*metric_get_or_create)(RRDDIM *rd, STORAGE_INSTANCE *si);
640 void (*metric_release)(STORAGE_METRIC_HANDLE *);
641 STORAGE_METRIC_HANDLE *(*metric_dup)(STORAGE_METRIC_HANDLE *);
642 - bool (*metric_retention_by_uuid)(STORAGE_INSTANCE *si, uuid_t *uuid, time_t *first_entry_s, time_t *last_entry_s);
642 + bool (*metric_retention_by_uuid)(STORAGE_INSTANCE *si, nd_uuid_t *uuid, time_t *first_entry_s, time_t *last_entry_s);
643 } STORAGE_ENGINE_API;
644
645 typedef struct storage_engine {
@@ -719,7 +719,7 @@ struct pluginsd_rrddim {
719 };
720
721 struct rrdset {
722 - uuid_t chart_uuid; // the global UUID for this chart
722 + nd_uuid_t chart_uuid; // the global UUID for this chart
723
724 // ------------------------------------------------------------------------
725 // chart configuration
@@ -1025,8 +1025,8 @@ struct alarm_entry {
1025 uint32_t alarm_id;
1026 uint32_t alarm_event_id;
1027 usec_t global_id;
1028 - uuid_t config_hash_id;
1029 - uuid_t transition_id;
1028 + nd_uuid_t config_hash_id;
1029 + nd_uuid_t transition_id;
1030
1031 time_t when;
1032 time_t duration;
@@ -1231,7 +1231,7 @@ struct rrdhost {
1231 // the following are state information for the threading
1232 // streaming metrics from this netdata to an upstream netdata
1233 struct sender_state *sender;
1234 - netdata_thread_t rrdpush_sender_thread; // the sender thread
1234 + ND_THREAD *rrdpush_sender_thread; // the sender thread
1235 size_t rrdpush_sender_replicating_charts; // the number of charts currently being replicated to a parent
1236 struct aclk_sync_cfg_t *aclk_config;
1237
@@ -1307,8 +1307,8 @@ struct rrdhost {
1307 time_t last_time_s;
1308 } retention;
1309
1310 - uuid_t host_uuid; // Global GUID for this host
1311 - uuid_t *node_id; // Cloud node_id
1310 + nd_uuid_t host_uuid; // Global GUID for this host
1311 + nd_uuid_t *node_id; // Cloud node_id
1312
1313 netdata_mutex_t aclk_state_lock;
1314 aclk_rrdhost_state aclk_state;
@@ -1365,7 +1365,8 @@ extern netdata_rwlock_t rrd_rwlock;
1365
1366 #define rrd_rdlock() netdata_rwlock_rdlock(&rrd_rwlock)
1367 #define rrd_wrlock() netdata_rwlock_wrlock(&rrd_rwlock)
1368 -#define rrd_unlock() netdata_rwlock_unlock(&rrd_rwlock)
1368 +#define rrd_rdunlock() netdata_rwlock_rdunlock(&rrd_rwlock)
1369 +#define rrd_wrunlock() netdata_rwlock_wrunlock(&rrd_rwlock)
1370
1371 // ----------------------------------------------------------------------------
1372
src/database/rrdcollector.c
+1 -1
@@ -68,7 +68,7 @@ void rrd_collector_started(void) {
68 if(!thread_rrd_collector)
69 thread_rrd_collector = callocz(1, sizeof(struct rrd_collector));
70
71 - thread_rrd_collector->tid = gettid();
71 + thread_rrd_collector->tid = gettid_cached();
72 __atomic_store_n(&thread_rrd_collector->running, true, __ATOMIC_RELAXED);
73 }
74
src/database/rrdfunctions-inflight.c
+4 -4
@@ -10,7 +10,7 @@ struct rrd_function_inflight {
10 bool used;
11
12 RRDHOST *host;
13 - uuid_t transaction_uuid;
13 + nd_uuid_t transaction_uuid;
14 const char *transaction;
15 const char *cmd;
16 const char *sanitized_cmd;
@@ -491,7 +491,7 @@ int rrd_function_run(RRDHOST *host, BUFFER *result_wb, int timeout_s,
491 // validate and parse the transaction, or generate a new transaction id
492
493 char uuid_str[UUID_COMPACT_STR_LEN];
494 - uuid_t uuid;
494 + nd_uuid_t uuid;
495
496 if(!transaction || !*transaction || uuid_parse_flexi(transaction, uuid) != 0)
497 uuid_generate_random(uuid);
@@ -597,7 +597,7 @@ int rrd_function_run(RRDHOST *host, BUFFER *result_wb, int timeout_s,
597 return rrd_call_function_async(r, wait);
598 }
599
600 -bool rrd_function_has_this_original_result_callback(uuid_t *transaction, rrd_function_result_callback_t cb) {
600 +bool rrd_function_has_this_original_result_callback(nd_uuid_t *transaction, rrd_function_result_callback_t cb) {
601 bool ret = false;
602 char str[UUID_COMPACT_STR_LEN];
603 uuid_unparse_lower_compact(*transaction, str);
@@ -684,7 +684,7 @@ cleanup:
684 dictionary_acquired_item_release(rrd_functions_inflight_requests, item);
685 }
686
687 -void rrd_function_call_progresser(uuid_t *transaction) {
687 +void rrd_function_call_progresser(nd_uuid_t *transaction) {
688 char str[UUID_COMPACT_STR_LEN];
689 uuid_unparse_lower_compact(*transaction, str);
690 rrd_function_progress(str);
src/database/rrdfunctions-inflight.h
+1 -1
@@ -11,6 +11,6 @@ void rrd_functions_inflight_init(void);
11 void rrd_function_cancel(const char *transaction);
12
13 void rrd_function_progress(const char *transaction);
14 -void rrd_function_call_progresser(uuid_t *transaction);
14 +void rrd_function_call_progresser(nd_uuid_t *transaction);
15
16 #endif //NETDATA_RRDFUNCTIONS_INFLIGHT_H
src/database/rrdfunctions.c
+2 -2
@@ -333,10 +333,10 @@ int rrd_functions_find_by_name(RRDHOST *host, BUFFER *wb, const char *name, size
333 s = &buffer[key_length - 1];
334
335 // skip a word from the end
336 - while (s >= buffer && !isspace(*s)) *s-- = '\0';
336 + while (s >= buffer && !isspace((uint8_t)*s)) *s-- = '\0';
337
338 // skip all spaces
339 - while (s >= buffer && isspace(*s)) *s-- = '\0';
339 + while (s >= buffer && isspace((uint8_t)*s)) *s-- = '\0';
340 }
341 }
342
src/database/rrdfunctions.h
+2 -2
@@ -19,7 +19,7 @@ typedef void (*rrd_function_progresser_cb_t)(void *data);
19 typedef void (*rrd_function_register_progresser_cb_t)(void *register_progresser_cb_data, rrd_function_progresser_cb_t progresser_cb, void *progresser_cb_data);
20
21 struct rrd_function_execute {
22 - uuid_t *transaction;
22 + nd_uuid_t *transaction;
23 const char *function;
24 BUFFER *payload;
25 const char *source;
@@ -85,7 +85,7 @@ int rrd_call_function_error(BUFFER *wb, const char *msg, int code);
85
86 bool rrd_function_available(RRDHOST *host, const char *function);
87
88 -bool rrd_function_has_this_original_result_callback(uuid_t *transaction, rrd_function_result_callback_t cb);
88 +bool rrd_function_has_this_original_result_callback(nd_uuid_t *transaction, rrd_function_result_callback_t cb);
89
90 #include "rrdfunctions-inline.h"
91 #include "rrdfunctions-inflight.h"
src/database/rrdhost.c
+10 -13
@@ -35,13 +35,13 @@ time_t rrdhost_free_ephemeral_time_s = 86400;
35
36 RRDHOST *find_host_by_node_id(char *node_id) {
37
38 - uuid_t node_uuid;
38 + nd_uuid_t node_uuid;
39 if (unlikely(!node_id || uuid_parse(node_id, node_uuid)))
40 return NULL;
41
42 RRDHOST *host, *ret = NULL;
43 dfe_start_read(rrdhost_root_index, host) {
44 - if (host->node_id && !(uuid_memcmp(host->node_id, &node_uuid))) {
44 + if (host->node_id && uuid_eq(*host->node_id, node_uuid)) {
45 ret = host;
46 break;
47 }
@@ -319,7 +319,7 @@ static RRDHOST *prepare_host_for_unittest(RRDHOST *host)
319
320 rrd_wrlock();
321 rrdhost_free___while_having_rrd_wrlock(host, true);
322 - rrd_unlock();
322 + rrd_wrunlock();
323 return NULL;
324 }
325 return host;
@@ -492,7 +492,7 @@ static RRDHOST *rrdhost_create(
492 if (!is_localhost)
493 rrdhost_free___while_having_rrd_wrlock(host, true);
494
495 - rrd_unlock();
495 + rrd_wrunlock();
496 return NULL;
497 }
498
@@ -503,7 +503,7 @@ static RRDHOST *rrdhost_create(
503 else
504 DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(localhost, host, prev, next);
505
506 - rrd_unlock();
506 + rrd_wrunlock();
507
508 // ------------------------------------------------------------------------
509
@@ -732,7 +732,7 @@ RRDHOST *rrdhost_find_or_create(
732 rrd_wrlock();
733 rrdhost_free___while_having_rrd_wrlock(host, true);
734 host = NULL;
735 - rrd_unlock();
735 + rrd_wrunlock();
736 }
737
738 if(!host) {
@@ -811,7 +811,7 @@ inline int rrdhost_should_be_removed(RRDHOST *host, RRDHOST *protected_host, tim
811
812 #ifdef ENABLE_DBENGINE
813 struct dbengine_initialization {
814 - netdata_thread_t thread;
814 + ND_THREAD *thread;
815 char path[FILENAME_MAX + 1];
816 int disk_space_mb;
817 size_t tier;
@@ -937,8 +937,7 @@ void dbengine_init(char *hostname) {
937 if(parallel_initialization) {
938 char tag[NETDATA_THREAD_TAG_MAX + 1];
939 snprintfz(tag, NETDATA_THREAD_TAG_MAX, "DBENGINIT[%zu]", tier);
940 - netdata_thread_create(&tiers_init[tier].thread, tag, NETDATA_THREAD_OPTION_JOINABLE,
941 - dbengine_tier_init, &tiers_init[tier]);
940 + tiers_init[tier].thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_JOINABLE, dbengine_tier_init, &tiers_init[tier]);
941 }
942 else
943 dbengine_tier_init(&tiers_init[tier]);
@@ -947,10 +946,8 @@ void dbengine_init(char *hostname) {
946 config_set_number(CONFIG_SECTION_DB, "storage tiers", storage_tiers);
947
948 for(size_t tier = 0; tier < storage_tiers ;tier++) {
950 - void *ptr;
951 -
949 if(parallel_initialization)
953 - netdata_thread_join(tiers_init[tier].thread, &ptr);
950 + nd_thread_join(tiers_init[tier].thread);
951
952 if(tiers_init[tier].ret != 0) {
953 nd_log(NDLS_DAEMON, NDLP_ERR,
@@ -1289,7 +1286,7 @@ void rrdhost_free_all(void) {
1286 if(localhost)
1287 rrdhost_free___while_having_rrd_wrlock(localhost, true);
1288
1292 - rrd_unlock();
1289 + rrd_wrunlock();
1290 }
1291
1292 void rrd_finalize_collection_for_all_hosts(void) {
src/database/rrdset.c
+11 -15
@@ -1081,7 +1081,7 @@ void rrdset_timed_next(RRDSET *st, struct timeval now, usec_t duration_since_las
1081 last_time_s = now.tv_sec;
1082
1083 if(min_delta > permanent_min_delta) {
1084 - netdata_log_info("MINIMUM MICROSECONDS DELTA of thread %d increased from %"PRIi64" to %"PRIi64" (+%"PRIi64")", gettid(), permanent_min_delta, min_delta, min_delta - permanent_min_delta);
1084 + netdata_log_info("MINIMUM MICROSECONDS DELTA of thread %d increased from %"PRIi64" to %"PRIi64" (+%"PRIi64")", gettid_cached(), permanent_min_delta, min_delta, min_delta - permanent_min_delta);
1085 permanent_min_delta = min_delta;
1086 }
1087
@@ -1313,6 +1313,7 @@ void store_metric_collection_completed() {
1313 struct rda_item {
1314 const DICTIONARY_ITEM *item;
1315 RRDDIM *rd;
1316 + bool reset_or_overflow;
1317 };
1318
1319 static __thread struct rda_item *thread_rda = NULL;
@@ -1353,7 +1354,6 @@ static inline size_t rrdset_done_interpolate(
1354 , usec_t last_collect_ut
1355 , usec_t now_collect_ut
1356 , char store_this_entry
1356 - , uint32_t has_reset_value
1357 ) {
1358 RRDDIM *rd;
1359
@@ -1368,11 +1368,6 @@ static inline size_t rrdset_done_interpolate(
1368 size_t counter = st->counter;
1369 long current_entry = st->db.current_entry;
1370
1371 - SN_FLAGS storage_flags = SN_DEFAULT_FLAGS;
1372 -
1373 - if (has_reset_value)
1374 - storage_flags |= SN_FLAG_RESET;
1375 -
1371 for( ; next_store_ut <= now_collect_ut ; last_collect_ut = next_store_ut, next_store_ut += update_every_ut, iterations-- ) {
1372
1373 internal_error(iterations < 0,
@@ -1398,6 +1393,11 @@ static inline size_t rrdset_done_interpolate(
1393 rd = rda->rd;
1394 if(unlikely(!rd)) continue;
1395
1396 + SN_FLAGS storage_flags = SN_DEFAULT_FLAGS;
1397 +
1398 + if (rda->reset_or_overflow)
1399 + storage_flags |= SN_FLAG_RESET;
1400 +
1401 NETDATA_DOUBLE new_value;
1402
1403 switch(rd->algorithm) {
@@ -1514,9 +1514,6 @@ static inline size_t rrdset_done_interpolate(
1514
1515 ml_chart_update_end(st);
1516
1517 - // reset the storage flags for the next point, if any;
1518 - storage_flags = SN_DEFAULT_FLAGS;
1519 -
1517 st->counter = ++counter;
1518 st->db.current_entry = current_entry = ((current_entry + 1) >= st->db.entries) ? 0 : current_entry + 1;
1519
@@ -1678,8 +1675,6 @@ void rrdset_timed_done(RRDSET *st, struct timeval now, bool pending_rrdset_next)
1675 if(stream_buffer.wb && !stream_buffer.v2)
1676 rrdset_push_metrics_v1(&stream_buffer, st);
1677
1681 - uint32_t has_reset_value = 0;
1682 -
1678 size_t rda_slots = dictionary_entries(st->rrddim_root_index);
1679 struct rda_item *rda_base = rrdset_thread_rda_get(&rda_slots);
1680
@@ -1697,12 +1692,14 @@ void rrdset_timed_done(RRDSET *st, struct timeval now, bool pending_rrdset_next)
1692 if(rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)) {
1693 rda->item = NULL;
1694 rda->rd = NULL;
1695 + rda->reset_or_overflow = false;
1696 continue;
1697 }
1698
1699 // store the dimension in the array
1700 rda->item = dictionary_acquired_item_dup(st->rrddim_root_index, rd_dfe.item);
1701 rda->rd = dictionary_acquired_item_value(rda->item);
1702 + rda->reset_or_overflow = false;
1703
1704 // calculate totals
1705 if(likely(rrddim_check_updated(rd))) {
@@ -1717,7 +1714,7 @@ void rrdset_timed_done(RRDSET *st, struct timeval now, bool pending_rrdset_next)
1714 );
1715
1716 if(!(rrddim_option_check(rd, RRDDIM_OPTION_DONT_DETECT_RESETS_OR_OVERFLOWS)))
1720 - has_reset_value = 1;
1717 + rda->reset_or_overflow = true;
1718
1719 rd->collector.last_collected_value = rd->collector.collected_value;
1720 }
@@ -1820,7 +1817,7 @@ void rrdset_timed_done(RRDSET *st, struct timeval now, bool pending_rrdset_next)
1817 , rd->collector.collected_value);
1818
1819 if(!(rrddim_option_check(rd, RRDDIM_OPTION_DONT_DETECT_RESETS_OR_OVERFLOWS)))
1823 - has_reset_value = 1;
1820 + rda->reset_or_overflow = true;
1821
1822 uint64_t last = (uint64_t)rd->collector.last_collected_value;
1823 uint64_t new = (uint64_t)rd->collector.collected_value;
@@ -1944,7 +1941,6 @@ void rrdset_timed_done(RRDSET *st, struct timeval now, bool pending_rrdset_next)
1941 , last_collect_ut
1942 , now_collect_ut
1943 , store_this_entry
1947 - , has_reset_value
1944 );
1945
1946 for(dim_id = 0, rda = rda_base ; dim_id < rda_slots ; ++dim_id, ++rda) {
src/database/sqlite/sqlite_aclk.c
+10 -10
@@ -97,7 +97,7 @@ static int create_host_callback(void *data, int argc, char **argv, char **column
97 is_registered = str2i(argv[IDX_IS_REGISTERED]);
98
99 char guid[UUID_STR_LEN];
100 - uuid_unparse_lower(*(uuid_t *)argv[IDX_HOST_ID], guid);
100 + uuid_unparse_lower(*(nd_uuid_t *)argv[IDX_HOST_ID], guid);
101
102 if (is_ephemeral && age > rrdhost_free_ephemeral_time_s) {
103 netdata_log_info(
@@ -116,7 +116,7 @@ static int create_host_callback(void *data, int argc, char **argv, char **column
116
117 system_info->hops = str2i((const char *) argv[IDX_HOPS]);
118
119 - sql_build_host_system_info((uuid_t *)argv[IDX_HOST_ID], system_info);
119 + sql_build_host_system_info((nd_uuid_t *)argv[IDX_HOST_ID], system_info);
120
121 RRDHOST *host = rrdhost_find_or_create(
122 (const char *)argv[IDX_HOSTNAME],
@@ -157,7 +157,7 @@ static int create_host_callback(void *data, int argc, char **argv, char **column
157 if (is_ephemeral)
158 host->child_disconnected_time = now_realtime_sec();
159
160 - host->rrdlabels = sql_load_host_labels((uuid_t *)argv[IDX_HOST_ID]);
160 + host->rrdlabels = sql_load_host_labels((nd_uuid_t *)argv[IDX_HOST_ID]);
161 host->last_connected = last_connected;
162 }
163
@@ -175,7 +175,7 @@ static int create_host_callback(void *data, int argc, char **argv, char **column
175 #ifdef ENABLE_ACLK
176
177 #define SQL_SELECT_HOST_BY_UUID "SELECT host_id FROM host WHERE host_id = @host_id"
178 -static int is_host_available(uuid_t *host_id)
178 +static int is_host_available(nd_uuid_t *host_id)
179 {
180 sqlite3_stmt *res = NULL;
181 int rc = 0;
@@ -205,7 +205,7 @@ static void sql_delete_aclk_table_list(char *host_guid)
205 char host_str[UUID_STR_LEN];
206
207 int rc;
208 - uuid_t host_uuid;
208 + nd_uuid_t host_uuid;
209
210 if (unlikely(!host_guid))
211 return;
@@ -249,7 +249,7 @@ fail:
249 static void sql_unregister_node(char *machine_guid)
250 {
251 int rc;
252 - uuid_t host_uuid;
252 + nd_uuid_t host_uuid;
253
254 if (unlikely(!machine_guid))
255 return;
@@ -333,11 +333,11 @@ static void sql_maint_aclk_sync_database_all(void)
333 static int aclk_config_parameters(void *data __maybe_unused, int argc __maybe_unused, char **argv, char **column __maybe_unused)
334 {
335 char uuid_str[UUID_STR_LEN];
336 - uuid_unparse_lower(*((uuid_t *) argv[0]), uuid_str);
336 + uuid_unparse_lower(*((nd_uuid_t *) argv[0]), uuid_str);
337
338 RRDHOST *host = rrdhost_find_by_guid(uuid_str);
339 if (host != localhost)
340 - sql_create_aclk_table(host, (uuid_t *) argv[0], (uuid_t *) argv[1]);
340 + sql_create_aclk_table(host, (nd_uuid_t *) argv[0], (nd_uuid_t *) argv[1]);
341 return 0;
342 }
343
@@ -374,7 +374,7 @@ static void timer_cb(uv_timer_t *handle)
374 static void aclk_synchronization(void *arg __maybe_unused)
375 {
376 struct aclk_sync_config_s *config = arg;
377 - uv_thread_set_name_np(config->thread, "ACLKSYNC");
377 + uv_thread_set_name_np("ACLKSYNC");
378 worker_register("ACLKSYNC");
379 service_register(SERVICE_THREAD_TYPE_EVENT_LOOP, NULL, NULL, NULL, true);
380
@@ -487,7 +487,7 @@ static void aclk_synchronization_init(void)
487
488 // -------------------------------------------------------------
489
490 -void sql_create_aclk_table(RRDHOST *host __maybe_unused, uuid_t *host_uuid __maybe_unused, uuid_t *node_id __maybe_unused)
490 +void sql_create_aclk_table(RRDHOST *host __maybe_unused, nd_uuid_t *host_uuid __maybe_unused, nd_uuid_t *node_id __maybe_unused)
491 {
492 #ifdef ENABLE_ACLK
493 char uuid_str[UUID_STR_LEN];
src/database/sqlite/sqlite_aclk.h
+3 -3
@@ -9,7 +9,7 @@
9 #define ACLK_DELETE_ACK_ALERTS_INTERNAL (86400)
10 #define ACLK_SYNC_QUERY_SIZE 512
11
12 -static inline void uuid_unparse_lower_fix(uuid_t *uuid, char *out)
12 +static inline void uuid_unparse_lower_fix(nd_uuid_t *uuid, char *out)
13 {
14 uuid_unparse_lower(*uuid, out);
15 out[8] = '_';
@@ -18,7 +18,7 @@ static inline void uuid_unparse_lower_fix(uuid_t *uuid, char *out)
18 out[23] = '_';
19 }
20
21 -static inline int uuid_parse_fix(char *in, uuid_t uuid)
21 +static inline int uuid_parse_fix(char *in, nd_uuid_t uuid)
22 {
23 in[8] = '-';
24 in[13] = '-';
@@ -80,7 +80,7 @@ typedef struct aclk_sync_cfg_t {
80 uint64_t alerts_log_last_sequence_id;
81 } aclk_sync_cfg_t;
82
83 -void sql_create_aclk_table(RRDHOST *host, uuid_t *host_uuid, uuid_t *node_id);
83 +void sql_create_aclk_table(RRDHOST *host, nd_uuid_t *host_uuid, nd_uuid_t *node_id);
84 void sql_aclk_sync_init(void);
85 void aclk_push_alert_config(const char *node_id, const char *config_hash);
86 void aclk_push_node_alert_snapshot(const char *node_id);
src/database/sqlite/sqlite_aclk_alert.c
+8 -8
@@ -45,7 +45,7 @@ done:
45 "WHERE hld.unique_id = @unique_id AND hl.config_hash_id = ah.hash_id AND hld.health_log_id = hl.health_log_id " \
46 "AND hl.host_id = @host_id AND ah.warn IS NULL AND ah.crit IS NULL"
47
48 -static inline bool is_event_from_alert_variable_config(int64_t unique_id, uuid_t *host_id)
48 +static inline bool is_event_from_alert_variable_config(int64_t unique_id, nd_uuid_t *host_id)
49 {
50 sqlite3_stmt *res = NULL;
51
@@ -106,15 +106,15 @@ static bool should_send_to_cloud(RRDHOST *host, ALARM_ENTRY *ae)
106 param = 0;
107 int rc = sqlite3_step_monitored(res);
108 if (likely(rc == SQLITE_ROW)) {
109 - uuid_t config_hash_id;
109 + nd_uuid_t config_hash_id;
110 RRDCALC_STATUS status = (RRDCALC_STATUS)sqlite3_column_int(res, 0);
111
112 if (sqlite3_column_type(res, 1) != SQLITE_NULL)
113 - uuid_copy(config_hash_id, *((uuid_t *)sqlite3_column_blob(res, 1)));
113 + uuid_copy(config_hash_id, *((nd_uuid_t *)sqlite3_column_blob(res, 1)));
114
115 int64_t unique_id = sqlite3_column_int64(res, 2);
116
117 - if (ae->new_status != (RRDCALC_STATUS)status || uuid_memcmp(&ae->config_hash_id, &config_hash_id))
117 + if (ae->new_status != (RRDCALC_STATUS)status || !uuid_eq(ae->config_hash_id, config_hash_id))
118 send = true;
119 else
120 update_filtered(ae, unique_id, host->aclk_config->uuid_str);
@@ -203,7 +203,7 @@ static inline char *sqlite3_uuid_unparse_strdupz(sqlite3_stmt *res, int iCol) {
203 if(sqlite3_column_type(res, iCol) == SQLITE_NULL)
204 uuid_str[0] = '\0';
205 else
206 - uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, iCol)), uuid_str);
206 + uuid_unparse_lower(*((nd_uuid_t *) sqlite3_column_blob(res, iCol)), uuid_str);
207
208 return strdupz(uuid_str);
209 }
@@ -499,7 +499,7 @@ void aclk_push_alert_config_event(char *node_id __maybe_unused, char *config_has
499 if (!PREPARE_STATEMENT(db_meta, SQL_SELECT_ALERT_CONFIG, &res))
500 return;
501
502 - uuid_t hash_uuid;
502 + nd_uuid_t hash_uuid;
503 if (uuid_parse(config_hash, hash_uuid))
504 return;
505
@@ -593,7 +593,7 @@ done:
593 // Start streaming alerts
594 void aclk_start_alert_streaming(char *node_id, bool resets)
595 {
596 - uuid_t node_uuid;
596 + nd_uuid_t node_uuid;
597
598 if (unlikely(!node_id || uuid_parse(node_id, node_uuid)))
599 return;
@@ -675,7 +675,7 @@ void sql_queue_removed_alerts_to_aclk(RRDHOST *host)
675
676 void aclk_process_send_alarm_snapshot(char *node_id, char *claim_id __maybe_unused, char *snapshot_uuid)
677 {
678 - uuid_t node_uuid;
678 + nd_uuid_t node_uuid;
679
680 if (unlikely(!node_id || uuid_parse(node_id, node_uuid)))
681 return;
src/database/sqlite/sqlite_aclk_node.c
+1 -1
@@ -113,7 +113,7 @@ static void build_node_info(RRDHOST *host)
113 host->machine_guid,
114 host == localhost ? "parent" : "child");
115
116 - rrd_unlock();
116 + rrd_rdunlock();
117 freez(node_info.claim_id);
118 freez(node_info.node_instance_capabilities);
119 freez(host_version);
src/database/sqlite/sqlite_context.c
+9 -11
@@ -78,7 +78,7 @@ int sql_init_context_database(int memory)
78 #define CTX_GET_CHART_LIST "SELECT c.chart_id, c.type||'.'||c.id, c.name, c.context, c.title, c.unit, c.priority, " \
79 "c.update_every, c.chart_type, c.family FROM chart c WHERE c.host_id = @host_id AND c.chart_id IS NOT NULL"
80
81 -void ctx_get_chart_list(uuid_t *host_uuid, void (*dict_cb)(SQL_CHART_DATA *, void *), void *data)
81 +void ctx_get_chart_list(nd_uuid_t *host_uuid, void (*dict_cb)(SQL_CHART_DATA *, void *), void *data)
82 {
83 static __thread sqlite3_stmt *res = NULL;
84
@@ -96,7 +96,7 @@ void ctx_get_chart_list(uuid_t *host_uuid, void (*dict_cb)(SQL_CHART_DATA *, voi
96 param = 0;
97 SQL_CHART_DATA chart_data = { 0 };
98 while (sqlite3_step_monitored(res) == SQLITE_ROW) {
99 - uuid_copy(chart_data.chart_id, *((uuid_t *)sqlite3_column_blob(res, 0)));
99 + uuid_copy(chart_data.chart_id, *((nd_uuid_t *)sqlite3_column_blob(res, 0)));
100 chart_data.id = (char *) sqlite3_column_text(res, 1);
101 chart_data.name = (char *) sqlite3_column_text(res, 2);
102 chart_data.context = (char *) sqlite3_column_text(res, 3);
@@ -117,7 +117,7 @@ done:
117 // Dimension list
118 #define CTX_GET_DIMENSION_LIST "SELECT d.dim_id, d.id, d.name, CASE WHEN INSTR(d.options,\"hidden\") > 0 THEN 1 ELSE 0 END " \
119 "FROM dimension d WHERE d.chart_id = @id AND d.dim_id IS NOT NULL ORDER BY d.rowid ASC"
120 -void ctx_get_dimension_list(uuid_t *chart_uuid, void (*dict_cb)(SQL_DIMENSION_DATA *, void *), void *data)
120 +void ctx_get_dimension_list(nd_uuid_t *chart_uuid, void (*dict_cb)(SQL_DIMENSION_DATA *, void *), void *data)
121 {
122 static __thread sqlite3_stmt *res = NULL;
123
@@ -131,7 +131,7 @@ void ctx_get_dimension_list(uuid_t *chart_uuid, void (*dict_cb)(SQL_DIMENSION_DA
131
132 param = 0;
133 while (sqlite3_step_monitored(res) == SQLITE_ROW) {
134 - uuid_copy(dimension_data.dim_id, *((uuid_t *)sqlite3_column_blob(res, 0)));
134 + uuid_copy(dimension_data.dim_id, *((nd_uuid_t *)sqlite3_column_blob(res, 0)));
135 dimension_data.id = (char *) sqlite3_column_text(res, 1);
136 dimension_data.name = (char *) sqlite3_column_text(res, 2);
137 dimension_data.hidden = sqlite3_column_int(res, 3);
@@ -146,7 +146,7 @@ done:
146 // LABEL LIST
147 #define CTX_GET_LABEL_LIST "SELECT l.label_key, l.label_value, l.source_type FROM meta.chart_label l WHERE l.chart_id = @id"
148
149 -void ctx_get_label_list(uuid_t *chart_uuid, void (*dict_cb)(SQL_CLABEL_DATA *, void *), void *data)
149 +void ctx_get_label_list(nd_uuid_t *chart_uuid, void (*dict_cb)(SQL_CLABEL_DATA *, void *), void *data)
150 {
151 static __thread sqlite3_stmt *res = NULL;
152
@@ -175,7 +175,7 @@ done:
175 #define CTX_GET_CONTEXT_LIST "SELECT id, version, title, chart_type, unit, priority, first_time_t, " \
176 "last_time_t, deleted, family FROM context c WHERE c.host_id = @host_id"
177
178 -void ctx_get_context_list(uuid_t *host_uuid, void (*dict_cb)(VERSIONED_CONTEXT_DATA *, void *), void *data)
178 +void ctx_get_context_list(nd_uuid_t *host_uuid, void (*dict_cb)(VERSIONED_CONTEXT_DATA *, void *), void *data)
179 {
180
181 if (unlikely(!host_uuid))
@@ -220,7 +220,7 @@ done:
220 "(host_id, id, version, title, chart_type, unit, priority, first_time_t, last_time_t, deleted, family) " \
221 "VALUES (@host_id, @context, @version, @title, @chart_type, @unit, @priority, @first_t, @last_t, @delete, @family)"
222
223 -int ctx_store_context(uuid_t *host_uuid, VERSIONED_CONTEXT_DATA *context_data)
223 +int ctx_store_context(nd_uuid_t *host_uuid, VERSIONED_CONTEXT_DATA *context_data)
224 {
225 int rc_stored = 1;
226 sqlite3_stmt *res = NULL;
@@ -259,7 +259,7 @@ done:
259 // Delete a context
260
261 #define CTX_DELETE_CONTEXT "DELETE FROM context WHERE host_id = @host_id AND id = @context"
262 -int ctx_delete_context(uuid_t *host_uuid, VERSIONED_CONTEXT_DATA *context_data)
262 +int ctx_delete_context(nd_uuid_t *host_uuid, VERSIONED_CONTEXT_DATA *context_data)
263 {
264 int rc_stored = 1;
265 sqlite3_stmt *res = NULL;
@@ -293,9 +293,7 @@ int sql_context_cache_stats(int op)
293 if (unlikely(!db_context_meta))
294 return 0;
295
296 - netdata_thread_disable_cancelability();
296 sqlite3_db_status(db_context_meta, op, &count, &dummy, 0);
298 - netdata_thread_enable_cancelability();
297 return count;
298 }
299
@@ -336,7 +334,7 @@ static void dict_ctx_get_context_list_cb(VERSIONED_CONTEXT_DATA *context_data, v
334
335 int ctx_unittest(void)
336 {
339 - uuid_t host_uuid;
337 + nd_uuid_t host_uuid;
338 uuid_generate(host_uuid);
339
340 if (sqlite_library_init())
src/database/sqlite/sqlite_context.h
+8 -8
@@ -8,7 +8,7 @@
8
9 int sql_context_cache_stats(int op);
10 typedef struct ctx_chart {
11 - uuid_t chart_id;
11 + nd_uuid_t chart_id;
12 const char *id;
13 const char *name;
14 const char *context;
@@ -21,7 +21,7 @@ typedef struct ctx_chart {
21 } SQL_CHART_DATA;
22
23 typedef struct ctx_dimension {
24 - uuid_t dim_id;
24 + nd_uuid_t dim_id;
25 char *id;
26 char *name;
27 bool hidden;
@@ -52,17 +52,17 @@ typedef struct versioned_context_data {
52
53 } VERSIONED_CONTEXT_DATA;
54
55 -void ctx_get_context_list(uuid_t *host_uuid, void (*dict_cb)(VERSIONED_CONTEXT_DATA *, void *), void *data);
55 +void ctx_get_context_list(nd_uuid_t *host_uuid, void (*dict_cb)(VERSIONED_CONTEXT_DATA *, void *), void *data);
56
57 -void ctx_get_chart_list(uuid_t *host_uuid, void (*dict_cb)(SQL_CHART_DATA *, void *), void *data);
58 -void ctx_get_label_list(uuid_t *chart_uuid, void (*dict_cb)(SQL_CLABEL_DATA *, void *), void *data);
59 -void ctx_get_dimension_list(uuid_t *chart_uuid, void (*dict_cb)(SQL_DIMENSION_DATA *, void *), void *data);
57 +void ctx_get_chart_list(nd_uuid_t *host_uuid, void (*dict_cb)(SQL_CHART_DATA *, void *), void *data);
58 +void ctx_get_label_list(nd_uuid_t *chart_uuid, void (*dict_cb)(SQL_CLABEL_DATA *, void *), void *data);
59 +void ctx_get_dimension_list(nd_uuid_t *chart_uuid, void (*dict_cb)(SQL_DIMENSION_DATA *, void *), void *data);
60
61 -int ctx_store_context(uuid_t *host_uuid, VERSIONED_CONTEXT_DATA *context_data);
61 +int ctx_store_context(nd_uuid_t *host_uuid, VERSIONED_CONTEXT_DATA *context_data);
62
63 #define ctx_update_context(host_uuid, context_data) ctx_store_context(host_uuid, context_data)
64
65 -int ctx_delete_context(uuid_t *host_id, VERSIONED_CONTEXT_DATA *context_data);
65 +int ctx_delete_context(nd_uuid_t *host_id, VERSIONED_CONTEXT_DATA *context_data);
66
67 int sql_init_context_database(int memory);
68 uint64_t sqlite_get_context_space(void);
src/database/sqlite/sqlite_health.c
+24 -24
@@ -249,7 +249,7 @@ done:
249 #define SQL_INJECT_REMOVED_UPDATE_LOG \
250 "UPDATE health_log SET last_transition_id = ?1 WHERE alarm_id = ?2 AND last_transition_id = ?3 AND host_id = ?4"
251
252 -bool sql_update_removed_in_health_log(RRDHOST *host, uint32_t alarm_id, uuid_t *transition_id, uuid_t *last_transition)
252 +bool sql_update_removed_in_health_log(RRDHOST *host, uint32_t alarm_id, nd_uuid_t *transition_id, nd_uuid_t *last_transition)
253 {
254 int rc = 0;
255 sqlite3_stmt *res;
@@ -275,7 +275,7 @@ done:
275 return (param == 0 && rc == SQLITE_DONE);
276 }
277
278 -bool sql_update_removed_in_health_log_detail(uint32_t unique_id, uint32_t max_unique_id, uuid_t *prev_transition_id)
278 +bool sql_update_removed_in_health_log_detail(uint32_t unique_id, uint32_t max_unique_id, nd_uuid_t *prev_transition_id)
279 {
280 int rc = 0;
281 sqlite3_stmt *res;
@@ -307,7 +307,7 @@ void sql_inject_removed_status(
307 uint32_t alarm_event_id,
308 uint32_t unique_id,
309 uint32_t max_unique_id,
310 - uuid_t *last_transition)
310 + nd_uuid_t *last_transition)
311 {
312 if (!alarm_id || !alarm_event_id || !unique_id || !max_unique_id)
313 return;
@@ -317,7 +317,7 @@ void sql_inject_removed_status(
317 if (!PREPARE_STATEMENT(db_meta, SQL_INJECT_REMOVED, &res))
318 return;
319
320 - uuid_t transition_id;
320 + nd_uuid_t transition_id;
321 uuid_generate_random(transition_id);
322
323 int param = 0;
@@ -379,7 +379,7 @@ void sql_check_removed_alerts_state(RRDHOST *host)
379 {
380 uint32_t max_unique_id = 0;
381 sqlite3_stmt *res = NULL;
382 - uuid_t transition_id;
382 + nd_uuid_t transition_id;
383
384 if (!PREPARE_STATEMENT(db_meta, SQL_SELECT_LAST_STATUSES, &res))
385 return;
@@ -396,7 +396,7 @@ void sql_check_removed_alerts_state(RRDHOST *host)
396 unique_id = (uint32_t)sqlite3_column_int64(res, 1);
397 alarm_id = (uint32_t)sqlite3_column_int64(res, 2);
398 alarm_event_id = (uint32_t)sqlite3_column_int64(res, 3);
399 - uuid_copy(transition_id, *((uuid_t *)sqlite3_column_blob(res, 4)));
399 + uuid_copy(transition_id, *((nd_uuid_t *)sqlite3_column_blob(res, 4)));
400
401 if (unlikely(status != RRDCALC_STATUS_REMOVED)) {
402 if (unlikely(!max_unique_id))
@@ -414,12 +414,12 @@ done:
414 "DELETE FROM health_log WHERE host_id = @host_id AND chart NOT IN " \
415 "(SELECT type||'.'||id FROM chart WHERE host_id = @host_id)"
416
417 -static void sql_remove_alerts_from_deleted_charts(RRDHOST *host, uuid_t *host_uuid)
417 +static void sql_remove_alerts_from_deleted_charts(RRDHOST *host, nd_uuid_t *host_uuid)
418 {
419 sqlite3_stmt *res = NULL;
420 int ret;
421
422 - uuid_t *actual_uuid = host ? &host->host_uuid : host_uuid;
422 + nd_uuid_t *actual_uuid = host ? &host->host_uuid : host_uuid;
423 if (!actual_uuid)
424 return;
425
@@ -446,10 +446,10 @@ static int clean_host_alerts(void *data, int argc, char **argv, char **column)
446 UNUSED(column);
447
448 char guid[UUID_STR_LEN];
449 - uuid_unparse_lower(*(uuid_t *)argv[0], guid);
449 + uuid_unparse_lower(*(nd_uuid_t *)argv[0], guid);
450
451 netdata_log_info("Checking host %s (%s)", guid, (const char *) argv[1]);
452 - sql_remove_alerts_from_deleted_charts(NULL, (uuid_t *)argv[0]);
452 + sql_remove_alerts_from_deleted_charts(NULL, (nd_uuid_t *)argv[0]);
453
454 return 0;
455 }
@@ -568,7 +568,7 @@ void sql_health_alarm_log_load(RRDHOST *host)
568 ae->alarm_id = alarm_id;
569
570 if (sqlite3_column_type(res, 3) != SQLITE_NULL)
571 - uuid_copy(ae->config_hash_id, *((uuid_t *) sqlite3_column_blob(res, 3)));
571 + uuid_copy(ae->config_hash_id, *((nd_uuid_t *) sqlite3_column_blob(res, 3)));
572
573 ae->alarm_event_id = (uint32_t) sqlite3_column_int64(res, 2);
574 ae->updated_by_id = (uint32_t) sqlite3_column_int64(res, 4);
@@ -609,7 +609,7 @@ void sql_health_alarm_log_load(RRDHOST *host)
609 ae->chart_context = SQLITE3_COLUMN_STRINGDUP_OR_NULL(res, 29);
610
611 if (sqlite3_column_type(res, 30) != SQLITE_NULL)
612 - uuid_copy(ae->transition_id, *((uuid_t *)sqlite3_column_blob(res, 30)));
612 + uuid_copy(ae->transition_id, *((nd_uuid_t *)sqlite3_column_blob(res, 30)));
613
614 if (sqlite3_column_type(res, 31) != SQLITE_NULL)
615 ae->global_id = sqlite3_column_int64(res, 31);
@@ -894,11 +894,11 @@ void sql_health_alarm_log2json(RRDHOST *host, BUFFER *wb, time_t after, const ch
894 char new_value_string[100 + 1];
895
896 char config_hash_id[UUID_STR_LEN];
897 - uuid_unparse_lower(*((uuid_t *)sqlite3_column_blob(stmt_query, 3)), config_hash_id);
897 + uuid_unparse_lower(*((nd_uuid_t *)sqlite3_column_blob(stmt_query, 3)), config_hash_id);
898
899 char transition_id[UUID_STR_LEN] = {0};
900 if (sqlite3_column_type(stmt_query, 30) != SQLITE_NULL)
901 - uuid_unparse_lower(*((uuid_t *)sqlite3_column_blob(stmt_query, 30)), transition_id);
901 + uuid_unparse_lower(*((nd_uuid_t *)sqlite3_column_blob(stmt_query, 30)), transition_id);
902
903 char *edit_command = sqlite3_column_bytes(stmt_query, 16) > 0 ?
904 health_edit_command_from_source((char *)sqlite3_column_text(stmt_query, 16)) :
@@ -988,7 +988,7 @@ int health_migrate_old_health_log_table(char *table) {
988 }
989
990 char *uuid_from_table = strdupz(table + 11);
991 - uuid_t uuid;
991 + nd_uuid_t uuid;
992 if (uuid_parse_fix(uuid_from_table, uuid)) {
993 freez(uuid_from_table);
994 return 0;
@@ -1175,7 +1175,7 @@ bool sql_find_alert_transition(
1175
1176 char machine_guid[UUID_STR_LEN];
1177
1178 - uuid_t transition_uuid;
1178 + nd_uuid_t transition_uuid;
1179 if (uuid_parse(transition, transition_uuid))
1180 return false;
1181
@@ -1190,7 +1190,7 @@ bool sql_find_alert_transition(
1190 param = 0;
1191 while (sqlite3_step_monitored(res) == SQLITE_ROW) {
1192 ok = true;
1193 - uuid_unparse_lower(*(uuid_t *) sqlite3_column_blob(res, 1), machine_guid);
1193 + uuid_unparse_lower(*(nd_uuid_t *) sqlite3_column_blob(res, 1), machine_guid);
1194 cb(machine_guid, (const char *) sqlite3_column_text(res, 2), sqlite3_column_int(res, 0), data);
1195 }
1196
@@ -1234,7 +1234,7 @@ void sql_alert_transitions(
1234 void *data,
1235 bool debug __maybe_unused)
1236 {
1237 - uuid_t transition_uuid;
1237 + nd_uuid_t transition_uuid;
1238 char sql[512];
1239 int rc;
1240 sqlite3_stmt *res = NULL;
@@ -1273,7 +1273,7 @@ void sql_alert_transitions(
1273
1274 void *t;
1275 dfe_start_read(nodes, t) {
1276 - uuid_t host_uuid;
1276 + nd_uuid_t host_uuid;
1277 uuid_parse( t_dfe.name, host_uuid);
1278
1279 rc = sqlite3_bind_blob(res, 1, &host_uuid, sizeof(host_uuid), SQLITE_STATIC);
@@ -1323,9 +1323,9 @@ run_query:;
1323
1324 param = 0;
1325 while (sqlite3_step(res) == SQLITE_ROW) {
1326 - atd.host_id = (uuid_t *) sqlite3_column_blob(res, 0);
1326 + atd.host_id = (nd_uuid_t *) sqlite3_column_blob(res, 0);
1327 atd.alarm_id = sqlite3_column_int64(res, 1);
1328 - atd.config_hash_id = (uuid_t *)sqlite3_column_blob(res, 2);
1328 + atd.config_hash_id = (nd_uuid_t *)sqlite3_column_blob(res, 2);
1329 atd.alert_name = (const char *) sqlite3_column_text(res, 3);
1330 atd.chart = (const char *) sqlite3_column_text(res, 4);
1331 atd.chart_name = (const char *) sqlite3_column_text(res, 5);
@@ -1347,7 +1347,7 @@ run_query:;
1347 atd.new_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 21);
1348 atd.old_value = (NETDATA_DOUBLE) sqlite3_column_double(res, 22);
1349 atd.last_repeat = sqlite3_column_int64(res, 23);
1350 - atd.transition_id = (uuid_t *) sqlite3_column_blob(res, 24);
1350 + atd.transition_id = (nd_uuid_t *) sqlite3_column_blob(res, 24);
1351 atd.global_id = sqlite3_column_int64(res, 25);
1352 atd.classification = (const char *) sqlite3_column_text(res, 26);
1353 atd.type = (const char *) sqlite3_column_text(res, 27);
@@ -1413,7 +1413,7 @@ int sql_get_alert_configuration(
1413
1414 void *t;
1415 dfe_start_read(configs, t) {
1416 - uuid_t hash_id;
1416 + nd_uuid_t hash_id;
1417 uuid_parse( t_dfe.name, hash_id);
1418
1419 rc = sqlite3_bind_blob(res, 1, &hash_id, sizeof(hash_id), SQLITE_STATIC);
@@ -1446,7 +1446,7 @@ int sql_get_alert_configuration(
1446 int param;
1447 while (sqlite3_step(res) == SQLITE_ROW) {
1448 param = 0;
1449 - acd.config_hash_id = (uuid_t *) sqlite3_column_blob(res, param++);
1449 + acd.config_hash_id = (nd_uuid_t *) sqlite3_column_blob(res, param++);
1450 acd.name = (const char *) sqlite3_column_text(res, param++);
1451 acd.selectors.on_template = (const char *) sqlite3_column_text(res, param++);
1452 acd.selectors.on_key = (const char *) sqlite3_column_text(res, param++);
src/database/sqlite/sqlite_metadata.c
+48 -52
@@ -224,13 +224,11 @@ int sql_metadata_cache_stats(int op)
224 if (!REQUIRE_DB(db_meta))
225 return 0;
226
227 - netdata_thread_disable_cancelability();
227 sqlite3_db_status(db_meta, op, &count, &dummy, 0);
229 - netdata_thread_enable_cancelability();
228 return count;
229 }
230
233 -static inline void set_host_node_id(RRDHOST *host, uuid_t *node_id)
231 +static inline void set_host_node_id(RRDHOST *host, nd_uuid_t *node_id)
232 {
233 if (unlikely(!host))
234 return;
@@ -244,7 +242,7 @@ static inline void set_host_node_id(RRDHOST *host, uuid_t *node_id)
242 struct aclk_sync_cfg_t *wc = host->aclk_config;
243
244 if (unlikely(!host->node_id)) {
247 - uuid_t *t = mallocz(sizeof(*host->node_id));
245 + nd_uuid_t *t = mallocz(sizeof(*host->node_id));
246 uuid_copy(*t, *node_id);
247 __atomic_store_n(&host->node_id, t, __ATOMIC_RELAXED);
248 }
@@ -260,7 +258,7 @@ static inline void set_host_node_id(RRDHOST *host, uuid_t *node_id)
258
259 #define SQL_UPDATE_NODE_ID "UPDATE node_instance SET node_id = @node_id WHERE host_id = @host_id"
260
263 -int update_node_id(uuid_t *host_id, uuid_t *node_id)
261 +int update_node_id(nd_uuid_t *host_id, nd_uuid_t *node_id)
262 {
263 sqlite3_stmt *res = NULL;
264 RRDHOST *host = NULL;
@@ -272,7 +270,7 @@ int update_node_id(uuid_t *host_id, uuid_t *node_id)
270 host = rrdhost_find_by_guid(host_guid);
271 if (likely(host))
272 set_host_node_id(host, node_id);
275 - rrd_unlock();
273 + rrd_wrunlock();
274
275 if (!REQUIRE_DB(db_meta))
276 return 1;
@@ -298,7 +296,7 @@ done:
296
297 #define SQL_SELECT_NODE_ID "SELECT node_id FROM node_instance WHERE host_id = @host_id AND node_id IS NOT NULL"
298
301 -int get_node_id(uuid_t *host_id, uuid_t *node_id)
299 +int get_node_id(nd_uuid_t *host_id, nd_uuid_t *node_id)
300 {
301 sqlite3_stmt *res = NULL;
302
@@ -314,7 +312,7 @@ int get_node_id(uuid_t *host_id, uuid_t *node_id)
312 param = 0;
313 rc = sqlite3_step_monitored(res);
314 if (likely(rc == SQLITE_ROW && node_id))
317 - uuid_copy(*node_id, *((uuid_t *) sqlite3_column_blob(res, 0)));
315 + uuid_copy(*node_id, *((nd_uuid_t *) sqlite3_column_blob(res, 0)));
316
317 done:
318 REPORT_BIND_FAIL(res, param);
@@ -326,7 +324,7 @@ done:
324 "UPDATE node_instance SET node_id = NULL WHERE EXISTS " \
325 "(SELECT host_id FROM node_instance WHERE host_id = @host_id AND (@claim_id IS NULL OR claim_id <> @claim_id))"
326
329 -void invalidate_node_instances(uuid_t *host_id, uuid_t *claim_id)
327 +void invalidate_node_instances(nd_uuid_t *host_id, nd_uuid_t *claim_id)
328 {
329 sqlite3_stmt *res = NULL;
330
@@ -384,10 +382,10 @@ struct node_instance_list *get_node_list(void)
382 // TODO: Check to remove lock
383 rrd_rdlock();
384 while (sqlite3_step_monitored(res) == SQLITE_ROW) {
387 - if (sqlite3_column_bytes(res, 0) == sizeof(uuid_t))
388 - uuid_copy(node_list[row].node_id, *((uuid_t *)sqlite3_column_blob(res, 0)));
389 - if (sqlite3_column_bytes(res, 1) == sizeof(uuid_t)) {
390 - uuid_t *host_id = (uuid_t *)sqlite3_column_blob(res, 1);
385 + if (sqlite3_column_bytes(res, 0) == sizeof(nd_uuid_t))
386 + uuid_copy(node_list[row].node_id, *((nd_uuid_t *)sqlite3_column_blob(res, 0)));
387 + if (sqlite3_column_bytes(res, 1) == sizeof(nd_uuid_t)) {
388 + nd_uuid_t *host_id = (nd_uuid_t *)sqlite3_column_blob(res, 1);
389 uuid_unparse_lower(*host_id, host_guid);
390 RRDHOST *host = rrdhost_find_by_guid(host_guid);
391 if (!host)
@@ -404,7 +402,7 @@ struct node_instance_list *get_node_list(void)
402 node_list[row].live =
403 (host == localhost || host->receiver || !(rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN))) ? 1 : 0;
404 node_list[row].hops = host->system_info ? host->system_info->hops :
407 - uuid_memcmp(host_id, &localhost->host_uuid) ? 1 : 0;
405 + uuid_eq(*host_id, localhost->host_uuid) ? 0 : 1;
406 node_list[row].hostname =
407 sqlite3_column_bytes(res, 2) ? strdupz((char *)sqlite3_column_text(res, 2)) : NULL;
408 }
@@ -412,7 +410,7 @@ struct node_instance_list *get_node_list(void)
410 if (row == max_rows)
411 break;
412 }
415 - rrd_unlock();
413 + rrd_rdunlock();
414
415 failed:
416 SQLITE_FINALIZE(res);
@@ -438,8 +436,8 @@ void sql_load_node_id(RRDHOST *host)
436 param = 0;
437 int rc = sqlite3_step_monitored(res);
438 if (likely(rc == SQLITE_ROW)) {
441 - if (likely(sqlite3_column_bytes(res, 0) == sizeof(uuid_t)))
442 - set_host_node_id(host, (uuid_t *)sqlite3_column_blob(res, 0));
439 + if (likely(sqlite3_column_bytes(res, 0) == sizeof(nd_uuid_t)))
440 + set_host_node_id(host, (nd_uuid_t *)sqlite3_column_blob(res, 0));
441 else
442 set_host_node_id(host, NULL);
443 }
@@ -451,7 +449,7 @@ done:
449
450 #define SELECT_HOST_INFO "SELECT system_key, system_value FROM host_info WHERE host_id = @host_id"
451
454 -void sql_build_host_system_info(uuid_t *host_id, struct rrdhost_system_info *system_info)
452 +void sql_build_host_system_info(nd_uuid_t *host_id, struct rrdhost_system_info *system_info)
453 {
454 sqlite3_stmt *res = NULL;
455
@@ -475,7 +473,7 @@ done:
473 #define SELECT_HOST_LABELS "SELECT label_key, label_value, source_type FROM host_label WHERE host_id = @host_id " \
474 "AND label_key IS NOT NULL AND label_value IS NOT NULL"
475
478 -RRDLABELS *sql_load_host_labels(uuid_t *host_id)
476 +RRDLABELS *sql_load_host_labels(nd_uuid_t *host_id)
477 {
478 RRDLABELS *labels = NULL;
479 sqlite3_stmt *res = NULL;
@@ -503,7 +501,7 @@ done:
501 return labels;
502 }
503
506 -static int exec_statement_with_uuid(const char *sql, uuid_t *uuid)
504 +static int exec_statement_with_uuid(const char *sql, nd_uuid_t *uuid)
505 {
506 int result = 1;
507 sqlite3_stmt *res = NULL;
@@ -573,7 +571,7 @@ static void recover_database(const char *sqlite_database, const char *new_sqlite
571
572 static void sqlite_uuid_parse(sqlite3_context *context, int argc, sqlite3_value **argv)
573 {
576 - uuid_t uuid;
574 + nd_uuid_t uuid;
575
576 if ( argc != 1 ){
577 sqlite3_result_null(context);
@@ -585,7 +583,7 @@ static void sqlite_uuid_parse(sqlite3_context *context, int argc, sqlite3_value
583 return ;
584 }
585
588 - sqlite3_result_blob(context, &uuid, sizeof(uuid_t), SQLITE_TRANSIENT);
586 + sqlite3_result_blob(context, &uuid, sizeof(nd_uuid_t), SQLITE_TRANSIENT);
587 }
588
589 void sqlite_now_usec(sqlite3_context *context, int argc, sqlite3_value **argv)
@@ -608,9 +606,9 @@ void sqlite_uuid_random(sqlite3_context *context, int argc, sqlite3_value **argv
606 (void)argc;
607 (void)argv;
608
611 - uuid_t uuid;
609 + nd_uuid_t uuid;
610 uuid_generate_random(uuid);
613 - sqlite3_result_blob(context, &uuid, sizeof(uuid_t), SQLITE_TRANSIENT);
611 + sqlite3_result_blob(context, &uuid, sizeof(nd_uuid_t), SQLITE_TRANSIENT);
612 }
613
614 // Init
@@ -726,7 +724,7 @@ struct query_build {
724 #define SQL_DELETE_CHART_LABELS_BY_HOST \
725 "DELETE FROM chart_label WHERE chart_id in (SELECT chart_id FROM chart WHERE host_id = @host_id)"
726
729 -static void delete_host_chart_labels(uuid_t *host_uuid)
727 +static void delete_host_chart_labels(nd_uuid_t *host_uuid)
728 {
729 sqlite3_stmt *res = NULL;
730
@@ -809,7 +807,7 @@ static int check_and_update_chart_labels(RRDSET *st, BUFFER *work_buffer, size_t
807 }
808
809 // If the machine guid has changed, then existing one with hops 0 will be marked as hops 1 (child)
812 -void detect_machine_guid_change(uuid_t *host_uuid)
810 +void detect_machine_guid_change(nd_uuid_t *host_uuid)
811 {
812 int rc;
813
@@ -820,7 +818,7 @@ void detect_machine_guid_change(uuid_t *host_uuid)
818 }
819 }
820
823 -static int store_claim_id(uuid_t *host_id, uuid_t *claim_id)
821 +static int store_claim_id(nd_uuid_t *host_id, nd_uuid_t *claim_id)
822 {
823 sqlite3_stmt *res = NULL;
824 int rc = 0;
@@ -850,7 +848,7 @@ done:
848 return rc != SQLITE_DONE;
849 }
850
853 -static void delete_dimension_uuid(uuid_t *dimension_uuid, sqlite3_stmt **action_res __maybe_unused, bool flag __maybe_unused)
851 +static void delete_dimension_uuid(nd_uuid_t *dimension_uuid, sqlite3_stmt **action_res __maybe_unused, bool flag __maybe_unused)
852 {
853 static __thread sqlite3_stmt *res = NULL;
854 int rc;
@@ -913,7 +911,7 @@ bind_fail:
911 return 1;
912 }
913
916 -static int add_host_sysinfo_key_value(const char *name, const char *value, uuid_t *uuid)
914 +static int add_host_sysinfo_key_value(const char *name, const char *value, nd_uuid_t *uuid)
915 {
916 static __thread sqlite3_stmt *res = NULL;
917
@@ -1065,7 +1063,7 @@ bind_fail:
1063 return 1;
1064 }
1065
1068 -static bool dimension_can_be_deleted(uuid_t *dim_uuid __maybe_unused, sqlite3_stmt **res __maybe_unused, bool flag __maybe_unused)
1066 +static bool dimension_can_be_deleted(nd_uuid_t *dim_uuid __maybe_unused, sqlite3_stmt **res __maybe_unused, bool flag __maybe_unused)
1067 {
1068 #ifdef ENABLE_DBENGINE
1069 if(dbengine_enabled) {
@@ -1093,8 +1091,8 @@ static bool dimension_can_be_deleted(uuid_t *dim_uuid __maybe_unused, sqlite3_st
1091 static bool run_cleanup_loop(
1092 sqlite3_stmt *res,
1093 struct metadata_wc *wc,
1096 - bool (*check_cb)(uuid_t *, sqlite3_stmt **, bool),
1097 - void (*action_cb)(uuid_t *, sqlite3_stmt **, bool),
1094 + bool (*check_cb)(nd_uuid_t *, sqlite3_stmt **, bool),
1095 + void (*action_cb)(nd_uuid_t *, sqlite3_stmt **, bool),
1096 uint32_t *total_checked,
1097 uint32_t *total_deleted,
1098 uint64_t *row_id,
@@ -1118,10 +1116,10 @@ static bool run_cleanup_loop(
1116 break;
1117
1118 *row_id = sqlite3_column_int64(res, 1);
1121 - rc = check_cb((uuid_t *)sqlite3_column_blob(res, 0), check_stmt, check_flag);
1119 + rc = check_cb((nd_uuid_t *)sqlite3_column_blob(res, 0), check_stmt, check_flag);
1120
1121 if (rc == true) {
1124 - action_cb((uuid_t *)sqlite3_column_blob(res, 0), action_stmt, action_flag);
1122 + action_cb((nd_uuid_t *)sqlite3_column_blob(res, 0), action_stmt, action_flag);
1123 (*total_deleted)++;
1124 }
1125
@@ -1135,7 +1133,7 @@ static bool run_cleanup_loop(
1133 #define SQL_CHECK_CHART_EXISTENCE_IN_DIMENSION "SELECT count(1) FROM dimension WHERE chart_id = @chart_id"
1134 #define SQL_CHECK_CHART_EXISTENCE_IN_CHART "SELECT count(1) FROM chart WHERE chart_id = @chart_id"
1135
1138 -static bool chart_can_be_deleted(uuid_t *chart_uuid, sqlite3_stmt **check_res, bool check_in_dimension)
1136 +static bool chart_can_be_deleted(nd_uuid_t *chart_uuid, sqlite3_stmt **check_res, bool check_in_dimension)
1137 {
1138 int rc, result = 1;
1139 sqlite3_stmt *res = check_res ? *check_res : NULL;
@@ -1173,7 +1171,7 @@ skip:
1171 #define SQL_DELETE_CHART_BY_UUID "DELETE FROM chart WHERE chart_id = @chart_id"
1172 #define SQL_DELETE_CHART_LABEL_BY_UUID "DELETE FROM chart_label WHERE chart_id = @chart_id"
1173
1176 -static void delete_chart_uuid(uuid_t *chart_uuid, sqlite3_stmt **action_res, bool label_only)
1174 +static void delete_chart_uuid(nd_uuid_t *chart_uuid, sqlite3_stmt **action_res, bool label_only)
1175 {
1176 int rc;
1177 sqlite3_stmt *res = action_res ? *action_res : NULL;
@@ -1812,7 +1810,7 @@ static void do_chart_label_cleanup(struct host_chart_label_cleanup *cl_cleanup_d
1810
1811 RRDHOST *host = rrdhost_find_by_guid(machine_guid);
1812 if (likely(!host)) {
1815 - uuid_t host_uuid;
1813 + nd_uuid_t host_uuid;
1814 if (!uuid_parse(machine_guid, host_uuid))
1815 delete_host_chart_labels(&host_uuid);
1816 }
@@ -1883,7 +1881,7 @@ static void start_metadata_hosts(uv_work_t *req __maybe_unused)
1881
1882 if (unlikely(rrdhost_flag_check(host, RRDHOST_FLAG_METADATA_CLAIMID))) {
1883 rrdhost_flag_clear(host, RRDHOST_FLAG_METADATA_CLAIMID);
1886 - uuid_t uuid;
1884 + nd_uuid_t uuid;
1885 int rc;
1886 if (likely(host->aclk_state.claimed_id && !uuid_parse(host->aclk_state.claimed_id, uuid)))
1887 rc = store_claim_id(&host->host_uuid, &uuid);
@@ -1952,7 +1950,7 @@ static void metadata_event_loop(void *arg)
1950 struct metadata_wc *wc = arg;
1951 enum metadata_opcode opcode;
1952
1955 - uv_thread_set_name_np(wc->thread, "METASYNC");
1953 + uv_thread_set_name_np("METASYNC");
1954 loop = wc->loop = mallocz(sizeof(uv_loop_t));
1955 ret = uv_loop_init(loop);
1956 if (ret) {
@@ -1991,7 +1989,7 @@ static void metadata_event_loop(void *arg)
1989 struct host_chart_label_cleanup *cl_cleanup_data = NULL;
1990
1991 while (shutdown == 0 || (wc->flags & METADATA_FLAG_PROCESSING)) {
1994 - uuid_t *uuid;
1992 + nd_uuid_t *uuid;
1993 RRDHOST *host = NULL;
1994
1995 worker_is_idle();
@@ -2021,13 +2019,13 @@ static void metadata_event_loop(void *arg)
2019 case METADATA_DATABASE_TIMER:
2020 break;
2021 case METADATA_DEL_DIMENSION:
2024 - uuid = (uuid_t *) cmd.param[0];
2022 + uuid = (nd_uuid_t *) cmd.param[0];
2023 if (likely(dimension_can_be_deleted(uuid, NULL, false)))
2024 delete_dimension_uuid(uuid, NULL, false);
2025 freez(uuid);
2026 break;
2027 case METADATA_STORE_CLAIM_ID:
2030 - store_claim_id((uuid_t *) cmd.param[0], (uuid_t *) cmd.param[1]);
2028 + store_claim_id((nd_uuid_t *) cmd.param[0], (nd_uuid_t *) cmd.param[1]);
2029 freez((void *) cmd.param[0]);
2030 freez((void *) cmd.param[1]);
2031 break;
@@ -2217,22 +2215,22 @@ static inline void queue_metadata_cmd(enum metadata_opcode opcode, const void *p
2215 }
2216
2217 // Public
2220 -void metaqueue_delete_dimension_uuid(uuid_t *uuid)
2218 +void metaqueue_delete_dimension_uuid(nd_uuid_t *uuid)
2219 {
2220 if (unlikely(!metasync_worker.loop))
2221 return;
2224 - uuid_t *use_uuid = mallocz(sizeof(*uuid));
2222 + nd_uuid_t *use_uuid = mallocz(sizeof(*uuid));
2223 uuid_copy(*use_uuid, *uuid);
2224 queue_metadata_cmd(METADATA_DEL_DIMENSION, use_uuid, NULL);
2225 }
2226
2229 -void metaqueue_store_claim_id(uuid_t *host_uuid, uuid_t *claim_uuid)
2227 +void metaqueue_store_claim_id(nd_uuid_t *host_uuid, nd_uuid_t *claim_uuid)
2228 {
2229 if (unlikely(!host_uuid))
2230 return;
2231
2234 - uuid_t *local_host_uuid = mallocz(sizeof(*host_uuid));
2235 - uuid_t *local_claim_uuid = NULL;
2232 + nd_uuid_t *local_host_uuid = mallocz(sizeof(*host_uuid));
2233 + nd_uuid_t *local_claim_uuid = NULL;
2234
2235 uuid_copy(*local_host_uuid, *host_uuid);
2236 if (likely(claim_uuid)) {
@@ -2318,13 +2316,12 @@ static void *metadata_unittest_threads(void)
2316 threads_to_create,
2317 (long long)seconds_to_run);
2318
2321 - netdata_thread_t threads[threads_to_create];
2319 + ND_THREAD *threads[threads_to_create];
2320 tu.join = 0;
2321 for (int i = 0; i < threads_to_create; i++) {
2322 char buf[100 + 1];
2323 snprintf(buf, sizeof(buf) - 1, "META[%d]", i);
2326 - netdata_thread_create(
2327 - &threads[i],
2324 + threads[i] = nd_thread_create(
2325 buf,
2326 NETDATA_THREAD_OPTION_DONT_LOG | NETDATA_THREAD_OPTION_JOINABLE,
2327 unittest_queue_metadata,
@@ -2335,8 +2332,7 @@ static void *metadata_unittest_threads(void)
2332
2333 __atomic_store_n(&tu.join, 1, __ATOMIC_RELAXED);
2334 for (int i = 0; i < threads_to_create; i++) {
2338 - void *retval;
2339 - netdata_thread_join(threads[i], &retval);
2335 + nd_thread_join(threads[i]);
2336 }
2337 sleep_usec(5 * USEC_PER_SEC);
2338
src/database/sqlite/sqlite_metadata.h
+10 -10
@@ -8,8 +8,8 @@
8
9 // return a node list
10 struct node_instance_list {
11 - uuid_t node_id;
12 - uuid_t host_id;
11 + nd_uuid_t node_id;
12 + nd_uuid_t host_id;
13 char *hostname;
14 int live;
15 int queryable;
@@ -29,26 +29,26 @@ void metadata_sync_init(void);
29 void metadata_sync_shutdown(void);
30 void metadata_sync_shutdown_prepare(void);
31
32 -void metaqueue_delete_dimension_uuid(uuid_t *uuid);
33 -void metaqueue_store_claim_id(uuid_t *host_uuid, uuid_t *claim_uuid);
32 +void metaqueue_delete_dimension_uuid(nd_uuid_t *uuid);
33 +void metaqueue_store_claim_id(nd_uuid_t *host_uuid, nd_uuid_t *claim_uuid);
34 void metaqueue_host_update_info(RRDHOST *host);
35 void metaqueue_ml_load_models(RRDDIM *rd);
36 -void detect_machine_guid_change(uuid_t *host_uuid);
36 +void detect_machine_guid_change(nd_uuid_t *host_uuid);
37 void metadata_queue_load_host_context(RRDHOST *host);
38 void metadata_delete_host_chart_labels(char *machine_guid);
39 void vacuum_database(sqlite3 *database, const char *db_alias, int threshold, int vacuum_pc);
40
41 int sql_metadata_cache_stats(int op);
42
43 -int get_node_id(uuid_t *host_id, uuid_t *node_id);
44 -int update_node_id(uuid_t *host_id, uuid_t *node_id);
43 +int get_node_id(nd_uuid_t *host_id, nd_uuid_t *node_id);
44 +int update_node_id(nd_uuid_t *host_id, nd_uuid_t *node_id);
45 struct node_instance_list *get_node_list(void);
46 void sql_load_node_id(RRDHOST *host);
47
48 // Help build archived hosts in memory when agent starts
49 -void sql_build_host_system_info(uuid_t *host_id, struct rrdhost_system_info *system_info);
50 -void invalidate_node_instances(uuid_t *host_id, uuid_t *claim_id);
51 -RRDLABELS *sql_load_host_labels(uuid_t *host_id);
49 +void sql_build_host_system_info(nd_uuid_t *host_id, struct rrdhost_system_info *system_info);
50 +void invalidate_node_instances(nd_uuid_t *host_id, nd_uuid_t *claim_id);
51 +RRDLABELS *sql_load_host_labels(nd_uuid_t *host_id);
52
53 uint64_t sqlite_get_meta_space(void);
54 int sql_init_meta_database(db_check_action_type_t rebuild, int memory);
src/exporting/aws_kinesis/aws_kinesis.c
+4
@@ -100,6 +100,10 @@ void aws_kinesis_connector_worker(void *instance_p)
100 struct aws_kinesis_specific_config *connector_specific_config = instance->config.connector_specific_config;
101 struct aws_kinesis_specific_data *connector_specific_data = instance->connector_specific_data;
102
103 + char threadname[ND_THREAD_TAG_MAX + 1];
104 + snprintfz(threadname, ND_THREAD_TAG_MAX, "EXPKNSS[%zu]", instance->index);
105 + uv_thread_set_name_np(threadname);
106 +
107 while (!instance->engine->exit) {
108 unsigned long long partition_key_seq = 0;
109 struct stats *stats = &instance->stats;
src/exporting/exporting_engine.c
+5 -4
@@ -119,9 +119,11 @@ static void exporting_clean_engine()
119 *
120 * @param ptr thread data.
121 */
122 -static void exporting_main_cleanup(void *ptr)
122 +static void exporting_main_cleanup(void *pptr)
123 {
124 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
124 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
125 + if(!static_thread) return;
126 +
127 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
128
129 netdata_log_info("cleaning up...");
@@ -174,7 +176,7 @@ static void exporting_main_cleanup(void *ptr)
176 */
177 void *exporting_main(void *ptr)
178 {
177 - netdata_thread_cleanup_push(exporting_main_cleanup, ptr);
179 + CLEANUP_FUNCTION_REGISTER(exporting_main_cleanup) cleanup_ptr = ptr;
180
181 engine = read_exporting_config();
182 if (!engine) {
@@ -214,6 +216,5 @@ void *exporting_main(void *ptr)
216 }
217
218 cleanup:
217 - netdata_thread_cleanup_pop(1);
219 return NULL;
220 }
src/exporting/graphite/graphite.c
+1 -1
@@ -74,7 +74,7 @@ int init_graphite_instance(struct instance *instance)
74 void sanitize_graphite_label_value(char *dst, const char *src, size_t len)
75 {
76 while (*src != '\0' && len) {
77 - if (isspace(*src) || *src == ';' || *src == '~')
77 + if (isspace((uint8_t)*src) || *src == ';' || *src == '~')
78 *dst++ = '_';
79 else
80 *dst++ = *src;
src/exporting/init_connectors.c
-3
@@ -95,9 +95,6 @@ int init_connectors(struct engine *engine)
95 netdata_log_error("EXPORTING: cannot create thread worker. uv_thread_create(): %s", uv_strerror(error));
96 return 1;
97 }
98 - char threadname[NETDATA_THREAD_NAME_MAX + 1];
99 - snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "EXPORTING-%zu", instance->index);
100 - uv_thread_set_name_np(instance->thread, threadname);
98
99 analytics_statistic_t statistic = { "EXPORTING_START", "OK", instance->config.type_name };
100 analytics_statistic_send(&statistic);
src/exporting/mongodb/mongodb.c
+4
@@ -285,6 +285,10 @@ void mongodb_connector_worker(void *instance_p)
285 struct mongodb_specific_data *connector_specific_data =
286 (struct mongodb_specific_data *)instance->connector_specific_data;
287
288 + char threadname[ND_THREAD_TAG_MAX + 1];
289 + snprintfz(threadname, ND_THREAD_TAG_MAX, "EXPMNG[%zu]", instance->index);
290 + uv_thread_set_name_np(threadname);
291 +
292 while (!instance->engine->exit) {
293 struct stats *stats = &instance->stats;
294
src/exporting/opentsdb/opentsdb.c
+1 -1
@@ -127,7 +127,7 @@ int init_opentsdb_http_instance(struct instance *instance)
127 void sanitize_opentsdb_label_value(char *dst, const char *src, size_t len)
128 {
129 while (*src != '\0' && len) {
130 - if (isalpha(*src) || isdigit(*src) || *src == '-' || *src == '.' || *src == '/' || IS_UTF8_BYTE(*src))
130 + if (isalpha((uint8_t)*src) || isdigit((uint8_t)*src) || *src == '-' || *src == '.' || *src == '/' || IS_UTF8_BYTE(*src))
131 *dst++ = *src;
132 else
133 *dst++ = '_';
src/exporting/process_data.c
+1 -3
@@ -336,7 +336,6 @@ void end_batch_formatting(struct engine *engine)
336 */
337 void prepare_buffers(struct engine *engine)
338 {
339 - netdata_thread_disable_cancelability();
339 start_batch_formatting(engine);
340
341 rrd_rdlock();
@@ -358,8 +357,7 @@ void prepare_buffers(struct engine *engine)
357 variables_formatting(engine, host);
358 end_host_formatting(engine, host);
359 }
361 - rrd_unlock();
362 - netdata_thread_enable_cancelability();
360 + rrd_rdunlock();
361
362 end_batch_formatting(engine);
363 }
src/exporting/prometheus/prometheus.c
+3 -3
@@ -552,8 +552,8 @@ static void prometheus_print_os_info(
552 if (!in_val_part) {
553 /* Only accepts alphabetic characters and '_'
554 * in key part */
555 - if (isalpha(*in) || *in == '_') {
556 - *(sanitized++) = tolower(*in);
555 + if (isalpha((uint8_t)*in) || *in == '_') {
556 + *(sanitized++) = tolower((uint8_t)*in);
557 } else if (*in == '=') {
558 in_val_part = 1;
559 *(sanitized++) = '=';
@@ -568,7 +568,7 @@ static void prometheus_print_os_info(
568 case '\t':
569 break;
570 default:
571 - if (isprint(*in)) {
571 + if (isprint((uint8_t)*in)) {
572 *(sanitized++) = *in;
573 }
574 }
src/exporting/pubsub/pubsub.c
+4
@@ -99,6 +99,10 @@ void pubsub_connector_worker(void *instance_p)
99 struct pubsub_specific_config *connector_specific_config = instance->config.connector_specific_config;
100 struct pubsub_specific_data *connector_specific_data = instance->connector_specific_data;
101
102 + char threadname[ND_THREAD_TAG_MAX + 1];
103 + snprintfz(threadname, ND_THREAD_TAG_MAX, "EXPPBSB[%zu]", instance->index);
104 + uv_thread_set_name_np(threadname);
105 +
106 while (!instance->engine->exit) {
107 struct stats *stats = &instance->stats;
108 char error_message[ERROR_LINE_MAX + 1] = "";
src/exporting/send_data.c
+4
@@ -217,6 +217,10 @@ void simple_connector_worker(void *instance_p)
217 struct instance *instance = (struct instance*)instance_p;
218 struct simple_connector_data *connector_specific_data = instance->connector_specific_data;
219
220 + char threadname[ND_THREAD_TAG_MAX + 1];
221 + snprintfz(threadname, ND_THREAD_TAG_MAX, "EXPSMPL[%zu]", instance->index);
222 + uv_thread_set_name_np(threadname);
223 +
224 #ifdef ENABLE_HTTPS
225 uint32_t options = (uint32_t)instance->config.options;
226
src/health/health.h
+1 -1
@@ -89,7 +89,7 @@ void health_string2json(BUFFER *wb, const char *prefix, const char *label, const
89
90 void health_log_alert_transition_with_trace(RRDHOST *host, ALARM_ENTRY *ae, int line, const char *file, const char *function);
91 #define health_log_alert(host, ae) health_log_alert_transition_with_trace(host, ae, __LINE__, __FILE__, __FUNCTION__)
92 -bool health_alarm_log_get_global_id_and_transition_id_for_rrdcalc(RRDCALC *rc, usec_t *global_id, uuid_t *transitions_id);
92 +bool health_alarm_log_get_global_id_and_transition_id_for_rrdcalc(RRDCALC *rc, usec_t *global_id, nd_uuid_t *transitions_id);
93
94 int alert_variable_lookup_trace(RRDHOST *host, RRDSET *st, const char *variable, BUFFER *wb);
95
src/health/health_config.c
+23 -23
@@ -19,14 +19,14 @@ static inline int health_parse_delay(
19 while(*s) {
20 char *key = s;
21
22 - while(*s && !isspace(*s)) s++;
23 - while(*s && isspace(*s)) *s++ = '\0';
22 + while(*s && !isspace((uint8_t)*s)) s++;
23 + while(*s && isspace((uint8_t)*s)) *s++ = '\0';
24
25 if(!*key) break;
26
27 char *value = s;
28 - while(*s && !isspace(*s)) s++;
29 - while(*s && isspace(*s)) *s++ = '\0';
28 + while(*s && !isspace((uint8_t)*s)) s++;
29 + while(*s && isspace((uint8_t)*s)) *s++ = '\0';
30
31 if(!strcasecmp(key, "up")) {
32 if (!config_parse_duration(value, delay_up_duration)) {
@@ -91,12 +91,12 @@ static inline ALERT_ACTION_OPTIONS health_parse_options(const char *s) {
91 buf[0] = '\0';
92
93 // skip spaces
94 - while(*s && isspace(*s))
94 + while(*s && isspace((uint8_t)*s))
95 s++;
96
97 // find the next space
98 size_t count = 0;
99 - while(*s && count < 100 && !isspace(*s))
99 + while(*s && count < 100 && !isspace((uint8_t)*s))
100 buf[count++] = *s++;
101
102 if(buf[0]) {
@@ -124,14 +124,14 @@ static inline int health_parse_repeat(
124 while(*s) {
125 char *key = s;
126
127 - while(*s && !isspace(*s)) s++;
128 - while(*s && isspace(*s)) *s++ = '\0';
127 + while(*s && !isspace((uint8_t)*s)) s++;
128 + while(*s && isspace((uint8_t)*s)) *s++ = '\0';
129
130 if(!*key) break;
131
132 char *value = s;
133 - while(*s && !isspace(*s)) s++;
134 - while(*s && isspace(*s)) *s++ = '\0';
133 + while(*s && !isspace((uint8_t)*s)) s++;
134 + while(*s && isspace((uint8_t)*s)) *s++ = '\0';
135
136 if(!strcasecmp(key, "off")) {
137 *warn_repeat_every = 0;
@@ -176,8 +176,8 @@ static inline int health_parse_db_lookup(size_t line, const char *filename, char
176
177 // first is the group method
178 key = s;
179 - while(*s && !isspace(*s) && *s != '(') s++;
180 - while(*s && isspace(*s)) *s++ = '\0';
179 + while(*s && !isspace((uint8_t)*s) && *s != '(') s++;
180 + while(*s && isspace((uint8_t)*s)) *s++ = '\0';
181 if(!*s) {
182 netdata_log_error("Health configuration invalid chart calculation at line %zu of file '%s': expected group method followed by the 'after' time, but got '%s'",
183 line, filename, key);
@@ -224,12 +224,12 @@ static inline int health_parse_db_lookup(size_t line, const char *filename, char
224 ac->time_group_condition = ALERT_LOOKUP_TIME_GROUP_CONDITION_LESS;
225 }
226
227 - while(*s && isspace(*s)) s++;
227 + while(*s && isspace((uint8_t)*s)) s++;
228
229 if(*s) {
230 - if(isdigit(*s) || *s == '.') {
230 + if(isdigit((uint8_t)*s) || *s == '.') {
231 ac->time_group_value = str2ndd(s, &s);
232 - while(s && *s && isspace(*s)) s++;
232 + while(s && *s && isspace((uint8_t)*s)) s++;
233
234 if(!s || *s != ')') {
235 netdata_log_error("Health configuration at line %zu of file '%s': missing closing parenthesis after number in aggregation method on '%s'",
@@ -270,8 +270,8 @@ static inline int health_parse_db_lookup(size_t line, const char *filename, char
270
271 // then is the 'after' time
272 key = s;
273 - while(*s && !isspace(*s)) s++;
274 - while(*s && isspace(*s)) *s++ = '\0';
273 + while(*s && !isspace((uint8_t)*s)) s++;
274 + while(*s && isspace((uint8_t)*s)) *s++ = '\0';
275
276 if(!config_parse_duration(key, &ac->after)) {
277 netdata_log_error("Health configuration at line %zu of file '%s': invalid duration '%s' after group method",
@@ -285,14 +285,14 @@ static inline int health_parse_db_lookup(size_t line, const char *filename, char
285 // now we may have optional parameters
286 while(*s) {
287 key = s;
288 - while(*s && !isspace(*s)) s++;
289 - while(*s && isspace(*s)) *s++ = '\0';
288 + while(*s && !isspace((uint8_t)*s)) s++;
289 + while(*s && isspace((uint8_t)*s)) *s++ = '\0';
290 if(!*key) break;
291
292 if(!strcasecmp(key, "at")) {
293 char *value = s;
294 - while(*s && !isspace(*s)) s++;
295 - while(*s && isspace(*s)) *s++ = '\0';
294 + while(*s && !isspace((uint8_t)*s)) s++;
295 + while(*s && isspace((uint8_t)*s)) *s++ = '\0';
296
297 if (!config_parse_duration(value, &ac->before)) {
298 netdata_log_error("Health configuration at line %zu of file '%s': invalid duration '%s' for '%s' keyword",
@@ -301,8 +301,8 @@ static inline int health_parse_db_lookup(size_t line, const char *filename, char
301 }
302 else if(!strcasecmp(key, HEALTH_EVERY_KEY)) {
303 char *value = s;
304 - while(*s && !isspace(*s)) s++;
305 - while(*s && isspace(*s)) *s++ = '\0';
304 + while(*s && !isspace((uint8_t)*s)) s++;
305 + while(*s && isspace((uint8_t)*s)) *s++ = '\0';
306
307 if (!config_parse_duration(value, &ac->update_every)) {
308 netdata_log_error("Health configuration at line %zu of file '%s': invalid duration '%s' for '%s' keyword",
src/health/health_event_loop.c
+7 -10
@@ -740,16 +740,16 @@ static void health_event_loop(void) {
740 }
741
742
743 -static void health_main_cleanup(void *ptr) {
744 - worker_unregister();
743 +static void health_main_cleanup(void *pptr) {
744 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
745 + if(!static_thread) return;
746
746 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
747 + worker_unregister();
748 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
749 netdata_log_info("cleaning up...");
750 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
751
751 - nd_log(NDLS_DAEMON, NDLP_DEBUG,
752 - "Health thread ended.");
752 + nd_log(NDLS_DAEMON, NDLP_DEBUG, "Health thread ended.");
753 }
754
755 void *health_main(void *ptr) {
@@ -765,10 +765,7 @@ void *health_main(void *ptr) {
765 worker_register_job_name(WORKER_HEALTH_JOB_DELAYED_INIT_RRDSET, "rrdset init");
766 worker_register_job_name(WORKER_HEALTH_JOB_DELAYED_INIT_RRDDIM, "rrddim init");
767
768 - netdata_thread_cleanup_push(health_main_cleanup, ptr);
769 - {
770 - health_event_loop();
771 - }
772 - netdata_thread_cleanup_pop(1);
768 + CLEANUP_FUNCTION_REGISTER(health_main_cleanup) cleanup_ptr = ptr;
769 + health_event_loop();
770 return NULL;
771 }
src/health/health_notifications.c
+2 -2
@@ -108,7 +108,7 @@ static bool prepare_command(BUFFER *wb,
108 const char *classification,
109 const char *edit_command,
110 const char *machine_guid,
111 - uuid_t *transition_id,
111 + nd_uuid_t *transition_id,
112 const char *summary,
113 const char *context,
114 const char *component,
@@ -479,7 +479,7 @@ done:
479 health_alarm_log_save(host, ae);
480 }
481
482 -bool health_alarm_log_get_global_id_and_transition_id_for_rrdcalc(RRDCALC *rc, usec_t *global_id, uuid_t *transitions_id) {
482 +bool health_alarm_log_get_global_id_and_transition_id_for_rrdcalc(RRDCALC *rc, usec_t *global_id, nd_uuid_t *transitions_id) {
483 if(!rc->rrdset)
484 return false;
485
src/health/health_prototypes.c
+1 -1
@@ -374,7 +374,7 @@ static void health_prototype_activate_match_patterns(struct rrd_alert_match *am)
374 void health_prototype_hash_id(RRD_ALERT_PROTOTYPE *ap) {
375 CLEAN_BUFFER *wb = buffer_create(100, NULL);
376 health_prototype_to_json(wb, ap, true);
377 - UUID uuid = UUID_generate_from_hash(buffer_tostring(wb), buffer_strlen(wb));
377 + ND_UUID uuid = UUID_generate_from_hash(buffer_tostring(wb), buffer_strlen(wb));
378 uuid_copy(ap->config.hash_id, uuid.uuid);
379
380 sql_alert_store_config(ap);
src/health/health_prototypes.h
+1 -1
@@ -57,7 +57,7 @@ struct rrd_alert_match {
57 void rrd_alert_match_cleanup(struct rrd_alert_match *am);
58
59 struct rrd_alert_config {
60 - uuid_t hash_id;
60 + nd_uuid_t hash_id;
61
62 STRING *name; // the name of this alarm
63
src/health/rrdcalc.c
+2 -2
@@ -60,13 +60,13 @@ inline const char *rrdcalc_status2string(RRDCALC_STATUS status) {
60 }
61 }
62
63 -uint32_t rrdcalc_get_unique_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id, uuid_t *config_hash_id) {
63 +uint32_t rrdcalc_get_unique_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id, nd_uuid_t *config_hash_id) {
64 rw_spinlock_read_lock(&host->health_log.spinlock);
65
66 // re-use old IDs, by looking them up in the alarm log
67 ALARM_ENTRY *ae = NULL;
68 for(ae = host->health_log.alarms; ae ;ae = ae->next) {
69 - if(unlikely(name == ae->name && chart == ae->chart && !uuid_memcmp(&ae->config_hash_id, config_hash_id))) {
69 + if(unlikely(name == ae->name && chart == ae->chart && uuid_eq(ae->config_hash_id, *config_hash_id))) {
70 if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
71 break;
72 }
src/health/rrdcalc.h
+1 -1
@@ -121,7 +121,7 @@ RRDCALC *rrdcalc_acquired_to_rrdcalc(const RRDCALC_ACQUIRED *rca);
121
122 const char *rrdcalc_status2string(RRDCALC_STATUS status);
123
124 -uint32_t rrdcalc_get_unique_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id, uuid_t *config_hash_id);
124 +uint32_t rrdcalc_get_unique_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id, nd_uuid_t *config_hash_id);
125
126 static inline int rrdcalc_isrepeating(RRDCALC *rc) {
127 if (unlikely(rc->config.warn_repeat_every > 0 || rc->config.crit_repeat_every > 0)) {
src/health/rrdvar.c
+1 -1
@@ -12,7 +12,7 @@ typedef struct rrdvar {
12 inline int rrdvar_fix_name(char *variable) {
13 int fixed = 0;
14 while(*variable) {
15 - if (!isalnum(*variable) && *variable != '.' && *variable != '_') {
15 + if (!isalnum((uint8_t)*variable) && *variable != '.' && *variable != '_') {
16 *variable++ = '_';
17 fixed++;
18 }
src/libnetdata/aral/aral.c
+10 -8
@@ -1018,14 +1018,16 @@ int aral_stress_test(size_t threads, size_t elements, size_t seconds) {
1018 };
1019
1020 usec_t started_ut = now_monotonic_usec();
1021 - netdata_thread_t thread_ptrs[threads];
1021 + ND_THREAD *thread_ptrs[threads];
1022
1023 for(size_t i = 0; i < threads ; i++) {
1024 - char tag[NETDATA_THREAD_NAME_MAX + 1];
1025 - snprintfz(tag, NETDATA_THREAD_NAME_MAX, "TH[%zu]", i);
1026 - netdata_thread_create(&thread_ptrs[i], tag,
1027 - NETDATA_THREAD_OPTION_JOINABLE | NETDATA_THREAD_OPTION_DONT_LOG,
1028 - aral_test_thread, &auc);
1024 + char tag[ND_THREAD_TAG_MAX + 1];
1025 + snprintfz(tag, ND_THREAD_TAG_MAX, "TH[%zu]", i);
1026 + thread_ptrs[i] = nd_thread_create(
1027 + tag,
1028 + NETDATA_THREAD_OPTION_JOINABLE | NETDATA_THREAD_OPTION_DONT_LOG,
1029 + aral_test_thread,
1030 + &auc);
1031 }
1032
1033 size_t malloc_done = 0;
@@ -1047,12 +1049,12 @@ int aral_stress_test(size_t threads, size_t elements, size_t seconds) {
1049
1050 // fprintf(stderr, "Cancelling the threads...\n");
1051 // for(size_t i = 0; i < threads ; i++) {
1050 -// netdata_thread_cancel(thread_ptrs[i]);
1052 +// nd_thread_signal_cancel(thread_ptrs[i]);
1053 // }
1054
1055 fprintf(stderr, "Waiting the threads to finish...\n");
1056 for(size_t i = 0; i < threads ; i++) {
1055 - netdata_thread_join(thread_ptrs[i], NULL);
1057 + nd_thread_join(thread_ptrs[i]);
1058 }
1059
1060 usec_t ended_ut = now_monotonic_usec();
src/libnetdata/avl/avl.c
+2 -2
@@ -334,7 +334,7 @@ static inline void avl_write_lock(avl_tree_lock *t) {
334
335 static inline void avl_read_unlock(avl_tree_lock *t) {
336 #if defined(AVL_LOCK_WITH_RWLOCK)
337 - netdata_rwlock_unlock(&t->rwlock);
337 + netdata_rwlock_rdunlock(&t->rwlock);
338 #else
339 rw_spinlock_read_unlock(&t->rwlock);
340 #endif
@@ -342,7 +342,7 @@ static inline void avl_read_unlock(avl_tree_lock *t) {
342
343 static inline void avl_write_unlock(avl_tree_lock *t) {
344 #if defined(AVL_LOCK_WITH_RWLOCK)
345 - netdata_rwlock_unlock(&t->rwlock);
345 + netdata_rwlock_wrunlock(&t->rwlock);
346 #else
347 rw_spinlock_write_unlock(&t->rwlock);
348 #endif
src/libnetdata/buffer/buffer.h
+6 -3
@@ -141,6 +141,9 @@ static inline void _buffer_json_depth_push(BUFFER *wb, BUFFER_JSON_NODE_TYPE typ
141 assert(wb->json.depth <= BUFFER_JSON_MAX_DEPTH && "BUFFER JSON: max nesting reached");
142 #endif
143 wb->json.depth++;
144 +#ifdef NETDATA_INTERNAL_CHECKS
145 + assert(wb->json.depth >= 0 && "Depth wrapped around and is negative");
146 +#endif
147 wb->json.stack[wb->json.depth].count = 0;
148 wb->json.stack[wb->json.depth].type = type;
149 }
@@ -772,7 +775,7 @@ static inline void buffer_json_member_add_quoted_string(BUFFER *wb, const char *
775 wb->json.stack[wb->json.depth].count++;
776 }
777
775 -static inline void buffer_json_member_add_uuid(BUFFER *wb, const char *key, uuid_t *value) {
778 +static inline void buffer_json_member_add_uuid(BUFFER *wb, const char *key, nd_uuid_t *value) {
779 buffer_print_json_comma_newline_spacing(wb);
780 buffer_print_json_key(wb, key);
781 buffer_fast_strcat(wb, ":", 1);
@@ -834,7 +837,7 @@ static inline void buffer_json_add_array_item_string(BUFFER *wb, const char *val
837 wb->json.stack[wb->json.depth].count++;
838 }
839
837 -static inline void buffer_json_add_array_item_uuid(BUFFER *wb, uuid_t *value) {
840 +static inline void buffer_json_add_array_item_uuid(BUFFER *wb, nd_uuid_t *value) {
841 if(value && !uuid_is_null(*value)) {
842 char uuid[GUID_LEN + 1];
843 uuid_unparse_lower(*value, uuid);
@@ -844,7 +847,7 @@ static inline void buffer_json_add_array_item_uuid(BUFFER *wb, uuid_t *value) {
847 buffer_json_add_array_item_string(wb, NULL);
848 }
849
847 -static inline void buffer_json_add_array_item_uuid_compact(BUFFER *wb, uuid_t *value) {
850 +static inline void buffer_json_add_array_item_uuid_compact(BUFFER *wb, nd_uuid_t *value) {
851 if(value && !uuid_is_null(*value)) {
852 char uuid[GUID_LEN + 1];
853 uuid_unparse_lower_compact(*value, uuid);
src/libnetdata/buffered_reader/buffered_reader.h
+35 -36
@@ -26,7 +26,7 @@ typedef enum {
26 BUFFERED_READER_READ_POLLNVAL = -5,
27 BUFFERED_READER_READ_POLL_UNKNOWN = -6,
28 BUFFERED_READER_READ_POLL_TIMEOUT = -7,
29 - BUFFERED_READER_READ_POLL_FAILED = -8,
29 + BUFFERED_READER_READ_POLL_CANCELLED = -8,
30 } buffered_reader_ret_t;
31
32
@@ -53,48 +53,47 @@ static inline buffered_reader_ret_t buffered_reader_read(struct buffered_reader
53 }
54
55 static inline buffered_reader_ret_t buffered_reader_read_timeout(struct buffered_reader *reader, int fd, int timeout_ms, bool log_error) {
56 - errno = 0;
57 - struct pollfd fds[1];
58 -
59 - fds[0].fd = fd;
60 - fds[0].events = POLLIN;
61 -
62 - int ret = poll(fds, 1, timeout_ms);
56 + short int revents = 0;
57 + switch(wait_on_socket_or_cancel_with_timeout(
58 +#ifdef ENABLE_HTTPS
59 + NULL,
60 +#endif
61 + fd, timeout_ms, POLLIN, &revents)) {
62
64 - if (ret > 0) {
65 - /* There is data to read */
66 - if (fds[0].revents & POLLIN)
63 + case 0: // data are waiting
64 return buffered_reader_read(reader, fd);
65
69 - else if(fds[0].revents & POLLERR) {
70 - if(log_error)
71 - netdata_log_error("PARSER: read failed: POLLERR.");
72 - return BUFFERED_READER_READ_POLLERR;
73 - }
74 - else if(fds[0].revents & POLLHUP) {
66 + case 1: // timeout reached
67 if(log_error)
76 - netdata_log_error("PARSER: read failed: POLLHUP.");
77 - return BUFFERED_READER_READ_POLLHUP;
78 - }
79 - else if(fds[0].revents & POLLNVAL) {
80 - if(log_error)
81 - netdata_log_error("PARSER: read failed: POLLNVAL.");
82 - return BUFFERED_READER_READ_POLLNVAL;
83 - }
84 -
85 - if(log_error)
86 - netdata_log_error("PARSER: poll() returned positive number, but POLLIN|POLLERR|POLLHUP|POLLNVAL are not set.");
87 - return BUFFERED_READER_READ_POLL_UNKNOWN;
88 - }
89 - else if (ret == 0) {
90 - if(log_error)
91 - netdata_log_error("PARSER: timeout while waiting for data.");
92 - return BUFFERED_READER_READ_POLL_TIMEOUT;
68 + netdata_log_error("PARSER: timeout while waiting for data.");
69 + return BUFFERED_READER_READ_POLL_TIMEOUT;
70 +
71 + case -1: // thread cancelled
72 + netdata_log_error("PARSER: thread cancelled while waiting for data.");
73 + return BUFFERED_READER_READ_POLL_CANCELLED;
74 +
75 + default:
76 + case 2: // error on socket
77 + if(revents & POLLERR) {
78 + if(log_error)
79 + netdata_log_error("PARSER: read failed: POLLERR.");
80 + return BUFFERED_READER_READ_POLLERR;
81 + }
82 + if(revents & POLLHUP) {
83 + if(log_error)
84 + netdata_log_error("PARSER: read failed: POLLHUP.");
85 + return BUFFERED_READER_READ_POLLHUP;
86 + }
87 + if(revents & POLLNVAL) {
88 + if(log_error)
89 + netdata_log_error("PARSER: read failed: POLLNVAL.");
90 + return BUFFERED_READER_READ_POLLNVAL;
91 + }
92 }
93
94 if(log_error)
96 - netdata_log_error("PARSER: poll() failed with code %d.", ret);
97 - return BUFFERED_READER_READ_POLL_FAILED;
95 + netdata_log_error("PARSER: poll() returned positive number, but POLLIN|POLLERR|POLLHUP|POLLNVAL are not set.");
96 + return BUFFERED_READER_READ_POLL_UNKNOWN;
97 }
98
99 /* Produce a full line if one exists, statefully return where we start next time.
src/libnetdata/clocks/clocks.c
+3 -3
@@ -92,7 +92,7 @@ void clocks_init(void) {
92 inline time_t now_sec(clockid_t clk_id) {
93 struct timespec ts;
94 if(unlikely(clock_gettime(clk_id, &ts) == -1)) {
95 - netdata_log_error("clock_gettime(%d, &timespec) failed.", clk_id);
95 + netdata_log_error("clock_gettime(%ld, &timespec) failed.", (long int)clk_id);
96 return 0;
97 }
98 return ts.tv_sec;
@@ -101,7 +101,7 @@ inline time_t now_sec(clockid_t clk_id) {
101 inline usec_t now_usec(clockid_t clk_id) {
102 struct timespec ts;
103 if(unlikely(clock_gettime(clk_id, &ts) == -1)) {
104 - netdata_log_error("clock_gettime(%d, &timespec) failed.", clk_id);
104 + netdata_log_error("clock_gettime(%ld, &timespec) failed.", (long int)clk_id);
105 return 0;
106 }
107 return (usec_t)ts.tv_sec * USEC_PER_SEC + (usec_t)(ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC;
@@ -111,7 +111,7 @@ inline int now_timeval(clockid_t clk_id, struct timeval *tv) {
111 struct timespec ts;
112
113 if(unlikely(clock_gettime(clk_id, &ts) == -1)) {
114 - netdata_log_error("clock_gettime(%d, &timespec) failed.", clk_id);
114 + netdata_log_error("clock_gettime(%ld, &timespec) failed.", (long int)clk_id);
115 tv->tv_sec = 0;
116 tv->tv_usec = 0;
117 return -1;
src/libnetdata/config/appconfig.c
+2 -2
@@ -904,7 +904,7 @@ void appconfig_generate(struct config *root, BUFFER *wb, int only_changed)
904 * @return It returns 1 on success and 0 otherwise
905 */
906 int config_parse_duration(const char* string, int* result) {
907 - while(*string && isspace(*string)) string++;
907 + while(*string && isspace((uint8_t)*string)) string++;
908
909 if(unlikely(!*string)) goto fallback;
910
@@ -915,7 +915,7 @@ int config_parse_duration(const char* string, int* result) {
915 }
916
917 // make sure it is a number
918 - if(!(isdigit(*string) || *string == '+' || *string == '-')) goto fallback;
918 + if(!(isdigit((uint8_t)*string) || *string == '+' || *string == '-')) goto fallback;
919
920 char *e = NULL;
921 NETDATA_DOUBLE n = str2ndd(string, &e);
src/libnetdata/config/dyncfg.c
+22 -3
@@ -1,6 +1,6 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 -#include "../libnetdata.h"
3 +#include "../../libnetdata/libnetdata.h"
4
5 // ----------------------------------------------------------------------------
6
@@ -203,13 +203,32 @@ bool dyncfg_is_valid_id(const char *id) {
203 const char *s = id;
204
205 while(*s) {
206 - if(isspace(*s) || *s == '\'') return false;
206 + if(isspace((uint8_t)*s) || *s == '\'') return false;
207 s++;
208 }
209
210 return true;
211 }
212
213 +static inline bool is_forbidden_char(char c) {
214 + if(isspace((uint8_t)c) || !isprint((uint8_t)c))
215 + return true;
216 +
217 + switch(c) {
218 + case '/':
219 + return true;
220 +
221 +#ifdef COMPILED_FOR_WINDOWS
222 + case ':':
223 + case '|':
224 + return true;
225 +#endif
226 +
227 + default:
228 + return false;
229 + }
230 +}
231 +
232 char *dyncfg_escape_id_for_filename(const char *id) {
233 if (id == NULL) return NULL;
234
@@ -221,7 +240,7 @@ char *dyncfg_escape_id_for_filename(const char *id) {
240 char *dest = escaped;
241
242 while (*src) {
224 - if (*src == '/' || isspace(*src) || !isprint(*src)) {
243 + if (is_forbidden_char(*src)) {
244 sprintf(dest, "%%%02X", (unsigned char)*src);
245 dest += 3;
246 } else {
src/libnetdata/datetime/rfc3339.c
+2 -2
@@ -102,8 +102,8 @@ usec_t rfc3339_parse_ut(const char *rfc3339, char **endptr) {
102 if (*s == '+' || *s == '-') {
103 // Parse the hours:mins part of the timezone
104
105 - if (!isdigit(s[1]) || !isdigit(s[2]) || s[3] != ':' ||
106 - !isdigit(s[4]) || !isdigit(s[5]))
105 + if (!isdigit((uint8_t)s[1]) || !isdigit((uint8_t)s[2]) || s[3] != ':' ||
106 + !isdigit((uint8_t)s[4]) || !isdigit((uint8_t)s[5]))
107 return 0; // Parsing error
108
109 char tz_sign = *s;
src/libnetdata/dictionary/dictionary-item.h
+3 -3
@@ -53,7 +53,7 @@ static inline DICTIONARY_ITEM *dict_item_create(DICTIONARY *dict __maybe_unused,
53 memset(item, 0, sizeof(DICTIONARY_ITEM));
54
55 #ifdef NETDATA_INTERNAL_CHECKS
56 - item->creator_pid = gettid();
56 + item->creator_pid = gettid_cached();
57 #endif
58
59 item->refcount = 1;
@@ -256,7 +256,7 @@ static inline void item_linked_list_add(DICTIONARY *dict, DICTIONARY_ITEM *item)
256 DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(dict->items.list, item, prev, next);
257
258 #ifdef NETDATA_INTERNAL_CHECKS
259 - item->ll_adder_pid = gettid();
259 + item->ll_adder_pid = gettid_cached();
260 #endif
261
262 // clear the BEING created flag,
@@ -273,7 +273,7 @@ static inline void item_linked_list_remove(DICTIONARY *dict, DICTIONARY_ITEM *it
273 DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(dict->items.list, item, prev, next);
274
275 #ifdef NETDATA_INTERNAL_CHECKS
276 - item->ll_remover_pid = gettid();
276 + item->ll_remover_pid = gettid_cached();
277 #endif
278
279 garbage_collect_pending_deletes(dict);
src/libnetdata/dictionary/dictionary-locks.h
+5 -5
@@ -22,19 +22,19 @@ static inline size_t dictionary_locks_destroy(DICTIONARY *dict __maybe_unused) {
22 }
23
24 static inline void ll_recursive_lock_set_thread_as_writer(DICTIONARY *dict) {
25 - pid_t expected = 0, desired = gettid();
25 + pid_t expected = 0, desired = gettid_cached();
26 if(!__atomic_compare_exchange_n(&dict->items.writer_pid, &expected, desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
27 - fatal("DICTIONARY: Cannot set thread %d as exclusive writer, expected %d, desired %d, found %d.", gettid(), expected, desired, __atomic_load_n(&dict->items.writer_pid, __ATOMIC_RELAXED));
27 + fatal("DICTIONARY: Cannot set thread %d as exclusive writer, expected %d, desired %d, found %d.", gettid_cached(), expected, desired, __atomic_load_n(&dict->items.writer_pid, __ATOMIC_RELAXED));
28 }
29
30 static inline void ll_recursive_unlock_unset_thread_writer(DICTIONARY *dict) {
31 - pid_t expected = gettid(), desired = 0;
31 + pid_t expected = gettid_cached(), desired = 0;
32 if(!__atomic_compare_exchange_n(&dict->items.writer_pid, &expected, desired, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
33 - fatal("DICTIONARY: Cannot unset thread %d as exclusive writer, expected %d, desired %d, found %d.", gettid(), expected, desired, __atomic_load_n(&dict->items.writer_pid, __ATOMIC_RELAXED));
33 + fatal("DICTIONARY: Cannot unset thread %d as exclusive writer, expected %d, desired %d, found %d.", gettid_cached(), expected, desired, __atomic_load_n(&dict->items.writer_pid, __ATOMIC_RELAXED));
34 }
35
36 static inline bool ll_recursive_lock_is_thread_the_writer(DICTIONARY *dict) {
37 - pid_t tid = gettid();
37 + pid_t tid = gettid_cached();
38 return tid > 0 && tid == __atomic_load_n(&dict->items.writer_pid, __ATOMIC_RELAXED);
39 }
40
src/libnetdata/dictionary/dictionary-refcount.h
+1 -1
@@ -219,7 +219,7 @@ static inline int item_is_not_referenced_and_can_be_removed_advanced(DICTIONARY
219
220 #ifdef NETDATA_INTERNAL_CHECKS
221 if(ret == RC_ITEM_OK)
222 - item->deleter_pid = gettid();
222 + item->deleter_pid = gettid_cached();
223 #endif
224
225 if(unlikely(spins > 1))
src/libnetdata/dictionary/dictionary-unittest.c
+9 -14
@@ -569,7 +569,7 @@ struct thread_unittest {
569 DICTIONARY *dict;
570 int dups;
571
572 - netdata_thread_t thread;
572 + ND_THREAD *thread;
573 struct dictionary_stats stats;
574 };
575
@@ -638,7 +638,7 @@ static void *unittest_dict_thread(void *arg) {
638
639 // test concurrent deletions and flushes
640 {
641 - if(gettid() % 2) {
641 + if(gettid_cached() % 2) {
642 char buf [256 + 1];
643
644 for (int i = 0; i < 1000; i++) {
@@ -690,8 +690,7 @@ static int dictionary_unittest_threads() {
690
691 char buf[100 + 1];
692 snprintf(buf, 100, "dict%d", i);
693 - netdata_thread_create(
694 - &tu[i].thread,
693 + tu[i].thread = nd_thread_create(
694 buf,
695 NETDATA_THREAD_OPTION_DONT_LOG | NETDATA_THREAD_OPTION_JOINABLE,
696 unittest_dict_thread,
@@ -703,8 +702,7 @@ static int dictionary_unittest_threads() {
702 for (int i = 0; i < threads_to_create; i++) {
703 __atomic_store_n(&tu[i].join, 1, __ATOMIC_RELAXED);
704
706 - void *retval;
707 - netdata_thread_join(tu[i].thread, &retval);
705 + nd_thread_join(tu[i].thread);
706
707 if(i) {
708 tu[0].stats.ops.inserts += tu[i].stats.ops.inserts;
@@ -870,18 +868,16 @@ static int dictionary_unittest_view_threads() {
868 "\nChecking dictionary concurrency with 1 master and 1 view threads for %lld seconds...\n",
869 (long long)seconds_to_run);
870
873 - netdata_thread_t master_thread, view_thread;
871 + ND_THREAD *master_thread, *view_thread;
872 tv.join = 0;
873
876 - netdata_thread_create(
877 - &master_thread,
874 + master_thread = nd_thread_create(
875 "master",
876 NETDATA_THREAD_OPTION_DONT_LOG | NETDATA_THREAD_OPTION_JOINABLE,
877 unittest_dict_master_thread,
878 &tv);
879
883 - netdata_thread_create(
884 - &view_thread,
880 + view_thread = nd_thread_create(
881 "view",
882 NETDATA_THREAD_OPTION_DONT_LOG | NETDATA_THREAD_OPTION_JOINABLE,
883 unittest_dict_view_thread,
@@ -890,9 +886,8 @@ static int dictionary_unittest_view_threads() {
886 sleep_usec(seconds_to_run * USEC_PER_SEC);
887
888 __atomic_store_n(&tv.join, 1, __ATOMIC_RELAXED);
893 - void *retval;
894 - netdata_thread_join(view_thread, &retval);
895 - netdata_thread_join(master_thread, &retval);
889 + nd_thread_join(view_thread);
890 + nd_thread_join(master_thread);
891
892 #ifdef DICT_WITH_STATS
893 fprintf(stderr,
src/libnetdata/dictionary/dictionary.c
+1 -1
@@ -555,7 +555,7 @@ DICTIONARY *dictionary_create_view(DICTIONARY *master) {
555 dict->creation_function = function;
556 dict->creation_file = file;
557 dict->creation_line = line;
558 - dict->creation_tid = gettid();
558 + dict->creation_tid = gettid_cached();
559 #endif
560
561 DICTIONARY_STATS_DICT_CREATIONS_PLUS1(dict);
src/libnetdata/eval/eval.c
+2 -2
@@ -383,7 +383,7 @@ static inline void print_parsed_as_node(BUFFER *out, EVAL_NODE *op, int *error)
383 // skip spaces
384 static inline void skip_spaces(const char **string) {
385 const char *s = *string;
386 - while(isspace(*s)) s++;
386 + while(isspace((uint8_t)*s)) s++;
387 *string = s;
388 }
389
@@ -1219,7 +1219,7 @@ void expression_hardcode_variable(EVAL_EXPRESSION *expression, STRING *variable,
1219 }
1220
1221 if (s) {
1222 - if (s == s1 && (isalnum(s[len]) || s[len] == '_')) {
1222 + if (s == s1 && (isalnum((uint8_t)s[len]) || s[len] == '_')) {
1223 // Move past the variable if it's part of a larger word.
1224 source_ptr = s + len;
1225 continue;
src/libnetdata/facets/facets.c
+5 -5
@@ -2229,8 +2229,8 @@ static int facets_keys_reorder_compar(const void *a, const void *b) {
2229 if(!an) an = "0";
2230 if(!bn) bn = "0";
2231
2232 - while(*an && ispunct(*an)) an++;
2233 - while(*bn && ispunct(*bn)) bn++;
2232 + while(*an && ispunct((uint8_t)*an)) an++;
2233 + while(*bn && ispunct((uint8_t)*bn)) bn++;
2234
2235 return strcasecmp(an, bn);
2236 }
@@ -2256,8 +2256,8 @@ static int facets_key_values_reorder_by_name_compar(const void *a, const void *b
2256 const char *an = (av->name && av->name_len) ? av->name : "0";
2257 const char *bn = (bv->name && bv->name_len) ? bv->name : "0";
2258
2259 - while(*an && ispunct(*an)) an++;
2260 - while(*bn && ispunct(*bn)) bn++;
2259 + while(*an && ispunct((uint8_t)*an)) an++;
2260 + while(*bn && ispunct((uint8_t)*bn)) bn++;
2261
2262 int ret = strcasecmp(an, bn);
2263 return ret;
@@ -2309,7 +2309,7 @@ static uint32_t facets_sort_and_reorder_values_internal(FACET_KEY *k) {
2309
2310 if(all_values_numeric && !v->empty && v->name && v->name_len) {
2311 const char *s = v->name;
2312 - while(isdigit(*s)) s++;
2312 + while(isdigit((uint8_t)*s)) s++;
2313 if(*s != '\0')
2314 all_values_numeric = false;
2315 }
src/libnetdata/functions_evloop/functions_evloop.c
+37 -11
@@ -49,9 +49,10 @@ struct functions_evloop_globals {
49
50 netdata_mutex_t *stdout_mutex;
51 bool *plugin_should_exit;
52 + bool workers_exit; // all workers are waiting on the same condition - this makes them all exit, when any is cancelled
53
53 - netdata_thread_t reader_thread;
54 - netdata_thread_t *worker_threads;
54 + ND_THREAD *reader_thread;
55 + ND_THREAD **worker_threads;
56
57 struct {
58 DICTIONARY *nodes;
@@ -60,13 +61,28 @@ struct functions_evloop_globals {
61 struct rrd_functions_expectation *expectations;
62 };
63
64 +static void rrd_functions_worker_canceller(void *data) {
65 + struct functions_evloop_globals *wg = data;
66 + pthread_mutex_lock(&wg->worker_mutex);
67 + wg->workers_exit = true;
68 + pthread_cond_signal(&wg->worker_cond_var);
69 + pthread_mutex_unlock(&wg->worker_mutex);
70 +}
71 +
72 static void *rrd_functions_worker_globals_worker_main(void *arg) {
73 struct functions_evloop_globals *wg = arg;
74
75 + nd_thread_register_canceller(rrd_functions_worker_canceller, wg);
76 +
77 bool last_acquired = true;
78 while (true) {
79 pthread_mutex_lock(&wg->worker_mutex);
80
81 + if(wg->workers_exit || nd_thread_signaled_to_cancel()) {
82 + pthread_mutex_unlock(&wg->worker_mutex);
83 + break;
84 + }
85 +
86 if(dictionary_entries(wg->worker_queue) == 0 || !last_acquired)
87 pthread_cond_wait(&wg->worker_cond_var, &wg->worker_mutex);
88
@@ -84,6 +100,13 @@ static void *rrd_functions_worker_globals_worker_main(void *arg) {
100
101 pthread_mutex_unlock(&wg->worker_mutex);
102
103 + if(wg->workers_exit || nd_thread_signaled_to_cancel()) {
104 + if(acquired)
105 + dictionary_acquired_item_release(wg->worker_queue, acquired);
106 +
107 + break;
108 + }
109 +
110 if(acquired) {
111 ND_LOG_STACK lgs[] = {
112 ND_LOG_FIELD_TXT(NDF_REQUEST, j->cmd),
@@ -101,6 +124,7 @@ static void *rrd_functions_worker_globals_worker_main(void *arg) {
124 else
125 last_acquired = false;
126 }
127 +
128 return NULL;
129 }
130
@@ -146,7 +170,9 @@ static void worker_add_job(struct functions_evloop_globals *wg, const char *keyw
170 else {
171 found = true;
172 j->used = true;
173 + pthread_mutex_lock(&wg->worker_mutex);
174 pthread_cond_signal(&wg->worker_cond_var);
175 + pthread_mutex_unlock(&wg->worker_mutex);
176 }
177 }
178 }
@@ -310,18 +336,18 @@ struct functions_evloop_globals *functions_evloop_init(size_t worker_threads, co
336 wg->plugin_should_exit = plugin_should_exit;
337 wg->stdout_mutex = stdout_mutex;
338 wg->workers = worker_threads;
313 - wg->worker_threads = callocz(wg->workers, sizeof(netdata_thread_t ));
339 + wg->worker_threads = callocz(wg->workers, sizeof(ND_THREAD *));
340 wg->tag = tag;
341
342 char tag_buffer[NETDATA_THREAD_TAG_MAX + 1];
343 snprintfz(tag_buffer, NETDATA_THREAD_TAG_MAX, "%s_READER", wg->tag);
318 - netdata_thread_create(&wg->reader_thread, tag_buffer, NETDATA_THREAD_OPTION_DONT_LOG,
319 - rrd_functions_worker_globals_reader_main, wg);
344 + wg->reader_thread = nd_thread_create(tag_buffer, NETDATA_THREAD_OPTION_DONT_LOG,
345 + rrd_functions_worker_globals_reader_main, wg);
346
347 for(size_t i = 0; i < wg->workers ; i++) {
348 snprintfz(tag_buffer, NETDATA_THREAD_TAG_MAX, "%s_WORK[%zu]", wg->tag, i+1);
323 - netdata_thread_create(&wg->worker_threads[i], tag_buffer, NETDATA_THREAD_OPTION_DONT_LOG,
324 - rrd_functions_worker_globals_worker_main, wg);
349 + wg->worker_threads[i] = nd_thread_create(tag_buffer, NETDATA_THREAD_OPTION_DONT_LOG,
350 + rrd_functions_worker_globals_worker_main, wg);
351 }
352
353 functions_evloop_add_function(wg, "config", functions_evloop_config_cb, 120, wg);
@@ -339,11 +365,11 @@ void functions_evloop_add_function(struct functions_evloop_globals *wg, const ch
365 DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(wg->expectations, we, prev, next);
366 }
367
342 -void functions_evloop_cancel_threads(struct functions_evloop_globals *wg){
343 - for(size_t i = 0; i < wg->workers ; i++)
344 - netdata_thread_cancel(wg->worker_threads[i]);
368 +void functions_evloop_cancel_threads(struct functions_evloop_globals *wg) {
369 + nd_thread_signal_cancel(wg->reader_thread);
370
346 - netdata_thread_cancel(wg->reader_thread);
371 + for(size_t i = 0; i < wg->workers ; i++)
372 + nd_thread_signal_cancel(wg->worker_threads[i]);
373 }
374
375 // ----------------------------------------------------------------------------
src/libnetdata/inlined.h
+8 -8
@@ -453,7 +453,7 @@ static inline bool sanitize_command_argument_string(char *dst, const char *src,
453 if (dst_size < 1)
454 return false;
455
456 - if (iscntrl(*src) || *src == '$') {
456 + if (iscntrl((uint8_t)*src) || *src == '$') {
457 // remove control characters and characters that are expanded by bash
458 *dst++ = '_';
459 dst_size--;
@@ -597,7 +597,7 @@ static inline char *strsep_skip_consecutive_separators(char **ptr, char *s) {
597 // remove leading and trailing spaces; may return NULL
598 static inline char *trim(char *s) {
599 // skip leading spaces
600 - while (*s && isspace(*s)) s++;
600 + while (*s && isspace((uint8_t)*s)) s++;
601 if (!*s) return NULL;
602
603 // skip tailing spaces
@@ -605,7 +605,7 @@ static inline char *trim(char *s) {
605 ssize_t l = (ssize_t)strlen(s);
606 if (--l >= 0) {
607 char *p = s + l;
608 - while (p > s && isspace(*p)) p--;
608 + while (p > s && isspace((uint8_t)*p)) p--;
609 *++p = '\0';
610 }
611
@@ -619,27 +619,27 @@ static inline char *trim_all(char *buffer) {
619 char *d = buffer, *s = buffer;
620
621 // skip spaces
622 - while(isspace(*s)) s++;
622 + while(isspace((uint8_t)*s)) s++;
623
624 while(*s) {
625 // copy the non-space part
626 - while(*s && !isspace(*s)) *d++ = *s++;
626 + while(*s && !isspace((uint8_t)*s)) *d++ = *s++;
627
628 // add a space if we have to
629 - if(*s && isspace(*s)) {
629 + if(*s && isspace((uint8_t)*s)) {
630 *d++ = ' ';
631 s++;
632 }
633
634 // skip spaces
635 - while(isspace(*s)) s++;
635 + while(isspace((uint8_t)*s)) s++;
636 }
637
638 *d = '\0';
639
640 if(d > buffer) {
641 d--;
642 - if(isspace(*d)) *d = '\0';
642 + if(isspace((uint8_t)*d)) *d = '\0';
643 }
644
645 if(!buffer[0]) return NULL;
src/libnetdata/libnetdata.c
+8 -8
@@ -2,17 +2,17 @@
2
3 #include "libnetdata.h"
4
5 -#ifdef __APPLE__
6 -#define INHERIT_NONE 0
7 -#endif /* __APPLE__ */
8 -#if defined(__FreeBSD__) || defined(__APPLE__)
9 -# define O_NOATIME 0
10 -# define MADV_DONTFORK INHERIT_NONE
11 -#endif /* __FreeBSD__ || __APPLE__*/
5 +#if !defined(MADV_DONTFORK)
6 +#define MADV_DONTFORK 0
7 +#endif
8 +
9 +#if !defined(O_NOATIME)
10 +#define O_NOATIME 0
11 +#endif
12
13 struct rlimit rlimit_nofile = { .rlim_cur = 1024, .rlim_max = 1024 };
14
15 -#ifdef MADV_MERGEABLE
15 +#if defined(MADV_MERGEABLE)
16 int enable_ksm = 1;
17 #else
18 int enable_ksm = 0;
src/libnetdata/libnetdata.h
+130 -22
@@ -76,6 +76,8 @@ extern "C" {
76 #define NETDATA_OS_TYPE "freebsd"
77 #elif defined(__APPLE__)
78 #define NETDATA_OS_TYPE "macos"
79 +#elif defined(COMPILED_FOR_WINDOWS)
80 +#define NETDATA_OS_TYPE "windows"
81 #else
82 #define NETDATA_OS_TYPE "linux"
83 #endif /* __FreeBSD__, __APPLE__*/
@@ -90,40 +92,112 @@ extern "C" {
92 #include <ctype.h>
93 #include <string.h>
94 #include <strings.h>
93 -#include <arpa/inet.h>
94 -#include <netinet/tcp.h>
95 -#include <sys/ioctl.h>
95 #include <libgen.h>
96 #include <dirent.h>
97 #include <fcntl.h>
98 #include <getopt.h>
100 -#include <grp.h>
101 -#include <pwd.h>
99 #include <limits.h>
100 #include <locale.h>
101 +#include <signal.h>
102 +#include <sys/time.h>
103 +#include <sys/types.h>
104 +#include <time.h>
105 +#include <unistd.h>
106 +#include <uv.h>
107 +#include <assert.h>
108 +
109 +#ifdef HAVE_ARPA_INET_H
110 +#include <arpa/inet.h>
111 +#endif
112 +
113 +#ifdef HAVE_NETINET_TCP_H
114 +#include <netinet/tcp.h>
115 +#endif
116 +
117 +#ifdef HAVE_SYS_IOCTL_H
118 +#include <sys/ioctl.h>
119 +#endif
120 +
121 +#ifdef HAVE_GRP_H
122 +#include <grp.h>
123 +#else
124 +typedef uint32_t gid_t;
125 +#endif
126 +
127 +#ifdef HAVE_PWD_H
128 +#include <pwd.h>
129 +#else
130 +typedef uint32_t uid_t;
131 +#endif
132 +
133 +#ifdef HAVE_NET_IF_H
134 #include <net/if.h>
135 +#endif
136 +
137 +#ifdef HAVE_POLL_H
138 #include <poll.h>
106 -#include <signal.h>
139 +#endif
140 +
141 +#ifdef HAVE_SYSLOG_H
142 #include <syslog.h>
143 +#else
144 +/* priorities */
145 +#define LOG_EMERG 0 /* system is unusable */
146 +#define LOG_ALERT 1 /* action must be taken immediately */
147 +#define LOG_CRIT 2 /* critical conditions */
148 +#define LOG_ERR 3 /* error conditions */
149 +#define LOG_WARNING 4 /* warning conditions */
150 +#define LOG_NOTICE 5 /* normal but significant condition */
151 +#define LOG_INFO 6 /* informational */
152 +#define LOG_DEBUG 7 /* debug-level messages */
153 +
154 +/* facility codes */
155 +#define LOG_KERN (0<<3) /* kernel messages */
156 +#define LOG_USER (1<<3) /* random user-level messages */
157 +#define LOG_MAIL (2<<3) /* mail system */
158 +#define LOG_DAEMON (3<<3) /* system daemons */
159 +#define LOG_AUTH (4<<3) /* security/authorization messages */
160 +#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
161 +#define LOG_LPR (6<<3) /* line printer subsystem */
162 +#define LOG_NEWS (7<<3) /* network news subsystem */
163 +#define LOG_UUCP (8<<3) /* UUCP subsystem */
164 +#define LOG_CRON (9<<3) /* clock daemon */
165 +#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */
166 +#define LOG_FTP (11<<3) /* ftp daemon */
167 +
168 +/* other codes through 15 reserved for system use */
169 +#define LOG_LOCAL0 (16<<3) /* reserved for local use */
170 +#define LOG_LOCAL1 (17<<3) /* reserved for local use */
171 +#define LOG_LOCAL2 (18<<3) /* reserved for local use */
172 +#define LOG_LOCAL3 (19<<3) /* reserved for local use */
173 +#define LOG_LOCAL4 (20<<3) /* reserved for local use */
174 +#define LOG_LOCAL5 (21<<3) /* reserved for local use */
175 +#define LOG_LOCAL6 (22<<3) /* reserved for local use */
176 +#define LOG_LOCAL7 (23<<3) /* reserved for local use */
177 +#endif
178 +
179 +#ifdef HAVE_SYS_MMAN_H
180 #include <sys/mman.h>
181 +#endif
182 +
183 +#ifdef HAVE_SYS_RESOURCE_H
184 #include <sys/resource.h>
185 +#endif
186 +
187 +#ifdef HAVE_SYS_SOCKET_H
188 #include <sys/socket.h>
111 -#include <sys/syscall.h>
112 -#include <sys/time.h>
113 -#include <sys/types.h>
189 +#endif
190 +
191 +#ifdef HAVE_SYS_WAIT_H
192 #include <sys/wait.h>
193 +#endif
194 +
195 +#ifdef HAVE_SYS_UN_H
196 #include <sys/un.h>
116 -#include <time.h>
117 -#include <unistd.h>
118 -#include <uuid/uuid.h>
119 -#include <spawn.h>
120 -#include <uv.h>
121 -#include <assert.h>
197 +#endif
198
123 -// CentOS 7 has older version that doesn't define this
124 -// same goes for MacOS
125 -#ifndef UUID_STR_LEN
126 -#define UUID_STR_LEN (37)
199 +#ifdef HAVE_SPAWN_H
200 +#include <spawn.h>
201 #endif
202
203 #ifdef HAVE_NETINET_IN_H
@@ -190,6 +264,10 @@ extern "C" {
264 #endif
265
266
267 +#ifndef O_CLOEXEC
268 +#define O_CLOEXEC (0)
269 +#endif
270 +
271 // ----------------------------------------------------------------------------
272 // netdata common definitions
273
@@ -213,8 +291,10 @@ extern "C" {
291 #define MALLOCLIKE
292 #endif
293
216 -#ifdef HAVE_FUNC_ATTRIBUTE_FORMAT
217 -#define PRINTFLIKE(f, a) __attribute__ ((format(__printf__, f, a)))
294 +#if defined(HAVE_FUNC_ATTRIBUTE_FORMAT) && !defined(COMPILED_FOR_MACOS)
295 +#define PRINTFLIKE(f, a) __attribute__ ((format(gnu_printf, f, a)))
296 +#elif defined(HAVE_FUNC_ATTRIBUTE_FORMAT)
297 +#define PRINTFLIKE(f, a) __attribute__ ((format(printf, f, a)))
298 #else
299 #define PRINTFLIKE(f, a)
300 #endif
@@ -376,6 +456,8 @@ void for_each_open_fd(OPEN_FD_ACTION action, OPEN_FD_EXCLUDE excluded_fds);
456 void netdata_cleanup_and_exit(int ret, const char *action, const char *action_result, const char *action_data) NORETURN;
457 extern char *netdata_configured_host_prefix;
458
459 +#include "os/os.h"
460 +
461 #define XXH_INLINE_ALL
462 #include "xxhash.h"
463
@@ -386,7 +468,6 @@ extern char *netdata_configured_host_prefix;
468 #include "config/dyncfg.h"
469 #include "libjudy/src/Judy.h"
470 #include "july/july.h"
389 -#include "os.h"
471 #include "threads/threads.h"
472 #include "buffer/buffer.h"
473 #include "locks/locks.h"
@@ -594,6 +675,33 @@ static inline void freez_const_charp(const char **p) {
675 #define CLEAN_CONST_CHAR_P _cleanup_(freez_const_charp) const char
676 #define CLEAN_CHAR_P _cleanup_(freez_charp) char
677
678 +// --------------------------------------------------------------------------------------------------------------------
679 +// automatic cleanup function, instead of pthread pop/push
680 +
681 +// volatile: Tells the compiler that the variable defined might be accessed in unexpected ways
682 +// (e.g., by the cleanup function). This prevents it from being optimized out.
683 +#define CLEANUP_FUNCTION_REGISTER(func) volatile void * __attribute__((cleanup(func)))
684 +
685 +static inline void *CLEANUP_FUNCTION_GET_PTR(void *pptr) {
686 + void *ret;
687 + void **p = (void **)pptr;
688 + if(p) {
689 + ret = *p;
690 + *p = NULL; // use it only once - this will prevent using it again
691 +
692 + if(!ret)
693 + nd_log(NDLS_DAEMON, NDLP_ERR, "cleanup function called multiple times!");
694 + }
695 + else {
696 + nd_log(NDLS_DAEMON, NDLP_ERR, "cleanup function called with NULL pptr!");
697 + ret = NULL;
698 + }
699 +
700 + return ret;
701 +}
702 +
703 +// --------------------------------------------------------------------------------------------------------------------
704 +
705 # ifdef __cplusplus
706 }
707 # endif
src/libnetdata/locks/locks.c
+69 -129
@@ -18,64 +18,6 @@
18
19 #endif // NETDATA_TRACE_RWLOCKS
20
21 -// ----------------------------------------------------------------------------
22 -// automatic thread cancelability management, based on locks
23 -
24 -static __thread int netdata_thread_first_cancelability = 0;
25 -static __thread int netdata_thread_nested_disables = 0;
26 -
27 -static __thread size_t netdata_locks_acquired_rwlocks = 0;
28 -static __thread size_t netdata_locks_acquired_mutexes = 0;
29 -
30 -inline void netdata_thread_disable_cancelability(void) {
31 - if(!netdata_thread_nested_disables) {
32 - int old;
33 - int ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
34 -
35 - if(ret != 0)
36 - netdata_log_error("THREAD_CANCELABILITY: pthread_setcancelstate() on thread %s returned error %d",
37 - netdata_thread_tag(), ret);
38 -
39 - netdata_thread_first_cancelability = old;
40 - }
41 -
42 - netdata_thread_nested_disables++;
43 -}
44 -
45 -inline void netdata_thread_enable_cancelability(void) {
46 - if(unlikely(netdata_thread_nested_disables < 1)) {
47 - internal_fatal(true, "THREAD_CANCELABILITY: trying to enable cancelability, but it was not not disabled");
48 -
49 - netdata_log_error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): invalid thread cancelability count %d "
50 - "on thread %s - results will be undefined - please report this!",
51 - netdata_thread_nested_disables, netdata_thread_tag());
52 -
53 - netdata_thread_nested_disables = 1;
54 - }
55 -
56 - if(netdata_thread_nested_disables == 1) {
57 - int old = 1;
58 - int ret = pthread_setcancelstate(netdata_thread_first_cancelability, &old);
59 - if(ret != 0)
60 - netdata_log_error("THREAD_CANCELABILITY: pthread_setcancelstate() on thread %s returned error %d",
61 - netdata_thread_tag(),
62 - ret);
63 - else {
64 - if(old != PTHREAD_CANCEL_DISABLE) {
65 - internal_fatal(true, "THREAD_CANCELABILITY: invalid old state cancelability");
66 -
67 - netdata_log_error("THREAD_CANCELABILITY: netdata_thread_enable_cancelability(): old thread cancelability "
68 - "on thread %s was changed, expected DISABLED (%d), found %s (%d) - please report this!",
69 - netdata_thread_tag(), PTHREAD_CANCEL_DISABLE,
70 - (old == PTHREAD_CANCEL_ENABLE) ? "ENABLED" : "UNKNOWN",
71 - old);
72 - }
73 - }
74 - }
75 -
76 - netdata_thread_nested_disables--;
77 -}
78 -
21 // ----------------------------------------------------------------------------
22 // mutex
23
@@ -94,27 +36,22 @@ int __netdata_mutex_destroy(netdata_mutex_t *mutex) {
36 }
37
38 int __netdata_mutex_lock(netdata_mutex_t *mutex) {
97 - netdata_thread_disable_cancelability();
98 -
39 int ret = pthread_mutex_lock(mutex);
40 if(unlikely(ret != 0)) {
101 - netdata_thread_enable_cancelability();
41 netdata_log_error("MUTEX_LOCK: failed to get lock (code %d)", ret);
42 }
43 else
105 - netdata_locks_acquired_mutexes++;
44 + nd_thread_mutex_locked();
45
46 return ret;
47 }
48
49 int __netdata_mutex_trylock(netdata_mutex_t *mutex) {
111 - netdata_thread_disable_cancelability();
112 -
50 int ret = pthread_mutex_trylock(mutex);
51 if(ret != 0)
115 - netdata_thread_enable_cancelability();
52 + ;
53 else
117 - netdata_locks_acquired_mutexes++;
54 + nd_thread_mutex_locked();
55
56 return ret;
57 }
@@ -123,10 +60,8 @@ int __netdata_mutex_unlock(netdata_mutex_t *mutex) {
60 int ret = pthread_mutex_unlock(mutex);
61 if(unlikely(ret != 0))
62 netdata_log_error("MUTEX_LOCK: failed to unlock (code %d).", ret);
126 - else {
127 - netdata_locks_acquired_mutexes--;
128 - netdata_thread_enable_cancelability();
129 - }
63 + else
64 + nd_thread_mutex_unlocked();
65
66 return ret;
67 }
@@ -226,65 +161,61 @@ int __netdata_rwlock_init(netdata_rwlock_t *rwlock) {
161 }
162
163 int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock) {
229 - netdata_thread_disable_cancelability();
230 -
164 int ret = pthread_rwlock_rdlock(&rwlock->rwlock_t);
232 - if(unlikely(ret != 0)) {
233 - netdata_thread_enable_cancelability();
165 + if(unlikely(ret != 0))
166 netdata_log_error("RW_LOCK: failed to obtain read lock (code %d)", ret);
235 - }
167 else
237 - netdata_locks_acquired_rwlocks++;
168 + nd_thread_rwlock_read_locked();
169
170 return ret;
171 }
172
173 int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock) {
243 - netdata_thread_disable_cancelability();
244 -
174 int ret = pthread_rwlock_wrlock(&rwlock->rwlock_t);
246 - if(unlikely(ret != 0)) {
175 + if(unlikely(ret != 0))
176 netdata_log_error("RW_LOCK: failed to obtain write lock (code %d)", ret);
248 - netdata_thread_enable_cancelability();
249 - }
177 else
251 - netdata_locks_acquired_rwlocks++;
178 + nd_thread_rwlock_write_locked();
179
180 return ret;
181 }
182
256 -int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock) {
183 +int __netdata_rwlock_rdunlock(netdata_rwlock_t *rwlock) {
184 int ret = pthread_rwlock_unlock(&rwlock->rwlock_t);
185 if(unlikely(ret != 0))
186 netdata_log_error("RW_LOCK: failed to release lock (code %d)", ret);
260 - else {
261 - netdata_thread_enable_cancelability();
262 - netdata_locks_acquired_rwlocks--;
263 - }
187 + else
188 + nd_thread_rwlock_read_unlocked();
189
190 return ret;
191 }
192
268 -int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
269 - netdata_thread_disable_cancelability();
193 +int __netdata_rwlock_wrunlock(netdata_rwlock_t *rwlock) {
194 + int ret = pthread_rwlock_unlock(&rwlock->rwlock_t);
195 + if(unlikely(ret != 0))
196 + netdata_log_error("RW_LOCK: failed to release lock (code %d)", ret);
197 + else
198 + nd_thread_rwlock_write_unlocked();
199
200 + return ret;
201 +}
202 +
203 +int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock) {
204 int ret = pthread_rwlock_tryrdlock(&rwlock->rwlock_t);
205 if(ret != 0)
273 - netdata_thread_enable_cancelability();
206 + ;
207 else
275 - netdata_locks_acquired_rwlocks++;
208 + nd_thread_rwlock_read_locked();
209
210 return ret;
211 }
212
213 int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock) {
281 - netdata_thread_disable_cancelability();
282 -
214 int ret = pthread_rwlock_trywrlock(&rwlock->rwlock_t);
215 if(ret != 0)
285 - netdata_thread_enable_cancelability();
216 + ;
217 else
287 - netdata_locks_acquired_rwlocks++;
218 + nd_thread_rwlock_write_locked();
219
220 return ret;
221 }
@@ -297,16 +228,11 @@ void spinlock_init(SPINLOCK *spinlock) {
228 memset(spinlock, 0, sizeof(SPINLOCK));
229 }
230
300 -static inline void spinlock_lock_internal(SPINLOCK *spinlock, bool cancelable) {
301 - static const struct timespec ns = { .tv_sec = 0, .tv_nsec = 1 };
302 -
231 +static inline void spinlock_lock_internal(SPINLOCK *spinlock) {
232 #ifdef NETDATA_INTERNAL_CHECKS
233 size_t spins = 0;
234 #endif
235
307 - if (!cancelable)
308 - netdata_thread_disable_cancelability();
309 -
236 for(int i = 1;
237 __atomic_load_n(&spinlock->locked, __ATOMIC_RELAXED) ||
238 __atomic_test_and_set(&spinlock->locked, __ATOMIC_ACQUIRE)
@@ -318,7 +244,7 @@ static inline void spinlock_lock_internal(SPINLOCK *spinlock, bool cancelable) {
244 #endif
245 if(unlikely(i == 8)) {
246 i = 0;
321 - nanosleep(&ns, NULL);
247 + tinysleep();
248 }
249 }
250
@@ -326,63 +252,60 @@ static inline void spinlock_lock_internal(SPINLOCK *spinlock, bool cancelable) {
252
253 #ifdef NETDATA_INTERNAL_CHECKS
254 spinlock->spins += spins;
329 - spinlock->locker_pid = gettid();
255 + spinlock->locker_pid = gettid_cached();
256 #endif
257 +
258 + nd_thread_spinlock_locked();
259 }
260
333 -static inline void spinlock_unlock_internal(SPINLOCK *spinlock, bool cancelable) {
261 +static inline void spinlock_unlock_internal(SPINLOCK *spinlock) {
262 #ifdef NETDATA_INTERNAL_CHECKS
263 spinlock->locker_pid = 0;
264 #endif
265 __atomic_clear(&spinlock->locked, __ATOMIC_RELEASE);
266
339 - if (!cancelable)
340 - netdata_thread_enable_cancelability();
267 + nd_thread_spinlock_unlocked();
268 }
269
343 -static inline bool spinlock_trylock_internal(SPINLOCK *spinlock, bool cancelable) {
344 - if (!cancelable)
345 - netdata_thread_disable_cancelability();
346 -
270 +static inline bool spinlock_trylock_internal(SPINLOCK *spinlock) {
271 if(!__atomic_load_n(&spinlock->locked, __ATOMIC_RELAXED) &&
348 - !__atomic_test_and_set(&spinlock->locked, __ATOMIC_ACQUIRE))
272 + !__atomic_test_and_set(&spinlock->locked, __ATOMIC_ACQUIRE)) {
273 // we got the lock
274 + nd_thread_spinlock_locked();
275 return true;
276 + }
277
352 - // we didn't get the lock
353 - if (!cancelable)
354 - netdata_thread_enable_cancelability();
278 return false;
279 }
280
281 void spinlock_lock(SPINLOCK *spinlock)
282 {
360 - spinlock_lock_internal(spinlock, false);
283 + spinlock_lock_internal(spinlock);
284 }
285
286 void spinlock_unlock(SPINLOCK *spinlock)
287 {
365 - spinlock_unlock_internal(spinlock, false);
288 + spinlock_unlock_internal(spinlock);
289 }
290
291 bool spinlock_trylock(SPINLOCK *spinlock)
292 {
370 - return spinlock_trylock_internal(spinlock, false);
293 + return spinlock_trylock_internal(spinlock);
294 }
295
296 void spinlock_lock_cancelable(SPINLOCK *spinlock)
297 {
375 - spinlock_lock_internal(spinlock, true);
298 + spinlock_lock_internal(spinlock);
299 }
300
301 void spinlock_unlock_cancelable(SPINLOCK *spinlock)
302 {
380 - spinlock_unlock_internal(spinlock, true);
303 + spinlock_unlock_internal(spinlock);
304 }
305
306 bool spinlock_trylock_cancelable(SPINLOCK *spinlock)
307 {
385 - return spinlock_trylock_internal(spinlock, true);
308 + return spinlock_trylock_internal(spinlock);
309 }
310
311 // ----------------------------------------------------------------------------
@@ -394,11 +317,11 @@ void rw_spinlock_init(RW_SPINLOCK *rw_spinlock) {
317 }
318
319 void rw_spinlock_read_lock(RW_SPINLOCK *rw_spinlock) {
397 - netdata_thread_disable_cancelability();
398 -
320 spinlock_lock(&rw_spinlock->spinlock);
321 __atomic_add_fetch(&rw_spinlock->readers, 1, __ATOMIC_RELAXED);
322 spinlock_unlock(&rw_spinlock->spinlock);
323 +
324 + nd_thread_rwspinlock_read_locked();
325 }
326
327 void rw_spinlock_read_unlock(RW_SPINLOCK *rw_spinlock) {
@@ -410,12 +333,10 @@ void rw_spinlock_read_unlock(RW_SPINLOCK *rw_spinlock) {
333 fatal("RW_SPINLOCK: readers is negative %d", x);
334 #endif
335
413 - netdata_thread_enable_cancelability();
336 + nd_thread_rwspinlock_read_unlocked();
337 }
338
339 void rw_spinlock_write_lock(RW_SPINLOCK *rw_spinlock) {
417 - static const struct timespec ns = { .tv_sec = 0, .tv_nsec = 1 };
418 -
340 size_t spins = 0;
341 while(1) {
342 spins++;
@@ -426,21 +347,24 @@ void rw_spinlock_write_lock(RW_SPINLOCK *rw_spinlock) {
347
348 // Busy wait until all readers have released their locks.
349 spinlock_unlock(&rw_spinlock->spinlock);
429 - nanosleep(&ns, NULL);
350 + tinysleep();
351 }
352
353 (void)spins;
354 +
355 + nd_thread_rwspinlock_write_locked();
356 }
357
358 void rw_spinlock_write_unlock(RW_SPINLOCK *rw_spinlock) {
359 spinlock_unlock(&rw_spinlock->spinlock);
360 + nd_thread_rwspinlock_write_unlocked();
361 }
362
363 bool rw_spinlock_tryread_lock(RW_SPINLOCK *rw_spinlock) {
364 if(spinlock_trylock(&rw_spinlock->spinlock)) {
365 __atomic_add_fetch(&rw_spinlock->readers, 1, __ATOMIC_RELAXED);
366 spinlock_unlock(&rw_spinlock->spinlock);
443 - netdata_thread_disable_cancelability();
367 + nd_thread_rwspinlock_read_locked();
368 return true;
369 }
370
@@ -451,6 +375,7 @@ bool rw_spinlock_trywrite_lock(RW_SPINLOCK *rw_spinlock) {
375 if(spinlock_trylock(&rw_spinlock->spinlock)) {
376 if (__atomic_load_n(&rw_spinlock->readers, __ATOMIC_RELAXED) == 0) {
377 // No readers, we've successfully acquired the write lock
378 + nd_thread_rwspinlock_write_locked();
379 return true;
380 }
381 else {
@@ -583,7 +508,22 @@ int netdata_rwlock_wrlock_debug(const char *file __maybe_unused, const char *fun
508 return ret;
509 }
510
586 -int netdata_rwlock_unlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
511 +int netdata_rwlock_rdunlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
512 + const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
513 +
514 + netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
515 +
516 + if(unlikely(!locker))
517 + fatal("UNLOCK WITHOUT LOCK");
518 +
519 + int ret = __netdata_rwlock_rdunlock(rwlock);
520 + if(likely(!ret))
521 + remove_rwlock_locker(file, function, line, rwlock, locker);
522 +
523 + return ret;
524 +}
525 +
526 +int netdata_rwlock_wrunlock_debug(const char *file __maybe_unused, const char *function __maybe_unused,
527 const unsigned long line __maybe_unused, netdata_rwlock_t *rwlock) {
528
529 netdata_rwlock_locker *locker = find_rwlock_locker(file, function, line, rwlock);
@@ -591,7 +531,7 @@ int netdata_rwlock_unlock_debug(const char *file __maybe_unused, const char *fun
531 if(unlikely(!locker))
532 fatal("UNLOCK WITHOUT LOCK");
533
594 - int ret = __netdata_rwlock_unlock(rwlock);
534 + int ret = __netdata_rwlock_wrunlock(rwlock);
535 if(likely(!ret))
536 remove_rwlock_locker(file, function, line, rwlock, locker);
537
src/libnetdata/locks/locks.h
+8 -7
@@ -106,13 +106,11 @@ int __netdata_rwlock_destroy(netdata_rwlock_t *rwlock);
106 int __netdata_rwlock_init(netdata_rwlock_t *rwlock);
107 int __netdata_rwlock_rdlock(netdata_rwlock_t *rwlock);
108 int __netdata_rwlock_wrlock(netdata_rwlock_t *rwlock);
109 -int __netdata_rwlock_unlock(netdata_rwlock_t *rwlock);
109 +int __netdata_rwlock_rdunlock(netdata_rwlock_t *rwlock);
110 +int __netdata_rwlock_wrunlock(netdata_rwlock_t *rwlock);
111 int __netdata_rwlock_tryrdlock(netdata_rwlock_t *rwlock);
112 int __netdata_rwlock_trywrlock(netdata_rwlock_t *rwlock);
113
113 -void netdata_thread_disable_cancelability(void);
114 -void netdata_thread_enable_cancelability(void);
115 -
114 #ifdef NETDATA_TRACE_RWLOCKS
115
116 int netdata_mutex_init_debug( const char *file, const char *function, const unsigned long line, netdata_mutex_t *mutex);
@@ -125,7 +123,8 @@ int netdata_rwlock_destroy_debug( const char *file, const char *function, const
123 int netdata_rwlock_init_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
124 int netdata_rwlock_rdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
125 int netdata_rwlock_wrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
128 -int netdata_rwlock_unlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
126 +int netdata_rwlock_rdunlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
127 +int netdata_rwlock_wrunlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
128 int netdata_rwlock_tryrdlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
129 int netdata_rwlock_trywrlock_debug( const char *file, const char *function, const unsigned long line, netdata_rwlock_t *rwlock);
130
@@ -139,7 +138,8 @@ int netdata_rwlock_trywrlock_debug( const char *file, const char *function, cons
138 #define netdata_rwlock_init(rwlock) netdata_rwlock_init_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
139 #define netdata_rwlock_rdlock(rwlock) netdata_rwlock_rdlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
140 #define netdata_rwlock_wrlock(rwlock) netdata_rwlock_wrlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
142 -#define netdata_rwlock_unlock(rwlock) netdata_rwlock_unlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
141 +#define netdata_rwlock_rdunlock(rwlock) netdata_rwlock_rdunlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
142 +#define netdata_rwlock_wrunlock(rwlock) netdata_rwlock_wrunlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
143 #define netdata_rwlock_tryrdlock(rwlock) netdata_rwlock_tryrdlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
144 #define netdata_rwlock_trywrlock(rwlock) netdata_rwlock_trywrlock_debug(__FILE__, __FUNCTION__, __LINE__, rwlock)
145
@@ -155,7 +155,8 @@ int netdata_rwlock_trywrlock_debug( const char *file, const char *function, cons
155 #define netdata_rwlock_init(rwlock) __netdata_rwlock_init(rwlock)
156 #define netdata_rwlock_rdlock(rwlock) __netdata_rwlock_rdlock(rwlock)
157 #define netdata_rwlock_wrlock(rwlock) __netdata_rwlock_wrlock(rwlock)
158 -#define netdata_rwlock_unlock(rwlock) __netdata_rwlock_unlock(rwlock)
158 +#define netdata_rwlock_rdunlock(rwlock) __netdata_rwlock_rdunlock(rwlock)
159 +#define netdata_rwlock_wrunlock(rwlock) __netdata_rwlock_wrunlock(rwlock)
160 #define netdata_rwlock_tryrdlock(rwlock) __netdata_rwlock_tryrdlock(rwlock)
161 #define netdata_rwlock_trywrlock(rwlock) __netdata_rwlock_trywrlock(rwlock)
162
src/libnetdata/log/journal.c
+1 -1
@@ -67,7 +67,7 @@ int journal_direct_fd(const char *path) {
67 return fd;
68 }
69
70 -static inline bool journal_send_with_memfd(int fd, const char *msg, size_t msg_len) {
70 +static inline bool journal_send_with_memfd(int fd __maybe_unused, const char *msg __maybe_unused, size_t msg_len __maybe_unused) {
71 #if defined(__NR_memfd_create) && defined(MFD_ALLOW_SEALING) && defined(F_ADD_SEALS) && defined(F_SEAL_SHRINK) && defined(F_SEAL_GROW) && defined(F_SEAL_WRITE)
72 // Create a memory file descriptor
73 int memfd = (int)syscall(__NR_memfd_create, "journald", MFD_ALLOW_SEALING);
src/libnetdata/log/log.c
+6 -25
@@ -22,8 +22,6 @@
22 #include <systemd/sd-journal.h>
23 #endif
24
25 -#include <syslog.h>
26 -
25 const char *program_name = "";
26
27 uint64_t debug_flags = 0;
@@ -368,7 +366,7 @@ struct nd_log_source {
366 };
367
368 static struct {
371 - uuid_t invocation_id;
369 + nd_uuid_t invocation_id;
370
371 ND_LOG_SOURCES overwrite_process_source;
372
@@ -1599,7 +1597,7 @@ static bool needs_quotes_for_logfmt(const char *s)
1597 return true;
1598
1599 while(*s) {
1602 - if(*s == '=' || isspace(*s) || !safe_for_logfmt[(uint8_t)*s])
1600 + if(*s == '=' || isspace((uint8_t)*s) || !safe_for_logfmt[(uint8_t)*s])
1601 return true;
1602
1603 s++;
@@ -1733,7 +1731,7 @@ bool nd_log_journal_socket_available(void) {
1731 return is_path_unix_socket("/run/systemd/journal/socket");
1732 }
1733
1736 -static bool nd_logger_journal_libsystemd(struct log_field *fields, size_t fields_max) {
1734 +static bool nd_logger_journal_libsystemd(struct log_field *fields __maybe_unused, size_t fields_max __maybe_unused) {
1735 #ifdef HAVE_SYSTEMD
1736
1737 // --- FIELD_PARSER_VERSIONS ---
@@ -2153,17 +2151,10 @@ static void nd_logger(const char *file, const char *function, const unsigned lon
2151 }
2152
2153 if(likely(!thread_log_fields[NDF_TID].entry.set))
2156 - thread_log_fields[NDF_TID].entry = ND_LOG_FIELD_U64(NDF_TID, gettid());
2154 + thread_log_fields[NDF_TID].entry = ND_LOG_FIELD_U64(NDF_TID, gettid_cached());
2155
2158 - char os_threadname[NETDATA_THREAD_NAME_MAX + 1];
2156 if(likely(!thread_log_fields[NDF_THREAD_TAG].entry.set)) {
2160 - const char *thread_tag = netdata_thread_tag();
2161 - if (!netdata_thread_tag_exists()) {
2162 - os_thread_get_current_name_np(os_threadname);
2163 - if ('\0' != os_threadname[0])
2164 - /* If it is not an empty string replace "MAIN" thread_tag */
2165 - thread_tag = os_threadname;
2166 - }
2157 + const char *thread_tag = nd_thread_tag();
2158 thread_log_fields[NDF_THREAD_TAG].entry = ND_LOG_FIELD_TXT(NDF_THREAD_TAG, thread_tag);
2159
2160 // TODO: fix the ND_MODULE in logging by setting proper module name in threads
@@ -2303,17 +2294,7 @@ void netdata_logger_fatal( const char *file, const char *function, const unsigne
2294 char action_data[70+1];
2295 snprintfz(action_data, 70, "%04lu@%-10.10s:%-15.15s/%d", line, file, function, saved_errno);
2296
2306 - char os_threadname[NETDATA_THREAD_NAME_MAX + 1];
2307 - const char *thread_tag = netdata_thread_tag();
2308 - if (!netdata_thread_tag_exists()) {
2309 - os_thread_get_current_name_np(os_threadname);
2310 - if ('\0' != os_threadname[0])
2311 - /* If it is not an empty string replace "MAIN" thread_tag */
2312 - thread_tag = os_threadname;
2313 - }
2314 - if(!thread_tag)
2315 - thread_tag = "UNKNOWN";
2316 -
2297 + const char *thread_tag = nd_thread_tag();
2298 const char *tag_to_send = thread_tag;
2299
2300 // anonymize thread names
src/libnetdata/log/log.h
+1 -1
@@ -170,7 +170,7 @@ struct log_stack_entry {
170 uint64_t u64;
171 int64_t i64;
172 double dbl;
173 - const uuid_t *uuid;
173 + const nd_uuid_t *uuid;
174 struct {
175 log_formatter_callback_t formatter;
176 void *formatter_data;
src/libnetdata/maps/local-sockets.h
+1 -1
@@ -203,7 +203,7 @@ typedef struct local_socket {
203
204 // --------------------------------------------------------------------------------------------------------------------
205
206 -static inline void local_sockets_log(LS_STATE *ls, const char *format, ...) __attribute__ ((format(__printf__, 2, 3)));
206 +static inline void local_sockets_log(LS_STATE *ls, const char *format, ...) PRINTFLIKE(2, 3);
207 static inline void local_sockets_log(LS_STATE *ls, const char *format, ...) {
208 if(++ls->stats.errors_encountered == ls->config.max_errors) {
209 nd_log(NDLS_COLLECTORS, NDLP_ERR, "LOCAL-SOCKETS: max number of logs reached. Not logging anymore");
src/libnetdata/os.c deleted
-300
@@ -1,300 +0,0 @@
1 -// SPDX-License-Identifier: GPL-3.0-or-later
2 -
3 -#include "os.h"
4 -
5 -// ----------------------------------------------------------------------------
6 -// system functions
7 -// to retrieve settings of the system
8 -
9 -#define CPUS_FOR_COLLECTORS 0
10 -#define CPUS_FOR_NETDATA 1
11 -
12 -long get_system_cpus_with_cache(bool cache, bool for_netdata) {
13 - static long processors[2] = { 0, 0 };
14 -
15 - int index = for_netdata ? CPUS_FOR_NETDATA : CPUS_FOR_COLLECTORS;
16 -
17 - if(likely(cache && processors[index] > 0))
18 - return processors[index];
19 -
20 -#if defined(__APPLE__) || defined(__FreeBSD__)
21 -#if defined(__APPLE__)
22 -#define HW_CPU_NAME "hw.logicalcpu"
23 -#else
24 -#define HW_CPU_NAME "hw.ncpu"
25 -#endif
26 -
27 - int32_t tmp_processors;
28 - bool error = false;
29 -
30 - if (unlikely(GETSYSCTL_BY_NAME(HW_CPU_NAME, tmp_processors)))
31 - error = true;
32 - else
33 - processors[index] = tmp_processors;
34 -
35 - if(processors[index] < 1) {
36 - processors[index] = 1;
37 -
38 - if(error)
39 - netdata_log_error("Assuming system has %d processors.", processors[index]);
40 - }
41 -
42 - return processors[index];
43 -#else
44 -
45 - char filename[FILENAME_MAX + 1];
46 - snprintfz(filename, FILENAME_MAX, "%s/proc/stat",
47 - (!for_netdata && netdata_configured_host_prefix) ? netdata_configured_host_prefix : "");
48 -
49 - procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
50 - if(!ff) {
51 - processors[index] = 1;
52 - netdata_log_error("Cannot open file '%s'. Assuming system has %ld processors.", filename, processors[index]);
53 - return processors[index];
54 - }
55 -
56 - ff = procfile_readall(ff);
57 - if(!ff) {
58 - processors[index] = 1;
59 - netdata_log_error("Cannot open file '%s'. Assuming system has %ld processors.", filename, processors[index]);
60 - return processors[index];
61 - }
62 -
63 - long tmp_processors = 0;
64 - unsigned int i;
65 - for(i = 0; i < procfile_lines(ff); i++) {
66 - if(!procfile_linewords(ff, i)) continue;
67 -
68 - if(strncmp(procfile_lineword(ff, i, 0), "cpu", 3) == 0)
69 - tmp_processors++;
70 - }
71 - procfile_close(ff);
72 -
73 - processors[index] = --tmp_processors;
74 -
75 - if(processors[index] < 1)
76 - processors[index] = 1;
77 -
78 - netdata_log_debug(D_SYSTEM, "System has %ld processors.", processors[index]);
79 - return processors[index];
80 -
81 -#endif /* __APPLE__, __FreeBSD__ */
82 -}
83 -
84 -pid_t pid_max = 32768;
85 -pid_t get_system_pid_max(void) {
86 -#ifdef __APPLE__
87 - // As we currently do not know a solution to query pid_max from the os
88 - // we use the number defined in bsd/sys/proc_internal.h in XNU sources
89 - pid_max = 99999;
90 - return pid_max;
91 -#elif __FreeBSD__
92 - int32_t tmp_pid_max;
93 -
94 - if (unlikely(GETSYSCTL_BY_NAME("kern.pid_max", tmp_pid_max))) {
95 - pid_max = 99999;
96 - netdata_log_error("Assuming system's maximum pid is %d.", pid_max);
97 - } else {
98 - pid_max = tmp_pid_max;
99 - }
100 -
101 - return pid_max;
102 -#else
103 -
104 - static char read = 0;
105 - if(unlikely(read)) return pid_max;
106 - read = 1;
107 -
108 - char filename[FILENAME_MAX + 1];
109 - snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", netdata_configured_host_prefix?netdata_configured_host_prefix:"");
110 -
111 - unsigned long long max = 0;
112 - if(read_single_number_file(filename, &max) != 0) {
113 - netdata_log_error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max);
114 - return pid_max;
115 - }
116 -
117 - if(!max) {
118 - netdata_log_error("Cannot parse file '%s'. Assuming system supports %d pids.", filename, pid_max);
119 - return pid_max;
120 - }
121 -
122 - pid_max = (pid_t) max;
123 - return pid_max;
124 -
125 -#endif /* __APPLE__, __FreeBSD__ */
126 -}
127 -
128 -unsigned int system_hz;
129 -void get_system_HZ(void) {
130 - long ticks;
131 -
132 - if ((ticks = sysconf(_SC_CLK_TCK)) == -1) {
133 - netdata_log_error("Cannot get system clock ticks");
134 - }
135 -
136 - system_hz = (unsigned int) ticks;
137 -}
138 -
139 -static inline unsigned long cpuset_str2ul(char **s) {
140 - unsigned long n = 0;
141 - char c;
142 - for(c = **s; c >= '0' && c <= '9' ; c = *(++*s)) {
143 - n *= 10;
144 - n += c - '0';
145 - }
146 - return n;
147 -}
148 -
149 -unsigned long read_cpuset_cpus(const char *filename, long system_cpus) {
150 - static char *buf = NULL;
151 - static size_t buf_size = 0;
152 -
153 - if(!buf) {
154 - buf_size = 100U + 6 * system_cpus + 1; // taken from kernel/cgroup/cpuset.c
155 - buf = mallocz(buf_size);
156 - }
157 -
158 - int ret = read_txt_file(filename, buf, buf_size);
159 -
160 - if(!ret) {
161 - char *s = buf;
162 - unsigned long ncpus = 0;
163 -
164 - // parse the cpuset string and calculate the number of cpus the cgroup is allowed to use
165 - while (*s) {
166 - if (isspace(*s)) {
167 - s++;
168 - continue;
169 - }
170 - unsigned long n = cpuset_str2ul(&s);
171 - ncpus++;
172 - if(*s == ',') {
173 - s++;
174 - continue;
175 - }
176 - if(*s == '-') {
177 - s++;
178 - unsigned long m = cpuset_str2ul(&s);
179 - ncpus += m - n; // calculate the number of cpus in the region
180 - }
181 - s++;
182 - }
183 -
184 - if(!ncpus)
185 - return 0;
186 -
187 - return ncpus;
188 - }
189 -
190 - return 0;
191 -}
192 -
193 -// =====================================================================================================================
194 -// FreeBSD
195 -
196 -#if __FreeBSD__
197 -
198 -const char *os_type = "freebsd";
199 -
200 -int getsysctl_by_name(const char *name, void *ptr, size_t len) {
201 - size_t nlen = len;
202 -
203 - if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
204 - netdata_log_error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
205 - return 1;
206 - }
207 - if (unlikely(nlen != len)) {
208 - netdata_log_error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
209 - return 1;
210 - }
211 - return 0;
212 -}
213 -
214 -int getsysctl_simple(const char *name, int *mib, size_t miblen, void *ptr, size_t len) {
215 - size_t nlen = len;
216 -
217 - if (unlikely(!mib[0]))
218 - if (unlikely(getsysctl_mib(name, mib, miblen)))
219 - return 1;
220 -
221 - if (unlikely(sysctl(mib, miblen, ptr, &nlen, NULL, 0) == -1)) {
222 - netdata_log_error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
223 - return 1;
224 - }
225 - if (unlikely(nlen != len)) {
226 - netdata_log_error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
227 - return 1;
228 - }
229 -
230 - return 0;
231 -}
232 -
233 -int getsysctl(const char *name, int *mib, size_t miblen, void *ptr, size_t *len) {
234 - size_t nlen = *len;
235 -
236 - if (unlikely(!mib[0]))
237 - if (unlikely(getsysctl_mib(name, mib, miblen)))
238 - return 1;
239 -
240 - if (unlikely(sysctl(mib, miblen, ptr, len, NULL, 0) == -1)) {
241 - netdata_log_error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
242 - return 1;
243 - }
244 - if (unlikely(ptr != NULL && nlen != *len)) {
245 - netdata_log_error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)*len, (unsigned long)nlen);
246 - return 1;
247 - }
248 -
249 - return 0;
250 -}
251 -
252 -int getsysctl_mib(const char *name, int *mib, size_t len) {
253 - size_t nlen = len;
254 -
255 - if (unlikely(sysctlnametomib(name, mib, &nlen) == -1)) {
256 - netdata_log_error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
257 - return 1;
258 - }
259 - if (unlikely(nlen != len)) {
260 - netdata_log_error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
261 - return 1;
262 - }
263 - return 0;
264 -}
265 -
266 -
267 -#endif
268 -
269 -
270 -// =====================================================================================================================
271 -// MacOS
272 -
273 -#if __APPLE__
274 -
275 -const char *os_type = "macos";
276 -
277 -int getsysctl_by_name(const char *name, void *ptr, size_t len) {
278 - size_t nlen = len;
279 -
280 - if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
281 - netdata_log_error("MACOS: sysctl(%s...) failed: %s", name, strerror(errno));
282 - return 1;
283 - }
284 - if (unlikely(nlen != len)) {
285 - netdata_log_error("MACOS: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
286 - return 1;
287 - }
288 - return 0;
289 -}
290 -
291 -#endif
292 -
293 -// =====================================================================================================================
294 -// Linux
295 -
296 -#if __linux__
297 -
298 -const char *os_type = "linux";
299 -
300 -#endif
src/libnetdata/os.h deleted
-70
@@ -1,70 +0,0 @@
1 -// SPDX-License-Identifier: GPL-3.0-or-later
2 -
3 -#ifndef NETDATA_OS_H
4 -#define NETDATA_OS_H
5 -
6 -#include "libnetdata.h"
7 -
8 -// =====================================================================================================================
9 -// FreeBSD
10 -
11 -#if __FreeBSD__
12 -
13 -#include <sys/sysctl.h>
14 -
15 -#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
16 -int getsysctl_by_name(const char *name, void *ptr, size_t len);
17 -
18 -#define GETSYSCTL_MIB(name, mib) getsysctl_mib(name, mib, sizeof(mib)/sizeof(int))
19 -
20 -int getsysctl_mib(const char *name, int *mib, size_t len);
21 -
22 -#define GETSYSCTL_SIMPLE(name, mib, var) getsysctl_simple(name, mib, sizeof(mib)/sizeof(int), &(var), sizeof(var))
23 -#define GETSYSCTL_WSIZE(name, mib, var, size) getsysctl_simple(name, mib, sizeof(mib)/sizeof(int), var, size)
24 -
25 -int getsysctl_simple(const char *name, int *mib, size_t miblen, void *ptr, size_t len);
26 -
27 -#define GETSYSCTL_SIZE(name, mib, size) getsysctl(name, mib, sizeof(mib)/sizeof(int), NULL, &(size))
28 -#define GETSYSCTL(name, mib, var, size) getsysctl(name, mib, sizeof(mib)/sizeof(int), &(var), &(size))
29 -
30 -int getsysctl(const char *name, int *mib, size_t miblen, void *ptr, size_t *len);
31 -
32 -#endif
33 -
34 -// =====================================================================================================================
35 -// MacOS
36 -
37 -#if __APPLE__
38 -
39 -#include <sys/sysctl.h>
40 -#include "byteorder.h"
41 -
42 -#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
43 -int getsysctl_by_name(const char *name, void *ptr, size_t len);
44 -
45 -#endif
46 -
47 -// =====================================================================================================================
48 -// common defs for Apple/FreeBSD/Linux
49 -
50 -extern const char *os_type;
51 -
52 -#define get_system_cpus() get_system_cpus_with_cache(true, false)
53 -#define get_system_cpus_uncached() get_system_cpus_with_cache(false, false)
54 -long get_system_cpus_with_cache(bool cache, bool for_netdata);
55 -unsigned long read_cpuset_cpus(const char *filename, long system_cpus);
56 -
57 -extern pid_t pid_max;
58 -pid_t get_system_pid_max(void);
59 -
60 -extern unsigned int system_hz;
61 -void get_system_HZ(void);
62 -
63 -#include <sys/timex.h>
64 -#if defined(__FreeBSD__) || defined(__APPLE__)
65 -#define ADJUST_TIMEX(x) ntp_adjtime(x)
66 -#else
67 -#define ADJUST_TIMEX(x) adjtimex(x)
68 -#endif
69 -
70 -#endif //NETDATA_OS_H
src/libnetdata/os/adjtimex.c new
+16
@@ -0,0 +1,16 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +int os_adjtimex(struct timex *buf __maybe_unused) {
6 +#if defined(COMPILED_FOR_MACOS) || defined(COMPILED_FOR_FREEBSD)
7 + return ntp_adjtime(buf);
8 +#endif
9 +
10 +#if defined(COMPILED_FOR_LINUX)
11 + return adjtimex(buf);
12 +#endif
13 +
14 + errno = ENOSYS;
15 + return -1;
16 +}
src/libnetdata/os/adjtimex.h new
+13
@@ -0,0 +1,13 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_ADJTIMEX_H
4 +#define NETDATA_ADJTIMEX_H
5 +
6 +#if defined(COMPILED_FOR_LINUX) || defined(COMPILED_FOR_FREEBSD) || defined(COMPILED_FOR_MACOS)
7 +#include <sys/timex.h>
8 +#endif
9 +
10 +struct timex;
11 +int os_adjtimex(struct timex *buf);
12 +
13 +#endif //NETDATA_ADJTIMEX_H
src/libnetdata/os/byteorder.h renamed
src/libnetdata/os/get_pid_max.c new
+58
@@ -0,0 +1,58 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +pid_t pid_max = 32768;
6 +pid_t os_get_system_pid_max(void) {
7 +#if defined(COMPILED_FOR_MACOS)
8 +
9 + // As we currently do not know a solution to query pid_max from the os
10 + // we use the number defined in bsd/sys/proc_internal.h in XNU sources
11 + pid_max = 99999;
12 + return pid_max;
13 +
14 +#elif defined(COMPILED_FOR_FREEBSD)
15 +
16 + int32_t tmp_pid_max;
17 +
18 + if (unlikely(GETSYSCTL_BY_NAME("kern.pid_max", tmp_pid_max))) {
19 + pid_max = 99999;
20 + netdata_log_error("Assuming system's maximum pid is %d.", pid_max);
21 + } else {
22 + pid_max = tmp_pid_max;
23 + }
24 +
25 + return pid_max;
26 +
27 +#elif defined(COMPILED_FOR_LINUX)
28 +
29 + static char read = 0;
30 + if(unlikely(read)) return pid_max;
31 + read = 1;
32 +
33 + char filename[FILENAME_MAX + 1];
34 + snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", netdata_configured_host_prefix?netdata_configured_host_prefix:"");
35 +
36 + unsigned long long max = 0;
37 + if(read_single_number_file(filename, &max) != 0) {
38 + netdata_log_error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max);
39 + return pid_max;
40 + }
41 +
42 + if(!max) {
43 + netdata_log_error("Cannot parse file '%s'. Assuming system supports %d pids.", filename, pid_max);
44 + return pid_max;
45 + }
46 +
47 + pid_max = (pid_t) max;
48 + return pid_max;
49 +
50 +#else
51 +
52 + // just a big default
53 +
54 + pid_max = 4194304;
55 + return pid_max;
56 +
57 +#endif
58 +}
src/libnetdata/os/get_pid_max.h new
+11
@@ -0,0 +1,11 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_GET_PID_MAX_H
4 +#define NETDATA_GET_PID_MAX_H
5 +
6 +#include <unistd.h>
7 +
8 +extern pid_t pid_max;
9 +pid_t os_get_system_pid_max(void);
10 +
11 +#endif //NETDATA_GET_PID_MAX_H
src/libnetdata/os/get_system_cpus.c new
+93
@@ -0,0 +1,93 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +#if defined(COMPILED_FOR_WINDOWS)
6 +#include <windows.h>
7 +#endif
8 +
9 +#define CPUS_FOR_COLLECTORS 0
10 +#define CPUS_FOR_NETDATA 1
11 +
12 +long os_get_system_cpus_cached(bool cache, bool for_netdata) {
13 + static long processors[2] = { 0, 0 };
14 +
15 + int index = for_netdata ? CPUS_FOR_NETDATA : CPUS_FOR_COLLECTORS;
16 +
17 + if(likely(cache && processors[index] > 0))
18 + return processors[index];
19 +
20 +#if defined(COMPILED_FOR_FREEBSD) || defined(COMPILED_FOR_MACOS)
21 +#if defined(COMPILED_FOR_MACOS)
22 +#define HW_CPU_NAME "hw.logicalcpu"
23 +#else
24 +#define HW_CPU_NAME "hw.ncpu"
25 +#endif
26 +
27 + int32_t tmp_processors;
28 + bool error = false;
29 +
30 + if (unlikely(GETSYSCTL_BY_NAME(HW_CPU_NAME, tmp_processors)))
31 + error = true;
32 + else
33 + processors[index] = tmp_processors;
34 +
35 + if(processors[index] < 1) {
36 + processors[index] = 1;
37 +
38 + if(error)
39 + netdata_log_error("Assuming system has %ld processors.", processors[index]);
40 + }
41 +
42 + return processors[index];
43 +#elif defined(COMPILED_FOR_LINUX)
44 +
45 + char filename[FILENAME_MAX + 1];
46 + snprintfz(filename, FILENAME_MAX, "%s/proc/stat",
47 + (!for_netdata && netdata_configured_host_prefix) ? netdata_configured_host_prefix : "");
48 +
49 + procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
50 + if(!ff) {
51 + processors[index] = 1;
52 + netdata_log_error("Cannot open file '%s'. Assuming system has %ld processors.", filename, processors[index]);
53 + return processors[index];
54 + }
55 +
56 + ff = procfile_readall(ff);
57 + if(!ff) {
58 + processors[index] = 1;
59 + netdata_log_error("Cannot open file '%s'. Assuming system has %ld processors.", filename, processors[index]);
60 + return processors[index];
61 + }
62 +
63 + long tmp_processors = 0;
64 + unsigned int i;
65 + for(i = 0; i < procfile_lines(ff); i++) {
66 + if(!procfile_linewords(ff, i)) continue;
67 +
68 + if(strncmp(procfile_lineword(ff, i, 0), "cpu", 3) == 0)
69 + tmp_processors++;
70 + }
71 + procfile_close(ff);
72 +
73 + processors[index] = --tmp_processors;
74 +
75 + if(processors[index] < 1)
76 + processors[index] = 1;
77 +
78 + netdata_log_debug(D_SYSTEM, "System has %ld processors.", processors[index]);
79 + return processors[index];
80 +
81 +#elif defined(COMPILED_FOR_WINDOWS)
82 +
83 + SYSTEM_INFO sysInfo;
84 + GetSystemInfo(&sysInfo);
85 + return (long) sysInfo.dwNumberOfProcessors;
86 +
87 +#else
88 +
89 + processors[index] = 1;
90 + return processors[index];
91 +
92 +#endif
93 +}
src/libnetdata/os/get_system_cpus.h new
+10
@@ -0,0 +1,10 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_GET_SYSTEM_CPUS_H
4 +#define NETDATA_GET_SYSTEM_CPUS_H
5 +
6 +#include "../libnetdata.h"
7 +
8 +long os_get_system_cpus_cached(bool cache, bool for_netdata);
9 +
10 +#endif //NETDATA_GET_SYSTEM_CPUS_H
src/libnetdata/os/getgrouplist.c new
+16
@@ -0,0 +1,16 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +int os_getgrouplist(const char *username __maybe_unused, gid_t gid __maybe_unused, gid_t *supplementary_groups __maybe_unused, int *ngroups __maybe_unused) {
6 +#if defined(COMPILED_FOR_LINUX) || defined(COMPILED_FOR_FREEBSD)
7 + return getgrouplist(username, gid, supplementary_groups, ngroups);
8 +#endif
9 +
10 +#if defined(COMPILED_FOR_MACOS)
11 + return getgrouplist(username, gid, (int *)supplementary_groups, ngroups);
12 +#endif
13 +
14 + errno = ENOSYS;
15 + return -1;
16 +}
src/libnetdata/os/getgrouplist.h new
+9
@@ -0,0 +1,9 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_GETGROUPLIST_H
4 +#define NETDATA_GETGROUPLIST_H
5 +
6 +#include <unistd.h>
7 +int os_getgrouplist(const char *username, gid_t gid, gid_t *supplementary_groups, int *ngroups);
8 +
9 +#endif //NETDATA_GETGROUPLIST_H
src/libnetdata/os/gettid.c new
+33
@@ -0,0 +1,33 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +#if defined(COMPILED_FOR_WINDOWS)
6 +#include <windows.h>
7 +#endif
8 +
9 +pid_t os_gettid(void) {
10 +#if defined(HAVE_GETTID)
11 + return gettid();
12 +#elif defined(HAVE_PTHREAD_GETTHREADID_NP)
13 + return (pid_t)pthread_getthreadid_np();
14 +#elif defined(HAVE_PTHREAD_THREADID_NP)
15 + uint64_t curthreadid;
16 + pthread_threadid_np(NULL, &curthreadid);
17 + return curthreadid;
18 +#elif defined(COMPILED_FOR_WINDOWS)
19 + return (pid_t)GetCurrentThreadId();
20 +#elif defined(COMPILED_FOR_LINUX)
21 + return (pid_t)syscall(SYS_gettid);
22 +#else
23 + return (pid_t)pthread_self();
24 +#endif
25 +}
26 +
27 +static __thread pid_t gettid_cached_tid = 0;
28 +pid_t gettid_cached(void) {
29 + if(unlikely(gettid_cached_tid == 0))
30 + gettid_cached_tid = os_gettid();
31 +
32 + return gettid_cached_tid;
33 +}
\ No newline at end of file
src/libnetdata/os/gettid.h new
+11
@@ -0,0 +1,11 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_GETTID_H
4 +#define NETDATA_GETTID_H
5 +
6 +#include <unistd.h>
7 +
8 +pid_t os_gettid(void);
9 +pid_t gettid_cached(void);
10 +
11 +#endif //NETDATA_GETTID_H
src/libnetdata/os/os-freebsd-wrappers.c new
+73
@@ -0,0 +1,73 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +#if defined(COMPILED_FOR_FREEBSD)
6 +
7 +int getsysctl_by_name(const char *name, void *ptr, size_t len) {
8 + size_t nlen = len;
9 +
10 + if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
11 + netdata_log_error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
12 + return 1;
13 + }
14 + if (unlikely(nlen != len)) {
15 + netdata_log_error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
16 + return 1;
17 + }
18 + return 0;
19 +}
20 +
21 +int getsysctl_simple(const char *name, int *mib, size_t miblen, void *ptr, size_t len) {
22 + size_t nlen = len;
23 +
24 + if (unlikely(!mib[0]))
25 + if (unlikely(getsysctl_mib(name, mib, miblen)))
26 + return 1;
27 +
28 + if (unlikely(sysctl(mib, miblen, ptr, &nlen, NULL, 0) == -1)) {
29 + netdata_log_error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
30 + return 1;
31 + }
32 + if (unlikely(nlen != len)) {
33 + netdata_log_error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
34 + return 1;
35 + }
36 +
37 + return 0;
38 +}
39 +
40 +int getsysctl(const char *name, int *mib, size_t miblen, void *ptr, size_t *len) {
41 + size_t nlen = *len;
42 +
43 + if (unlikely(!mib[0]))
44 + if (unlikely(getsysctl_mib(name, mib, miblen)))
45 + return 1;
46 +
47 + if (unlikely(sysctl(mib, miblen, ptr, len, NULL, 0) == -1)) {
48 + netdata_log_error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
49 + return 1;
50 + }
51 + if (unlikely(ptr != NULL && nlen != *len)) {
52 + netdata_log_error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)*len, (unsigned long)nlen);
53 + return 1;
54 + }
55 +
56 + return 0;
57 +}
58 +
59 +int getsysctl_mib(const char *name, int *mib, size_t len) {
60 + size_t nlen = len;
61 +
62 + if (unlikely(sysctlnametomib(name, mib, &nlen) == -1)) {
63 + netdata_log_error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
64 + return 1;
65 + }
66 + if (unlikely(nlen != len)) {
67 + netdata_log_error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
68 + return 1;
69 + }
70 + return 0;
71 +}
72 +
73 +#endif
src/libnetdata/os/os-freebsd-wrappers.h new
+29
@@ -0,0 +1,29 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_OS_FREEBSD_WRAPPERS_H
4 +#define NETDATA_OS_FREEBSD_WRAPPERS_H
5 +
6 +#include "../libnetdata.h"
7 +
8 +#if defined(COMPILED_FOR_FREEBSD)
9 +#include <sys/sysctl.h>
10 +
11 +#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
12 +int getsysctl_by_name(const char *name, void *ptr, size_t len);
13 +
14 +#define GETSYSCTL_MIB(name, mib) getsysctl_mib(name, mib, sizeof(mib)/sizeof(int))
15 +
16 +int getsysctl_mib(const char *name, int *mib, size_t len);
17 +
18 +#define GETSYSCTL_SIMPLE(name, mib, var) getsysctl_simple(name, mib, sizeof(mib)/sizeof(int), &(var), sizeof(var))
19 +#define GETSYSCTL_WSIZE(name, mib, var, size) getsysctl_simple(name, mib, sizeof(mib)/sizeof(int), var, size)
20 +
21 +int getsysctl_simple(const char *name, int *mib, size_t miblen, void *ptr, size_t len);
22 +
23 +#define GETSYSCTL_SIZE(name, mib, size) getsysctl(name, mib, sizeof(mib)/sizeof(int), NULL, &(size))
24 +#define GETSYSCTL(name, mib, var, size) getsysctl(name, mib, sizeof(mib)/sizeof(int), &(var), &(size))
25 +
26 +int getsysctl(const char *name, int *mib, size_t miblen, void *ptr, size_t *len);
27 +#endif
28 +
29 +#endif //NETDATA_OS_FREEBSD_WRAPPERS_H
src/libnetdata/os/os-macos-wrappers.c new
+21
@@ -0,0 +1,21 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +#if defined(COMPILED_FOR_MACOS)
6 +
7 +int getsysctl_by_name(const char *name, void *ptr, size_t len) {
8 + size_t nlen = len;
9 +
10 + if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
11 + netdata_log_error("MACOS: sysctl(%s...) failed: %s", name, strerror(errno));
12 + return 1;
13 + }
14 + if (unlikely(nlen != len)) {
15 + netdata_log_error("MACOS: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
16 + return 1;
17 + }
18 + return 0;
19 +}
20 +
21 +#endif
src/libnetdata/os/os-macos-wrappers.h new
+17
@@ -0,0 +1,17 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_OS_MACOS_WRAPPERS_H
4 +#define NETDATA_OS_MACOS_WRAPPERS_H
5 +
6 +#include "../libnetdata.h"
7 +
8 +#if defined(COMPILED_FOR_MACOS)
9 +#include <sys/sysctl.h>
10 +#include "byteorder.h"
11 +
12 +#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
13 +int getsysctl_by_name(const char *name, void *ptr, size_t len);
14 +
15 +#endif
16 +
17 +#endif //NETDATA_OS_MACOS_WRAPPERS_H
src/libnetdata/os/os.c new
+92
@@ -0,0 +1,92 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +// ----------------------------------------------------------------------------
6 +// system functions
7 +// to retrieve settings of the system
8 +
9 +unsigned int system_hz;
10 +void os_get_system_HZ(void) {
11 + long ticks;
12 +
13 + if ((ticks = sysconf(_SC_CLK_TCK)) == -1) {
14 + netdata_log_error("Cannot get system clock ticks");
15 + }
16 +
17 + system_hz = (unsigned int) ticks;
18 +}
19 +
20 +static inline unsigned long cpuset_str2ul(char **s) {
21 + unsigned long n = 0;
22 + char c;
23 + for(c = **s; c >= '0' && c <= '9' ; c = *(++*s)) {
24 + n *= 10;
25 + n += c - '0';
26 + }
27 + return n;
28 +}
29 +
30 +unsigned long os_read_cpuset_cpus(const char *filename, long system_cpus) {
31 + static char *buf = NULL;
32 + static size_t buf_size = 0;
33 +
34 + if(!buf) {
35 + buf_size = 100U + 6 * system_cpus + 1; // taken from kernel/cgroup/cpuset.c
36 + buf = mallocz(buf_size);
37 + }
38 +
39 + int ret = read_txt_file(filename, buf, buf_size);
40 +
41 + if(!ret) {
42 + char *s = buf;
43 + unsigned long ncpus = 0;
44 +
45 + // parse the cpuset string and calculate the number of cpus the cgroup is allowed to use
46 + while (*s) {
47 + if (isspace((uint8_t)*s)) {
48 + s++;
49 + continue;
50 + }
51 + unsigned long n = cpuset_str2ul(&s);
52 + ncpus++;
53 + if(*s == ',') {
54 + s++;
55 + continue;
56 + }
57 + if(*s == '-') {
58 + s++;
59 + unsigned long m = cpuset_str2ul(&s);
60 + ncpus += m - n; // calculate the number of cpus in the region
61 + }
62 + s++;
63 + }
64 +
65 + if(!ncpus)
66 + return 0;
67 +
68 + return ncpus;
69 + }
70 +
71 + return 0;
72 +}
73 +
74 +// =====================================================================================================================
75 +// os_type
76 +
77 +#if defined(COMPILED_FOR_LINUX)
78 +const char *os_type = "linux";
79 +#endif
80 +
81 +#if defined(COMPILED_FOR_FREEBSD)
82 +const char *os_type = "freebsd";
83 +#endif
84 +
85 +#if defined(COMPILED_FOR_MACOS)
86 +const char *os_type = "macos";
87 +#endif
88 +
89 +#if defined(COMPILED_FOR_WINDOWS)
90 +const char *os_type = "windows";
91 +#endif
92 +
src/libnetdata/os/os.h new
+37
@@ -0,0 +1,37 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_OS_H
4 +#define NETDATA_OS_H
5 +
6 +#if defined(COMPILED_FOR_LINUX) || defined(COMPILED_FOR_FREEBSD) || defined(COMPILED_FOR_MACOS)
7 +#include <sys/syscall.h>
8 +#endif
9 +
10 +#include "setresuid.h"
11 +#include "setresgid.h"
12 +#include "getgrouplist.h"
13 +#include "adjtimex.h"
14 +#include "gettid.h"
15 +#include "waitid.h"
16 +#include "get_pid_max.h"
17 +#include "get_system_cpus.h"
18 +#include "tinysleep.h"
19 +#include "uuid_generate.h"
20 +#include "setenv.h"
21 +#include "os-freebsd-wrappers.h"
22 +#include "os-macos-wrappers.h"
23 +
24 +// =====================================================================================================================
25 +// common defs for Apple/FreeBSD/Linux
26 +
27 +extern const char *os_type;
28 +
29 +#define os_get_system_cpus() os_get_system_cpus_cached(true, false)
30 +#define os_get_system_cpus_uncached() os_get_system_cpus_cached(false, false)
31 +long os_get_system_cpus_cached(bool cache, bool for_netdata);
32 +unsigned long os_read_cpuset_cpus(const char *filename, long system_cpus);
33 +
34 +extern unsigned int system_hz;
35 +void os_get_system_HZ(void);
36 +
37 +#endif //NETDATA_OS_H
src/libnetdata/os/setenv.c new
+30
@@ -0,0 +1,30 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "config.h"
4 +
5 +#ifndef HAVE_SETENV
6 +
7 +#include <stdio.h>
8 +#include <stdlib.h>
9 +#include <string.h>
10 +
11 +int os_setenv(const char *name, const char *value, int overwrite) {
12 + char *env_var;
13 + int result;
14 +
15 + if (!overwrite) {
16 + env_var = getenv(name);
17 + if (env_var) return 0; // Already set
18 + }
19 +
20 + size_t len = strlen(name) + strlen(value) + 2; // +2 for '=' and '\0'
21 + env_var = malloc(len);
22 + if (!env_var) return -1; // Allocation failure
23 + snprintf(env_var, len, "%s=%s", name, value);
24 +
25 + result = putenv(env_var);
26 + // free(env_var); // _putenv in Windows makes a copy of the string
27 + return result;
28 +}
29 +
30 +#endif
src/libnetdata/os/setenv.h new
+13
@@ -0,0 +1,13 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_SETENV_H
4 +#define NETDATA_SETENV_H
5 +
6 +#include "config.h"
7 +
8 +#ifndef HAVE_SETENV
9 +int os_setenv(const char *name, const char *value, int overwrite);
10 +#define setenv(name, value, overwrite) os_setenv(name, value, overwrite)
11 +#endif
12 +
13 +#endif //NETDATA_SETENV_H
src/libnetdata/os/setresgid.c new
+16
@@ -0,0 +1,16 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +int os_setresgid(gid_t gid __maybe_unused, gid_t egid __maybe_unused, gid_t sgid __maybe_unused) {
6 +#if defined(COMPILED_FOR_LINUX) || defined(COMPILED_FOR_FREEBSD)
7 + return setresgid(gid, egid, sgid);
8 +#endif
9 +
10 +#if defined(COMPILED_FOR_MACOS)
11 + return setregid(gid, egid);
12 +#endif
13 +
14 + errno = ENOSYS;
15 + return -1;
16 +}
src/libnetdata/os/setresgid.h new
+9
@@ -0,0 +1,9 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_SETRESGID_H
4 +#define NETDATA_SETRESGID_H
5 +
6 +#include <unistd.h>
7 +int os_setresgid(gid_t gid, gid_t egid, gid_t sgid);
8 +
9 +#endif //NETDATA_SETRESGID_H
src/libnetdata/os/setresuid.c new
+16
@@ -0,0 +1,16 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +int os_setresuid(uid_t uid __maybe_unused, uid_t euid __maybe_unused, uid_t suid __maybe_unused) {
6 +#if defined(COMPILED_FOR_LINUX) || defined(COMPILED_FOR_FREEBSD)
7 + return setresuid(uid, euid, suid);
8 +#endif
9 +
10 +#if defined(COMPILED_FOR_MACOS)
11 + return setreuid(uid, euid);
12 +#endif
13 +
14 + errno = ENOSYS;
15 + return -1;
16 +}
src/libnetdata/os/setresuid.h new
+10
@@ -0,0 +1,10 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_SETRESUID_H
4 +#define NETDATA_SETRESUID_H
5 +
6 +#include <unistd.h>
7 +
8 +int os_setresuid(uid_t uid, uid_t euid, uid_t suid);
9 +
10 +#endif //NETDATA_SETRESUID_H
src/libnetdata/os/strndup.c new
+13
@@ -0,0 +1,13 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef HAVE_STRNDUP
4 +#include "../libnetdata.h"
5 +
6 +static inline char *os_strndup( const char *s1, size_t n)
7 +{
8 + char *copy= (char*)malloc( n+1 );
9 + memcpy( copy, s1, n );
10 + copy[n] = 0;
11 + return copy;
12 +};
13 +#endif
src/libnetdata/os/strndup.h new
+12
@@ -0,0 +1,12 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef STRNDUP_H
4 +#define STRNDUP_H
5 +
6 +#include "config.h"
7 +
8 +#ifndef HAVE_STRNDUP
9 +#define strndup(s, n) os_strndup(s, n)
10 +#endif
11 +
12 +#endif //STRNDUP_H
src/libnetdata/os/tinysleep.c new
+23
@@ -0,0 +1,23 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +#ifdef COMPILED_FOR_WINDOWS
6 +#include <windows.h>
7 +
8 +void tinysleep(void) {
9 + // Improve the system timer resolution to 1 ms
10 + timeBeginPeriod(1);
11 +
12 + // Sleep for the desired duration
13 + Sleep(1);
14 +
15 + // Reset the system timer resolution
16 + timeEndPeriod(1);
17 +}
18 +#else
19 +void tinysleep(void) {
20 + static const struct timespec ns = { .tv_sec = 0, .tv_nsec = 1 };
21 + nanosleep(&ns, NULL);
22 +}
23 +#endif
src/libnetdata/os/tinysleep.h new
+8
@@ -0,0 +1,8 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_TINYSLEEP_H
4 +#define NETDATA_TINYSLEEP_H
5 +
6 +void tinysleep(void);
7 +
8 +#endif //NETDATA_TINYSLEEP_H
src/libnetdata/os/uuid_generate.c new
+45
@@ -0,0 +1,45 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +#undef uuid_generate
5 +#undef uuid_generate_random
6 +#undef uuid_generate_time
7 +
8 +#ifdef COMPILED_FOR_WINDOWS
9 +#include <windows.h>
10 +
11 +void os_uuid_generate(void *out) {
12 + RPC_STATUS status = UuidCreate(out);
13 + while (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
14 + tinysleep();
15 + status = UuidCreate(out);
16 + }
17 +}
18 +
19 +void os_uuid_generate_random(void *out) {
20 + os_uuid_generate(out);
21 +}
22 +
23 +void os_uuid_generate_time(void *out) {
24 + os_uuid_generate(out);
25 +}
26 +
27 +#else
28 +
29 +#if !defined(COMPILED_FOR_MACOS)
30 +#include <uuid.h>
31 +#endif
32 +
33 +void os_uuid_generate(void *out) {
34 + uuid_generate(out);
35 +}
36 +
37 +void os_uuid_generate_random(void *out) {
38 + uuid_generate_random(out);
39 +}
40 +
41 +void os_uuid_generate_time(void *out) {
42 + uuid_generate_time(out);
43 +}
44 +
45 +#endif
src/libnetdata/os/uuid_generate.h new
+10
@@ -0,0 +1,10 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_UUID_GENERATE_H
4 +#define NETDATA_UUID_GENERATE_H
5 +
6 +void os_uuid_generate(void *out);
7 +void os_uuid_generate_random(void *out);
8 +void os_uuid_generate_time(void *out);
9 +
10 +#endif //NETDATA_UUID_GENERATE_H
src/libnetdata/os/waitid.c new
+72
@@ -0,0 +1,72 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "../libnetdata.h"
4 +
5 +int os_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) {
6 +#if defined(HAVE_WAITID)
7 + return waitid(idtype, id, infop, options);
8 +#else
9 + // emulate waitid() using waitpid()
10 +
11 + // a cache for WNOWAIT
12 + static const struct pid_status empty = { 0, 0 };
13 + static __thread struct pid_status last = { 0, 0 }; // the cache
14 + struct pid_status current = { 0, 0 };
15 +
16 + // zero the infop structure
17 + memset(infop, 0, sizeof(*infop));
18 +
19 + // from the infop structure we use only 3 fields:
20 + // - si_pid
21 + // - si_code
22 + // - si_status
23 + // so, we update only these 3
24 +
25 + switch(idtype) {
26 + case P_ALL:
27 + current.pid = waitpid((pid_t)-1, &current.status, options);
28 + if(options & WNOWAIT)
29 + last = current;
30 + else
31 + last = empty;
32 + break;
33 +
34 + case P_PID:
35 + if(last.pid == (pid_t)id) {
36 + current = last;
37 + last = empty;
38 + }
39 + else
40 + current.pid = waitpid((pid_t)id, &current.status, options);
41 +
42 + break;
43 +
44 + default:
45 + errno = ENOSYS;
46 + return -1;
47 + }
48 +
49 + if (current.pid > 0) {
50 + if (WIFEXITED(current.status)) {
51 + infop->si_code = CLD_EXITED;
52 + infop->si_status = WEXITSTATUS(current.status);
53 + } else if (WIFSIGNALED(current.status)) {
54 + infop->si_code = WTERMSIG(current.status) == SIGABRT ? CLD_DUMPED : CLD_KILLED;
55 + infop->si_status = WTERMSIG(current.status);
56 + } else if (WIFSTOPPED(current.status)) {
57 + infop->si_code = CLD_STOPPED;
58 + infop->si_status = WSTOPSIG(current.status);
59 + } else if (WIFCONTINUED(current.status)) {
60 + infop->si_code = CLD_CONTINUED;
61 + infop->si_status = SIGCONT;
62 + }
63 + infop->si_pid = current.pid;
64 + return 0;
65 + } else if (current.pid == 0) {
66 + // No change in state, depends on WNOHANG
67 + return 0;
68 + }
69 +
70 + return -1;
71 +#endif
72 +}
src/libnetdata/os/waitid.h new
+48
@@ -0,0 +1,48 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_WAITID_H
4 +#define NETDATA_WAITID_H
5 +
6 +#include "config.h"
7 +#include <sys/types.h>
8 +#include <signal.h>
9 +
10 +#ifdef HAVE_SYS_WAIT_H
11 +#include <sys/wait.h>
12 +#endif
13 +
14 +#ifndef WNOWAIT
15 +#define WNOWAIT 0x01000000
16 +#endif
17 +
18 +#ifndef WEXITED
19 +#define WEXITED 4
20 +#endif
21 +
22 +#if !defined(HAVE_WAITID)
23 +typedef enum
24 +{
25 + P_ALL, /* Wait for any child. */
26 + P_PID, /* Wait for specified process. */
27 + P_PGID, /* Wait for members of process group. */
28 + P_PIDFD, /* Wait for the child referred by the PID file descriptor. */
29 +} idtype_t;
30 +
31 +struct pid_status {
32 + pid_t pid;
33 + int status;
34 +};
35 +
36 +#if defined(COMPILED_FOR_WINDOWS) && !defined(__CYGWIN__)
37 +typedef uint32_t id_t;
38 +typedef struct {
39 + int si_code; /* Signal code. */
40 + int si_status; /* Exit value or signal. */
41 + pid_t si_pid; /* Sending process ID. */
42 +} siginfo_t;
43 +#endif
44 +#endif
45 +
46 +int os_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
47 +
48 +#endif //NETDATA_WAITID_H
src/libnetdata/popen/popen.c
+1 -1
@@ -98,7 +98,7 @@ int netdata_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) {
98 }
99 else {
100 // we haven't reaped this child yet
101 - ret = waitid(idtype, id, infop, options);
101 + ret = os_waitid(idtype, id, infop, options);
102
103 if(mp && !mp->reaped) {
104 mp->reaped = true;
src/libnetdata/popen/popen.h
+3 -1
@@ -3,6 +3,9 @@
3 #ifndef NETDATA_POPEN_H
4 #define NETDATA_POPEN_H 1
5
6 +#include "../os/waitid.h"
7 +int netdata_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
8 +
9 #include "../libnetdata.h"
10
11 #define PIPE_READ 0
@@ -28,6 +31,5 @@ int netdata_popene_variadic_internal_dont_use_directly(volatile pid_t *pidptr, c
31 int netdata_pclose(FILE *fp_child_input, FILE *fp_child_output, pid_t pid);
32
33 int netdata_spawn(const char *command, volatile pid_t *pidptr);
31 -int netdata_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
34
35 #endif /* NETDATA_POPEN_H */
src/libnetdata/query_progress/progress.c
+17 -17
@@ -12,7 +12,7 @@
12
13 struct query;
14 #define SIMPLE_HASHTABLE_VALUE_TYPE struct query
15 -#define SIMPLE_HASHTABLE_KEY_TYPE uuid_t
15 +#define SIMPLE_HASHTABLE_KEY_TYPE nd_uuid_t
16 #define SIMPLE_HASHTABLE_NAME _QUERY
17 #define SIMPLE_HASHTABLE_VALUE2KEY_FUNCTION query_transaction
18 #define SIMPLE_HASHTABLE_COMPARE_KEYS_FUNCTION query_compare_keys
@@ -21,7 +21,7 @@ struct query;
21 // ----------------------------------------------------------------------------
22
23 typedef struct query {
24 - uuid_t transaction;
24 + nd_uuid_t transaction;
25
26 BUFFER *query;
27 BUFFER *payload;
@@ -48,12 +48,12 @@ typedef struct query {
48 struct query *prev, *next;
49 } QUERY_PROGRESS;
50
51 -static inline uuid_t *query_transaction(QUERY_PROGRESS *qp) {
51 +static inline nd_uuid_t *query_transaction(QUERY_PROGRESS *qp) {
52 return qp ? &qp->transaction : NULL;
53 }
54
55 -static inline bool query_compare_keys(uuid_t *t1, uuid_t *t2) {
56 - if(t1 == t2 || (t1 && t2 && memcmp(t1, t2, sizeof(uuid_t)) == 0))
55 +static inline bool query_compare_keys(nd_uuid_t *t1, nd_uuid_t *t2) {
56 + if(t1 == t2 || (t1 && t2 && memcmp(t1, t2, sizeof(nd_uuid_t)) == 0))
57 return true;
58
59 return false;
@@ -75,7 +75,7 @@ static struct progress {
75 .spinlock = NETDATA_SPINLOCK_INITIALIZER,
76 };
77
78 -SIMPLE_HASHTABLE_HASH query_hash(uuid_t *transaction) {
78 +SIMPLE_HASHTABLE_HASH query_hash(nd_uuid_t *transaction) {
79 struct uuid_hi_lo_t {
80 uint64_t hi;
81 uint64_t lo;
@@ -93,7 +93,7 @@ static void query_progress_init_unsafe(void) {
93
94 // ----------------------------------------------------------------------------
95
96 -static inline QUERY_PROGRESS *query_progress_find_in_hashtable_unsafe(uuid_t *transaction) {
96 +static inline QUERY_PROGRESS *query_progress_find_in_hashtable_unsafe(nd_uuid_t *transaction) {
97 SIMPLE_HASHTABLE_HASH hash = query_hash(transaction);
98 SIMPLE_HASHTABLE_SLOT_QUERY *slot = simple_hashtable_get_slot_QUERY(&progress.hashtable, hash, transaction, true);
99 QUERY_PROGRESS *qp = SIMPLE_HASHTABLE_SLOT_DATA(slot);
@@ -136,7 +136,7 @@ static inline void query_progress_remove_from_hashtable_unsafe(QUERY_PROGRESS *q
136
137 // ----------------------------------------------------------------------------
138
139 -static QUERY_PROGRESS *query_progress_alloc(uuid_t *transaction) {
139 +static QUERY_PROGRESS *query_progress_alloc(nd_uuid_t *transaction) {
140 QUERY_PROGRESS *qp;
141 qp = callocz(1, sizeof(*qp));
142 uuid_copy(qp->transaction, *transaction);
@@ -155,7 +155,7 @@ static void query_progress_free(QUERY_PROGRESS *qp) {
155 freez(qp);
156 }
157
158 -static void query_progress_cleanup_to_reuse(QUERY_PROGRESS *qp, uuid_t *transaction) {
158 +static void query_progress_cleanup_to_reuse(QUERY_PROGRESS *qp, nd_uuid_t *transaction) {
159 assert(qp && qp->prev == NULL && qp->next == NULL);
160 assert(!transaction || !qp->indexed);
161
@@ -210,7 +210,7 @@ static inline void query_progress_unlink_from_cache_unsafe(QUERY_PROGRESS *qp) {
210 // ----------------------------------------------------------------------------
211 // Progress API
212
213 -void query_progress_start_or_update(uuid_t *transaction, usec_t started_ut, HTTP_REQUEST_MODE mode, HTTP_ACL acl, const char *query, BUFFER *payload, const char *client) {
213 +void query_progress_start_or_update(nd_uuid_t *transaction, usec_t started_ut, HTTP_REQUEST_MODE mode, HTTP_ACL acl, const char *query, BUFFER *payload, const char *client) {
214 if(!transaction)
215 return;
216
@@ -246,7 +246,7 @@ void query_progress_start_or_update(uuid_t *transaction, usec_t started_ut, HTTP
246 spinlock_unlock(&progress.spinlock);
247 }
248
249 -void query_progress_set_finish_line(uuid_t *transaction, size_t all) {
249 +void query_progress_set_finish_line(nd_uuid_t *transaction, size_t all) {
250 if(!transaction)
251 return;
252
@@ -264,7 +264,7 @@ void query_progress_set_finish_line(uuid_t *transaction, size_t all) {
264 spinlock_unlock(&progress.spinlock);
265 }
266
267 -void query_progress_done_step(uuid_t *transaction, size_t done) {
267 +void query_progress_done_step(nd_uuid_t *transaction, size_t done) {
268 if(!transaction)
269 return;
270
@@ -280,7 +280,7 @@ void query_progress_done_step(uuid_t *transaction, size_t done) {
280 spinlock_unlock(&progress.spinlock);
281 }
282
283 -void query_progress_finished(uuid_t *transaction, usec_t finished_ut, short int response_code, usec_t duration_ut, size_t response_size, size_t sent_size) {
283 +void query_progress_finished(nd_uuid_t *transaction, usec_t finished_ut, short int response_code, usec_t duration_ut, size_t response_size, size_t sent_size) {
284 if(!transaction)
285 return;
286
@@ -319,7 +319,7 @@ void query_progress_finished(uuid_t *transaction, usec_t finished_ut, short int
319 }
320 }
321
322 -void query_progress_functions_update(uuid_t *transaction, size_t done, size_t all) {
322 +void query_progress_functions_update(nd_uuid_t *transaction, size_t done, size_t all) {
323 // functions send to the total 'done', not the increment
324
325 if(!transaction)
@@ -346,7 +346,7 @@ void query_progress_functions_update(uuid_t *transaction, size_t done, size_t al
346 // ----------------------------------------------------------------------------
347 // /api/v2/progress - to get the progress of a transaction
348
349 -int web_api_v2_report_progress(uuid_t *transaction, BUFFER *wb) {
349 +int web_api_v2_report_progress(nd_uuid_t *transaction, BUFFER *wb) {
350 buffer_flush(wb);
351 buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
352
@@ -622,7 +622,7 @@ int progress_function_result(BUFFER *wb, const char *hostname) {
622
623 int progress_unittest(void) {
624 size_t permanent = 100;
625 - uuid_t valid[permanent];
625 + nd_uuid_t valid[permanent];
626
627 usec_t started = now_monotonic_usec();
628
@@ -632,7 +632,7 @@ int progress_unittest(void) {
632 }
633
634 for(size_t n = 0; n < 5000000 ;n++) {
635 - uuid_t t;
635 + nd_uuid_t t;
636 uuid_generate_random(t);
637 query_progress_start_or_update(&t, 0, HTTP_REQUEST_MODE_OPTIONS, HTTP_ACL_WEBRTC, "ephemeral", NULL, "test");
638 query_progress_finished(&t, 0, 200, 1234, 123, 12);
src/libnetdata/query_progress/progress.h
+6 -6
@@ -5,13 +5,13 @@
5
6 #include "../libnetdata.h"
7
8 -void query_progress_start_or_update(uuid_t *transaction, usec_t started_ut, HTTP_REQUEST_MODE mode, HTTP_ACL acl, const char *query, BUFFER *payload, const char *client);
9 -void query_progress_done_step(uuid_t *transaction, size_t done);
10 -void query_progress_set_finish_line(uuid_t *transaction, size_t all);
11 -void query_progress_finished(uuid_t *transaction, usec_t finished_ut, short int response_code, usec_t duration_ut, size_t response_size, size_t sent_size);
12 -void query_progress_functions_update(uuid_t *transaction, size_t done, size_t all);
8 +void query_progress_start_or_update(nd_uuid_t *transaction, usec_t started_ut, HTTP_REQUEST_MODE mode, HTTP_ACL acl, const char *query, BUFFER *payload, const char *client);
9 +void query_progress_done_step(nd_uuid_t *transaction, size_t done);
10 +void query_progress_set_finish_line(nd_uuid_t *transaction, size_t all);
11 +void query_progress_finished(nd_uuid_t *transaction, usec_t finished_ut, short int response_code, usec_t duration_ut, size_t response_size, size_t sent_size);
12 +void query_progress_functions_update(nd_uuid_t *transaction, size_t done, size_t all);
13
14 -int web_api_v2_report_progress(uuid_t *transaction, BUFFER *wb);
14 +int web_api_v2_report_progress(nd_uuid_t *transaction, BUFFER *wb);
15
16 #define RRDFUNCTIONS_PROGRESS_HELP "View the progress on the running and latest Netdata API Requests"
17 int progress_function_result(BUFFER *wb, const char *hostname);
src/libnetdata/socket/security.c
+13
@@ -233,6 +233,19 @@ static inline bool is_handshake_complete(NETDATA_SSL *ssl, const char *op) {
233 * (These are often the same value, but can be different on some systems.)
234 */
235
236 +ssize_t netdata_ssl_pending(NETDATA_SSL *ssl) {
237 + return SSL_pending(ssl->conn);
238 +}
239 +
240 +bool netdata_ssl_has_pending(NETDATA_SSL *ssl) {
241 + // this call was added on OpenSSL 1.1.0
242 + // however, it is more accurate than SSL_pending()
243 + // unfortunately it does not exists in libressl.
244 + // return SSL_has_pending(ssl->conn);
245 +
246 + return SSL_pending(ssl->conn) > 0;
247 +}
248 +
249 ssize_t netdata_ssl_read(NETDATA_SSL *ssl, void *buf, size_t num) {
250 errno = 0;
251 ssl->ssl_errno = 0;
src/libnetdata/socket/security.h
+4 -1
@@ -39,7 +39,7 @@ typedef struct netdata_ssl {
39 unsigned long ssl_errno; // The SSL errno of the last SSL call
40 } NETDATA_SSL;
41
42 -#define NETDATA_SSL_UNSET_CONNECTION (NETDATA_SSL){ .conn = NULL, .state = NETDATA_SSL_STATE_NOT_SSL }
42 +#define NETDATA_SSL_UNSET_CONNECTION (NETDATA_SSL){ .conn = NULL, .state = NETDATA_SSL_STATE_NOT_SSL, .ssl_errno = 0 }
43
44 #define SSL_connection(ssl) ((ssl)->conn && (ssl)->state != NETDATA_SSL_STATE_NOT_SSL)
45
@@ -70,5 +70,8 @@ void netdata_ssl_close(NETDATA_SSL *ssl);
70 ssize_t netdata_ssl_read(NETDATA_SSL *ssl, void *buf, size_t num);
71 ssize_t netdata_ssl_write(NETDATA_SSL *ssl, const void *buf, size_t num);
72
73 +ssize_t netdata_ssl_pending(NETDATA_SSL *ssl);
74 +bool netdata_ssl_has_pending(NETDATA_SSL *ssl);
75 +
76 # endif //ENABLE_HTTPS
77 #endif //NETDATA_SECURITY_H
src/libnetdata/socket/socket.c
+124 -101
@@ -201,7 +201,7 @@ void sock_setcloexec(int fd)
201 #endif
202 }
203
204 -int sock_setreuse_port(int fd, int reuse) {
204 +int sock_setreuse_port(int fd __maybe_unused, int reuse __maybe_unused) {
205 int ret;
206
207 #ifdef SO_REUSEPORT
@@ -757,10 +757,10 @@ int listen_sockets_setup(LISTEN_SOCKETS *sockets) {
757 char *e = s;
758
759 // skip separators, moving both s(tart) and e(nd)
760 - while(isspace(*e) || *e == ',') s = ++e;
760 + while(isspace((uint8_t)*e) || *e == ',') s = ++e;
761
762 // move e(nd) to the first separator
763 - while(*e && !isspace(*e) && *e != ',') e++;
763 + while(*e && !isspace((uint8_t)*e) && *e != ',') e++;
764
765 // is there anything?
766 if(!*s || s == e) break;
@@ -872,6 +872,7 @@ int connect_to_this_ip46(int protocol, int socktype, const char *host, uint32_t
872
873 int fd = -1;
874 for (ai = ai_head; ai != NULL && fd == -1; ai = ai->ai_next) {
875 + if(nd_thread_signaled_to_cancel()) break;
876
877 if (ai->ai_family == PF_INET6) {
878 struct sockaddr_in6 *pSadrIn6 = (struct sockaddr_in6 *) ai->ai_addr;
@@ -925,53 +926,46 @@ int connect_to_this_ip46(int protocol, int socktype, const char *host, uint32_t
926 hostBfr, servBfr);
927
928 // Convert 'struct timeval' to milliseconds for poll():
928 - int timeout_milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
929 -
930 - struct pollfd fds[1];
931 - fds[0].fd = fd;
932 - fds[0].events = POLLOUT; // We are looking for the ability to write to the socket
933 -
934 - int ret = poll(fds, 1, timeout_milliseconds);
935 - if (ret > 0) {
936 - // poll() completed normally. We can check the revents to see what happened
937 - if (fds[0].revents & POLLOUT) {
938 - // connect() completed successfully, socket is writable.
929 + int timeout_ms = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
930
931 + switch(wait_on_socket_or_cancel_with_timeout(
932 +#ifdef ENABLE_HTTPS
933 + NULL,
934 +#endif
935 + fd, timeout_ms, POLLOUT, NULL)) {
936 + case 0: // proceed
937 nd_log(NDLS_DAEMON, NDLP_DEBUG,
938 "connect() to ip %s port %s completed successfully",
939 hostBfr, servBfr);
940 + break;
941
944 - }
945 - else {
946 - // This means that the socket is in error. We will close it and set fd to -1
947 -
942 + case -1: // thread cancelled
943 nd_log(NDLS_DAEMON, NDLP_ERR,
949 - "Failed to connect to '%s', port '%s'.",
944 + "Thread is cancelled while connecting to '%s', port '%s'.",
945 hostBfr, servBfr);
946
947 close(fd);
948 fd = -1;
954 - }
955 - }
956 - else if (ret == 0) {
957 - // poll() timed out, the connection is not established within the specified timeout.
958 - errno = 0;
949 + break;
950
960 - nd_log(NDLS_DAEMON, NDLP_ERR,
961 - "Timed out while connecting to '%s', port '%s'.",
962 - hostBfr, servBfr);
951 + case 1: // timeout
952 + nd_log(NDLS_DAEMON, NDLP_ERR,
953 + "Timed out while connecting to '%s', port '%s'.",
954 + hostBfr, servBfr);
955
964 - close(fd);
965 - fd = -1;
966 - }
967 - else { // ret < 0
968 - // poll() returned an error.
969 - nd_log(NDLS_DAEMON, NDLP_ERR,
970 - "Failed to connect to '%s', port '%s'. poll() returned %d",
971 - hostBfr, servBfr, ret);
956 + close(fd);
957 + fd = -1;
958 + break;
959 +
960 + default:
961 + case 2: // error
962 + nd_log(NDLS_DAEMON, NDLP_ERR,
963 + "Failed to connect to '%s', port '%s'.",
964 + hostBfr, servBfr);
965
973 - close(fd);
974 - fd = -1;
966 + close(fd);
967 + fd = -1;
968 + break;
969 }
970 }
971 else {
@@ -1091,10 +1085,10 @@ void foreach_entry_in_connection_string(const char *destination, bool (*callback
1085 const char *e = s;
1086
1087 // skip separators, moving both s(tart) and e(nd)
1094 - while(isspace(*e) || *e == ',') s = ++e;
1088 + while(isspace((uint8_t)*e) || *e == ',') s = ++e;
1089
1090 // move e(nd) to the first separator
1097 - while(*e && !isspace(*e) && *e != ',') e++;
1091 + while(*e && !isspace((uint8_t)*e) && *e != ',') e++;
1092
1093 // is there anything?
1094 if(!*s || s == e) break;
@@ -1177,38 +1171,91 @@ int connect_to_one_of_urls(const char *destination, int default_port, struct tim
1171 // --------------------------------------------------------------------------------------------------------------------
1172 // helpers to send/receive data in one call, in blocking mode, with a timeout
1173
1174 +// returns: -1 = thread cancelled, 0 = proceed to read/write, 1 = time exceeded, 2 = error on fd
1175 +// timeout parameter can be zero to wait forever
1176 +inline int wait_on_socket_or_cancel_with_timeout(
1177 #ifdef ENABLE_HTTPS
1181 -ssize_t recv_timeout(NETDATA_SSL *ssl,int sockfd, void *buf, size_t len, int flags, int timeout) {
1182 -#else
1183 -ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
1178 + NETDATA_SSL *ssl,
1179 #endif
1180 + int fd, int timeout_ms, short int poll_events, short int *revents) {
1181 + struct pollfd pfd = {
1182 + .fd = fd,
1183 + .events = poll_events,
1184 + .revents = 0,
1185 + };
1186
1186 - for(;;) {
1187 - struct pollfd fd = {
1188 - .fd = sockfd,
1189 - .events = POLLIN,
1190 - .revents = 0
1191 - };
1187 + bool forever = (timeout_ms == 0);
1188 +
1189 + while (timeout_ms > 0 || forever) {
1190 + if(nd_thread_signaled_to_cancel()) {
1191 + errno = ECANCELED;
1192 + return -1;
1193 + }
1194 +
1195 +#ifdef ENABLE_HTTPS
1196 + if(poll_events == POLLIN && ssl && SSL_connection(ssl) && netdata_ssl_has_pending(ssl))
1197 + return 0;
1198 +#endif
1199 +
1200 + const int wait_ms = (timeout_ms >= ND_CHECK_CANCELLABILITY_WHILE_WAITING_EVERY_MS || forever) ?
1201 + ND_CHECK_CANCELLABILITY_WHILE_WAITING_EVERY_MS : timeout_ms;
1202
1203 errno = 0;
1194 - int retval = poll(&fd, 1, timeout * 1000);
1204
1196 - if(retval == -1) {
1197 - // failed
1205 + // check every wait_ms
1206 + const int ret = poll(&pfd, 1, wait_ms);
1207 +
1208 + if(revents)
1209 + *revents = pfd.revents;
1210 +
1211 + if(ret == -1) {
1212 + // poll failed
1213
1214 if(errno == EINTR || errno == EAGAIN)
1215 continue;
1216
1202 - return -1;
1217 + return 2;
1218 }
1219
1205 - if(!retval) {
1220 + if(ret == 0) {
1221 // timeout
1207 - return 0;
1222 + if(!forever)
1223 + timeout_ms -= wait_ms;
1224 + continue;
1225 }
1226
1210 - if(fd.revents & POLLIN)
1227 + if(pfd.revents & poll_events)
1228 + return 0;
1229 +
1230 + // all other errors
1231 + return 2;
1232 + }
1233 +
1234 + errno = ETIMEDOUT;
1235 + return 1;
1236 +}
1237 +
1238 +ssize_t recv_timeout(
1239 +#ifdef ENABLE_HTTPS
1240 + NETDATA_SSL *ssl,
1241 +#endif
1242 + int sockfd, void *buf, size_t len, int flags, int timeout) {
1243 +
1244 + switch(wait_on_socket_or_cancel_with_timeout(
1245 +#ifdef ENABLE_HTTPS
1246 + ssl,
1247 +#endif
1248 + sockfd, timeout * 1000, POLLIN, NULL)) {
1249 + case 0: // data are waiting
1250 break;
1251 +
1252 + case 1: // timeout
1253 + return 0;
1254 +
1255 + default:
1256 + case -1: // thread cancelled
1257 + case 2: // error on socket
1258 + return -1;
1259 }
1260
1261 #ifdef ENABLE_HTTPS
@@ -1220,37 +1267,27 @@ ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout)
1267 return recv(sockfd, buf, len, flags);
1268 }
1269
1270 +ssize_t send_timeout(
1271 #ifdef ENABLE_HTTPS
1224 -ssize_t send_timeout(NETDATA_SSL *ssl,int sockfd, void *buf, size_t len, int flags, int timeout) {
1225 -#else
1226 -ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout) {
1272 + NETDATA_SSL *ssl,
1273 #endif
1274 + int sockfd, void *buf, size_t len, int flags, int timeout) {
1275
1229 - for(;;) {
1230 - struct pollfd fd = {
1231 - .fd = sockfd,
1232 - .events = POLLOUT,
1233 - .revents = 0
1234 - };
1235 -
1236 - errno = 0;
1237 - int retval = poll(&fd, 1, timeout * 1000);
1238 -
1239 - if(retval == -1) {
1240 - // failed
1241 -
1242 - if(errno == EINTR || errno == EAGAIN)
1243 - continue;
1244 -
1245 - return -1;
1246 - }
1276 + switch(wait_on_socket_or_cancel_with_timeout(
1277 +#ifdef ENABLE_HTTPS
1278 + ssl,
1279 +#endif
1280 + sockfd, timeout * 1000, POLLOUT, NULL)) {
1281 + case 0: // data are waiting
1282 + break;
1283
1248 - if(!retval) {
1249 - // timeout
1284 + case 1: // timeout
1285 return 0;
1251 - }
1286
1253 - if(fd.revents & POLLOUT) break;
1287 + default:
1288 + case -1: // thread cancelled
1289 + case 2: // error on socket
1290 + return -1;
1291 }
1292
1293 #ifdef ENABLE_HTTPS
@@ -1560,7 +1597,6 @@ inline POLLINFO *poll_add_fd(POLLJOB *p
1597 pi->recv_count = 0;
1598 pi->send_count = 0;
1599
1563 - netdata_thread_disable_cancelability();
1600 p->used++;
1601 if(unlikely(pi->slot > p->max))
1602 p->max = pi->slot;
@@ -1572,7 +1608,6 @@ inline POLLINFO *poll_add_fd(POLLJOB *p
1608 if(pi->flags & POLLINFO_FLAG_SERVER_SOCKET) {
1609 p->min = pi->slot;
1610 }
1575 - netdata_thread_enable_cancelability();
1611
1612 return pi;
1613 }
@@ -1584,8 +1619,6 @@ inline void poll_close_fd(POLLINFO *pi) {
1619
1620 if(unlikely(pf->fd == -1)) return;
1621
1587 - netdata_thread_disable_cancelability();
1588 -
1622 if(pi->flags & POLLINFO_FLAG_CLIENT_SOCKET) {
1623 pi->del_callback(pi);
1624
@@ -1633,7 +1666,6 @@ inline void poll_close_fd(POLLINFO *pi) {
1666 }
1667 }
1668 }
1636 - netdata_thread_enable_cancelability();
1669 }
1670
1671 void *poll_default_add_callback(POLLINFO *pi, short int *events, void *data) {
@@ -1692,11 +1724,11 @@ void poll_default_tmr_callback(void *timer_data) {
1724 (void)timer_data;
1725 }
1726
1695 -static void poll_events_cleanup(void *data) {
1696 - POLLJOB *p = (POLLJOB *)data;
1727 +static void poll_events_cleanup(void *pptr) {
1728 + POLLJOB *p = CLEANUP_FUNCTION_GET_PTR(pptr);
1729 + if(!p) return;
1730
1698 - size_t i;
1699 - for(i = 0 ; i <= p->max ; i++) {
1731 + for(size_t i = 0 ; i <= p->max ; i++) {
1732 POLLINFO *pi = &p->inf[i];
1733 poll_close_fd(pi);
1734 }
@@ -1933,7 +1965,6 @@ void poll_events(LISTEN_SOCKETS *sockets
1965
1966 int listen_sockets_active = 1;
1967
1936 - int timeout_ms = 1000; // in milliseconds
1968 time_t last_check = now_boottime_sec();
1969
1970 usec_t timer_usec = timer_milliseconds * USEC_PER_MS;
@@ -1945,9 +1976,9 @@ void poll_events(LISTEN_SOCKETS *sockets
1976 next_timer_usec = now_usec - (now_usec % timer_usec) + timer_usec;
1977 }
1978
1948 - netdata_thread_cleanup_push(poll_events_cleanup, &p);
1979 + CLEANUP_FUNCTION_REGISTER(poll_events_cleanup) cleanup_ptr = &p;
1980
1950 - while(!check_to_stop_callback()) {
1981 + while(!check_to_stop_callback() && !nd_thread_signaled_to_cancel()) {
1982 if(unlikely(timer_usec)) {
1983 now_usec = now_boottime_usec();
1984
@@ -1957,12 +1988,6 @@ void poll_events(LISTEN_SOCKETS *sockets
1988 now_usec = now_boottime_usec();
1989 next_timer_usec = now_usec - (now_usec % timer_usec) + timer_usec;
1990 }
1960 -
1961 - usec_t dt_usec = next_timer_usec - now_usec;
1962 - if(dt_usec < 1000 * USEC_PER_MS)
1963 - timeout_ms = 1000;
1964 - else
1965 - timeout_ms = (int)(dt_usec / USEC_PER_MS);
1991 }
1992
1993 // enable or disable the TCP listening sockets, based on the current number of sockets used and the limit set
@@ -1980,7 +2005,7 @@ void poll_events(LISTEN_SOCKETS *sockets
2005 }
2006 }
2007
1983 - retval = poll(p.fds, p.max + 1, timeout_ms);
2008 + retval = poll(p.fds, p.max + 1, ND_CHECK_CANCELLABILITY_WHILE_WAITING_EVERY_MS);
2009 time_t now = now_boottime_sec();
2010
2011 if(unlikely(retval == -1)) {
@@ -2151,6 +2176,4 @@ void poll_events(LISTEN_SOCKETS *sockets
2176 }
2177 }
2178 }
2154 -
2155 - netdata_thread_cleanup_pop(1);
2179 }
src/libnetdata/socket/socket.h
+4
@@ -9,6 +9,8 @@
9 #define MAX_LISTEN_FDS 50
10 #endif
11
12 +#define ND_CHECK_CANCELLABILITY_WHILE_WAITING_EVERY_MS 100
13 +
14 typedef struct listen_sockets {
15 struct config *config; // the config file to use
16 const char *config_section; // the netdata configuration section to read settings from
@@ -40,9 +42,11 @@ int connect_to_one_of_urls(const char *destination, int default_port, struct tim
42 #ifdef ENABLE_HTTPS
43 ssize_t recv_timeout(NETDATA_SSL *ssl,int sockfd, void *buf, size_t len, int flags, int timeout);
44 ssize_t send_timeout(NETDATA_SSL *ssl,int sockfd, void *buf, size_t len, int flags, int timeout);
45 +int wait_on_socket_or_cancel_with_timeout(NETDATA_SSL *ssl, int fd, int timeout_ms, short int poll_events, short int *revents);
46 #else
47 ssize_t recv_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);
48 ssize_t send_timeout(int sockfd, void *buf, size_t len, int flags, int timeout);
49 +int wait_on_socket_or_cancel_with_timeout(int fd, int timeout_ms, short int poll_events, short int *revents);
50 #endif
51
52 bool fd_is_socket(int fd);
src/libnetdata/string/string.c
+4 -7
@@ -661,21 +661,18 @@ int string_unittest(size_t entries) {
661 threads_to_create,
662 (long long)seconds_to_run);
663 // check string concurrency
664 - netdata_thread_t threads[threads_to_create];
664 + ND_THREAD *threads[threads_to_create];
665 tu.join = 0;
666 for (int i = 0; i < threads_to_create; i++) {
667 char buf[100 + 1];
668 snprintf(buf, 100, "string%d", i);
669 - netdata_thread_create(
670 - &threads[i], buf, NETDATA_THREAD_OPTION_DONT_LOG | NETDATA_THREAD_OPTION_JOINABLE, string_thread, &tu);
669 + threads[i] = nd_thread_create(buf, NETDATA_THREAD_OPTION_DONT_LOG | NETDATA_THREAD_OPTION_JOINABLE, string_thread, &tu);
670 }
671 sleep_usec(seconds_to_run * USEC_PER_SEC);
672
673 __atomic_store_n(&tu.join, 1, __ATOMIC_RELAXED);
675 - for (int i = 0; i < threads_to_create; i++) {
676 - void *retval;
677 - netdata_thread_join(threads[i], &retval);
678 - }
674 + for (int i = 0; i < threads_to_create; i++)
675 + nd_thread_join(threads[i]);
676
677 size_t inserts, deletes, searches, sentries, references, memory, duplications, releases;
678 string_statistics(&inserts, &deletes, &searches, &sentries, &references, &memory, &duplications, &releases);
src/libnetdata/threads/threads.c
+302 -206
@@ -2,135 +2,202 @@
2
3 #include "../libnetdata.h"
4
5 -static pthread_attr_t *netdata_threads_attr = NULL;
5 +#define nd_thread_status_get(nti) __atomic_load_n(&((nti)->options), __ATOMIC_ACQUIRE)
6 +#define nd_thread_status_check(nti, flag) (__atomic_load_n(&((nti)->options), __ATOMIC_ACQUIRE) & (flag))
7 +#define nd_thread_status_set(nti, flag) __atomic_or_fetch(&((nti)->options), flag, __ATOMIC_RELEASE)
8 +#define nd_thread_status_clear(nti, flag) __atomic_and_fetch(&((nti)->options), ~(flag), __ATOMIC_RELEASE)
9
7 -// ----------------------------------------------------------------------------
8 -// per thread data
10 +typedef void (*nd_thread_canceller)(void *data);
11
10 -typedef struct {
12 +struct nd_thread {
13 void *arg;
12 - char tag[NETDATA_THREAD_NAME_MAX + 1];
14 + pid_t tid;
15 + char tag[ND_THREAD_TAG_MAX + 1];
16 + void *ret; // the return value of start routine
17 void *(*start_routine) (void *);
18 NETDATA_THREAD_OPTIONS options;
15 -} NETDATA_THREAD;
19 + pthread_t thread;
20 + bool cancel_atomic;
21
17 -static __thread NETDATA_THREAD *netdata_thread = NULL;
22 +#ifdef NETDATA_INTERNAL_CHECKS
23 + // keep track of the locks currently held
24 + // used to detect locks that are left locked during exit
25 + int rwlocks_read_locks;
26 + int rwlocks_write_locks;
27 + int mutex_locks;
28 + int spinlock_locks;
29 + int rwspinlock_read_locks;
30 + int rwspinlock_write_locks;
31 +#endif
32
19 -inline int netdata_thread_tag_exists(void) {
20 - return (netdata_thread && *netdata_thread->tag);
33 + struct {
34 + SPINLOCK spinlock;
35 + nd_thread_canceller cb;
36 + void *data;
37 + } canceller;
38 +
39 + struct nd_thread *prev, *next;
40 +};
41 +
42 +static struct {
43 + struct {
44 + SPINLOCK spinlock;
45 + ND_THREAD *list;
46 + } exited;
47 +
48 + struct {
49 + SPINLOCK spinlock;
50 + ND_THREAD *list;
51 + } running;
52 +
53 + pthread_attr_t *attr;
54 +} threads_globals = {
55 + .exited = {
56 + .spinlock = NETDATA_SPINLOCK_INITIALIZER,
57 + .list = NULL,
58 + },
59 + .running = {
60 + .spinlock = NETDATA_SPINLOCK_INITIALIZER,
61 + .list = NULL,
62 + },
63 + .attr = NULL,
64 +};
65 +
66 +static __thread ND_THREAD *_nd_thread_info = NULL;
67 +static __thread char _nd_thread_os_name[ND_THREAD_TAG_MAX + 1] = "";
68 +
69 +// --------------------------------------------------------------------------------------------------------------------
70 +// O/S abstraction
71 +
72 +// get the thread name from the operating system
73 +static inline void os_get_thread_name(char *out, size_t size) {
74 +#if defined(__FreeBSD__)
75 + pthread_get_name_np(pthread_self(), out, size);
76 + if(strcmp(_nd_thread_os_name, "netdata") == 0)
77 + strncpyz(out, "MAIN", size - 1);
78 +#elif defined(HAVE_PTHREAD_GETNAME_NP)
79 + pthread_getname_np(pthread_self(), out, size - 1);
80 + if(strcmp(out, "netdata") == 0)
81 + strncpyz(out, "MAIN", size - 1);
82 +#else
83 + strncpyz(out, "MAIN", size - 1);
84 +#endif
85 }
86
23 -static const char *thread_name_get(bool recheck) {
24 - static __thread char threadname[NETDATA_THREAD_NAME_MAX + 1] = "";
25 -
26 - if(netdata_thread_tag_exists())
27 - strncpyz(threadname, netdata_thread->tag, NETDATA_THREAD_NAME_MAX);
28 - else {
29 - if(!recheck && threadname[0])
30 - return threadname;
31 -
87 +// set the thread name to the operating system
88 +static inline void os_set_thread_name(const char *name) {
89 #if defined(__FreeBSD__)
33 - pthread_get_name_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX + 1);
34 - if(strcmp(threadname, "netdata") == 0)
35 - strncpyz(threadname, "MAIN", NETDATA_THREAD_NAME_MAX);
90 + pthread_set_name_np(pthread_self(), name);
91 #elif defined(__APPLE__)
37 - strncpyz(threadname, "MAIN", NETDATA_THREAD_NAME_MAX);
38 -#elif defined(HAVE_PTHREAD_GETNAME_NP)
39 - pthread_getname_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX + 1);
40 - if(strcmp(threadname, "netdata") == 0)
41 - strncpyz(threadname, "MAIN", NETDATA_THREAD_NAME_MAX);
92 + pthread_setname_np(name);
93 #else
43 - strncpyz(threadname, "MAIN", NETDATA_THREAD_NAME_MAX);
94 + pthread_setname_np(pthread_self(), name);
95 #endif
45 - }
46 -
47 - return threadname;
96 }
97
50 -const char *netdata_thread_tag(void) {
51 - return thread_name_get(false);
98 +// --------------------------------------------------------------------------------------------------------------------
99 +// internal API for managing names
100 +
101 +inline int nd_thread_has_tag(void) {
102 + return (_nd_thread_info && _nd_thread_info->tag[0]);
103 }
104
54 -static size_t webrtc_id = 0;
55 -static __thread bool webrtc_name_set = false;
56 -void webrtc_set_thread_name(void) {
57 - if(!netdata_thread && !webrtc_name_set) {
58 - webrtc_name_set = true;
59 - char threadname[NETDATA_THREAD_NAME_MAX + 1];
105 +// For threads created by netdata, return the tag of the thread.
106 +// For threads created by others (libuv, webrtc, etc), return the tag of the operating system.
107 +// This caches the response, so that it won't query the operating system multiple times.
108 +static inline const char *nd_thread_get_name(bool recheck) {
109 + if(nd_thread_has_tag())
110 + return _nd_thread_info->tag;
111
61 -#if defined(__FreeBSD__)
62 - snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "WEBRTC[%zu]", __atomic_fetch_add(&webrtc_id, 1, __ATOMIC_RELAXED));
63 - pthread_set_name_np(pthread_self(), threadname);
64 -#elif defined(__APPLE__)
65 - snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "WEBRTC[%zu]", __atomic_fetch_add(&webrtc_id, 1, __ATOMIC_RELAXED));
66 - pthread_setname_np(threadname);
67 -#elif defined(HAVE_PTHREAD_GETNAME_NP)
68 - pthread_getname_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX+1);
69 - if(strcmp(threadname, "netdata") == 0) {
70 - snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "WEBRTC[%zu]", __atomic_fetch_add(&webrtc_id, 1, __ATOMIC_RELAXED));
71 - pthread_setname_np(pthread_self(), threadname);
72 - }
73 -#else
74 - snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "WEBRTC[%zu]", __atomic_fetch_add(&webrtc_id, 1, __ATOMIC_RELAXED));
75 - pthread_setname_np(pthread_self(), threadname);
76 -#endif
112 + if(!recheck && _nd_thread_os_name[0])
113 + return _nd_thread_os_name;
114
78 - thread_name_get(true);
79 - }
115 + os_get_thread_name(_nd_thread_os_name, sizeof(_nd_thread_os_name));
116 +
117 + return _nd_thread_os_name;
118 }
119
82 -// ----------------------------------------------------------------------------
83 -// compatibility library functions
120 +const char *nd_thread_tag(void) {
121 + return nd_thread_get_name(false);
122 +}
123
85 -static __thread pid_t gettid_cached_tid = 0;
86 -pid_t gettid(void) {
87 - pid_t tid = 0;
124 +void nd_thread_tag_set(const char *tag) {
125 + if(!tag || !*tag) return;
126
89 - if(likely(gettid_cached_tid > 0))
90 - return gettid_cached_tid;
127 + if(_nd_thread_info)
128 + strncpyz(_nd_thread_info->tag, tag, sizeof(_nd_thread_info->tag) - 1);
129
92 -#ifdef __FreeBSD__
130 + strncpyz(_nd_thread_os_name, tag, sizeof(_nd_thread_os_name) - 1);
131
94 - tid = (pid_t)pthread_getthreadid_np();
132 + os_set_thread_name(_nd_thread_os_name);
133 +}
134
96 -#elif defined(__APPLE__)
135 +// --------------------------------------------------------------------------------------------------------------------
136 +
137 +static __thread bool libuv_name_set = false;
138 +void uv_thread_set_name_np(const char* name) {
139 + if(libuv_name_set) return;
140 +
141 + strncpyz(_nd_thread_os_name, name, sizeof(_nd_thread_os_name) - 1);
142 + os_set_thread_name(_nd_thread_os_name);
143 + libuv_name_set = true;
144 +}
145
98 - #if (defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)
99 - uint64_t curthreadid;
100 - pthread_threadid_np(NULL, &curthreadid);
101 - tid = (pid_t)curthreadid;
102 - #else /* __MAC_OS_X_VERSION_MIN_REQUIRED */
103 - tid = (pid_t)pthread_self;
104 - #endif /* __MAC_OS_X_VERSION_MIN_REQUIRED */
146 +// --------------------------------------------------------------------------------------------------------------------
147 +
148 +static size_t webrtc_id = 0;
149 +static __thread bool webrtc_name_set = false;
150 +void webrtc_set_thread_name(void) {
151 + if(_nd_thread_info || webrtc_name_set) return;
152
106 -#else /* __APPLE__*/
153 + webrtc_name_set = true;
154
108 - tid = (pid_t)syscall(SYS_gettid);
155 + char tmp[ND_THREAD_TAG_MAX + 1] = "";
156 + os_get_thread_name(tmp, sizeof(tmp));
157
110 -#endif /* __FreeBSD__, __APPLE__*/
158 + if(!tmp[0] || strcmp(tmp, "netdata") == 0) {
159 + char name[ND_THREAD_TAG_MAX + 1];
160 + snprintfz(name, ND_THREAD_TAG_MAX, "WEBRTC[%zu]", __atomic_fetch_add(&webrtc_id, 1, __ATOMIC_RELAXED));
161 + os_set_thread_name(name);
162 + }
163
112 - gettid_cached_tid = tid;
113 - return tid;
164 + nd_thread_get_name(true);
165 }
166
116 -// ----------------------------------------------------------------------------
167 +// --------------------------------------------------------------------------------------------------------------------
168 +// locks tracking
169 +
170 +#ifdef NETDATA_INTERNAL_CHECKS
171 +void nd_thread_rwlock_read_locked(void) { if(_nd_thread_info) _nd_thread_info->rwlocks_read_locks++; }
172 +void nd_thread_rwlock_read_unlocked(void) { if(_nd_thread_info) _nd_thread_info->rwlocks_read_locks--; }
173 +void nd_thread_rwlock_write_locked(void) { if(_nd_thread_info) _nd_thread_info->rwlocks_write_locks++; }
174 +void nd_thread_rwlock_write_unlocked(void) { if(_nd_thread_info) _nd_thread_info->rwlocks_write_locks--; }
175 +void nd_thread_mutex_locked(void) { if(_nd_thread_info) _nd_thread_info->mutex_locks++; }
176 +void nd_thread_mutex_unlocked(void) { if(_nd_thread_info) _nd_thread_info->mutex_locks--; }
177 +void nd_thread_spinlock_locked(void) { if(_nd_thread_info) _nd_thread_info->spinlock_locks++; }
178 +void nd_thread_spinlock_unlocked(void) { if(_nd_thread_info) _nd_thread_info->spinlock_locks--; }
179 +void nd_thread_rwspinlock_read_locked(void) { if(_nd_thread_info) _nd_thread_info->rwspinlock_read_locks++; }
180 +void nd_thread_rwspinlock_read_unlocked(void) { if(_nd_thread_info) _nd_thread_info->rwspinlock_read_locks--; }
181 +void nd_thread_rwspinlock_write_locked(void) { if(_nd_thread_info) _nd_thread_info->rwspinlock_write_locks++; }
182 +void nd_thread_rwspinlock_write_unlocked(void) { if(_nd_thread_info) _nd_thread_info->rwspinlock_write_locks--; }
183 +#endif
184 +
185 +// --------------------------------------------------------------------------------------------------------------------
186 // early initialization
187
188 size_t netdata_threads_init(void) {
189 int i;
190
122 - // --------------------------------------------------------------------
123 - // get the required stack size of the threads of netdata
124 -
125 - if(!netdata_threads_attr) {
126 - netdata_threads_attr = callocz(1, sizeof(pthread_attr_t));
127 - i = pthread_attr_init(netdata_threads_attr);
191 + if(!threads_globals.attr) {
192 + threads_globals.attr = callocz(1, sizeof(pthread_attr_t));
193 + i = pthread_attr_init(threads_globals.attr);
194 if (i != 0)
195 fatal("pthread_attr_init() failed with code %d.", i);
196 }
197
198 + // get the required stack size of the threads of netdata
199 size_t stacksize = 0;
133 - i = pthread_attr_getstacksize(netdata_threads_attr, &stacksize);
200 + i = pthread_attr_getstacksize(threads_globals.attr, &stacksize);
201 if(i != 0)
202 fatal("pthread_attr_getstacksize() failed with code %d.", i);
203
@@ -143,11 +210,9 @@ size_t netdata_threads_init(void) {
210 void netdata_threads_init_after_fork(size_t stacksize) {
211 int i;
212
146 - // ------------------------------------------------------------------------
213 // set pthread stack size
148 -
149 - if(netdata_threads_attr && stacksize > (size_t)PTHREAD_STACK_MIN) {
150 - i = pthread_attr_setstacksize(netdata_threads_attr, stacksize);
214 + if(threads_globals.attr && stacksize > (size_t)PTHREAD_STACK_MIN) {
215 + i = pthread_attr_setstacksize(threads_globals.attr, stacksize);
216 if(i != 0)
217 nd_log(NDLS_DAEMON, NDLP_WARNING, "pthread_attr_setstacksize() to %zu bytes, failed with code %d.", stacksize, i);
218 else
@@ -169,7 +234,6 @@ void netdata_threads_init_for_external_plugins(size_t stacksize) {
234 }
235
236 // ----------------------------------------------------------------------------
172 -// netdata_thread_create
237
238 void rrdset_thread_rda_free(void);
239 void sender_thread_buffer_free(void);
@@ -177,92 +241,99 @@ void query_target_free(void);
241 void service_exits(void);
242 void rrd_collector_finished(void);
243
180 -static void thread_cleanup(void *ptr) {
181 - if(netdata_thread != ptr) {
182 - NETDATA_THREAD *info = (NETDATA_THREAD *)ptr;
183 - nd_log(NDLS_DAEMON, NDLP_ERR, "THREADS: internal error - thread local variable does not match the one passed to this function. Expected thread '%s', passed thread '%s'", netdata_thread->tag, info->tag);
184 - }
244 +static void nd_thread_join_exited_detached_threads(void) {
245 + while(1) {
246 + spinlock_lock(&threads_globals.exited.spinlock);
247
186 - if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP))
187 - nd_log(NDLS_DAEMON, NDLP_DEBUG, "thread with task id %d finished", gettid());
248 + ND_THREAD *nti = threads_globals.exited.list;
249 + while (nti && nd_thread_status_check(nti, NETDATA_THREAD_OPTION_JOINABLE) == 0)
250 + nti = nti->next;
251
189 - rrd_collector_finished();
190 - sender_thread_buffer_free();
191 - rrdset_thread_rda_free();
192 - query_target_free();
193 - thread_cache_destroy();
194 - service_exits();
195 - worker_unregister();
252 + if(nti)
253 + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(threads_globals.exited.list, nti, prev, next);
254
197 - netdata_thread->tag[0] = '\0';
255 + spinlock_unlock(&threads_globals.exited.spinlock);
256
199 - freez(netdata_thread);
200 - netdata_thread = NULL;
257 + if(nti) {
258 + nd_log(NDLS_DAEMON, NDLP_INFO, "Joining detached thread '%s', tid %d", nti->tag, nti->tid);
259 + nd_thread_join(nti);
260 + }
261 + else
262 + break;
263 + }
264 }
265
203 -void netdata_thread_set_tag(const char *tag) {
204 - if(!tag || !*tag)
205 - return;
266 +static void nd_thread_exit(void *pptr) {
267 + ND_THREAD *nti = CLEANUP_FUNCTION_GET_PTR(pptr);
268
207 - int ret = 0;
269 + if(nti != _nd_thread_info || !nti || !_nd_thread_info) {
270 + nd_log(NDLS_DAEMON, NDLP_ERR,
271 + "THREADS: internal error - thread local variable does not match the one passed to this function. "
272 + "Expected thread '%s', passed thread '%s'",
273 + _nd_thread_info ? _nd_thread_info->tag : "(null)", nti ? nti->tag : "(null)");
274
209 - char threadname[NETDATA_THREAD_NAME_MAX+1];
210 - strncpyz(threadname, tag, NETDATA_THREAD_NAME_MAX);
275 + if(!nti) nti = _nd_thread_info;
276 + }
277
212 -#if defined(__FreeBSD__)
213 - pthread_set_name_np(pthread_self(), threadname);
214 -#elif defined(__APPLE__)
215 - ret = pthread_setname_np(threadname);
216 -#else
217 - ret = pthread_setname_np(pthread_self(), threadname);
218 -#endif
278 + if(!nti) return;
279
220 - if (ret != 0)
221 - nd_log(NDLS_DAEMON, NDLP_WARNING, "cannot set pthread name of %d to %s. ErrCode: %d", gettid(), threadname, ret);
222 - else
223 - nd_log(NDLS_DAEMON, NDLP_DEBUG, "set name of thread %d to %s", gettid(), threadname);
280 + internal_fatal(nti->rwlocks_read_locks != 0,
281 + "THREAD '%s' WITH PID %d HAS %d RWLOCKS READ ACQUIRED WHILE EXITING !!!",
282 + (nti) ? nti->tag : "(unset)", gettid_cached(), nti->rwlocks_read_locks);
283
225 - if(netdata_thread) {
226 - strncpyz(netdata_thread->tag, threadname, sizeof(netdata_thread->tag) - 1);
227 - }
228 -}
284 + internal_fatal(nti->rwlocks_write_locks != 0,
285 + "THREAD '%s' WITH PID %d HAS %d RWLOCKS WRITE ACQUIRED WHILE EXITING !!!",
286 + (nti) ? nti->tag : "(unset)", gettid_cached(), nti->rwlocks_write_locks);
287
230 -void uv_thread_set_name_np(uv_thread_t ut, const char* name) {
231 - int ret = 0;
288 + internal_fatal(nti->mutex_locks != 0,
289 + "THREAD '%s' WITH PID %d HAS %d MUTEXES ACQUIRED WHILE EXITING !!!",
290 + (nti) ? nti->tag : "(unset)", gettid_cached(), nti->mutex_locks);
291
233 - char threadname[NETDATA_THREAD_NAME_MAX+1];
234 - strncpyz(threadname, name, NETDATA_THREAD_NAME_MAX);
292 + internal_fatal(nti->spinlock_locks != 0,
293 + "THREAD '%s' WITH PID %d HAS %d SPINLOCKS ACQUIRED WHILE EXITING !!!",
294 + (nti) ? nti->tag : "(unset)", gettid_cached(), nti->spinlock_locks);
295
236 -#if defined(__FreeBSD__)
237 - pthread_set_name_np(ut ? ut : pthread_self(), threadname);
238 -#elif defined(__APPLE__)
239 - // Apple can only set its own name
240 - UNUSED(ut);
241 -#else
242 - ret = pthread_setname_np(ut ? ut : pthread_self(), threadname);
243 -#endif
296 + internal_fatal(nti->rwspinlock_read_locks != 0,
297 + "THREAD '%s' WITH PID %d HAS %d RWSPINLOCKS READ ACQUIRED WHILE EXITING !!!",
298 + (nti) ? nti->tag : "(unset)", gettid_cached(), nti->rwspinlock_read_locks);
299
245 - thread_name_get(true);
300 + internal_fatal(nti->rwspinlock_write_locks != 0,
301 + "THREAD '%s' WITH PID %d HAS %d RWSPINLOCKS WRITE ACQUIRED WHILE EXITING !!!",
302 + (nti) ? nti->tag : "(unset)", gettid_cached(), nti->rwspinlock_write_locks);
303
247 - if (ret)
248 - nd_log(NDLS_DAEMON, NDLP_NOTICE, "cannot set libuv thread name to %s. Err: %d", threadname, ret);
249 -}
304 + if(nd_thread_status_check(nti, NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP) != NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP)
305 + nd_log(NDLS_DAEMON, NDLP_DEBUG, "thread with task id %d finished", nti->tid);
306
251 -void os_thread_get_current_name_np(char threadname[NETDATA_THREAD_NAME_MAX + 1])
252 -{
253 - threadname[0] = '\0';
254 -#if defined(__FreeBSD__)
255 - pthread_get_name_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX + 1);
256 -#elif defined(HAVE_PTHREAD_GETNAME_NP) /* Linux & macOS */
257 - (void)pthread_getname_np(pthread_self(), threadname, NETDATA_THREAD_NAME_MAX + 1);
258 -#endif
307 + rrd_collector_finished();
308 + sender_thread_buffer_free();
309 + rrdset_thread_rda_free();
310 + query_target_free();
311 + thread_cache_destroy();
312 + service_exits();
313 + worker_unregister();
314 +
315 + nd_thread_status_set(nti, NETDATA_THREAD_STATUS_FINISHED);
316 +
317 + spinlock_lock(&threads_globals.running.spinlock);
318 + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(threads_globals.running.list, nti, prev, next);
319 + spinlock_unlock(&threads_globals.running.spinlock);
320 +
321 + if (nd_thread_status_check(nti, NETDATA_THREAD_OPTION_JOINABLE) != NETDATA_THREAD_OPTION_JOINABLE) {
322 + spinlock_lock(&threads_globals.exited.spinlock);
323 + DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(threads_globals.exited.list, nti, prev, next);
324 + spinlock_unlock(&threads_globals.exited.spinlock);
325 + }
326 }
327
261 -static void *netdata_thread_init(void *ptr) {
262 - netdata_thread = (NETDATA_THREAD *)ptr;
328 +static void *nd_thread_starting_point(void *ptr) {
329 + ND_THREAD *nti = _nd_thread_info = (ND_THREAD *)ptr;
330 + nd_thread_status_set(nti, NETDATA_THREAD_STATUS_STARTED);
331 +
332 + nti->tid = gettid_cached();
333 + nd_thread_tag_set(nti->tag);
334
264 - if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_STARTUP))
265 - nd_log(NDLS_DAEMON, NDLP_DEBUG, "thread created with task id %d", gettid());
335 + if(nd_thread_status_check(nti, NETDATA_THREAD_OPTION_DONT_LOG_STARTUP) != NETDATA_THREAD_OPTION_DONT_LOG_STARTUP)
336 + nd_log(NDLS_DAEMON, NDLP_DEBUG, "thread created with task id %d", gettid_cached());
337
338 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
339 nd_log(NDLS_DAEMON, NDLP_WARNING, "cannot set pthread cancel type to DEFERRED.");
@@ -270,72 +341,97 @@ static void *netdata_thread_init(void *ptr) {
341 if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
342 nd_log(NDLS_DAEMON, NDLP_WARNING, "cannot set pthread cancel state to ENABLE.");
343
273 - netdata_thread_set_tag(netdata_thread->tag);
344 + CLEANUP_FUNCTION_REGISTER(nd_thread_exit) cleanup_ptr = nti;
345
275 - if (!(netdata_thread->options & NETDATA_THREAD_OPTION_JOINABLE)) {
276 - int rc = pthread_detach(pthread_self());
277 - if (rc != 0)
278 - nd_log(NDLS_DAEMON, NDLP_WARNING,
279 - "cannot request detach of newly created %s thread. pthread_detach() failed with code %d",
280 - netdata_thread->tag, rc);
281 - }
346 + // run the thread code
347 + nti->ret = nti->start_routine(nti->arg);
348 +
349 + return nti;
350 +}
351 +
352 +ND_THREAD *nd_thread_self(void) {
353 + return _nd_thread_info;
354 +}
355
283 - void *ret = NULL;
284 - pthread_cleanup_push(thread_cleanup, ptr) {
285 - ret = netdata_thread->start_routine(netdata_thread->arg);
356 +bool nd_thread_is_me(ND_THREAD *nti) {
357 + return nti && nti->thread == pthread_self();
358 +}
359 +
360 +ND_THREAD *nd_thread_create(const char *tag, NETDATA_THREAD_OPTIONS options, void *(*start_routine)(void *), void *arg) {
361 + nd_thread_join_exited_detached_threads();
362 +
363 + ND_THREAD *nti = callocz(1, sizeof(*nti));
364 + spinlock_init(&nti->canceller.spinlock);
365 + nti->arg = arg;
366 + nti->start_routine = start_routine;
367 + nti->options = options & NETDATA_THREAD_OPTIONS_ALL;
368 + strncpyz(nti->tag, tag, ND_THREAD_TAG_MAX);
369 +
370 + spinlock_lock(&threads_globals.running.spinlock);
371 + DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(threads_globals.running.list, nti, prev, next);
372 + spinlock_unlock(&threads_globals.running.spinlock);
373 +
374 + int ret = pthread_create(&nti->thread, threads_globals.attr, nd_thread_starting_point, nti);
375 + if(ret != 0) {
376 + nd_log(NDLS_DAEMON, NDLP_ERR,
377 + "failed to create new thread for %s. pthread_create() failed with code %d",
378 + tag, ret);
379 +
380 + spinlock_lock(&threads_globals.running.spinlock);
381 + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(threads_globals.running.list, nti, prev, next);
382 + spinlock_unlock(&threads_globals.running.spinlock);
383 + freez(nti);
384 + return NULL;
385 }
287 - pthread_cleanup_pop(1);
386
289 - return ret;
387 + return nti;
388 }
389
292 -int netdata_thread_create(netdata_thread_t *thread, const char *tag, NETDATA_THREAD_OPTIONS options, void *(*start_routine) (void *), void *arg) {
293 - NETDATA_THREAD *info = callocz(1, sizeof(NETDATA_THREAD));
294 - info->arg = arg;
295 - info->start_routine = start_routine;
296 - info->options = options;
297 - strncpyz(info->tag, tag, NETDATA_THREAD_NAME_MAX);
390 +// --------------------------------------------------------------------------------------------------------------------
391
299 - int ret = pthread_create(thread, netdata_threads_attr, netdata_thread_init, info);
300 - if(ret != 0)
301 - nd_log(NDLS_DAEMON, NDLP_ERR, "failed to create new thread for %s. pthread_create() failed with code %d", tag, ret);
392 +void nd_thread_register_canceller(nd_thread_canceller cb, void *data) {
393 + ND_THREAD *nti = _nd_thread_info;
394 + if(!nti) return;
395
303 - return ret;
396 + spinlock_lock(&nti->canceller.spinlock);
397 + nti->canceller.cb = cb;
398 + nti->canceller.data = data;
399 + spinlock_unlock(&nti->canceller.spinlock);
400 }
401
306 -// ----------------------------------------------------------------------------
307 -// netdata_thread_cancel
308 -#ifdef NETDATA_INTERNAL_CHECKS
309 -int netdata_thread_cancel_with_trace(netdata_thread_t thread, int line, const char *file, const char *function) {
310 -#else
311 -int netdata_thread_cancel(netdata_thread_t thread) {
312 -#endif
313 - int ret = pthread_cancel(thread);
314 - if(ret != 0)
315 -#ifdef NETDATA_INTERNAL_CHECKS
316 - nd_log(NDLS_DAEMON, NDLP_WARNING, "cannot cancel thread. pthread_cancel() failed with code %d at %d@%s, function %s()", ret, line, file, function);
317 -#else
318 - nd_log(NDLS_DAEMON, NDLP_WARNING, "cannot cancel thread. pthread_cancel() failed with code %d.", ret);
319 -#endif
402 +void nd_thread_signal_cancel(ND_THREAD *nti) {
403 + if(!nti) return;
404 +
405 + __atomic_store_n(&nti->cancel_atomic, true, __ATOMIC_RELAXED);
406 +
407 + spinlock_lock(&nti->canceller.spinlock);
408 + if(nti->canceller.cb)
409 + nti->canceller.cb(nti->canceller.data);
410 + spinlock_unlock(&nti->canceller.spinlock);
411 +}
412
321 - return ret;
413 +bool nd_thread_signaled_to_cancel(void) {
414 + if(!_nd_thread_info) return false;
415 + return __atomic_load_n(&_nd_thread_info->cancel_atomic, __ATOMIC_RELAXED);
416 }
417
418 // ----------------------------------------------------------------------------
325 -// netdata_thread_join
419 +// nd_thread_join
420
327 -int netdata_thread_join(netdata_thread_t thread, void **retval) {
328 - int ret = pthread_join(thread, retval);
421 +void nd_thread_join(ND_THREAD *nti) {
422 + if(!nti) return;
423 +
424 + int ret = pthread_join(nti->thread, NULL);
425 if(ret != 0)
426 nd_log(NDLS_DAEMON, NDLP_WARNING, "cannot join thread. pthread_join() failed with code %d.", ret);
427 + else {
428 + nd_thread_status_set(nti, NETDATA_THREAD_STATUS_JOINED);
429
332 - return ret;
333 -}
334 -
335 -int netdata_thread_detach(pthread_t thread) {
336 - int ret = pthread_detach(thread);
337 - if(ret != 0)
338 - nd_log(NDLS_DAEMON, NDLP_WARNING, "cannot detach thread. pthread_detach() failed with code %d.", ret);
430 + spinlock_lock(&threads_globals.exited.spinlock);
431 + if(nti->prev)
432 + DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(threads_globals.exited.list, nti, prev, next);
433 + spinlock_unlock(&threads_globals.exited.spinlock);
434
340 - return ret;
435 + freez(nti);
436 + }
437 }
src/libnetdata/threads/threads.h
+49 -26
@@ -5,22 +5,25 @@
5
6 #include "../libnetdata.h"
7
8 -pid_t gettid(void);
9 -
10 -typedef enum {
8 +typedef enum __attribute__((packed)) {
9 NETDATA_THREAD_OPTION_DEFAULT = 0 << 0,
10 NETDATA_THREAD_OPTION_JOINABLE = 1 << 0,
11 NETDATA_THREAD_OPTION_DONT_LOG_STARTUP = 1 << 1,
12 NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP = 1 << 2,
15 - NETDATA_THREAD_OPTION_DONT_LOG = NETDATA_THREAD_OPTION_DONT_LOG_STARTUP|NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP,
13 + NETDATA_THREAD_STATUS_STARTED = 1 << 3,
14 + NETDATA_THREAD_STATUS_FINISHED = 1 << 4,
15 + NETDATA_THREAD_STATUS_JOINED = 1 << 5,
16 } NETDATA_THREAD_OPTIONS;
17
18 +#define NETDATA_THREAD_OPTIONS_ALL (NETDATA_THREAD_OPTION_JOINABLE | NETDATA_THREAD_OPTION_DONT_LOG_STARTUP | NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP)
19 +#define NETDATA_THREAD_OPTION_DONT_LOG (NETDATA_THREAD_OPTION_DONT_LOG_STARTUP | NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP)
20 +
21 #define netdata_thread_cleanup_push(func, arg) pthread_cleanup_push(func, arg)
22 #define netdata_thread_cleanup_pop(execute) pthread_cleanup_pop(execute)
23
21 -void netdata_thread_set_tag(const char *tag);
24 +void nd_thread_tag_set(const char *tag);
25
23 -typedef pthread_t netdata_thread_t;
26 +typedef struct nd_thread ND_THREAD;
27
28 struct netdata_static_thread {
29 // the name of the thread as it should appear in the logs
@@ -36,7 +39,7 @@ struct netdata_static_thread {
39 volatile sig_atomic_t enabled;
40
41 // internal use, to maintain a pointer to the created thread
39 - netdata_thread_t *thread;
42 + ND_THREAD *thread;
43
44 // an initialization function to run before spawning the thread
45 void (*init_routine) (void);
@@ -56,36 +59,56 @@ struct netdata_static_thread {
59 #define NETDATA_MAIN_THREAD_EXITED CONFIG_BOOLEAN_NO
60
61 #define NETDATA_THREAD_TAG_MAX 100
59 -const char *netdata_thread_tag(void);
60 -int netdata_thread_tag_exists(void);
62 +const char *nd_thread_tag(void);
63 +int nd_thread_has_tag(void);
64
65 #define THREAD_TAG_STREAM_RECEIVER "RCVR"
66 #define THREAD_TAG_STREAM_SENDER "SNDR"
67
65 -
68 size_t netdata_threads_init(void);
69 void netdata_threads_init_after_fork(size_t stacksize);
70 void netdata_threads_init_for_external_plugins(size_t stacksize);
71
70 -int netdata_thread_create(netdata_thread_t *thread, const char *tag, NETDATA_THREAD_OPTIONS options, void *(*start_routine) (void *), void *arg);
72 +ND_THREAD *nd_thread_create(const char *tag, NETDATA_THREAD_OPTIONS options, void *(*start_routine) (void *), void *arg);
73 +void nd_thread_join(ND_THREAD * nti);
74 +ND_THREAD *nd_thread_self(void);
75 +bool nd_thread_is_me(ND_THREAD *nti);
76
72 -#ifdef NETDATA_INTERNAL_CHECKS
73 -#define netdata_thread_cancel(thread) netdata_thread_cancel_with_trace(thread, __LINE__, __FILE__, __FUNCTION__)
74 -int netdata_thread_cancel_with_trace(netdata_thread_t thread, int line, const char *file, const char *function);
75 -#else
76 -int netdata_thread_cancel(netdata_thread_t thread);
77 -#endif
78 -
79 -int netdata_thread_join(netdata_thread_t thread, void **retval);
80 -int netdata_thread_detach(pthread_t thread);
81 -
82 -#define NETDATA_THREAD_NAME_MAX 15
83 -void uv_thread_set_name_np(uv_thread_t ut, const char* name);
84 -void os_thread_get_current_name_np(char threadname[NETDATA_THREAD_NAME_MAX + 1]);
77 +typedef void (*nd_thread_canceller)(void *data);
78 +void nd_thread_register_canceller(nd_thread_canceller cb, void *data);
79 +void nd_thread_signal_cancel(ND_THREAD *nti);
80 +bool nd_thread_signaled_to_cancel(void);
81
82 +#define ND_THREAD_TAG_MAX 15
83 +void uv_thread_set_name_np(const char* name);
84 void webrtc_set_thread_name(void);
85
88 -#define netdata_thread_self pthread_self
89 -#define netdata_thread_testcancel pthread_testcancel
86 +#ifdef NETDATA_INTERNAL_CHECKS
87 +void nd_thread_rwlock_read_locked(void);
88 +void nd_thread_rwlock_read_unlocked(void);
89 +void nd_thread_rwlock_write_locked(void);
90 +void nd_thread_rwlock_write_unlocked(void);
91 +void nd_thread_mutex_locked(void);
92 +void nd_thread_mutex_unlocked(void);
93 +void nd_thread_spinlock_locked(void);
94 +void nd_thread_spinlock_unlocked(void);
95 +void nd_thread_rwspinlock_read_locked(void);
96 +void nd_thread_rwspinlock_read_unlocked(void);
97 +void nd_thread_rwspinlock_write_locked(void);
98 +void nd_thread_rwspinlock_write_unlocked(void);
99 +#else
100 +#define nd_thread_rwlock_read_locked() debug_dummy()
101 +#define nd_thread_rwlock_read_unlocked() debug_dummy()
102 +#define nd_thread_rwlock_write_locked() debug_dummy()
103 +#define nd_thread_rwlock_write_unlocked() debug_dummy()
104 +#define nd_thread_mutex_locked() debug_dummy()
105 +#define nd_thread_mutex_unlocked() debug_dummy()
106 +#define nd_thread_spinlock_locked() debug_dummy()
107 +#define nd_thread_spinlock_unlocked() debug_dummy()
108 +#define nd_thread_rwspinlock_read_locked() debug_dummy()
109 +#define nd_thread_rwspinlock_read_unlocked() debug_dummy()
110 +#define nd_thread_rwspinlock_write_locked() debug_dummy()
111 +#define nd_thread_rwspinlock_write_unlocked() debug_dummy()
112 +#endif
113
114 #endif //NETDATA_THREADS_H
src/libnetdata/url/url.c
+3 -3
@@ -25,7 +25,7 @@ char *url_encode(char *str) {
25 pbuf = buf = mallocz(strlen(str) * 3 + 1);
26
27 while (*str) {
28 - if (isalnum(*str) || *str == '-' || *str == '_' || *str == '.' || *str == '~')
28 + if (isalnum((uint8_t)*str) || *str == '-' || *str == '_' || *str == '.' || *str == '~')
29 *pbuf++ = *str;
30
31 else if (*str == ' ')
@@ -267,9 +267,9 @@ url_is_request_complete_and_extract_payload(const char *begin, const char *end,
267 const char *ct = strcasestr(begin, "Content-Type: ");
268 if(ct) {
269 ct = &ct[14];
270 - while (*ct && isspace(*ct)) ct++;
270 + while (*ct && isspace((uint8_t)*ct)) ct++;
271 const char *space = ct;
272 - while (*space && !isspace(*space) && *space != ';') space++;
272 + while (*space && !isspace((uint8_t)*space) && *space != ';') space++;
273 size_t ct_len = space - ct;
274
275 char ct_copy[ct_len + 1];
src/libnetdata/uuid/uuid.c
+33 -12
@@ -2,11 +2,10 @@
2
3 #include "../libnetdata.h"
4
5 +ND_UUID UUID_generate_from_hash(const void *payload, size_t payload_len) {
6 + assert(sizeof(XXH128_hash_t) == sizeof(ND_UUID));
7
6 -UUID UUID_generate_from_hash(const void *payload, size_t payload_len) {
7 - assert(sizeof(XXH128_hash_t) == sizeof(UUID));
8 -
9 - UUID uuid;
8 + ND_UUID uuid = UUID_ZERO;
9 XXH128_hash_t *xxh3_128 = (XXH128_hash_t *)&uuid;
10
11 // Hash the payload using XXH128
@@ -22,7 +21,7 @@ UUID UUID_generate_from_hash(const void *payload, size_t payload_len) {
21 return uuid;
22 }
23
25 -void uuid_unparse_lower_compact(const uuid_t uuid, char *out) {
24 +void uuid_unparse_lower_compact(const nd_uuid_t uuid, char *out) {
25 static const char *hex_chars = "0123456789abcdef";
26 for (int i = 0; i < 16; i++) {
27 out[i * 2] = hex_chars[(uuid[i] >> 4) & 0x0F];
@@ -31,7 +30,29 @@ void uuid_unparse_lower_compact(const uuid_t uuid, char *out) {
30 out[32] = '\0'; // Null-terminate the string
31 }
32
34 -inline int uuid_parse_compact(const char *in, uuid_t uuid) {
33 +static inline void nd_uuid_unparse_full(const nd_uuid_t uuid, char *out, const char *hex_chars) {
34 + int shifts = 0;
35 + for (int i = 0; i < 16; i++) {
36 + if (i == 4 || i == 6 || i == 8 || i == 10) {
37 + out[i * 2 + shifts] = '-';
38 + shifts++;
39 + }
40 + out[i * 2 + shifts] = hex_chars[(uuid[i] >> 4) & 0x0F];
41 + out[i * 2 + 1 + shifts] = hex_chars[uuid[i] & 0x0F];
42 + }
43 + out[36] = '\0'; // Null-terminate the string
44 +}
45 +
46 +// Wrapper functions for lower and upper case hexadecimal representation
47 +void nd_uuid_unparse_lower(const nd_uuid_t uuid, char *out) {
48 + nd_uuid_unparse_full(uuid, out, "0123456789abcdef");
49 +}
50 +
51 +void nd_uuid_unparse_upper(const nd_uuid_t uuid, char *out) {
52 + nd_uuid_unparse_full(uuid, out, "0123456789ABCDEF");
53 +}
54 +
55 +inline int uuid_parse_compact(const char *in, nd_uuid_t uuid) {
56 if (strlen(in) != 32)
57 return -1; // Invalid input length
58
@@ -48,7 +69,7 @@ inline int uuid_parse_compact(const char *in, uuid_t uuid) {
69 return 0; // Success
70 }
71
51 -int uuid_parse_flexi(const char *in, uuid_t uu) {
72 +int uuid_parse_flexi(const char *in, nd_uuid_t uu) {
73 if(!in || !*in)
74 return -1;
75
@@ -56,7 +77,7 @@ int uuid_parse_flexi(const char *in, uuid_t uu) {
77 size_t hyphenCount = 0;
78 const char *s = in;
79 int byteIndex = 0;
59 - uuid_t uuid; // work on a temporary place, to not corrupt the previous value of uu if we fail
80 + nd_uuid_t uuid; // work on a temporary place, to not corrupt the previous value of uu if we fail
81
82 while (*s && byteIndex < 16) {
83 if (*s == '-') {
@@ -68,11 +89,11 @@ int uuid_parse_flexi(const char *in, uuid_t uu) {
89 return -2;
90 }
91
71 - if (likely(isxdigit(*s))) {
92 + if (likely(isxdigit((uint8_t)*s))) {
93 int high = hex_char_to_int(*s++);
94 hexCharCount++;
95
75 - if (likely(isxdigit(*s))) {
96 + if (likely(isxdigit((uint8_t)*s))) {
97 int low = hex_char_to_int(*s++);
98 hexCharCount++;
99
@@ -100,7 +121,7 @@ int uuid_parse_flexi(const char *in, uuid_t uu) {
121 return -7;
122
123 // copy the final value
103 - memcpy(uu, uuid, sizeof(uuid_t));
124 + memcpy(uu, uuid, sizeof(nd_uuid_t));
125
126 return 0;
127 }
@@ -125,7 +146,7 @@ int uuid_unittest(void) {
146
147 int i;
148 for (i = 0; i < num_tests; i++) {
128 - uuid_t original_uuid, parsed_uuid;
149 + nd_uuid_t original_uuid, parsed_uuid;
150 char uuid_str_with_hyphens[UUID_STR_LEN], uuid_str_without_hyphens[UUID_COMPACT_STR_LEN];
151
152 // Generate a random UUID
src/libnetdata/uuid/uuid.h
+84 -19
@@ -3,39 +3,60 @@
3 #ifndef NETDATA_UUID_H
4 #define NETDATA_UUID_H
5
6 -UUID_DEFINE(streaming_from_child_msgid, 0xed,0x4c,0xdb, 0x8f, 0x1b, 0xeb, 0x4a, 0xd3, 0xb5, 0x7c, 0xb3, 0xca, 0xe2, 0xd1, 0x62, 0xfa);
7 -UUID_DEFINE(streaming_to_parent_msgid, 0x6e, 0x2e, 0x38, 0x39, 0x06, 0x76, 0x48, 0x96, 0x8b, 0x64, 0x60, 0x45, 0xdb, 0xf2, 0x8d, 0x66);
8 -UUID_DEFINE(health_alert_transition_msgid, 0x9c, 0xe0, 0xcb, 0x58, 0xab, 0x8b, 0x44, 0xdf, 0x82, 0xc4, 0xbf, 0x1a, 0xd9, 0xee, 0x22, 0xde);
6 +// for compatibility with libuuid
7 +typedef unsigned char nd_uuid_t[16];
8
10 -// this is also defined in alarm-notify.sh.in
11 -UUID_DEFINE(health_alert_notification_msgid, 0x6d, 0xb0, 0x01, 0x8e, 0x83, 0xe3, 0x43, 0x20, 0xae, 0x2a, 0x65, 0x9d, 0x78, 0x01, 0x9f, 0xb7);
12 -
13 -typedef struct {
9 +// for quickly managing it as 2x 64-bit numbers
10 +typedef struct _uuid {
11 union {
15 - uuid_t uuid;
12 + nd_uuid_t uuid;
13 struct {
14 uint64_t hig64;
15 uint64_t low64;
16 } parts;
17 };
21 -} UUID;
22 -UUID UUID_generate_from_hash(const void *payload, size_t payload_len);
18 +} ND_UUID;
19 +
20 +#ifdef __GNUC__
21 +#define ND_UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
22 + static const nd_uuid_t name __attribute__ ((unused)) = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
23 +#else
24 +#define ND_UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
25 + static const nd_uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
26 +#endif
27 +
28 +static const ND_UUID UUID_ZERO = (ND_UUID){ { .parts = { .hig64 = 0, .low64 = 0 } }};
29 +ND_UUID_DEFINE(streaming_from_child_msgid, 0xed,0x4c,0xdb, 0x8f, 0x1b, 0xeb, 0x4a, 0xd3, 0xb5, 0x7c, 0xb3, 0xca, 0xe2, 0xd1, 0x62, 0xfa);
30 +ND_UUID_DEFINE(streaming_to_parent_msgid, 0x6e, 0x2e, 0x38, 0x39, 0x06, 0x76, 0x48, 0x96, 0x8b, 0x64, 0x60, 0x45, 0xdb, 0xf2, 0x8d, 0x66);
31 +ND_UUID_DEFINE(health_alert_transition_msgid, 0x9c, 0xe0, 0xcb, 0x58, 0xab, 0x8b, 0x44, 0xdf, 0x82, 0xc4, 0xbf, 0x1a, 0xd9, 0xee, 0x22, 0xde);
32 +
33 +// this is also defined in alarm-notify.sh.in
34 +ND_UUID_DEFINE(health_alert_notification_msgid, 0x6d, 0xb0, 0x01, 0x8e, 0x83, 0xe3, 0x43, 0x20, 0xae, 0x2a, 0x65, 0x9d, 0x78, 0x01, 0x9f, 0xb7);
35 +
36 +ND_UUID UUID_generate_from_hash(const void *payload, size_t payload_len);
37
38 #define UUIDeq(a, b) ((a).parts.hig64 == (b).parts.hig64 && (a).parts.low64 == (b).parts.low64)
39
26 -static inline UUID uuid2UUID(uuid_t uu1) {
27 - UUID *ret = (UUID *)uu1;
28 - return *ret;
40 +static inline ND_UUID uuid2UUID(const nd_uuid_t uu1) {
41 + // uu1 may not be aligned, so copy it to the output
42 + ND_UUID copy;
43 + memcpy(copy.uuid, uu1, sizeof(nd_uuid_t));
44 + return copy;
45 }
46
47 +#ifndef UUID_STR_LEN
48 +// CentOS 7 has older version that doesn't define this
49 +// same goes for MacOS
50 +#define UUID_STR_LEN 37
51 +#endif
52 +
53 #define UUID_COMPACT_STR_LEN 33
32 -void uuid_unparse_lower_compact(const uuid_t uuid, char *out);
33 -int uuid_parse_compact(const char *in, uuid_t uuid);
34 -int uuid_parse_flexi(const char *in, uuid_t uuid);
54
36 -static inline int uuid_memcmp(const uuid_t *uu1, const uuid_t *uu2) {
37 - return memcmp(uu1, uu2, sizeof(uuid_t));
38 -}
55 +void uuid_unparse_lower_compact(const nd_uuid_t uuid, char *out);
56 +int uuid_parse_compact(const char *in, nd_uuid_t uuid);
57 +
58 +int uuid_parse_flexi(const char *in, nd_uuid_t uuid);
59 +#define uuid_parse(in, uuid) uuid_parse_flexi(in, uuid)
60
61 static inline int hex_char_to_int(char c) {
62 if (c >= '0' && c <= '9') return c - '0';
@@ -44,4 +65,48 @@ static inline int hex_char_to_int(char c) {
65 return -1; // Invalid hexadecimal character
66 }
67
68 +static inline void nd_uuid_clear(nd_uuid_t uu) {
69 + memset(uu, 0, sizeof(nd_uuid_t));
70 +}
71 +
72 +// Netdata does not need to sort UUIDs lexicographically and this kind
73 +// of sorting does not need to be portable between little/big endian.
74 +// So, any kind of sorting will work, as long as it compares UUIDs.
75 +// The fastest possible, is good enough.
76 +static inline int nd_uuid_compare(const nd_uuid_t uu1, const nd_uuid_t uu2) {
77 + // IMPORTANT:
78 + // uu1 or uu2 may not be aligned to word boundaries on this call,
79 + // so casting this to a struct may give SIGBUS on some architectures.
80 + return memcmp(uu1, uu2, sizeof(nd_uuid_t));
81 +}
82 +
83 +static inline void nd_uuid_copy(nd_uuid_t dst, const nd_uuid_t src) {
84 + memcpy(dst, src, sizeof(nd_uuid_t));
85 +}
86 +
87 +static inline bool nd_uuid_eq(const nd_uuid_t uu1, const nd_uuid_t uu2) {
88 + return nd_uuid_compare(uu1, uu2) == 0;
89 +}
90 +
91 +static inline int nd_uuid_is_null(const nd_uuid_t uu) {
92 + return nd_uuid_compare(uu, UUID_ZERO.uuid) == 0;
93 +}
94 +
95 +void nd_uuid_unparse_lower(const nd_uuid_t uuid, char *out);
96 +void nd_uuid_unparse_upper(const nd_uuid_t uuid, char *out);
97 +
98 +#define uuid_is_null(uu) nd_uuid_is_null(uu)
99 +#define uuid_clear(uu) nd_uuid_clear(uu)
100 +#define uuid_compare(uu1, uu2) nd_uuid_compare(uu1, uu2)
101 +#define uuid_copy(dst, src) nd_uuid_copy(dst, src)
102 +#define uuid_eq(uu1, uu2) nd_uuid_eq(uu1, uu2)
103 +
104 +#define uuid_generate(out) os_uuid_generate(out)
105 +#define uuid_generate_random(out) os_uuid_generate_random(out)
106 +#define uuid_generate_time(out) os_uuid_generate_time(out)
107 +
108 +#define uuid_unparse(uu, out) nd_uuid_unparse_lower(uu, out)
109 +#define uuid_unparse_lower(uu, out) nd_uuid_unparse_lower(uu, out)
110 +#define uuid_unparse_upper(uu, out) nd_uuid_unparse_upper(uu, out)
111 +
112 #endif //NETDATA_UUID_H
src/libnetdata/worker_utilization/worker_utilization.c
+2 -2
@@ -92,8 +92,8 @@ void worker_register(const char *name) {
92 return;
93
94 worker = callocz(1, sizeof(struct worker));
95 - worker->pid = gettid();
96 - worker->tag = strdupz(netdata_thread_tag());
95 + worker->pid = gettid_cached();
96 + worker->tag = strdupz(nd_thread_tag());
97 worker->workname = strdupz(name);
98
99 usec_t now = worker_now_monotonic_usec();
src/logsmanagement/db_api.c
+1 -1
@@ -617,7 +617,7 @@ int db_init() {
617
618 /* Create directory of collection of logs for the particular
619 * log source (in the form of a UUID) and bind it. */
620 - uuid_t uuid;
620 + nd_uuid_t uuid;
621 uuid_generate(uuid);
622 char uuid_str[UUID_STR_LEN]; // ex. "1b4e28ba-2fa1-11d2-883f-0016d3cca427" + "\0"
623 uuid_unparse_lower(uuid, uuid_str);
src/ml/ml-dummy.c
+3 -3
@@ -100,7 +100,7 @@ bool ml_dimension_is_anomalous(RRDDIM *rd, time_t curr_time, double value, bool
100 return false;
101 }
102
103 -int ml_dimension_load_models(RRDDIM *rd, sqlite3_stmt **stmp) {
103 +int ml_dimension_load_models(RRDDIM *rd, sqlite3_stmt **stmp __maybe_unused) {
104 UNUSED(rd);
105 return 0;
106 }
@@ -109,12 +109,12 @@ void ml_update_global_statistics_charts(uint64_t models_consulted) {
109 UNUSED(models_consulted);
110 }
111
112 -bool ml_host_get_host_status(RRDHOST *rh, struct ml_metrics_statistics *mlm) {
112 +bool ml_host_get_host_status(RRDHOST *rh __maybe_unused, struct ml_metrics_statistics *mlm) {
113 memset(mlm, 0, sizeof(*mlm));
114 return false;
115 }
116
117 -bool ml_host_running(RRDHOST *rh) {
117 +bool ml_host_running(RRDHOST *rh __maybe_unused) {
118 return false;
119 }
120
src/ml/ml-private.h
+3 -3
@@ -274,13 +274,13 @@ typedef struct {
274 } ml_host_t;
275
276 typedef struct {
277 - uuid_t metric_uuid;
277 + nd_uuid_t metric_uuid;
278 ml_kmeans_t kmeans;
279 } ml_model_info_t;
280
281 typedef struct {
282 size_t id;
283 - netdata_thread_t nd_thread;
283 + ND_THREAD *nd_thread;
284 netdata_mutex_t nd_mutex;
285
286 ml_queue_t *training_queue;
@@ -347,7 +347,7 @@ typedef struct {
347
348 std::vector<uint32_t> random_nums;
349
350 - netdata_thread_t detection_thread;
350 + ND_THREAD *detection_thread;
351 std::atomic<bool> detection_stop;
352
353 size_t num_training_threads;
src/ml/ml.cc
+10 -15
@@ -443,7 +443,7 @@ const char *db_models_prune =
443 "WHERE after < @after LIMIT @n;";
444
445 static int
446 -ml_dimension_add_model(const uuid_t *metric_uuid, const ml_kmeans_t *km)
446 +ml_dimension_add_model(const nd_uuid_t *metric_uuid, const ml_kmeans_t *km)
447 {
448 static __thread sqlite3_stmt *res = NULL;
449 int param = 0;
@@ -520,7 +520,7 @@ bind_fail:
520 }
521
522 static int
523 -ml_dimension_delete_models(const uuid_t *metric_uuid, time_t before)
523 +ml_dimension_delete_models(const nd_uuid_t *metric_uuid, time_t before)
524 {
525 static __thread sqlite3_stmt *res = NULL;
526 int rc = 0;
@@ -1175,7 +1175,7 @@ ml_acquired_dimension_get(char *machine_guid, STRING *chart_id, STRING *dimensio
1175 }
1176 }
1177
1178 - rrd_unlock();
1178 + rrd_rdunlock();
1179
1180 ml_acquired_dimension_t acq_dim = {
1181 acq_rh, acq_rs, acq_rd, dim
@@ -1232,7 +1232,7 @@ ml_detect_main(void *arg)
1232
1233 ml_host_detect_once((ml_host_t *) rh->ml_host);
1234 }
1235 - rrd_unlock();
1235 + rrd_rdunlock();
1236
1237 if (Cfg.enable_statistics_charts) {
1238 // collect and update training thread stats
@@ -1833,12 +1833,14 @@ void ml_start_threads() {
1833 char tag[NETDATA_THREAD_TAG_MAX + 1];
1834
1835 snprintfz(tag, NETDATA_THREAD_TAG_MAX, "%s", "PREDICT");
1836 - netdata_thread_create(&Cfg.detection_thread, tag, NETDATA_THREAD_OPTION_JOINABLE, ml_detect_main, NULL);
1836 + Cfg.detection_thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_JOINABLE,
1837 + ml_detect_main, NULL);
1838
1839 for (size_t idx = 0; idx != Cfg.num_training_threads; idx++) {
1840 ml_training_thread_t *training_thread = &Cfg.training_threads[idx];
1841 snprintfz(tag, NETDATA_THREAD_TAG_MAX, "TRAIN[%zu]", training_thread->id);
1841 - netdata_thread_create(&training_thread->nd_thread, tag, NETDATA_THREAD_OPTION_JOINABLE, ml_train_main, training_thread);
1842 + training_thread->nd_thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_JOINABLE,
1843 + ml_train_main, training_thread);
1844 }
1845 }
1846
@@ -1853,7 +1855,7 @@ void ml_stop_threads()
1855 if (!Cfg.detection_thread)
1856 return;
1857
1856 - netdata_thread_join(Cfg.detection_thread, NULL);
1858 + nd_thread_join(Cfg.detection_thread);
1859 Cfg.detection_thread = 0;
1860
1861 // signal the training queue of each thread
@@ -1863,18 +1865,11 @@ void ml_stop_threads()
1865 ml_queue_signal(training_thread->training_queue);
1866 }
1867
1866 - // cancel training threads
1867 - for (size_t idx = 0; idx != Cfg.num_training_threads; idx++) {
1868 - ml_training_thread_t *training_thread = &Cfg.training_threads[idx];
1869 -
1870 - netdata_thread_cancel(training_thread->nd_thread);
1871 - }
1872 -
1868 // join training threads
1869 for (size_t idx = 0; idx != Cfg.num_training_threads; idx++) {
1870 ml_training_thread_t *training_thread = &Cfg.training_threads[idx];
1871
1877 - netdata_thread_join(training_thread->nd_thread, NULL);
1872 + nd_thread_join(training_thread->nd_thread);
1873 }
1874
1875 // clear training thread data
src/registry/registry_init.c
-5
@@ -172,9 +172,6 @@ int registry_init(void) {
172 &netdata_configured_cache_dir,
173 use_mmap, true);
174
175 - // disable cancelability to avoid enable/disable per item in the dictionary locks
176 - netdata_thread_disable_cancelability();
177 -
175 registry_log_open();
176 registry_db_load();
177 registry_log_load();
@@ -185,8 +182,6 @@ int registry_init(void) {
182 // registry_db_stats();
183 // registry_generate_curl_urls();
184 // exit(0);
188 -
189 - netdata_thread_enable_cancelability();
185 }
186
187 return 0;
src/registry/registry_internals.c
+4 -4
@@ -11,7 +11,7 @@ struct registry registry;
11 // parse a GUID and re-generated to be always lower case
12 // this is used as a protection against the variations of GUIDs
13 int regenerate_guid(const char *guid, char *result) {
14 - uuid_t uuid;
14 + nd_uuid_t uuid;
15 if(unlikely(uuid_parse(guid, uuid) == -1)) {
16 netdata_log_info("Registry: GUID '%s' is not a valid GUID.", guid);
17 return -1;
@@ -35,12 +35,12 @@ static inline char *registry_fix_machine_name(char *name, size_t *len) {
35 char *s = name?name:"";
36
37 // skip leading spaces
38 - while(*s && isspace(*s)) s++;
38 + while(*s && isspace((uint8_t)*s)) s++;
39
40 // make sure all spaces are a SPACE
41 char *t = s;
42 while(*t) {
43 - if(unlikely(isspace(*t)))
43 + if(unlikely(isspace((uint8_t)*t)))
44 *t = ' ';
45
46 t++;
@@ -298,7 +298,7 @@ const char *registry_get_this_machine_guid(void) {
298
299 // generate a new one?
300 if(!guid[0]) {
301 - uuid_t uuid;
301 + nd_uuid_t uuid;
302
303 uuid_generate_time(uuid);
304 uuid_unparse_lower(uuid, guid);
src/registry/registry_person.c
+1 -1
@@ -118,7 +118,7 @@ REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when)
118 REGISTRY_PERSON *p = aral_mallocz(registry.persons_aral);
119 if(!person_guid) {
120 for(;;) {
121 - uuid_t uuid;
121 + nd_uuid_t uuid;
122 uuid_generate(uuid);
123 uuid_unparse_lower(uuid, p->guid);
124
src/spawn/spawn.c
-1
@@ -248,7 +248,6 @@ void spawn_init(void)
248 /* wait for spawn client thread to initialize */
249 completion_wait_for(&completion);
250 completion_destroy(&completion);
251 - uv_thread_set_name_np(thread, "DAEMON_SPAWN");
251
252 if (spawn_thread_error) {
253 error = uv_thread_join(&thread);
src/spawn/spawn_client.c
+2
@@ -170,6 +170,8 @@ static void spawn_process_cmd(struct spawn_cmd_info *cmdinfo)
170
171 void spawn_client(void *arg)
172 {
173 + uv_thread_set_name_np("DAEMON_SPAWN");
174 +
175 int ret;
176 struct completion *completion = (struct completion *)arg;
177
src/spawn/spawn_server.c
+1 -1
@@ -127,7 +127,7 @@ static void wait_children(void *arg)
127
128 while (!server_shutdown) {
129 i.si_pid = 0;
130 - if (waitid(P_ALL, (id_t) 0, &i, WEXITED) == -1) {
130 + if (os_waitid(P_ALL, (id_t) 0, &i, WEXITED) == -1) {
131 if (errno != ECHILD)
132 fprintf(stderr, "SPAWN: Failed to wait: %s\n", strerror(errno));
133 break;
src/streaming/receiver.c
+109 -85
@@ -58,8 +58,12 @@ static inline int read_stream(struct receiver_state *r, char* buffer, size_t siz
58 }
59
60 #ifdef ENABLE_H2O
61 - if (is_h2o_rrdpush(r))
61 + if (is_h2o_rrdpush(r)) {
62 + if(nd_thread_signaled_to_cancel())
63 + return -4;
64 +
65 return (int)h2o_stream_read(r->h2o_ctx, buffer, size);
66 + }
67 #endif
68
69 int tries = 100;
@@ -68,6 +72,29 @@ static inline int read_stream(struct receiver_state *r, char* buffer, size_t siz
72 do {
73 errno = 0;
74
75 + switch(wait_on_socket_or_cancel_with_timeout(
76 +#ifdef ENABLE_HTTPS
77 + &r->ssl,
78 +#endif
79 + r->fd, 0, POLLIN, NULL))
80 + {
81 + case 0: // data are waiting
82 + break;
83 +
84 + case 1: // timeout reached
85 + netdata_log_error("STREAM: %s(): timeout while waiting for data on socket!", __FUNCTION__);
86 + return -3;
87 +
88 + case -1: // thread cancelled
89 + netdata_log_error("STREAM: %s(): thread has been cancelled timeout while waiting for data on socket!", __FUNCTION__);
90 + return -4;
91 +
92 + default:
93 + case 2: // error on socket
94 + netdata_log_error("STREAM: %s() socket error!", __FUNCTION__);
95 + return -2;
96 + }
97 +
98 #ifdef ENABLE_HTTPS
99 if (SSL_connection(&r->ssl))
100 bytes_read = netdata_ssl_read(&r->ssl, buffer, size);
@@ -116,6 +143,10 @@ static inline STREAM_HANDSHAKE read_stream_error_to_reason(int code) {
143 // timeout
144 return STREAM_HANDSHAKE_DISCONNECT_SOCKET_READ_TIMEOUT;
145
146 + case -4:
147 + // the thread is cancelled
148 + return STREAM_HANDSHAKE_DISCONNECT_SHUTDOWN;
149 +
150 default:
151 // anything else
152 return STREAM_HANDSHAKE_DISCONNECT_UNKNOWN_SOCKET_READ_ERROR;
@@ -261,6 +292,11 @@ static void receiver_set_exit_reason(struct receiver_state *rpt, STREAM_HANDSHAK
292 static inline bool receiver_should_stop(struct receiver_state *rpt) {
293 static __thread size_t counter = 0;
294
295 + if(nd_thread_signaled_to_cancel()) {
296 + receiver_set_exit_reason(rpt, STREAM_HANDSHAKE_DISCONNECT_SHUTDOWN, false);
297 + return true;
298 + }
299 +
300 if(unlikely(rpt->exit.shutdown)) {
301 receiver_set_exit_reason(rpt, STREAM_HANDSHAKE_DISCONNECT_SHUTDOWN, false);
302 return true;
@@ -271,11 +307,8 @@ static inline bool receiver_should_stop(struct receiver_state *rpt) {
307 return true;
308 }
309
274 - if(unlikely((counter++ % 1000) == 0)) {
275 - // check every 1000 lines read
276 - netdata_thread_testcancel();
310 + if(unlikely((counter++ % 1000) == 0))
311 rpt->last_msg_t = now_monotonic_sec();
278 - }
312
313 return false;
314 }
@@ -307,60 +340,58 @@ static size_t streaming_parser(struct receiver_state *rpt, struct plugind *cd, i
340
341 // this keeps the parser with its current value
342 // so, parser needs to be allocated before pushing it
310 - netdata_thread_cleanup_push(pluginsd_process_thread_cleanup, parser) {
311 - bool compressed_connection = rrdpush_decompression_initialize(rpt);
312 - buffered_reader_init(&rpt->reader);
343 + CLEANUP_FUNCTION_REGISTER(pluginsd_process_thread_cleanup) parser_ptr = parser;
344 +
345 + bool compressed_connection = rrdpush_decompression_initialize(rpt);
346 + buffered_reader_init(&rpt->reader);
347
348 #ifdef NETDATA_LOG_STREAM_RECEIVE
315 - {
316 - char filename[FILENAME_MAX + 1];
317 - snprintfz(filename, FILENAME_MAX, "/tmp/stream-receiver-%s.txt", rpt->host ? rrdhost_hostname(
318 - rpt->host) : "unknown"
319 - );
320 - parser->user.stream_log_fp = fopen(filename, "w");
321 - parser->user.stream_log_repertoire = PARSER_REP_METADATA;
322 - }
349 + {
350 + char filename[FILENAME_MAX + 1];
351 + snprintfz(filename, FILENAME_MAX, "/tmp/stream-receiver-%s.txt", rpt->host ? rrdhost_hostname(
352 + rpt->host) : "unknown"
353 + );
354 + parser->user.stream_log_fp = fopen(filename, "w");
355 + parser->user.stream_log_repertoire = PARSER_REP_METADATA;
356 + }
357 #endif
358
325 - CLEAN_BUFFER *buffer = buffer_create(sizeof(rpt->reader.read_buffer), NULL);
326 -
327 - ND_LOG_STACK lgs[] = {
328 - ND_LOG_FIELD_CB(NDF_REQUEST, line_splitter_reconstruct_line, &parser->line),
329 - ND_LOG_FIELD_CB(NDF_NIDL_NODE, parser_reconstruct_node, parser),
330 - ND_LOG_FIELD_CB(NDF_NIDL_INSTANCE, parser_reconstruct_instance, parser),
331 - ND_LOG_FIELD_CB(NDF_NIDL_CONTEXT, parser_reconstruct_context, parser),
332 - ND_LOG_FIELD_END(),
333 - };
334 - ND_LOG_STACK_PUSH(lgs);
335 -
336 - while(!receiver_should_stop(rpt)) {
359 + CLEAN_BUFFER *buffer = buffer_create(sizeof(rpt->reader.read_buffer), NULL);
360
338 - if(!buffered_reader_next_line(&rpt->reader, buffer)) {
339 - STREAM_HANDSHAKE reason = STREAM_HANDSHAKE_DISCONNECT_UNKNOWN_SOCKET_READ_ERROR;
361 + ND_LOG_STACK lgs[] = {
362 + ND_LOG_FIELD_CB(NDF_REQUEST, line_splitter_reconstruct_line, &parser->line),
363 + ND_LOG_FIELD_CB(NDF_NIDL_NODE, parser_reconstruct_node, parser),
364 + ND_LOG_FIELD_CB(NDF_NIDL_INSTANCE, parser_reconstruct_instance, parser),
365 + ND_LOG_FIELD_CB(NDF_NIDL_CONTEXT, parser_reconstruct_context, parser),
366 + ND_LOG_FIELD_END(),
367 + };
368 + ND_LOG_STACK_PUSH(lgs);
369
341 - bool have_new_data = compressed_connection ? receiver_read_compressed(rpt, &reason)
342 - : receiver_read_uncompressed(rpt, &reason);
370 + while(!receiver_should_stop(rpt)) {
371
344 - if(unlikely(!have_new_data)) {
345 - receiver_set_exit_reason(rpt, reason, false);
346 - break;
347 - }
372 + if(!buffered_reader_next_line(&rpt->reader, buffer)) {
373 + STREAM_HANDSHAKE reason = STREAM_HANDSHAKE_DISCONNECT_UNKNOWN_SOCKET_READ_ERROR;
374
349 - continue;
350 - }
375 + bool have_new_data = compressed_connection ? receiver_read_compressed(rpt, &reason)
376 + : receiver_read_uncompressed(rpt, &reason);
377
352 - if(unlikely(parser_action(parser, buffer->buffer))) {
353 - receiver_set_exit_reason(rpt, STREAM_HANDSHAKE_DISCONNECT_PARSER_FAILED, false);
378 + if(unlikely(!have_new_data)) {
379 + receiver_set_exit_reason(rpt, reason, false);
380 break;
381 }
382
357 - buffer->len = 0;
358 - buffer->buffer[0] = '\0';
383 + continue;
384 }
360 - result = parser->user.data_collections_count;
361 - }
362 - netdata_thread_cleanup_pop(1); // free parser with the pop function
385
386 + if(unlikely(parser_action(parser, buffer->buffer))) {
387 + receiver_set_exit_reason(rpt, STREAM_HANDSHAKE_DISCONNECT_PARSER_FAILED, false);
388 + break;
389 + }
390 +
391 + buffer->len = 0;
392 + buffer->buffer[0] = '\0';
393 + }
394 + result = parser->user.data_collections_count;
395 return result;
396 }
397
@@ -480,7 +511,7 @@ bool stop_streaming_receiver(RRDHOST *host, STREAM_HANDSHAKE reason) {
511 shutdown(host->receiver->fd, SHUT_RDWR);
512 }
513
483 - netdata_thread_cancel(host->receiver->thread);
514 + nd_thread_signal_cancel(host->receiver->thread);
515 }
516
517 int count = 2000;
@@ -843,20 +874,18 @@ cleanup:
874 ;
875 }
876
846 -static void rrdpush_receiver_thread_cleanup(void *ptr) {
847 - struct receiver_state *rpt = (struct receiver_state *) ptr;
848 - worker_unregister();
849 -
850 - rrdhost_clear_receiver(rpt);
877 +static void rrdpush_receiver_thread_cleanup(void *pptr) {
878 + struct receiver_state *rpt = CLEANUP_FUNCTION_GET_PTR(pptr);
879 + if(!rpt) return;
880
881 netdata_log_info("STREAM '%s' [receive from [%s]:%s]: "
882 "receive thread ended (task id %d)"
854 - , rpt->hostname ? rpt->hostname : "-"
855 - , rpt->client_ip ? rpt->client_ip : "-", rpt->client_port ? rpt->client_port : "-"
856 - , gettid());
883 + , rpt->hostname ? rpt->hostname : "-"
884 + , rpt->client_ip ? rpt->client_ip : "-", rpt->client_port ? rpt->client_port : "-", gettid_cached());
885
886 + worker_unregister();
887 + rrdhost_clear_receiver(rpt);
888 receiver_state_free(rpt);
859 -
889 rrdhost_set_is_parent_label();
890 }
891
@@ -883,42 +912,37 @@ static bool stream_receiver_log_transport(BUFFER *wb, void *ptr) {
912 }
913
914 void *rrdpush_receiver_thread(void *ptr) {
886 - netdata_thread_cleanup_push(rrdpush_receiver_thread_cleanup, ptr);
887 -
888 - {
889 - worker_register("STREAMRCV");
915 + CLEANUP_FUNCTION_REGISTER(rrdpush_receiver_thread_cleanup) cleanup_ptr = ptr;
916 + worker_register("STREAMRCV");
917
891 - worker_register_job_custom_metric(WORKER_RECEIVER_JOB_BYTES_READ,
892 - "received bytes", "bytes/s",
893 - WORKER_METRIC_INCREMENT);
918 + worker_register_job_custom_metric(WORKER_RECEIVER_JOB_BYTES_READ,
919 + "received bytes", "bytes/s",
920 + WORKER_METRIC_INCREMENT);
921
895 - worker_register_job_custom_metric(WORKER_RECEIVER_JOB_BYTES_UNCOMPRESSED,
896 - "uncompressed bytes", "bytes/s",
897 - WORKER_METRIC_INCREMENT);
922 + worker_register_job_custom_metric(WORKER_RECEIVER_JOB_BYTES_UNCOMPRESSED,
923 + "uncompressed bytes", "bytes/s",
924 + WORKER_METRIC_INCREMENT);
925
899 - worker_register_job_custom_metric(WORKER_RECEIVER_JOB_REPLICATION_COMPLETION,
900 - "replication completion", "%",
901 - WORKER_METRIC_ABSOLUTE);
926 + worker_register_job_custom_metric(WORKER_RECEIVER_JOB_REPLICATION_COMPLETION,
927 + "replication completion", "%",
928 + WORKER_METRIC_ABSOLUTE);
929
903 - struct receiver_state *rpt = (struct receiver_state *) ptr;
904 - rpt->tid = gettid();
905 -
906 - ND_LOG_STACK lgs[] = {
907 - ND_LOG_FIELD_TXT(NDF_SRC_IP, rpt->client_ip),
908 - ND_LOG_FIELD_TXT(NDF_SRC_PORT, rpt->client_port),
909 - ND_LOG_FIELD_TXT(NDF_NIDL_NODE, rpt->hostname),
910 - ND_LOG_FIELD_CB(NDF_SRC_TRANSPORT, stream_receiver_log_transport, rpt),
911 - ND_LOG_FIELD_CB(NDF_SRC_CAPABILITIES, stream_receiver_log_capabilities, rpt),
912 - ND_LOG_FIELD_END(),
913 - };
914 - ND_LOG_STACK_PUSH(lgs);
930 + struct receiver_state *rpt = (struct receiver_state *) ptr;
931 + rpt->tid = gettid_cached();
932
916 - netdata_log_info("STREAM %s [%s]:%s: receive thread started", rpt->hostname, rpt->client_ip
917 - , rpt->client_port);
933 + ND_LOG_STACK lgs[] = {
934 + ND_LOG_FIELD_TXT(NDF_SRC_IP, rpt->client_ip),
935 + ND_LOG_FIELD_TXT(NDF_SRC_PORT, rpt->client_port),
936 + ND_LOG_FIELD_TXT(NDF_NIDL_NODE, rpt->hostname),
937 + ND_LOG_FIELD_CB(NDF_SRC_TRANSPORT, stream_receiver_log_transport, rpt),
938 + ND_LOG_FIELD_CB(NDF_SRC_CAPABILITIES, stream_receiver_log_capabilities, rpt),
939 + ND_LOG_FIELD_END(),
940 + };
941 + ND_LOG_STACK_PUSH(lgs);
942
919 - rrdpush_receive(rpt);
920 - }
943 + netdata_log_info("STREAM %s [%s]:%s: receive thread started", rpt->hostname, rpt->client_ip
944 + , rpt->client_port);
945
922 - netdata_thread_cleanup_pop(1);
946 + rrdpush_receive(rpt);
947 return NULL;
948 }
src/streaming/replication.c
+26 -29
@@ -1036,7 +1036,7 @@ static struct replication_thread {
1036 struct {
1037 size_t last_executed; // caching of the atomic.executed to report number of requests executed since last time
1038
1039 - netdata_thread_t **threads_ptrs;
1039 + ND_THREAD **threads_ptrs;
1040 size_t threads;
1041 } main_thread; // access is allowed only by the main thread
1042
@@ -1445,8 +1445,6 @@ static bool replication_execute_request(struct replication_request *rq, bool wor
1445 goto cleanup;
1446 }
1447
1448 - netdata_thread_disable_cancelability();
1449 -
1448 if(!rq->q) {
1449 if(likely(workers))
1450 worker_is_busy(WORKER_JOB_PREPARE_QUERY);
@@ -1468,7 +1466,6 @@ static bool replication_execute_request(struct replication_request *rq, bool wor
1466 rq->q, (size_t)((unsigned long long)rq->sender->host->sender->buffer->max_size * MAX_REPLICATION_MESSAGE_PERCENT_SENDER_BUFFER / 100ULL));
1467
1468 rq->q = NULL;
1471 - netdata_thread_enable_cancelability();
1469
1470 __atomic_add_fetch(&replication_globals.atomic.executed, 1, __ATOMIC_RELAXED);
1471
@@ -1830,43 +1827,44 @@ static int replication_pipeline_execute_next(void) {
1827 return REQUEST_OK;
1828 }
1829
1833 -static void replication_worker_cleanup(void *ptr __maybe_unused) {
1830 +static void replication_worker_cleanup(void *pptr) {
1831 + if(CLEANUP_FUNCTION_GET_PTR(pptr) != (void *)0x01) return;
1832 replication_pipeline_cancel_and_cleanup();
1833 worker_unregister();
1834 }
1835
1838 -static void *replication_worker_thread(void *ptr) {
1836 +static void *replication_worker_thread(void *ptr __maybe_unused) {
1837 + CLEANUP_FUNCTION_REGISTER(replication_worker_cleanup) cleanup_ptr = (void *)0x1;
1838 replication_initialize_workers(false);
1839
1841 - netdata_thread_cleanup_push(replication_worker_cleanup, ptr) {
1842 - while (service_running(SERVICE_REPLICATION)) {
1843 - if (unlikely(replication_pipeline_execute_next() == REQUEST_QUEUE_EMPTY)) {
1844 - sender_thread_buffer_free();
1845 - worker_is_busy(WORKER_JOB_WAIT);
1846 - worker_is_idle();
1847 - sleep_usec(1 * USEC_PER_SEC);
1848 - }
1840 + while (service_running(SERVICE_REPLICATION)) {
1841 + if (unlikely(replication_pipeline_execute_next() == REQUEST_QUEUE_EMPTY)) {
1842 + sender_thread_buffer_free();
1843 + worker_is_busy(WORKER_JOB_WAIT);
1844 + worker_is_idle();
1845 + sleep_usec(1 * USEC_PER_SEC);
1846 }
1847 }
1851 - netdata_thread_cleanup_pop(1);
1848 +
1849 return NULL;
1850 }
1851
1855 -static void replication_main_cleanup(void *ptr) {
1856 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
1852 +static void replication_main_cleanup(void *pptr) {
1853 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
1854 + if(!static_thread) return;
1855 +
1856 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
1857
1858 replication_pipeline_cancel_and_cleanup();
1859
1860 int threads = (int)replication_globals.main_thread.threads;
1861 for(int i = 0; i < threads ;i++) {
1863 - netdata_thread_join(*replication_globals.main_thread.threads_ptrs[i], NULL);
1864 - freez(replication_globals.main_thread.threads_ptrs[i]);
1865 - __atomic_sub_fetch(&replication_buffers_allocated, sizeof(netdata_thread_t), __ATOMIC_RELAXED);
1862 + nd_thread_join(replication_globals.main_thread.threads_ptrs[i]);
1863 + __atomic_sub_fetch(&replication_buffers_allocated, sizeof(ND_THREAD *), __ATOMIC_RELAXED);
1864 }
1865 freez(replication_globals.main_thread.threads_ptrs);
1866 replication_globals.main_thread.threads_ptrs = NULL;
1869 - __atomic_sub_fetch(&replication_buffers_allocated, threads * sizeof(netdata_thread_t), __ATOMIC_RELAXED);
1867 + __atomic_sub_fetch(&replication_buffers_allocated, threads * sizeof(ND_THREAD *), __ATOMIC_RELAXED);
1868
1869 aral_destroy(replication_globals.aral_rse);
1870 replication_globals.aral_rse = NULL;
@@ -1894,20 +1892,20 @@ void *replication_thread_main(void *ptr __maybe_unused) {
1892
1893 if(--threads) {
1894 replication_globals.main_thread.threads = threads;
1897 - replication_globals.main_thread.threads_ptrs = mallocz(threads * sizeof(netdata_thread_t *));
1898 - __atomic_add_fetch(&replication_buffers_allocated, threads * sizeof(netdata_thread_t), __ATOMIC_RELAXED);
1895 + replication_globals.main_thread.threads_ptrs = mallocz(threads * sizeof(ND_THREAD *));
1896 + __atomic_add_fetch(&replication_buffers_allocated, threads * sizeof(ND_THREAD *), __ATOMIC_RELAXED);
1897
1898 for(int i = 0; i < threads ;i++) {
1899 char tag[NETDATA_THREAD_TAG_MAX + 1];
1900 snprintfz(tag, NETDATA_THREAD_TAG_MAX, "REPLAY[%d]", i + 2);
1903 - replication_globals.main_thread.threads_ptrs[i] = mallocz(sizeof(netdata_thread_t));
1904 - __atomic_add_fetch(&replication_buffers_allocated, sizeof(netdata_thread_t), __ATOMIC_RELAXED);
1905 - netdata_thread_create(replication_globals.main_thread.threads_ptrs[i], tag,
1906 - NETDATA_THREAD_OPTION_JOINABLE, replication_worker_thread, NULL);
1901 + replication_globals.main_thread.threads_ptrs[i] = mallocz(sizeof(ND_THREAD *));
1902 + __atomic_add_fetch(&replication_buffers_allocated, sizeof(ND_THREAD *), __ATOMIC_RELAXED);
1903 + replication_globals.main_thread.threads_ptrs[i] = nd_thread_create(tag, NETDATA_THREAD_OPTION_JOINABLE,
1904 + replication_worker_thread, NULL);
1905 }
1906 }
1907
1910 - netdata_thread_cleanup_push(replication_main_cleanup, ptr);
1908 + CLEANUP_FUNCTION_REGISTER(replication_main_cleanup) cleanup_ptr = ptr;
1909
1910 // start from 100% completed
1911 worker_set_metric(WORKER_JOB_CUSTOM_METRIC_COMPLETION, 100.0);
@@ -2030,6 +2028,5 @@ void *replication_thread_main(void *ptr __maybe_unused) {
2028 }
2029 }
2030
2033 - netdata_thread_cleanup_pop(1);
2031 return NULL;
2032 }
src/streaming/rrdpush.c
+12 -6
@@ -192,7 +192,7 @@ int configured_as_parent() {
192
193 appconfig_wrlock(&stream_config);
194 for (section = stream_config.first_section; section; section = section->next) {
195 - uuid_t uuid;
195 + nd_uuid_t uuid;
196
197 if (uuid_parse(section->name, uuid) != -1 &&
198 appconfig_get_boolean_by_section(section, "enabled", 0)) {
@@ -610,6 +610,9 @@ int connect_to_one_of_destinations(
610 for (struct rrdpush_destinations *d = host->destinations; d; d = d->next) {
611 time_t now = now_realtime_sec();
612
613 + if(nd_thread_signaled_to_cancel())
614 + return -1;
615 +
616 if(d->postpone_reconnection_until > now)
617 continue;
618
@@ -718,7 +721,7 @@ void rrdpush_sender_thread_stop(RRDHOST *host, STREAM_HANDSHAKE reason, bool wai
721 host->sender->exit.reason = reason;
722
723 // signal it to cancel
721 - netdata_thread_cancel(host->rrdpush_sender_thread);
724 + nd_thread_signal_cancel(host->rrdpush_sender_thread);
725 }
726
727 sender_unlock(host->sender);
@@ -744,7 +747,9 @@ static void rrdpush_sender_thread_spawn(RRDHOST *host) {
747 char tag[NETDATA_THREAD_TAG_MAX + 1];
748 snprintfz(tag, NETDATA_THREAD_TAG_MAX, THREAD_TAG_STREAM_SENDER "[%s]", rrdhost_hostname(host));
749
747 - if(netdata_thread_create(&host->rrdpush_sender_thread, tag, NETDATA_THREAD_OPTION_DEFAULT, rrdpush_sender_thread, (void *) host->sender))
750 + host->rrdpush_sender_thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_DEFAULT,
751 + rrdpush_sender_thread, (void *)host->sender);
752 + if(!host->rrdpush_sender_thread)
753 nd_log_daemon(NDLP_ERR, "STREAM %s [send]: failed to create new thread for client.", rrdhost_hostname(host));
754 else
755 rrdhost_flag_set(host, RRDHOST_FLAG_RRDPUSH_SENDER_SPAWN);
@@ -795,7 +800,7 @@ static void rrdpush_receiver_takeover_web_connection(struct web_client *w, struc
800 }
801
802 void *rrdpush_receiver_thread(void *ptr);
798 -int rrdpush_receiver_thread_spawn(struct web_client *w, char *decoded_query_string, void *h2o_ctx) {
803 +int rrdpush_receiver_thread_spawn(struct web_client *w, char *decoded_query_string, void *h2o_ctx __maybe_unused) {
804
805 if(!service_running(ABILITY_STREAMING_CONNECTIONS))
806 return rrdpush_receiver_too_busy_now(w);
@@ -1155,7 +1160,7 @@ int rrdpush_receiver_thread_spawn(struct web_client *w, char *decoded_query_stri
1160 }
1161 netdata_mutex_unlock(&host->receiver_lock);
1162 }
1158 - rrd_unlock();
1163 + rrd_rdunlock();
1164
1165 if (receiver_stale && stop_streaming_receiver(host, STREAM_HANDSHAKE_DISCONNECT_STALE_RECEIVER)) {
1166 // we stopped the receiver
@@ -1197,7 +1202,8 @@ int rrdpush_receiver_thread_spawn(struct web_client *w, char *decoded_query_stri
1202 snprintfz(tag, NETDATA_THREAD_TAG_MAX, THREAD_TAG_STREAM_RECEIVER "[%s]", rpt->hostname);
1203 tag[NETDATA_THREAD_TAG_MAX] = '\0';
1204
1200 - if(netdata_thread_create(&rpt->thread, tag, NETDATA_THREAD_OPTION_DEFAULT, rrdpush_receiver_thread, (void *)rpt)) {
1205 + rpt->thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_DEFAULT, rrdpush_receiver_thread, (void *)rpt);
1206 + if(!rpt->thread) {
1207 rrdpush_receive_log_status(
1208 rpt, "can't create receiver thread",
1209 RRDPUSH_STATUS_INTERNAL_SERVER_ERROR, NDLP_ERR);
src/streaming/rrdpush.h
+2 -2
@@ -201,7 +201,7 @@ typedef enum __attribute__((packed)) {
201
202 struct sender_state {
203 RRDHOST *host;
204 - pid_t tid; // the thread id of the sender, from gettid()
204 + pid_t tid; // the thread id of the sender, from gettid_cached()
205 SENDER_FLAGS flags;
206 int timeout;
207 int default_port;
@@ -337,7 +337,7 @@ typedef struct stream_node_instance {
337 struct receiver_state {
338 RRDHOST *host;
339 pid_t tid;
340 - netdata_thread_t thread;
340 + ND_THREAD *thread;
341 int fd;
342 char *key;
343 char *hostname;
src/streaming/sender.c
+22 -18
@@ -883,9 +883,8 @@ static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_p
883 return false;
884 }
885
886 - ssize_t bytes, len = (ssize_t)strlen(http);
887 -
888 - bytes = send_timeout(
886 + ssize_t len = (ssize_t)strlen(http);
887 + ssize_t bytes = send_timeout(
888 #ifdef ENABLE_HTTPS
889 &host->sender->ssl,
890 #endif
@@ -1015,8 +1014,10 @@ static bool attempt_to_connect(struct sender_state *state) {
1014 usec_t now_ut = now_monotonic_usec();
1015 usec_t end_ut = now_ut + USEC_PER_SEC * state->reconnect_delay;
1016 while(now_ut < end_ut) {
1018 - netdata_thread_testcancel();
1019 - sleep_usec(500 * USEC_PER_MS); // seconds
1017 + if(nd_thread_signaled_to_cancel())
1018 + return false;
1019 +
1020 + sleep_usec(100 * USEC_PER_MS); // seconds
1021 now_ut = now_monotonic_usec();
1022 }
1023
@@ -1386,7 +1387,7 @@ static bool rrdpush_sender_pipe_close(RRDHOST *host, int *pipe_fds, bool reopen)
1387 }
1388
1389 void rrdpush_signal_sender_to_wake_up(struct sender_state *s) {
1389 - if(unlikely(s->tid == gettid()))
1390 + if(unlikely(s->tid == gettid_cached()))
1391 return;
1392
1393 RRDHOST *host = s->host;
@@ -1409,7 +1410,7 @@ static bool rrdhost_set_sender(RRDHOST *host) {
1410 rrdhost_flag_clear(host, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED | RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
1411 rrdhost_flag_set(host, RRDHOST_FLAG_RRDPUSH_SENDER_SPAWN);
1412 host->rrdpush_sender_connection_counter++;
1412 - host->sender->tid = gettid();
1413 + host->sender->tid = gettid_cached();
1414 host->sender->last_state_since_t = now_realtime_sec();
1415 host->sender->exit.reason = STREAM_HANDSHAKE_NEVER;
1416 ret = true;
@@ -1424,7 +1425,7 @@ static bool rrdhost_set_sender(RRDHOST *host) {
1425 static void rrdhost_clear_sender___while_having_sender_mutex(RRDHOST *host) {
1426 if(unlikely(!host->sender)) return;
1427
1427 - if(host->sender->tid == gettid()) {
1428 + if(host->sender->tid == gettid_cached()) {
1429 host->sender->tid = 0;
1430 host->sender->exit.shutdown = false;
1431 rrdhost_flag_clear(host, RRDHOST_FLAG_RRDPUSH_SENDER_SPAWN | RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED | RRDHOST_FLAG_RRDPUSH_SENDER_READY_4_METRICS);
@@ -1439,8 +1440,11 @@ static void rrdhost_clear_sender___while_having_sender_mutex(RRDHOST *host) {
1440 }
1441
1442 static bool rrdhost_sender_should_exit(struct sender_state *s) {
1442 - // check for outstanding cancellation requests
1443 - netdata_thread_testcancel();
1443 + if(unlikely(nd_thread_signaled_to_cancel())) {
1444 + if(!s->exit.reason)
1445 + s->exit.reason = STREAM_HANDSHAKE_DISCONNECT_SHUTDOWN;
1446 + return true;
1447 + }
1448
1449 if(unlikely(!service_running(SERVICE_STREAMING))) {
1450 if(!s->exit.reason)
@@ -1469,8 +1473,10 @@ static bool rrdhost_sender_should_exit(struct sender_state *s) {
1473 return false;
1474 }
1475
1472 -static void rrdpush_sender_thread_cleanup_callback(void *ptr) {
1473 - struct rrdpush_sender_thread_data *s = ptr;
1476 +static void rrdpush_sender_thread_cleanup_callback(void *pptr) {
1477 + struct rrdpush_sender_thread_data *s = CLEANUP_FUNCTION_GET_PTR(pptr);
1478 + if(!s) return;
1479 +
1480 worker_unregister();
1481
1482 RRDHOST *host = s->host;
@@ -1615,19 +1621,19 @@ void *rrdpush_sender_thread(void *ptr) {
1621 !*s->host->rrdpush_send_destination || !s->host->rrdpush_send_api_key ||
1622 !*s->host->rrdpush_send_api_key) {
1623 netdata_log_error("STREAM %s [send]: thread created (task id %d), but host has streaming disabled.",
1618 - rrdhost_hostname(s->host), gettid());
1624 + rrdhost_hostname(s->host), gettid_cached());
1625 return NULL;
1626 }
1627
1628 if(!rrdhost_set_sender(s->host)) {
1629 netdata_log_error("STREAM %s [send]: thread created (task id %d), but there is another sender running for this host.",
1624 - rrdhost_hostname(s->host), gettid());
1630 + rrdhost_hostname(s->host), gettid_cached());
1631 return NULL;
1632 }
1633
1634 rrdpush_initialize_ssl_ctx(s->host);
1635
1630 - netdata_log_info("STREAM %s [send]: thread created (task id %d)", rrdhost_hostname(s->host), gettid());
1636 + netdata_log_info("STREAM %s [send]: thread created (task id %d)", rrdhost_hostname(s->host), gettid_cached());
1637
1638 s->timeout = (int)appconfig_get_number(
1639 &stream_config, CONFIG_SECTION_STREAM, "timeout seconds", 600);
@@ -1670,7 +1676,7 @@ void *rrdpush_sender_thread(void *ptr) {
1676 thread_data->pipe_buffer = mallocz(pipe_buffer_size);
1677 thread_data->host = s->host;
1678
1673 - netdata_thread_cleanup_push(rrdpush_sender_thread_cleanup_callback, thread_data);
1679 + CLEANUP_FUNCTION_REGISTER(rrdpush_sender_thread_cleanup_callback) cleanup_ptr = thread_data;
1680
1681 size_t iterations = 0;
1682 time_t now_s = now_monotonic_sec();
@@ -1794,7 +1800,6 @@ void *rrdpush_sender_thread(void *ptr) {
1800
1801 // Spurious wake-ups without error - loop again
1802 if (poll_rc == 0 || ((poll_rc == -1) && (errno == EAGAIN || errno == EINTR))) {
1797 - netdata_thread_testcancel();
1803 netdata_log_debug(D_STREAM, "Spurious wakeup");
1804 now_s = now_monotonic_sec();
1805 continue;
@@ -1888,6 +1893,5 @@ void *rrdpush_sender_thread(void *ptr) {
1893 worker_set_metric(WORKER_SENDER_JOB_REPLAY_DICT_SIZE, (NETDATA_DOUBLE) dictionary_entries(s->replication.requests));
1894 }
1895
1891 - netdata_thread_cleanup_pop(1);
1896 return NULL;
1897 }
src/web/api/badges/web_buffer_svg.c
+1 -1
@@ -255,7 +255,7 @@ static inline char *format_value_with_precision_and_unit(char *value_string, siz
255 value = 0.0;
256
257 char *separator = "";
258 - if(unlikely(isalnum(*units)))
258 + if(unlikely(isalnum((uint8_t)*units)))
259 separator = " ";
260
261 if(precision < 0) {
src/web/api/formatters/charts2json.c
+1 -1
@@ -96,7 +96,7 @@ void charts2json(RRDHOST *host, BUFFER *wb) {
96 buffer_json_object_close(wb);
97 }
98 }
99 - rrd_unlock();
99 + rrd_rdunlock();
100 }
101 buffer_json_array_close(wb);
102
src/web/api/http_auth.c
+2 -2
@@ -8,7 +8,7 @@ bool netdata_is_protected_by_bearer = false; // this is controlled by cloud, at
8 static DICTIONARY *netdata_authorized_bearers = NULL;
9
10 struct bearer_token {
11 - uuid_t cloud_account_id;
11 + nd_uuid_t cloud_account_id;
12 char cloud_user_name[CLOUD_USER_NAME_LENGTH];
13 HTTP_ACCESS access;
14 HTTP_USER_ROLE user_role;
@@ -59,7 +59,7 @@ void bearer_tokens_init(void) {
59 NULL, sizeof(struct bearer_token));
60 }
61
62 -time_t bearer_create_token(uuid_t *uuid, struct web_client *w) {
62 +time_t bearer_create_token(nd_uuid_t *uuid, struct web_client *w) {
63 char uuid_str[UUID_COMPACT_STR_LEN];
64
65 uuid_generate_random(*uuid);
src/web/api/http_auth.h
+1 -1
@@ -11,7 +11,7 @@ extern bool netdata_is_protected_by_bearer;
11
12 bool extract_bearer_token_from_request(struct web_client *w, char *dst, size_t dst_len);
13
14 -time_t bearer_create_token(uuid_t *uuid, struct web_client *w);
14 +time_t bearer_create_token(nd_uuid_t *uuid, struct web_client *w);
15 bool web_client_bearer_token_auth(struct web_client *w, const char *v);
16
17 static inline bool http_access_user_has_enough_access_level_for_endpoint(HTTP_ACCESS user, HTTP_ACCESS endpoint) {
src/web/api/http_header.c
+1 -1
@@ -170,7 +170,7 @@ static void http_header_x_netdata_auth(struct web_client *w, const char *v, size
170
171 if(strncasecmp(v, "Bearer ", 7) == 0) {
172 v = &v[7];
173 - while(*v && isspace(*v)) v++;
173 + while(*v && isspace((uint8_t)*v)) v++;
174 web_client_bearer_token_auth(w, v);
175 }
176 }
src/web/api/queries/countif/countif.h
+2 -2
@@ -28,7 +28,7 @@ static inline void tg_countif_create(RRDR *r, const char *options __maybe_unused
28
29 if(options && *options) {
30 // skip any leading spaces
31 - while(isspace(*options)) options++;
31 + while(isspace((uint8_t)*options)) options++;
32
33 // find the comparison function
34 switch(*options) {
@@ -73,7 +73,7 @@ static inline void tg_countif_create(RRDR *r, const char *options __maybe_unused
73 if(*options) options++;
74
75 // skip everything up to the first digit
76 - while(isspace(*options)) options++;
76 + while(isspace((uint8_t)*options)) options++;
77
78 g->target = str2ndd(options, NULL);
79 }
src/web/api/queries/weights.h
+1 -1
@@ -58,7 +58,7 @@ typedef struct query_weights_request {
58 weights_interrupt_callback_t interrupt_callback;
59 void *interrupt_callback_data;
60
61 - uuid_t *transaction;
61 + nd_uuid_t *transaction;
62 } QUERY_WEIGHTS_REQUEST;
63
64 int web_api_v12_weights(BUFFER *wb, QUERY_WEIGHTS_REQUEST *qwr);
src/web/api/web_api.h
+1 -1
@@ -28,7 +28,7 @@ static inline void fix_google_param(char *s) {
28 if(unlikely(!s || !*s)) return;
29
30 for( ; *s ;s++) {
31 - if(!isalnum(*s) && *s != '.' && *s != '_' && *s != '-')
31 + if(!isalnum((uint8_t)*s) && *s != '.' && *s != '_' && *s != '-')
32 *s = '_';
33 }
34 }
src/web/api/web_api_v1.c
+3 -3
@@ -142,7 +142,7 @@ void web_client_api_v1_init(void) {
142
143 time_grouping_init();
144
145 - uuid_t uuid;
145 + nd_uuid_t uuid;
146
147 // generate
148 uuid_generate(uuid);
@@ -181,7 +181,7 @@ char *get_mgmt_api_key(void) {
181
182 // generate a new one?
183 if(!guid[0]) {
184 - uuid_t uuid;
184 + nd_uuid_t uuid;
185
186 uuid_generate_time(uuid);
187 uuid_unparse_lower(uuid, guid);
@@ -1233,7 +1233,7 @@ static inline void web_client_api_request_v1_info_mirrored_hosts(BUFFER *wb) {
1233 }
1234 buffer_json_array_close(wb);
1235
1236 - rrd_unlock();
1236 + rrd_rdunlock();
1237 }
1238
1239 void host_labels2json(RRDHOST *host, BUFFER *wb, const char *key) {
src/web/api/web_api_v2.c
+2 -2
@@ -99,7 +99,7 @@ int api_v2_bearer_token(RRDHOST *host __maybe_unused, struct web_client *w __may
99 return HTTP_RESP_BAD_REQUEST;
100 }
101
102 - uuid_t uuid;
102 + nd_uuid_t uuid;
103 time_t expires_s = bearer_create_token(&uuid, w);
104
105 BUFFER *wb = w->response.data;
@@ -575,7 +575,7 @@ static int web_client_api_request_v2_progress(RRDHOST *host __maybe_unused, stru
575 if(!strcmp(name, "transaction")) transaction = value;
576 }
577
578 - uuid_t tr;
578 + nd_uuid_t tr;
579 uuid_parse_flexi(transaction, tr);
580
581 rrd_function_call_progresser(&tr);
src/web/rtc/webrtc.c
+7 -7
@@ -366,7 +366,7 @@ static void myOpenCallback(int id __maybe_unused, void *user_ptr) {
366 WEBRTC_DC *chan = user_ptr;
367 internal_fatal(chan->dc != id, "WEBRTC[%d],DC[%d]: dc mismatch, expected %d, got %d", chan->conn->pc, chan->dc, chan->dc, id);
368
369 - nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d],DC[%d]: %d DATA CHANNEL '%s' OPEN", chan->conn->pc, chan->dc, gettid(), chan->label);
369 + nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d],DC[%d]: %d DATA CHANNEL '%s' OPEN", chan->conn->pc, chan->dc, gettid_cached(), chan->label);
370 internal_error(true, "WEBRTC[%d],DC[%d]: data channel opened.", chan->conn->pc, chan->dc);
371 chan->open = true;
372 }
@@ -384,7 +384,7 @@ static void myClosedCallback(int id __maybe_unused, void *user_ptr) {
384 DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(chan->conn->channels.head, chan, link.prev, link.next);
385 spinlock_unlock(&chan->conn->channels.spinlock);
386
387 - nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d],DC[%d]: %d DATA CHANNEL '%s' CLOSED", chan->conn->pc, chan->dc, gettid(), chan->label);
387 + nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d],DC[%d]: %d DATA CHANNEL '%s' CLOSED", chan->conn->pc, chan->dc, gettid_cached(), chan->label);
388
389 freez(chan->label);
390 freez(chan);
@@ -566,27 +566,27 @@ static void myStateChangeCallback(int pc __maybe_unused, rtcState state, void *u
566 break;
567
568 case RTC_CONNECTING:
569 - nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTING", conn->pc, gettid());
569 + nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTING", conn->pc, gettid_cached());
570 internal_error(true, "WEBRTC[%d]: connecting...", conn->pc);
571 break;
572
573 case RTC_CONNECTED:
574 - nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTED", conn->pc, gettid());
574 + nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTED", conn->pc, gettid_cached());
575 internal_error(true, "WEBRTC[%d]: connected!", conn->pc);
576 break;
577
578 case RTC_DISCONNECTED:
579 - nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d DISCONNECTED", conn->pc, gettid());
579 + nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d DISCONNECTED", conn->pc, gettid_cached());
580 internal_error(true, "WEBRTC[%d]: disconnected.", conn->pc);
581 break;
582
583 case RTC_FAILED:
584 - nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTION FAILED", conn->pc, gettid());
584 + nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTION FAILED", conn->pc, gettid_cached());
585 internal_error(true, "WEBRTC[%d]: failed.", conn->pc);
586 break;
587
588 case RTC_CLOSED:
589 - nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTION CLOSED", conn->pc, gettid());
589 + nd_log(NDLS_ACCESS, NDLP_DEBUG, "WEBRTC[%d]: %d CONNECTION CLOSED", conn->pc, gettid_cached());
590 internal_error(true, "WEBRTC[%d]: closed.", conn->pc);
591 spinlock_lock(&webrtc_base.unsafe.spinlock);
592 webrtc_destroy_connection_unsafe(conn);
src/web/server/h2o/http_server.c
-2
@@ -363,8 +363,6 @@ void *h2o_main(void *ptr) {
363 h2o_pathconf_t *pathconf;
364 h2o_hostconf_t *hostconf;
365
366 - netdata_thread_disable_cancelability();
367 -
366 const char *bind_addr = config_get(HTTPD_CONFIG_SECTION, "bind to", "127.0.0.1");
367 int bind_port = config_get_number(HTTPD_CONFIG_SECTION, "port", 19998);
368
src/web/server/static/static-threaded.c
+32 -31
@@ -61,7 +61,7 @@ static struct web_client *web_client_create_on_fd(POLLINFO *pi) {
61 // the main socket listener - STATIC-THREADED
62
63 struct web_server_static_threaded_worker {
64 - netdata_thread_t thread;
64 + ND_THREAD *thread;
65
66 int id;
67 int running;
@@ -394,8 +394,9 @@ cleanup:
394 // ----------------------------------------------------------------------------
395 // web server worker thread
396
397 -static void socket_listen_main_static_threaded_worker_cleanup(void *ptr) {
398 - worker_private = (struct web_server_static_threaded_worker *)ptr;
397 +static void socket_listen_main_static_threaded_worker_cleanup(void *pptr) {
398 + worker_private = CLEANUP_FUNCTION_GET_PTR(pptr);
399 + if(!worker_private) return;
400
401 netdata_log_info("stopped after %zu connects, %zu disconnects (max concurrent %zu), %zu receptions and %zu sends",
402 worker_private->connected,
@@ -414,7 +415,7 @@ static bool web_server_should_stop(void) {
415 }
416
417 void *socket_listen_main_static_threaded_worker(void *ptr) {
417 - worker_private = (struct web_server_static_threaded_worker *)ptr;
418 + worker_private = ptr;
419 worker_private->running = 1;
420 worker_register("WEB");
421 worker_register_job_name(WORKER_JOB_ADD_CONNECTION, "connect");
@@ -427,26 +428,24 @@ void *socket_listen_main_static_threaded_worker(void *ptr) {
428 worker_register_job_name(WORKER_JOB_SND_DATA, "send");
429 worker_register_job_name(WORKER_JOB_PROCESS, "process");
430
430 - netdata_thread_cleanup_push(socket_listen_main_static_threaded_worker_cleanup, ptr);
431 -
432 - poll_events(&api_sockets
433 - , web_server_add_callback
434 - , web_server_del_callback
435 - , web_server_rcv_callback
436 - , web_server_snd_callback
437 - , NULL
438 - , web_server_should_stop
439 - , web_allow_connections_from
440 - , web_allow_connections_dns
441 - , NULL
442 - , web_client_first_request_timeout
443 - , web_client_timeout
444 - , default_rrd_update_every * 1000 // timer_milliseconds
445 - , ptr // timer_data
446 - , worker_private->max_sockets
447 - );
448 -
449 - netdata_thread_cleanup_pop(1);
431 + CLEANUP_FUNCTION_REGISTER(socket_listen_main_static_threaded_worker_cleanup) cleanup_ptr = worker_private;
432 + poll_events(&api_sockets
433 + , web_server_add_callback
434 + , web_server_del_callback
435 + , web_server_rcv_callback
436 + , web_server_snd_callback
437 + , NULL
438 + , web_server_should_stop
439 + , web_allow_connections_from
440 + , web_allow_connections_dns
441 + , NULL
442 + , web_client_first_request_timeout
443 + , web_client_timeout
444 + , default_rrd_update_every * 1000 // timer_milliseconds
445 + , ptr // timer_data
446 + , worker_private->max_sockets
447 + );
448 +
449 return NULL;
450 }
451
@@ -454,8 +453,10 @@ void *socket_listen_main_static_threaded_worker(void *ptr) {
453 // ----------------------------------------------------------------------------
454 // web server main thread - also becomes a worker
455
457 -static void socket_listen_main_static_threaded_cleanup(void *ptr) {
458 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
456 +static void socket_listen_main_static_threaded_cleanup(void *pptr) {
457 + struct netdata_static_thread *static_thread = CLEANUP_FUNCTION_GET_PTR(pptr);
458 + if(!static_thread) return;
459 +
460 static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
461
462 // int i, found = 0;
@@ -466,7 +467,7 @@ static void socket_listen_main_static_threaded_cleanup(void *ptr) {
467 // if(static_workers_private_data[i].running) {
468 // found++;
469 // netdata_log_info("stopping worker %d", i + 1);
469 -// netdata_thread_cancel(static_workers_private_data[i].thread);
470 +// nd_thread_signal_cancel(static_workers_private_data[i].thread);
471 // }
472 // else
473 // netdata_log_info("found stopped worker %d", i + 1);
@@ -496,7 +497,7 @@ static void socket_listen_main_static_threaded_cleanup(void *ptr) {
497 }
498
499 void *socket_listen_main_static_threaded(void *ptr) {
499 - netdata_thread_cleanup_push(socket_listen_main_static_threaded_cleanup, ptr);
500 + CLEANUP_FUNCTION_REGISTER(socket_listen_main_static_threaded_cleanup) cleanup_ptr = ptr;
501 web_server_mode = WEB_SERVER_MODE_STATIC_THREADED;
502
503 if(!api_sockets.opened)
@@ -548,14 +549,14 @@ void *socket_listen_main_static_threaded(void *ptr) {
549 snprintfz(tag, sizeof(tag) - 1, "WEB[%d]", i+1);
550
551 netdata_log_info("starting worker %d", i+1);
551 - netdata_thread_create(&static_workers_private_data[i].thread, tag, NETDATA_THREAD_OPTION_DEFAULT,
552 - socket_listen_main_static_threaded_worker, (void *)&static_workers_private_data[i]);
552 + static_workers_private_data[i].thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_DEFAULT,
553 + socket_listen_main_static_threaded_worker,
554 + (void *)&static_workers_private_data[i]);
555 }
556
557 // and the main one
558 static_workers_private_data[0].max_sockets = max_sockets / static_threaded_workers_count;
559 socket_listen_main_static_threaded_worker((void *)&static_workers_private_data[0]);
560
559 - netdata_thread_cleanup_pop(1);
561 return NULL;
562 }
src/web/server/web_client.c
+3 -3
@@ -130,7 +130,7 @@ static inline char *strip_control_characters(char *url) {
130 if(!url) return "";
131
132 for(char *s = url; *s ;s++)
133 - if(iscntrl(*s)) *s = ' ';
133 + if(iscntrl((uint8_t)*s)) *s = ' ';
134
135 return url;
136 }
@@ -479,7 +479,7 @@ static int mysendfile(struct web_client *w, char *filename) {
479 // if the filename contains "strange" characters, refuse to serve it
480 char *s;
481 for(s = filename; *s ;s++) {
482 - if( !isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
482 + if( !isalnum((uint8_t)*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
483 netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
484 w->response.data->content_type = CT_TEXT_HTML;
485 buffer_sprintf(w->response.data, "Filename contains invalid characters: ");
@@ -1065,7 +1065,7 @@ static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, ch
1065 if(!host) {
1066 // we didn't find it, but it may be a uuid case mismatch for MACHINE_GUID
1067 // so, recreate the machine guid in lower-case.
1068 - uuid_t uuid;
1068 + nd_uuid_t uuid;
1069 char txt[UUID_STR_LEN];
1070 if (uuid_parse(tok, uuid) == 0) {
1071 uuid_unparse_lower(uuid, txt);
src/web/server/web_client.h
+3 -3
@@ -165,7 +165,7 @@ struct web_client {
165 unsigned long long id;
166 size_t use_count;
167
168 - uuid_t transaction;
168 + nd_uuid_t transaction;
169
170 WEB_CLIENT_FLAGS flags; // status flags for the client
171 HTTP_REQUEST_MODE mode; // the operational mode of the client
@@ -207,8 +207,8 @@ struct web_client {
207 #endif
208
209 struct {
210 - uuid_t bearer_token;
211 - uuid_t cloud_account_id;
210 + nd_uuid_t bearer_token;
211 + nd_uuid_t cloud_account_id;
212 char client_name[CLOUD_USER_NAME_LENGTH];
213 } auth;
214