1/*
2 * Copyright 2006-2012, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 */
8
9
10/*!	Note, this class don't provide any locking whatsoever - you are
11	supposed to have a BPrivate::AppServerLink object around which
12	does the necessary locking.
13	However, this is not enforced in the methods here, you have to
14	take care for yourself!
15*/
16
17
18#include "ServerMemoryAllocator.h"
19
20#include <new>
21
22#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
23#	include <syscalls.h>
24#endif
25
26
27static const size_t kReservedSize = 128 * 1024 * 1024;
28static const size_t kReserveMaxSize = 32 * 1024 * 1024;
29
30
31namespace BPrivate {
32
33
34struct area_mapping {
35	area_id	server_area;
36	area_id local_area;
37	uint8*	local_base;
38};
39
40
41ServerMemoryAllocator::ServerMemoryAllocator()
42	:
43	fAreas(4)
44{
45}
46
47
48ServerMemoryAllocator::~ServerMemoryAllocator()
49{
50	for (int32 i = fAreas.CountItems(); i-- > 0;) {
51		area_mapping* mapping = (area_mapping*)fAreas.ItemAt(i);
52
53		delete_area(mapping->local_area);
54		delete mapping;
55	}
56}
57
58
59status_t
60ServerMemoryAllocator::InitCheck()
61{
62	return B_OK;
63}
64
65
66status_t
67ServerMemoryAllocator::AddArea(area_id serverArea, area_id& _area,
68	uint8*& _base, size_t size, bool readOnly)
69{
70	area_mapping* mapping = new (std::nothrow) area_mapping;
71	if (mapping == NULL || !fAreas.AddItem(mapping)) {
72		delete mapping;
73		return B_NO_MEMORY;
74	}
75
76	status_t status = B_ERROR;
77	uint32 addressSpec = B_ANY_ADDRESS;
78	void* base;
79#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
80	if (!readOnly && size < kReserveMaxSize) {
81		// Reserve 128 MB of space for the area, but only if the area
82		// is smaller than 32 MB (else the address space waste would
83		// likely to be too large)
84		base = (void*)0x60000000;
85		status = _kern_reserve_address_range((addr_t*)&base, B_BASE_ADDRESS,
86			kReservedSize);
87		addressSpec = status == B_OK ? B_EXACT_ADDRESS : B_BASE_ADDRESS;
88	}
89#endif
90
91	mapping->local_area = clone_area(readOnly
92			? "server read-only memory" : "server_memory", &base, addressSpec,
93		B_CLONEABLE_AREA | B_READ_AREA | (readOnly ? 0 : B_WRITE_AREA),
94		serverArea);
95	if (mapping->local_area < B_OK) {
96		status = mapping->local_area;
97
98		fAreas.RemoveItem(mapping);
99		delete mapping;
100
101		return status;
102	}
103
104	mapping->server_area = serverArea;
105	mapping->local_base = (uint8*)base;
106
107	_area = mapping->local_area;
108	_base = mapping->local_base;
109
110	return B_OK;
111}
112
113
114void
115ServerMemoryAllocator::RemoveArea(area_id serverArea)
116{
117	for (int32 i = fAreas.CountItems(); i-- > 0;) {
118		area_mapping* mapping = (area_mapping*)fAreas.ItemAt(i);
119
120		if (mapping->server_area == serverArea) {
121			// we found the area we should remove
122			delete_area(mapping->local_area);
123			delete mapping;
124			fAreas.RemoveItem(i);
125			break;
126		}
127	}
128}
129
130
131status_t
132ServerMemoryAllocator::AreaAndBaseFor(area_id serverArea, area_id& _area,
133	uint8*& _base)
134{
135	// TODO: why not use a map?
136	for (int32 i = fAreas.CountItems(); i-- > 0;) {
137		area_mapping* mapping = (area_mapping*)fAreas.ItemAt(i);
138
139		if (mapping->server_area == serverArea) {
140			_area = mapping->local_area;
141			_base = mapping->local_base;
142			return B_OK;
143		}
144	}
145
146	return B_ERROR;
147}
148
149
150}	// namespace BPrivate
151