Chinaunix首页 | 论坛 | 博客
  • 博客访问: 493099
  • 博文数量: 41
  • 博客积分: 4007
  • 博客等级: 中校
  • 技术积分: 725
  • 用 户 组: 普通用户
  • 注册时间: 2006-09-30 15:43
文章分类

全部博文(41)

文章存档

2011年(13)

2010年(14)

2009年(2)

2008年(12)

分类: C/C++

2011-01-17 15:54:44

发信人: wxc200 (伊泽), 信区: KernelTech
标  题: cgroup通过eventfd提供内存使用超限通知机制
发信站: 水木社区 (Sun Jan 16 23:20:23 2011), 转信

1.内存threshold阀值限制
内存资源控制subsystem提供cgroup通知机制,用户态程序可以向cgroup注册对内存资源的阀值监控,当进程使用内存超限时,会通过eventfd通知用户态的监听进程。

用户mount内存的subsystem时,在cgroup目录下有memory.usage_in_bytes 或者memory_memsw.usage_in_bytes属性文件,那么对这两种资源监控需要如下几步:
1) 用系统调用eventfd(2)创建eventfd文件。
2)打开上述属性文件
3) 按照如下格式
 
写入到cgroup提供的对event事件的支持属性文件
cgroup.event_control

当内存使用超限,会通过eventfd_signal通知上层。

2.内存oom通知
想监听哪些进程被oom杀死吗? 现在可以了。

类似于前面提到的内存属性文件,OOM在cgroup里通过memory.oom_control提供控制接口。对这个文件进行eventfd操作,memory subsystem会提供会oom杀死进程的事件通知。
操作方式:
==> cgroup.event_control

当OOM发生时,应用程序会得到通知。


这里有片代码,实现了对cgroup上述属性文件的支持。

/*
 * cgroup_event_listener.c - Simple listener of cgroup events
 *
 * Copyright (C) Kirill A. Shutemov
 */

#include
#include
#include
#include
#include
#include
#include
#include

#include

#define USAGE_STR "Usage: cgroup_event_listener \n"

int main(int argc, char **argv)
{
    int efd = -1;
    int cfd = -1;
    int event_control = -1;
    char event_control_path[PATH_MAX];
    char line[LINE_MAX];
    int ret;

    if (argc != 3) {
        fputs(USAGE_STR, stderr);
        return 1;
    }

    cfd = open(argv[1], O_RDONLY); //要操作的subsystem属性文件
    if (cfd == -1) {
        fprintf(stderr, "Cannot open %s: %s\n", argv[1],
                strerror(errno));
        goto out;
    }

    ret = snprintf(event_control_path, PATH_MAX, "%s/cgroup.event_control", //将参数写到这个配置文件里。内核对此文件的支持很清晰,后面会分析到。
            dirname(argv[1]));
    if (ret >= PATH_MAX) {
        fputs("Path to cgroup.event_control is too long\n", stderr);
        goto out;
    }

    event_control = open(event_control_path, O_WRONLY);//打开cgroup event.control配置文件
    if (event_control == -1) {
        fprintf(stderr, "Cannot open %s: %s\n", event_control_path,
                strerror(errno));
        goto out;
    }

    efd = eventfd(0, 0); //创建eventfd
    if (efd == -1) {
        perror("eventfd() failed");
        goto out;
    }

    ret = snprintf(line, LINE_MAX, "%d %d %s", efd, cfd, argv[2]); //合成要写入的字符串
    if (ret >= LINE_MAX) {
        fputs("Arguments string is too long\n", stderr);
        goto out;
    }

    ret = write(event_control, line, strlen(line) + 1);
    if (ret == -1) {
        perror("Cannot write to cgroup.event_control");
        goto out;
    }
//完成写入,守候通知吧。
    while (1) {
        uint64_t result;

        ret = read(efd, &result, sizeof(result)); //读取event count数值
        if (ret == -1) {
            if (errno == EINTR)
                continue;
            perror("Cannot read from eventfd");
            break;
        }
        assert(ret == sizeof(result));

        ret = access(event_control_path, W_OK);
        if ((ret == -1) && (errno == ENOENT)) {
                puts("The cgroup seems to have removed.");
                ret = 0;
                break;
        }

        if (ret == -1) {
            perror("cgroup.event_control "
                    "is not accessable any more");
            break;
        }

        printf("%s %s: crossed\n", argv[1], argv[2]);
    }

out:
    if (efd >= 0)
        close(efd);
    if (event_control >= 0)
        close(event_control);
    if (cfd >= 0)
        close(cfd);

    return (ret != 0);
}

Coming soon:
1) 分析内核cgroup和相应subsystem(memory)对eventfd的支持
2) eventfd 的实现
3) eventfd/pipe等机制的比较。

参考文献:
0) cgroup.c eventfd.c memcontrol.c anon_inodes.c
1) Documentation/cgroup/memory.txt+cgroup.txt
2) cgroup_event_listener.c
3) eventfd分析:
  
4) pipe分析:
  
阅读(2113) | 评论(0) | 转发(0) |
0

上一篇:工作三年总结

下一篇:修改线程栈 zz

给主人留下些什么吧!~~