2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <strings.h>
2N/A#include <sys/shm.h>
2N/A#include <sys/mman.h>
2N/A#include <fcntl.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <errno.h>
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/auxv.h>
2N/A#include <stdarg.h>
2N/A#include <syslog.h>
2N/A#include <sys/param.h>
2N/A#include <sys/sysmacros.h>
2N/A#include <procfs.h>
2N/A#include <dlfcn.h>
2N/A#include <assert.h>
2N/A#include <libintl.h>
2N/A#include <locale.h>
2N/A
2N/Aextern int gmatch(const char *s, const char *p);
2N/A
2N/A#pragma init(__madvmain)
2N/A
2N/Astatic FILE *errfp = NULL;
2N/Astatic const char *madvident = "madv.so.1";
2N/Astatic int pagesize;
2N/Astatic int advice_all = -1;
2N/Astatic int advice_heap = -1;
2N/Astatic int advice_shm = -1;
2N/Astatic int advice_ism = -1;
2N/Astatic int advice_dism = -1;
2N/Astatic int advice_map = -1;
2N/Astatic int advice_mapshared = -1;
2N/Astatic int advice_mapprivate = -1;
2N/Astatic int advice_mapanon = -1;
2N/A
2N/A/* environment variables */
2N/A
2N/A#define ENV_MADV "MADV"
2N/A#define ENV_MADVCFGFILE "MADVCFGFILE"
2N/A#define ENV_MADVERRFILE "MADVERRFILE"
2N/A
2N/A/* config file */
2N/A
2N/A#define DEF_MADVCFGFILE "/etc/madv.conf"
2N/A#define MAXLINELEN MAXPATHLEN + 64
2N/A#define CFGDELIMITER ':'
2N/A#define ARGDELIMITER ' '
2N/A
2N/A/*
2N/A * avoid malloc which causes certain applications to crash
2N/A */
2N/Astatic char lbuf[MAXLINELEN];
2N/Astatic char pbuf[MAXPATHLEN];
2N/A
2N/A#ifdef MADVDEBUG
2N/A#define ENV_MADVDEBUG "MADVDEBUG"
2N/A#define MADVPRINT(x, y) if (madvdebug & x) (void) fprintf y;
2N/A
2N/Astatic int madvdebug = 0;
2N/A#else
2N/A#define MADVPRINT(x, y)
2N/A#endif
2N/A
2N/A/*
2N/A * advice options
2N/A */
2N/Astatic char *legal_optstr[] = {
2N/A "madv",
2N/A "heap",
2N/A "shm",
2N/A "ism",
2N/A "dism",
2N/A "map",
2N/A "mapshared",
2N/A "mapprivate",
2N/A "mapanon",
2N/A NULL
2N/A};
2N/A
2N/Aenum optenum {
2N/A OPT_MADV,
2N/A OPT_HEAP,
2N/A OPT_SHM,
2N/A OPT_ISM,
2N/A OPT_DISM,
2N/A OPT_MAP,
2N/A OPT_MAPSHARED,
2N/A OPT_MAPPRIVATE,
2N/A OPT_MAPANON
2N/A};
2N/A
2N/A/*
2N/A * Advice values
2N/A * These need to correspond to the order of the MADV_ flags in mman.h
2N/A * since the position infers the value for the flag.
2N/A */
2N/Astatic char *legal_madvice[] = {
2N/A "normal",
2N/A "random",
2N/A "sequential",
2N/A "willneed_NOT_SUPPORTED!",
2N/A "dontneed_NOT_SUPPORTED!",
2N/A "free_NOT_SUPPORTED!",
2N/A "access_default",
2N/A "access_lwp",
2N/A "access_many",
2N/A "access_many_pset",
2N/A NULL
2N/A};
2N/A
2N/A#if !defined(TEXT_DOMAIN)
2N/A#define TEXT_DOMAIN "SYS_TEST"
2N/A#endif
2N/A
2N/A/*PRINTFLIKE2*/
2N/Astatic void
2N/Amadverr(FILE *fp, char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A va_start(ap, fmt);
2N/A if (fp)
2N/A (void) vfprintf(fp, fmt, ap);
2N/A else
2N/A vsyslog(LOG_ERR, fmt, ap);
2N/A va_end(ap);
2N/A}
2N/A
2N/A/*
2N/A * Return the pointer to the fully-resolved path name of the process's
2N/A * executable file obtained from the AT_SUN_EXECNAME aux vector entry.
2N/A */
2N/Astatic const char *
2N/Amygetexecname(void)
2N/A{
2N/A const char *execname = NULL;
2N/A static auxv_t auxb;
2N/A
2N/A /*
2N/A * The first time through, read the initial aux vector that was
2N/A * passed to the process at exec(2). Only do this once.
2N/A */
2N/A int fd = open("/proc/self/auxv", O_RDONLY);
2N/A
2N/A if (fd >= 0) {
2N/A while (read(fd, &auxb, sizeof (auxv_t)) == sizeof (auxv_t)) {
2N/A if (auxb.a_type == AT_SUN_EXECNAME) {
2N/A execname = auxb.a_un.a_ptr;
2N/A break;
2N/A }
2N/A }
2N/A (void) close(fd);
2N/A }
2N/A return (execname);
2N/A}
2N/A
2N/A/*
2N/A * Return the process's current brk base and size.
2N/A */
2N/Astatic int
2N/Amygetbrk(uintptr_t *base, size_t *size)
2N/A{
2N/A int fd;
2N/A pstatus_t ps;
2N/A int rc;
2N/A
2N/A fd = open("/proc/self/status", O_RDONLY);
2N/A
2N/A if (fd >= 0) {
2N/A if (read(fd, &ps, sizeof (ps)) == sizeof (ps)) {
2N/A *base = ps.pr_brkbase;
2N/A *size = ps.pr_brksize;
2N/A rc = 0;
2N/A } else {
2N/A rc = errno;
2N/A }
2N/A (void) close(fd);
2N/A } else {
2N/A rc = errno;
2N/A }
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * Check if exec name matches cfgname found in madv cfg file.
2N/A */
2N/Astatic int
2N/Afnmatch(const char *execname, char *cfgname, char *cwd)
2N/A{
2N/A const char *ename;
2N/A int rc;
2N/A
2N/A /* cfgname should not have a '/' unless it begins with one */
2N/A if (cfgname[0] == '/') {
2N/A /*
2N/A * if execname does not begin with a '/', prepend the
2N/A * current directory.
2N/A */
2N/A if (execname[0] != '/') {
2N/A ename = (const char *)strcat(cwd, execname);
2N/A } else
2N/A ename = execname;
2N/A } else { /* simple cfg name */
2N/A if (ename = strrchr(execname, '/'))
2N/A /* execname is a path name - get the base name */
2N/A ename++;
2N/A else
2N/A ename = execname;
2N/A }
2N/A rc = gmatch(ename, cfgname);
2N/A MADVPRINT(2, (stderr, "gmatch: %s %s %s %d\n",
2N/A cfgname, ename, execname, rc));
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * Check if string matches any of exec arguments.
2N/A */
2N/Astatic int
2N/Aargmatch(char *str)
2N/A{
2N/A int fd;
2N/A psinfo_t pi;
2N/A int rc = 0;
2N/A int arg;
2N/A char **argv;
2N/A
2N/A fd = open("/proc/self/psinfo", O_RDONLY);
2N/A
2N/A if (fd >= 0) {
2N/A if (read(fd, &pi, sizeof (pi)) == sizeof (pi)) {
2N/A argv = (char **)pi.pr_argv;
2N/A argv++;
2N/A MADVPRINT(2, (stderr, "argmatch: %s ", str));
2N/A for (arg = 1; arg < pi.pr_argc; arg++, argv++) {
2N/A if (rc = gmatch(*argv, str)) {
2N/A MADVPRINT(2, (stderr, "%s ", *argv));
2N/A break;
2N/A }
2N/A }
2N/A MADVPRINT(2, (stderr, "%d\n", rc));
2N/A } else {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: /proc/self/psinfo read failed [%s]\n"),
2N/A madvident, strerror(errno));
2N/A }
2N/A (void) close(fd);
2N/A } else {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: /proc/self/psinfo open failed [%s]\n"),
2N/A madvident, strerror(errno));
2N/A }
2N/A return (rc);
2N/A}
2N/A
2N/Astatic int
2N/Aempty(char *str)
2N/A{
2N/A char c;
2N/A
2N/A while ((c = *str) == '\n' || c == ' ' || c == '\t')
2N/A str++;
2N/A return (*str == '\0');
2N/A}
2N/A
2N/Astatic int
2N/Astrtoadv(char *advstr)
2N/A{
2N/A char *dummy, *locstr = advstr;
2N/A
2N/A return (getsubopt(&locstr, legal_madvice, &dummy));
2N/A}
2N/A
2N/Astatic void
2N/Aadvice_opts(char *optstr, const char *execname, char *cfgfile, int lineno)
2N/A{
2N/A char *value;
2N/A int opt;
2N/A int advice = 0;
2N/A
2N/A while (*optstr != '\0') {
2N/A opt = getsubopt(&optstr, legal_optstr, &value);
2N/A if (opt < 0) {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: invalid advice option (%s)"
2N/A " for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile, lineno);
2N/A break;
2N/A } else if (!value) {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: option missing advice"
2N/A " for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, execname, cfgfile, lineno);
2N/A break;
2N/A }
2N/A advice = strtoadv(value);
2N/A if (advice < 0) {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: invalid advice specified (%s)"
2N/A " for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile, lineno);
2N/A break;
2N/A }
2N/A switch (opt) {
2N/A case OPT_MADV:
2N/A advice_all = advice;
2N/A break;
2N/A case OPT_HEAP:
2N/A if (advice_heap < 0) {
2N/A advice_heap = advice;
2N/A } else {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: duplicate advice specified "
2N/A "(%s) for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile,
2N/A lineno);
2N/A }
2N/A break;
2N/A case OPT_SHM:
2N/A if (advice_shm < 0) {
2N/A advice_shm = advice;
2N/A } else {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: duplicate advice specified "
2N/A "(%s) for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile,
2N/A lineno);
2N/A }
2N/A break;
2N/A case OPT_ISM:
2N/A if (advice_ism < 0) {
2N/A advice_ism = advice;
2N/A } else {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: duplicate advice specified "
2N/A "(%s) for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile,
2N/A lineno);
2N/A }
2N/A break;
2N/A case OPT_DISM:
2N/A if (advice_dism < 0) {
2N/A advice_dism = advice;
2N/A } else {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: duplicate advice specified "
2N/A "(%s) for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile,
2N/A lineno);
2N/A }
2N/A break;
2N/A case OPT_MAP:
2N/A if (advice_map < 0) {
2N/A advice_map = advice;
2N/A } else {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: duplicate advice specified "
2N/A "(%s) for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile,
2N/A lineno);
2N/A }
2N/A break;
2N/A case OPT_MAPSHARED:
2N/A if (advice_mapshared < 0) {
2N/A advice_mapshared = advice;
2N/A } else {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: duplicate advice specified "
2N/A "(%s) for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile,
2N/A lineno);
2N/A }
2N/A break;
2N/A case OPT_MAPPRIVATE:
2N/A if (advice_mapprivate < 0) {
2N/A advice_mapprivate = advice;
2N/A } else {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: duplicate advice specified "
2N/A "(%s) for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile,
2N/A lineno);
2N/A }
2N/A break;
2N/A case OPT_MAPANON:
2N/A if (advice_mapanon < 0) {
2N/A advice_mapanon = advice;
2N/A } else {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: duplicate advice specified "
2N/A "(%s) for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile,
2N/A lineno);
2N/A }
2N/A break;
2N/A default:
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: invalid advice option (%s)"
2N/A " for %s - cfgfile: %s, line: %d\n"),
2N/A madvident, value, execname, cfgfile, lineno);
2N/A break;
2N/A }
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/A__madvmain()
2N/A{
2N/A char *cfgfile, *errfile;
2N/A FILE *fp = NULL;
2N/A const char *execname;
2N/A char *cwd;
2N/A int cwdlen;
2N/A char *tok, *tokadv, *tokarg;
2N/A char *str, *envadv;
2N/A int lineno = 0;
2N/A int advice;
2N/A uintptr_t brkbase, brkend;
2N/A size_t brksize;
2N/A int rc;
2N/A char *locale;
2N/A
2N/A /*
2N/A * If a private error file is indicated then set the locale
2N/A * for error messages for the duration of this routine.
2N/A * Error messages destined for syslog should not be translated
2N/A * and thus come from the default C locale.
2N/A */
2N/A if ((errfile = getenv(ENV_MADVERRFILE)) != NULL) {
2N/A errfp = fopen(errfile, "aF");
2N/A if (errfp) {
2N/A locale = setlocale(LC_MESSAGES, "");
2N/A } else {
2N/A madverr(NULL, dgettext(TEXT_DOMAIN,
2N/A "%s: cannot open error file: %s [%s]\n"),
2N/A madvident, errfile, strerror(errno));
2N/A }
2N/A }
2N/A
2N/A#ifdef MADVDEBUG
2N/A if (str = getenv(ENV_MADVDEBUG))
2N/A madvdebug = atoi(str);
2N/A#endif
2N/A
2N/A if (envadv = getenv(ENV_MADV)) {
2N/A if ((advice = strtoadv(envadv)) >= 0)
2N/A advice_all = advice;
2N/A else
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: invalid advice specified: MADV=%s\n"),
2N/A madvident, envadv);
2N/A }
2N/A
2N/A /*
2N/A * Open specified cfg file or default one.
2N/A */
2N/A if (cfgfile = getenv(ENV_MADVCFGFILE)) {
2N/A fp = fopen(cfgfile, "rF");
2N/A if (!fp) {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: cannot open configuration file: %s [%s]\n"),
2N/A madvident, cfgfile, strerror(errno));
2N/A }
2N/A } else {
2N/A cfgfile = DEF_MADVCFGFILE;
2N/A fp = fopen(cfgfile, "rF");
2N/A }
2N/A
2N/A if (fp) {
2N/A execname = mygetexecname();
2N/A
2N/A cwd = getcwd(pbuf, MAXPATHLEN);
2N/A if (!cwd)
2N/A return;
2N/A
2N/A cwd = strcat(cwd, "/");
2N/A cwdlen = strlen(cwd);
2N/A
2N/A while (fgets(lbuf, MAXLINELEN, fp)) {
2N/A lineno++;
2N/A
2N/A /*
2N/A * Make sure line wasn't truncated.
2N/A */
2N/A if (strlen(lbuf) >= MAXLINELEN - 1) {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: invalid entry, "
2N/A "line too long - cfgfile:"
2N/A " %s, line: %d\n"),
2N/A madvident, cfgfile, lineno);
2N/A continue;
2N/A }
2N/A
2N/A if (empty(lbuf))
2N/A continue;
2N/A
2N/A /*
2N/A * Get advice options.
2N/A * Parse right to left in case delimiter is in name.
2N/A */
2N/A if (!(tokadv = strrchr(lbuf, CFGDELIMITER))) {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: no delimiter specified - cfgfile:"
2N/A " %s, line: %d\n"),
2N/A madvident, cfgfile, lineno);
2N/A continue;
2N/A }
2N/A *tokadv++ = '\0';
2N/A
2N/A /*
2N/A * Remove newline from end of advice options.
2N/A */
2N/A if (str = strrchr(tokadv, '\n'))
2N/A *str = '\0';
2N/A
2N/A /*
2N/A * Get optional argument string.
2N/A */
2N/A if (tokarg = strrchr(lbuf, ARGDELIMITER)) {
2N/A *tokarg++ = '\0';
2N/A }
2N/A
2N/A /*
2N/A * Compare exec name.
2N/A */
2N/A tok = lbuf;
2N/A if (!fnmatch(execname, tok, cwd)) {
2N/A tokadv = tokarg = NULL;
2N/A cwd[cwdlen] = '\0';
2N/A continue;
2N/A }
2N/A
2N/A /*
2N/A * Compare arguments if argument string specified.
2N/A */
2N/A if (tokarg &&
2N/A !empty(tokarg) &&
2N/A !argmatch(tokarg)) {
2N/A tokadv = tokarg = NULL;
2N/A cwd[cwdlen] = '\0';
2N/A continue;
2N/A }
2N/A
2N/A /*
2N/A * Parse advice options.
2N/A * If empty, any advice from ENV_MADV is reset.
2N/A */
2N/A if (empty(tokadv)) {
2N/A advice_all = -1;
2N/A } else {
2N/A advice_opts(tokadv, execname, cfgfile, lineno);
2N/A }
2N/A break;
2N/A }
2N/A (void) fclose(fp);
2N/A }
2N/A
2N/A /*
2N/A * Pagesize needed for proper aligning by brk interpose.
2N/A */
2N/A pagesize = sysconf(_SC_PAGESIZE);
2N/A
2N/A /*
2N/A * Apply global advice if set.
2N/A * Specific options in the cfgfile take precedence.
2N/A */
2N/A if (advice_all >= 0) {
2N/A if (advice_heap < 0)
2N/A advice_heap = advice_all;
2N/A if (advice_shm < 0)
2N/A advice_shm = advice_all;
2N/A if (advice_map < 0)
2N/A advice_map = advice_all;
2N/A }
2N/A
2N/A MADVPRINT(2, (stderr, "advice_all %d\n", advice_all));
2N/A MADVPRINT(2, (stderr, "advice_heap %d\n", advice_heap));
2N/A MADVPRINT(2, (stderr, "advice_shm %d\n", advice_shm));
2N/A MADVPRINT(2, (stderr, "advice_ism %d\n", advice_ism));
2N/A MADVPRINT(2, (stderr, "advice_dism %d\n", advice_dism));
2N/A MADVPRINT(2, (stderr, "advice_map %d\n", advice_map));
2N/A MADVPRINT(2, (stderr, "advice_mapshared %d\n", advice_mapshared));
2N/A MADVPRINT(2, (stderr, "advice_mapprivate %d\n", advice_mapprivate));
2N/A MADVPRINT(2, (stderr, "advice_mapanon %d\n", advice_mapanon));
2N/A
2N/A /*
2N/A * If heap advice is specified, apply it to the existing heap.
2N/A * As the heap grows the kernel applies the advice automatically
2N/A * to new portions of the heap.
2N/A */
2N/A if (advice_heap >= 0) {
2N/A if (rc = mygetbrk(&brkbase, &brksize)) {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: /proc/self/status read failed [%s]\n"),
2N/A madvident, strerror(rc));
2N/A } else {
2N/A MADVPRINT(4, (stderr, "brkbase 0x%x brksize 0x%x\n",
2N/A brkbase, brksize));
2N/A /*
2N/A * Align start address for memcntl and apply advice
2N/A * on full pages of heap. Create a page of heap if
2N/A * it does not already exist.
2N/A */
2N/A brkend = roundup(brkbase+brksize, pagesize);
2N/A brkbase = roundup(brkbase, pagesize);
2N/A brksize = brkend - brkbase;
2N/A if (brksize < pagesize) {
2N/A if (sbrk(pagesize) == (void *)-1) {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: sbrk failed [%s]\n"),
2N/A madvident, strerror(errno));
2N/A goto out;
2N/A }
2N/A brksize = pagesize;
2N/A }
2N/A MADVPRINT(1, (stderr, "heap advice: 0x%x 0x%x %d\n",
2N/A brkbase, brksize, advice_heap));
2N/A if (memcntl((caddr_t)brkbase, brksize, MC_ADVISE,
2N/A (caddr_t)(intptr_t)advice_heap, 0, 0) < 0) {
2N/A madverr(errfp, dgettext(TEXT_DOMAIN,
2N/A "%s: memcntl() failed [%s]: heap advice\n"),
2N/A madvident, strerror(errno));
2N/A }
2N/A }
2N/A }
2N/Aout:
2N/A if (errfp) {
2N/A (void) fclose(errfp);
2N/A (void) setlocale(LC_MESSAGES, locale);
2N/A } else {
2N/A /* close log file: no-op if nothing logged to syslog */
2N/A closelog();
2N/A }
2N/A
2N/A}
2N/A
2N/A/*
2N/A * shmat interpose
2N/A */
2N/Avoid *
2N/Ashmat(int shmid, const void *shmaddr, int shmflag)
2N/A{
2N/A static caddr_t (*shmatfunc)() = NULL;
2N/A void *result;
2N/A int advice = -1;
2N/A struct shmid_ds mds;
2N/A#ifdef MADVDEBUG
2N/A int rc;
2N/A#else
2N/A /* LINTED */
2N/A int rc;
2N/A#endif
2N/A
2N/A if (!shmatfunc) {
2N/A shmatfunc = (caddr_t (*)()) dlsym(RTLD_NEXT, "shmat");
2N/A assert(shmatfunc);
2N/A }
2N/A
2N/A result = shmatfunc(shmid, shmaddr, shmflag);
2N/A
2N/A /*
2N/A * Options ism, dism take precedence over option shm.
2N/A */
2N/A if (advice_ism >= 0 && (shmflag & SHM_SHARE_MMU)) {
2N/A advice = advice_ism;
2N/A } else if (advice_dism >= 0 && (shmflag & SHM_PAGEABLE)) {
2N/A advice = advice_dism;
2N/A } else if (advice_shm >= 0) {
2N/A advice = advice_shm;
2N/A }
2N/A
2N/A /*
2N/A * Apply advice if specified and shmat succeeded.
2N/A */
2N/A if (advice >= 0 && result != (void *)-1) {
2N/A /* First determine segment size */
2N/A rc = shmctl(shmid, IPC_STAT, &mds);
2N/A MADVPRINT(4, (stderr, "shmctl rc %d errno %d\n",
2N/A strerror(errno)));
2N/A
2N/A rc = memcntl(result, mds.shm_segsz, MC_ADVISE,
2N/A (caddr_t)(intptr_t)advice, 0, 0);
2N/A MADVPRINT(1, (stderr,
2N/A "shmat advice: 0x%x 0x%x %d, rc %d errno %d\n",
2N/A result, mds.shm_segsz, advice, rc, errno));
2N/A }
2N/A
2N/A return (result);
2N/A}
2N/A
2N/A/*
2N/A * mmap interpose
2N/A */
2N/Avoid *
2N/Ammap(void *addr, size_t len, int prot, int flags, int fd, off_t pos)
2N/A{
2N/A static void *(*mmapfunc)() = NULL;
2N/A void *result;
2N/A int advice = -1;
2N/A#ifdef MADVDEBUG
2N/A int rc;
2N/A#else
2N/A /* LINTED */
2N/A int rc;
2N/A#endif
2N/A
2N/A if (!mmapfunc) {
2N/A mmapfunc = (void *(*)())dlsym(RTLD_NEXT, "mmap");
2N/A assert(mmapfunc);
2N/A }
2N/A
2N/A result = mmapfunc(addr, len, prot, flags, fd, pos);
2N/A
2N/A /*
2N/A * Option mapanon has highest precedence while option map
2N/A * has lowest precedence.
2N/A */
2N/A if (advice_mapanon >= 0 && (flags & MAP_ANON)) {
2N/A advice = advice_mapanon;
2N/A } else if (advice_mapshared >= 0 && (flags & MAP_SHARED)) {
2N/A advice = advice_mapshared;
2N/A } else if (advice_mapprivate >= 0 && (flags & MAP_PRIVATE)) {
2N/A advice = advice_mapprivate;
2N/A } else if (advice_map >= 0) {
2N/A advice = advice_map;
2N/A }
2N/A
2N/A /*
2N/A * Apply advice if specified and mmap succeeded.
2N/A */
2N/A if (advice >= 0 && result != MAP_FAILED) {
2N/A rc = memcntl(result, len, MC_ADVISE,
2N/A (caddr_t)(intptr_t)advice, 0, 0);
2N/A MADVPRINT(1, (stderr,
2N/A "mmap advice: 0x%x 0x%x %d, rc %d errno %d\n",
2N/A result, len, advice, rc, errno));
2N/A }
2N/A
2N/A return (result);
2N/A}
2N/A
2N/A#if !defined(_LP64)
2N/A/*
2N/A * mmap64 interpose
2N/A */
2N/Avoid *
2N/Ammap64(void *addr, size_t len, int prot, int flags, int fd, off64_t pos)
2N/A{
2N/A static void *(*mmap64func)();
2N/A void *result;
2N/A int advice = -1;
2N/A#ifdef MADVDEBUG
2N/A int rc;
2N/A#else
2N/A /* LINTED */
2N/A int rc;
2N/A#endif
2N/A
2N/A if (!mmap64func) {
2N/A mmap64func = (void *(*)())dlsym(RTLD_NEXT, "mmap64");
2N/A assert(mmap64func);
2N/A }
2N/A
2N/A result = mmap64func(addr, len, prot, flags, fd, pos);
2N/A
2N/A /*
2N/A * Option mapanon has highest precedence while option map
2N/A * has lowest precedence.
2N/A */
2N/A if (advice_mapanon >= 0 && (flags & MAP_ANON)) {
2N/A advice = advice_mapanon;
2N/A } else if (advice_mapshared >= 0 && (flags & MAP_SHARED)) {
2N/A advice = advice_mapshared;
2N/A } else if (advice_mapprivate >= 0 && (flags & MAP_PRIVATE)) {
2N/A advice = advice_mapprivate;
2N/A } else if (advice_map >= 0) {
2N/A advice = advice_map;
2N/A }
2N/A
2N/A /*
2N/A * Apply advice if specified and mmap succeeded.
2N/A */
2N/A if (advice >= 0 && result != MAP_FAILED) {
2N/A rc = memcntl(result, len, MC_ADVISE, (caddr_t)advice, 0, 0);
2N/A MADVPRINT(1, (stderr,
2N/A "mmap64 advice: 0x%x 0x%x %d, rc %d errno %d\n",
2N/A result, len, advice, rc, errno));
2N/A }
2N/A
2N/A return (result);
2N/A}
2N/A#endif /* !_LP64 */