Created attachment 14406 [details] Timer application I have following ubuntu environment: Description: Ubuntu 20.04.1 LTS Release: 20.04 gcc 9.4.0 Linux version 5.15.0-48-generic libc-2.31.so I am using libc timer_create system call with option SIGEV_THREAD to create a timer, My timer functionality is working fine but when I exit my code after successfully deletion of timer using timer_delete system call I am getting 272 bytes of memory leak in valgrind report. I have attached my sample application(timer_app.c). Please review and let me know if I am doing anything wrong here. below is the valgrind memory leak snippet ==682959== 272 bytes in 1 blocks are possibly lost in loss record 1 of 1 ==682959== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==682959== by 0x40149DA: allocate_dtv (dl-tls.c:286) ==682959== by 0x40149DA: _dl_allocate_tls (dl-tls.c:532) ==682959== by 0x4A65322: allocate_stack (allocatestack.c:622) ==682959== by 0x4A65322: pthread_create@@GLIBC_2.2.5 (pthread_create.c:660) ==682959== by 0x4865BCC: __start_helper_thread (timer_routines.c:176) ==682959== by 0x4A6D4DE: __pthread_once_slow (pthread_once.c:116) ==682959== by 0x48649A2: timer_create@@GLIBC_2.3.3 (timer_create.c:101) ==682959== by 0x1092F1: SupTimerInit (in /home/vikas/a.out) ==682959== by 0x109490: main (in /home/vikas/a.out) ======================================================================= complete valgrind dump ==682959== Memcheck, a memory error detector ==682959== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==682959== Using Valgrind-3.15.0-608cb11914-20190413 and LibVEX; rerun with -h for copyright info ==682959== Command: ./a.out ==682959== Parent PID: 681415 ==682959== --682959-- --682959-- Valgrind options: --682959-- --leak-check=full --682959-- --show-leak-kinds=all --682959-- --track-origins=yes --682959-- --verbose --682959-- --log-file=valgrind-out.txt --682959-- Contents of /proc/version: --682959-- Linux version 5.15.0-48-generic (buildd@lcy02-amd64-043) (gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #54~20.04.1-Ubuntu SMP Thu Sep 1 16:17:26 UTC 2022 --682959-- --682959-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-ssse3-avx-avx2-bmi-f16c-rdrand --682959-- Page sizes: currently 4096, max supported 4096 --682959-- Valgrind library directory: /usr/lib/x86_64-linux-gnu/valgrind --682959-- Reading syms from /home/vikas/a.out --682959-- Reading syms from /usr/lib/x86_64-linux-gnu/ld-2.31.so --682959-- Considering /usr/lib/debug/.build-id/45/87364908de169dec62ffa538170118c1c3a078.debug .. --682959-- .. build-id is valid --682959-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux --682959-- object doesn't have a symbol table --682959-- object doesn't have a dynamic symbol table --682959-- Scheduler: using generic scheduler lock implementation. --682959-- Reading suppressions file: /usr/lib/x86_64-linux-gnu/valgrind/default.supp ==682959== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-682959-by-vikas-on-??? ==682959== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-682959-by-vikas-on-??? ==682959== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-682959-by-vikas-on-??? ==682959== ==682959== TO CONTROL THIS PROCESS USING vgdb (which you probably ==682959== don't want to do, unless you know exactly what you're doing, ==682959== or are doing some strange experiment): ==682959== /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=682959 ...command... ==682959== ==682959== TO DEBUG THIS PROCESS USING GDB: start GDB like this ==682959== /path/to/gdb ./a.out ==682959== and then give GDB the following command ==682959== target remote | /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=682959 ==682959== --pid is optional if only one valgrind process is running ==682959== --682959-- REDIR: 0x4022e20 (ld-linux-x86-64.so.2:strlen) redirected to 0x580c9ce2 (???) --682959-- REDIR: 0x4022bf0 (ld-linux-x86-64.so.2:index) redirected to 0x580c9cfc (???) --682959-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so --682959-- object doesn't have a symbol table --682959-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so --682959-- object doesn't have a symbol table ==682959== WARNING: new redirection conflicts with existing -- ignoring it --682959-- old: 0x04022e20 (strlen ) R-> (0000.0) 0x580c9ce2 ??? --682959-- new: 0x04022e20 (strlen ) R-> (2007.0) 0x0483f060 strlen --682959-- REDIR: 0x401f600 (ld-linux-x86-64.so.2:strcmp) redirected to 0x483ffd0 (strcmp) --682959-- REDIR: 0x4023380 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4843a20 (mempcpy) --682959-- Reading syms from /usr/lib/x86_64-linux-gnu/librt-2.31.so --682959-- Considering /usr/lib/debug/.build-id/ce/016c975d94bc4770ed8c62d45dea6b71405a2c.debug .. --682959-- .. build-id is valid --682959-- Reading syms from /usr/lib/x86_64-linux-gnu/libc-2.31.so --682959-- Considering /usr/lib/debug/.build-id/18/78e6b475720c7c51969e69ab2d276fae6d1dee.debug .. --682959-- .. build-id is valid --682959-- Reading syms from /usr/lib/x86_64-linux-gnu/libpthread-2.31.so --682959-- Considering /usr/lib/debug/.build-id/7b/4536f41cdaa5888408e82d0836e33dcf436466.debug .. --682959-- .. build-id is valid --682959-- REDIR: 0x490a480 (libc.so.6:memmove) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4909780 (libc.so.6:strncpy) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a7b0 (libc.so.6:strcasecmp) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x49090a0 (libc.so.6:strcat) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x49097e0 (libc.so.6:rindex) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490bc50 (libc.so.6:rawmemchr) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4926ce0 (libc.so.6:wmemchr) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4926820 (libc.so.6:wcscmp) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a5e0 (libc.so.6:mempcpy) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a410 (libc.so.6:bcmp) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4909710 (libc.so.6:strncmp) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4909150 (libc.so.6:strcmp) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a540 (libc.so.6:memset) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x49267e0 (libc.so.6:wcschr) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4909670 (libc.so.6:strnlen) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4909230 (libc.so.6:strcspn) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a800 (libc.so.6:strncasecmp) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x49091d0 (libc.so.6:strcpy) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a950 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4927f50 (libc.so.6:wcsnlen) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4926860 (libc.so.6:wcscpy) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4909820 (libc.so.6:strpbrk) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4909100 (libc.so.6:index) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4909630 (libc.so.6:strlen) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4912bb0 (libc.so.6:memrchr) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a850 (libc.so.6:strcasecmp_l) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a3d0 (libc.so.6:memchr) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4926930 (libc.so.6:wcslen) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x4909ae0 (libc.so.6:strspn) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a750 (libc.so.6:stpncpy) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a6f0 (libc.so.6:stpcpy) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490bc90 (libc.so.6:strchrnul) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x490a8a0 (libc.so.6:strncasecmp_l) redirected to 0x48331d0 (_vgnU_ifunc_wrapper) --682959-- REDIR: 0x49f2500 (libc.so.6:__strrchr_avx2) redirected to 0x483ea10 (rindex) --682959-- REDIR: 0x4905b10 (libc.so.6:calloc) redirected to 0x483dce0 (calloc) --682959-- REDIR: 0x49046d0 (libc.so.6:free) redirected to 0x483c9d0 (free) --682959-- REDIR: 0x49040e0 (libc.so.6:malloc) redirected to 0x483b780 (malloc) --682959-- REDIR: 0x49f2310 (libc.so.6:__strchrnul_avx2) redirected to 0x4843540 (strchrnul) --682959-- REDIR: 0x49f56c0 (libc.so.6:__mempcpy_avx_unaligned_erms) redirected to 0x4843660 (mempcpy) --682959-- REDIR: 0x49f5b60 (libc.so.6:__memset_avx2_unaligned_erms) redirected to 0x48428e0 (memset) ==682959== ==682959== HEAP SUMMARY: ==682959== in use at exit: 272 bytes in 1 blocks ==682959== total heap usage: 6 allocs, 5 frees, 1,688 bytes allocated ==682959== ==682959== Searching for pointers to 1 not-freed blocks ==682959== Checked 116,416 bytes ==682959== ==682959== 272 bytes in 1 blocks are possibly lost in loss record 1 of 1 ==682959== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==682959== by 0x40149DA: allocate_dtv (dl-tls.c:286) ==682959== by 0x40149DA: _dl_allocate_tls (dl-tls.c:532) ==682959== by 0x4A65322: allocate_stack (allocatestack.c:622) ==682959== by 0x4A65322: pthread_create@@GLIBC_2.2.5 (pthread_create.c:660) ==682959== by 0x4865BCC: __start_helper_thread (timer_routines.c:176) ==682959== by 0x4A6D4DE: __pthread_once_slow (pthread_once.c:116) ==682959== by 0x48649A2: timer_create@@GLIBC_2.3.3 (timer_create.c:101) ==682959== by 0x1092F1: SupTimerInit (in /home/vikas/a.out) ==682959== by 0x109490: main (in /home/vikas/a.out) ==682959== ==682959== LEAK SUMMARY: ==682959== definitely lost: 0 bytes in 0 blocks ==682959== indirectly lost: 0 bytes in 0 blocks ==682959== possibly lost: 272 bytes in 1 blocks ==682959== still reachable: 0 bytes in 0 blocks ==682959== suppressed: 0 bytes in 0 blocks ==682959== ==682959== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) Regards, Vikas
This is by design, Linux timer_crate/SIGEV_THREAD creates a helper detached thread on the first usage that acts as an activator for the callbacks. The timer_delete removes the timer from the internal list, the background thread is kept so a next timer_create do not need to recreate it. This is done as an optimization: it trades some contention on accessing the internal list (so the helper thread can find and execute the timer callback) with the need to create/destroy a thread for each timer invocation. I expect that for a limited number of timers it should be way faster (although thread creation is somewhat fast, it still has some overhead and issues a bunch of syscalls), I am not sure if the number of configured signals it still yields better performance.
Hi Adhemerval Zanella, Thanks for your comments. Do we have any mechanism by which we can free the timer helper detachable thread resources. I have used pthread_detach(pthread_self()) system call in timer handler function but that doesn't work.
We don't really know if all but one thread have been stopped when __libc_freeres is called by the leak detector. valgrind does this, but other callers might not or might not have the capability to do that because Linux does not provide it. If those threads are still running, bad things will happen if we free the DTV and other per-thread data. The best thing we can probably do here is not to use malloc to allocate DTVs and other low-level per-thread data structures, effectively hiding these allocations from the leak detector.
I can confirm that on my environment. Operating System: Slackware 15.0 (Current) Kernel Version: 5.19.17 (64-bit) Processors: 8 × Intel® Core™ i7-8565U CPU @ 1.80GHz gcc (GCC) : 12.2.0 glibc: 2.36