1// RequestAllocator.cpp 2 3#include <new> 4 5#include "AreaSupport.h" 6#include "Compatibility.h" 7#include "Debug.h" 8#include "Port.h" 9#include "RequestAllocator.h" 10 11// constructor 12RequestAllocator::RequestAllocator(Port* port) 13 : fError(B_NO_INIT), 14 fPort(NULL), 15 fRequest(NULL), 16 fRequestSize(0), 17 fAllocatedAreaCount(0), 18 fDeferredInitInfoCount(0), 19 fRequestInPortBuffer(false) 20{ 21 Init(port); 22} 23 24// destructor 25RequestAllocator::~RequestAllocator() 26{ 27 Uninit(); 28} 29 30// Init 31status_t 32RequestAllocator::Init(Port* port) 33{ 34 Uninit(); 35 if (port) { 36 fPort = port; 37 fError = fPort->InitCheck(); 38 } 39 return fError; 40} 41 42// Uninit 43void 44RequestAllocator::Uninit() 45{ 46 if (!fRequestInPortBuffer) 47 delete[] (uint8*)fRequest; 48 for (int32 i = 0; i < fAllocatedAreaCount; i++) 49 delete_area(fAllocatedAreas[i]); 50 fAllocatedAreaCount = 0; 51 for (int32 i = 0; i < fDeferredInitInfoCount; i++) { 52 if (fDeferredInitInfos[i].inPortBuffer) 53 delete[] fDeferredInitInfos[i].data; 54 } 55 fDeferredInitInfoCount = 0; 56 fError = B_NO_INIT; 57 fPort = NULL; 58 fRequest = NULL; 59 fRequestSize = 0; 60} 61 62// Error 63status_t 64RequestAllocator::Error() const 65{ 66 return fError; 67} 68 69// FinishDeferredInit 70void 71RequestAllocator::FinishDeferredInit() 72{ 73 if (fError != B_OK) 74 return; 75 for (int32 i = 0; i < fDeferredInitInfoCount; i++) { 76 DeferredInitInfo& info = fDeferredInitInfos[i]; 77 if (info.inPortBuffer) { 78 if (info.size > 0) 79 memcpy((uint8*)fRequest + info.offset, info.data, info.size); 80 delete[] info.data; 81 } 82 PRINT(("RequestAllocator::FinishDeferredInit(): area: %ld, " 83 "offset: %ld, size: %ld\n", info.area, info.offset, info.size)); 84 info.target->SetTo(info.area, info.offset, info.size); 85 } 86 fDeferredInitInfoCount = 0; 87} 88 89// AllocateRequest 90status_t 91RequestAllocator::AllocateRequest(int32 size) 92{ 93 if (fError != B_OK) 94 RETURN_ERROR(fError); 95 if (size < (int32)sizeof(Request) || size > fPort->GetCapacity()) 96 RETURN_ERROR(fError = B_BAD_VALUE); 97 fRequest = (Request*)fPort->GetBuffer(); 98 fRequestSize = size; 99 fRequestInPortBuffer = true; 100 return B_OK; 101} 102 103// ReadRequest 104status_t 105RequestAllocator::ReadRequest() 106{ 107 if (fError != B_OK) 108 RETURN_ERROR(fError); 109 if (fPort->GetMessageSize() < (int32)sizeof(Request)) 110 RETURN_ERROR(fError = B_BAD_DATA); 111 // clone the request 112 fRequest = (Request*)new(nothrow) uint8[fPort->GetMessageSize()]; 113 if (!fRequest) 114 RETURN_ERROR(fError = B_NO_MEMORY); 115 memcpy(fRequest, fPort->GetMessage(), fPort->GetMessageSize()); 116 fRequestSize = fPort->GetMessageSize(); 117 fRequestInPortBuffer = false; 118 // relocate the request 119 fError = relocate_request(fRequest, fRequestSize, fAllocatedAreas, 120 &fAllocatedAreaCount); 121 RETURN_ERROR(fError); 122} 123 124// GetRequest 125Request* 126RequestAllocator::GetRequest() const 127{ 128 return fRequest; 129} 130 131// GetRequestSize 132int32 133RequestAllocator::GetRequestSize() const 134{ 135 return fRequestSize; 136} 137 138// AllocateAddress 139status_t 140RequestAllocator::AllocateAddress(Address& address, int32 size, int32 align, 141 void** data, bool deferredInit) 142{ 143 if (fError != B_OK) 144 return fError; 145 if (!fRequest) 146 RETURN_ERROR(B_NO_INIT); 147 if (size < 0) 148 RETURN_ERROR(B_BAD_VALUE); 149 if (fDeferredInitInfoCount >= MAX_REQUEST_ADDRESS_COUNT) 150 RETURN_ERROR(B_BAD_VALUE); 151 // fix the alignment -- valid is 1, 2, 4, 8 152 if (align <= 0 || size == 0 || (align & 0x1)) 153 align = 1; 154 else if (align & 0x2) 155 align = 2; 156 else if (align & 0x4) 157 align = 4; 158 else 159 align = 8; 160 // check address location 161 // Currently we only support relocation of addresses inside the 162 // port buffer. 163 int32 addressOffset = (uint8*)&address - (uint8*)fRequest; 164 if (addressOffset < (int32)sizeof(Request) 165 || addressOffset + (int32)sizeof(Address) > fRequestSize) { 166 RETURN_ERROR(B_BAD_VALUE); 167 } 168 // get the next free aligned offset in the port buffer 169 int32 offset = (fRequestSize + align - 1) / align * align; 170 // allocate the data 171 if (offset + size <= fPort->GetCapacity()) { 172 // there's enough free space in the port buffer 173 fRequestSize = offset + size; 174 if (deferredInit) { 175 DeferredInitInfo& info 176 = fDeferredInitInfos[fDeferredInitInfoCount]; 177 if (size > 0) { 178 info.data = new(nothrow) uint8[size]; 179 if (!info.data) 180 RETURN_ERROR(B_NO_MEMORY); 181 } else 182 info.data = NULL; 183 info.area = -1; 184 info.offset = offset; 185 info.size = size; 186 info.inPortBuffer = true; 187 info.target = &address; 188 *data = info.data; 189 fDeferredInitInfoCount++; 190 } else { 191 *data = (uint8*)fRequest + offset; 192 address.SetTo(-1, offset, size); 193 } 194 } else { 195 // not enough room in the port's buffer: we need to allocate an area 196 if (fAllocatedAreaCount >= MAX_REQUEST_ADDRESS_COUNT) 197 RETURN_ERROR(B_ERROR); 198 int32 areaSize = (size + B_PAGE_SIZE - 1) / B_PAGE_SIZE * B_PAGE_SIZE; 199 area_id area = create_area("request data", data, 200#ifdef _KERNEL_MODE 201 B_ANY_KERNEL_ADDRESS, 202#else 203 B_ANY_ADDRESS, 204#endif 205 areaSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 206 if (area < 0) 207 RETURN_ERROR(area); 208 fAllocatedAreas[fAllocatedAreaCount++] = area; 209 if (deferredInit) { 210 DeferredInitInfo& info 211 = fDeferredInitInfos[fDeferredInitInfoCount]; 212 info.data = NULL; 213 info.area = area; 214 info.offset = 0; 215 info.size = size; 216 info.inPortBuffer = false; 217 info.target = &address; 218 fDeferredInitInfoCount++; 219PRINT((" RequestAllocator::AllocateAddress(): deferred allocated area: " 220"%ld, size: %ld (%ld), data: %p\n", area, size, areaSize, *data)); 221 } else 222 address.SetTo(area, 0, size); 223 } 224 return B_OK; 225} 226 227// AllocateData 228status_t 229RequestAllocator::AllocateData(Address& address, const void* data, int32 size, 230 int32 align, bool deferredInit) 231{ 232 void* destination; 233 status_t error = AllocateAddress(address, size, align, &destination, 234 deferredInit); 235 if (error != B_OK) 236 return error; 237 if (size > 0) 238 memcpy(destination, data, size); 239 return error; 240} 241 242// AllocateString 243status_t 244RequestAllocator::AllocateString(Address& address, const char* data, 245 bool deferredInit) 246{ 247 int32 size = (data ? strlen(data) + 1 : 0); 248 return AllocateData(address, data, size, 1, deferredInit); 249} 250 251// SetAddress 252/*status_t 253RequestAllocator::SetAddress(Address& address, void* data, int32 size) 254{ 255 if (fError != B_OK) 256 return fError; 257 if (!fRequest) 258 return (fError = B_NO_INIT); 259 // check address location 260 // Currently we only support relocation of addresses inside the 261 // port buffer. 262 int32 addressOffset = (uint8*)&address - (uint8*)fRequest; 263 if (addressOffset < (int32)sizeof(Request) 264 || addressOffset + (int32)sizeof(Address) > fRequestSize) { 265 return (fError = B_BAD_VALUE); 266 } 267 // if data does itself lie within the port buffer, we store only the 268 // request relative offset 269 int32 inRequestOffset = (uint8*)data - (uint8*)fRequest; 270 if (!data) { 271 address.SetTo(-1, 0, 0); 272 } else if (inRequestOffset >= (int32)sizeof(Request) 273 && inRequestOffset <= fRequestSize) { 274 if (inRequestOffset + size > fRequestSize) 275 return (fError = B_BAD_VALUE); 276 address.SetTo(-1, inRequestOffset, size); 277 } else { 278 // get the area and in-area offset for the address 279 area_id area; 280 int32 offset; 281 fError = get_area_for_address(data, size, &area, &offset); 282 if (fError != B_OK) 283 return fError; 284 // set the address 285 address.SetTo(area, offset, size); 286 } 287 return fError; 288}*/ 289 290