* first implementation of passing data via area to app_server

this makes printing of large images work, fixes task #1067



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27214 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Karsten Heimrich 2008-08-27 13:39:16 +00:00
parent 953cb30447
commit 4e61552ecd
3 changed files with 89 additions and 40 deletions

View File

@ -21,7 +21,7 @@
#include <Region.h>
#include "link_message.h"
#include "syscalls.h"
//#define DEBUG_BPORTLINK
#ifdef DEBUG_BPORTLINK
@ -245,9 +245,11 @@ LinkReceiver::ReadFromPort(bigtime_t timeout)
status_t
LinkReceiver::Read(void *data, ssize_t size)
LinkReceiver::Read(void *data, ssize_t passedSize)
{
// STRACE(("info: LinkReceiver Read()ing %ld bytes...\n", size));
ssize_t size = passedSize;
if (fReadError < B_OK)
return fReadError;
@ -259,13 +261,49 @@ LinkReceiver::Read(void *data, ssize_t size)
if (fDataSize == 0 || fReplySize == 0)
return B_NO_INIT; // need to call GetNextReply() first
bool useArea = false;
if ((size_t)size >= kMaxBufferSize) {
useArea = true;
size = sizeof(area_id);
}
if (fRecvPosition + size > fRecvStart + fReplySize) {
// reading past the end of current message
fReadError = B_BAD_VALUE;
return B_BAD_VALUE;
}
memcpy(data, fRecvBuffer + fRecvPosition, size);
if (useArea) {
area_id sourceArea;
memcpy((void*)&sourceArea, fRecvBuffer + fRecvPosition, size);
area_info areaInfo;
if (get_area_info(sourceArea, &areaInfo) < B_OK)
fReadError = B_BAD_VALUE;
if (fReadError >= B_OK) {
thread_info threadInfo;
get_thread_info(find_thread(NULL), &threadInfo);
void* areaAddress = NULL;
if (areaInfo.team != threadInfo.team) {
sourceArea = _kern_transfer_area(sourceArea, &areaAddress,
B_ANY_ADDRESS, threadInfo.team);
if (sourceArea < B_OK)
fReadError = sourceArea;
} else {
areaAddress = areaInfo.address;
}
if (areaAddress && sourceArea >= B_OK) {
memcpy(data, areaAddress, passedSize);
delete_area(sourceArea);
}
}
} else {
memcpy(data, fRecvBuffer + fRecvPosition, size);
}
fRecvPosition += size;
return fReadError;
}

View File

@ -129,8 +129,11 @@ LinkSender::CancelMessage()
status_t
LinkSender::Attach(const void *data, size_t size)
LinkSender::Attach(const void *passedData, size_t passedSize)
{
size_t size = passedSize;
const void* data = passedData;
if (fCurrentStatus < B_OK)
return fCurrentStatus;
@ -140,6 +143,12 @@ LinkSender::Attach(const void *data, size_t size)
if (fCurrentEnd == fCurrentStart)
return B_NO_INIT; // need to call StartMessage() first
bool useArea = false;
if (size >= kMaxBufferSize) {
useArea = true;
size = sizeof(area_id);
}
if (SpaceLeft() < size) {
// we have to make space for the data
@ -148,6 +157,20 @@ LinkSender::Attach(const void *data, size_t size)
return fCurrentStatus = status;
}
area_id senderArea = -1;
if (useArea) {
void* address = NULL;
off_t alignedSize = (passedSize + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1);
senderArea = create_area("LinkSenderArea", &address, B_ANY_ADDRESS,
alignedSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (senderArea < B_OK)
return senderArea;
data = &senderArea;
memcpy(address, passedData, passedSize);
}
memcpy(fBuffer + fCurrentEnd, data, size);
fCurrentEnd += size;

View File

@ -30,6 +30,7 @@
#include <List.h>
#include <Shape.h>
#include <new>
#include <stdio.h>
#include <stack>
@ -976,37 +977,27 @@ ServerPicture::DataLength() const
}
#define BUFFER_SIZE 4096
status_t
ServerPicture::ImportData(BPrivate::LinkReceiver &link)
{
int32 size = 0;
link.Read<int32>(&size);
if (size >= 65536) {
//TODO: Pass via an area.
// Ideally the Link** api would allow to write partial messages,
// so that a big picture could be written in chunks of 4096 bytes
// or so
return B_ERROR;
}
off_t oldPosition = fData->Position();
fData->Seek(0, SEEK_SET);
// TODO: Oh yeah... 65kb on the stack...
char buffer[size];
status_t read = link.Read(buffer, size);
if (read < B_OK)
return (status_t)read;
fData->Write(buffer, size);
status_t status = B_NO_MEMORY;
char* buffer = new(std::nothrow) char[size];
if (buffer) {
status = B_OK;
ssize_t read = link.Read(buffer, size);
if (read < B_OK || fData->Write(buffer, size) < B_OK)
status = B_ERROR;
delete [] buffer;
}
fData->Seek(oldPosition, SEEK_SET);
return B_OK;
return status;
}
@ -1032,27 +1023,24 @@ ServerPicture::ExportData(BPrivate::PortLink &link)
off_t size = 0;
fData->GetSize(&size);
link.Attach<int32>((int32)size);
if (size >= 65536) {
//TODO: Pass via an area
status_t status = B_NO_MEMORY;
char* buffer = new(std::nothrow) char[size];
if (buffer) {
status = B_OK;
ssize_t read = fData->Read(buffer, size);
if (read < B_OK || link.Attach(buffer, read) < B_OK)
status = B_ERROR;
delete [] buffer;
}
if (status < B_OK) {
link.CancelMessage();
link.StartMessage(B_ERROR);
return B_ERROR;
}
// TODO: Oh yeah... 65kb on the stack...
char buffer[size];
ssize_t read = fData->Read(buffer, size);
if (read < B_OK)
return (status_t)read;
if (link.Attach(buffer, read) < B_OK) {
//
link.CancelMessage();
link.StartMessage(B_ERROR);
};
fData->Seek(oldPosition, SEEK_SET);
return B_OK;
return status;
}