@@ 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);
}