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