kernel - Fix races created by a comedy of circumstansces (3)
[dragonfly.git] / contrib / top / utils.c
bloba3617de94257578ab260e205a6c057b9c3259c5d
1 /*
2 * Copyright (c) 1984 through 2008, William LeFebvre
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
16 * * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Top users/processes display for Unix
35 * Version 3
39 * This file contains various handy utilities used by top.
42 #include "os.h"
43 #include <ctype.h>
44 #ifdef HAVE_STDARG_H
45 #include <stdarg.h>
46 #else
47 #undef DEBUG
48 #endif
49 #include "top.h"
50 #include "utils.h"
52 static int
53 alldigits(char *s)
56 int ch;
58 while ((ch = *s++) != '\0')
60 if (!isdigit(ch))
62 return 0;
65 return 1;
68 int
69 atoiwi(char *str)
72 register int len;
74 len = strlen(str);
75 if (len != 0)
77 if (strncmp(str, "infinity", len) == 0 ||
78 strncmp(str, "all", len) == 0 ||
79 strncmp(str, "maximum", len) == 0)
81 return(Infinity);
83 else if (alldigits(str))
85 return(atoi(str));
87 else
89 return(Invalid);
92 return(0);
96 * itoa - convert integer (decimal) to ascii string for positive numbers
97 * only (we don't bother with negative numbers since we know we
98 * don't use them).
102 * How do we know that 16 will suffice?
103 * Because the biggest number that we will
104 * ever convert will be 2^32-1, which is 10
105 * digits.
108 char *
109 itoa(int val)
112 register char *ptr;
113 static char buffer[16]; /* result is built here */
114 /* 16 is sufficient since the largest number
115 we will ever convert will be 2^32-1,
116 which is 10 digits. */
118 ptr = buffer + sizeof(buffer);
119 *--ptr = '\0';
120 if (val == 0)
122 *--ptr = '0';
124 else while (val != 0)
126 *--ptr = (val % 10) + '0';
127 val /= 10;
129 return(ptr);
133 * itoa7(val) - like itoa, except the number is right justified in a 7
134 * character field. This code is a duplication of itoa instead of
135 * a front end to a more general routine for efficiency.
138 char *
139 itoa_w(int val, int w)
142 char *ptr;
143 char *eptr;
144 static char buffer[16]; /* result is built here */
145 /* 16 is sufficient since the largest number
146 we will ever convert will be 2^32-1,
147 which is 10 digits. */
149 if (w > 15)
151 w = 15;
153 eptr = ptr = buffer + sizeof(buffer);
154 *--ptr = '\0';
155 if (val == 0)
157 *--ptr = '0';
159 else while (val != 0)
161 *--ptr = (val % 10) + '0';
162 val /= 10;
164 while (ptr >= eptr - w)
166 *--ptr = ' ';
168 return(ptr);
171 char *
172 itoa7(int val)
175 return itoa_w(val, 7);
179 * digits(val) - return number of decimal digits in val. Only works for
180 * positive numbers. If val < 0 then digits(val) == 0, but
181 * digits(0) == 1.
185 digits(int val)
188 register int cnt = 0;
190 if (val == 0)
192 return 1;
194 while (val > 0)
196 cnt++;
197 val /= 10;
199 return(cnt);
203 * printable(char *str) - make the string pointed to by "str" into one that is
204 * printable (i.e.: all ascii), by converting all non-printable
205 * characters into '?'. Replacements are done in place and a pointer
206 * to the original buffer is returned.
209 char *
210 printable(char *str)
213 register char *ptr;
214 register int ch;
216 ptr = str;
217 while ((ch = *ptr) != '\0')
219 if (!isprint(ch))
221 *ptr = '?';
223 ptr++;
225 return(str);
229 * strcpyend(to, from) - copy string "from" into "to" and return a pointer
230 * to the END of the string "to".
233 char *
234 strcpyend(char *to, char *from)
237 while ((*to++ = *from++) != '\0');
238 return(--to);
242 * char *
243 * homogenize(char *str)
245 * Remove unwanted characters from "str" and make everything lower case.
246 * Newly allocated string is returned: the original is not altered.
249 char *homogenize(char *str)
252 char *ans;
253 char *fr;
254 char *to;
255 int ch;
257 to = fr = ans = strdup(str);
258 while ((ch = *fr++) != '\0')
260 if (isalnum(ch))
262 *to++ = tolower(ch);
266 *to = '\0';
267 return ans;
271 * string_index(string, array) - find string in array and return index
275 string_index(char *string, char **array)
278 register int i = 0;
280 while (*array != NULL)
282 if (strcmp(string, *array) == 0)
284 return(i);
286 array++;
287 i++;
289 return(-1);
293 * char *string_list(char **strings)
295 * Create a comma-separated list of the strings in the NULL-terminated
296 * "strings". Returned string is malloc-ed and should be freed when the
297 * caller is done. Note that this is not an efficient function.
300 char *string_list(char **strings)
303 int cnt = 0;
304 char **pp;
305 char *p;
306 char *result = NULL;
307 char *resp = NULL;
309 pp = strings;
310 while ((p = *pp++) != NULL)
312 cnt += strlen(p) + 2;
315 if (cnt > 0)
317 resp = result = (char *)malloc(cnt);
318 pp = strings;
319 while ((p = *pp++) != NULL)
321 resp = strcpyend(resp, p);
322 if (*pp != NULL)
324 resp = strcpyend(resp, ", ");
329 return result;
333 * argparse(line, cntp) - parse arguments in string "line", separating them
334 * out into an argv-like array, and setting *cntp to the number of
335 * arguments encountered. This is a simple parser that doesn't understand
336 * squat about quotes.
339 char **
340 argparse(char *line, int *cntp)
343 register char *from;
344 register char *to;
345 register int cnt;
346 register int ch;
347 int length;
348 int lastch;
349 register char **argv;
350 char **argarray;
351 char *args;
353 /* unfortunately, the only real way to do this is to go thru the
354 input string twice. */
356 /* step thru the string counting the white space sections */
357 from = line;
358 lastch = cnt = length = 0;
359 while ((ch = *from++) != '\0')
361 length++;
362 if (ch == ' ' && lastch != ' ')
364 cnt++;
366 lastch = ch;
369 /* add three to the count: one for the initial "dummy" argument,
370 one for the last argument and one for NULL */
371 cnt += 3;
373 /* allocate a char * array to hold the pointers */
374 argarray = (char **)malloc(cnt * sizeof(char *));
376 /* allocate another array to hold the strings themselves */
377 args = (char *)malloc(length+2);
379 /* initialization for main loop */
380 from = line;
381 to = args;
382 argv = argarray;
383 lastch = '\0';
385 /* create a dummy argument to keep getopt happy */
386 *argv++ = to;
387 *to++ = '\0';
388 cnt = 2;
390 /* now build argv while copying characters */
391 *argv++ = to;
392 while ((ch = *from++) != '\0')
394 if (ch != ' ')
396 if (lastch == ' ')
398 *to++ = '\0';
399 *argv++ = to;
400 cnt++;
402 *to++ = ch;
404 lastch = ch;
406 *to++ = '\0';
408 /* set cntp and return the allocated array */
409 *cntp = cnt;
410 return(argarray);
414 * percentages(cnt, out, new, old, diffs) - calculate percentage change
415 * between array "old" and "new", putting the percentages i "out".
416 * "cnt" is size of each array and "diffs" is used for scratch space.
417 * The array "old" is updated on each call.
418 * The routine assumes modulo arithmetic. This function is especially
419 * useful on BSD mchines for calculating cpu state percentages.
422 long
423 percentages(int cnt, int *out, long *new, long *old, long *diffs)
426 register int i;
427 register long change;
428 register long total_change;
429 register long *dp;
430 long half_total;
432 /* initialization */
433 total_change = 0;
434 dp = diffs;
436 /* calculate changes for each state and the overall change */
437 for (i = 0; i < cnt; i++)
439 if ((change = *new - *old) < 0)
441 /* this only happens when the counter wraps */
442 change = (int)
443 ((unsigned long)*new-(unsigned long)*old);
445 total_change += (*dp++ = change);
446 *old++ = *new++;
449 /* avoid divide by zero potential */
450 if (total_change == 0)
452 total_change = 1;
455 /* calculate percentages based on overall change, rounding up */
456 half_total = total_change / 2l;
457 for (i = 0; i < cnt; i++)
459 *out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
462 /* return the total in case the caller wants to use it */
463 return(total_change);
467 * errmsg(errnum) - return an error message string appropriate to the
468 * error number "errnum". This is a substitute for the System V
469 * function "strerror". There appears to be no reliable way to
470 * determine if "strerror" exists at compile time, so I make do
471 * by providing something of similar functionality. For those
472 * systems that have strerror and NOT errlist, define
473 * -DHAVE_STRERROR in the module file and this function will
474 * use strerror.
477 /* externs referenced by errmsg */
479 #ifndef HAVE_STRERROR
480 #if !HAVE_DECL_SYS_ERRLIST
481 extern char *sys_errlist[];
482 #endif
484 extern int sys_nerr;
485 #endif
487 char *
488 errmsg(int errnum)
491 #ifdef HAVE_STRERROR
492 char *msg = strerror(errnum);
493 if (msg != NULL)
495 return msg;
497 #else
498 if (errnum > 0 && errnum < sys_nerr)
500 return((char *)(sys_errlist[errnum]));
502 #endif
503 return("No error");
506 /* format_percent(v) - format a double as a percentage in a manner that
507 * does not exceed 5 characters (excluding any trailing
508 * percent sign). Since it is possible for the value
509 * to exceed 100%, we format such values with no fractional
510 * component to fit within the 5 characters.
513 char *
514 format_percent(double v)
517 static char result[10];
519 /* enumerate the possibilities */
520 if (v < 0 || v >= 100000.)
522 /* we dont want to try extreme values */
523 strcpy(result, " ???");
525 else if (v > 99.99)
527 sprintf(result, "%5.0f", v);
529 else
531 sprintf(result, "%5.2f", v);
534 return result;
537 /* format_time(seconds) - format number of seconds into a suitable
538 * display that will fit within 6 characters. Note that this
539 * routine builds its string in a static area. If it needs
540 * to be called more than once without overwriting previous data,
541 * then we will need to adopt a technique similar to the
542 * one used for format_k.
545 /* Explanation:
546 We want to keep the output within 6 characters. For low values we use
547 the format mm:ss. For values that exceed 999:59, we switch to a format
548 that displays hours and fractions: hhh.tH. For values that exceed
549 999.9, we use hhhh.t and drop the "H" designator. For values that
550 exceed 9999.9, we use "???".
553 void *
554 format_time(long seconds, char *result, int len)
557 /* sanity protection */
558 if (seconds < 0 || seconds > (99999l * 360l))
560 strcpy(result, " ???");
562 else if (seconds >= (1000l * 60l))
564 /* alternate (slow) method displaying hours and tenths */
565 snprintf(result, len - 1, "%5.1fH", (double)seconds / (double)(60l * 60l));
567 /* It is possible that the sprintf took more than 6 characters.
568 If so, then the "H" appears as result[6]. If not, then there
569 is a \0 in result[6]. Either way, it is safe to step on.
571 if (len / sizeof(result[0]) > 6)
572 result[6] = '\0';
574 else
576 /* standard method produces MMM:SS */
577 /* we avoid printf as must as possible to make this quick */
578 snprintf(result, len - 1, "%3ld:%02ld", seconds / 60l, seconds % 60l);
580 return(result);
584 * format_k(amt) - format a kilobyte memory value, returning a string
585 * suitable for display. Returns a pointer to a static
586 * area that changes each call. "amt" is converted to a
587 * string with a trailing "K". If "amt" is 10000 or greater,
588 * then it is formatted as megabytes (rounded) with a
589 * trailing "M".
593 * Compromise time. We need to return a string, but we don't want the
594 * caller to have to worry about freeing a dynamically allocated string.
595 * Unfortunately, we can't just return a pointer to a static area as one
596 * of the common uses of this function is in a large call to sprintf where
597 * it might get invoked several times. Our compromise is to maintain an
598 * array of strings and cycle thru them with each invocation. We make the
599 * array large enough to handle the above mentioned case. The constant
600 * NUM_STRINGS defines the number of strings in this array: we can tolerate
601 * up to NUM_STRINGS calls before we start overwriting old information.
602 * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer
603 * to convert the modulo operation into something quicker. What a hack!
606 #define NUM_STRINGS 8
608 char *
609 format_k(long amt)
612 static char retarray[NUM_STRINGS][16];
613 static int index = 0;
614 register char *ret;
615 register char tag = 'K';
617 ret = retarray[index];
618 index = (index + 1) % NUM_STRINGS;
620 if (amt >= 10000)
622 amt = (amt + 512) / 1024;
623 tag = 'M';
624 if (amt >= 10000)
626 amt = (amt + 512) / 1024;
627 tag = 'G';
631 snprintf(ret, sizeof(retarray[index])-1, "%ld%c", amt, tag);
633 return(ret);
637 * Time keeping functions.
640 static struct timeval lasttime = { 0, 0 };
641 static unsigned int elapsed_msecs = 0;
643 void
644 time_get(struct timeval *tv)
647 /* get the current time */
648 #ifdef HAVE_GETTIMEOFDAY
649 gettimeofday(tv, NULL);
650 #else
651 tv->tv_sec = (long)time(NULL);
652 tv->tv_usec = 0;
653 #endif
656 void
657 time_mark(struct timeval *tv)
660 struct timeval thistime;
661 struct timeval timediff;
663 /* if the caller didnt provide one then use our own */
664 if (tv == NULL)
666 tv = &thistime;
669 /* get the current time */
670 #ifdef HAVE_GETTIMEOFDAY
671 gettimeofday(tv, NULL);
672 #else
673 tv->tv_sec = (long)time(NULL);
674 tv->tv_usec = 0;
675 #endif
677 /* calculate the difference */
678 timediff.tv_sec = tv->tv_sec - lasttime.tv_sec;
679 timediff.tv_usec = tv->tv_usec - lasttime.tv_usec;
680 if (timediff.tv_usec < 0) {
681 timediff.tv_sec--;
682 timediff.tv_usec += 1000000;
685 /* convert to milliseconds */
686 elapsed_msecs = timediff.tv_sec * 1000 + timediff.tv_usec / 1000;
687 if (elapsed_msecs == 0)
689 elapsed_msecs = 1;
692 /* save for next time */
693 lasttime = *tv;
696 unsigned int
697 time_elapsed()
700 return elapsed_msecs;
703 unsigned int
704 diff_per_second(unsigned int x, unsigned int y)
707 return (y > x ? UINT_MAX - y + x + 1 : x - y) * 1000 / elapsed_msecs;
710 static int debug_on = 0;
712 #ifdef DEBUG
713 FILE *debugfile;
714 #endif
716 void
717 debug_set(int i)
720 debug_on = i;
721 #ifdef DEBUG
722 debugfile = fopen("/tmp/top.debug", "w");
723 #endif
726 #ifdef DEBUG
727 void
728 xdprintf(char *fmt, ...)
731 va_list argp;
733 va_start(argp, fmt);
735 if (debug_on)
737 vfprintf(debugfile, fmt, argp);
738 fflush(debugfile);
741 va_end(argp);
743 #endif