1 /*
2  * Copyright (C) 2009 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 "rsContext.h"
18 #include "rsThreadIO.h"
19 #include "rsgApiStructs.h"
20 
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 
25 #include <fcntl.h>
26 #include <poll.h>
27 
28 
29 namespace android {
30 namespace renderscript {
31 
ThreadIO()32 ThreadIO::ThreadIO() {
33     mRunning = true;
34     mMaxInlineSize = 1024;
35 }
36 
~ThreadIO()37 ThreadIO::~ThreadIO() {
38 }
39 
init()40 bool ThreadIO::init() {
41     return mToClient.init() && mToCore.init();
42 }
43 
shutdown()44 void ThreadIO::shutdown() {
45     mRunning = false;
46     mToCore.shutdown();
47 }
48 
coreHeader(uint32_t cmdID,size_t dataLen)49 void * ThreadIO::coreHeader(uint32_t cmdID, size_t dataLen) {
50     //ALOGE("coreHeader %i %i", cmdID, dataLen);
51     CoreCmdHeader *hdr = (CoreCmdHeader *)&mSendBuffer[0];
52     hdr->bytes = dataLen;
53     hdr->cmdID = cmdID;
54     mSendLen = dataLen + sizeof(CoreCmdHeader);
55     //mToCoreSocket.writeAsync(&hdr, sizeof(hdr));
56     //ALOGE("coreHeader ret ");
57     return &mSendBuffer[sizeof(CoreCmdHeader)];
58 }
59 
coreCommit()60 void ThreadIO::coreCommit() {
61     mToCore.writeAsync(&mSendBuffer, mSendLen);
62 }
63 
clientShutdown()64 void ThreadIO::clientShutdown() {
65     mToClient.shutdown();
66 }
67 
coreWrite(const void * data,size_t len)68 void ThreadIO::coreWrite(const void *data, size_t len) {
69     //ALOGV("core write %p %i", data, (int)len);
70     mToCore.writeAsync(data, len, true);
71 }
72 
coreRead(void * data,size_t len)73 void ThreadIO::coreRead(void *data, size_t len) {
74     //ALOGV("core read %p %i", data, (int)len);
75     mToCore.read(data, len);
76 }
77 
coreSetReturn(const void * data,size_t dataLen)78 void ThreadIO::coreSetReturn(const void *data, size_t dataLen) {
79     uint32_t buf;
80     if (data == nullptr) {
81         data = &buf;
82         dataLen = sizeof(buf);
83     }
84 
85     mToCore.readReturn(data, dataLen);
86 }
87 
coreGetReturn(void * data,size_t dataLen)88 void ThreadIO::coreGetReturn(void *data, size_t dataLen) {
89     uint32_t buf;
90     if (data == nullptr) {
91         data = &buf;
92         dataLen = sizeof(buf);
93     }
94 
95     mToCore.writeWaitReturn(data, dataLen);
96 }
97 
setTimeoutCallback(void (* cb)(void *),void * dat,uint64_t timeout)98 void ThreadIO::setTimeoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) {
99     //mToCore.setTimeoutCallback(cb, dat, timeout);
100 }
101 
playCoreCommands(Context * con,int waitFd)102 bool ThreadIO::playCoreCommands(Context *con, int waitFd) {
103     bool ret = false;
104 
105     uint8_t buf[2 * 1024];
106     const CoreCmdHeader *cmd = (const CoreCmdHeader *)&buf[0];
107     const void * data = (const void *)&buf[sizeof(CoreCmdHeader)];
108 
109     struct pollfd p[2];
110     p[0].fd = mToCore.getReadFd();
111     p[0].events = POLLIN;
112     p[0].revents = 0;
113     p[1].fd = waitFd;
114     p[1].events = POLLIN;
115     p[1].revents = 0;
116     int pollCount = 1;
117     if (waitFd >= 0) {
118         pollCount = 2;
119     }
120 
121     if (con->props.mLogTimes) {
122         con->timerSet(Context::RS_TIMER_IDLE);
123     }
124 
125     int waitTime = -1;
126     while (mRunning) {
127         int pr = poll(p, pollCount, waitTime);
128         if (pr <= 0) {
129             break;
130         }
131 
132         if (p[0].revents) {
133             size_t r = 0;
134             r = mToCore.read(&buf[0], sizeof(CoreCmdHeader));
135             mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes);
136             if (r != sizeof(CoreCmdHeader)) {
137               // exception or timeout occurred.
138               break;
139             }
140 
141             ret = true;
142             if (con->props.mLogTimes) {
143                 con->timerSet(Context::RS_TIMER_INTERNAL);
144             }
145             //ALOGV("playCoreCommands 3 %i %i", cmd->cmdID, cmd->bytes);
146 
147             if (cmd->cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
148                 rsAssert(cmd->cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
149                 ALOGE("playCoreCommands error con %p, cmd %i", con, cmd->cmdID);
150             }
151 
152             gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes);
153 
154             if (con->props.mLogTimes) {
155                 con->timerSet(Context::RS_TIMER_IDLE);
156             }
157 
158             if (waitFd < 0) {
159                 // If we don't have a secondary wait object we should stop blocking now
160                 // that at least one command has been processed.
161                 waitTime = 0;
162             }
163         }
164 
165         if (p[1].revents && !p[0].revents) {
166             // We want to finish processing fifo events before processing the vsync.
167             // Otherwise we can end up falling behind and having tremendous lag.
168             break;
169         }
170     }
171     return ret;
172 }
173 
getClientHeader(size_t * receiveLen,uint32_t * usrID)174 RsMessageToClientType ThreadIO::getClientHeader(size_t *receiveLen, uint32_t *usrID) {
175     //ALOGE("getClientHeader");
176     mToClient.read(&mLastClientHeader, sizeof(mLastClientHeader));
177 
178     receiveLen[0] = mLastClientHeader.bytes;
179     usrID[0] = mLastClientHeader.userID;
180     //ALOGE("getClientHeader %i %i %i", mLastClientHeader.cmdID, usrID[0], receiveLen[0]);
181     return (RsMessageToClientType)mLastClientHeader.cmdID;
182 }
183 
getClientPayload(void * data,size_t * receiveLen,uint32_t * usrID,size_t bufferLen)184 RsMessageToClientType ThreadIO::getClientPayload(void *data, size_t *receiveLen,
185                                 uint32_t *usrID, size_t bufferLen) {
186     //ALOGE("getClientPayload");
187     receiveLen[0] = mLastClientHeader.bytes;
188     usrID[0] = mLastClientHeader.userID;
189     if (bufferLen < mLastClientHeader.bytes) {
190         return RS_MESSAGE_TO_CLIENT_RESIZE;
191     }
192     if (receiveLen[0]) {
193         mToClient.read(data, receiveLen[0]);
194     }
195     //ALOGE("getClientPayload x");
196     return (RsMessageToClientType)mLastClientHeader.cmdID;
197 }
198 
sendToClient(RsMessageToClientType cmdID,uint32_t usrID,const void * data,size_t dataLen,bool waitForSpace)199 bool ThreadIO::sendToClient(RsMessageToClientType cmdID, uint32_t usrID, const void *data,
200                             size_t dataLen, bool waitForSpace) {
201 
202     //ALOGE("sendToClient %i %i %i", cmdID, usrID, (int)dataLen);
203     ClientCmdHeader hdr;
204     hdr.bytes = (uint32_t)dataLen;
205     hdr.cmdID = cmdID;
206     hdr.userID = usrID;
207 
208     mToClient.writeAsync(&hdr, sizeof(hdr));
209     if (dataLen) {
210         mToClient.writeAsync(data, dataLen);
211     }
212 
213     //ALOGE("sendToClient x");
214     return true;
215 }
216 
217 } // namespace renderscript
218 } // namespace android
219