1 Star2 Stars3 Stars4 Stars5 Stars (还没有评分)
Loading...

Dtrace-example源码分析

Adam Leventhalgithub上建立了一个dtrace-example项目,介绍如何使用DTraceAPI做一个单独的trace工具。在这篇文章里,我就对这个项目的源码做一个简单的分析。

dtrace-example.c包含了4个函数,其中最主要的是main函数,代码如下:

int
main(int argc, char **argv)
{
    int err;

    if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
        die("failed to initialize: %s\n",
            dtrace_errmsg(NULL, err));
    }

    if (dtrace_setopt(g_dtp, "bufsize", "1k") == -1)
        ddie("failed to set 'bufsize'");

    dtrace_prog_t *prog;
    dtrace_proginfo_t info;

    if ((prog = dtrace_program_strcompile(g_dtp, g_script,
        DTRACE_PROBESPEC_NAME, 0, 0, NULL)) == NULL) {
        die("failed to compile\n");
    }

    if (dtrace_program_exec(g_dtp, prog, &info) == -1)
        die("failed to enable probes\n");

    if (dtrace_go(g_dtp) != 0)
        ddie("failed to start");

    int done = 0;

    do {
        if (!g_exit && !done)
            dtrace_sleep(g_dtp);

        if (g_exit || done) {
            done = 1;
            if (dtrace_stop(g_dtp) == -1)
                ddie("failed to stop");
        }

        switch (dtrace_work(g_dtp, stdout, NULL, chewrec, NULL)) {
        case DTRACE_WORKSTATUS_DONE:
            done = 1;
            break;
        case DTRACE_WORKSTATUS_OKAY:
            break;
        default:
            die("processing aborted");
        }
    } while (!done);

    dtrace_close(g_dtp);

    return (0);
}  

(1)程序首先调用dtrace_open函数,返回一个dtrace handle。第一个参数是DTrace的版本;第二个参数是一些flags(例如DTRACE_O_NODEV,表示不打开dtrace设备);第三个参数则是在出错时存放错误值。
(2)得到dtrace handle后,调用dtrace_setopt函数设置dtrace的缓冲区大小为1k
(3)调用dtrace_program_strcompile函数编译g_script所指向的字符串(内容是一个简单的DTrace脚本)。
(4)编译成功后,调用dtrace_program_exec开始执行编译好的程序,也即使probe生效。
(5)dtrace_go函数开始trace的工作。
(6)在接下的循环中包含两个动作:dtrace_sleepdtrace_workdtrace_sleep会阻塞程序等待事件的发生,但不会超过dtrace handle所设定的时间。而dtrace_work则注册了chewrec这个callback函数,用来消化得到的记录。
(7)最后dtrace_close优雅地关闭dtrace handle

接下来看一下chewrec这个函数:

static int
chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg)
{
    if (rec == NULL)
        return (DTRACE_CONSUME_NEXT);

    switch (rec->dtrd_action) {
    case DTRACEACT_DIFEXPR:
        (void) printf("%s\n", data->dtpda_data);
        return (DTRACE_CONSUME_NEXT);
    case DTRACEACT_EXIT:
        g_exit = 1;
        return (DTRACE_CONSUME_NEXT);
    default:
        (void) printf("%d\n", rec->dtrd_action);
        return (DTRACE_CONSUME_NEXT);
    }

    return (DTRACE_CONSUME_THIS);
}

可以看到这个函数根据dtrace action的不同,或者打印原始的数据(printf("%s\n", data->dtpda_data)),或者准备退出(g_exit = 1)。

另外两个函数(dieddie)都是打印log而已,就不细说了。

以下是编译和执行这个程序得到的结果:

root# make
cc -o dtrace-example dtrace-example.c -ldtrace
root# ./dtrace-example
Hello, DTrace API!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.