ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Digest-Hashcash/perlmulticore.h
Revision: 1.1
Committed: Tue Jul 21 05:06:32 2015 UTC (8 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_1, rel-1_0, HEAD
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * Author: Marc A. Lehmann <xsthreadpool@schmorp.de>
3 * License: public domain, or where this is not possible/at your option,
4 * CC0 (https://creativecommons.org/publicdomain/zero/1.0/)
5 *
6 * Full documentation can be found at http://perlmulticore.schmorp.de/
7 * The newest version of this header can be downloaded from
8 * http://perlmulticore.schmorp.de/perlmulticore.h
9 */
10
11 #ifndef PERL_MULTICORE_H
12 #define PERL_MULTICORE_H
13
14 /*
15
16 =head1 NAME
17
18 perlmulticore.h - implements the Perl Multicore Specification
19
20 =head1 SYNOPSIS
21
22 #include "perlmultiore.h"
23
24 // in your XS function:
25
26 perlinterp_release ();
27 do_the_C_thing ();
28 perlinterp_acquire ();
29
30 =head1 DESCRIPTION
31
32 This documentation is the abridged version of the full documention at
33 L<http://perlmulticore.schmorp.de/>. It's recommended to go there instead
34 of reading this document.
35
36 This header file implements a very low overhead (both in code and runtime)
37 mechanism for XS modules to allow re-use of the perl interpreter for other
38 threads while doing some lengthy operation, such as cryptography, SQL
39 queries, disk I/O and so on.
40
41 The newest version of the header file itself, can be downloaded from
42 L<http://perlmulticore.schmorp.de/perlmulticore.h>.
43
44 =head1 HOW DO I USE THIS IN MY MODULES?
45
46 The usage is very simple - you include this header file in your XS module. Then, before you
47 do your lengthy operation, you release the perl interpreter:
48
49 perlinterp_release ();
50
51 And when you are done with your computation, you acquire it again:
52
53 perlinterp_acquire ();
54
55 And that's it. This doesn't load any modules and consists of only a few
56 machine instructions when no module to take advantage of it is loaded.
57
58 More documentation and examples can be found at the perl multicore site at
59 L<http://perlmulticore.schmorp.de>.
60
61 =head1 THE HARD AND FAST RULES
62
63 As with everything, there are a number of rules to follow.
64
65 =over 4
66
67 =item I<Never> touch any perl data structures after calling C<perlinterp_release>.
68
69 Anything perl is completely off-limits after C<perlinterp_release>, until
70 you call C<perlinterp_acquire>, after which you can access perl stuff
71 again.
72
73 That includes anything in the perl interpreter that you didn't prove to be
74 safe, and didn't prove to be safe in older and future versions of perl:
75 global variables, local perl scalars, even if you are sure nobody accesses
76 them and you only try to "read" their value.
77
78 =item I<Always> call C<perlinterp_release> and C<perlinterp_acquire> in pairs.
79
80 For each C<perlinterp_release> call there must be a C<perlinterp_acquire>
81 call. They don't have to be in the same function, and you can have
82 multiple calls to them, as long as every C<perlinterp_release> call is
83 followed by exactly one C<perlinterp_acquire> call at runtime.
84
85 =item I<Never> nest calls to C<perlinterp_release> and C<perlinterp_acquire>.
86
87 That simply means that after calling C<perlinterp_release>, you must
88 call C<perlinterp_acquire> before calling C<perlinterp_release>
89 again. Likewise, after C<perlinterp_acquire>, you can call
90 C<perlinterp_release> but not another C<perlinterp_acquire>.
91
92 =item I<Always> call C<perlinterp_release> first.
93
94 You I<must not> call C<perlinterp_acquire> without having called
95 C<perlinterp_release> before.
96
97 =item I<Never> underestimate threads.
98
99 While it's easy to add parallel execution ability to your XS module, it
100 doesn't mean it is safe. After you release the perl interpreter, it's
101 perfectly possible that it will call your XS function in another thread,
102 even while your original function still executes. In other words: your C
103 code must be thread safe, and if you use any library, that library must be
104 thread-safe, too.
105
106 Always assume that the code between C<perlinterp_release> and
107 C<perlinterp_acquire> is executed in parallel on multiple CPUs at the same
108 time.
109
110 =back
111
112
113 =head1 DISABLING PERL MULTICORE AT COMPILE TIME
114
115 You can disable the complete perl multicore API by defining the
116 symbol C<PERL_MULTICORE_DISABLE> to C<1> (e.g. by specifying
117 F<-DPERL_MULTICORE_DISABLE> as compiler argument).
118
119 This could be added to perl's C<CPPFLAGS> when configuring perl on
120 platforms that do not support threading at all for example.
121
122
123 =head1 AUTHOR
124
125 Marc A. Lehmann <perlmulticore@schmorp.de>
126 http://perlmulticore.schmorp.de/
127
128 =head1 LICENSE
129
130 The F<perlmulticore.h> header file is put into the public
131 domain. Where this is legally not possible, or at your
132 option, it can be licensed under creativecommons CC0
133 license: L<https://creativecommons.org/publicdomain/zero/1.0/>.
134
135 =cut
136
137 */
138
139 #define PERL_MULTICORE_MAJOR 1 /* bumped on incompatible changes */
140 #define PERL_MULTICORE_MINOR 0 /* bumped on every change */
141
142 #if PERL_MULTICORE_DISABLE
143
144 #define perlinterp_release() do { } while (0)
145 #define perlinterp_acquire() do { } while (0)
146
147 #else
148
149 START_EXTERN_C
150
151 /* this struct is shared between all modules, and currently */
152 /* contain only the two function pointers for release/acquire */
153 struct perl_multicore_api
154 {
155 void (*pmapi_release)(void);
156 void (*pmapi_acquire)(void);
157 };
158
159 static void perl_multicore_init (void);
160
161 static const struct perl_multicore_api perl_multicore_api_init
162 = { perl_multicore_init, 0 };
163
164 static struct perl_multicore_api *perl_multicore_api
165 = (struct perl_multicore_api *)&perl_multicore_api_init;
166
167 #define perlinterp_release() perl_multicore_api->pmapi_release ()
168 #define perlinterp_acquire() perl_multicore_api->pmapi_acquire ()
169
170 /* this is the release/acquire implementation used as fallback */
171 static void
172 perl_multicore_nop (void)
173 {
174 }
175
176 static const char perl_multicore_api_key[] = "perl_multicore_api";
177
178 /* this is the initial implementation of "release" - it initialises */
179 /* the api and then calls the real release function */
180 static void
181 perl_multicore_init (void)
182 {
183 dTHX;
184
185 /* check for existing API struct in PL_modglobal */
186 SV **api_svp = hv_fetch (PL_modglobal, perl_multicore_api_key,
187 sizeof (perl_multicore_api_key) - 1, 1);
188
189 if (SvPOKp (*api_svp))
190 perl_multicore_api = (struct perl_multicore_api *)SvPVX (*api_svp); /* we have one, use the existing one */
191 else
192 {
193 /* create a new one with a dummy nop implementation */
194 SV *api_sv = NEWSV (0, sizeof (*perl_multicore_api));
195 SvCUR_set (api_sv, sizeof (*perl_multicore_api));
196 SvPOK_only (api_sv);
197 perl_multicore_api = (struct perl_multicore_api *)SvPVX (api_sv);
198 perl_multicore_api->pmapi_release =
199 perl_multicore_api->pmapi_acquire = perl_multicore_nop;
200 *api_svp = api_sv;
201 }
202
203 /* call the real (or dummy) implementation now */
204 perlinterp_release ();
205 }
206
207 END_EXTERN_C
208
209 #endif
210
211 #endif