ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/perlmulticore/perlmulticore.h
Revision: 1.6
Committed: Sun Mar 3 13:06:01 2019 UTC (5 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.5: +38 -3 lines
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 "perlmulticore.h"
23
24 // in your XS function:
25
26 perlinterp_release ();
27 do_the_C_thing ();
28 perlinterp_acquire ();
29
30 // optional, in BOOT section:
31
32 perlmulticore_advertise ();
33
34 =head1 DESCRIPTION
35
36 This documentation is the abridged version of the full documention at
37 L<http://perlmulticore.schmorp.de/>. It's recommended to go there instead
38 of reading this document.
39
40 This header file implements a very low overhead (both in code and runtime)
41 mechanism for XS modules to allow re-use of the perl interpreter for other
42 threads while doing some lengthy operation, such as cryptography, SQL
43 queries, disk I/O and so on.
44
45 The newest version of the header file itself, can be downloaded from
46 L<http://perlmulticore.schmorp.de/perlmulticore.h>.
47
48 =head1 HOW DO I USE THIS IN MY MODULES?
49
50 The usage is very simple - you include this header file in your XS module. Then, before you
51 do your lengthy operation, you release the perl interpreter:
52
53 perlinterp_release ();
54
55 And when you are done with your computation, you acquire it again:
56
57 perlinterp_acquire ();
58
59 And that's it. This doesn't load any modules and consists of only a few
60 machine instructions when no module to take advantage of it is loaded.
61
62 More documentation and examples can be found at the perl multicore site at
63 L<http://perlmulticore.schmorp.de>.
64
65 =head1 THE HARD AND FAST RULES
66
67 As with everything, there are a number of rules to follow.
68
69 =over 4
70
71 =item I<Never> touch any perl data structures after calling C<perlinterp_release>.
72
73 Anything perl is completely off-limits after C<perlinterp_release>, until
74 you call C<perlinterp_acquire>, after which you can access perl stuff
75 again.
76
77 That includes anything in the perl interpreter that you didn't prove to be
78 safe, and didn't prove to be safe in older and future versions of perl:
79 global variables, local perl scalars, even if you are sure nobody accesses
80 them and you only try to "read" their value.
81
82 =item I<Always> call C<perlinterp_release> and C<perlinterp_acquire> in pairs.
83
84 For each C<perlinterp_release> call there must be a C<perlinterp_acquire>
85 call. They don't have to be in the same function, and you can have
86 multiple calls to them, as long as every C<perlinterp_release> call is
87 followed by exactly one C<perlinterp_acquire> call at runtime.
88
89 =item I<Never> nest calls to C<perlinterp_release> and C<perlinterp_acquire>.
90
91 That simply means that after calling C<perlinterp_release>, you must
92 call C<perlinterp_acquire> before calling C<perlinterp_release>
93 again. Likewise, after C<perlinterp_acquire>, you can call
94 C<perlinterp_release> but not another C<perlinterp_acquire>.
95
96 =item I<Always> call C<perlinterp_release> first.
97
98 You I<must not> call C<perlinterp_acquire> without having called
99 C<perlinterp_release> before.
100
101 =item I<Never> underestimate threads.
102
103 While it's easy to add parallel execution ability to your XS module, it
104 doesn't mean it is safe. After you release the perl interpreter, it's
105 perfectly possible that it will call your XS function in another thread,
106 even while your original function still executes. In other words: your C
107 code must be thread safe, and if you use any library, that library must be
108 thread-safe, too.
109
110 Always assume that the code between C<perlinterp_release> and
111 C<perlinterp_acquire> is executed in parallel on multiple CPUs at the same
112 time.
113
114 =back
115
116
117 =head1 DISABLING PERL MULTICORE AT COMPILE TIME
118
119 You can disable the complete perl multicore API by defining the
120 symbol C<PERL_MULTICORE_DISABLE> to C<1> (e.g. by specifying
121 F<-DPERL_MULTICORE_DISABLE> as compiler argument).
122
123 This could be added to perl's C<CPPFLAGS> when configuring perl on
124 platforms that do not support threading at all for example.
125
126
127 =head1 ADVERTISING MULTICORE API SUPPORT
128
129 To help users find out whether a particular build of your module is, in
130 fact, multicore enabled, you can invoke the C<perlmulticore_advertise>
131 macro in your C<BOOT:> section, e.g.:
132
133
134 MODULE = My::Mod PACKAGE = My::Mod::Pkg
135
136 BOOT:
137 perlmulticore_advertise ();
138
139 What this does is set the C<$My::Mod::PERLMULTICORE_SUPPORT> variable to
140 the major API version * 1000 + minor version, for example, version C<1002>
141 introduced this feature.
142
143 For this to work, the C<cv> parameter passed to C<BOOT:> must still be
144 in scope. To ensure this, either invoke the macro early in your C<BOOT:>
145 section, or don't declare a local variable called C<cv>, either of which
146 should be easy to do.
147
148 Note that this is I<optional>, so you don't have to do that.
149
150
151 =head1 AUTHOR
152
153 Marc A. Lehmann <perlmulticore@schmorp.de>
154 http://perlmulticore.schmorp.de/
155
156 =head1 LICENSE
157
158 The F<perlmulticore.h> header file is put into the public
159 domain. Where this is legally not possible, or at your
160 option, it can be licensed under creativecommons CC0
161 license: L<https://creativecommons.org/publicdomain/zero/1.0/>.
162
163 =cut
164
165 */
166
167 #define PERL_MULTICORE_MAJOR 1 /* bumped on incompatible changes */
168 #define PERL_MULTICORE_MINOR 2 /* bumped on every change */
169
170 #if PERL_MULTICORE_DISABLE
171
172 #define perlinterp_release() do { } while (0)
173 #define perlinterp_acquire() do { } while (0)
174 #define perlmulticore_advertise() do { } while (0)
175
176 #else
177
178 START_EXTERN_C
179
180 /* this struct is shared between all modules, and currently */
181 /* contain only the two function pointers for release/acquire */
182 struct perl_multicore_api
183 {
184 void (*pmapi_release)(void);
185 void (*pmapi_acquire)(void);
186 };
187
188 static void perl_multicore_init (void);
189
190 static const struct perl_multicore_api perl_multicore_api_init
191 = { perl_multicore_init, 0 };
192
193 static struct perl_multicore_api *perl_multicore_api
194 = (struct perl_multicore_api *)&perl_multicore_api_init;
195
196 #define perlinterp_release() perl_multicore_api->pmapi_release ()
197 #define perlinterp_acquire() perl_multicore_api->pmapi_acquire ()
198
199 /* this is the release/acquire implementation used as fallback */
200 static void
201 perl_multicore_nop (void)
202 {
203 }
204
205 static const char perl_multicore_api_key[] = "perl_multicore_api";
206
207 /* this is the initial implementation of "release" - it initialises */
208 /* the api and then calls the real release function */
209 static void
210 perl_multicore_init (void)
211 {
212 dTHX;
213
214 /* check for existing API struct in PL_modglobal */
215 SV **api_svp = hv_fetch (PL_modglobal, perl_multicore_api_key,
216 sizeof (perl_multicore_api_key) - 1, 1);
217
218 if (SvPOKp (*api_svp))
219 perl_multicore_api = (struct perl_multicore_api *)SvPVX (*api_svp); /* we have one, use the existing one */
220 else
221 {
222 /* create a new one with a dummy nop implementation */
223 #ifdef NEWSV
224 SV *api_sv = NEWSV (0, sizeof (*perl_multicore_api));
225 #else
226 SV *api_sv = newSV ( sizeof (*perl_multicore_api));
227 #endif
228 SvCUR_set (api_sv, sizeof (*perl_multicore_api));
229 SvPOK_only (api_sv);
230 perl_multicore_api = (struct perl_multicore_api *)SvPVX (api_sv);
231 perl_multicore_api->pmapi_release =
232 perl_multicore_api->pmapi_acquire = perl_multicore_nop;
233 *api_svp = api_sv;
234 }
235
236 /* call the real (or dummy) implementation now */
237 perlinterp_release ();
238 }
239
240 #define perlmulticore_advertise() \
241 sv_setiv (get_sv ( \
242 form ("%s::PERLMULTICORE_SUPPORT", HvNAME (GvSTASH (CvGV (cv)))), \
243 GV_ADD | GV_ADDMULTI), \
244 PERL_MULTICORE_MAJOR * 1000 + PERL_MULTICORE_MINOR); \
245
246 END_EXTERN_C
247
248 #endif
249
250 #endif
251