@@ -1822,12 +1822,14 @@ void closeDirectLogFiledes(int fd) {
1822
1822
1823
1823
#ifdef HAVE_BACKTRACE
1824
1824
#define BACKTRACE_MAX_SIZE 100
1825
+
1825
1826
#ifdef __linux__
1826
1827
#include <sys/prctl.h>
1827
1828
#include <sys/syscall.h>
1828
1829
#include <dirent.h>
1829
1830
1830
- static pid_t * get_ready_to_signal_threads_tids (pid_t pid , int sig_num , size_t * tids_len_output );
1831
+ #define TIDS_MAX_SIZE 50
1832
+ static size_t get_ready_to_signal_threads_tids (pid_t pid , int sig_num , pid_t tids [TIDS_MAX_SIZE ]);
1831
1833
1832
1834
#define MAX_BUFF_LENGTH 256
1833
1835
typedef struct {
@@ -1837,60 +1839,70 @@ typedef struct {
1837
1839
void * trace [BACKTRACE_MAX_SIZE ];
1838
1840
} stacktrace_data ;
1839
1841
1840
- __attribute__ ((noinline )) static void * collect_stacktrace_data (void ) {
1842
+ static stacktrace_data * stacktraces_mempool = NULL ;
1843
+ static redisAtomic size_t g_thread_ids = 0 ;
1844
+
1845
+ static stacktrace_data * get_stack_trace_pool (void ) {
1846
+ size_t thread_id ;
1847
+ atomicGetIncr (g_thread_ids , thread_id , 1 );
1848
+ return stacktraces_mempool + thread_id ;
1849
+ }
1850
+
1851
+ __attribute__ ((noinline )) static void collect_stacktrace_data (void ) {
1841
1852
/* allocate stacktrace_data struct */
1842
- stacktrace_data * trace_data = zmalloc ( sizeof ( stacktrace_data ) );
1853
+ stacktrace_data * trace_data = get_stack_trace_pool ( );
1843
1854
1844
1855
/* Get the stack trace first! */
1845
1856
trace_data -> trace_size = backtrace (trace_data -> trace , BACKTRACE_MAX_SIZE );
1846
-
1857
+
1847
1858
/* get the thread name */
1848
1859
prctl (PR_GET_NAME , trace_data -> thread_name );
1849
1860
1850
1861
/* get the thread id */
1851
1862
trace_data -> tid = syscall (SYS_gettid );
1852
-
1853
- /* return the trace data */
1854
- return trace_data ;
1855
1863
}
1856
1864
1857
- __attribute__ ((noinline ))
1865
+ __attribute__ ((noinline ))
1858
1866
static void writeStacktraces (int fd , int uplevel ) {
1859
1867
/* get the list of all the process's threads that don't block or ignore the THREADS_SIGNAL */
1860
1868
pid_t pid = getpid ();
1861
- size_t len_tids = 0 ;
1862
- pid_t * tids = get_ready_to_signal_threads_tids (pid , THREADS_SIGNAL , & len_tids );
1869
+ pid_t tids [TIDS_MAX_SIZE ];
1870
+ size_t len_tids = get_ready_to_signal_threads_tids (pid , THREADS_SIGNAL , tids );
1871
+ if (!len_tids ) {
1872
+ serverLogFromHandler (LL_WARNING , "writeStacktraces(): Failed to get the process's threads." );
1873
+ }
1863
1874
1864
- /* This call returns either NULL or the stacktraces data from all tids */
1865
- stacktrace_data * * stacktraces_data = (stacktrace_data * * )ThreadsManager_runOnThreads (tids , len_tids , collect_stacktrace_data );
1875
+ stacktrace_data stacktraces [len_tids ];
1876
+ stacktraces_mempool = stacktraces ;
1877
+ memset (stacktraces , 0 , sizeof (stacktrace_data ) * len_tids );
1866
1878
1867
- /* free tids */
1868
- zfree ( tids );
1879
+ /* restart mempool iterator */
1880
+ atomicSet ( g_thread_ids , 0 );
1869
1881
1870
- /* ThreadsManager_runOnThreads returns NULL if it is already running */
1871
- if (!stacktraces_data ) return ;
1882
+ /* ThreadsManager_runOnThreads returns 0 if it is already running */
1883
+ if (!ThreadsManager_runOnThreads ( tids , len_tids , collect_stacktrace_data ) ) return ;
1872
1884
1873
1885
size_t skipped = 0 ;
1874
1886
1875
1887
char buff [MAX_BUFF_LENGTH ];
1876
1888
pid_t calling_tid = syscall (SYS_gettid );
1877
1889
/* for backtrace_data in backtraces_data: */
1878
1890
for (size_t i = 0 ; i < len_tids ; i ++ ) {
1879
- stacktrace_data * curr_stacktrace_data = stacktraces_data [i ];
1891
+ stacktrace_data curr_stacktrace_data = stacktraces [i ];
1880
1892
/*ThreadsManager_runOnThreads might fail to collect the thread's data */
1881
- if (! curr_stacktrace_data ) {
1893
+ if (0 == curr_stacktrace_data . trace_size ) {
1882
1894
skipped ++ ;
1883
1895
continue ;
1884
1896
}
1885
1897
1886
1898
/* stacktrace header includes the tid and the thread's name */
1887
- snprintf (buff , MAX_BUFF_LENGTH , "\n%d %s" , curr_stacktrace_data -> tid , curr_stacktrace_data -> thread_name );
1899
+ snprintf (buff , MAX_BUFF_LENGTH , "\n%d %s" , curr_stacktrace_data . tid , curr_stacktrace_data . thread_name );
1888
1900
if (write (fd ,buff ,strlen (buff )) == -1 ) {/* Avoid warning. */ };
1889
1901
1890
1902
/* skip kernel call to the signal handler, the signal handler and the callback addresses */
1891
1903
int curr_uplevel = 3 ;
1892
1904
1893
- if (curr_stacktrace_data -> tid == calling_tid ) {
1905
+ if (curr_stacktrace_data . tid == calling_tid ) {
1894
1906
/* skip signal syscall and ThreadsManager_runOnThreads */
1895
1907
curr_uplevel += uplevel + 2 ;
1896
1908
/* Add an indication to header of the thread that is handling the log file */
@@ -1903,11 +1915,8 @@ static void writeStacktraces(int fd, int uplevel) {
1903
1915
if (write (fd ,buff ,strlen (buff )) == -1 ) {/* Avoid warning. */ };
1904
1916
1905
1917
/* add the stacktrace */
1906
- backtrace_symbols_fd (curr_stacktrace_data -> trace + curr_uplevel , curr_stacktrace_data -> trace_size - curr_uplevel , fd );
1907
-
1908
- zfree (curr_stacktrace_data );
1918
+ backtrace_symbols_fd (curr_stacktrace_data .trace + curr_uplevel , curr_stacktrace_data .trace_size - curr_uplevel , fd );
1909
1919
}
1910
- zfree (stacktraces_data );
1911
1920
1912
1921
snprintf (buff , MAX_BUFF_LENGTH , "\n%zu/%zu expected stacktraces.\n" , len_tids - skipped , len_tids );
1913
1922
if (write (fd ,buff ,strlen (buff )) == -1 ) {/* Avoid warning. */ };
@@ -2486,9 +2495,8 @@ void debugDelay(int usec) {
2486
2495
#ifdef __linux__
2487
2496
2488
2497
/* =========================== Stacktrace Utils ============================ */
2489
- #define TIDS_INITIAL_SIZE 50
2490
2498
2491
- /** If it doesn't block and doesn't ignore, return 1 (the thread will handle the signal)
2499
+ /** If it doesn't block and doesn't ignore, return 1 (the thread will handle the signal)
2492
2500
* If thread tid blocks or ignores sig_num returns 0 (thread is not ready to catch the signal).
2493
2501
* also returns 0 if something is wrong and prints a warning message to the log file **/
2494
2502
static int is_thread_ready_to_signal (pid_t pid , pid_t tid , int sig_num ) {
@@ -2527,23 +2535,21 @@ static int is_thread_ready_to_signal(pid_t pid, pid_t tid, int sig_num) {
2527
2535
serverLog (LL_WARNING ,
2528
2536
"tid:%d: failed to find SigBlk or/and SigIgn field(s) in /proc/%d/task/%d/status file" , tid , pid , tid );
2529
2537
}
2530
- return ret ;
2538
+ return ret ;
2531
2539
}
2532
2540
2533
- /** Returns a list of all the process's (pid) threads that can receive signal sig_num.
2534
- * Also updates tids_len_output to the number of valid threads' ids in the returned array
2535
- * NOTE: It is the caller responsibility to free the returned array with zfree(). */
2536
- static pid_t * get_ready_to_signal_threads_tids (pid_t pid , int sig_num , size_t * tids_len_output ) {
2541
+ /** Returns the number of the process's threads that can receive signal sig_num.
2542
+ * Writes into tids the tids of these threads.
2543
+ * If it fails, returns 0.
2544
+ */
2545
+ static size_t get_ready_to_signal_threads_tids (pid_t pid , int sig_num , pid_t tids [TIDS_MAX_SIZE ]) {
2537
2546
/* Initialize the path the process threads' directory. */
2538
2547
char path_buff [MAX_BUFF_LENGTH ];
2539
2548
snprintf (path_buff , MAX_BUFF_LENGTH , "/proc/%d/task" , pid );
2540
2549
2541
2550
/* Get the directory handler. */
2542
2551
DIR * dir ;
2543
- if (!(dir = opendir (path_buff ))) return NULL ;
2544
-
2545
- size_t tids_cap = TIDS_INITIAL_SIZE ;
2546
- pid_t * tids = zmalloc (sizeof (pid_t ) * tids_cap );
2552
+ if (!(dir = opendir (path_buff ))) return 0 ;
2547
2553
2548
2554
size_t tids_count = 0 ;
2549
2555
struct dirent * entry ;
@@ -2555,7 +2561,7 @@ static pid_t *get_ready_to_signal_threads_tids(pid_t pid, int sig_num, size_t *t
2555
2561
if (entry -> d_type == DT_DIR ) {
2556
2562
/* Skip irrelevant directories. */
2557
2563
if (strcmp (entry -> d_name , "." ) != 0 && strcmp (entry -> d_name , ".." ) != 0 ) {
2558
- /* the thread's directory name is equivalent to its tid. */
2564
+ /* the thread's directory name is equivalent to its tid. */
2559
2565
pid_t tid = atoi (entry -> d_name );
2560
2566
2561
2567
if (!is_thread_ready_to_signal (pid , tid , sig_num )) continue ;
@@ -2564,31 +2570,28 @@ static pid_t *get_ready_to_signal_threads_tids(pid_t pid, int sig_num, size_t *t
2564
2570
current_thread_index = tids_count ;
2565
2571
}
2566
2572
2567
- /* increase tids capacity if needed */
2568
- if (tids_count >= tids_cap ) {
2569
- tids_cap *= 2 ;
2570
- tids = zrealloc (tids , sizeof (pid_t ) * tids_cap );
2571
- }
2572
-
2573
2573
/* save the thread id */
2574
2574
tids [tids_count ++ ] = tid ;
2575
2575
}
2576
2576
}
2577
+ /* Stop if we reached the maximum threads number. */
2578
+ if (tids_count == TIDS_MAX_SIZE ) {
2579
+ serverLogFromHandler (LL_WARNING ,"get_ready_to_signal_threads_tids(): Reached the limit of the tids buffer." );
2580
+ break ;
2581
+ }
2577
2582
}
2578
2583
2579
2584
/* Swap the last tid with the the current thread id */
2580
2585
if (current_thread_index != -1 ) {
2581
2586
pid_t last_tid = tids [tids_count - 1 ];
2582
-
2587
+
2583
2588
tids [tids_count - 1 ] = calling_tid ;
2584
2589
tids [current_thread_index ] = last_tid ;
2585
2590
}
2586
2591
2587
-
2588
2592
closedir (dir );
2589
2593
2590
- * tids_len_output = tids_count ;
2591
- return tids ;
2594
+ return tids_count ;
2592
2595
}
2593
2596
#endif /* __linux__ */
2594
2597
#endif /* HAVE_BACKTRACE */
0 commit comments