@@ -62,6 +62,7 @@ our @EXPORT_OK = qw($tool_name $tool_dir $lcov_version $lcov_url $VERSION
6262 @exclude_file_patterns @include_file_patterns %excluded_files
6363 @omit_line_patterns @exclude_function_patterns $case_insensitive
6464 munge_file_patterns warn_file_patterns transform_pattern
65+ warn_pattern_list
6566 parse_cov_filters summarize_cov_filters
6667 disable_cov_filters reenable_cov_filters is_filter_enabled
6768 filterStringsAndComments simplifyCode balancedParens
@@ -219,6 +220,15 @@ our $opt_no_external;
219220our @build_directory ;
220221
221222our @configured_callbacks ;
223+ # list of callbacks which support save/restore
224+ our @callback_save_restore ;
225+ # list of callbacks which support 'finalize'
226+ our @callback_finalize ;
227+ # list of callbacks which implement 'start' - which gets called when
228+ # child process starts
229+ our @callback_start_list ;
230+ # the callback data which is saved from child process/restored from child process
231+ our @callback_state ;
222232
223233# optional callback to keep track of whatever user decides is important
224234our @contextCallback ;
@@ -988,6 +998,26 @@ sub configure_callback
988998 # $package->import(qw(new));
989999 # the first value in @_ is the script name
9901000 $$cb = $class -> new(@args );
1001+ if (exists ($ENV {LCOV_FORCE_PARALLEL }) ||
1002+ (defined ($lcovutil::maxParallelism ) &&
1003+ 1 != $lcovutil::maxParallelism )
1004+ ) {
1005+ # don't set up for parallel processing if we aren't going to fork
1006+ if ($$cb -> can(' save' )) {
1007+ if ($$cb -> can(' restore' )) {
1008+ push (@callback_save_restore , [$class , $$cb ]);
1009+ push (@callback_start_list , [$class , $$cb ])
1010+ if ($$cb -> can(' start' ));
1011+ } else {
1012+ lcovutil::ignorable_error($lcovutil::ERROR_PACKAGE ,
1013+ " $class implements 'save' but not 'restore'." );
1014+ return ;
1015+ }
1016+ }
1017+ }
1018+ # implement 'finalize', regardless of parallel/not parallel
1019+ push (@callback_finalize , [$class , $$cb ])
1020+ if ($$cb -> can(' finalize' ));
9911021 };
9921022 if ($@ ||
9931023 !defined ($$cb )) {
@@ -1745,23 +1775,40 @@ sub munge_file_patterns
17451775 @suppress_function_patterns = map ({ $_ -> [0] } @exclude_function_patterns );
17461776}
17471777
1778+ sub warn_pattern_list
1779+ {
1780+ my ($type , $patterns ) = @_ ;
1781+ foreach my $pat (@$patterns ) {
1782+ my $count = $pat -> [-1];
1783+ if (0 == $count ) {
1784+ my $str = $pat -> [-2];
1785+ lcovutil::ignorable_error($ERROR_UNUSED ,
1786+ " '$type ' pattern '$str ' is unused." );
1787+ }
1788+ }
1789+ }
1790+
17481791sub warn_file_patterns
17491792{
1793+ # a bit of a hack...we need a place to call the 'finalize' methods
1794+ # (if any are registered) - and this method is called very late in
1795+ # the game, by lcov/genhtml/geninfo - so is a workable location
1796+ for (my $i = 0; $i <= $#lcovutil::callback_finalize ; ++$i ) {
1797+ my ($class , $cb ) = @{$lcovutil::callback_finalize [$i ]};
1798+ eval { $cb -> finalize(); };
1799+ if ($@ ) {
1800+ lcovutil::ignorable_error($lcovutil::ERROR_CALLBACK ,
1801+ " \" $class ->finalize()\" failed: $@ " );
1802+ }
1803+ }
1804+
17501805 foreach my $p ([' include' , \@include_file_patterns ],
17511806 [' exclude' , \@exclude_file_patterns ],
17521807 [' substitute' , \@file_subst_patterns ],
17531808 [' omit-lines' , \@omit_line_patterns ],
17541809 [' exclude-functions' , \@exclude_function_patterns ],
17551810 ) {
1756- my ($type , $patterns ) = @$p ;
1757- foreach my $pat (@$patterns ) {
1758- my $count = $pat -> [scalar (@$pat ) - 1];
1759- if (0 == $count ) {
1760- my $str = $pat -> [scalar (@$pat ) - 2];
1761- lcovutil::ignorable_error($ERROR_UNUSED ,
1762- " '$type ' pattern '$str ' is unused." );
1763- }
1764- }
1811+ warn_pattern_list(@$p );
17651812 }
17661813}
17671814
@@ -2081,14 +2128,24 @@ sub initial_state
20812128 }
20822129 }
20832130
2131+ for (my $i = 0; $i <= $#lcovutil::callback_start_list ; ++$i ) {
2132+ my ($class , $cb ) = @{$lcovutil::callback_start_list [$i ]};
2133+ eval { $cb -> start(); };
2134+ if ($@ ) {
2135+ lcovutil::ignorable_error($lcovutil::ERROR_CALLBACK ,
2136+ " \" $class ->start()\" failed: $@ " );
2137+ }
2138+ }
2139+
20842140 return Storable::dclone([\@message_count , \%versionCache , \%resolveCache ]);
20852141}
20862142
20872143sub compute_update
20882144{
20892145 my $state = shift ;
2090- my @new_count ;
20912146 my ($initialCount , $initialVersionCache , $initialResolveCache ) = @$state ;
2147+
2148+ my @new_count ;
20922149 my $id = 0;
20932150 foreach my $count (@message_count ) {
20942151 my $v = $count - $initialCount -> [$id ++];
@@ -2104,7 +2161,20 @@ sub compute_update
21042161 $resolveUpdate {$f } = $v
21052162 unless exists ($initialResolveCache -> {$f });
21062163 }
2107- my @rtn = (\@new_count ,
2164+ my @cbData ;
2165+ for (my $i = 0; $i <= $#lcovutil::callback_save_restore ; ++$i ) {
2166+ my ($class , $cb ) = @{$lcovutil::callback_save_restore [$i ]};
2167+ eval {
2168+ my $data = $cb -> save();
2169+ push (@cbData , $data );
2170+ };
2171+ if ($@ ) {
2172+ lcovutil::ignorable_error($lcovutil::ERROR_CALLBACK ,
2173+ " \" $class ->save(...)\" failed: $@ " );
2174+ }
2175+ }
2176+ my @rtn = (\@cbData ,
2177+ \@new_count ,
21082178 \%versionUpdate ,
21092179 \%resolveUpdate ,
21102180 \%message_types ,
@@ -2131,6 +2201,15 @@ sub compute_update
21312201
21322202sub update_state
21332203{
2204+ my $callbackData = shift ;
2205+ for (my $i = 0; $i <= $# $callbackData ; ++$i ) {
2206+ my ($class , $cb ) = @{$lcovutil::callback_save_restore [$i ]};
2207+ eval { $cb -> restore($callbackData -> [$i ]); };
2208+ if ($@ ) {
2209+ lcovutil::ignorable_error($lcovutil::ERROR_CALLBACK ,
2210+ " \" $class ->restore(...)\" failed: $@ " );
2211+ }
2212+ }
21342213 my $updateCount = shift ;
21352214 my $id = 0;
21362215 foreach my $count (@$updateCount ) {
0 commit comments