File Coverage

blib/lib/Devel/Monitor.pm
Criterion Covered Total %
statement 222 270 82.2
branch 72 112 64.2
condition 8 18 44.4
subroutine 32 45 71.1
pod 0 3 0.0
total 334 448 74.5


line stmt bran cond sub pod time code
1             package Devel::Monitor;
2              
3 1     1   24521 use 5.008006;
  1         4  
  1         38  
4 1     1   6 use strict;
  1         2  
  1         27  
5 1     1   6 use warnings;
  1         6  
  1         48  
6              
7             require Exporter;
8 1     1   902 use AutoLoader qw(AUTOLOAD);
  1         1868  
  1         6  
9              
10             our @ISA = qw(Exporter);
11              
12             # Items to export into callers namespace by default. Note: do not export
13             # names by default without a very good reason. Use EXPORT_OK instead.
14             # Do not simply export all your public functions/methods/constants.
15              
16             # This allows declaration use Devel::Monitor ':all';
17             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
18             # will save memory.
19              
20             our @EXPORT = qw(); #Export by default
21              
22             our %EXPORT_TAGS = ( #Export as groups
23             'all' => [
24             qw(monitor
25             print_circular_ref
26             )
27             ]
28             );
29              
30             Exporter::export_ok_tags( #Export by request (into @EXPORT_OK)
31             'all');
32              
33             our $VERSION = '0.9.0.7';
34              
35 1     1   982 use Error qw(:try);
  1         6758  
  1         6  
36 1     1   216 use Scalar::Util qw(isweak);
  1         2  
  1         147  
37 1     1   650 use Devel::Monitor::Common qw(:all);
  1         3  
  1         134  
38 1     1   715 use Devel::Monitor::Trace;
  1         2  
  1         25  
39 1     1   614 use Devel::Monitor::TraceItem;
  1         2  
  1         25  
40 1     1   561 use Devel::Monitor::Array;
  1         2  
  1         34  
41 1     1   660 use Devel::Monitor::Hash;
  1         2  
  1         26  
42 1     1   615 use Devel::Monitor::Scalar;
  1         3  
  1         28  
43            
44             #Circular references type
45 1     1   5 use constant CRT_NONE => undef;
  1         3  
  1         57  
46 1     1   6 use constant CRT_CIRC_REF => 1;
  1         1  
  1         92  
47 1     1   5 use constant CRT_INTERNAL_CIRC_REF => 2;
  1         2  
  1         37  
48 1     1   4 use constant CRT_WEAK_CIRC_REF => 3;
  1         2  
  1         4839  
49              
50             # METH monitor
51             #
52             # DESC Monitoring multiple variables
53             # monitor('name for a' => \$a,
54             # 'name for b' => \$b,
55             # 'name for c' => \$c,
56             # 'name for d' => \@d,
57             # 'name for e' => \%e,
58             # 'name for F' => \&F);
59             # DESC Monitoring single constant variable (FOR INTERNAL USE ONLY)
60             # monitor('name for F' => \&F, 1);
61             # The last flag indicates that it is code reference
62              
63             sub monitor {
64 9     9 0 27 my $isCode;
65 9 100       28 $isCode = pop if scalar(@_) % 2 != 0;
66 9         24 my %values = @_;
67 9         19 foreach my $key (keys %values) {
68 9         13 my $varRef = $values{$key};
69 9 50       18 if ($varRef) { #If the value is undef
70 9         18 _dereference(\$varRef);
71 9 100       65 if ($varRef =~ /HASH/ ) { #An hash object or an hash
    100          
    100          
    50          
72 2         7 _tieHash($varRef,$key,$isCode);
73             }
74             elsif ($varRef =~ /SCALAR|REF/) {
75 4         10 _tieScalar($varRef,$key,$isCode);
76             }
77             elsif ($varRef =~ /ARRAY/) {
78 2         6 _tieArray($varRef,$key,$isCode);
79             }
80             elsif ($varRef =~ /CODE/) {
81             ###########################################################
82             # Info on constants
83             ###########################################################
84             # use constant CONST => [1,2];
85             # print \&CONST."\n";
86             # print &CONST."\n";
87             # print \&CONST()."\n";
88             # print &CONST()."\n";
89             #
90             # CODE(0x8203000)
91             # ARRAY(0x81d4c04)
92             # REF(0x820303c)
93             # ARRAY(0x81d4c04)
94             #
95             # Code Ref
96             # | |
97             # Array Array
98             # | |
99             # +---+ +---+
100             # |1,2| |1,2|
101             # +---+ +---+
102             #
103             ###########################################################
104             # use constant CONST => 'a scalar';
105             # print \&CONST."\n";
106             # print &CONST."\n";
107             # print \&CONST()."\n";
108             # print &CONST()."\n";
109             #
110             # CODE(0x820300c)
111             # a scalar
112             # SCALAR(0x81fb2c4)
113             # a scalar
114             #
115             # Code Scalar
116             # | |
117             # 'a scalar' 'a scalar'
118             #
119             # Instead of :
120             #
121             # Code Ref
122             # | |
123             # Scalar Scalar
124             # | |
125             # 'a scalar' 'a scalar'
126             #
127             ###########################################################
128 1 50       10 if (ref(&$varRef) =~ /ARRAY|HASH/) {
129 1         370 _monitorRecursively($key => &$varRef);
130             } else {
131             #_tieScalar($varRef);
132 0         0 Devel::Monitor::Common::printMsg("Scalar constant $key cannot be monitored\n");
133             }
134             }
135             else {
136 0         0 my $runPatch = 0;
137             try {
138 0     0   0 _tieHash($varRef,$key);
139             } otherwise {
140             ###########################################################
141             # Patch for Error.pm
142             # It seems there is a bug in this module
143             ###########################################################
144             # Example :
145             ###########################################################
146             # #!/usr/bin/perl
147             # use strict;
148             # use warnings;
149             # use Devel::Monitor;
150             # {
151             # my @a = (1,2,3,4);
152             # monitor('a'=>\@a);
153             # print STDERR "Leaving scope\n";
154             # }
155             # print STDERR "Scope left\n";
156             ###########################################################
157             # Output without the patch (Very bad for mod_perl)
158             ###########################################################
159             # MONITOR ARRAY : a
160             # Leaving scope
161             # Scope left
162             # DESTROY ARRAY : a
163             ###########################################################
164             # Output with the patch (Ok)
165             ###########################################################
166             # MONITOR ARRAY : a
167             # Leaving scope
168             # DESTROY ARRAY : a
169             # Scope left
170             ###########################################################
171 0     0   0 $runPatch = 1;
172             #try {
173             # _tieArray($varRef,$key);
174             #} otherwise {
175             # Devel::Monitor::Common::printMsg("$varRef($key) cannot be monitored\n");
176             #};
177 0         0 };
178 0 0       0 if ($runPatch) {
179             try {
180 0     0   0 _tieArray($varRef,$key);
181             } otherwise {
182 0     0   0 Devel::Monitor::Common::printMsg("$varRef($key) cannot be monitored\n");
183 0         0 };
184             }
185             }
186             }
187             }
188             }
189            
190             sub _monitorRecursively {
191 4     4   11 my %values = @_;
192 4         12 foreach my $key (keys %values) {
193 4         5 my $varRef = $values{$key};
194 4 50       11 if ($varRef) { #If the value is undef
195 4         9 _dereference(\$varRef);
196 4 50       27 if ($varRef =~ /HASH/ ) { #An hash object or an hash
    100          
    50          
    0          
197             HASH_ITEM:
198 0         0 foreach my $item (keys %$varRef) {
199             #print STDERR "ITEM : ".$varRef->{$item}."\n";
200 0         0 _monitorRecursively("$key {$item}" => \($varRef->{$item}));
201             }
202             }
203             elsif ($varRef =~ /SCALAR/) {
204             # nothing
205             }
206             elsif ($varRef =~ /ARRAY/) {
207 1         2 ARRAY_ITEM:
208             my $i = 0;
209 1         2 foreach my $item (@$varRef) {
210             #print STDERR "ITEM : ".$item."\n";
211 3         23 _monitorRecursively("$key [$i]" => \$item);
212 3         53 $i++;
213             }
214             }
215             elsif ($varRef =~ /CODE/) {
216             # nothing
217             }
218             else {
219 0         0 my $runPatch = 0;
220             try {
221 0     0   0 goto HASH_ITEM;
222             } otherwise {
223 0     0   0 $runPatch = 1;
224 0         0 };
225 0 0       0 if ($runPatch) {
226             try {
227 0     0   0 goto ARRAY_ITEM;
228 0     0   0 } otherwise {
229             #Devel::Monitor::Common::printMsg("$varRef($key) cannot be monitored recursively\n");
230             #we call monitor, this one will print the error
231 0         0 };
232             }
233             }
234             # Finally, monitor current variable
235 4         29 monitor($key => $varRef, 1);
236             }
237             }
238             }
239            
240             sub _tieHash {
241 2     2   2 my $varRef = shift;
242 2         3 my $name = shift;
243 2         11 my $isCode = shift;
244            
245 2 50       5 if (not tied %$varRef) {
246 2         16 tie %$varRef, 'Devel::Monitor::Hash', $varRef, $name, $isCode;
247             } else {
248 0         0 my $self = tied %$varRef;
249             #if tied by our Devel::Monitor
250 0 0       0 if (ref($self) =~ /Devel::Monitor/) {
251 0         0 Devel::Monitor::Common::printMsg("Hash from $name is already tied by ".$self->{Devel::Monitor::Common::F_ID()}."\n");
252             } else {
253 0         0 Devel::Monitor::Common::printMsg("Array from $name is already tied by the ".ref($self)." package\n");
254             }
255             }
256             }
257            
258             sub _tieArray {
259 2     2   4 my $varRef = shift;
260 2         3 my $name = shift;
261 2         4 my $isCode = shift;
262            
263 2 50       4 if (not tied @$varRef) {
264 2         14 tie @$varRef, 'Devel::Monitor::Array', $varRef, $name, $isCode;
265             } else {
266 0         0 my $self = tied @$varRef;
267             #if tied by our Devel::Monitor
268 0 0       0 if (ref($self) =~ /Devel::Monitor/) {
269 0         0 Devel::Monitor::Common::printMsg("Array from $name is already tied by ".$self->{Devel::Monitor::Common::F_ID()}."\n");
270             } else {
271 0         0 Devel::Monitor::Common::printMsg("Array from $name is already tied by the ".ref($self)." package\n");
272             }
273             }
274             }
275            
276             sub _tieScalar {
277 4     4   8 my $varRef = shift;
278 4         6 my $name = shift;
279 4         5 my $isCode = shift;
280            
281 4 50       9 if (not tied $$varRef) {
282             try {
283 4     4   98 tie $$varRef, 'Devel::Monitor::Scalar', $varRef, $name, $isCode;
284             } otherwise {
285 0     0   0 Devel::Monitor::Common::printMsg("Scalar from $name is read-only, monitor skipped\n");
286 4         51 };
287             } else {
288 0         0 my $self = tied $$varRef;
289             #if tied by our Devel::Monitor
290 0 0       0 if (ref($self) =~ /Devel::Monitor/) {
291 0         0 Devel::Monitor::Common::printMsg("Scalar from $name is already tied by ".$self->{Devel::Monitor::Common::F_ID()}."\n");
292             } else {
293 0         0 Devel::Monitor::Common::printMsg("Array from $name is already tied by the ".ref($self)." package\n");
294             }
295             }
296             }
297            
298             #Not used
299             # sub unmonitor {
300             # my @varsRef = @_;
301             # foreach my $varRef (@varsRef) {
302             # if ($varRef) {
303             # _dereference(\$varRef);
304             # if ($varRef =~ /HASH/ ) { #An object or an hash
305             # Devel::Monitor::Hash::unmonitor($varRef);
306             # }
307             # elsif ($varRef =~ /SCALAR/) {
308             # Devel::Monitor::Scalar::unmonitor($varRef);
309             # }
310             # elsif ($varRef =~ /ARRAY/) {
311             # Devel::Monitor::Array::unmonitor($varRef);
312             # }
313             # elsif ($varRef =~ /CODE/) {
314             # unmonitor(&$varRef); #TODO : Unmonitor recursively, do not touch scalars
315             # }
316             # else {
317             # my $runPatch = 0;
318             # try {
319             # Devel::Monitor::Hash::unmonitor($varRef);
320             # } otherwise {
321             # $runPatch = 1;
322             # };
323             # if ($runPatch) {
324             # try {
325             # Devel::Monitor::Array::unmonitor($varRef);
326             # } otherwise {
327             # Devel::Monitor::Common::printMsg("$varRef cannot be unmonitored\n");
328             # };
329             # }
330             # }
331             # }
332             # }
333             # }
334            
335             sub _dereference {
336 13     13   15 my $varRefRef = shift;
337 13         22 my $type = ref($$varRefRef);
338             #print STDERR "VARIABLE : $$varRefRef\n";
339             #print STDERR "TYPE : $type\n";
340             ##############################################################
341             # You need to dereference, otherwise, you may
342             # get this error : Modification of a read-only value attempted
343             # is you monitor a variable that use a constant by example
344             ##############################################################
345 13         42 while ($type =~ /REF/) {
346 1         3 $$varRefRef = $$$varRefRef;
347 1         4 $type = ref($$varRefRef);
348             #print STDERR "V : $$varRefRef\n";
349             #print STDERR "T : $type\n";
350             }
351             }
352            
353             # METH printCircularRef
354             #
355             # DESC Try to find circular references and print it out into STDERR
356              
357             #Little redirect to be "Perl compliant"
358             #TODO : use the underscore syntax
359 13     13 0 33 sub print_circular_ref { return printCircularRef(@_); }
360              
361             sub printCircularRef {
362 158     158 0 170 my $varRef = shift;
363 158         178 my $hideWeakenedCircRef = shift; #Boolean
364 158         167 my $source = shift;
365 158         152 my $trace = shift; #A array container containing the current trace
366 158         143 my $weakenedRef = shift; #A array containing the trace to the weakened ref it any
367 158         134 my $origRef = shift; #Contains original reference to verify circular references
368 158         151 my $seenRef = shift;
369 158         145 my $circRefTypesRef = shift;
370            
371             #print STDERR "###############################################################\n";
372             #print STDERR "VARIABLE : ".$varRef."\n";
373             #print STDERR "TYPE : ".ref($varRef)."\n";
374 158         196 my $isFirst = (!$origRef);
375 158 100       341 $trace = Devel::Monitor::Trace->new() if not $trace;
376 158 100       357 $weakenedRef = [] if not $weakenedRef;
377 158 100       252 $seenRef = {} if not $seenRef;
378 158 100       262 $circRefTypesRef = [] if not $circRefTypesRef;
379              
380 158 50       252 return undef if not $varRef;
381            
382 158         165 my $isWeak = 0;
383 158         192 my $simpleSeenRef = {};
384             #Since we dereference scalars, they are not displayed on the final prints
385 158         497 while ($varRef =~ /REF/) {
386             #print STDERR "DEREFERING $varRef ($$varRef)\n";
387             #print STDERR "Current variable : $varRef from ".\$varRef."\n";
388 70 50       208 if (isweak($$varRef)) {
389 0         0 $isWeak = 1;
390             #print STDERR "WEAK for $$varRef\n";
391 0         0 push(@$weakenedRef, $$varRef);
392             }
393 70         105 _addSeenRef($varRef,$simpleSeenRef);
394             #Exceptional case : $a = \$a or $a = \$b = \$c
395             #TODO : This "if" should not be handled as an exception (At least, we should try)
396 70 100 66     345 if (exists($simpleSeenRef->{$varRef}) && ($simpleSeenRef->{$varRef} > 1)) {
397 3 100       7 if ($isFirst) {
398 2         13 _printCircularRefHeader($varRef);
399 2         6 push(@$circRefTypesRef, CRT_CIRC_REF());
400 2         5 Devel::Monitor::Common::printMsg("-------------------------------------------------------------------------------\n");
401 2         9 Devel::Monitor::Common::printMsg("Circular reference on scalar(s) starting at $varRef\n");
402 2         6 Devel::Monitor::Common::printMsg("-------------------------------------------------------------------------------\n");
403 2         4 _printCircularRefResults($varRef,$circRefTypesRef);
404             } else {
405 1         3 push(@$circRefTypesRef, CRT_INTERNAL_CIRC_REF());
406 1         4 Devel::Monitor::Common::printMsg("-------------------------------------------------------------------------------\n");
407 1         5 Devel::Monitor::Common::printMsg('Internal circular reference on scalar(s) starting at : '.$trace->getCircularPath()."\n");
408 1         6 $trace->dump();
409 1         4 Devel::Monitor::Common::printMsg("-------------------------------------------------------------------------------\n");
410             }
411 3         21 return undef;
412             }
413            
414 67         208 $varRef = $$varRef;
415             }
416 155         417 $trace->push($varRef,$source);
417 155 100       385 _addSeenRef($varRef,$seenRef) if $origRef; #We skip the first item which is $origRef
418             #print STDERR "--------------------------------------------\n";
419             #print STDERR "Current variable : $varRef from ".\$varRef."\n";
420 155         266 my $circRefType = _checkCircularRef($varRef,$hideWeakenedCircRef,$trace,$weakenedRef,$origRef,$seenRef);
421             #print STDERR "\$circRefType : $circRefType\n";
422 155 100       272 if ($circRefType) {
423 19         54 $trace->pop();
424 19         60 push(@$circRefTypesRef, $circRefType);
425 19         92 return undef; #Don't go any further because we loop
426             }
427 136 100       211 if ($isFirst) {
428 11         11 $origRef = $varRef;
429 11         21 _printCircularRefHeader($origRef);
430             }
431            
432             #print STDERR 'Current trace : '.$trace->getCircularPath()."\n";
433 136         251 _printCircularRef($varRef,$hideWeakenedCircRef,$source,$trace,$weakenedRef,$origRef,$seenRef,$circRefTypesRef);
434            
435             #We go into another branch
436 136         379 $trace->pop();
437 136 50       371 pop(@$weakenedRef) if $isWeak; # Remove weakened item
438 136         261 delete($seenRef->{$varRef}); # Remove varRef from "seen" hash
439            
440 136 100       365 _printCircularRefResults($origRef,$circRefTypesRef) if $isFirst;
441            
442 136         511 return undef;
443             }
444            
445             sub _printCircularRef {
446 136     136   149 my $varRef = shift;
447 136         142 my $hideWeakenedCircRef = shift;
448 136         135 my $source = shift;
449 136         142 my $trace = shift;
450 136         130 my $weakenedRef = shift;
451 136         138 my $origRef = shift;
452 136         150 my $seenRef = shift;
453 136         127 my $circRefTypesRef = shift;
454            
455 136 100       901 if ($varRef =~ /HASH/ ) { #An object or an hash
    100          
    50          
456 14 50       29 HASH_ITEM:
457             Devel::Monitor::Common::printMsg('Object '.$trace->getCircularPath().' = '.$varRef." is tied. Untie it to check circular references for this object.\n") if tied(%$varRef);
458 14         80 foreach my $item (keys %$varRef) {
459 23         48 my $ref = _getVarRef(\($varRef->{$item}));
460 23         77 printCircularRef($ref,$hideWeakenedCircRef,'{'.$item.'}',$trace,$weakenedRef,$origRef,$seenRef,$circRefTypesRef);
461             }
462             }
463             elsif ($varRef =~ /SCALAR|CODE/) {
464             #No circular references are possible here, so we don't do anything
465             }
466             elsif ($varRef =~ /ARRAY/) {
467 11 50       22 ARRAY_ITEM:
468             Devel::Monitor::Common::printMsg('Object '.$trace->getCircularPath().' = '.$varRef." is tied. Untie it to check circular references for this object.\n") if tied(@$varRef);
469 11         37 for (my $i=0; $i
470             #print STDERR "CURRENT VAR : ".\($varRef->[$i])." ::: ".$varRef->[$i]."\n";
471 122         260 my $ref = _getVarRef(\($varRef->[$i]));
472             #Devel::Monitor::Common::printMsg('Object at '.$trace->getCircularPath().'['.$i.']'.
473             #" is ARRAY ARRAY ARRAY tied. We cannot check circular references for this object.\n") if $ref =~ /SCALAR/;
474 122         418 printCircularRef($ref,$hideWeakenedCircRef,'['.$i.']',$trace,$weakenedRef,$origRef,$seenRef,$circRefTypesRef);
475             }
476             } else {
477             #Other objects
478 0         0 my $runPatch = 0;
479             try {
480 0     0   0 goto HASH_ITEM;
481             } otherwise {
482 0     0   0 $runPatch = 1;
483 0         0 };
484 0 0       0 if ($runPatch) {
485             try {
486 0     0   0 goto ARRAY_ITEM;
487             } otherwise {
488 0     0   0 die("Cannot verify circular references for $varRef of type ".ref($varRef)."\n");
489 0         0 };
490             }
491             }
492             }
493              
494             sub _printCircularRefHeader {
495 13     13   15 my $origRef = shift;
496            
497 13         35 Devel::Monitor::Common::printMsg("-------------------------------------------------------------------------------\n");
498 13         65 Devel::Monitor::Common::printMsg("Checking circular references for $origRef\n");
499             }
500            
501             sub _printCircularRefResults {
502 13     13   17 my ($origRef, $circRefTypesRef) = @_;
503            
504 13         18 my $circRefsCount = 0;
505 13         13 my $internalCircRefsCount = 0;
506 13         17 my $weakCircRefsCount = 0;
507 13         21 foreach my $crt (@$circRefTypesRef) {
508 22 50       47 $weakCircRefsCount++ if $crt == CRT_WEAK_CIRC_REF();
509 22 100       36 $circRefsCount++ if $crt == CRT_CIRC_REF();
510 22 100       49 $internalCircRefsCount++ if $crt == CRT_INTERNAL_CIRC_REF();
511             }
512 13         33 Devel::Monitor::Common::printMsg("-------------------------------------------------------------------------------\n");
513 13         59 Devel::Monitor::Common::printMsg("Results for $origRef\n");
514 13         53 Devel::Monitor::Common::printMsg("Circular reference : $circRefsCount\n");
515 13         54 Devel::Monitor::Common::printMsg("Internal circular reference : $internalCircRefsCount\n");
516 13         50 Devel::Monitor::Common::printMsg("Weak circular reference : $weakCircRefsCount\n");
517 13         40 Devel::Monitor::Common::printMsg("-------------------------------------------------------------------------------\n");
518             }
519            
520             # METH _checkCircularRef
521             #
522             # DESC Verify if there is a circular reference on the current variable
523             # RETV Circular Reference Type
524             # One of : CRT_NONE, CRT_CIRC_REF, CRT_WEAK_CIRC_REF, CRT_INTERNAL_CIRC_REF
525              
526             sub _checkCircularRef {
527 155     155   173 my $varRef = shift;
528 155         157 my $hideWeakenedCircRef = shift;
529 155         155 my $trace = shift;
530 155         136 my $weakenedRef = shift;
531 155         144 my $origRef = shift;
532 155         146 my $seenRef = shift;
533 155 50       291 if ($varRef) {
534             #print STDERR "\$varRef : $varRef\n";
535             #print STDERR "\$origRef : $origRef\n";
536 155 100       245 if ($origRef) {
537             #If we found the original reference
538 144         287 my $isCircRef = ($varRef eq $origRef);
539             #If we found a reference more than one time, it means we loop infinitely
540 144   66     613 my $isInternalCircRef = (exists($seenRef->{$varRef}) && ($seenRef->{$varRef} > 1));
541            
542 144 100 100     561 if ($isCircRef || $isInternalCircRef) {
543 19         29 my $weakenedInCircRefRef = _getWeakenedInCircRef($trace,$weakenedRef);
544 19         37 my $isWeakenedItems = (scalar(@$weakenedInCircRefRef) > 0);
545 19 50 0     53 if (!$hideWeakenedCircRef || #If we show everything
    0 33        
      0        
546             ($hideWeakenedCircRef && !$isWeakenedItems)) { #Otherwise, if there is no weak reference
547            
548 19         67 Devel::Monitor::Common::printMsg("-------------------------------------------------------------------------------\n");
549 19 100       59 if ($isCircRef) {
    50          
550 13         42 Devel::Monitor::Common::printMsg('Circular reference found : '.$trace->getCircularPath()."\n");
551             }
552             elsif ($isInternalCircRef) {
553 6         19 Devel::Monitor::Common::printMsg('Internal circular reference found : '.$trace->getCircularPath()." on $varRef\n");
554             }
555 19 50       56 if ($isWeakenedItems) {
556 0         0 Devel::Monitor::Common::printMsg('with weakened reference on : '.join(', ', @$weakenedInCircRefRef)."\n");
557             }
558 19         56 $trace->dump();
559 19         52 Devel::Monitor::Common::printMsg("-------------------------------------------------------------------------------\n");
560 19 50       46 return CRT_WEAK_CIRC_REF() if $isWeakenedItems;
561 19 100       75 return CRT_CIRC_REF() if $isCircRef;
562 6 50       29 return CRT_INTERNAL_CIRC_REF() if $isInternalCircRef;
563 0         0 die("_checkCircularRef : Should not be here (1)\n");
564             }
565             elsif ($hideWeakenedCircRef && $isWeakenedItems) {
566 0         0 return CRT_WEAK_CIRC_REF();
567             }
568             }
569             }
570 136         266 return CRT_NONE();
571             }
572 0         0 die("_checkCircularRef : \$varRef is undefined\n");
573             }
574              
575             sub _addSeenRef {
576 214     214   224 my $varRef = shift;
577 214         218 my $seenRef = shift;
578             #print STDERR "_addSeenRef: $varRef\n";
579 214 100       473 if (exists($seenRef->{$varRef})) {
580 16         40 $seenRef->{$varRef}++;
581             } else {
582 198         626 $seenRef->{$varRef} = 1;
583             }
584             }
585              
586             sub _getVarRef {
587 145     145   155 my $varRef = shift;
588             ###########################################################
589             # We cannot use tied objects because it reuse memory space
590             ###########################################################
591             # use Tie::Hash;
592             #
593             # my $self = {'a' => 1,
594             # 'b' => 2};
595             # #monitor('self' => \$self);
596             # tie %$self, 'Tie::StdHash';
597             # print STDERR \($self->{'a'})."\n";
598             # print STDERR \($self->{'b'})."\n";
599             # print STDERR \($self->{'a'}).\($self->{'b'})."\n";
600             # foreach my $key (keys %$self) {
601             # my $keyRef = \$key;
602             # my $value = $self->{$key};
603             # my $valueRef = \($self->{$key});
604             # print STDERR "KEY:$key, KEY REF:$keyRef, VALUE:$value, VALUE REF:$valueRef\n";
605             # }
606             ###########################################################
607             # Output
608             ###########################################################
609             # MONITOR HASH : self
610             # SCALAR(0x8141384)
611             # SCALAR(0x8141384)
612             # SCALAR(0x8141384)SCALAR(0x81413cc)
613             # KEY:a, KEY REF:SCALAR(0x8141420), VALUE:1, VALUE REF:SCALAR(0x824becc)
614             # KEY:b, KEY REF:SCALAR(0x81413cc), VALUE:2, VALUE REF:SCALAR(0x824becc)
615             # DESTROY HASH : self
616             ###########################################################
617             # We see clearly that it reuse memory space instead of
618             # refering to the original values from the untied object
619             ###########################################################
620 145         132 my $ref;
621             #if ($$varRef &&
622             # ($varRef =~ /SCALAR/) &&
623             # ($$varRef =~ /(ARRAY|HASH)/)) {
624             # $ref = $$varRef;
625             #} else {
626 145         136 $ref = $varRef;
627             #}
628 145         206 return $ref;
629             }
630              
631             sub _getWeakenedInCircRef {
632 19     19   22 my $trace = shift;
633 19         19 my $weakenedRef = shift;
634              
635 19         21 my @weakenedInCircRef;
636 19         52 my $traceItemsRef = $trace->getTraceItems;
637             #The last item represent the circular reference
638 19         28 my $traceItemCircRef = $traceItemsRef->[$#$traceItemsRef];
639             #for my $i (($#$traceItemsRef-1)..0) {
640 19         52 for (my $i=($#$traceItemsRef-1); $i>=0; $i--) {
641             #Get the current item
642 45         61 my $traceItem = $traceItemsRef->[$i];
643             #print STDERR "traceItem ".$traceItem->getVarRef()."\n";
644             #We verify that the item is a weaken reference or not
645 45         69 foreach my $weakened (@$weakenedRef) {
646             #print STDERR "weakened ".$weakened."\n";
647 0 0       0 if ($traceItem->getVarRef() eq $weakened) {
648             #print STDERR "push\n";
649 0         0 push(@weakenedInCircRef, $weakened);
650             }
651             }
652             #We finish when we end the circular reference
653 45 100       110 last if ($traceItem->getVarRef() eq $traceItemCircRef->getVarRef());
654             }
655             #print STDERR "RETURN ".join(', ', @weakenedInCircRef)."\n";
656 19         45 return \@weakenedInCircRef;
657             }
658            
659             1;
660              
661             __END__