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