~siborgium/prelockdpp

c2ca3b61004762499e0962ac27ea507639a2ac99 — Sergey Smirnykh 2 years ago 4750491
Implement set of mapped files
1 files changed, 66 insertions(+), 29 deletions(-)

M main.cpp
M main.cpp => main.cpp +66 -29
@@ 120,9 120,14 @@ struct base_fd {
struct signal_fd: public base_fd {
    static constexpr auto id = SourceId::Signal;
    signal_fd(auto... sigs) {
        auto check = [](auto && f, auto* err, auto&&... args) {
            if (f(std::forward<decltype(args)>(args)...) != 0) {
                throw errno_exception{ err, errno };
            }
        };
        sigset_t mask;
        sigemptyset(&mask);
        (sigaddset(&mask, sigs), ...);
        check(sigemptyset, "sigemptyset", &mask);
        (check(sigaddset, "sigaddset", &mask, sigs), ...);
        if (sigprocmask(SIG_SETMASK, &mask, NULL)) {
            throw errno_exception("Failed to set signal mask", errno);
        }


@@ 153,11 158,6 @@ struct timer_fd: public base_fd {

namespace intr = boost::intrusive;

struct mapping: intr::set_base_hook<intr::optimize_size<true>> {
    std::size_t refs;
    char* filename;
};

namespace tags {
    struct alive{};
    struct dead{};


@@ 234,6 234,41 @@ namespace std {
    };
}

// each `mapping` holds filename it points to
// `mapping` is to be allocated via `mapping::create`, see it's description
struct mapping: intr::set_base_hook<intr::optimize_size<true>> {
    std::size_t      refs;
    std::string_view filename;

    bool operator < (const mapping& m) const { return filename < m.filename; }
    bool operator == (const mapping& m) const { return filename == m.filename; }

    // allocates mapping and it's filename as contigious chunk of memory
    // so you can free both mapping and filename at once
    static mapping* create(std::string_view filename) {
        auto size = sizeof(mapping) + filename.size();
        auto* ptr = new (std::align_val_t{ alignof(mapping) }) char[size];

        auto* begin = ptr + sizeof(mapping);
        auto* end = begin + filename.size();
        assert(end - begin == filename.size());
        auto* end1 = std::copy(filename.begin(), filename.end(), begin);
        assert(end1 == end);

        auto* map = new (ptr) mapping{ .refs = 0, .filename = { begin, end } };
        assert((void*)map == (void*)ptr);
        return map;
    }
    static void operator delete (void *p) { return delete[] static_cast<char*>(p); }
};

struct mapping_sv_comp {
    constexpr bool operator ()(const mapping& m, std::string_view view) const { return m.filename < view; }
    constexpr bool operator ()(std::string_view view, const mapping& m) const { return view < m.filename; }
};

using mapping_set = intr::set<mapping, intr::compare<std::less<mapping>>>;

struct linebuf {
    char*  ptr{ nullptr };
    size_t capacity{ 0 };


@@ 289,6 324,7 @@ struct context {
    // storage for ids
    plf::colony<uniq_id> ids;
    uniq_alive_set       current_uniqs_set;
    mapping_set          mappings;

    // FIXME: I could use Boost.Intrusive & build something decent
    //        instead of endless maps & sets


@@ 386,7 422,7 @@ struct context {
            }

            std::string_view stat_view( stat_buffer.ptr, stat_len );
            if (stat_view.ends_with(" 0 0 0")) {
            if (stat_view.ends_with(" 0 0 0"sv)) {
                // ignore kthreads
                return;
            }


@@ 458,7 494,7 @@ struct context {
            }
        }
    }
    auto add_mappings(auto & vec) {
    auto add_mappings(mapping_set& set) {
        try {
            fmt_proc_pid_file(maps_path);
            auto file = fopen(path_buf, "r");


@@ 467,9 503,15 @@ struct context {
            }
            ssize_t n = 0;
            while ((n = line_buffer.getline(file)) != -1) {
                auto begin = std::find(line_buffer.ptr, line_buffer.ptr + n, '/');
                if (begin != line_buffer.ptr + n) {
                    vec.emplace_back(begin, line_buffer.ptr + n - begin);
                auto end = line_buffer.ptr + n;
                if (auto begin = std::find(line_buffer.ptr, end, '/'); begin != end) {
                    std::string_view path{ begin, end };

                    mapping_set::insert_commit_data commit_data;
                    auto [_, can_insert] = set.insert_check( path, mapping_sv_comp{}, commit_data);
                    if (can_insert) {
                        set.insert_commit(*mapping::create(path), commit_data);
                    }
                }
            }
        } catch (const errno_exception& e) {


@@ 489,6 531,7 @@ struct context {
        //       when inserting to `current_uniqs_set`, just = move(new_ids)
        //       plus any_hooks are pain
        uniq_alive_set new_ids;
        mapping_set    uniq_mappings;

        auto m0 = get_clock_time(CLOCK_MONOTONIC);
        auto p0 = get_clock_time(CLOCK_PROCESS_CPUTIME_ID);


@@ 507,7 550,8 @@ struct context {
            if (entry->d_type != DT_DIR) {
                continue;
            }
            auto name_end = entry->d_name + strlen(entry->d_name);
            auto const name_end = entry->d_name + strlen(entry->d_name);
            // try to parse pid
            int pid;
            auto [p, ec] = std::from_chars(entry->d_name, name_end, pid);
            if (ec != std::errc() || p != name_end || pid == self_pid) {


@@ 519,7 563,7 @@ struct context {

            with_uniq_id(path_buf, [&](auto start_time) {
                {
                    // if uniq_id is already exists
                    // if uniq_id already exists
                    // (e.g. process was alive on the prev iteration)
                    // we migrate it to the `current_ids` set
                    // NOTE: we create `source` & use it to lookup the set


@@ 542,13 586,7 @@ struct context {
                    }
                }



#if 0
                if (!uniq_mappings.contains(*iter)) {
                    add_mappings(uniq_mappings[*iter]);
                }
#endif
                add_mappings(uniq_mappings);
            });
        }
        if (errno) {


@@ 568,16 606,14 @@ struct context {
        }

        for (auto && id: current_uniqs_set) {
            fmt::print("{}.{} {}\n", id.start_time.tv_sec, id.start_time.tv_nsec, id.pid);
            auto lifetime = tspec_diff(id.start_time, uptime);
            fmt::print("{}.{} {} ({}.{})\n", id.start_time.tv_sec, id.start_time.tv_nsec, id.pid, lifetime.tv_sec, lifetime.tv_nsec);
        }

#if 0
        for (auto && [k, v]: uniq_mappings) {
            for (auto && m: v) {
                std::cout << m << '\n';
            }
        for (auto && k: uniq_mappings) {
            fmt::print("Mapped file: {}\n", k.filename);
        }
#endif

        auto m = tspec_diff(m0, get_clock_time(CLOCK_MONOTONIC));
        auto p = tspec_diff(p0, get_clock_time(CLOCK_PROCESS_CPUTIME_ID));



@@ 623,7 659,8 @@ struct lock_context {
    timer_fd  timer;

    lock_context(context& ctx): ctx{ ctx }, sigs{ SIGINT, SIGHUP, SIGTERM, SIGQUIT } {
        epoll_fd = epoll_create(0xABCDEF);
        constexpr int arbitrary_number = 0xABCDEF;
        epoll_fd = epoll_create(arbitrary_number);
        if (epoll_fd < 0) {
            throw errno_exception("Failed to create epoll fd", errno);
        }