From e7bfa6cb1bb043d6ea66e03b32981e26965d2da3 Mon Sep 17 00:00:00 2001
From: Glauber Costa <glommer@cloudius-systems.com>
Date: Thu, 24 Apr 2014 11:32:28 +0400
Subject: [PATCH] linux: provide a /proc/$$/stat compatibility file

MongoDB wants it. In general, I am providing the information that is easy
to get, and ignoring the ones which are not - with the exception of process
count, that seemed easy enough to implement.

This is the kind of thing Mongo does with it:

2014-04-15T09:54:12.322+0000 [clientcursormon] mem (MB) res:670160 virt:25212
2014-04-15T09:54:12.323+0000 [clientcursormon]  mapped (incl journal view):160
2014-04-15T09:54:12.324+0000 [clientcursormon]  connections:0

Signed-off-by: Glauber Costa <glommer@cloudius-systems.com>
Signed-off-by: Pekka Enberg <penberg@cloudius-systems.com>
---
 core/sched.cc             |  6 ++++
 fs/procfs/procfs_vnops.cc | 73 +++++++++++++++++++++++++++++++++++++++
 include/osv/sched.hh      |  2 ++
 3 files changed, 81 insertions(+)

diff --git a/core/sched.cc b/core/sched.cc
index 7bf9e0555..a8b7aa034 100644
--- a/core/sched.cc
+++ b/core/sched.cc
@@ -568,6 +568,12 @@ std::chrono::nanoseconds osv_run_stats()
     return std::chrono::duration_cast<std::chrono::nanoseconds>(total_app_time);
 }
 
+int thread::numthreads()
+{
+    SCOPE_LOCK(thread_map_mutex);
+    return thread_map.size();
+}
+
 // We reserve a space in the end of the PID space, so we can reuse those
 // special purpose ids for other things. 4096 positions is arbitrary, but
 // <<should be enough for anybody>> (tm)
diff --git a/fs/procfs/procfs_vnops.cc b/fs/procfs/procfs_vnops.cc
index 77839072d..7fed5d09c 100644
--- a/fs/procfs/procfs_vnops.cc
+++ b/fs/procfs/procfs_vnops.cc
@@ -17,6 +17,12 @@
 #include <map>
 #include "fs/vfs/vfs.h"
 
+#include <libgen.h>
+#include <osv/mempool.hh>
+#include <osv/printf.hh>
+
+#include <sys/resource.h>
+
 namespace procfs {
 
 using namespace std;
@@ -255,6 +261,71 @@ procfs_readdir(vnode *vp, file *fp, dirent *dir)
     return 0;
 }
 
+static std::string procfs_stats()
+{
+    int pid = 0, ppid = 0, pgrp = 0, session = 0, tty = 0, tpgid = -1,
+        flags = 0;
+    // Postpone this one. We need to hook into ZFS statistics to properly figure
+    // out which faults are maj, which are min.
+    int min_flt = 0, cmin_flt = 0, maj_flt = 0, cmaj_flt = 0;
+    unsigned long stime = 0, cutime = 0, cstime = 0;
+
+    using namespace std::chrono;
+    unsigned long utime = duration_cast<microseconds>(sched::osv_run_stats()).count();
+    char state = 'R';
+    int priority = getpriority(PRIO_PROCESS, 0);
+    int nice = priority;
+    int nlwp = sched::thread::numthreads();
+    int start_time = 0; // boot is reference, so it is 0.
+    unsigned long rss = memory::stats::total() - memory::stats::free();
+    unsigned long vsize = mmu::all_vmas_size();
+    unsigned long rss_rlim = memory::stats::total();
+    void *start_code = nullptr;
+    void *end_code = nullptr;
+    void *start_stack = nullptr;
+    void *kstk_esp = nullptr;
+    void *kstk_eip = nullptr;
+
+    // All the signal stuff is marked in the manpage as obsolete.
+    unsigned long pending = 0;
+    unsigned long blocked = 0;
+    unsigned long sigign = 0;
+    unsigned long sigcatch = 0;
+    unsigned long nextalarm = 0;
+    // Except for this. This is maintained, but we also don't deliver any signal
+    unsigned long exit_signal = 0;
+    int cpu = sched::cpu::current()->id;
+    int wchan = 0, rt_priority = 0, policy = 0; // SCHED_OTHER = 0
+    int zero = 0;
+
+    std::ostringstream os;
+    osv::fprintf(os, "%d (%s) %c "
+                     "%d %d %d %d %d "
+                     "%lu %lu %lu %lu %lu "
+                     "%lu %lu %ld %ld "
+                     "%ld %ld %ld %ld "
+                     "%lu %lu "
+                     "%lu %lu "
+                     "%p %p %p %p %p "
+                     "%lu %lx %lu %lu "
+                     "%d %d %d "
+                     "%lu %d %d %d",
+                     pid, program_invocation_short_name, state,
+                     ppid, pgrp, session, tty, tpgid,
+                     flags, min_flt, cmin_flt, maj_flt, cmaj_flt,
+                     utime, stime, cutime, cstime,
+                     priority, nice, nlwp, nextalarm,
+                     start_time, vsize,
+                     rss, rss_rlim,
+                     start_code, end_code, start_stack, kstk_esp, kstk_eip,
+                     pending, blocked, sigign, sigcatch,
+                     wchan, zero, zero,
+                     exit_signal, cpu, rt_priority, policy
+                );
+    return os.str();
+
+}
+
 static int
 procfs_mount(mount* mp, char *dev, int flags, void* data)
 {
@@ -262,9 +333,11 @@ procfs_mount(mount* mp, char *dev, int flags, void* data)
 
     auto self = make_shared<proc_dir_node>(inode_count++);
     self->add("maps", inode_count++, mmu::procfs_maps);
+    self->add("stat", inode_count++, procfs_stats);
 
     auto* root = new proc_dir_node(vp->v_ino);
     root->add("self", self);
+    root->add("0", self); // our standard pid
 
     vp->v_data = static_cast<void*>(root);
 
diff --git a/include/osv/sched.hh b/include/osv/sched.hh
index becd9639d..befa5d0e1 100644
--- a/include/osv/sched.hh
+++ b/include/osv/sched.hh
@@ -572,6 +572,8 @@ public:
     lockless_queue_link<thread> _wakeup_link;
     static unsigned long _s_idgen;
     static thread *find_by_id(unsigned int id);
+
+    static int numthreads();
 private:
     class reaper;
     friend class reaper;
-- 
GitLab