struct cpuacct_usage *usage; // Real usage as read from the host's /proc/stat
struct cpuacct_usage *view; // Usage stats reported to the container
int cpu_count;
+ pthread_mutex_t lock; // For node manipulation
struct cg_proc_stat *next;
};
struct cg_proc_stat_head {
struct cg_proc_stat *next;
time_t lastcheck;
+
+ /*
+ * For access to the list. Reading can be parallel, pruning is exclusive.
+ */
+ pthread_rwlock_t lock;
};
#define CPUVIEW_HASH_SIZE 100
(*head)->lastcheck = time(NULL);
(*head)->next = NULL;
+
+ if (pthread_rwlock_init(&(*head)->lock, NULL) != 0) {
+ lxcfs_error("%s\n", "Failed to initialize list lock");
+ free(*head);
+ return false;
+ }
+
return true;
}
static void free_proc_stat_node(struct cg_proc_stat *node)
{
+ pthread_mutex_destroy(&node->lock);
free(node->cg);
free(node->usage);
free(node->view);
}
}
+ pthread_rwlock_destroy(&head->lock);
free(head);
}
time_t now = time(NULL);
for (i = 0; i < CPUVIEW_HASH_SIZE; i++) {
- if ((proc_stat_history[i]->lastcheck + PROC_STAT_PRUNE_INTERVAL) > now)
+ pthread_rwlock_wrlock(&proc_stat_history[i]->lock);
+
+ if ((proc_stat_history[i]->lastcheck + PROC_STAT_PRUNE_INTERVAL) > now) {
+ pthread_rwlock_unlock(&proc_stat_history[i]->lock);
return;
+ }
- if (!proc_stat_history[i]->next)
- continue;
+ if (proc_stat_history[i]->next) {
+ proc_stat_history[i]->next = prune_proc_stat_list(proc_stat_history[i]->next);
+ proc_stat_history[i]->lastcheck = now;
+ }
- proc_stat_history[i]->next = prune_proc_stat_list(proc_stat_history[i]->next);
- proc_stat_history[i]->lastcheck = now;
+ pthread_rwlock_unlock(&proc_stat_history[i]->lock);
}
}
-static struct cg_proc_stat *find_proc_stat_node(const char *cg)
+static struct cg_proc_stat *find_proc_stat_node(struct cg_proc_stat_head *head, const char *cg)
{
- int hash = calc_hash(cg) % CPUVIEW_HASH_SIZE;
- struct cg_proc_stat_head *head = proc_stat_history[hash];
struct cg_proc_stat *node;
- if (!head->next)
+ pthread_rwlock_rdlock(&head->lock);
+
+ if (!head->next) {
+ pthread_rwlock_unlock(&head->lock);
return NULL;
+ }
node = head->next;
node = NULL;
out:
+ pthread_rwlock_unlock(&head->lock);
prune_proc_stat_history();
return node;
}
node->cpu_count = cpu_count;
node->next = NULL;
+ if (pthread_mutex_init(&node->lock, NULL) != 0) {
+ lxcfs_error("%s\n", "Failed to initialize node lock");
+ goto err;
+ }
+
for (i = 0; i < cpu_count; i++) {
node->view[i].user = 0;
node->view[i].system = 0;
return NULL;
}
-static void add_proc_stat_node(struct cg_proc_stat *new_node)
+static struct cg_proc_stat *add_proc_stat_node(struct cg_proc_stat *new_node)
{
int hash = calc_hash(new_node->cg) % CPUVIEW_HASH_SIZE;
struct cg_proc_stat_head *head = proc_stat_history[hash];
- struct cg_proc_stat *node;
+ struct cg_proc_stat *node, *rv = new_node;
+
+ pthread_rwlock_wrlock(&head->lock);
if (!head->next) {
head->next = new_node;
- return;
+ goto out;
}
+ node = head->next;
+
for (;;) {
- node = head->next;
+ if (strcmp(node->cg, new_node->cg) == 0) {
+ /* The node is already present, return it */
+ free_proc_stat_node(new_node);
+ rv = node;
+ goto out;
+ }
if (node->next) {
node = node->next;
}
node->next = new_node;
- return;
+ goto out;
+ }
+
+out:
+ pthread_rwlock_unlock(&head->lock);
+ return rv;
+}
+
+static struct cg_proc_stat *find_or_create_proc_stat_node(struct cpuacct_usage *usage, int cpu_count, const char *cg)
+{
+ int hash = calc_hash(cg) % CPUVIEW_HASH_SIZE;
+ struct cg_proc_stat_head *head = proc_stat_history[hash];
+ struct cg_proc_stat *node;
+
+ node = find_proc_stat_node(head, cg);
+
+ if (!node) {
+ node = new_proc_stat_node(usage, cpu_count, cg);
+ if (!node)
+ return NULL;
+
+ node = add_proc_stat_node(node);
+ lxcfs_debug("New stat node (%d) for %s\n", cpu_count, cg);
}
+
+ pthread_mutex_lock(&node->lock);
+ return node;
}
static void reset_proc_stat_node(struct cg_proc_stat *node, struct cpuacct_usage *usage, int cpu_count)
if (max_cpus > cpu_cnt)
max_cpus = cpu_cnt;
- stat_node = find_proc_stat_node(cg);
+ stat_node = find_or_create_proc_stat_node(cg_cpu_usage, nprocs, cg);
if (!stat_node) {
- stat_node = new_proc_stat_node(cg_cpu_usage, nprocs, cg);
- if (!stat_node) {
- rv = 0;
- goto err;
- }
-
- add_proc_stat_node(stat_node);
+ lxcfs_error("unable to find/create stat node for %s\n", cg);
+ rv = 0;
+ goto err;
}
diff = malloc(sizeof(struct cpuacct_usage) * nprocs);
rv = total_len;
err:
+ if (stat_node)
+ pthread_mutex_unlock(&stat_node->lock);
if (line)
free(line);
if (diff)