line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package threads::shared; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
69611
|
use 5.008; |
|
2
|
|
|
|
|
16
|
|
4
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
10
|
use strict; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
81
|
|
6
|
2
|
|
|
2
|
|
13
|
use warnings; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
51
|
|
7
|
2
|
|
|
2
|
|
8
|
use Config; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
106
|
|
8
|
|
|
|
|
|
|
|
9
|
2
|
|
|
2
|
|
22
|
use Scalar::Util qw(reftype refaddr blessed); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
472
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $VERSION = '1.59'; # Please update the pod, too. |
12
|
|
|
|
|
|
|
my $XS_VERSION = $VERSION; |
13
|
|
|
|
|
|
|
$VERSION = eval $VERSION; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# Declare that we have been loaded |
16
|
|
|
|
|
|
|
$threads::shared::threads_shared = 1; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Method of complaint about things we can't clone |
19
|
|
|
|
|
|
|
$threads::shared::clone_warn = undef; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# Load the XS code, if applicable |
22
|
|
|
|
|
|
|
if ($Config::Config{'useithreads'} && $threads::threads) { |
23
|
|
|
|
|
|
|
require XSLoader; |
24
|
|
|
|
|
|
|
XSLoader::load('threads::shared', $XS_VERSION); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
*is_shared = \&_id; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
} else { |
29
|
|
|
|
|
|
|
# String eval is generally evil, but we don't want these subs to |
30
|
|
|
|
|
|
|
# exist at all if 'threads' is not loaded successfully. |
31
|
|
|
|
|
|
|
# Vivifying them conditionally this way saves on average about 4K |
32
|
|
|
|
|
|
|
# of memory per thread. |
33
|
2
|
|
|
2
|
1
|
2768
|
eval <<'_MARKER_'; |
|
2
|
|
|
2
|
1
|
2770
|
|
|
0
|
|
|
0
|
1
|
0
|
|
|
2
|
|
|
2
|
1
|
3350
|
|
|
0
|
|
|
0
|
1
|
0
|
|
|
5
|
|
|
5
|
1
|
8617
|
|
34
|
|
|
|
|
|
|
sub share (\[$@%]) { return $_[0] } |
35
|
|
|
|
|
|
|
sub is_shared (\[$@%]) { undef } |
36
|
|
|
|
|
|
|
sub cond_wait (\[$@%];\[$@%]) { undef } |
37
|
|
|
|
|
|
|
sub cond_timedwait (\[$@%]$;\[$@%]) { undef } |
38
|
|
|
|
|
|
|
sub cond_signal (\[$@%]) { undef } |
39
|
|
|
|
|
|
|
sub cond_broadcast (\[$@%]) { undef } |
40
|
|
|
|
|
|
|
_MARKER_ |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
### Export ### |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub import |
47
|
|
|
|
|
|
|
{ |
48
|
|
|
|
|
|
|
# Exported subroutines |
49
|
2
|
|
|
2
|
|
14038
|
my @EXPORT = qw(share is_shared cond_wait cond_timedwait |
50
|
|
|
|
|
|
|
cond_signal cond_broadcast shared_clone); |
51
|
2
|
50
|
|
|
|
8
|
if ($threads::threads) { |
52
|
0
|
|
|
|
|
0
|
push(@EXPORT, 'bless'); |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# Export subroutine names |
56
|
2
|
|
|
|
|
6
|
my $caller = caller(); |
57
|
2
|
|
|
|
|
4
|
foreach my $sym (@EXPORT) { |
58
|
2
|
|
|
2
|
|
15
|
no strict 'refs'; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
1221
|
|
59
|
14
|
|
|
|
|
18
|
*{$caller.'::'.$sym} = \&{$sym}; |
|
14
|
|
|
|
|
1679
|
|
|
14
|
|
|
|
|
28
|
|
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# Predeclarations for internal functions |
65
|
|
|
|
|
|
|
my ($make_shared); |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
### Methods, etc. ### |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub threads::shared::tie::SPLICE |
71
|
|
|
|
|
|
|
{ |
72
|
0
|
|
|
0
|
|
|
require Carp; |
73
|
0
|
|
|
|
|
|
Carp::croak('Splice not implemented for shared arrays'); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# Create a thread-shared clone of a complex data structure or object |
78
|
|
|
|
|
|
|
sub shared_clone |
79
|
|
|
|
|
|
|
{ |
80
|
0
|
0
|
|
0
|
1
|
|
if (@_ != 1) { |
81
|
0
|
|
|
|
|
|
require Carp; |
82
|
0
|
|
|
|
|
|
Carp::croak('Usage: shared_clone(REF)'); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
0
|
|
|
|
|
|
return $make_shared->(shift, {}); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
### Internal Functions ### |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# Used by shared_clone() to recursively clone |
92
|
|
|
|
|
|
|
# a complex data structure or object |
93
|
|
|
|
|
|
|
$make_shared = sub { |
94
|
|
|
|
|
|
|
my ($item, $cloned) = @_; |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# Just return the item if: |
97
|
|
|
|
|
|
|
# 1. Not a ref; |
98
|
|
|
|
|
|
|
# 2. Already shared; or |
99
|
|
|
|
|
|
|
# 3. Not running 'threads'. |
100
|
|
|
|
|
|
|
return $item if (! ref($item) || is_shared($item) || ! $threads::threads); |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# Check for previously cloned references |
103
|
|
|
|
|
|
|
# (this takes care of circular refs as well) |
104
|
|
|
|
|
|
|
my $addr = refaddr($item); |
105
|
|
|
|
|
|
|
if (exists($cloned->{$addr})) { |
106
|
|
|
|
|
|
|
# Return the already existing clone |
107
|
|
|
|
|
|
|
return $cloned->{$addr}; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# Make copies of array, hash and scalar refs and refs of refs |
111
|
|
|
|
|
|
|
my $copy; |
112
|
|
|
|
|
|
|
my $ref_type = reftype($item); |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# Copy an array ref |
115
|
|
|
|
|
|
|
if ($ref_type eq 'ARRAY') { |
116
|
|
|
|
|
|
|
# Make empty shared array ref |
117
|
|
|
|
|
|
|
$copy = &share([]); |
118
|
|
|
|
|
|
|
# Add to clone checking hash |
119
|
|
|
|
|
|
|
$cloned->{$addr} = $copy; |
120
|
|
|
|
|
|
|
# Recursively copy and add contents |
121
|
|
|
|
|
|
|
push(@$copy, map { $make_shared->($_, $cloned) } @$item); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# Copy a hash ref |
125
|
|
|
|
|
|
|
elsif ($ref_type eq 'HASH') { |
126
|
|
|
|
|
|
|
# Make empty shared hash ref |
127
|
|
|
|
|
|
|
$copy = &share({}); |
128
|
|
|
|
|
|
|
# Add to clone checking hash |
129
|
|
|
|
|
|
|
$cloned->{$addr} = $copy; |
130
|
|
|
|
|
|
|
# Recursively copy and add contents |
131
|
|
|
|
|
|
|
foreach my $key (keys(%{$item})) { |
132
|
|
|
|
|
|
|
$copy->{$key} = $make_shared->($item->{$key}, $cloned); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# Copy a scalar ref |
137
|
|
|
|
|
|
|
elsif ($ref_type eq 'SCALAR') { |
138
|
|
|
|
|
|
|
$copy = \do{ my $scalar = $$item; }; |
139
|
|
|
|
|
|
|
share($copy); |
140
|
|
|
|
|
|
|
# Add to clone checking hash |
141
|
|
|
|
|
|
|
$cloned->{$addr} = $copy; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# Copy of a ref of a ref |
145
|
|
|
|
|
|
|
elsif ($ref_type eq 'REF') { |
146
|
|
|
|
|
|
|
# Special handling for $x = \$x |
147
|
|
|
|
|
|
|
if ($addr == refaddr($$item)) { |
148
|
|
|
|
|
|
|
$copy = \$copy; |
149
|
|
|
|
|
|
|
share($copy); |
150
|
|
|
|
|
|
|
$cloned->{$addr} = $copy; |
151
|
|
|
|
|
|
|
} else { |
152
|
|
|
|
|
|
|
my $tmp; |
153
|
|
|
|
|
|
|
$copy = \$tmp; |
154
|
|
|
|
|
|
|
share($copy); |
155
|
|
|
|
|
|
|
# Add to clone checking hash |
156
|
|
|
|
|
|
|
$cloned->{$addr} = $copy; |
157
|
|
|
|
|
|
|
# Recursively copy and add contents |
158
|
|
|
|
|
|
|
$tmp = $make_shared->($$item, $cloned); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
} else { |
162
|
|
|
|
|
|
|
require Carp; |
163
|
|
|
|
|
|
|
if (! defined($threads::shared::clone_warn)) { |
164
|
|
|
|
|
|
|
Carp::croak("Unsupported ref type: ", $ref_type); |
165
|
|
|
|
|
|
|
} elsif ($threads::shared::clone_warn) { |
166
|
|
|
|
|
|
|
Carp::carp("Unsupported ref type: ", $ref_type); |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
return undef; |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# If input item is an object, then bless the copy into the same class |
172
|
|
|
|
|
|
|
if (my $class = blessed($item)) { |
173
|
|
|
|
|
|
|
bless($copy, $class); |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# Clone READONLY flag |
177
|
|
|
|
|
|
|
if ($ref_type eq 'SCALAR') { |
178
|
|
|
|
|
|
|
if (Internals::SvREADONLY($$item)) { |
179
|
|
|
|
|
|
|
Internals::SvREADONLY($$copy, 1) if ($] >= 5.008003); |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
if (Internals::SvREADONLY($item)) { |
183
|
|
|
|
|
|
|
Internals::SvREADONLY($copy, 1) if ($] >= 5.008003); |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
return $copy; |
187
|
|
|
|
|
|
|
}; |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
1; |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
__END__ |