1/** Implementation of page-related functions for GNUstep
2   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3
4   Written by:  Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
5   Created: May 1996
6
7   This file is part of the GNUstep Base Library.
8
9   This library is free software; you can redistribute it and/or
10   modify it under the terms of the GNU Lesser General Public
11   License as published by the Free Software Foundation; either
12   version 2 of the License, or (at your option) any later version.
13
14   This library is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public
20   License along with this library; if not, write to the Free
21   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22   Boston, MA 02110 USA.
23
24   <title>NSPage class reference</title>
25   $Date$ $Revision$
26   */
27
28#import "common.h"
29#include <stdio.h>
30#if __mach__
31#include <mach.h>
32#endif
33
34#ifdef __CYGWIN__
35#include <malloc.h>
36#endif
37
38#ifdef _WIN32
39#include <malloc.h>
40static size_t
41getpagesize(void)
42{
43  SYSTEM_INFO info;
44  GetSystemInfo(&info);
45  return info.dwPageSize;
46}
47#endif
48
49#ifdef __SOLARIS__
50#define getpagesize() sysconf(_SC_PAGESIZE)
51#endif
52
53#ifdef __svr4__
54#define getpagesize() sysconf(_SC_PAGESIZE)
55#endif
56
57#if __mach__
58#define getpagesize vm_page_size
59#endif
60
61#ifdef __BEOS__
62#include <kernel/OS.h>
63#define getpagesize()  B_PAGE_SIZE
64#endif
65
66/* Cache the size of a memory page here, so we don't have to make the
67   getpagesize() system call repeatedly. */
68static NSUInteger ns_page_size = 0;
69
70/**
71 * Return the number of bytes in a memory page.
72 */
73NSUInteger
74NSPageSize (void)
75{
76  if (!ns_page_size)
77    ns_page_size = getpagesize ();
78  return ns_page_size;
79}
80
81/**
82 * Return log base 2 of the number of bytes in a memory page.
83 */
84NSUInteger
85NSLogPageSize (void)
86{
87  NSUInteger tmp_page_size = NSPageSize();
88  NSUInteger log = 0;
89
90  while (tmp_page_size >>= 1)
91    log++;
92  return log;
93}
94
95/**
96 * Round bytes down to the nearest multiple of the memory page size,
97 * and return it.
98 */
99NSUInteger
100NSRoundDownToMultipleOfPageSize (NSUInteger bytes)
101{
102  NSUInteger a = NSPageSize();
103
104  return (bytes / a) * a;
105}
106
107/**
108 * Round bytes up to the nearest multiple of the memory page size,
109 * and return it.
110 */
111NSUInteger
112NSRoundUpToMultipleOfPageSize (NSUInteger bytes)
113{
114  NSUInteger a = NSPageSize();
115
116  return ((bytes % a) ? ((bytes / a + 1) * a) : bytes);
117}
118
119#if __linux__
120#include	<sys/sysinfo.h>
121#endif
122
123/**
124 * Return the number of bytes of real (physical) memory available.
125 */
126NSUInteger
127NSRealMemoryAvailable ()
128{
129#if __linux__
130  struct sysinfo info;
131
132  if ((sysinfo(&info)) != 0)
133    return 0;
134  return  info.freeram;
135#elif defined(_WIN32)
136  MEMORYSTATUSEX memory;
137
138  memory.dwLength = sizeof(memory);
139  GlobalMemoryStatusEx(&memory);
140  return memory.ullAvailPhys;
141#elif defined(__BEOS__)
142  system_info info;
143
144  if (get_system_info(&info) != B_OK)
145    return 0;
146  return (info.max_pages - info.used_pages) * B_PAGE_SIZE;
147#else
148  fprintf (stderr, "NSRealMemoryAvailable() not implemented.\n");
149  return 0;
150#endif
151}
152
153/**
154 * Allocate memory for this process and return a pointer to it (or a null
155 * pointer on failure). The allocated memory is page aligned and the
156 * actual size of memory allocated is a multiple of the page size.
157 */
158void *
159NSAllocateMemoryPages (NSUInteger bytes)
160{
161  NSUInteger size = NSRoundUpToMultipleOfPageSize (bytes);
162  void *where;
163#if defined(_WIN32)
164  where = VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
165#elif __mach__
166  kern_return_t r;
167  r = vm_allocate (mach_task_self(), &where, (vm_size_t) size, 1);
168  if (r != KERN_SUCCESS)
169    return NULL;
170  return where;
171#elif	HAVE_POSIX_MEMALIGN
172  if (posix_memalign(&where, NSPageSize(), size) != 0)
173    return NULL;
174#else
175  where = valloc (size);
176  if (where == NULL)
177    return NULL;
178#endif
179  memset (where, 0, bytes);
180  return where;
181}
182
183/**
184 * Deallocate memory which was previously allocated using the
185 * NSAllocateMemoryPages() function.<br />
186 * The bytes argument should be the same as the value passed
187 * to the NSAllocateMemoryPages() function.
188 */
189void
190NSDeallocateMemoryPages (void *ptr, NSUInteger bytes)
191{
192#if defined(_WIN32)
193  VirtualFree(ptr, 0, MEM_RELEASE);
194#elif __mach__
195  vm_deallocate (mach_task_self (), ptr, NSRoundUpToMultipleOfPageSize (bytes));
196#else
197  free (ptr);
198#endif
199}
200
201/**
202 * Perform an efficient large scale copy of data from src to dest.
203 * The value bytes specifies the length of the data copied.
204 */
205void
206NSCopyMemoryPages (const void *src, void *dest, NSUInteger bytes)
207{
208#if __mach__
209  kern_return_t r;
210  r = vm_copy (mach_task_self(), src, bytes, dest);
211  NSParameterAssert (r == KERN_SUCCESS);
212#else
213  memcpy (dest, src, bytes);
214#endif
215}
216
217