XS side of new threads::shared designed, coded and compiles,
[p5sagit/p5-mst-13.2.git] / ext / threads / shared / shared.pm
1 package threads::shared;
2
3 use strict;
4 use warnings;
5 use Config;
6 use Scalar::Util qw(weaken);
7 use attributes qw(reftype);
8
9 BEGIN {
10     if ($Config{'useithreads'} && $threads::threads) {
11         *share = \&share_enabled;
12         *cond_wait = \&cond_wait_enabled;
13         *cond_signal = \&cond_signal_enabled;
14         *cond_broadcast = \&cond_broadcast_enabled;
15         *unlock = \&unlock_enabled;
16     } else {
17         *share = \&share_disabled;
18         *cond_wait = \&cond_wait_disabled;
19         *cond_signal = \&cond_signal_disabled;
20         *cond_broadcast = \&cond_broadcast_disabled;
21         *unlock = \&unlock_disabled;
22     }
23 }
24
25 require Exporter;
26 require DynaLoader;
27 our @ISA = qw(Exporter DynaLoader);
28
29 our @EXPORT = qw(share cond_wait cond_broadcast cond_signal unlock);
30 our $VERSION = '0.90';
31
32 our %shared;
33
34 sub cond_wait_disabled { return @_ };
35 sub cond_signal_disabled { return @_};
36 sub cond_broadcast_disabled { return @_};
37 sub unlock_disabled { 1 };
38 sub lock_disabled { 1 }
39 sub share_disabled { return @_}
40
41 sub share_enabled (\[$@%]) { # \]
42     my $value = $_[0];
43     my $ref = reftype($value);
44     if($ref eq 'SCALAR') {
45         my $obj = \threads::shared::sv->new($$value);
46         bless $obj, 'threads::shared::sv';
47         $shared{$$obj} = $value;
48         weaken($shared{$$obj});
49     } elsif($ref eq "ARRAY") {
50         tie @$value, 'threads::shared::av', $value;
51     } elsif($ref eq "HASH") {
52         tie %$value, "threads::shared::hv", $value;
53     } else {
54         die "You cannot share ref of type $_[0]\n";
55     }
56 }
57
58
59 package threads::shared::sv;
60 use base 'threads::shared';
61
62 sub DESTROY {}
63
64 package threads::shared::av;
65 use base 'threads::shared';
66 use Scalar::Util qw(weaken);
67 sub TIEARRAY {
68         my $class = shift;
69         my $value = shift;
70         my $self = bless \threads::shared::av->new($value),'threads::shared::av';
71         $shared{$self->ptr} = $value;
72         weaken($shared{$self->ptr});
73         return $self;
74 }
75
76 package threads::shared::hv;
77 use base 'threads::shared';
78 use Scalar::Util qw(weaken);
79 sub TIEHASH {
80     my $class = shift;
81     my $value = shift;
82     my $self = bless \threads::shared::hv->new($value),'threads::shared::hv';
83     $shared{$self->ptr} = $value;
84     weaken($shared{$self->ptr});
85     return $self;
86 }
87
88 package threads::shared;
89
90 $threads::shared::threads_shared = 1;
91
92 bootstrap threads::shared $VERSION;
93
94 __END__
95
96 =head1 NAME
97
98 threads::shared - Perl extension for sharing data structures between threads
99
100 =head1 SYNOPSIS
101
102   use threads::shared;
103
104   my($foo, @foo, %foo);
105   share($foo);
106   share(@foo);
107   share(%hash);
108   my $bar = share([]);
109   $hash{bar} = share({});
110
111   lock(%hash);
112   unlock(%hash);
113   cond_wait($scalar);
114   cond_broadcast(@array);
115   cond_signal(%hash);
116
117 =head1 DESCRIPTION
118
119 This modules allows you to share() variables. These variables will
120 then be shared across different threads (and pseudoforks on
121 win32). They are used together with the threads module.
122
123 =head1 EXPORT
124
125 C<share>, C<lock>, C<unlock>, C<cond_wait>, C<cond_signal>, C<cond_broadcast>
126
127 =head1 FUNCTIONS
128
129 =over 4
130
131 =item share VARIABLE
132
133 C<share> takes a value and marks it as shared, you can share a scalar, array, hash
134 scalar ref, array ref and hash ref, C<share> will return the shared value.
135
136 C<share> will traverse up references exactly I<one> level.
137 C<share(\$a)> is equivalent to C<share($a)>, while C<share(\\$a)> is not.
138
139 =item lock VARIABLE
140
141 C<lock> places a lock on a variable until the lock goes out of scope.  If
142 the variable is locked by another thread, the C<lock> call will block until
143 it's available. C<lock> is recursive, so multiple calls to C<lock> are
144 safe--the variable will remain locked until the outermost lock on the
145 variable goes out of scope or C<unlock> is called enough times to match
146 the number of calls to <lock>.
147
148 If a container object, such as a hash or array, is locked, all the elements
149 of that container are not locked. For example, if a thread does a C<lock
150 @a>, any other thread doing a C<lock($a[12])> won't block.
151
152 C<lock> will traverse up references exactly I<one> level.
153 C<lock(\$a)> is equivalent to C<lock($a)>, while C<lock(\\$a)> is not.
154
155
156 =item unlock VARIABLE
157
158 C<unlock> takes a locked shared value and decrements the lock count.
159 If the lock count is zero the variable is unlocked. It is not necessary
160 to call C<unlock> but it can be usefull to reduce lock contention.
161
162 C<unlock> will traverse up references exactly I<one> level.
163 C<unlock(\$a)> is equivalent to C<unlock($a)>, while C<unlock(\\$a)> is not.
164
165 =item cond_wait VARIABLE
166
167 The C<cond_wait> function takes a B<locked> variable as a parameter,
168 unlocks the variable, and blocks until another thread does a C<cond_signal>
169 or C<cond_broadcast> for that same locked variable. The variable that
170 C<cond_wait> blocked on is relocked after the C<cond_wait> is satisfied.
171 If there are multiple threads C<cond_wait>ing on the same variable, all but
172 one will reblock waiting to reaquire the lock on the variable. (So if
173 you're only using C<cond_wait> for synchronization, give up the lock as
174 soon as possible)
175
176 It is important to note that the variable can be notified even if no
177 thread C<cond_signal> or C<cond_broadcast> on the variable. It is therefore
178 important to check the value of the variable and go back to waiting if the
179 requirment is not fullfilled.
180
181 =item cond_signal VARIABLE
182
183 The C<cond_signal> function takes a B<locked> variable as a parameter and
184 unblocks one thread that's C<cond_wait>ing on that variable. If more than
185 one thread is blocked in a C<cond_wait> on that variable, only one (and
186 which one is indeterminate) will be unblocked.
187
188 If there are no threads blocked in a C<cond_wait> on the variable, the
189 signal is discarded.
190
191 =item cond_broadcast VARIABLE
192
193 The C<cond_broadcast> function works similarly to C<cond_signal>.
194 C<cond_broadcast>, though, will unblock B<all> the threads that are blocked
195 in a C<cond_wait> on the locked variable, rather than only one.
196
197
198 =head1 NOTES
199
200 threads::shared is designed to disable itself silently if threads are
201 not available. If you want access to threads, you must C<use threads>
202 before you C<use threads::shared>.  threads will emit a warning if you
203 use it after threads::shared.
204
205 =head1 BUGS
206
207 C<bless> is not supported on shared references, in the current version
208 C<bless> will only bless the thread local reference and the blessing
209 will not propagate to the other threads, this is expected to be implmented
210 in the future.
211
212 Does not support splice on arrays!
213
214 =head1 AUTHOR
215
216 Arthur Bergman E<lt>arthur at contiller.seE<gt>
217
218 threads::shared is released under the same license as Perl
219
220 Documentation borrowed from Thread.pm
221
222 =head1 SEE ALSO
223
224 L<perl> L<threads>
225
226 =cut
227
228
229
230
231