1 /* top.c - Provide a view of process activity in real time.
3 * Copyright 2013 Bilal Qureshi <bilal.jmi@gmail.com>
4 * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com>
5 * Copyright 2013 Kyungwan Han <asura321@gmail.com>
9 USE_TOP(NEWTOY(top, ">0d#=3n#<1mb", TOYFLAG_USR|TOYFLAG_BIN))
16 usage: top [-mb] [ -d seconds ] [ -n iterations ]
18 Provide a view of process activity in real time.
20 N/M/P/T show CPU usage, sort by pid/mem/cpu/time
28 -n Iterations before exiting
29 -d Delay between updates
54 #define PROC_NAME_LEN 512 //For long cmdline.
58 long unsigned utime, ntime, stime, itime;
59 long unsigned iowtime, irqtime, sirqtime, steal;
60 unsigned long long total;
63 struct keycode_map_s {
69 struct proc_info *next;
72 char name[PROC_NAME_LEN];
73 char tname[PROC_NAME_LEN];
76 unsigned long utime, stime, delta_utime, delta_stime, delta_time;
77 unsigned long vss, vssrw, rss, rss_shr, drt, drt_shr, stack;
80 static struct proc_info *free_procs, **old_procs, **new_procs;
81 static struct cpu_info old_cpu[10], new_cpu[10]; //1 total, 8 cores, 1 null
82 static int (*proc_cmp)(const void *a, const void *b);
84 static struct proc_info *find_old_proc(pid_t pid)
88 for (i = 0; old_procs && old_procs[i]; i++)
89 if (old_procs[i]->pid == pid) return old_procs[i];
94 static void read_stat(char *filename, struct proc_info *proc)
98 char *open_paren, *close_paren;
100 if (!(file = fopen(filename, "r"))) return;
101 fgets(toybuf, sizeof(toybuf), file);
104 // Split at first '(' and last ')' to get process name.
105 open_paren = strchr(toybuf, '(');
106 close_paren = strrchr(toybuf, ')');
107 if (!open_paren || !close_paren) return;
109 *open_paren = *close_paren = '\0';
110 snprintf(proc->tname, PROC_NAME_LEN, "[%s]",open_paren + 1);
112 // Scan rest of string.
113 sscanf(close_paren + 1, " %c %d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
114 "%lu %lu %*d %*d %*d %d %*d %*d %*d %lu %ld "
115 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d",
116 &proc->state[0], &proc->ppid, &proc->utime, &proc->stime, &nice,
117 &proc->vss, &proc->rss, &proc->prs);
118 if (!proc->vss && proc->state[0] != 'Z') proc->state[1] = 'W';
119 else proc->state[1] = ' ';
120 if (nice < 0 ) proc->state[2] = '<';
121 else if (nice) proc->state[2] = 'N';
122 else proc->state[2] = ' ';
125 static void read_status(char *filename, struct proc_info *proc)
129 if (!(file = fopen(filename, "r"))) return;
130 while (fgets(toybuf, sizeof(toybuf), file))
131 if (sscanf(toybuf, "Uid: %u", &(proc->uid)) == 1) break;
136 static void read_cmdline(char *filename, struct proc_info *proc)
138 int fd, len, rbytes = 0;
139 char *ch, *base, tname[PROC_NAME_LEN];
141 if ((fd = open(filename, O_RDONLY)) == -1) return;
142 rbytes = readall(fd, toybuf, sizeof(toybuf));
145 strcpy(proc->name, proc->tname);
148 toybuf[rbytes] = '\0';
149 while (--rbytes >= 0 && toybuf[rbytes] == '\0') continue;
151 snprintf(tname, PROC_NAME_LEN, "%s", proc->tname+1);
152 tname[strlen(tname) - 1] = '\0';
153 ch = strchr(toybuf, ' ');
155 base = strrchr(toybuf, '/');
159 for (; rbytes >= 0; rbytes--)
160 if ((unsigned char)toybuf[rbytes] < ' ') toybuf[rbytes] = ' ';
162 if (*base == '-') base++;
164 if (strncmp(base, tname, len)) {
166 rbytes = strlen(toybuf);
167 memmove(toybuf+ len, toybuf, rbytes+1);
168 snprintf(toybuf, sizeof(toybuf), "{%s}", tname);
171 snprintf(proc->name, PROC_NAME_LEN, "%s", toybuf);
174 static void add_proc(int proc_num, struct proc_info *proc)
178 if (proc_num >= TT.num_new_procs-1) {
179 new_procs = xrealloc(new_procs, (INIT_PROCS + TT.num_new_procs)
180 * sizeof(struct proc_info *));
181 for (i = TT.num_new_procs; i < (INIT_PROCS + TT.num_new_procs); i++)
183 TT.num_new_procs += INIT_PROCS;
185 new_procs[proc_num] = proc;
188 void signal_handler(int sig)
190 tcsetattr(STDIN_FILENO, TCSANOW, &TT.inf);
192 signal(sig, SIG_DFL);
197 static int get_key_code(char *ch, int i)
199 static struct keycode_map_s type2[] = {
200 {"OA",KEY_UP}, {"OB",KEY_DOWN}, {"OH",KEY_HOME},
201 {"OF",KEY_END}, {"[A",KEY_UP}, {"[B",KEY_DOWN},
202 {"[H",KEY_HOME}, {"[F",KEY_END}, {NULL, 0}
205 static struct keycode_map_s type3[] = {
206 {"[1~", KEY_HOME}, {"[4~", KEY_END}, {"[5~", KEY_PGUP},
207 {"[6~", KEY_PGDN}, {"[7~", KEY_HOME}, {"[8~", KEY_END},
210 struct keycode_map_s *table, *keytable[3] = {type2, type3, NULL};
213 if ( i > 3 || i < 1) return -1;
215 for (j=0; (table = keytable[j]); j++) {
217 if (!strncmp(ch, table->key, i)) break;
221 if (i == 1 || (i == 2 && j)) return 1;
228 static int read_input(int delay)
230 struct pollfd pfd[1];
231 int ret, fret = 0, cnt = 0, escproc = 0, timeout = delay * 1000;
232 char ch, seq[4] = {0,};
235 tcgetattr(0, &TT.inf);
236 if (toys.optflags & FLAG_b) {
241 pfd[0].events = POLLIN;
243 //prepare terminal for input, without Enter of Carriage return
244 memcpy(&newf, &TT.inf, sizeof(struct termios));
245 newf.c_lflag &= ~(ICANON | ECHO | ECHONL);
247 newf.c_cc[VTIME] = 0;
248 tcsetattr(0, TCSANOW, &newf);
251 if ((ret = poll(pfd, 1, timeout)) >= 0) break;
253 if (timeout > 0) timeout--;
254 if (errno == EINTR) continue;
260 if (read(STDIN_FILENO, &ch, 1) != 1) toys.optflags |= FLAG_b;
261 else if (ch == '\033' || escproc) {
265 if (!poll(pfd, 1, 50)) break; //no more chars
270 code = get_key_code(seq, cnt);
277 default: // got the key
281 } else if ((ch == TT.inf.c_cc[VINTR])
282 || (ch == TT.inf.c_cc[VEOF]))
284 else fret = ch | 0x20;
287 tcsetattr(0, TCSANOW, &TT.inf);
291 // Allocation for Processes
292 static struct proc_info *alloc_proc(void)
294 struct proc_info *proc;
298 free_procs = free_procs->next;
299 memset(proc, 0, sizeof(*proc));
300 } else proc = xzalloc(sizeof(*proc));
305 static void free_proc_list(struct proc_info *procs)
307 struct proc_info *tmp = procs;
309 for (;tmp; tmp = procs) {
315 // Free allocated Processes in order to avoid memory leaks
316 static void free_proc(struct proc_info *proc)
318 proc->next = free_procs;
322 static struct proc_info *add_new_proc(pid_t pid, pid_t tid)
325 struct proc_info *proc = alloc_proc();
327 proc->pid = (tid)? tid : pid;
329 sprintf(filename, "/proc/%d/stat", pid);
330 read_stat(filename, proc);
331 sprintf(filename, "/proc/%d/cmdline", pid);
332 read_cmdline(filename, proc);
333 sprintf(filename, "/proc/%d/status", pid);
334 read_status(filename, proc);
336 sprintf(filename, "/proc/%d/task/%d/stat", pid,tid);
337 read_stat(filename, proc);
338 sprintf(filename, "/proc/%d/task/%d/cmdline", pid, tid);
339 read_cmdline(filename, proc);
344 static void read_smaps(pid_t pid, struct proc_info *p)
349 long long start, end, val, prvcl, prvdr, shrdr, shrcl;
353 start = end = val = prvcl = prvdr = shrdr = shrcl = 0;
354 sprintf(toybuf, "/proc/%u/smaps", pid);
355 if (!(fp = fopen(toybuf, "r"))) {
356 error_msg("No %ld\n", (long)pid);
363 if (0 >= getline(&line, &len, fp)) break;
364 count = sscanf(line, "%llx-%llx %s %*s %*s %*s %n",
365 &start, &end, toybuf, &off);
369 if (strncmp(line+off, "/dev/", 5) || !strcmp(line+off, "/dev/zero\n")) {
371 if (toybuf[1] == 'w') p->vssrw += end;
373 if (line[off] && !strncmp(line+off, "[stack]",7)) p->stack += end;
375 if (0<sscanf(line, "Private_Clean: %lld", &val)) prvcl += val;
376 if (0<sscanf(line, "Private_Dirty: %lld", &val)) prvdr += val;
377 if (0<sscanf(line, "Shared_Dirty: %lld", &val)) shrdr += val;
378 if (0<sscanf(line, "Shared_Clean: %lld", &val)) shrcl += val;
382 free(line); //incase it broke out.
383 p->rss_shr = shrdr + shrcl;
384 p->drt = prvdr + shrdr;
386 p->rss = p->rss_shr + prvdr + prvcl;
390 static void read_procs(void) // Read Processes
392 DIR *proc_dir, *thr_dir;
393 struct dirent *pid_dir, *t_dir;
394 struct proc_info *proc;
398 proc_dir = opendir("/proc");
399 if (!proc_dir) perror_exit("Could not open /proc");
401 new_procs = xzalloc(INIT_PROCS * sizeof(struct proc_info *));
402 TT.num_new_procs = INIT_PROCS;
404 while ((pid_dir = readdir(proc_dir))) {
405 if (!isdigit(pid_dir->d_name[0])) continue;
407 pid = atoi(pid_dir->d_name);
408 proc = add_new_proc(pid, 0);
410 read_smaps(pid, proc);
416 add_proc(proc_num++, proc);
420 uid_t uid = proc->uid;
422 sprintf(filename,"/proc/%d/task",pid);
423 if ((thr_dir = opendir(filename))) {
424 while ((t_dir = readdir(thr_dir))) {
425 if (!isdigit(t_dir->d_name[0])) continue;
427 tid = atoi(t_dir->d_name);
428 if (pid == tid) continue;
429 proc = add_new_proc(pid, tid);
430 proc->uid = uid; //child will have same uid as parent.
431 add_proc(proc_num++, proc);
439 TT.num_new_procs = proc_num;
442 //calculate percentage.
443 static char* show_percent(long unsigned num, long unsigned den)
446 static char ch, buff[12]={'\0'};
448 if(num > den) num = den;
449 res = (num * 100)/den;
450 sprintf(buff,"%ld", (num * 100)% den);
452 sprintf(buff, "%ld.%c",res, ch);
456 static int print_header(struct sysinfo *info, unsigned int cols)
458 int fd, j, k, rows =0;
459 long unsigned total, meminfo_cached, anon, meminfo_mapped,
460 meminfo_slab, meminfo_dirty, meminfo_writeback, swapT, swapF;
463 fd = xopen("/proc/meminfo", O_RDONLY);
464 while ((buff = get_line(fd))) {
465 if (!strncmp(buff, "Cached", 6))
466 sscanf(buff,"%*s %lu\n",&meminfo_cached);
467 else if (!strncmp(buff, "AnonPages", 9))
468 sscanf(buff,"%*s %lu\n",&anon);
469 else if (!strncmp(buff, "Mapped", 6))
470 sscanf(buff,"%*s %lu\n",&meminfo_mapped);
471 else if (!strncmp(buff, "Slab", 4))
472 sscanf(buff,"%*s %lu\n",&meminfo_slab);
473 else if (!strncmp(buff, "Dirty", 5))
474 sscanf(buff,"%*s %lu\n",&meminfo_dirty);
475 else if (!strncmp(buff, "Writeback", 9))
476 sscanf(buff,"%*s %lu\n",&meminfo_writeback);
477 else if (!strncmp(buff, "SwapTotal", 9))
478 sscanf(buff,"%*s %lu\n",&swapT);
479 else if (!strncmp(buff, "SwapFree", 8))
480 sscanf(buff,"%*s %lu\n",&swapF);
485 if (!(toys.optflags & FLAG_b)) printf("\033[H\033[J");
488 sprintf(toybuf, "Mem total:%lu anon:%lu map:%lu free:%lu",
489 ((info->totalram) >> 10), anon, meminfo_mapped,
490 ((info->freeram) >> 10));
491 printf("%.*s\n", cols, toybuf);
493 sprintf(toybuf, "slab:%lu buf:%lu cache:%lu dirty:%lu write:%lu",
494 meminfo_slab, ((info->bufferram) >>10), meminfo_cached,
495 meminfo_dirty,meminfo_writeback);
496 printf("%.*s\n", cols, toybuf);
498 sprintf(toybuf, "Swap total:%lu free:%lu",swapT, swapF);
499 printf("%.*s\n", cols, toybuf);
502 sprintf(toybuf,"Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
503 (info->totalram-info->freeram) >>10, (info->freeram) >>10,
504 (info->sharedram) >>10, (info->bufferram) >>10, meminfo_cached);
505 printf("%.*s\n", cols, toybuf);
507 for (k = 1; new_cpu[k].total; k++) {
511 j = sprintf(toybuf,"CPU:");
512 } else j = sprintf(toybuf,"CPU%d:", k-1);
514 total = (new_cpu[k].total) - (old_cpu[k].total);
515 if (!total) total = 1; //avoid denominator as 0, FPE
516 j += sprintf(toybuf + j," %s%% usr",
517 show_percent((new_cpu[k].utime - old_cpu[k].utime), total));
518 j += sprintf(toybuf+j," %s%% sys",
519 show_percent((new_cpu[k].stime - old_cpu[k].stime), total));
520 j += sprintf(toybuf+j," %s%% nic",
521 show_percent(new_cpu[k].ntime - old_cpu[k].ntime, total));
522 j += sprintf(toybuf+j," %s%% idle",
523 show_percent(new_cpu[k].itime - old_cpu[k].itime, total));
524 j += sprintf(toybuf+j," %s%% io",
525 show_percent((new_cpu[k].iowtime - old_cpu[k].iowtime), total));
526 j += sprintf(toybuf+j," %s%% irq",
527 show_percent(new_cpu[k].irqtime - old_cpu[k].irqtime, total));
528 j += sprintf(toybuf+j," %s%% sirq",
529 show_percent(new_cpu[k].sirqtime - old_cpu[k].sirqtime, total));
530 printf("%.*s\n", cols, toybuf);
534 if ((buff = readfile("/proc/loadavg", NULL, 0))) {
535 buff[strlen(buff) -1] = '\0'; //removing '\n' at end
536 sprintf(toybuf, "Load average: %s", buff);
537 printf("%.*s\n", cols, toybuf);
540 rows += 2 + ((TT.smp) ? k-1 : 1);
545 static void print_procs(void)
548 struct proc_info *old_proc, *proc;
549 long unsigned total_delta_time;
551 char *user_str, user_buf[20];
553 unsigned int cols=0, rows =0;
555 terminal_size(&cols, &rows);
557 rows = 24; //on serial consoles setting default
560 if (toys.optflags & FLAG_b) rows = INT_MAX;
563 for (i = 0; i < TT.num_new_procs; i++) {
565 old_proc = find_old_proc(new_procs[i]->pid);
567 new_procs[i]->delta_utime = new_procs[i]->utime - old_proc->utime;
568 new_procs[i]->delta_stime = new_procs[i]->stime - old_proc->stime;
570 new_procs[i]->delta_utime = 0;
571 new_procs[i]->delta_stime = 0;
573 new_procs[i]->delta_time = new_procs[i]->delta_utime
574 + new_procs[i]->delta_stime;
578 total_delta_time = new_cpu[0].total - old_cpu[0].total;
579 if (!total_delta_time) total_delta_time = 1;
581 qsort(new_procs, TT.num_new_procs, sizeof(struct proc_info *), proc_cmp);
585 info.totalram *= info.mem_unit;
586 info.freeram *= info.mem_unit;
587 info.sharedram *= info.mem_unit;
588 info.bufferram *= info.mem_unit;
590 rows -= print_header(&info, cols);
593 sprintf(toybuf, "%5s %5s %5s %5s %5s %5s %5s %5s %s", "PID", "VSZ", "VSZRW",
594 "RSS", "(SHR)", "DIRTY", "(SHR)", "STACK", "COMMAND");
595 toybuf[11 + TT.cmp_field*6] = (TT.reverse)?'_':'^'; //11 for PID,VSZ fields
596 } else sprintf(toybuf, "%5s %5s %-8s %4s %5s %5s %4s %5s %s", "PID", "PPID",
597 "USER", "STAT", "VSZ", "%VSZ", "CPU" , "%CPU", "COMMAND");
599 printf((toys.optflags & FLAG_b)?"%.*s\n":"\033[7m%.*s\033[0m\n",cols, toybuf);
601 for (i = TT.scroll_offset; i < TT.num_new_procs; i++) {
605 user = getpwuid(proc->uid);
606 if (user && user->pw_name) {
607 user_str = user->pw_name;
609 snprintf(user_buf, 20, "%d", proc->uid);
615 float vss_percentage = (float)(proc->vss)/info.totalram * 100;
617 j = sprintf(toybuf, "%5d %5d %-8.8s %-4s",proc->pid, proc->ppid, user_str,
620 if ((proc->vss >> 10) >= 100000)
621 j += sprintf(toybuf + j, " %4lum", ((proc->vss >> 10) >> 10));
622 else j += sprintf(toybuf+j, " %5lu", (proc->vss >> 10));
624 sprintf(toybuf + j," %5.1f %4d %5s %s", vss_percentage, proc->prs,
625 show_percent(proc->delta_time, total_delta_time),
626 ((proc->name[0])? proc->name : proc->tname));
627 printf("%.*s", cols, toybuf);
629 j = sprintf(toybuf, "%5d",proc->pid);
631 if ((proc->vss >> 10) >= 100000)
632 j += sprintf(toybuf + j, " %4lum", ((proc->vss >> 10) >> 10));
633 else j += sprintf(toybuf+j, " %5lu", (proc->vss >> 10));
634 if ((proc->vssrw >>10) >= 100000)
635 j += sprintf(toybuf + j, " %4lum", ((proc->vssrw >> 10) >> 10));
636 else j += sprintf(toybuf+j, " %5lu", (proc->vssrw >> 10));
637 if (proc->rss >= 100000)
638 j += sprintf(toybuf + j, " %4lum", ((proc->rss >> 10)));
639 else j += sprintf(toybuf+j, " %5lu", proc->rss);
640 if (proc->rss_shr >= 100000)
641 j += sprintf(toybuf + j, " %4lum", (proc->rss_shr >> 10));
642 else j += sprintf(toybuf+j, " %5lu", proc->rss_shr);
643 if (proc->drt >= 100000)
644 j += sprintf(toybuf + j, " %4lum", (proc->drt >> 10));
645 else j += sprintf(toybuf+j, " %5lu", proc->drt);
646 if (proc->drt_shr >= 100000)
647 j += sprintf(toybuf + j, " %4lum", (proc->drt_shr >> 10));
648 else j += sprintf(toybuf+j, " %5lu", proc->drt_shr);
649 if ((proc->stack >>10) >= 100000)
650 j += sprintf(toybuf + j, " %4lum", ((proc->stack >> 10) >> 10));
651 else j += sprintf(toybuf+j, " %5lu", (proc->stack >> 10));
653 sprintf(toybuf + j," %s",((proc->name[0])? proc->name : proc->tname));
654 printf("%.*s", cols, toybuf);
659 break; //don't print any more process details.
665 * Free old processes(displayed in old iteration) in order to
668 static void free_procs_arr(struct proc_info **procs)
671 for (i = 0; procs && procs[i]; i++)
677 static int numcmp(long long a, long long b)
679 if (a < b) return (TT.reverse)?-1 : 1;
680 if (a > b) return (TT.reverse)?1 : -1;
684 static int top_mem_cmp(const void *a, const void *b)
688 int n = offsetof(struct proc_info, vss) + TT.cmp_field * sizeof(unsigned long);
689 pa = *((char **)a); pb = *((char **)b);
690 return numcmp(*(unsigned long*)(pa+n), *(unsigned long*)(pb+n));
693 static int proc_time_cmp(const void *a, const void *b)
695 struct proc_info *pa, *pb;
697 pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
698 return numcmp(pa->utime + pa->stime, pb->utime+pa->stime);
702 * Function to compare CPU usgae % while displaying processes
703 * according to CPU usage
705 static int proc_cpu_cmp(const void *a, const void *b)
707 struct proc_info *pa, *pb;
709 pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
710 return numcmp(pa->delta_time, pb->delta_time);
714 * Function to compare memory taking by a process at the time of
715 * displaying processes according to Memory usage
717 static int proc_vss_cmp(const void *a, const void *b)
719 struct proc_info *pa, *pb;
721 pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
722 return numcmp(pa->vss, pb->vss);
725 static int proc_pid_cmp(const void *a, const void *b)
727 struct proc_info *pa, *pb;
729 pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
730 return numcmp(pa->pid, pb->pid);
733 /* Read CPU stats for all the cores, assuming max 8 cores
734 * to be present here.
736 static void read_cpu_stat()
740 char *line = 0, *params = "%lu %lu %lu %lu %lu %lu %lu %lu";
741 FILE *fp = xfopen("/proc/stat", "r");
743 for (i = 0; i<=8 && getline(&line, &len, fp) > 0; i++) {
744 if (i) sprintf(toybuf, "cpu%d %s", i-1, params);
745 else sprintf(toybuf, "cpu %s", params);
746 len = sscanf(line, toybuf, &new_cpu[i].utime, &new_cpu[i].ntime,
747 &new_cpu[i].stime, &new_cpu[i].itime, &new_cpu[i].iowtime,
748 &new_cpu[i].irqtime, &new_cpu[i].sirqtime, &new_cpu[i].steal);
750 new_cpu[i].total = new_cpu[i].utime + new_cpu[i].ntime + new_cpu[i].stime
751 + new_cpu[i].itime + new_cpu[i].iowtime + new_cpu[i].irqtime
752 + new_cpu[i].sirqtime + new_cpu[i].steal;
764 proc_cmp = &proc_cpu_cmp;
765 if ( TT.delay < 0) TT.delay = 3;
766 if (toys.optflags & FLAG_m) {
767 proc_cmp = &top_mem_cmp;
771 sigatexit(signal_handler);
773 get_key = read_input(0);
775 while (!(toys.optflags & FLAG_n) || TT.iterations--) {
776 old_procs = new_procs;
777 memcpy(old_cpu, new_cpu, sizeof(old_cpu));
781 free_procs_arr(old_procs);
782 if ((toys.optflags & FLAG_n) && !TT.iterations) break;
784 get_key = read_input(TT.delay);
785 if (get_key == 'q') break;
789 proc_cmp = &proc_pid_cmp;
793 if (!TT.m_flag) TT.threads ^= 1;
796 proc_cmp = &proc_vss_cmp;
808 TT.cmp_field = (TT.cmp_field + 1) % 7;//7 sort fields, vss,vssrw...
809 proc_cmp = &top_mem_cmp;
812 proc_cmp = &proc_cpu_cmp;
816 proc_cmp = &proc_time_cmp;
826 TT.scroll_offset = 0;
829 TT.scroll_offset = TT.num_new_procs - TT.rows/2;
832 TT.scroll_offset -= TT.rows/2;
835 TT.scroll_offset += TT.rows/2;
838 if (TT.scroll_offset >= TT.num_new_procs) TT.scroll_offset = TT.num_new_procs-1;
839 if (TT.scroll_offset < 0) TT.scroll_offset = 0;
842 if (CFG_TOYBOX_FREE) {
843 free_proc_list(free_procs);
845 free_procs_arr(new_procs);
846 free_proc_list(free_procs);