#ifndef lint
static  char sccsid[] = "@(#)chill.c 1.1 94/10/31 Copyr 1988 Sun Micro";
#endif

/*
 * Copyright (c) 1988 by Sun Microsystems, Inc.
 */

  /*
  **
  **  NOTE: The original version (which allocated virtmem == maxmem
  **  and ran around cycle times) which was designed to flush out all
  **  other pages.  But subsequent paging behavior indicates that not
  **  all pages were flushed.  One failure mode I can see is as
  **  follows.
  **
  **  Let all of main memory be represented as ten page slots,
  **  numbered 0 to 9.  Let the virtual memory pages in order be
  **  labeled a, b, ..., j.  Let the suspected unflushed page be page
  **  0.  If the paging daemon hand were at page 1, and all but page 0
  **  were free, and the free pages were in reverse order, we would
  **  have the following picture after the first 9 accesses, none of
  **  which would cause a page fault:
  **
  **		+ hand
  **		v
  **	    0   1   2   3   4   5   6   7   8   9
  **	    X   i   h   g   f   e   d   c   b   a
  **
  **	On the 10th access, we get
  **
  **		    + hand
  **		    v
  **	    0   1   2   3   4   5   6   7   8   9
  **	    X   j   h   g   f   e   d   c   b   a
  **
  **	We restart the cycle, and cause no faults on a..h.
  **	Access 9 yields
  **
  **			+ hand
  **			v
  **	    0   1   2   3   4   5   6   7   8   9
  **	    X   j   i   g   f   e   d   c   b   a
  **
  **	and access 10 does not cause a page fault.
  **
  **  As you can see, page 0 is still, X, the unknown; it has not been
  **  forced out.
  **
  **  In view of this, the algorithm has been changed.  The new
  **  algorithm is to allocate 2X maxmem, and cycle through it once.
  **
  **  version:	@(#)chill.c 1.1 94/10/31 hacked from page1.c 1.6 87/06/20
  */

#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <nlist.h>

char	*rindex();
char	*malloc();
off_t	lseek();

#define	setbasename(target, source) \
do {char *s = source, *t = rindex(s,'/'); target = t ? t + 1 : s;} while (0)

#define streq(s, t)	(strcmp(s, t) == 0)

char *Usage="Usage: %s [-f n] [-c n] [-m n]\n";
char *cmdname;
static int pagesize;
static int cycles = 1;
static int factor = 2;

main(argc, argv)
	int argc;
	char **argv;
{
	char *ptr;
	int i;
	int cycle;
	int memory = 0;
	int number;

	setbasename(cmdname, argv[0]);
	pagesize = getpagesize();

	argc--, argv++;
	while (*argv) {
		if (argv[0][0] == '-' && argv[0][2] == 0 && argc > 1) {
			number = atoi(argv[1]);
			if (number <= 0)
				usage();

			switch (argv[0][1]) {
			case 'c':
				cycles = number;
				break;
			case 'm':
				memory = number;
				break;
			case 'f':
				factor = number;
				break;
			default:
				usage();
				break;
			}
			argc--, argv++;
		} else
			usage();

		argc--, argv++;
	}

	if (memory == 0)
		memory = getmaxmem() * pagesize;

	memory *= factor;

	ptr = malloc((unsigned)memory);
	if (ptr == 0) {
		(void)fprintf(stderr, "%s: can't malloc %d -- exiting\n",
		    cmdname, memory);
		exit(1);
	}

	for (cycle = 0; cycle < cycles; cycle++)
		for (i = 0; i < memory; i+=pagesize)
			ptr[i] = 1;

	_exit(0);
	/*NOTREACHED*/
}

usage()
{
	(void)fprintf(stderr, Usage, cmdname);
	exit(1);
}



static struct nlist nl[] = {
	{"_maxmem" }, {""}, 
};

getmaxmem()
{
	int fd, maxmem;
	
	(void)nlist("/vmunix", nl);
	if (nl[0].n_value == 0) {
		(void)fprintf(stderr, "%s: bad namelist -- exiting\n",
		    cmdname);
		exit(1);
	}
	if ((fd = open("/dev/kmem", 0)) < 0) {
		(void)fprintf(stderr, "%s: open: ", cmdname);
	    	perror("/dev/kmem");
		exit(1);
	}
	if (lseek(fd, (off_t)nl[0].n_value, 0) == -1) {
		(void)fprintf(stderr, "%s: ", cmdname);
		perror("lseek");
		exit(1);
	}
	if (read(fd, (char *)&maxmem, sizeof(maxmem)) != sizeof (maxmem)) {
		(void)fprintf(stderr, "%s: ", cmdname);
		perror("read");
		exit(1);
	}
	return (maxmem);
}
