ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Crypt-Ed25519/perlmulticore.h
Revision: 1.3
Committed: Wed Aug 11 23:02:09 2021 UTC (2 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_05, HEAD
Changes since 1.2: +47 -3 lines
Log Message:
1.05

File Contents

# User Rev Content
1 root 1.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 root 1.2 *
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 root 1.1 */
10    
11     #ifndef PERL_MULTICORE_H
12     #define PERL_MULTICORE_H
13    
14     /*
15    
16     =head1 NAME
17    
18 root 1.2 perlmulticore.h - implements the Perl Multicore Specification
19 root 1.1
20     =head1 SYNOPSIS
21    
22 root 1.2 #include "perlmulticore.h"
23 root 1.1
24     // in your XS function:
25    
26     perlinterp_release ();
27     do_the_C_thing ();
28     perlinterp_acquire ();
29    
30 root 1.3 // optional, in BOOT section:
31    
32     perlmulticore_support ();
33    
34 root 1.1 =head1 DESCRIPTION
35    
36 root 1.2 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 root 1.1
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 root 1.2 More documentation and examples can be found at the perl multicore site at
63     L<http://perlmulticore.schmorp.de>.
64 root 1.1
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 root 1.2 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 root 1.1
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 root 1.2 them and you only try to "read" their value.
81 root 1.1
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 root 1.2 followed by exactly one C<perlinterp_acquire> call at runtime.
88 root 1.1
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 root 1.2 You I<must not> call C<perlinterp_acquire> without having called
99     C<perlinterp_release> before.
100 root 1.1
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 root 1.2 time.
113 root 1.1
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 root 1.3 =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_support>
131     macro in your C<BOOT:> 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<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 root 1.1 =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 root 1.3 /* 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 root 1.1 #define PERL_MULTICORE_MAJOR 1 /* bumped on incompatible changes */
172 root 1.3 #define PERL_MULTICORE_MINOR 2 /* bumped on every change */
173 root 1.1
174     #if PERL_MULTICORE_DISABLE
175    
176 root 1.3 #define perlinterp_release() do { } while (0)
177     #define perlinterp_acquire() do { } while (0)
178     #define perlmulticore_support() do { } while (0)
179 root 1.1
180     #else
181    
182 root 1.2 START_EXTERN_C
183    
184 root 1.1 /* 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 root 1.2 static const struct perl_multicore_api perl_multicore_api_init
195     = { perl_multicore_init, 0 };
196 root 1.1
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     perl_multicore_nop (void)
206     {
207     }
208    
209 root 1.2 static const char perl_multicore_api_key[] = "perl_multicore_api";
210    
211 root 1.1 /* this is the initial implementation of "release" - it initialises */
212     /* the api and then calls the real release function */
213     static void
214     perl_multicore_init (void)
215     {
216     dTHX;
217    
218     /* check for existing API struct in PL_modglobal */
219 root 1.2 SV **api_svp = hv_fetch (PL_modglobal, perl_multicore_api_key,
220     sizeof (perl_multicore_api_key) - 1, 1);
221 root 1.1
222     if (SvPOKp (*api_svp))
223     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 root 1.3 #ifdef NEWSV
228 root 1.1 SV *api_sv = NEWSV (0, sizeof (*perl_multicore_api));
229 root 1.3 #else
230     SV *api_sv = newSV ( sizeof (*perl_multicore_api));
231     #endif
232 root 1.1 SvCUR_set (api_sv, sizeof (*perl_multicore_api));
233     SvPOK_only (api_sv);
234     perl_multicore_api = (struct perl_multicore_api *)SvPVX (api_sv);
235     perl_multicore_api->pmapi_release =
236     perl_multicore_api->pmapi_acquire = perl_multicore_nop;
237     *api_svp = api_sv;
238     }
239    
240     /* call the real (or dummy) implementation now */
241     perlinterp_release ();
242     }
243    
244 root 1.3 #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 root 1.2 END_EXTERN_C
251    
252 root 1.1 #endif
253    
254     #endif
255 root 1.3