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
*/
}
}