+STATIC U32 rep_initialized = 0;
+
+STATIC void rep_teardown(pTHX_ void *root) {
+ if (!rep_initialized || aTHX != root)
+ return;
+
+ {
+ dMY_CXT;
+ ptable_free(MY_CXT.tbl);
+ }
+
+ rep_initialized = 0;
+}
+
+STATIC void rep_setup(pTHX) {
+#define rep_setup() rep_setup(aTHX)
+ if (rep_initialized)
+ return;
+
+ {
+ MY_CXT_INIT;
+ MY_CXT.tbl = ptable_new();
+ MY_CXT.owner = aTHX;
+ }
+
+ call_atexit(rep_teardown, aTHX);
+
+ rep_initialized = 1;
+}
+
+#else /* REP_THREADSAFE */
+
+#define rep_setup()
+
+#endif /* !REP_THREADSAFE */
+
+STATIC U32 rep_booted = 0;
+
+/* --- XS ------------------------------------------------------------------ */
+
+MODULE = re::engine::Plugin PACKAGE = re::engine::Plugin
+
+PROTOTYPES: DISABLE
+
+BOOT:
+{
+ if (!rep_booted++) {
+ HV *stash;
+
+ PERL_HASH(rep_hash, __PACKAGE__, __PACKAGE_LEN__);
+
+ stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1);
+ newCONSTSUB(stash, "REP_THREADSAFE", newSVuv(REP_THREADSAFE));
+ newCONSTSUB(stash, "REP_FORKSAFE", newSVuv(REP_FORKSAFE));
+ }
+
+ rep_setup();
+}
+
+#if REP_THREADSAFE
+
+void
+CLONE(...)
+PREINIT:
+ ptable *t;
+ GV *gv;
+PPCODE:
+ {
+ rep_ptable_clone_ud ud;
+ dMY_CXT;
+
+ t = ptable_new();
+ rep_ptable_clone_ud_init(ud, t, MY_CXT.owner);
+ ptable_walk(MY_CXT.tbl, rep_ptable_clone, &ud);
+ rep_ptable_clone_ud_deinit(ud);
+ }
+ {
+ MY_CXT_CLONE;
+ MY_CXT.tbl = t;
+ MY_CXT.owner = aTHX;
+ }
+ gv = gv_fetchpv(__PACKAGE__ "::_THREAD_CLEANUP", 0, SVt_PVCV);
+ if (gv) {
+ CV *cv = GvCV(gv);
+ if (!PL_endav)
+ PL_endav = newAV();
+ SvREFCNT_inc(cv);
+ if (!av_store(PL_endav, av_len(PL_endav) + 1, (SV *) cv))
+ SvREFCNT_dec(cv);
+ sv_magicext((SV *) PL_endav, NULL, PERL_MAGIC_ext, &rep_endav_vtbl, NULL, 0);
+ }
+ XSRETURN(0);
+
+void
+_THREAD_CLEANUP(...)
+PROTOTYPE: DISABLE
+PPCODE:
+ rep_thread_cleanup(aTHX_ NULL);
+ XSRETURN(0);
+
+#endif /* REP_THREADSAFE */
+
+void