#include #include #include #include #include #include #include #include #include #include #include #define LOG_MODULE "mem" #define LOG_ENABLE_DBG 0 #define SMALLEST_INTERVAL 500 #include "../bar/bar.h" #include "../config-verify.h" #include "../config.h" #include "../log.h" #include "../plugin.h" struct private { struct particle *label; uint16_t interval; }; static void destroy(struct module *mod) { struct private *m = mod->private; m->label->destroy(m->label); free(m); module_default_destroy(mod); } static const char * description(struct module *mod) { return "mem"; } static bool get_mem_stats(uint64_t *mem_free, uint64_t *mem_total) { bool mem_total_found = false; bool mem_free_found = false; FILE *fp = NULL; char *line = NULL; size_t len = 0; ssize_t read = 0; fp = fopen("/proc/meminfo", "r"); if (NULL == fp) { LOG_ERRNO("unable to open /proc/meminfo"); return false; } while ((read = getline(&line, &len, fp)) != -1) { if (strncmp(line, "MemTotal:", sizeof("MemTotal:") - 1) == 0) { read = sscanf(line + sizeof("MemTotal:") - 1, "%" SCNu64, mem_total); mem_total_found = (read == 1); } if (strncmp(line, "MemAvailable:", sizeof("MemAvailable:") - 1) == 0) { read = sscanf(line + sizeof("MemAvailable:"), "%" SCNu64, mem_free); mem_free_found = (read == 1); } } free(line); fclose(fp); return mem_free_found && mem_total_found; } static struct exposable * content(struct module *mod) { const struct private *p = mod->private; uint64_t mem_free = 0; uint64_t mem_used = 0; uint64_t mem_total = 0; if (!get_mem_stats(&mem_free, &mem_total)) { LOG_ERR("unable to retrieve the memory stats"); } mem_used = mem_total - mem_free; double percent_used = ((double)mem_used * 100) / (mem_total + 1); double percent_free = ((double)mem_free * 100) / (mem_total + 1); struct tag_set tags = { .tags = (struct tag *[]){tag_new_int(mod, "free", mem_free * 1024), tag_new_int(mod, "used", mem_used * 1024), tag_new_int(mod, "total", mem_total * 1024), tag_new_int_range(mod, "percent_free", round(percent_free), 0, 100), tag_new_int_range(mod, "percent_used", round(percent_used), 0, 100)}, .count = 5, }; struct exposable *exposable = p->label->instantiate(p->label, &tags); tag_set_destroy(&tags); return exposable; } static int run(struct module *mod) { const struct bar *bar = mod->bar; bar->refresh(bar); struct private *p = mod->private; while (true) { struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}}; int res = poll(fds, 1, p->interval); if (res < 0) { if (EINTR == errno) { continue; } LOG_ERRNO("unable to poll abort fd"); return -1; } if (fds[0].revents & POLLIN) break; bar->refresh(bar); } return 0; } static struct module * mem_new(uint16_t interval, struct particle *label) { struct private *p = calloc(1, sizeof(*p)); p->label = label; p->interval = interval; struct module *mod = module_common_new(); mod->private = p; mod->run = &run; mod->destroy = &destroy; mod->content = &content; mod->description = &description; return mod; } static struct module * from_conf(const struct yml_node *node, struct conf_inherit inherited) { const struct yml_node *interval = yml_get_value(node, "interval"); const struct yml_node *c = yml_get_value(node, "content"); return mem_new(interval == NULL ? SMALLEST_INTERVAL : yml_value_as_int(interval), conf_to_particle(c, inherited)); } static bool conf_verify_interval(keychain_t *chain, const struct yml_node *node) { if (!conf_verify_unsigned(chain, node)) return false; if (yml_value_as_int(node) < SMALLEST_INTERVAL) { LOG_ERR("%s: interval value cannot be less than %d ms", conf_err_prefix(chain, node), SMALLEST_INTERVAL); return false; } return true; } static bool verify_conf(keychain_t *chain, const struct yml_node *node) { static const struct attr_info attrs[] = { {"interval", false, &conf_verify_interval}, MODULE_COMMON_ATTRS, }; return conf_verify_dict(chain, node, attrs); } const struct module_iface module_mem_iface = { .verify_conf = &verify_conf, .from_conf = &from_conf, }; #if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES) extern const struct module_iface iface __attribute__((weak, alias("module_mem_iface"))); #endif