@@ -229,20 +229,18 @@ void
229229free_logs (Logs * logs ) {
230230 GLog * glog = NULL ;
231231 int i ;
232-
233232 for (i = 0 ; i < logs -> size ; ++ i ) {
234233 glog = & logs -> glog [i ];
235-
236234 free (glog -> props .filename );
237235 free (glog -> props .fname );
238236 free (glog -> fname_as_vhost );
239237 free_logerrors (glog );
240238 free (glog -> errors );
239+ pthread_mutex_destroy (& glog -> error_mutex ); // Destroy mutex
241240 if (glog -> pipe ) {
242241 fclose (glog -> pipe );
243242 }
244243 }
245-
246244 free (logs -> glog );
247245 free (logs );
248246}
@@ -2006,8 +2004,16 @@ validate_and_parse_line (char *line, GLogItem *logitem) {
20062004/* Collect error messages without incrementing counters (for dry run/testing) */
20072005static void
20082006collect_invalid_errors (GLog * glog , GLogItem * logitem ) {
2009- if (logitem -> errstr && glog -> log_erridx < MAX_LOG_ERRORS ) {
2010- glog -> errors [glog -> log_erridx ++ ] = xstrdup (logitem -> errstr );
2007+ if (logitem -> errstr ) {
2008+ pthread_mutex_lock (& glog -> error_mutex );
2009+
2010+ uint8_t idx = atomic_load (& glog -> log_erridx );
2011+ if (idx < MAX_LOG_ERRORS ) {
2012+ glog -> errors [idx ] = xstrdup (logitem -> errstr );
2013+ atomic_store (& glog -> log_erridx , idx + 1 );
2014+ }
2015+
2016+ pthread_mutex_unlock (& glog -> error_mutex );
20112017 }
20122018}
20132019
@@ -2140,26 +2146,20 @@ read_line (GLog *glog, char *line, int *test, uint32_t *cnt, int dry_run) {
21402146 GLogItem * logitem = NULL ;
21412147 int ret = 0 ;
21422148
2143- /* Begin processing the log line - in case of an invalid log format, flip
2144- * the test only if there's at least one valid record discovered during the log
2145- * format test. This condition applies solely when reading a log from the
2146- * beginning, not when tailing an ongoing log. */
21472149 if ((ret = parse_line (glog , line , dry_run , & logitem )) == 0 )
21482150 * test = 0 ;
21492151
2150- /* soft ignore these lines from parse_line */
21512152 if (ret == -1 )
21522153 return NULL ;
21532154
2154- /* reached num of lines to test and no valid records were found, log
2155- * format is likely not matching */
2155+ /* Increment local counter (will be synchronized later) */
21562156 if (conf .num_tests && ++ (* cnt ) >= conf .num_tests && * test ) {
21572157 uncount_processed (glog );
21582158 uncount_invalid (glog );
21592159 return NULL ;
21602160 }
2161- glog -> read ++ ;
21622161
2162+ atomic_fetch_add (& glog -> read , 1 ); // Only 2 arguments!
21632163 return logitem ;
21642164}
21652165
@@ -2168,19 +2168,29 @@ static void *
21682168read_lines_thread (void * arg ) {
21692169 GJob * job = (GJob * ) arg ;
21702170 int i = 0 ;
2171+ uint32_t local_cnt = atomic_load (& job -> cnt );
21712172
21722173 for (i = 0 ; i < job -> p ; i ++ ) {
2173- /* ensure we don't process more than we should when testing for log format,
2174- * else free chunk and stop processing threads */
2175- if (!job -> test || (job -> test && job -> cnt < conf .num_tests ))
2176- job -> logitems [i ] = read_line (job -> glog , job -> lines [i ], & job -> test , & job -> cnt , job -> dry_run );
2177- else
2178- conf .stop_processing = 1 ;
2174+ /* Check stop_processing atomically */
2175+ if (atomic_load (& conf .stop_processing ))
2176+ break ;
2177+
2178+ /* ensure we don't process more than we should when testing for log format */
2179+ if (!job -> test || (job -> test && local_cnt < conf .num_tests )) {
2180+ job -> logitems [i ] = read_line (job -> glog , job -> lines [i ], & job -> test , & local_cnt , job -> dry_run );
2181+ } else {
2182+ atomic_store (& conf .stop_processing , 1 );
2183+ break ;
2184+ }
21792185
21802186#ifdef WITH_GETLINE
21812187 free (job -> lines [i ]);
21822188#endif
21832189 }
2190+
2191+ /* Update shared counter atomically */
2192+ atomic_store (& job -> cnt , local_cnt );
2193+
21842194 return (void * ) 0 ;
21852195}
21862196
@@ -2257,10 +2267,17 @@ init_jobs (GJob jobs[2][conf.jobs], GLog *glog, int dry_run, int test) {
22572267 int i = 0 ;
22582268#endif
22592269
2270+ /* Initialize error mutex once */
2271+ static int mutex_initialized = 0 ;
2272+ if (!mutex_initialized ) {
2273+ pthread_mutex_init (& glog -> error_mutex , NULL );
2274+ mutex_initialized = 1 ;
2275+ }
2276+
22602277 for (b = 0 ; b < 2 ; b ++ ) {
22612278 for (k = 0 ; k < conf .jobs ; k ++ ) {
22622279 jobs [b ][k ].p = 0 ;
2263- jobs [b ][k ].cnt = 0 ;
2280+ atomic_store ( & jobs [b ][k ].cnt , 0 ); // Use atomic store
22642281 jobs [b ][k ].glog = glog ;
22652282 jobs [b ][k ].test = test ;
22662283 jobs [b ][k ].dry_run = dry_run ;
@@ -2299,11 +2316,13 @@ read_lines_from_file (FILE *fp, GLog *glog, GJob jobs[2][conf.jobs], int b, char
22992316static void
23002317process_lines (GJob jobs [2 ][conf .jobs ], uint32_t * cnt , int * test , int b ) {
23012318 int k = 0 ;
2302-
23032319 for (k = 0 ; k < conf .jobs ; k ++ ) {
23042320 process_lines_thread (& jobs [b ][k ]);
2305- * cnt += jobs [b ][k ].cnt ;
2306- jobs [b ][k ].cnt = 0 ;
2321+
2322+ /* Read atomic counter */
2323+ * cnt += atomic_load (& jobs [b ][k ].cnt );
2324+ atomic_store (& jobs [b ][k ].cnt , 0 );
2325+
23072326 * test &= jobs [b ][k ].test ;
23082327 jobs [b ][k ].p = 0 ;
23092328 }
@@ -2488,7 +2507,7 @@ read_log (GLog *glog, int dry_run) {
24882507 struct stat fdstat ;
24892508
24902509 /* Reset stop_processing flag for new parse attempt */
2491- conf .stop_processing = 0 ;
2510+ atomic_store ( & conf .stop_processing , 0 ) ;
24922511
24932512 /* Ensure we have a valid pipe to read from stdin. Only checking for
24942513 * conf.read_stdin without verifying for a valid FILE pointer would certainly
0 commit comments