The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxcfs/pull/235

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
This patch provides an interface for loadavg and consists of the load daemon, the hash table, and an interface of reading loadavg. Container can get its real loadavg by using it.

Hash table stores average load information for all containers. 

The load daemon finds the container’s process pid through cgroup file, then gets all threads’ status by reading proc system. Finally it calculates the average load per container and refreshes them just as the Linux kernel did. See:
https://github.com/torvalds/linux/blob/master/kernel/sched/loadavg.c
(calculate the average load function)

Applications in the container can get the container’s real loadavg by using the interface. It should be noted that container must read the interface once when it is created in order to create and store the hash node of this container.

Signed-off-by: zhang2639 <[email protected]>
Signed-off-by: yuwang <[email protected]>
From ba5ab95335f6d0c7df843b57dbc88089765bed97 Mon Sep 17 00:00:00 2001
From: zhang2639 <[email protected]>
Date: Wed, 18 Apr 2018 19:22:40 +0800
Subject: [PATCH 1/5] Necessary Instructions For Loadavg

Signed-off-by: zhang2639 <[email protected]>
Signed-off-by: yuwang <[email protected]>
---
 bindings.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/bindings.c b/bindings.c
index 9657160..7e82fb9 100644
--- a/bindings.c
+++ b/bindings.c
@@ -66,6 +66,7 @@ enum {
        LXC_TYPE_PROC_STAT,
        LXC_TYPE_PROC_DISKSTATS,
        LXC_TYPE_PROC_SWAPS,
+       LXC_TYPE_PROC_LOADAVG,
 };
 
 struct file_info {
@@ -4128,7 +4129,8 @@ int proc_getattr(const char *path, struct stat *sb)
                        strcmp(path, "/proc/uptime") == 0 ||
                        strcmp(path, "/proc/stat") == 0 ||
                        strcmp(path, "/proc/diskstats") == 0 ||
-                       strcmp(path, "/proc/swaps") == 0) {
+                       strcmp(path, "/proc/swaps") == 0 ||
+                       strcmp(path, "/proc/loadavg") == 0) {
                sb->st_size = 0;
                sb->st_mode = S_IFREG | 00444;
                sb->st_nlink = 1;
@@ -4148,7 +4150,8 @@ int proc_readdir(const char *path, void *buf, 
fuse_fill_dir_t filler, off_t offs
            filler(buf, "stat", NULL, 0) != 0 ||
            filler(buf, "uptime", NULL, 0) != 0 ||
            filler(buf, "diskstats", NULL, 0) != 0 ||
-           filler(buf, "swaps", NULL, 0) != 0)
+           filler(buf, "swaps", NULL, 0) != 0   ||
+           filler(buf, "loadavg", NULL, 0) != 0)
                return -EINVAL;
        return 0;
 }
@@ -4170,6 +4173,8 @@ int proc_open(const char *path, struct fuse_file_info *fi)
                type = LXC_TYPE_PROC_DISKSTATS;
        else if (strcmp(path, "/proc/swaps") == 0)
                type = LXC_TYPE_PROC_SWAPS;
+       else if (strcmp(path, "/proc/loadavg") == 0)
+               type = LXC_TYPE_PROC_LOADAVG;
        if (type == -1)
                return -ENOENT;
 
@@ -4227,6 +4232,8 @@ int proc_read(const char *path, char *buf, size_t size, 
off_t offset,
                return proc_diskstats_read(buf, size, offset, fi);
        case LXC_TYPE_PROC_SWAPS:
                return proc_swaps_read(buf, size, offset, fi);
+       case LXC_TYPE_PROC_LOADAVG:
+               return proc_loadavg_read(buf, size, offset, fi);
        default:
                return -EINVAL;
        }

From 0b7b8f89ab8f077cdb80b41bb9af391124e4e832 Mon Sep 17 00:00:00 2001
From: zhang2639 <[email protected]>
Date: Wed, 18 Apr 2018 19:28:54 +0800
Subject: [PATCH 2/5] Use hash table to store load information

struct load_head{} contains three locks for thread synchronization
and a pointer to the hash list.
struct load_node{} contains special information of container and
pointers to the hash node.
static struct load_head *load_hash[LOAD_SIZE] is hash table.
calc_hash : get the hash of a special container.
init_load : initialize hash table.
insert_node : insert a container node to the hash table.
locate_node : find the specital container node.
del_node : delete a specital container node and return the next node
of it.

Signed-off-by: zhang2639 <[email protected]>
Signed-off-by: yuwang <[email protected]>
---
 bindings.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/bindings.c b/bindings.c
index 7e82fb9..68f9490 100644
--- a/bindings.c
+++ b/bindings.c
@@ -80,6 +80,125 @@ struct file_info {
        int cached;
 };
 
+/* The function of hash table.*/
+#define LOAD_SIZE 100 /*the size of hash_table */
+static int calc_hash(char *name)
+{
+       unsigned int hash = 0;
+       unsigned int x = 0;
+       /* ELFHash algorithm. */
+       while (*name) {
+               hash = (hash << 4) + *name++;
+               x = hash & 0xf0000000;
+               if (x != 0) {
+                       hash ^= (x >> 24);
+                       hash &= ~x;
+               }
+       }
+       return ((hash & 0x7fffffff) % LOAD_SIZE);
+}
+
+struct load_node {
+       char *cg;  /*cg */
+       unsigned long avenrun[3];               /* Load averages */
+       unsigned int run_pid;
+       unsigned int total_pid;
+       unsigned int last_pid;
+       int cfd; /* The file descriptor of the mounted cgroup */
+       struct  load_node *next;
+       struct  load_node **pre;
+};
+
+struct load_head {
+       /* The lock is about insert load_node and refresh load_node.To the 
first load_node of each hash bucket, insert and
+       refresh in this hash bucket is mutually exclusive. */
+       pthread_mutex_t lock;
+       /* The rdlock is about read loadavg and delete load_node.To each hash 
bucket, read and delete is
+       mutually exclusive. But at the same time, we allow paratactic read 
operation. This rdlock is at list level.*/
+       pthread_rwlock_t rdlock;
+       /* The rilock is about read loadavg and insert load_node.To the first 
load_node of each hash bucket, read and insert is
+       mutually exclusive. But at the same time, we allow paratactic read 
operation.*/
+       pthread_rwlock_t rilock;
+       struct load_node *next;
+};
+
+static struct load_head *load_hash[LOAD_SIZE]; /* hash table */
+
+static void init_load(void)
+{
+       int i;
+
+       for (i = 0; i < LOAD_SIZE; i++) {
+               load_hash[i] = (struct load_head *)malloc(sizeof(struct 
load_head));
+               load_hash[i]->next = NULL;
+               if (pthread_mutex_init(&load_hash[i]->lock, NULL) != 0)
+                       goto out3;
+               if (pthread_rwlock_init(&load_hash[i]->rdlock, NULL) != 0)
+                       goto out2;
+               if (pthread_rwlock_init(&load_hash[i]->rilock, NULL) != 0)
+                       goto out1;
+       }
+       return;
+out1:
+       pthread_rwlock_destroy(&load_hash[i]->rdlock);
+out2:
+       pthread_mutex_destroy(&load_hash[i]->lock);
+out3:
+       free(load_hash[i]);
+       lxcfs_error("%s\n", "lock init error");
+       exit(1);
+}
+
+static void insert_node(struct load_node **n, int locate)
+{
+       pthread_mutex_lock(&load_hash[locate]->lock);
+       pthread_rwlock_wrlock(&load_hash[locate]->rilock);
+       struct load_node *f = load_hash[locate]->next;
+       load_hash[locate]->next = *n;
+
+       (*n)->pre = &(load_hash[locate]->next);
+       if (f)
+               f->pre = &((*n)->next);
+       (*n)->next = f;
+       pthread_mutex_unlock(&load_hash[locate]->lock);
+       pthread_rwlock_unlock(&load_hash[locate]->rilock);
+}
+/* Find spectial node. Not return NULL means success. */
+static struct load_node *locate_node(char *cg, int locate)
+{
+       struct load_node *f = NULL;
+       int i = 0;
+
+       pthread_rwlock_rdlock(&load_hash[locate]->rilock);
+       pthread_rwlock_rdlock(&load_hash[locate]->rdlock);
+       if (load_hash[locate]->next == NULL) {
+               pthread_rwlock_unlock(&load_hash[locate]->rilock);
+               return f;
+       }
+       f = load_hash[locate]->next;
+       pthread_rwlock_unlock(&load_hash[locate]->rilock);
+       while (f && ((i = strcmp(f->cg, cg)) != 0))
+               f = f->next;
+       return f;
+}
+/* Delete the load_node n and return the next node of it. */
+static struct load_node *del_node(struct load_node *n, int locate)
+{
+       struct load_node *g;
+
+       pthread_rwlock_wrlock(&load_hash[locate]->rdlock);
+       if (n->next == NULL) {
+               *(n->pre) = NULL;
+       } else {
+               *(n->pre) = n->next;
+               n->next->pre = n->pre;
+       }
+       g = n->next;
+       free(n->cg);
+       free(n);
+       pthread_rwlock_unlock(&load_hash[locate]->rdlock);
+       return g;
+}
 /* Reserve buffer size to account for file size changes. */
 #define BUF_RESERVE_SIZE 512
 

From fb804460323c2018736aac349ed5f499981c0ec5 Mon Sep 17 00:00:00 2001
From: zhang2639 <[email protected]>
Date: Wed, 18 Apr 2018 19:55:45 +0800
Subject: [PATCH 3/5] Use load daemon to calculate the average load.

calc_pid : find the process pid from cgroup path of a container.
calc_load : calculate the loadavg of a container.
refresh_load : refresh the loadavg of a container.
load_begin : traverse the hash table and update it.
load_daemon : create the thread of load_begin.

Signed-off-by: zhang2639 <[email protected]>
Signed-off-by: yuwang <[email protected]>
---
 bindings.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bindings.h |   1 +
 lxcfs.c    |  13 ++++
 3 files changed, 228 insertions(+)

diff --git a/bindings.c b/bindings.c
index 68f9490..3041ab0 100644
--- a/bindings.c
+++ b/bindings.c
@@ -82,6 +82,14 @@ struct file_info {
 
 /* The function of hash table.*/
 #define LOAD_SIZE 100 /*the size of hash_table */
+#define FLUSH_TIME 5  /*the flush rate */
+#define DEPTH_DIR 3   /*the depth of per cgroup */
+/* The function of calculate loadavg .*/
+#define FSHIFT         11              /* nr of bits of precision */
+#define FIXED_1                (1<<FSHIFT)     /* 1.0 as fixed-point */
+#define EXP_1          1884            /* 1/exp(5sec/1min) as fixed-point */
+#define EXP_5          2014            /* 1/exp(5sec/5min) */
+#define EXP_15         2037            /* 1/exp(5sec/15min) */
 static int calc_hash(char *name)
 {
        unsigned int hash = 0;
@@ -4212,6 +4220,212 @@ static int proc_swaps_read(char *buf, size_t size, 
off_t offset,
        return rv;
 }
 
+/*
+ * Find the process pid from cgroup path.
+ * eg:from /sys/fs/cgroup/cpu/docker/containerid/cgroup.procs to find the 
process pid.
+ * pid_buf : put pid to pid_buf.
+ * dpath : the path of cgroup. eg: /docker/containerid or 
/docker/containerid/child-cgroup ...
+ * depth : the depth of cgroup in container.
+ * sum : return the number of pid .
+ * cfd : the file descriptor of the mounted cgroup. eg: /sys/fs/cgroup/cpu
+ */
+static int calc_pid(char ***pid_buf, char *dpath, int depth, int sum, int cfd)
+{
+       DIR *dir;
+       int fd;
+       struct dirent *file;
+       /* path = dpath + "/cgroup.procs" + /0 */
+       char *path = (char *)malloc(strlen(dpath) + 20);
+
+       strcpy(path, dpath);
+       fd = openat(cfd, path, O_RDONLY);
+       if (fd < 0)
+               return sum;
+
+       if ((dir = fdopendir(fd)) == NULL) {
+               return sum;
+       } else {
+               while (((file = readdir(dir)) != NULL) && depth > 0) {
+                       if (strncmp(file->d_name, ".", 1) == 0)
+                               continue;
+                       else
+                               if (file->d_type == DT_DIR) {
+                                       /* path + '/' + d_name +/0 */
+                                       char *path_dir = (char 
*)malloc(strlen(path) + 2 + sizeof(file->d_name));
+                                       strcpy(path_dir, path);
+                                       strcat(path_dir, "/");
+                                       strcat(path_dir, file->d_name);
+                                       int pd = depth - 1;
+                                       sum = calc_pid(pid_buf, path_dir, pd, 
sum, cfd);
+                                       free(path_dir);
+                               }
+               }
+               closedir(dir);
+       }
+
+       close(fd);
+       /* realloc() failed */
+       if (sum == -1) {
+               free(path);
+               return -1;
+       }
+       strcat(path, "/cgroup.procs");
+       FILE *f = NULL;
+       size_t linelen = 0;
+       char *line = NULL;
+
+       fd = openat(cfd, path, O_RDONLY);
+       if (fd < 0)
+               return sum;
+
+       if (!(f = fdopen(fd, "r")))
+               return sum;
+
+       while (getline(&line, &linelen, f) != -1) {
+               char **pid;
+               pid = (char **)realloc(*pid_buf, sizeof(char *) * (sum + 1));
+               if (pid == NULL) {
+                       lxcfs_error("%s\n", "realloc error!");
+                       for (; sum > 0; sum--)
+                               free((*pid_buf)[sum - 1]);
+                       return -1;
+               }
+               *pid_buf = pid;
+               *(*pid_buf + sum) = (char *)malloc(strlen(line) + 3);
+               strcpy(*(*pid_buf + sum), line);
+               sum++;
+       }
+       fclose(f);
+       free(path);
+       return sum;
+}
+/*
+ * a1 = a0 * e + a * (1 - e)
+ */
+static unsigned long
+calc_load(unsigned long load, unsigned long exp, unsigned long active)
+{
+       unsigned long newload;
+       active = active > 0 ? active * FIXED_1 : 0;
+       newload = load * exp + active * (FIXED_1 - exp);
+       if (active >= load)
+               newload += FIXED_1 - 1;
+
+       return newload / FIXED_1;
+}
+
+static int refresh_load(struct load_node *p, char *path)
+{
+       FILE *f = NULL;
+       char **idbuf;
+       char proc_path[50];
+       int i, run_pid = 0, total_pid = 0, last_pid = 0;
+       char *line = NULL;
+       size_t linelen = 0;
+       idbuf = (char **)malloc(sizeof(char *));
+       int sum = calc_pid(&idbuf, path, DEPTH_DIR, 0, p->cfd);
+       DIR *dp;
+       struct dirent *file;
+
+       /*  normal exit or abnormal exit*/
+       if (sum == 0 || sum == -1) {
+               free(idbuf);
+               return 0;
+       }
+       for (i = 0; i < sum; i++) {
+               idbuf[i][strlen(idbuf[i])-1] = '\0';
+               sprintf(proc_path, "/proc/%s/task", idbuf[i]);
+               if (!(dp = opendir(proc_path))) {
+                       lxcfs_error("%s\n", "calc error when opendir.");
+                       continue;
+               } else
+                       while ((file = readdir(dp)) != NULL) {
+                               if (strncmp(file->d_name, ".", 1) == 0)
+                                       continue;
+                               total_pid++;
+                               /* We make the biggest pid become last_pid.*/
+                               last_pid = (atof(file->d_name) > last_pid) ? 
atof(file->d_name) : last_pid;
+                               sprintf(proc_path, "/proc/%s/task/%s/status", 
idbuf[i], file->d_name);
+                               if ((f = fopen(proc_path, "r")) != NULL) {
+                                       while (getline(&line, &linelen, f) != 
-1) {
+                                               /* find State */
+                                               if ((line[0] == 'S') && 
(line[1] == 't'))
+                                                       break;
+                                       }
+                               if ((line[7] == 'R') || (line[7] == 'D'))
+                                       run_pid++;
+                               fclose(f);
+                               }
+                       }
+               closedir(dp);
+       }
+       /*Calculate the loadavg.*/
+       p->avenrun[0] = calc_load(p->avenrun[0], EXP_1, run_pid);
+       p->avenrun[1] = calc_load(p->avenrun[1], EXP_5, run_pid);
+       p->avenrun[2] = calc_load(p->avenrun[2], EXP_15, run_pid);
+       p->run_pid = run_pid;
+       p->total_pid = total_pid;
+       p->last_pid = last_pid;
+
+       for (; i > 0; i--)
+               free(idbuf[i-1]);
+       free(idbuf);
+       free(line);
+       return sum;
+}
+/*
+ * Traverse the hash table and update it.
+ */
+void *load_begin(void *arg)
+{
+
+       char *path = NULL;
+       int i, sum;
+       struct load_node *f;
+       int first_node;
+       while (1) {
+               clock_t time1 = clock();
+               for (i = 0; i < LOAD_SIZE; i++) {
+                       pthread_mutex_lock(&load_hash[i]->lock);
+                       if (load_hash[i]->next == NULL) {
+                               pthread_mutex_unlock(&load_hash[i]->lock);
+                               continue;
+                       }
+                       f = load_hash[i]->next;
+                       first_node = 1;
+                       while (f) {
+                               path = (char *)malloc(strlen(f->cg) + 2);
+                               sprintf(path, "%s%s", *(f->cg) == '/' ? "." : 
"", f->cg);
+                               sum = refresh_load(f, path);
+                               if (sum == 0)
+                                       f = del_node(f, i);
+                               else
+                                       f = f->next;
+                               free(path);
+                               if (first_node == 1) {
+                                       first_node = 0;
+                                       
pthread_mutex_unlock(&load_hash[i]->lock);
+                               }
+                       }
+               }
+               clock_t time2 = clock();
+               usleep(FLUSH_TIME * 1000000 - (int)((time2 - time1) * 1000000 / 
CLOCKS_PER_SEC));
+       }
+}
+
+pthread_t load_daemon(void)
+{
+       init_load();
+       int ret;
+       pthread_t pid;
+       ret = pthread_create(&pid, NULL, load_begin, NULL);
+       if (ret != 0) {
+               lxcfs_error("%s\n", "Create pthread error!\n");
+               exit(1);
+       }
+       return pid;
+}
+
 static off_t get_procfile_size(const char *which)
 {
        FILE *f = fopen(which, "r");
diff --git a/bindings.h b/bindings.h
index c663287..b66fa2d 100644
--- a/bindings.h
+++ b/bindings.h
@@ -32,5 +32,6 @@ extern int proc_open(const char *path, struct fuse_file_info 
*fi);
 extern int proc_read(const char *path, char *buf, size_t size, off_t offset,
                struct fuse_file_info *fi);
 extern int proc_access(const char *path, int mask);
+extern pthread_t load_daemon(void);
 
 #endif /* __LXCFS_BINDINGS_H */
diff --git a/lxcfs.c b/lxcfs.c
index 62cfd35..61698a2 100644
--- a/lxcfs.c
+++ b/lxcfs.c
@@ -848,6 +848,8 @@ int main(int argc, char *argv[])
        char *pidfile = NULL, *v = NULL;
        size_t pidfile_len;
        bool debug = false;
+       pthread_t pid;
+       char *error;
        /*
         * what we pass to fuse_main is:
         * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
@@ -902,6 +904,17 @@ int main(int argc, char *argv[])
        if ((pidfd = set_pidfile(pidfile)) < 0)
                goto out;
 
+       dlerror();    /* Clear any existing error */
+       pthread_t (*load_daemon)(void);
+
+       load_daemon = (pthread_t (*)(void)) dlsym(dlopen_handle, "load_daemon");
+       error = dlerror();
+       if (error != NULL) {
+               lxcfs_error("%s\n", error);
+               return -1;
+       }
+       pid = load_daemon();
+
        if (!fuse_main(nargs, newargv, &lxcfs_ops, NULL))
                ret = EXIT_SUCCESS;
 

From 264548c6f952b364970bc9d7d6795aaf98ad0579 Mon Sep 17 00:00:00 2001
From: zhang2639 <[email protected]>
Date: Wed, 18 Apr 2018 20:00:45 +0800
Subject: [PATCH 4/5] Claim and use load_free() to free hash table.

Signed-off-by: zhang2639 <[email protected]>
Signed-off-by: yuwang <[email protected]>
---
 bindings.c | 35 +++++++++++++++++++++++++++++++++++
 bindings.h |  1 +
 lxcfs.c    | 14 ++++++++++++++
 3 files changed, 50 insertions(+)

diff --git a/bindings.c b/bindings.c
index 3041ab0..2669133 100644
--- a/bindings.c
+++ b/bindings.c
@@ -207,6 +207,41 @@ static struct load_node *del_node(struct load_node *n, int 
locate)
        pthread_rwlock_unlock(&load_hash[locate]->rdlock);
        return g;
 }
+
+void load_free(void)
+{
+       int i;
+       struct load_node *f, *p;
+
+       for (i = 0; i < LOAD_SIZE; i++) {
+               pthread_mutex_lock(&load_hash[i]->lock);
+               pthread_rwlock_wrlock(&load_hash[i]->rilock);
+               pthread_rwlock_wrlock(&load_hash[i]->rdlock);
+               if (load_hash[i]->next == NULL) {
+                       pthread_mutex_unlock(&load_hash[i]->lock);
+                       pthread_mutex_destroy(&load_hash[i]->lock);
+                       pthread_rwlock_unlock(&load_hash[i]->rilock);
+                       pthread_rwlock_destroy(&load_hash[i]->rilock);
+                       pthread_rwlock_unlock(&load_hash[i]->rdlock);
+                       pthread_rwlock_destroy(&load_hash[i]->rdlock);
+                       free(load_hash[i]);
+                       continue;
+               }
+               for (f = load_hash[i]->next; f; ) {
+                       free(f->cg);
+                       p = f->next;
+                       free(f);
+                       f = p;
+               }
+               pthread_mutex_unlock(&load_hash[i]->lock);
+               pthread_mutex_destroy(&load_hash[i]->lock);
+               pthread_rwlock_unlock(&load_hash[i]->rilock);
+               pthread_rwlock_destroy(&load_hash[i]->rilock);
+               pthread_rwlock_unlock(&load_hash[i]->rdlock);
+               pthread_rwlock_destroy(&load_hash[i]->rdlock);
+               free(load_hash[i]);
+       }
+}
 /* Reserve buffer size to account for file size changes. */
 #define BUF_RESERVE_SIZE 512
 
diff --git a/bindings.h b/bindings.h
index b66fa2d..a37abf6 100644
--- a/bindings.h
+++ b/bindings.h
@@ -33,5 +33,6 @@ extern int proc_read(const char *path, char *buf, size_t 
size, off_t offset,
                struct fuse_file_info *fi);
 extern int proc_access(const char *path, int mask);
 extern pthread_t load_daemon(void);
+extern void load_free(void);
 
 #endif /* __LXCFS_BINDINGS_H */
diff --git a/lxcfs.c b/lxcfs.c
index 61698a2..d22d920 100644
--- a/lxcfs.c
+++ b/lxcfs.c
@@ -917,6 +917,20 @@ int main(int argc, char *argv[])
 
        if (!fuse_main(nargs, newargv, &lxcfs_ops, NULL))
                ret = EXIT_SUCCESS;
+       if (pthread_cancel(pid) == 0) {
+               pthread_join(pid, NULL); /* Make sure sub thread has been 
canceled. */
+               dlerror();    /* Clear any existing error */
+               void (*load_free)(void);
+
+               load_free = (void (*)(void)) dlsym(dlopen_handle, "load_free");
+               error = dlerror();
+               if (error != NULL) {
+                       lxcfs_error("%s\n", error);
+                       return -1;
+               }
+               load_free();
+       } else
+               lxcfs_error("%s\n", "load_free error!");
 
 out:
        if (dlopen_handle)

From a110764127a953350e6716b9edabdde9309c291c Mon Sep 17 00:00:00 2001
From: zhang2639 <[email protected]>
Date: Wed, 18 Apr 2018 20:04:47 +0800
Subject: [PATCH 5/5] Use proc_loadavg_read() to read loadavg.

Signed-off-by: zhang2639 <[email protected]>
Signed-off-by: yuwang <[email protected]>
---
 bindings.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/bindings.c b/bindings.c
index 2669133..5126258 100644
--- a/bindings.c
+++ b/bindings.c
@@ -90,6 +90,8 @@ struct file_info {
 #define EXP_1          1884            /* 1/exp(5sec/1min) as fixed-point */
 #define EXP_5          2014            /* 1/exp(5sec/5min) */
 #define EXP_15         2037            /* 1/exp(5sec/15min) */
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
 static int calc_hash(char *name)
 {
        unsigned int hash = 0;
@@ -4448,6 +4450,82 @@ void *load_begin(void *arg)
        }
 }
 
+static int proc_loadavg_read(char *buf, size_t size, off_t offset,
+               struct fuse_file_info *fi)
+{
+       struct fuse_context *fc = fuse_get_context();
+       struct file_info *d = (struct file_info *)fi->fh;
+       char *cg;
+       size_t total_len = 0;
+       char *cache = d->buf;
+       struct load_node *n;
+       int hash;
+       int cfd;
+       unsigned long a, b, c;
+
+       if (offset) {
+               if (offset > d->size)
+                       return -EINVAL;
+               if (!d->cached)
+                       return 0;
+               int left = d->size - offset;
+               total_len = left > size ? size : left;
+               memcpy(buf, cache + offset, total_len);
+               return total_len;
+       }
+
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
+       cg = get_pid_cgroup(initpid, "cpu");
+       if (!cg)
+               return read_file("/proc/loadavg", buf, size, d);
+
+       prune_init_slice(cg);
+       hash = calc_hash(cg);
+       n = locate_node(cg, hash);
+
+       /* first time */
+       if (n == NULL) {
+               if (!find_mounted_controller("cpu", &cfd)) {
+                       pthread_rwlock_unlock(&load_hash[hash]->rdlock);
+                       return 0;
+               }
+
+               n = (struct load_node *)malloc(sizeof(struct load_node));
+               n->cg = (char *)malloc(strlen(cg)+1);
+               strcpy(n->cg, cg);
+               n->avenrun[0] = 0;
+               n->avenrun[1] = 0;
+               n->avenrun[2] = 0;
+               n->run_pid = 0;
+               n->total_pid = 1;
+               n->last_pid = initpid;
+               n->cfd = cfd;
+               insert_node(&n, hash);
+       }
+       a = n->avenrun[0] + (FIXED_1/200);
+       b = n->avenrun[1] + (FIXED_1/200);
+       c = n->avenrun[2] + (FIXED_1/200);
+       total_len = snprintf(d->buf, d->buflen, "%lu.%02lu %lu.%02lu %lu.%02lu 
%d/%d %d\n",
+               LOAD_INT(a), LOAD_FRAC(a),
+               LOAD_INT(b), LOAD_FRAC(b),
+               LOAD_INT(c), LOAD_FRAC(c),
+               n->run_pid, n->total_pid, n->last_pid);
+       pthread_rwlock_unlock(&load_hash[hash]->rdlock);
+       if (total_len < 0 || total_len >=  d->buflen) {
+               lxcfs_error("%s\n", "failed to write to cache");
+               return 0;
+       }
+       d->size = (int)total_len;
+       d->cached = 1;
+
+       if (total_len > size)
+               total_len = size;
+       memcpy(buf, d->buf, total_len);
+       return total_len;
+}
+
 pthread_t load_daemon(void)
 {
        init_load();
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to