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
29namespace android {
30namespace renderscript {
31
32ThreadIO::ThreadIO() {
33    mRunning = true;
34    mMaxInlineSize = 1024;
35}
36
37ThreadIO::~ThreadIO() {
38}
39
40bool ThreadIO::init() {
41    return mToClient.init() && mToCore.init();
42}
43
44void ThreadIO::shutdown() {
45    mRunning = false;
46    mToCore.shutdown();
47}
48
49void * 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
60void ThreadIO::coreCommit() {
61    mToCore.writeAsync(&mSendBuffer, mSendLen);
62}
63
64void ThreadIO::clientShutdown() {
65    mToClient.shutdown();
66}
67
68void 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
73void ThreadIO::coreRead(void *data, size_t len) {
74    //ALOGV("core read %p %i", data, (int)len);
75    mToCore.read(data, len);
76}
77
78void 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
88void 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
98void ThreadIO::setTimeoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) {
99    //mToCore.setTimeoutCallback(cb, dat, timeout);
100}
101
102bool 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
174RsMessageToClientType 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
184RsMessageToClientType 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
199bool 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