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