use a socketpair instead of a pipe in BitTube

Bug: 6252830
Change-Id: Ia7a7b08409517214136261c05569dc5959a597ab
This commit is contained in:
Mathias Agopian 2012-04-02 17:02:19 -07:00
parent 0e1080f887
commit 7b5be95cb3
7 changed files with 108 additions and 57 deletions

View File

@ -22,6 +22,7 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <cutils/log.h>
namespace android {
@ -43,9 +44,27 @@ public:
status_t writeToParcel(Parcel* reply) const;
template <typename T>
static ssize_t sendObjects(const sp<BitTube>& tube,
T const* events, size_t count) {
return sendObjects(tube, events, count, sizeof(T));
}
template <typename T>
static ssize_t recvObjects(const sp<BitTube>& tube,
T* events, size_t count) {
return recvObjects(tube, events, count, sizeof(T));
}
private:
int mSendFd;
mutable int mReceiveFd;
static ssize_t sendObjects(const sp<BitTube>& tube,
void const* events, size_t count, size_t objSize);
static ssize_t recvObjects(const sp<BitTube>& tube,
void* events, size_t count, size_t objSize);
};
// ----------------------------------------------------------------------------

View File

@ -89,7 +89,7 @@ public:
int getFd() const;
/*
* getEvents reads event from the queue and returns how many events were
* getEvents reads events from the queue and returns how many events were
* read. Returns 0 if there are no more events or a negative error code.
* If NOT_ENOUGH_DATA is returned, the object has become invalid forever, it
* should be destroyed and getEvents() shouldn't be called again.
@ -98,6 +98,13 @@ public:
static ssize_t getEvents(const sp<BitTube>& dataChannel,
Event* events, size_t count);
/*
* sendEvents write events to the queue and returns how many events were
* written.
*/
static ssize_t sendEvents(const sp<BitTube>& dataChannel,
Event const* events, size_t count);
/*
* setVsyncRate() sets the Event::VSync delivery rate. A value of
* 1 returns every Event::VSync. A value of 2 returns every other event,

View File

@ -54,7 +54,10 @@ public:
virtual void onFirstRef();
int getFd() const;
ssize_t write(ASensorEvent const* events, size_t numEvents);
static ssize_t write(const sp<BitTube>& tube,
ASensorEvent const* events, size_t numEvents);
ssize_t read(ASensorEvent* events, size_t numEvents);
status_t waitForEvent() const;

View File

@ -16,9 +16,9 @@
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <utils/Errors.h>
@ -30,17 +30,25 @@
namespace android {
// ----------------------------------------------------------------------------
// Socket buffer size. The default is typically about 128KB, which is much larger than
// we really need. So we make it smaller.
static const size_t SOCKET_BUFFER_SIZE = 4 * 1024;
BitTube::BitTube()
: mSendFd(-1), mReceiveFd(-1)
{
int fds[2];
if (pipe(fds) == 0) {
mReceiveFd = fds[0];
mSendFd = fds[1];
fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);
fcntl(mSendFd, F_SETFL, O_NONBLOCK);
// ignore SIGPIPE, we handle write errors through EPIPE instead
signal(SIGPIPE, SIG_IGN);
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
int size = SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
fcntl(sockets[0], F_SETFL, O_NONBLOCK);
fcntl(sockets[1], F_SETFL, O_NONBLOCK);
mReceiveFd = sockets[0];
mSendFd = sockets[1];
} else {
mReceiveFd = -errno;
ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
@ -52,6 +60,9 @@ BitTube::BitTube(const Parcel& data)
{
mReceiveFd = dup(data.readFileDescriptor());
if (mReceiveFd >= 0) {
int size = SOCKET_BUFFER_SIZE;
setsockopt(mReceiveFd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
setsockopt(mReceiveFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);
} else {
mReceiveFd = -errno;
@ -86,7 +97,7 @@ ssize_t BitTube::write(void const* vaddr, size_t size)
{
ssize_t err, len;
do {
len = ::write(mSendFd, vaddr, size);
len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
err = len < 0 ? errno : 0;
} while (err == EINTR);
return err == 0 ? len : -err;
@ -97,7 +108,7 @@ ssize_t BitTube::read(void* vaddr, size_t size)
{
ssize_t err, len;
do {
len = ::read(mReceiveFd, vaddr, size);
len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
err = len < 0 ? errno : 0;
} while (err == EINTR);
if (err == EAGAIN || err == EWOULDBLOCK) {
@ -119,5 +130,46 @@ status_t BitTube::writeToParcel(Parcel* reply) const
return result;
}
ssize_t BitTube::sendObjects(const sp<BitTube>& tube,
void const* events, size_t count, size_t objSize)
{
ssize_t numObjects = 0;
for (size_t i=0 ; i<count ; i++) {
const char* vaddr = reinterpret_cast<const char*>(events) + objSize * i;
ssize_t size = tube->write(vaddr, objSize);
if (size < 0) {
// error occurred
numObjects = -size;
break;
} else if (size == 0) {
// no more space
break;
}
numObjects++;
}
return numObjects;
}
ssize_t BitTube::recvObjects(const sp<BitTube>& tube,
void* events, size_t count, size_t objSize)
{
ssize_t numObjects = 0;
for (size_t i=0 ; i<count ; i++) {
char* vaddr = reinterpret_cast<char*>(events) + objSize * i;
ssize_t size = tube->read(vaddr, objSize);
if (size < 0) {
// error occurred
numObjects = -size;
break;
} else if (size == 0) {
// no more messages
break;
}
numObjects++;
}
return numObjects;
}
// ----------------------------------------------------------------------------
}; // namespace android

View File

@ -85,22 +85,13 @@ ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
ssize_t DisplayEventReceiver::getEvents(const sp<BitTube>& dataChannel,
Event* events, size_t count)
{
ssize_t size = dataChannel->read(events, sizeof(events[0])*count);
ALOGE_IF(size<0,
"DisplayEventReceiver::getEvents error (%s)",
strerror(-size));
if (size >= 0) {
// Note: if (size % sizeof(events[0])) != 0, we've got a
// partial read. This can happen if the queue filed up (ie: if we
// didn't pull from it fast enough).
// We discard the partial event and rely on the sender to
// re-send the event if appropriate (some events, like VSYNC
// can be lost forever).
return BitTube::recvObjects(dataChannel, events, count);
}
// returns number of events read
size /= sizeof(events[0]);
}
return size;
ssize_t DisplayEventReceiver::sendEvents(const sp<BitTube>& dataChannel,
Event const* events, size_t count)
{
return BitTube::sendObjects(dataChannel, events, count);
}
// ---------------------------------------------------------------------------

View File

@ -53,36 +53,15 @@ int SensorEventQueue::getFd() const
return mSensorChannel->getFd();
}
ssize_t SensorEventQueue::write(ASensorEvent const* events, size_t numEvents)
{
ssize_t size = mSensorChannel->write(events, numEvents * sizeof(events[0]));
if (size >= 0) {
if (size % sizeof(events[0])) {
// partial write!!! should never happen.
return -EINVAL;
}
// returns number of events written
size /= sizeof(events[0]);
}
return size;
ssize_t SensorEventQueue::write(const sp<BitTube>& tube,
ASensorEvent const* events, size_t numEvents) {
return BitTube::sendObjects(tube, events, numEvents);
}
ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents)
{
ssize_t size = mSensorChannel->read(events, numEvents*sizeof(events[0]));
ALOGE_IF(size<0 && size!=-EAGAIN,
"SensorChannel::read error (%s)", strerror(-size));
if (size >= 0) {
if (size % sizeof(events[0])) {
// partial read!!! should never happen.
ALOGE("SensorEventQueue partial read (event-size=%u, read=%d)",
sizeof(events[0]), int(size));
return -EINVAL;
}
// returns number of events read
size /= sizeof(events[0]);
}
return size;
return BitTube::recvObjects(mSensorChannel, events, numEvents);
}
sp<Looper> SensorEventQueue::getLooper() const

View File

@ -60,9 +60,9 @@ void DisplayEventConnection::requestNextVsync() {
mEventThread->requestNextVsync(this);
}
status_t DisplayEventConnection::postEvent(const DisplayEventReceiver::Event& event)
{
ssize_t size = mChannel->write(&event, sizeof(DisplayEventReceiver::Event));
status_t DisplayEventConnection::postEvent(
const DisplayEventReceiver::Event& event) {
ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}