blob: 8d71b6de3d5ecee098088684feadcba7da63fa66 [file] [log] [blame]
Jon Medhurst15ce78d2014-04-10 09:02:02 +01001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2010-2015. All rights reserved.
Jon Medhurst15ce78d2014-04-10 09:02:02 +01003 *
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.
7 */
8
9#include "ExternalSource.h"
10
Jon Medhurste31266f2014-08-04 15:47:44 +010011#include <fcntl.h>
Jon Medhurst15ce78d2014-04-10 09:02:02 +010012#include <sys/prctl.h>
Jon Medhurste31266f2014-08-04 15:47:44 +010013#include <unistd.h>
Jon Medhurst15ce78d2014-04-10 09:02:02 +010014
Jon Medhurstb1d07442015-05-08 12:04:18 +010015#include "Child.h"
Jon Medhurst15ce78d2014-04-10 09:02:02 +010016#include "Logging.h"
17#include "OlySocket.h"
18#include "SessionData.h"
19
Jon Medhurstb1d07442015-05-08 12:04:18 +010020extern Child *child;
21
22static const char STREAMLINE_ANNOTATE[] = "\0streamline-annotate";
Jon Medhurste31266f2014-08-04 15:47:44 +010023static const char MALI_VIDEO[] = "\0mali-video";
24static const char MALI_VIDEO_STARTUP[] = "\0mali-video-startup";
25static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n";
Jon Medhurst96b56152014-10-30 18:01:15 +000026static const char MALI_GRAPHICS[] = "\0mali_thirdparty_server";
27static const char MALI_GRAPHICS_STARTUP[] = "\0mali_thirdparty_client";
28static const char MALI_GRAPHICS_V1[] = "MALI_GRAPHICS 1\n";
Jon Medhurste31266f2014-08-04 15:47:44 +010029
30static bool setNonblock(const int fd) {
31 int flags;
32
33 flags = fcntl(fd, F_GETFL);
34 if (flags < 0) {
35 logg->logMessage("fcntl getfl failed");
36 return false;
37 }
38
39 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
40 logg->logMessage("fcntl setfl failed");
41 return false;
42 }
43
44 return true;
45}
46
Jon Medhurstb1d07442015-05-08 12:04:18 +010047ExternalSource::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), mAnnotateUds(STREAMLINE_ANNOTATE, sizeof(STREAMLINE_ANNOTATE), true), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) {
Jon Medhurste31266f2014-08-04 15:47:44 +010048 sem_init(&mBufferSem, 0, 0);
Jon Medhurst15ce78d2014-04-10 09:02:02 +010049}
50
51ExternalSource::~ExternalSource() {
52}
53
Jon Medhurst96b56152014-10-30 18:01:15 +000054void ExternalSource::waitFor(const int bytes) {
Jon Medhurste31266f2014-08-04 15:47:44 +010055 while (mBuffer.bytesAvailable() <= bytes) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010056 if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
57 logg->logMessage("One shot (external)");
58 child->endSession();
59 }
Jon Medhurste31266f2014-08-04 15:47:44 +010060 sem_wait(&mBufferSem);
61 }
62}
63
64void ExternalSource::configureConnection(const int fd, const char *const handshake, size_t size) {
65 if (!setNonblock(fd)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010066 logg->logError("Unable to set nonblock on fh");
Jon Medhurste31266f2014-08-04 15:47:44 +010067 handleException();
68 }
69
70 if (!mMonitor.add(fd)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010071 logg->logError("Unable to add fh to monitor");
Jon Medhurste31266f2014-08-04 15:47:44 +010072 handleException();
73 }
74
75 // Write the handshake to the circular buffer
Jon Medhurst96b56152014-10-30 18:01:15 +000076 waitFor(Buffer::MAXSIZE_PACK32 + size - 1);
Jon Medhurste31266f2014-08-04 15:47:44 +010077 mBuffer.packInt(fd);
Jon Medhurste31266f2014-08-04 15:47:44 +010078 mBuffer.writeBytes(handshake, size - 1);
Jon Medhurstb1d07442015-05-08 12:04:18 +010079 mBuffer.commit(1, true);
Jon Medhurst96b56152014-10-30 18:01:15 +000080}
81
82bool ExternalSource::connectMali() {
83 mMaliUds = OlySocket::connect(MALI_GRAPHICS, sizeof(MALI_GRAPHICS));
84 if (mMaliUds < 0) {
85 return false;
86 }
87
88 configureConnection(mMaliUds, MALI_GRAPHICS_V1, sizeof(MALI_GRAPHICS_V1));
89
90 return true;
Jon Medhurste31266f2014-08-04 15:47:44 +010091}
92
93bool ExternalSource::connectMve() {
94 if (!gSessionData->maliVideo.countersEnabled()) {
95 return true;
96 }
97
98 mMveUds = OlySocket::connect(MALI_VIDEO, sizeof(MALI_VIDEO));
99 if (mMveUds < 0) {
100 return false;
101 }
102
103 if (!gSessionData->maliVideo.start(mMveUds)) {
104 return false;
105 }
106
107 configureConnection(mMveUds, MALI_VIDEO_V1, sizeof(MALI_VIDEO_V1));
108
109 return true;
110}
111
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100112bool ExternalSource::prepare() {
Jon Medhurst96b56152014-10-30 18:01:15 +0000113 if (!mMonitor.init() ||
114 !setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd()) ||
115 !setNonblock(mMaliStartupUds.getFd()) || !mMonitor.add(mMaliStartupUds.getFd()) ||
116 !setNonblock(mAnnotate.getFd()) || !mMonitor.add(mAnnotate.getFd()) ||
Jon Medhurstb1d07442015-05-08 12:04:18 +0100117 !setNonblock(mAnnotateUds.getFd()) || !mMonitor.add(mAnnotateUds.getFd()) ||
Jon Medhurst96b56152014-10-30 18:01:15 +0000118 false) {
Jon Medhurste31266f2014-08-04 15:47:44 +0100119 return false;
120 }
121
Jon Medhurst96b56152014-10-30 18:01:15 +0000122 connectMali();
Jon Medhurste31266f2014-08-04 15:47:44 +0100123 connectMve();
124
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100125 return true;
126}
127
128void ExternalSource::run() {
Jon Medhurste31266f2014-08-04 15:47:44 +0100129 int pipefd[2];
130
131 prctl(PR_SET_NAME, (unsigned long)&"gatord-external", 0, 0, 0);
132
Jon Medhurst96b56152014-10-30 18:01:15 +0000133 if (pipe_cloexec(pipefd) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100134 logg->logError("pipe failed");
Jon Medhurste31266f2014-08-04 15:47:44 +0100135 handleException();
136 }
137 mInterruptFd = pipefd[1];
138
139 if (!mMonitor.add(pipefd[0])) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100140 logg->logError("Monitor::add failed");
Jon Medhurste31266f2014-08-04 15:47:44 +0100141 handleException();
142 }
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100143
Jon Medhurst96b56152014-10-30 18:01:15 +0000144 // Notify annotate clients to retry connecting to gatord
Jon Medhurstb1d07442015-05-08 12:04:18 +0100145 uint64_t val = 1;
146 if (::write(gSessionData->mAnnotateStart, &val, sizeof(val)) != sizeof(val)) {
147 logg->logMessage("Writing to annotate pipe failed");
148 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000149
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100150 while (gSessionData->mSessionIsActive) {
Jon Medhurste31266f2014-08-04 15:47:44 +0100151 struct epoll_event events[16];
152 // Clear any pending sem posts
153 while (sem_trywait(&mBufferSem) == 0);
154 int ready = mMonitor.wait(events, ARRAY_LENGTH(events), -1);
155 if (ready < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100156 logg->logError("Monitor::wait failed");
Jon Medhurste31266f2014-08-04 15:47:44 +0100157 handleException();
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100158 }
159
Jon Medhurstb1d07442015-05-08 12:04:18 +0100160 const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted;
Jon Medhurste31266f2014-08-04 15:47:44 +0100161
162 for (int i = 0; i < ready; ++i) {
163 const int fd = events[i].data.fd;
164 if (fd == mMveStartupUds.getFd()) {
165 // Mali Video Engine says it's alive
166 int client = mMveStartupUds.acceptConnection();
167 // Don't read from this connection, establish a new connection to Mali-V500
168 close(client);
169 if (!connectMve()) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100170 logg->logError("Unable to configure incoming Mali video connection");
Jon Medhurste31266f2014-08-04 15:47:44 +0100171 handleException();
172 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000173 } else if (fd == mMaliStartupUds.getFd()) {
174 // Mali Graphics says it's alive
175 int client = mMaliStartupUds.acceptConnection();
176 // Don't read from this connection, establish a new connection to Mali Graphics
177 close(client);
178 if (!connectMali()) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100179 logg->logError("Unable to configure incoming Mali graphics connection");
Jon Medhurst96b56152014-10-30 18:01:15 +0000180 handleException();
181 }
182 } else if (fd == mAnnotate.getFd()) {
183 int client = mAnnotate.acceptConnection();
184 if (!setNonblock(client) || !mMonitor.add(client)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100185 logg->logError("Unable to set socket options on incoming annotation connection");
186 handleException();
187 }
188 } else if (fd == mAnnotateUds.getFd()) {
189 int client = mAnnotateUds.acceptConnection();
190 if (!setNonblock(client) || !mMonitor.add(client)) {
191 logg->logError("Unable to set socket options on incoming annotation connection");
Jon Medhurst96b56152014-10-30 18:01:15 +0000192 handleException();
193 }
Jon Medhurste31266f2014-08-04 15:47:44 +0100194 } else if (fd == pipefd[0]) {
195 // Means interrupt has been called and mSessionIsActive should be reread
196 } else {
Jon Medhurst96b56152014-10-30 18:01:15 +0000197 /* This can result in some starvation if there are multiple
198 * threads which are annotating heavily, but it is not
199 * recommended that threads annotate that much as it can also
200 * starve out the gator data.
201 */
202 while (gSessionData->mSessionIsActive) {
203 // Wait until there is enough room for the fd, two headers and two ints
204 waitFor(7*Buffer::MAXSIZE_PACK32 + 2*sizeof(uint32_t));
Jon Medhurste31266f2014-08-04 15:47:44 +0100205 mBuffer.packInt(fd);
Jon Medhurste31266f2014-08-04 15:47:44 +0100206 const int contiguous = mBuffer.contiguousSpaceAvailable();
207 const int bytes = read(fd, mBuffer.getWritePos(), contiguous);
208 if (bytes < 0) {
209 if (errno == EAGAIN) {
Jon Medhurst96b56152014-10-30 18:01:15 +0000210 // Nothing left to read
Jon Medhurstb1d07442015-05-08 12:04:18 +0100211 mBuffer.commit(currTime, true);
Jon Medhurste31266f2014-08-04 15:47:44 +0100212 break;
213 }
214 // Something else failed, close the socket
Jon Medhurstb1d07442015-05-08 12:04:18 +0100215 mBuffer.commit(currTime, true);
Jon Medhurst96b56152014-10-30 18:01:15 +0000216 mBuffer.packInt(-1);
217 mBuffer.packInt(fd);
Jon Medhurstb1d07442015-05-08 12:04:18 +0100218 // Here and other commits, always force-flush the buffer as this frame don't work like others
219 mBuffer.commit(currTime, true);
Jon Medhurste31266f2014-08-04 15:47:44 +0100220 close(fd);
221 break;
222 } else if (bytes == 0) {
223 // The other side is closed
Jon Medhurstb1d07442015-05-08 12:04:18 +0100224 mBuffer.commit(currTime, true);
Jon Medhurst96b56152014-10-30 18:01:15 +0000225 mBuffer.packInt(-1);
226 mBuffer.packInt(fd);
Jon Medhurstb1d07442015-05-08 12:04:18 +0100227 mBuffer.commit(currTime, true);
Jon Medhurste31266f2014-08-04 15:47:44 +0100228 close(fd);
229 break;
230 }
231
Jon Medhurste31266f2014-08-04 15:47:44 +0100232 mBuffer.advanceWrite(bytes);
Jon Medhurstb1d07442015-05-08 12:04:18 +0100233 mBuffer.commit(currTime, true);
Jon Medhurste31266f2014-08-04 15:47:44 +0100234
235 // Short reads also mean nothing is left to read
236 if (bytes < contiguous) {
237 break;
238 }
239 }
240 }
241 }
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100242 }
243
244 mBuffer.setDone();
Jon Medhurste31266f2014-08-04 15:47:44 +0100245
Jon Medhurst96b56152014-10-30 18:01:15 +0000246 if (mMveUds >= 0) {
247 gSessionData->maliVideo.stop(mMveUds);
248 }
249
Jon Medhurste31266f2014-08-04 15:47:44 +0100250 mInterruptFd = -1;
251 close(pipefd[0]);
252 close(pipefd[1]);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100253}
254
255void ExternalSource::interrupt() {
Jon Medhurste31266f2014-08-04 15:47:44 +0100256 if (mInterruptFd >= 0) {
257 int8_t c = 0;
258 // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread
259 if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100260 logg->logError("write failed");
Jon Medhurste31266f2014-08-04 15:47:44 +0100261 handleException();
262 }
263 }
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100264}
265
266bool ExternalSource::isDone() {
267 return mBuffer.isDone();
268}
269
270void ExternalSource::write(Sender *sender) {
Jon Medhurste31266f2014-08-04 15:47:44 +0100271 // Don't send external data until the summary packet is sent so that monotonic delta is available
272 if (!gSessionData->mSentSummary) {
273 return;
274 }
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100275 if (!mBuffer.isDone()) {
276 mBuffer.write(sender);
Jon Medhurste31266f2014-08-04 15:47:44 +0100277 sem_post(&mBufferSem);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100278 }
279}