/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by John E. Lloyd.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

/*---------------------------------------------------------------------------
 *		
 * MODULE NAME:	lockMemory
 *
 * DESCRIPTION: Routines for locking and unlocking memory. The implementation
 *		of these routines varies from system to system.
 *
 * AUTHOR/DATE:	John Lloyd, Fall 1990
 *
 * MODIFICATION HISTORY:
 *
 *--------------------------------------------------------------------------*/

#include <errno.h>

#include "../h/cdefs.h"
#include "../h/errorCodes.h"
#include "../rci/link.h"

static int pageSize = UNDEF;
extern int rciSimOnly;

#if (defined(sun) || defined(linux)) && !defined(VXWORKS_CFG)

#include <sys/mman.h>
struct locksec {
	struct locksec *next;
	struct locksec *prev;
	char *addr;
	int size;
	int text;
  };
struct locksec *locklist = NULL;

#endif

lockMemory (addr, size, text)
char *addr;
int size;
int text;
{       	
	char *fxnName = "lockMemory() --";

/* IRIX: use system specific memory locking code here */

#if !defined(VXWORKS_CFG) && !defined(SIMONLY_CFG)
#if defined(sun) || defined(linux)
	struct locksec *ls;
	register char *top, *cp;
#endif
	if (rciSimOnly)
	 { return(1);
	 }
	if (pageSize == UNDEF)
	 { pageSize = getpagesize();
	 }
	/* page align memory locations, just in case :-) */
	addr = (char*)((unsigned int)addr/pageSize*pageSize);
	size = (size+pageSize-1)/pageSize*pageSize;
#ifdef vax
	if (memlock (addr, size) < 0)
	 { sysErrorMsg (EMemory, fxnName, "memlock");
	   return (-1);
	 }
#endif
#ifdef sgi
	if (mpin (addr, size) < 0)
	 { sysErrorMsg (EMemory, fxnName, "mpin");
	   return (-1);
	 }
#endif
	/* MS linux has mlock and mlockall as does sun */
#if defined(sun) || defined(linux) 
	if ((ls=ALLOC(struct locksec)) == NULL)
	 { errorMsg (EMemory, "%s out of memory\n", fxnName);
	   return (-1);
	 }
	if (locklist == NULL)
	 { if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0)
	    { if (errno == EPERM)
	       { rciSimOnly = 1;
		 return (1);
	       }
	      FREE(ls);
	      sysErrorMsg (EMemory, fxnName, "mlockall");
	      return (-1);
	    }
	 }
	if (mlock (addr, size) < 0)
	 { FREE(ls);
	   if (locklist == NULL)
	    { munlockall();
	    }
	   sysErrorMsg (EMemory, fxnName, "mlock");
	   return (-1);
	 }
	/* now touch the address range to bring in all the pages */
	for (cp=addr, top=addr+size; cp<top; cp+=pageSize)
	 { if (text)
	    { char touch = *cp;
	    }
	   else
	    { *cp = *cp;
	    }
	 }
	ls->addr = addr;
	ls->size = size;
	ls->text = text;
	LINK_H (locklist, ls);
#endif
#endif
	return (1);
}

unlockMemory (addr,size)
char *addr;
int size;
{
/* IRIX: use system specific memory unlocking code */
	
#if !defined(VXWORKS_CFG) && !defined(SIMONLY_CFG)
#if defined(sun) || defined(linux)
	struct locksec *ls;
#endif
	if (rciSimOnly)
	 { return(1);
	 }
	if (pageSize == UNDEF)
	 { pageSize = getpagesize();
	 }
	/* page align memory locations, just in case :-) */
	addr = (char*)((unsigned int)addr/pageSize*pageSize);
	size = (size+pageSize-1)/pageSize*pageSize;
#ifdef vax
	memunlock (addr, size);
#endif
#ifdef sgi
	munpin (addr, size);
#endif
#if defined(sun) || defined(linux)
	for (ls=locklist; ls; ls=ls->next)
	 { if (ls->addr == addr && ls->size == size)
	    { break;
	    }
	 }
	if (ls == NULL)
	 { return (0);
	 }
	munlock (addr, size);
	UNLINK_H (locklist, ls);
	FREE (ls);
	if (locklist == NULL)
	 { munlockall();
	 }
#endif
#endif
	return (1);
}
/* MS Assume for the moment that mlock works on linux */
sunTouchMemoryHack()
{
#if defined(sun) && !defined(SIMONLY_CFG) && !defined(VXWORKS_CFG)

	/* a dumb routine routine that seems to be necessary because the
	   Sun memory locking code seems to allow memory to get paged
	   out sometimes anyway.
	 */
	register char *top, *cp;
	register struct locksec *ls;

	if (rciSimOnly)
	 { return;
	 }
	for (ls=locklist; ls; ls=ls->next)
	 { for (cp=ls->addr, top=ls->addr+ls->size; cp<top; cp+=pageSize)
	    { if (ls->text)
	       { char touch = *cp;
	       }
	      else
	       { *cp = *cp;
	       }
	    }
	 }
#endif
}
