The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"

#ifndef USE_ITHREADS
int count_down;
int inside_logger;
int log_size;
#endif

void
take_snapshot(pTHX)
{
    dSP;

    ENTER;
    SAVETMPS;

    PUSHMARK(SP);

    call_pv("Devel::ContinuousProfiler::take_snapshot",G_DISCARD|G_NOARGS);

    FREETMPS;
    LEAVE;
}


int
sp_runops(pTHX)
{
    dVAR;
#ifdef USE_ITHREADS
    SV * count_down_sv, *inside_logger_sv, *log_size_sv;
    register OP *op = PL_op;
    while ((PL_op = op = CALL_FPTR(op->op_ppaddr)(aTHX))) {
        count_down_sv = get_sv("Devel::ContinuousProfiler::count_down", 0);
        assert(count_down_sv);
        assert(SvIV(count_down_sv) >= 0);

        if (SvTRUE(count_down_sv)) {
            sv_dec(count_down_sv);
        }
        else {
            inside_logger_sv = get_sv("Devel::ContinuousProfiler::inside_logger", 0);
            assert(inside_logger_sv);
            assert(SvIV(inside_logger_sv) == 1
                || SvIV(inside_logger_sv) == 0);

            log_size_sv = get_sv("Devel::ContinuousProfiler::log_size", GV_ADD);
            assert(log_size_sv);

            if (SvTRUE(inside_logger_sv)) {
                sv_inc(log_size_sv);
            }
            else {
                sv_setiv(inside_logger_sv, 1);
                sv_setiv(log_size_sv, 0);
                take_snapshot(aTHX);
                sv_setiv(
                    count_down_sv,
                    SvIV(log_size_sv) > 1024
                        ? (SvIV(log_size_sv) << 10)
                        : (1024 << 10));
                sv_setiv(inside_logger_sv, 0);
            }
        }
    }
#else
    register OP *op = PL_op;
    while ((PL_op = op = CALL_FPTR(op->op_ppaddr)(aTHX))) {
        if ( count_down > 0 ) {
            -- count_down;
        }
        else {
            if ( inside_logger ) {
                ++ log_size;
            }
            else {
                inside_logger = 1;
                log_size = 0;
                take_snapshot(aTHX);
                count_down =
                    log_size > 1024
                        ? (log_size << 10)
                        : (1024 << 10);
                inside_logger = 0;
            }
        }
    }
#endif

    TAINT_NOT;
    return 0;
}

void
_initialize()
{
#ifdef USE_ITHREADS
    sv_setiv(get_sv("Devel::ContinuousProfiler::count_down", GV_ADD), 0);
    sv_setiv(get_sv("Devel::ContinuousProfiler::inside_logger", GV_ADD), 0);
    sv_setiv(get_sv("Devel::ContinuousProfiler::log_size", GV_ADD), 1024 < 10);
#endif
    PL_runops = sp_runops;
}

MODULE = Devel::ContinuousProfiler PACKAGE = Devel::ContinuousProfiler

PROTOTYPES: DISABLE

void
_initialize()

BOOT:
    _initialize();