OSDN Git Service

Merge "Replace all instances of intptr_t with uintptr_t."
[android-x86/frameworks-native.git] / libs / gui / BitTube.cpp
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdint.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20
21 #include <fcntl.h>
22 #include <unistd.h>
23
24 #include <utils/Errors.h>
25
26 #include <binder/Parcel.h>
27
28 #include <gui/BitTube.h>
29
30 namespace android {
31 // ----------------------------------------------------------------------------
32
33 // Socket buffer size.  The default is typically about 128KB, which is much larger than
34 // we really need.  So we make it smaller.
35 static const size_t DEFAULT_SOCKET_BUFFER_SIZE = 4 * 1024;
36
37
38 BitTube::BitTube()
39     : mSendFd(-1), mReceiveFd(-1)
40 {
41     init(DEFAULT_SOCKET_BUFFER_SIZE, DEFAULT_SOCKET_BUFFER_SIZE);
42 }
43
44 BitTube::BitTube(size_t bufsize)
45     : mSendFd(-1), mReceiveFd(-1)
46 {
47     init(bufsize, bufsize);
48 }
49
50 BitTube::BitTube(const Parcel& data)
51     : mSendFd(-1), mReceiveFd(-1)
52 {
53     mReceiveFd = dup(data.readFileDescriptor());
54     if (mReceiveFd < 0) {
55         mReceiveFd = -errno;
56         ALOGE("BitTube(Parcel): can't dup filedescriptor (%s)",
57                 strerror(-mReceiveFd));
58     }
59 }
60
61 BitTube::~BitTube()
62 {
63     if (mSendFd >= 0)
64         close(mSendFd);
65
66     if (mReceiveFd >= 0)
67         close(mReceiveFd);
68 }
69
70 void BitTube::init(size_t rcvbuf, size_t sndbuf) {
71     int sockets[2];
72     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
73         size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
74         setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
75         setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
76         // sine we don't use the "return channel", we keep it small...
77         setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
78         setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
79         fcntl(sockets[0], F_SETFL, O_NONBLOCK);
80         fcntl(sockets[1], F_SETFL, O_NONBLOCK);
81         mReceiveFd = sockets[0];
82         mSendFd = sockets[1];
83     } else {
84         mReceiveFd = -errno;
85         ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
86     }
87 }
88
89 status_t BitTube::initCheck() const
90 {
91     if (mReceiveFd < 0) {
92         return status_t(mReceiveFd);
93     }
94     return NO_ERROR;
95 }
96
97 int BitTube::getFd() const
98 {
99     return mReceiveFd;
100 }
101
102 int BitTube::getSendFd() const
103 {
104     return mSendFd;
105 }
106
107 ssize_t BitTube::write(void const* vaddr, size_t size)
108 {
109     ssize_t err, len;
110     do {
111         len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
112         // cannot return less than size, since we're using SOCK_SEQPACKET
113         err = len < 0 ? errno : 0;
114     } while (err == EINTR);
115     return err == 0 ? len : -err;
116 }
117
118 ssize_t BitTube::read(void* vaddr, size_t size)
119 {
120     ssize_t err, len;
121     do {
122         len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
123         err = len < 0 ? errno : 0;
124     } while (err == EINTR);
125     if (err == EAGAIN || err == EWOULDBLOCK) {
126         // EAGAIN means that we have non-blocking I/O but there was
127         // no data to be read. Nothing the client should care about.
128         return 0;
129     }
130     return err == 0 ? len : -err;
131 }
132
133 status_t BitTube::writeToParcel(Parcel* reply) const
134 {
135     if (mReceiveFd < 0)
136         return -EINVAL;
137
138     status_t result = reply->writeDupFileDescriptor(mReceiveFd);
139     close(mReceiveFd);
140     mReceiveFd = -1;
141     return result;
142 }
143
144
145 ssize_t BitTube::sendObjects(const sp<BitTube>& tube,
146         void const* events, size_t count, size_t objSize)
147 {
148     const char* vaddr = reinterpret_cast<const char*>(events);
149     ssize_t size = tube->write(vaddr, count*objSize);
150
151     // should never happen because of SOCK_SEQPACKET
152     LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
153             "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were sent!)",
154             count, objSize, size);
155
156     //ALOGE_IF(size<0, "error %d sending %d events", size, count);
157     return size < 0 ? size : size / static_cast<ssize_t>(objSize);
158 }
159
160 ssize_t BitTube::recvObjects(const sp<BitTube>& tube,
161         void* events, size_t count, size_t objSize)
162 {
163     char* vaddr = reinterpret_cast<char*>(events);
164     ssize_t size = tube->read(vaddr, count*objSize);
165
166     // should never happen because of SOCK_SEQPACKET
167     LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
168             "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were received!)",
169             count, objSize, size);
170
171     //ALOGE_IF(size<0, "error %d receiving %d events", size, count);
172     return size < 0 ? size : size / static_cast<ssize_t>(objSize);
173 }
174
175 // ----------------------------------------------------------------------------
176 }; // namespace android