1// AreaUtils.cpp
2//
3// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de)
4//
5// Permission is hereby granted, free of charge, to any person obtaining a
6// copy of this software and associated documentation files (the "Software"),
7// to deal in the Software without restriction, including without limitation
8// the rights to use, copy, modify, merge, publish, distribute, sublicense,
9// and/or sell copies of the Software, and to permit persons to whom the
10// Software is furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21// DEALINGS IN THE SOFTWARE.
22//
23// Except as contained in this notice, the name of a copyright holder shall
24// not be used in advertising or otherwise to promote the sale, use or other
25// dealings in this Software without prior written authorization of the
26// copyright holder.
27
28#include <OS.h>
29
30#include "AreaUtils.h"
31#include "Debug.h"
32#include "Misc.h"
33
34#ifndef USE_STANDARD_FUNCTIONS
35#define USE_STANDARD_FUNCTIONS 0
36#endif
37
38
39// area_info_for
40static
41status_t
42area_info_for(void *address, area_info *info)
43{
44	status_t error = B_OK;
45	if (address) {
46		// get the area ID for the ptr
47		area_id area = area_for(address);
48		// check if supplied pointer points to the beginning of the area
49		if (area >= 0)
50			error = get_area_info(area, info);
51		else
52			error = area;
53	} else
54		error = B_BAD_VALUE;
55	return error;
56}
57
58// calloc
59void *
60AreaUtils::calloc(size_t nmemb, size_t size)
61{
62//PRINT(("AreaUtils::calloc(%lu, %lu)\n", nmemb, size));
63	return AreaUtils::malloc(nmemb * size);
64}
65
66// free
67void
68AreaUtils::free(void *ptr)
69{
70//PRINT(("AreaUtils::free(%p)\n", ptr));
71#if USE_STANDARD_FUNCTIONS
72	return ::free(ptr);
73#else
74	if (ptr) {
75		// get the area for the pointer
76		area_info info;
77		if (area_info_for(ptr, &info) == B_OK) {
78			if (ptr == info.address) {
79				// everything is fine, delete the area
80				delete_area(info.area);
81			} else {
82				INFORM(("WARNING: AreaUtils::free(%p): area begin is %p."
83						"Ignored.\n", ptr, info.address));
84			}
85		}
86	}
87#endif
88}
89
90// malloc
91void *
92AreaUtils::malloc(size_t size)
93{
94//PRINT(("AreaUtils::malloc(%lu)\n", size));
95#if USE_STANDARD_FUNCTIONS
96	return ::malloc(size);
97#else
98	void *address = NULL;
99	if (size > 0) {
100		// round to multiple of page size
101		size = (size + B_PAGE_SIZE - 1) / B_PAGE_SIZE * B_PAGE_SIZE;
102		// create an area
103#if USER
104		area_id area = create_area("AreaUtils::malloc", &address,
105								   B_ANY_ADDRESS, size, B_NO_LOCK,
106								   B_WRITE_AREA | B_READ_AREA);
107#else
108		area_id area = create_area("AreaUtils::malloc", &address,
109								   B_ANY_KERNEL_ADDRESS, size, B_FULL_LOCK,
110								   B_READ_AREA | B_WRITE_AREA);
111#endif
112		if (area < 0)
113			address = NULL;
114	}
115	return address;
116#endif
117}
118
119// realloc
120void *
121AreaUtils::realloc(void * ptr, size_t size)
122{
123//PRINT(("AreaUtils::realloc(%p, %lu)\n", ptr, size))
124#if USE_STANDARD_FUNCTIONS
125	return ::realloc(ptr, size);
126#else
127	void *newAddress = NULL;
128	if (size == 0) {
129		AreaUtils::free(ptr);
130	} else if (ptr) {
131		// get the area for the pointer
132		area_info info;
133		if (area_info_for(ptr, &info) == B_OK) {
134			if (ptr == info.address) {
135				// round to multiple of page size
136				size = (size + B_PAGE_SIZE - 1) / B_PAGE_SIZE * B_PAGE_SIZE;
137				if (size == info.size) {
138					// nothing to do
139					newAddress = ptr;
140				} else if (resize_area(info.area, size) == B_OK) {
141					// resizing the area went fine
142					newAddress = ptr;
143				} else {
144					// resizing the area failed: we need to allocate a new one
145					newAddress = AreaUtils::malloc(size);
146					if (newAddress) {
147						memcpy(newAddress, ptr, min(size, info.size));
148						delete_area(info.area);
149					}
150				}
151			} else {
152				INFORM(("WARNING: AreaUtils::realloc(%p): area begin is %p."
153						"Ignored.\n", ptr, info.address));
154			}
155		}
156	}
157	return newAddress;
158#endif
159}
160
161