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