File Coverage

perlmulticore.h
Criterion Covered Total %
statement 0 15 0.0
branch 0 2 0.0
condition n/a
subroutine n/a
pod n/a
total 0 17 0.0


line stmt bran cond sub pod time code
1             /*
2             * Author: Marc A. Lehmann
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_support ();
33              
34             =head1 DESCRIPTION
35              
36             This documentation is the abridged version of the full documention at
37             L. 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.
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.
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 touch any perl data structures after calling C.
72              
73             Anything perl is completely off-limits after C, until
74             you call C, 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 call C and C in pairs.
83              
84             For each C call there must be a C
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 call is
87             followed by exactly one C call at runtime.
88              
89             =item I nest calls to C and C.
90              
91             That simply means that after calling C, you must
92             call C before calling C
93             again. Likewise, after C, you can call
94             C but not another C.
95              
96             =item I call C first.
97              
98             You I call C without having called
99             C before.
100              
101             =item I 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 and
111             C 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 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 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
131             macro in your C section, e.g.:
132              
133              
134             MODULE = My::Mod PACKAGE = My::Mod::Pkg
135              
136             BOOT:
137             perlmulticore_support ();
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 parameter passed to C must still be
144             in scope. To ensure this, either invoke the macro early in your C
145             section, or don't declare a local variable called C, either of which
146             should be easy to do.
147              
148             Note that this is I, so you don't have to do that.
149              
150              
151             =head1 AUTHOR
152              
153             Marc A. Lehmann
154             http://perlmulticore.schmorp.de/
155              
156             =head1 LICENSE
157              
158             The F 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.
162              
163             =cut
164              
165             */
166              
167             /* version history
168             * 1.1 (1001) 2015-07-03: initial release.
169             * 1.2 (1002) 2019-03-03: introduce optional perlmulticore_support macro.
170             */
171             #define PERL_MULTICORE_MAJOR 1 /* bumped on incompatible changes */
172             #define PERL_MULTICORE_MINOR 2 /* bumped on every change */
173              
174             #if PERL_MULTICORE_DISABLE
175              
176             #define perlinterp_release() do { } while (0)
177             #define perlinterp_acquire() do { } while (0)
178             #define perlmulticore_support() do { } while (0)
179              
180             #else
181              
182             START_EXTERN_C
183              
184             /* this struct is shared between all modules, and currently */
185             /* contain only the two function pointers for release/acquire */
186             struct perl_multicore_api
187             {
188             void (*pmapi_release)(void);
189             void (*pmapi_acquire)(void);
190             };
191              
192             static void perl_multicore_init (void);
193              
194             static const struct perl_multicore_api perl_multicore_api_init
195             = { perl_multicore_init, 0 };
196              
197             static struct perl_multicore_api *perl_multicore_api
198             = (struct perl_multicore_api *)&perl_multicore_api_init;
199              
200             #define perlinterp_release() perl_multicore_api->pmapi_release ()
201             #define perlinterp_acquire() perl_multicore_api->pmapi_acquire ()
202              
203             /* this is the release/acquire implementation used as fallback */
204             static void
205 0           perl_multicore_nop (void)
206             {
207 0           }
208              
209             static const char perl_multicore_api_key[] = "perl_multicore_api";
210              
211             /* this is the initial implementation of "release" - it initialises */
212             /* the api and then calls the real release function */
213             static void
214 0           perl_multicore_init (void)
215             {
216             dTHX;
217              
218             /* check for existing API struct in PL_modglobal */
219 0           SV **api_svp = hv_fetch (PL_modglobal, perl_multicore_api_key,
220             sizeof (perl_multicore_api_key) - 1, 1);
221              
222 0 0         if (SvPOKp (*api_svp))
223 0           perl_multicore_api = (struct perl_multicore_api *)SvPVX (*api_svp); /* we have one, use the existing one */
224             else
225             {
226             /* create a new one with a dummy nop implementation */
227             #ifdef NEWSV
228 0           SV *api_sv = NEWSV (0, sizeof (*perl_multicore_api));
229             #else
230             SV *api_sv = newSV ( sizeof (*perl_multicore_api));
231             #endif
232 0           SvCUR_set (api_sv, sizeof (*perl_multicore_api));
233 0           SvPOK_only (api_sv);
234 0           perl_multicore_api = (struct perl_multicore_api *)SvPVX (api_sv);
235 0           perl_multicore_api->pmapi_release =
236 0           perl_multicore_api->pmapi_acquire = perl_multicore_nop;
237 0           *api_svp = api_sv;
238             }
239              
240             /* call the real (or dummy) implementation now */
241 0           perlinterp_release ();
242 0           }
243              
244             #define perlmulticore_support() \
245             sv_setiv (get_sv ( \
246             form ("%s::PERLMULTICORE_SUPPORT", HvNAME (GvSTASH (CvGV (cv)))), \
247             GV_ADD | GV_ADDMULTI), \
248             PERL_MULTICORE_MAJOR * 1000 + PERL_MULTICORE_MINOR); \
249              
250             END_EXTERN_C
251              
252             #endif
253              
254             #endif
255