/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "rsContext.h" #include "rsThreadIO.h" #include "rsgApiStructs.h" #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <fcntl.h> #include <poll.h> using namespace android; using namespace android::renderscript; ThreadIO::ThreadIO() { mRunning = true; mPureFifo = false; mMaxInlineSize = 1024; } ThreadIO::~ThreadIO() { } void ThreadIO::init() { mToClient.init(); mToCore.init(); } void ThreadIO::shutdown() { mRunning = false; mToCore.shutdown(); } void * ThreadIO::coreHeader(uint32_t cmdID, size_t dataLen) { //ALOGE("coreHeader %i %i", cmdID, dataLen); CoreCmdHeader *hdr = (CoreCmdHeader *)&mSendBuffer[0]; hdr->bytes = dataLen; hdr->cmdID = cmdID; mSendLen = dataLen + sizeof(CoreCmdHeader); //mToCoreSocket.writeAsync(&hdr, sizeof(hdr)); //ALOGE("coreHeader ret "); return &mSendBuffer[sizeof(CoreCmdHeader)]; } void ThreadIO::coreCommit() { mToCore.writeAsync(&mSendBuffer, mSendLen); } void ThreadIO::clientShutdown() { mToClient.shutdown(); } void ThreadIO::coreWrite(const void *data, size_t len) { //ALOGV("core write %p %i", data, (int)len); mToCore.writeAsync(data, len, true); } void ThreadIO::coreRead(void *data, size_t len) { //ALOGV("core read %p %i", data, (int)len); mToCore.read(data, len); } void ThreadIO::coreSetReturn(const void *data, size_t dataLen) { uint32_t buf; if (data == nullptr) { data = &buf; dataLen = sizeof(buf); } mToCore.readReturn(data, dataLen); } void ThreadIO::coreGetReturn(void *data, size_t dataLen) { uint32_t buf; if (data == nullptr) { data = &buf; dataLen = sizeof(buf); } mToCore.writeWaitReturn(data, dataLen); } void ThreadIO::setTimeoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) { //mToCore.setTimeoutCallback(cb, dat, timeout); } bool ThreadIO::playCoreCommands(Context *con, int waitFd) { bool ret = false; const bool isLocal = !isPureFifo(); uint8_t buf[2 * 1024]; const CoreCmdHeader *cmd = (const CoreCmdHeader *)&buf[0]; const void * data = (const void *)&buf[sizeof(CoreCmdHeader)]; struct pollfd p[2]; p[0].fd = mToCore.getReadFd(); p[0].events = POLLIN; p[0].revents = 0; p[1].fd = waitFd; p[1].events = POLLIN; p[1].revents = 0; int pollCount = 1; if (waitFd >= 0) { pollCount = 2; } if (con->props.mLogTimes) { con->timerSet(Context::RS_TIMER_IDLE); } int waitTime = -1; while (mRunning) { int pr = poll(p, pollCount, waitTime); if (pr <= 0) { break; } if (p[0].revents) { size_t r = 0; if (isLocal) { r = mToCore.read(&buf[0], sizeof(CoreCmdHeader)); mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes); if (r != sizeof(CoreCmdHeader)) { // exception or timeout occurred. break; } } else { r = mToCore.read((void *)&cmd->cmdID, sizeof(cmd->cmdID)); } ret = true; if (con->props.mLogTimes) { con->timerSet(Context::RS_TIMER_INTERNAL); } //ALOGV("playCoreCommands 3 %i %i", cmd->cmdID, cmd->bytes); if (cmd->cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) { rsAssert(cmd->cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *))); ALOGE("playCoreCommands error con %p, cmd %i", con, cmd->cmdID); } if (isLocal) { gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes); } else { gPlaybackRemoteFuncs[cmd->cmdID](con, this); } if (con->props.mLogTimes) { con->timerSet(Context::RS_TIMER_IDLE); } if (waitFd < 0) { // If we don't have a secondary wait object we should stop blocking now // that at least one command has been processed. waitTime = 0; } } if (p[1].revents && !p[0].revents) { // We want to finish processing fifo events before processing the vsync. // Otherwise we can end up falling behind and having tremendous lag. break; } } return ret; } RsMessageToClientType ThreadIO::getClientHeader(size_t *receiveLen, uint32_t *usrID) { //ALOGE("getClientHeader"); mToClient.read(&mLastClientHeader, sizeof(mLastClientHeader)); receiveLen[0] = mLastClientHeader.bytes; usrID[0] = mLastClientHeader.userID; //ALOGE("getClientHeader %i %i %i", mLastClientHeader.cmdID, usrID[0], receiveLen[0]); return (RsMessageToClientType)mLastClientHeader.cmdID; } RsMessageToClientType ThreadIO::getClientPayload(void *data, size_t *receiveLen, uint32_t *usrID, size_t bufferLen) { //ALOGE("getClientPayload"); receiveLen[0] = mLastClientHeader.bytes; usrID[0] = mLastClientHeader.userID; if (bufferLen < mLastClientHeader.bytes) { return RS_MESSAGE_TO_CLIENT_RESIZE; } if (receiveLen[0]) { mToClient.read(data, receiveLen[0]); } //ALOGE("getClientPayload x"); return (RsMessageToClientType)mLastClientHeader.cmdID; } bool ThreadIO::sendToClient(RsMessageToClientType cmdID, uint32_t usrID, const void *data, size_t dataLen, bool waitForSpace) { //ALOGE("sendToClient %i %i %i", cmdID, usrID, (int)dataLen); ClientCmdHeader hdr; hdr.bytes = (uint32_t)dataLen; hdr.cmdID = cmdID; hdr.userID = usrID; mToClient.writeAsync(&hdr, sizeof(hdr)); if (dataLen) { mToClient.writeAsync(data, dataLen); } //ALOGE("sendToClient x"); return true; }