struct proc_info *parse_proc_info(FILE *fp) { struct proc_info *proc = NULL; char *line = NULL; size_t len, sz = 0; int i, valid = 0; /* Strip comments & blank lines */ while (1) { if ((len = getline(&line, &sz, fp)) == -1) break; i = 0; while (i < len && isspace(line[i++])); if (i >= len || line[i-1] == '#') continue; if (!proc) { if ((proc = alloc_proc_info()) == NULL) break; } if ((valid = fill_proc_info(proc, line))) break; } if (line) free(line); if (!valid && proc) { free_proc_info(proc); proc = NULL; } return proc; }
int fill_infos(struct proc_info** infos) { DIR* dirp, *ddirp; struct dirent* dptr, *ddptr; __u32 pid, tid; int ret = -1; static char path[32]; if ((dirp = opendir("/proc")) == NULL) { ERROR("unable to open proc \n"); return -1; } while (dptr = readdir(dirp)) { char* endp; pid = strtoul(dptr->d_name, &endp, 10); if (*endp != '\0') continue; snprintf(path, sizeof(path), "/proc/%s/task/", dptr->d_name); if ((ddirp = opendir(path)) == NULL) { ERROR("Unable to open task dir\n"); goto close; } while (ddptr = readdir(ddirp)) { if (strcmp(ddptr->d_name, ".") == 0 || strcmp(ddptr->d_name, "..") == 0) continue; tid = strtoul(ddptr->d_name, &endp, 10); if (*endp != '\0') { ERROR("huh? %s\n", ddptr->d_name); goto close; } if (!(infos[tid] = alloc_proc_info())) { ERROR("Unable to alloc memory\n"); goto close; } infos[tid]->tgid = pid; infos[tid]->pid = tid; } } ret = 0; close : closedir(dirp); dirp = NULL; if (ret) return ret; for (tid = 0; tid < pid_max; tid++) { if (!infos[tid]) continue; if (infos[tid]->updated) continue; if (tid && (ret = send_cmd(TASKSTATS_CMD_GET, TASKSTATS_CMD_ATTR_PID, \ &tid, sizeof(__u32))) < 0) { ERROR("unable to send cmd to tid [%d]\n", tid); goto out; } retry : if ((ret = recv_taskstats(0, infos)) < 0) { //MSG_DONTWAIT goto out; } if (!infos[tid]->updated) goto retry; } out : return ret; }
int recv_taskstats(int recv_flags, struct proc_info** infos) { int rep_len, len, aggr_len, len2; struct msgtemplate msg; struct nlattr* na; __u32 tgid = 0, pid = 0; //recv : if ((rep_len = recv(nl_sd, &msg, sizeof(msg), recv_flags)) < 0) { //MSG_DONTWAIT //if (errno == EAGAIN) { // usleep(10000); // goto recv; //} //if (!(recv_flags | MSG_DONTWAIT) && rep_len == -1) { //} if ((recv_flags & MSG_DONTWAIT) && errno == EAGAIN) return -EAGAIN; ERROR("receive error %d %d\n", rep_len, errno); return rep_len; } //check if packet is error if (msg.n.nlmsg_type == NLMSG_ERROR || !NLMSG_OK((&msg.n), rep_len)) { struct nlmsgerr* err = NLMSG_DATA(&msg); ERROR("fatal reply error, errno %d\n", err->error); return -1; } rep_len = GENLMSG_PAYLOAD(&msg.n); na = (struct nlattr*)GENLMSG_DATA(&msg); len = 0; while (len < rep_len) { len += NLA_ALIGN(na->nla_len); switch (na->nla_type) { case TASKSTATS_TYPE_AGGR_TGID: // fall through case TASKSTATS_TYPE_AGGR_PID: aggr_len = NLA_PAYLOAD(na->nla_len); len2 = 0; na = (struct nlattr*)NLA_DATA(na); while (len2 < aggr_len) { switch (na->nla_type) { case TASKSTATS_TYPE_PID: pid = *(int*)NLA_DATA(na); tgid = 0; break; case TASKSTATS_TYPE_TGID: tgid = *(int*)NLA_DATA(na); pid = 0; break; case TASKSTATS_TYPE_STATS: if (tgid) { break; } if (!infos[pid] && !(infos[pid] = alloc_proc_info())) { ERROR("unable to allocate memory\n"); return -ENOMEM; } memcpy(&infos[pid]->t, (struct taskstats*)NLA_DATA(na), sizeof(struct taskstats)); infos[pid]->updated = 1; //print_delayacct(NLA_DATA(na)); //print_ioacct(NLA_DATA(na)); break; default : ERROR("unknown nested nla_type %d\n", na->nla_type); break; } len2 += NLA_ALIGN(na->nla_len); na = (struct nlattr*)((char*)na + len2); } //end of while for TASKSTATS_TYPE_AGGR_PID packet analysis break; case CGROUPSTATS_TYPE_CGROUP_STATS: PRINTF("cgroup\n"); break; default : PRINTF("default %d\n", msg.n.nlmsg_type); case TASKSTATS_TYPE_NULL: break; } //end of switch clause na = (struct nlattr*)(GENLMSG_DATA(&msg) + len); } //end of while loop for recv'ed packet analysis return 0; }