2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
9 #include "ExternalSource.h"
12 #include <sys/prctl.h>
16 #include "OlySocket.h"
17 #include "SessionData.h"
19 static const char MALI_VIDEO[] = "\0mali-video";
20 static const char MALI_VIDEO_STARTUP[] = "\0mali-video-startup";
21 static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n";
22 static const char MALI_GRAPHICS[] = "\0mali_thirdparty_server";
23 static const char MALI_GRAPHICS_STARTUP[] = "\0mali_thirdparty_client";
24 static const char MALI_GRAPHICS_V1[] = "MALI_GRAPHICS 1\n";
26 static bool setNonblock(const int fd) {
29 flags = fcntl(fd, F_GETFL);
31 logg->logMessage("fcntl getfl failed");
35 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
36 logg->logMessage("fcntl setfl failed");
43 ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mAnnotate(8083), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) {
44 sem_init(&mBufferSem, 0, 0);
47 ExternalSource::~ExternalSource() {
50 void ExternalSource::waitFor(const int bytes) {
51 while (mBuffer.bytesAvailable() <= bytes) {
52 sem_wait(&mBufferSem);
56 void ExternalSource::configureConnection(const int fd, const char *const handshake, size_t size) {
57 if (!setNonblock(fd)) {
58 logg->logError(__FILE__, __LINE__, "Unable to set nonblock on fh");
62 if (!mMonitor.add(fd)) {
63 logg->logError(__FILE__, __LINE__, "Unable to add fh to monitor");
67 // Write the handshake to the circular buffer
68 waitFor(Buffer::MAXSIZE_PACK32 + size - 1);
70 mBuffer.writeBytes(handshake, size - 1);
74 bool ExternalSource::connectMali() {
75 mMaliUds = OlySocket::connect(MALI_GRAPHICS, sizeof(MALI_GRAPHICS));
80 configureConnection(mMaliUds, MALI_GRAPHICS_V1, sizeof(MALI_GRAPHICS_V1));
85 bool ExternalSource::connectMve() {
86 if (!gSessionData->maliVideo.countersEnabled()) {
90 mMveUds = OlySocket::connect(MALI_VIDEO, sizeof(MALI_VIDEO));
95 if (!gSessionData->maliVideo.start(mMveUds)) {
99 configureConnection(mMveUds, MALI_VIDEO_V1, sizeof(MALI_VIDEO_V1));
104 bool ExternalSource::prepare() {
105 if (!mMonitor.init() ||
106 !setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd()) ||
107 !setNonblock(mMaliStartupUds.getFd()) || !mMonitor.add(mMaliStartupUds.getFd()) ||
108 !setNonblock(mAnnotate.getFd()) || !mMonitor.add(mAnnotate.getFd()) ||
119 void ExternalSource::run() {
122 prctl(PR_SET_NAME, (unsigned long)&"gatord-external", 0, 0, 0);
124 if (pipe_cloexec(pipefd) != 0) {
125 logg->logError(__FILE__, __LINE__, "pipe failed");
128 mInterruptFd = pipefd[1];
130 if (!mMonitor.add(pipefd[0])) {
131 logg->logError(__FILE__, __LINE__, "Monitor::add failed");
135 // Notify annotate clients to retry connecting to gatord
136 gSessionData->annotateListener.signal();
138 while (gSessionData->mSessionIsActive) {
139 struct epoll_event events[16];
140 // Clear any pending sem posts
141 while (sem_trywait(&mBufferSem) == 0);
142 int ready = mMonitor.wait(events, ARRAY_LENGTH(events), -1);
144 logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
148 const uint64_t currTime = getTime();
150 for (int i = 0; i < ready; ++i) {
151 const int fd = events[i].data.fd;
152 if (fd == mMveStartupUds.getFd()) {
153 // Mali Video Engine says it's alive
154 int client = mMveStartupUds.acceptConnection();
155 // Don't read from this connection, establish a new connection to Mali-V500
158 logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali video connection");
161 } else if (fd == mMaliStartupUds.getFd()) {
162 // Mali Graphics says it's alive
163 int client = mMaliStartupUds.acceptConnection();
164 // Don't read from this connection, establish a new connection to Mali Graphics
166 if (!connectMali()) {
167 logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali graphics connection");
170 } else if (fd == mAnnotate.getFd()) {
171 int client = mAnnotate.acceptConnection();
172 if (!setNonblock(client) || !mMonitor.add(client)) {
173 logg->logError(__FILE__, __LINE__, "Unable to set socket options on incoming annotation connection");
176 } else if (fd == pipefd[0]) {
177 // Means interrupt has been called and mSessionIsActive should be reread
179 /* This can result in some starvation if there are multiple
180 * threads which are annotating heavily, but it is not
181 * recommended that threads annotate that much as it can also
182 * starve out the gator data.
184 while (gSessionData->mSessionIsActive) {
185 // Wait until there is enough room for the fd, two headers and two ints
186 waitFor(7*Buffer::MAXSIZE_PACK32 + 2*sizeof(uint32_t));
188 const int contiguous = mBuffer.contiguousSpaceAvailable();
189 const int bytes = read(fd, mBuffer.getWritePos(), contiguous);
191 if (errno == EAGAIN) {
192 // Nothing left to read
193 mBuffer.commit(currTime);
196 // Something else failed, close the socket
197 mBuffer.commit(currTime);
200 mBuffer.commit(currTime);
203 } else if (bytes == 0) {
204 // The other side is closed
205 mBuffer.commit(currTime);
208 mBuffer.commit(currTime);
213 mBuffer.advanceWrite(bytes);
214 mBuffer.commit(currTime);
216 // Short reads also mean nothing is left to read
217 if (bytes < contiguous) {
228 gSessionData->maliVideo.stop(mMveUds);
236 void ExternalSource::interrupt() {
237 if (mInterruptFd >= 0) {
239 // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread
240 if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) {
241 logg->logError(__FILE__, __LINE__, "write failed");
247 bool ExternalSource::isDone() {
248 return mBuffer.isDone();
251 void ExternalSource::write(Sender *sender) {
252 // Don't send external data until the summary packet is sent so that monotonic delta is available
253 if (!gSessionData->mSentSummary) {
256 if (!mBuffer.isDone()) {
257 mBuffer.write(sender);
258 sem_post(&mBufferSem);