xref: /haiku/src/kits/app/ServerMemoryAllocator.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
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 
27 static const size_t kReservedSize = 128 * 1024 * 1024;
28 static const size_t kReserveMaxSize = 32 * 1024 * 1024;
29 
30 
31 namespace BPrivate {
32 
33 
34 struct area_mapping {
35 	area_id	server_area;
36 	area_id local_area;
37 	uint8*	local_base;
38 };
39 
40 
41 ServerMemoryAllocator::ServerMemoryAllocator()
42 	:
43 	fAreas(4)
44 {
45 }
46 
47 
48 ServerMemoryAllocator::~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 
59 status_t
60 ServerMemoryAllocator::InitCheck()
61 {
62 	return B_OK;
63 }
64 
65 
66 status_t
67 ServerMemoryAllocator::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_READ_AREA | (readOnly ? 0 : B_WRITE_AREA), serverArea);
94 	if (mapping->local_area < B_OK) {
95 		status = mapping->local_area;
96 
97 		fAreas.RemoveItem(mapping);
98 		delete mapping;
99 
100 		return status;
101 	}
102 
103 	mapping->server_area = serverArea;
104 	mapping->local_base = (uint8*)base;
105 
106 	_area = mapping->local_area;
107 	_base = mapping->local_base;
108 
109 	return B_OK;
110 }
111 
112 
113 void
114 ServerMemoryAllocator::RemoveArea(area_id serverArea)
115 {
116 	for (int32 i = fAreas.CountItems(); i-- > 0;) {
117 		area_mapping* mapping = (area_mapping*)fAreas.ItemAt(i);
118 
119 		if (mapping->server_area == serverArea) {
120 			// we found the area we should remove
121 			delete_area(mapping->local_area);
122 			delete mapping;
123 			fAreas.RemoveItem(i);
124 			break;
125 		}
126 	}
127 }
128 
129 
130 status_t
131 ServerMemoryAllocator::AreaAndBaseFor(area_id serverArea, area_id& _area,
132 	uint8*& _base)
133 {
134 	// TODO: why not use a map?
135 	for (int32 i = fAreas.CountItems(); i-- > 0;) {
136 		area_mapping* mapping = (area_mapping*)fAreas.ItemAt(i);
137 
138 		if (mapping->server_area == serverArea) {
139 			_area = mapping->local_area;
140 			_base = mapping->local_base;
141 			return B_OK;
142 		}
143 	}
144 
145 	return B_ERROR;
146 }
147 
148 
149 }	// namespace BPrivate
150