Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 1 | /** |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 2 | * Copyright (C) ARM Limited 2010-2015. All rights reserved. |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 3 | * |
| 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 Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 11 | #include <fcntl.h> |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 12 | #include <sys/prctl.h> |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 13 | #include <unistd.h> |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 14 | |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 15 | #include "Child.h" |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 16 | #include "Logging.h" |
| 17 | #include "OlySocket.h" |
| 18 | #include "SessionData.h" |
| 19 | |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 20 | extern Child *child; |
| 21 | |
| 22 | static const char STREAMLINE_ANNOTATE[] = "\0streamline-annotate"; |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 23 | static const char MALI_VIDEO[] = "\0mali-video"; |
| 24 | static const char MALI_VIDEO_STARTUP[] = "\0mali-video-startup"; |
| 25 | static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n"; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 26 | static const char MALI_GRAPHICS[] = "\0mali_thirdparty_server"; |
| 27 | static const char MALI_GRAPHICS_STARTUP[] = "\0mali_thirdparty_client"; |
| 28 | static const char MALI_GRAPHICS_V1[] = "MALI_GRAPHICS 1\n"; |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 29 | |
| 30 | static 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 Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 47 | 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), mAnnotateUds(STREAMLINE_ANNOTATE, sizeof(STREAMLINE_ANNOTATE), true), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) { |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 48 | sem_init(&mBufferSem, 0, 0); |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | ExternalSource::~ExternalSource() { |
| 52 | } |
| 53 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 54 | void ExternalSource::waitFor(const int bytes) { |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 55 | while (mBuffer.bytesAvailable() <= bytes) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 56 | if (gSessionData->mOneShot && gSessionData->mSessionIsActive) { |
| 57 | logg->logMessage("One shot (external)"); |
| 58 | child->endSession(); |
| 59 | } |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 60 | sem_wait(&mBufferSem); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | void ExternalSource::configureConnection(const int fd, const char *const handshake, size_t size) { |
| 65 | if (!setNonblock(fd)) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 66 | logg->logError("Unable to set nonblock on fh"); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 67 | handleException(); |
| 68 | } |
| 69 | |
| 70 | if (!mMonitor.add(fd)) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 71 | logg->logError("Unable to add fh to monitor"); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 72 | handleException(); |
| 73 | } |
| 74 | |
| 75 | // Write the handshake to the circular buffer |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 76 | waitFor(Buffer::MAXSIZE_PACK32 + size - 1); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 77 | mBuffer.packInt(fd); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 78 | mBuffer.writeBytes(handshake, size - 1); |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 79 | mBuffer.commit(1, true); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 80 | } |
| 81 | |
| 82 | bool 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 Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | bool 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 Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 112 | bool ExternalSource::prepare() { |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 113 | 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 Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 117 | !setNonblock(mAnnotateUds.getFd()) || !mMonitor.add(mAnnotateUds.getFd()) || |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 118 | false) { |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 119 | return false; |
| 120 | } |
| 121 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 122 | connectMali(); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 123 | connectMve(); |
| 124 | |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 125 | return true; |
| 126 | } |
| 127 | |
| 128 | void ExternalSource::run() { |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 129 | int pipefd[2]; |
| 130 | |
| 131 | prctl(PR_SET_NAME, (unsigned long)&"gatord-external", 0, 0, 0); |
| 132 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 133 | if (pipe_cloexec(pipefd) != 0) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 134 | logg->logError("pipe failed"); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 135 | handleException(); |
| 136 | } |
| 137 | mInterruptFd = pipefd[1]; |
| 138 | |
| 139 | if (!mMonitor.add(pipefd[0])) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 140 | logg->logError("Monitor::add failed"); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 141 | handleException(); |
| 142 | } |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 143 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 144 | // Notify annotate clients to retry connecting to gatord |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 145 | uint64_t val = 1; |
| 146 | if (::write(gSessionData->mAnnotateStart, &val, sizeof(val)) != sizeof(val)) { |
| 147 | logg->logMessage("Writing to annotate pipe failed"); |
| 148 | } |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 149 | |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 150 | while (gSessionData->mSessionIsActive) { |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 151 | 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 Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 156 | logg->logError("Monitor::wait failed"); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 157 | handleException(); |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 158 | } |
| 159 | |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 160 | const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted; |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 161 | |
| 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 Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 170 | logg->logError("Unable to configure incoming Mali video connection"); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 171 | handleException(); |
| 172 | } |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 173 | } 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 Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 179 | logg->logError("Unable to configure incoming Mali graphics connection"); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 180 | handleException(); |
| 181 | } |
| 182 | } else if (fd == mAnnotate.getFd()) { |
| 183 | int client = mAnnotate.acceptConnection(); |
| 184 | if (!setNonblock(client) || !mMonitor.add(client)) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 185 | 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 Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 192 | handleException(); |
| 193 | } |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 194 | } else if (fd == pipefd[0]) { |
| 195 | // Means interrupt has been called and mSessionIsActive should be reread |
| 196 | } else { |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 197 | /* 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 Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 205 | mBuffer.packInt(fd); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 206 | const int contiguous = mBuffer.contiguousSpaceAvailable(); |
| 207 | const int bytes = read(fd, mBuffer.getWritePos(), contiguous); |
| 208 | if (bytes < 0) { |
| 209 | if (errno == EAGAIN) { |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 210 | // Nothing left to read |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 211 | mBuffer.commit(currTime, true); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 212 | break; |
| 213 | } |
| 214 | // Something else failed, close the socket |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 215 | mBuffer.commit(currTime, true); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 216 | mBuffer.packInt(-1); |
| 217 | mBuffer.packInt(fd); |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 218 | // Here and other commits, always force-flush the buffer as this frame don't work like others |
| 219 | mBuffer.commit(currTime, true); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 220 | close(fd); |
| 221 | break; |
| 222 | } else if (bytes == 0) { |
| 223 | // The other side is closed |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 224 | mBuffer.commit(currTime, true); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 225 | mBuffer.packInt(-1); |
| 226 | mBuffer.packInt(fd); |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 227 | mBuffer.commit(currTime, true); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 228 | close(fd); |
| 229 | break; |
| 230 | } |
| 231 | |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 232 | mBuffer.advanceWrite(bytes); |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 233 | mBuffer.commit(currTime, true); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 234 | |
| 235 | // Short reads also mean nothing is left to read |
| 236 | if (bytes < contiguous) { |
| 237 | break; |
| 238 | } |
| 239 | } |
| 240 | } |
| 241 | } |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 242 | } |
| 243 | |
| 244 | mBuffer.setDone(); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 245 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 246 | if (mMveUds >= 0) { |
| 247 | gSessionData->maliVideo.stop(mMveUds); |
| 248 | } |
| 249 | |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 250 | mInterruptFd = -1; |
| 251 | close(pipefd[0]); |
| 252 | close(pipefd[1]); |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 253 | } |
| 254 | |
| 255 | void ExternalSource::interrupt() { |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 256 | 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 Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 260 | logg->logError("write failed"); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 261 | handleException(); |
| 262 | } |
| 263 | } |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 264 | } |
| 265 | |
| 266 | bool ExternalSource::isDone() { |
| 267 | return mBuffer.isDone(); |
| 268 | } |
| 269 | |
| 270 | void ExternalSource::write(Sender *sender) { |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 271 | // 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 Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 275 | if (!mBuffer.isDone()) { |
| 276 | mBuffer.write(sender); |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 277 | sem_post(&mBufferSem); |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 278 | } |
| 279 | } |