rsThreadIO.cpp revision 5f27d6fb0b0b9184ba9820c629fc1354a635e515
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
19#include "rsThreadIO.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
29using namespace android;
30using namespace android::renderscript;
31
32ThreadIO::ThreadIO() {
33    mRunning = true;
34}
35
36ThreadIO::~ThreadIO() {
37}
38
39void ThreadIO::init() {
40    mToClient.init();
41    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::coreSetReturn(const void *data, size_t dataLen) {
69    uint32_t buf;
70    if (data == NULL) {
71        data = &buf;
72        dataLen = sizeof(buf);
73    }
74
75    mToCore.readReturn(data, dataLen);
76}
77
78void ThreadIO::coreGetReturn(void *data, size_t dataLen) {
79    uint32_t buf;
80    if (data == NULL) {
81        data = &buf;
82        dataLen = sizeof(buf);
83    }
84
85    mToCore.writeWaitReturn(data, dataLen);
86}
87
88void ThreadIO::setTimeoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) {
89    //mToCore.setTimeoutCallback(cb, dat, timeout);
90}
91
92bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand, int waitFd) {
93    bool ret = false;
94
95    uint8_t buf[2 * 1024];
96    const CoreCmdHeader *cmd = (const CoreCmdHeader *)&buf[0];
97    const void * data = (const void *)&buf[sizeof(CoreCmdHeader)];
98
99    struct pollfd p[2];
100    p[0].fd = mToCore.getReadFd();
101    p[0].events = POLLIN;
102    p[0].revents = 0;
103    p[1].fd = waitFd;
104    p[1].events = POLLIN;
105    p[1].revents = 0;
106    int pollCount = 1;
107    if (waitFd >= 0) {
108        pollCount = 2;
109    }
110
111    if (con->props.mLogTimes) {
112        con->timerSet(Context::RS_TIMER_IDLE);
113    }
114
115    int waitTime = -1;
116    while (mRunning) {
117        int pr = poll(p, pollCount, waitTime);
118        if (pr <= 0) {
119            break;
120        }
121
122        if (p[0].revents) {
123            size_t r = mToCore.read(&buf[0], sizeof(CoreCmdHeader));
124            mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes);
125
126            if (r != sizeof(CoreCmdHeader)) {
127                // exception or timeout occurred.
128                break;
129            }
130
131            ret = true;
132            if (con->props.mLogTimes) {
133                con->timerSet(Context::RS_TIMER_INTERNAL);
134            }
135            waitForCommand = false;
136            //ALOGV("playCoreCommands 3 %i %i", cmd->cmdID, cmd->bytes);
137
138            if (cmd->cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
139                rsAssert(cmd->cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
140                ALOGE("playCoreCommands error con %p, cmd %i", con, cmd->cmdID);
141            }
142            gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes);
143
144            if (con->props.mLogTimes) {
145                con->timerSet(Context::RS_TIMER_IDLE);
146            }
147
148            if (waitFd < 0) {
149                // If we don't have a secondary wait object we should stop blocking now
150                // that at least one command has been processed.
151                waitTime = 0;
152            }
153        }
154
155        if (p[1].revents && !p[0].revents) {
156            // We want to finish processing fifo events before processing the vsync.
157            // Otherwise we can end up falling behind and having tremendous lag.
158            break;
159        }
160    }
161    return ret;
162}
163
164RsMessageToClientType ThreadIO::getClientHeader(size_t *receiveLen, uint32_t *usrID) {
165    //ALOGE("getClientHeader");
166    mToClient.read(&mLastClientHeader, sizeof(mLastClientHeader));
167
168    receiveLen[0] = mLastClientHeader.bytes;
169    usrID[0] = mLastClientHeader.userID;
170    //ALOGE("getClientHeader %i %i %i", mLastClientHeader.cmdID, usrID[0], receiveLen[0]);
171    return (RsMessageToClientType)mLastClientHeader.cmdID;
172}
173
174RsMessageToClientType ThreadIO::getClientPayload(void *data, size_t *receiveLen,
175                                uint32_t *usrID, size_t bufferLen) {
176    //ALOGE("getClientPayload");
177    receiveLen[0] = mLastClientHeader.bytes;
178    usrID[0] = mLastClientHeader.userID;
179    if (bufferLen < mLastClientHeader.bytes) {
180        return RS_MESSAGE_TO_CLIENT_RESIZE;
181    }
182    if (receiveLen[0]) {
183        mToClient.read(data, receiveLen[0]);
184    }
185    //ALOGE("getClientPayload x");
186    return (RsMessageToClientType)mLastClientHeader.cmdID;
187}
188
189bool ThreadIO::sendToClient(RsMessageToClientType cmdID, uint32_t usrID, const void *data,
190                            size_t dataLen, bool waitForSpace) {
191
192    //ALOGE("sendToClient %i %i %i", cmdID, usrID, (int)dataLen);
193    ClientCmdHeader hdr;
194    hdr.bytes = dataLen;
195    hdr.cmdID = cmdID;
196    hdr.userID = usrID;
197
198    mToClient.writeAsync(&hdr, sizeof(hdr));
199    if (dataLen) {
200        mToClient.writeAsync(data, dataLen);
201    }
202
203    //ALOGE("sendToClient x");
204    return true;
205}
206
207