Commit | Line | Data |
---|---|---|
adfe19db MHM |
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 |