| 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 |