ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Guard/Guard.xs
Revision: 1.11
Committed: Sun Jul 19 04:59:54 2009 UTC (14 years, 10 months ago) by root
Branch: MAIN
CVS Tags: rel-1_021, rel-1_022
Changes since 1.10: +1 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #define PERL_NO_GET_CONTEXT
2
3 #include "EXTERN.h"
4 #include "perl.h"
5 #include "XSUB.h"
6
7 /* apparently < 5.8.8 */
8 #ifndef SvSTASH_set
9 # define SvSTASH_set(x,a) SvSTASH(x) = (a)
10 #endif
11
12 #ifndef PERL_MAGIC_ext
13 # define PERL_MAGIC_ext '~'
14 #endif
15
16 static HV *guard_stash;
17
18 static SV *
19 guard_get_cv (pTHX_ SV *cb_sv)
20 {
21 HV *st;
22 GV *gvp;
23 CV *cv = sv_2cv (cb_sv, &st, &gvp, 0);
24
25 if (!cv)
26 croak ("expected a CODE reference for guard");
27
28 return (SV *)cv;
29 }
30
31 static void
32 exec_guard_cb (pTHX_ SV *cb)
33 {
34 dSP;
35 SV *saveerr = SvOK (ERRSV) ? sv_mortalcopy (ERRSV) : 0;
36 SV *savedie = PL_diehook;
37
38 PL_diehook = 0;
39
40 PUSHSTACKi (PERLSI_DESTROY);
41
42 PUSHMARK (SP);
43 PUTBACK;
44 call_sv (cb, G_VOID | G_DISCARD | G_EVAL);
45
46 if (SvTRUE (ERRSV))
47 {
48 SPAGAIN;
49
50 PUSHMARK (SP);
51 PUTBACK;
52 call_sv (get_sv ("Guard::DIED", 1), G_VOID | G_DISCARD | G_EVAL | G_KEEPERR);
53
54 sv_setpvn (ERRSV, "", 0);
55 }
56
57 if (saveerr)
58 sv_setsv (ERRSV, saveerr);
59
60 {
61 SV *oldhook = PL_diehook;
62 PL_diehook = savedie;
63 SvREFCNT_dec (oldhook);
64 }
65
66 POPSTACK;
67 }
68
69 static void
70 scope_guard_cb (pTHX_ void *cv)
71 {
72 exec_guard_cb (aTHX_ sv_2mortal ((SV *)cv));
73 }
74
75 static int
76 guard_free (pTHX_ SV *cv, MAGIC *mg)
77 {
78 exec_guard_cb (aTHX_ mg->mg_obj);
79
80 return 0;
81 }
82
83 static MGVTBL guard_vtbl = {
84 0, 0, 0, 0,
85 guard_free
86 };
87
88 MODULE = Guard PACKAGE = Guard
89
90 BOOT:
91 guard_stash = gv_stashpv ("Guard", 1);
92 CvNODEBUG_on (get_cv ("Guard::scope_guard", 0)); /* otherwise calling scope can be the debugger */
93
94 void
95 scope_guard (SV *block)
96 PROTOTYPE: &
97 CODE:
98 LEAVE; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
99 SAVEDESTRUCTOR_X (scope_guard_cb, (void *)SvREFCNT_inc (guard_get_cv (aTHX_ block)));
100 ENTER; /* unfortunately, perl sandwiches XS calls into ENTER/LEAVE */
101
102 SV *
103 guard (SV *block)
104 PROTOTYPE: &
105 CODE:
106 {
107 SV *cv = guard_get_cv (aTHX_ block);
108 SV *guard = NEWSV (0, 0);
109 SvUPGRADE (guard, SVt_PVMG);
110 sv_magicext (guard, cv, PERL_MAGIC_ext, &guard_vtbl, 0, 0);
111 RETVAL = newRV_noinc (guard);
112 SvOBJECT_on (guard);
113 ++PL_sv_objcount;
114 SvSTASH_set (guard, (HV*)SvREFCNT_inc ((SV *)guard_stash));
115 }
116 OUTPUT:
117 RETVAL
118
119 void
120 cancel (SV *guard)
121 PROTOTYPE: $
122 CODE:
123 {
124 MAGIC *mg;
125 if (!SvROK (guard)
126 || !(mg = mg_find (SvRV (guard), PERL_MAGIC_ext))
127 || mg->mg_virtual != &guard_vtbl)
128 croak ("Guard::cancel called on a non-guard object");
129
130 SvREFCNT_dec (mg->mg_obj);
131 mg->mg_obj = 0;
132 mg->mg_virtual = 0;
133 }