Commit | Line | Data |
adfe19db |
1 | ################################################################################ |
2 | ## |
3 | ## $Revision: 7 $ |
4 | ## $Author: mhx $ |
5 | ## $Date: 2004/08/13 12:45:55 +0200 $ |
6 | ## |
7 | ################################################################################ |
8 | ## |
9 | ## Version 3.x, Copyright (C) 2004, Marcus Holland-Moritz. |
10 | ## Version 2.x, Copyright (C) 2001, Paul Marquess. |
11 | ## Version 1.x, Copyright (C) 1999, Kenneth Albanowski. |
12 | ## |
13 | ## This program is free software; you can redistribute it and/or |
14 | ## modify it under the same terms as Perl itself. |
15 | ## |
16 | ################################################################################ |
17 | |
18 | =provides |
19 | |
20 | START_MY_CXT |
21 | dMY_CXT_SV |
22 | dMY_CXT |
23 | MY_CXT_INIT |
24 | MY_CXT |
25 | pMY_CXT |
26 | pMY_CXT_ |
27 | _pMY_CXT |
28 | aMY_CXT |
29 | aMY_CXT_ |
30 | _aMY_CXT |
31 | |
32 | =implementation |
33 | |
34 | #ifndef START_MY_CXT |
35 | |
36 | /* |
37 | * Boilerplate macros for initializing and accessing interpreter-local |
38 | * data from C. All statics in extensions should be reworked to use |
39 | * this, if you want to make the extension thread-safe. See ext/re/re.xs |
40 | * for an example of the use of these macros. |
41 | * |
42 | * Code that uses these macros is responsible for the following: |
43 | * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts" |
44 | * 2. Declare a typedef named my_cxt_t that is a structure that contains |
45 | * all the data that needs to be interpreter-local. |
46 | * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t. |
47 | * 4. Use the MY_CXT_INIT macro such that it is called exactly once |
48 | * (typically put in the BOOT: section). |
49 | * 5. Use the members of the my_cxt_t structure everywhere as |
50 | * MY_CXT.member. |
51 | * 6. Use the dMY_CXT macro (a declaration) in all the functions that |
52 | * access MY_CXT. |
53 | */ |
54 | |
55 | #if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \ |
56 | defined(PERL_CAPI) || defined(PERL_IMPLICIT_CONTEXT) |
57 | |
58 | /* This must appear in all extensions that define a my_cxt_t structure, |
59 | * right after the definition (i.e. at file scope). The non-threads |
60 | * case below uses it to declare the data as static. */ |
61 | #define START_MY_CXT |
62 | |
63 | #if (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION < 68 )) |
64 | /* Fetches the SV that keeps the per-interpreter data. */ |
65 | #define dMY_CXT_SV \ |
66 | SV *my_cxt_sv = get_sv(MY_CXT_KEY, FALSE) |
67 | #else /* >= perl5.004_68 */ |
68 | #define dMY_CXT_SV \ |
69 | SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY, \ |
70 | sizeof(MY_CXT_KEY)-1, TRUE) |
71 | #endif /* < perl5.004_68 */ |
72 | |
73 | /* This declaration should be used within all functions that use the |
74 | * interpreter-local data. */ |
75 | #define dMY_CXT \ |
76 | dMY_CXT_SV; \ |
77 | my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv)) |
78 | |
79 | /* Creates and zeroes the per-interpreter data. |
80 | * (We allocate my_cxtp in a Perl SV so that it will be released when |
81 | * the interpreter goes away.) */ |
82 | #define MY_CXT_INIT \ |
83 | dMY_CXT_SV; \ |
84 | /* newSV() allocates one more than needed */ \ |
85 | my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\ |
86 | Zero(my_cxtp, 1, my_cxt_t); \ |
87 | sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) |
88 | |
89 | /* This macro must be used to access members of the my_cxt_t structure. |
90 | * e.g. MYCXT.some_data */ |
91 | #define MY_CXT (*my_cxtp) |
92 | |
93 | /* Judicious use of these macros can reduce the number of times dMY_CXT |
94 | * is used. Use is similar to pTHX, aTHX etc. */ |
95 | #define pMY_CXT my_cxt_t *my_cxtp |
96 | #define pMY_CXT_ pMY_CXT, |
97 | #define _pMY_CXT ,pMY_CXT |
98 | #define aMY_CXT my_cxtp |
99 | #define aMY_CXT_ aMY_CXT, |
100 | #define _aMY_CXT ,aMY_CXT |
101 | |
102 | #else /* single interpreter */ |
103 | |
104 | #define START_MY_CXT static my_cxt_t my_cxt; |
105 | #define dMY_CXT_SV dNOOP |
106 | #define dMY_CXT dNOOP |
107 | #define MY_CXT_INIT NOOP |
108 | #define MY_CXT my_cxt |
109 | |
110 | #define pMY_CXT void |
111 | #define pMY_CXT_ |
112 | #define _pMY_CXT |
113 | #define aMY_CXT |
114 | #define aMY_CXT_ |
115 | #define _aMY_CXT |
116 | |
117 | #endif |
118 | |
119 | #endif /* START_MY_CXT */ |
120 | |
121 | =xsmisc |
122 | |
123 | #define MY_CXT_KEY "Devel::PPPort::_guts" XS_VERSION |
124 | |
125 | typedef struct { |
126 | /* Put Global Data in here */ |
127 | int dummy; |
128 | } my_cxt_t; |
129 | |
130 | START_MY_CXT |
131 | |
132 | =xsboot |
133 | |
134 | { |
135 | MY_CXT_INIT; |
136 | /* If any of the fields in the my_cxt_t struct need |
137 | * to be initialised, do it here. |
138 | */ |
139 | MY_CXT.dummy = 42; |
140 | } |
141 | |
142 | =xsubs |
143 | |
144 | int |
145 | MY_CXT_1() |
146 | CODE: |
147 | dMY_CXT; |
148 | RETVAL = MY_CXT.dummy == 42; |
149 | ++MY_CXT.dummy; |
150 | OUTPUT: |
151 | RETVAL |
152 | |
153 | int |
154 | MY_CXT_2() |
155 | CODE: |
156 | dMY_CXT; |
157 | RETVAL = MY_CXT.dummy == 43; |
158 | OUTPUT: |
159 | RETVAL |
160 | |
161 | =tests plan => 2 |
162 | |
163 | ok(&Devel::PPPort::MY_CXT_1()); |
164 | ok(&Devel::PPPort::MY_CXT_2()); |
165 | |