/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <dirent.h>
#include <limits.h>
#include <libproc.h>
#include <sys/sysmacros.h>
#include <libgen.h>
#include <thread.h>
#ifndef TRUE
#endif
#ifndef FALSE
#define FALSE 0
#endif
static char *command;
static volatile int interrupt;
static int Fflag;
static void intr(int);
static void usage();
/* subopt */
static char *suboptstr[] = {
"heap",
"stack",
"anon",
};
enum suboptenum {
};
static size_t
{
char *endptr;
return (INVPGSZ);
switch (*endptr) {
case 'T':
case 't':
sz *= 1024;
/*FALLTHRU*/
case 'G':
case 'g':
sz *= 1024;
/*FALLTHRU*/
case 'M':
case 'm':
sz *= 1024;
/*FALLTHRU*/
case 'K':
case 'k':
sz *= 1024;
/*FALLTHRU*/
case 'B':
case 'b':
default:
break;
}
return (sz);
}
/* pgsz array sufficient for max page sizes */
static int nelem;
static void
getpgsz()
{
" sizes\n", command);
exit(125);
}
}
static size_t
{
int i;
} else {
for (i = nelem - 1; i >= 0; i--) {
break;
break;
}
}
}
"%s: invalid page size specified (%s)\n",
} else {
usage();
}
exit(125);
}
return (pgsz);
}
static void
usage()
{
"usage:\t%s -o option[,option] [-F] cmd | -p pid ...\n"
" (set preferred page size of cmd or each process)\n"
" -o option[,option]: options are\n"
" stack=sz\n"
" heap=sz\n"
" anon=sz (sz: valid page size or 0 (zero))\n"
" -F: force grabbing of the target process(es)\n"
" cmd: launch command\n"
" -p pid ...: process id list\n",
command);
exit(125);
}
int
{
int errflg = 0;
int status;
command++;
else
getpgsz();
/* options */
switch (opt) {
case 'o': /* options */
while (*options != '\0') {
switch (subopt) {
case E_HEAP:
case E_STACK:
case E_ANON:
break;
default:
errflg = 1;
break;
}
}
break;
case 'F': /* force grabbing (no O_EXCL) */
Fflag = PGRAB_FORCE;
break;
case 'p':
cflag = 0;
break;
default:
errflg = 1;
break;
}
}
usage();
}
/* catch signals from terminal */
int err;
switch (err) {
case C_PERM:
"%s: cannot control set-id or "
"unreadable object file: %s\n",
break;
case C_LP64:
"%s: cannot control _LP64 "
break;
case C_NOEXEC:
exit(126);
break;
case C_NOENT:
exit(127);
break;
case C_STRANGE:
break;
default:
break;
}
exit(125);
}
exit(125);
}
/*
* release the command to run, wait for it and
* return it's exit status if we can.
*/
do {
if (pid == -1) {
exit(125);
}
/*
* Pass thru the child's exit value.
*/
}
/* process pids */
char *arg;
int gret;
/* get the specified pid and the psinfo struct */
if (pid == -1) {
"\tdo not use -p option"
" to launch a command\n");
}
err++;
if (rc != 0) {
err++;
}
} else {
switch (gret) {
case G_SYS:
"size for system process: %d [ %s ]\n",
err++;
break;
case G_SELF:
/* do it to own self */
if (rc != 0) {
"size failed for self: %d\n",
err++;
}
break;
default:
err++;
break;
}
}
}
exit(125);
return (0);
}
/* ARGSUSED */
static void
{
interrupt = 1;
}
/* ------ begin specific code ------ */
/* set process page size */
/*ARGSUSED*/
static int
{
int rc;
int err = 0;
int i;
continue;
if (i == E_ANON)
else {
}
if (rc < 0) {
err++;
}
}
return (err);
}
/*
* Walk through the process' address space segments. Set all anonymous
* segments to the new page size.
*/
static int
{
int fd;
int rc;
/*
* Setting the page size for anonymous segments on a process before it
* has run will have no effect, since it has not configured anonymous
* memory and the page size setting is not "sticky" inside the kernel.
* Any anonymous memory subsequently mapped will have the default page
* size.
*/
if (cflag)
return (0);
return (-1);
return (-1);
if (pgsz == 0)
return (-1);
/* Not anon. */
continue;
/* Can't change pagesize for shared mappings. */
continue;
pstatus->pr_brkbase &&
/* Heap. */
continue;
/* Stack. */
continue;
/* Too small. */
continue;
}
/*
* Find the first address in the segment that is page-aligned.
*/
else
/*
* Calculate how many pages will fit in the segment.
*/
if (pgsz == 0)
else
/*
* If no aligned pages fit in the segment, ignore it.
*/
continue;
}
MC_HAT_ADVISE, mpss, 0, 0);
/*
* If an error occurs on any segment, report the error here and
* then go on to try setting the page size for the remaining
* segments.
*/
if (rc < 0) {
"failed (%s) for pid %d for anon segment at "
}
}
return (0);
}
/*
* Discover the optimal page size for the process.
* Do this by creating a 4M segment in the target process, set its pagesize
* to 0, and read the map file to discover the page size selected by the system.
*/
static size_t
{
void *addr;
return (size);
goto err;
}
goto err;
}
/*
* Touch a page in the segment so the hat mapping gets created.
*/
/*
* Read through the address map looking for our segment.
*/
break;
}
goto err;
err:
if (addr != MAP_FAILED) {
"%s: couldn't delete segment at %p\n",
}
}
if (fd != -1)
return (size);
}
#ifdef _LP64
#endif
static caddr_t
/* ARGSUSED */
{
#ifdef _LP64
if (dmodel == PR_MODEL_ILP32) {
}
#endif
}