psproc 源码阅读 - 5

剩余的代码中,最重要的是show_one_proc,它读取结构体并解析其中的一项,调用其print函数打印到屏幕上。

/********** show one process (NULL proc prints header) **********/

//#define SPACE_AMOUNT page_size
#define SPACE_AMOUNT 144

static char *saved_outbuf;

void show_one_proc(const proc_t *restrict const p, const format_node *restrict fmt) {
    /* unknown: maybe set correct & actual to 1, remove +/- 1 below */
    int correct  = 0;  /* screen position we should be at */
    int actual   = 0;  /* screen position we are at */
    int amount   = 0;  /* amount of text that this data is */
    int leftpad  = 0;  /* amount of space this column _could_ need */
    int space    = 0;  /* amount of space we actually need to print */
    int dospace  = 0;  /* previous column determined that we need a space */
    int legit    = 0;  /* legitimately stolen extra space */
    int sz       = 0;  /* real size of data in outbuffer */
    int tmpspace = 0;
    char *restrict const outbuf = saved_outbuf;
    static int did_stuff = 0;  /* have we ever printed anything? */

p为-1时是其最后一次调用。如果仍然有内容,则打印剩余的内容。

    if(-1==(long)p) {   /* true only once, at the end */
        if(did_stuff) return;
        /* have _never_ printed anything, but might need a header */
        if(!--lines_to_next_header) {
            lines_to_next_header = header_gap;
            show_one_proc(NULL,fmt);
        }
        /* fprintf(stderr, "No processes available.\n"); */  /* legal? */
        exit(1);
    }

如果是其他情况,则生成这样的递归栈输出fmt。fmt(format node)就是那一组预定义的标头和格式化的数组。

    if(p) { /* not header, maybe we should call ourselves for it */
        if(!--lines_to_next_header) {
            lines_to_next_header = header_gap;
            show_one_proc(NULL,fmt);
        }
    }
    did_stuff = 1;
    if(active_cols>(int)OUTBUF_SIZE) fprintf(stderr,_("fix bigness error\n"));

    /* print row start sequence */
    for(;;) {
        legit = 0; 

        if(fmt->next) {
            max_rightward = fmt->width;
            tmpspace = 0;
        } else {
            tmpspace = correct-actual;
            if (tmpspace<1) {
                tmpspace = dospace;
                max_rightward = active_cols-actual-tmpspace;
            } else {
                max_rightward = active_cols - ( (correct>actual) ? correct : actual );
            }
        }
        if(max_rightward <= 0) max_rightward = 0;
        else if(max_rightward >= OUTBUF_SIZE) max_rightward = OUTBUF_SIZE-1;

        max_leftward  = fmt->width + actual - correct; /* TODO check this */
        if(max_leftward <= 0) max_leftward = 0;
        else if(max_leftward >= OUTBUF_SIZE) max_leftward = OUTBUF_SIZE-1;

计算完位置后,调用fmt的print函数来处理。举例阅读pr_wchan。

static int pr_wchan(char *restrict const outbuf, const proc_t *restrict const pp) {
    const char *w;
    size_t len;
    setREL1(WCHAN_NAME)  //<-- 如果没有设置outbuf,设置rel_WCHAN_NAME,设置完会退出。如果outbuf有值则不管。 这里outbuf是由saved_outbuf(= outbuf + SPACE_AMOUNT == 144,还记得最早的时候初始化的那个带保护页的区域吗……)传来的,因此有值。
    w = rSv(WCHAN_NAME, str, pp); //<-- rSv复习一下,就是pp->head[rel_WCHAN_NAME].result.str。

这个属性是由setDECL设置的。

setDECL(WCHAN_NAME)     {
    freNAME(str)(R);
    if (!(R->result.str = strdup(lookup_wchan(P->tid)))) I->seterr = 1;;
}

回到原函数中,剩余的就是将数据拷贝到outbuf中。

    len = strlen(w);
    if(len>max_rightward) len=max_rightward;
    memcpy(outbuf, w, len);
    outbuf[len] = '\0';
    return len;
}

回到上一层的函数中,如果没有fmt->pr则将fmt->name追加到outbuf里。

        /* prepare data and calculate leftpad */
        if(p && fmt->pr) amount = (*fmt->pr)(outbuf,p);
        else amount = snprintf(outbuf, OUTBUF_SIZE, "%s", fmt->name); /* AIX or headers */

并补足末尾0。

        if(amount < 0) outbuf[amount = 0] = '\0';
        else if(amount >= OUTBUF_SIZE) outbuf[amount = OUTBUF_SIZE-1] = '\0';

        switch((fmt->flags) & CF_JUST_MASK) {
        case 0:  /* for AIX, assigned outside this file */
            leftpad = 0;
            break;
        case CF_LEFT:          /* bad */
            leftpad = 0;
            break;
        case CF_RIGHT:     /* OK */
            leftpad = fmt->width - amount;
            if(leftpad < 0) leftpad = 0;
            break;
        case CF_SIGNAL:
            /* if the screen is wide enough, use full 16-character output */
            if(wide_signals) {
                leftpad = 16 - amount;
                legit = 7;
            } else {
                leftpad =  9 - amount;
            }
            if(leftpad < 0) leftpad = 0;
            break;
        case CF_USER:       /* bad */
            leftpad = fmt->width - amount;
            if(leftpad < 0) leftpad = 0;
            if(!user_is_number) leftpad = 0;
            break;
        case CF_WCHAN:       /* bad */
            if(wchan_is_number) {
                leftpad = fmt->width - amount;
                if(leftpad < 0) leftpad = 0;
                break;
            } else {
                if ((active_cols-actual-tmpspace)<1)
                    outbuf[1] = '\0';  /* oops, we (mostly) lose this column... */
                leftpad = 0;
                break;
            }
        case CF_UNLIMITED:
        {
            if(active_cols-actual-tmpspace < 1)
                outbuf[1] = '\0';    /* oops, we (mostly) lose this column... */
            leftpad = 0;
            break;
        }
        default:
            fprintf(stderr, _("bad alignment code\n"));
            break;
        }
        /* At this point:
         *
         * correct   from previous column
         * actual    from previous column
         * amount    not needed (garbage due to chopping)
         * leftpad   left padding for this column alone (not make-up or gap)
         * space     not needed (will recalculate now)
         * dospace   if we require space between this and the prior column
         * legit     space we were allowed to steal, and thus did steal
         */
        space = correct - actual + leftpad;
        if(space<1) space=dospace;
        if(space>SPACE_AMOUNT) space=SPACE_AMOUNT;  // only so much available

        /* real size -- don't forget in 'amount' is number of cells */
        outbuf[OUTBUF_SIZE-1] = '\0';
        sz = strlen(outbuf);

        /* print data, set x position stuff */
        if(!fmt->next) {
            /* Last column. Write padding + data + newline all together. */
            outbuf[sz] = '\n';
            fwrite(outbuf-space, space+sz+1, 1, stdout);
            break;
        }
        /* Not the last column. Write padding + data together. */
        fwrite(outbuf-space, space+sz, 1, stdout);
        actual  += space+amount;
        correct += fmt->width;
        correct += legit;        /* adjust for SIGNAL expansion */
        if(fmt->pr && fmt->next->pr) { /* neither is AIX filler */
            correct++;
            dospace = 1;
        } else {
            dospace = 0;
        }
        fmt = fmt->next;
        /* At this point:
         *
         * correct   screen position we should be at
         * actual    screen position we are at
         * amount    not needed
         * leftpad   not needed
         * space     not needed
         * dospace   if have determined that we need a space next time
         * legit     not needed
         */
    }
}

标签:none

添加新评论

captcha
请输入验证码