xref: /aosp_15_r20/external/mesa3d/src/gfxstream/guest/connection-manager/QemuPipeStream.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright 2011 Google LLC
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  */
5*61046927SAndroid Build Coastguard Worker #include "QemuPipeStream.h"
6*61046927SAndroid Build Coastguard Worker 
7*61046927SAndroid Build Coastguard Worker #include <errno.h>
8*61046927SAndroid Build Coastguard Worker #include <qemu_pipe_bp.h>
9*61046927SAndroid Build Coastguard Worker #include <stdio.h>
10*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
11*61046927SAndroid Build Coastguard Worker #include <string.h>
12*61046927SAndroid Build Coastguard Worker #include <unistd.h>
13*61046927SAndroid Build Coastguard Worker 
14*61046927SAndroid Build Coastguard Worker #include "util/log.h"
15*61046927SAndroid Build Coastguard Worker 
16*61046927SAndroid Build Coastguard Worker static const size_t kReadSize = 512 * 1024;
17*61046927SAndroid Build Coastguard Worker static const size_t kWriteOffset = kReadSize;
18*61046927SAndroid Build Coastguard Worker 
QemuPipeStream(size_t bufSize)19*61046927SAndroid Build Coastguard Worker QemuPipeStream::QemuPipeStream(size_t bufSize)
20*61046927SAndroid Build Coastguard Worker     : IOStream(bufSize), m_sock(-1), m_bufsize(bufSize), m_buf(NULL), m_read(0), m_readLeft(0) {}
21*61046927SAndroid Build Coastguard Worker 
QemuPipeStream(QEMU_PIPE_HANDLE sock,size_t bufSize)22*61046927SAndroid Build Coastguard Worker QemuPipeStream::QemuPipeStream(QEMU_PIPE_HANDLE sock, size_t bufSize)
23*61046927SAndroid Build Coastguard Worker     : IOStream(bufSize), m_sock(sock), m_bufsize(bufSize), m_buf(NULL), m_read(0), m_readLeft(0) {}
24*61046927SAndroid Build Coastguard Worker 
~QemuPipeStream()25*61046927SAndroid Build Coastguard Worker QemuPipeStream::~QemuPipeStream() {
26*61046927SAndroid Build Coastguard Worker     if (valid()) {
27*61046927SAndroid Build Coastguard Worker         flush();
28*61046927SAndroid Build Coastguard Worker         qemu_pipe_close((QEMU_PIPE_HANDLE)m_sock);
29*61046927SAndroid Build Coastguard Worker     }
30*61046927SAndroid Build Coastguard Worker     if (m_buf != NULL) {
31*61046927SAndroid Build Coastguard Worker         free(m_buf);
32*61046927SAndroid Build Coastguard Worker     }
33*61046927SAndroid Build Coastguard Worker }
34*61046927SAndroid Build Coastguard Worker 
connect(const char * serviceName)35*61046927SAndroid Build Coastguard Worker int QemuPipeStream::connect(const char* serviceName) {
36*61046927SAndroid Build Coastguard Worker     m_sock = (int)qemu_pipe_open("opengles");
37*61046927SAndroid Build Coastguard Worker     if (!valid()) {
38*61046927SAndroid Build Coastguard Worker         mesa_loge("%s: failed to connect to opengles pipe", __FUNCTION__);
39*61046927SAndroid Build Coastguard Worker         qemu_pipe_print_error(m_sock);
40*61046927SAndroid Build Coastguard Worker         return -1;
41*61046927SAndroid Build Coastguard Worker     }
42*61046927SAndroid Build Coastguard Worker     return 0;
43*61046927SAndroid Build Coastguard Worker }
44*61046927SAndroid Build Coastguard Worker 
processPipeInit()45*61046927SAndroid Build Coastguard Worker uint64_t QemuPipeStream::processPipeInit() {
46*61046927SAndroid Build Coastguard Worker     QEMU_PIPE_HANDLE processPipe = qemu_pipe_open("GLProcessPipe");
47*61046927SAndroid Build Coastguard Worker 
48*61046927SAndroid Build Coastguard Worker     uint64_t procUID = 0;
49*61046927SAndroid Build Coastguard Worker     if (!qemu_pipe_valid(processPipe)) {
50*61046927SAndroid Build Coastguard Worker         processPipe = 0;
51*61046927SAndroid Build Coastguard Worker         mesa_logi("Process pipe failed");
52*61046927SAndroid Build Coastguard Worker         return 0;
53*61046927SAndroid Build Coastguard Worker     }
54*61046927SAndroid Build Coastguard Worker 
55*61046927SAndroid Build Coastguard Worker     // Send a confirmation int to the host
56*61046927SAndroid Build Coastguard Worker     int32_t confirmInt = 100;
57*61046927SAndroid Build Coastguard Worker     if (qemu_pipe_write_fully(processPipe, &confirmInt, sizeof(confirmInt))) {  // failed
58*61046927SAndroid Build Coastguard Worker         qemu_pipe_close(processPipe);
59*61046927SAndroid Build Coastguard Worker         processPipe = 0;
60*61046927SAndroid Build Coastguard Worker         mesa_logi("Process pipe failed");
61*61046927SAndroid Build Coastguard Worker         return 0;
62*61046927SAndroid Build Coastguard Worker     }
63*61046927SAndroid Build Coastguard Worker 
64*61046927SAndroid Build Coastguard Worker     // Ask the host for per-process unique ID
65*61046927SAndroid Build Coastguard Worker     if (qemu_pipe_read_fully(processPipe, &procUID, sizeof(procUID))) {
66*61046927SAndroid Build Coastguard Worker         qemu_pipe_close(processPipe);
67*61046927SAndroid Build Coastguard Worker         processPipe = 0;
68*61046927SAndroid Build Coastguard Worker         procUID = 0;
69*61046927SAndroid Build Coastguard Worker         mesa_logi("Process pipe failed");
70*61046927SAndroid Build Coastguard Worker         return 0;
71*61046927SAndroid Build Coastguard Worker     }
72*61046927SAndroid Build Coastguard Worker 
73*61046927SAndroid Build Coastguard Worker     return procUID;
74*61046927SAndroid Build Coastguard Worker }
75*61046927SAndroid Build Coastguard Worker 
allocBuffer(size_t minSize)76*61046927SAndroid Build Coastguard Worker void* QemuPipeStream::allocBuffer(size_t minSize) {
77*61046927SAndroid Build Coastguard Worker     // Add dedicated read buffer space at the front of the buffer.
78*61046927SAndroid Build Coastguard Worker     minSize += kReadSize;
79*61046927SAndroid Build Coastguard Worker 
80*61046927SAndroid Build Coastguard Worker     size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize);
81*61046927SAndroid Build Coastguard Worker     if (!m_buf) {
82*61046927SAndroid Build Coastguard Worker         m_buf = (unsigned char*)malloc(allocSize);
83*61046927SAndroid Build Coastguard Worker     } else if (m_bufsize < allocSize) {
84*61046927SAndroid Build Coastguard Worker         unsigned char* p = (unsigned char*)realloc(m_buf, allocSize);
85*61046927SAndroid Build Coastguard Worker         if (p != NULL) {
86*61046927SAndroid Build Coastguard Worker             m_buf = p;
87*61046927SAndroid Build Coastguard Worker             m_bufsize = allocSize;
88*61046927SAndroid Build Coastguard Worker         } else {
89*61046927SAndroid Build Coastguard Worker             mesa_loge("realloc (%zu) failed\n", allocSize);
90*61046927SAndroid Build Coastguard Worker             free(m_buf);
91*61046927SAndroid Build Coastguard Worker             m_buf = NULL;
92*61046927SAndroid Build Coastguard Worker             m_bufsize = 0;
93*61046927SAndroid Build Coastguard Worker         }
94*61046927SAndroid Build Coastguard Worker     }
95*61046927SAndroid Build Coastguard Worker 
96*61046927SAndroid Build Coastguard Worker     return m_buf + kWriteOffset;
97*61046927SAndroid Build Coastguard Worker };
98*61046927SAndroid Build Coastguard Worker 
commitBuffer(size_t size)99*61046927SAndroid Build Coastguard Worker int QemuPipeStream::commitBuffer(size_t size) {
100*61046927SAndroid Build Coastguard Worker     if (size == 0) return 0;
101*61046927SAndroid Build Coastguard Worker     return writeFully(m_buf + kWriteOffset, size);
102*61046927SAndroid Build Coastguard Worker }
103*61046927SAndroid Build Coastguard Worker 
writeFully(const void * buf,size_t len)104*61046927SAndroid Build Coastguard Worker int QemuPipeStream::writeFully(const void* buf, size_t len) {
105*61046927SAndroid Build Coastguard Worker     return qemu_pipe_write_fully(m_sock, buf, len);
106*61046927SAndroid Build Coastguard Worker }
107*61046927SAndroid Build Coastguard Worker 
readFully(void * buf,size_t len)108*61046927SAndroid Build Coastguard Worker const unsigned char* QemuPipeStream::readFully(void* buf, size_t len) {
109*61046927SAndroid Build Coastguard Worker     return commitBufferAndReadFully(0, buf, len);
110*61046927SAndroid Build Coastguard Worker }
111*61046927SAndroid Build Coastguard Worker 
commitBufferAndReadFully(size_t writeSize,void * userReadBufPtr,size_t totalReadSize)112*61046927SAndroid Build Coastguard Worker const unsigned char* QemuPipeStream::commitBufferAndReadFully(size_t writeSize,
113*61046927SAndroid Build Coastguard Worker                                                               void* userReadBufPtr,
114*61046927SAndroid Build Coastguard Worker                                                               size_t totalReadSize) {
115*61046927SAndroid Build Coastguard Worker     unsigned char* userReadBuf = static_cast<unsigned char*>(userReadBufPtr);
116*61046927SAndroid Build Coastguard Worker 
117*61046927SAndroid Build Coastguard Worker     if (!valid()) return NULL;
118*61046927SAndroid Build Coastguard Worker 
119*61046927SAndroid Build Coastguard Worker     if (!userReadBuf) {
120*61046927SAndroid Build Coastguard Worker         if (totalReadSize > 0) {
121*61046927SAndroid Build Coastguard Worker             mesa_loge(
122*61046927SAndroid Build Coastguard Worker                 "QemuPipeStream::commitBufferAndReadFully failed, userReadBuf=NULL, totalReadSize "
123*61046927SAndroid Build Coastguard Worker                 "%zu, lethal"
124*61046927SAndroid Build Coastguard Worker                 " error, exiting.",
125*61046927SAndroid Build Coastguard Worker                 totalReadSize);
126*61046927SAndroid Build Coastguard Worker             abort();
127*61046927SAndroid Build Coastguard Worker         }
128*61046927SAndroid Build Coastguard Worker         if (!writeSize) {
129*61046927SAndroid Build Coastguard Worker             return NULL;
130*61046927SAndroid Build Coastguard Worker         }
131*61046927SAndroid Build Coastguard Worker     }
132*61046927SAndroid Build Coastguard Worker 
133*61046927SAndroid Build Coastguard Worker     // Advance buffered read if not yet consumed.
134*61046927SAndroid Build Coastguard Worker     size_t remaining = totalReadSize;
135*61046927SAndroid Build Coastguard Worker     size_t bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
136*61046927SAndroid Build Coastguard Worker     if (bufferedReadSize) {
137*61046927SAndroid Build Coastguard Worker         memcpy(userReadBuf, m_buf + (m_read - m_readLeft), bufferedReadSize);
138*61046927SAndroid Build Coastguard Worker         remaining -= bufferedReadSize;
139*61046927SAndroid Build Coastguard Worker         m_readLeft -= bufferedReadSize;
140*61046927SAndroid Build Coastguard Worker     }
141*61046927SAndroid Build Coastguard Worker 
142*61046927SAndroid Build Coastguard Worker     // Early out if nothing left to do.
143*61046927SAndroid Build Coastguard Worker     if (!writeSize && !remaining) {
144*61046927SAndroid Build Coastguard Worker         return userReadBuf;
145*61046927SAndroid Build Coastguard Worker     }
146*61046927SAndroid Build Coastguard Worker 
147*61046927SAndroid Build Coastguard Worker     writeFully(m_buf + kWriteOffset, writeSize);
148*61046927SAndroid Build Coastguard Worker 
149*61046927SAndroid Build Coastguard Worker     // Now done writing. Early out if no reading left to do.
150*61046927SAndroid Build Coastguard Worker     if (!remaining) {
151*61046927SAndroid Build Coastguard Worker         return userReadBuf;
152*61046927SAndroid Build Coastguard Worker     }
153*61046927SAndroid Build Coastguard Worker 
154*61046927SAndroid Build Coastguard Worker     // Read up to kReadSize bytes if all buffered read has been consumed.
155*61046927SAndroid Build Coastguard Worker     size_t maxRead = m_readLeft ? 0 : kReadSize;
156*61046927SAndroid Build Coastguard Worker 
157*61046927SAndroid Build Coastguard Worker     ssize_t actual = 0;
158*61046927SAndroid Build Coastguard Worker 
159*61046927SAndroid Build Coastguard Worker     if (maxRead) {
160*61046927SAndroid Build Coastguard Worker         actual = qemu_pipe_read(m_sock, m_buf, maxRead);
161*61046927SAndroid Build Coastguard Worker         // Updated buffered read size.
162*61046927SAndroid Build Coastguard Worker         if (actual > 0) {
163*61046927SAndroid Build Coastguard Worker             m_read = m_readLeft = actual;
164*61046927SAndroid Build Coastguard Worker         }
165*61046927SAndroid Build Coastguard Worker 
166*61046927SAndroid Build Coastguard Worker         if (actual == 0) {
167*61046927SAndroid Build Coastguard Worker             mesa_logi("%s: end of pipe", __FUNCTION__);
168*61046927SAndroid Build Coastguard Worker             return NULL;
169*61046927SAndroid Build Coastguard Worker         }
170*61046927SAndroid Build Coastguard Worker     }
171*61046927SAndroid Build Coastguard Worker 
172*61046927SAndroid Build Coastguard Worker     // Consume buffered read and read more if necessary.
173*61046927SAndroid Build Coastguard Worker     while (remaining) {
174*61046927SAndroid Build Coastguard Worker         bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
175*61046927SAndroid Build Coastguard Worker         if (bufferedReadSize) {
176*61046927SAndroid Build Coastguard Worker             memcpy(userReadBuf + (totalReadSize - remaining), m_buf + (m_read - m_readLeft),
177*61046927SAndroid Build Coastguard Worker                    bufferedReadSize);
178*61046927SAndroid Build Coastguard Worker             remaining -= bufferedReadSize;
179*61046927SAndroid Build Coastguard Worker             m_readLeft -= bufferedReadSize;
180*61046927SAndroid Build Coastguard Worker             continue;
181*61046927SAndroid Build Coastguard Worker         }
182*61046927SAndroid Build Coastguard Worker 
183*61046927SAndroid Build Coastguard Worker         actual = qemu_pipe_read(m_sock, m_buf, kReadSize);
184*61046927SAndroid Build Coastguard Worker 
185*61046927SAndroid Build Coastguard Worker         if (actual == 0) {
186*61046927SAndroid Build Coastguard Worker             mesa_logi("%s: Failed reading from pipe: %d", __FUNCTION__, errno);
187*61046927SAndroid Build Coastguard Worker             return NULL;
188*61046927SAndroid Build Coastguard Worker         }
189*61046927SAndroid Build Coastguard Worker 
190*61046927SAndroid Build Coastguard Worker         if (actual > 0) {
191*61046927SAndroid Build Coastguard Worker             m_read = m_readLeft = actual;
192*61046927SAndroid Build Coastguard Worker             continue;
193*61046927SAndroid Build Coastguard Worker         }
194*61046927SAndroid Build Coastguard Worker 
195*61046927SAndroid Build Coastguard Worker         if (!qemu_pipe_try_again(actual)) {
196*61046927SAndroid Build Coastguard Worker             mesa_logi("%s: Error reading from pipe: %d", __FUNCTION__, errno);
197*61046927SAndroid Build Coastguard Worker             return NULL;
198*61046927SAndroid Build Coastguard Worker         }
199*61046927SAndroid Build Coastguard Worker     }
200*61046927SAndroid Build Coastguard Worker 
201*61046927SAndroid Build Coastguard Worker     return userReadBuf;
202*61046927SAndroid Build Coastguard Worker }
203*61046927SAndroid Build Coastguard Worker 
read(void * buf,size_t * inout_len)204*61046927SAndroid Build Coastguard Worker const unsigned char* QemuPipeStream::read(void* buf, size_t* inout_len) {
205*61046927SAndroid Build Coastguard Worker     if (!valid()) return NULL;
206*61046927SAndroid Build Coastguard Worker     if (!buf) {
207*61046927SAndroid Build Coastguard Worker         mesa_loge("QemuPipeStream::read failed, buf=NULL");
208*61046927SAndroid Build Coastguard Worker         return NULL;  // do not allow NULL buf in that implementation
209*61046927SAndroid Build Coastguard Worker     }
210*61046927SAndroid Build Coastguard Worker 
211*61046927SAndroid Build Coastguard Worker     int n = recv(buf, *inout_len);
212*61046927SAndroid Build Coastguard Worker 
213*61046927SAndroid Build Coastguard Worker     if (n > 0) {
214*61046927SAndroid Build Coastguard Worker         *inout_len = n;
215*61046927SAndroid Build Coastguard Worker         return (const unsigned char*)buf;
216*61046927SAndroid Build Coastguard Worker     }
217*61046927SAndroid Build Coastguard Worker 
218*61046927SAndroid Build Coastguard Worker     return NULL;
219*61046927SAndroid Build Coastguard Worker }
220*61046927SAndroid Build Coastguard Worker 
valid()221*61046927SAndroid Build Coastguard Worker bool QemuPipeStream::valid() { return qemu_pipe_valid(m_sock); }
222*61046927SAndroid Build Coastguard Worker 
recv(void * buf,size_t len)223*61046927SAndroid Build Coastguard Worker int QemuPipeStream::recv(void* buf, size_t len) {
224*61046927SAndroid Build Coastguard Worker     if (!valid()) return int(ERR_INVALID_SOCKET);
225*61046927SAndroid Build Coastguard Worker     char* p = (char*)buf;
226*61046927SAndroid Build Coastguard Worker     int ret = 0;
227*61046927SAndroid Build Coastguard Worker     while (len > 0) {
228*61046927SAndroid Build Coastguard Worker         int res = qemu_pipe_read(m_sock, p, len);
229*61046927SAndroid Build Coastguard Worker         if (res > 0) {
230*61046927SAndroid Build Coastguard Worker             p += res;
231*61046927SAndroid Build Coastguard Worker             ret += res;
232*61046927SAndroid Build Coastguard Worker             len -= res;
233*61046927SAndroid Build Coastguard Worker             continue;
234*61046927SAndroid Build Coastguard Worker         }
235*61046927SAndroid Build Coastguard Worker         if (res == 0) { /* EOF */
236*61046927SAndroid Build Coastguard Worker             break;
237*61046927SAndroid Build Coastguard Worker         }
238*61046927SAndroid Build Coastguard Worker         if (qemu_pipe_try_again(res)) {
239*61046927SAndroid Build Coastguard Worker             continue;
240*61046927SAndroid Build Coastguard Worker         }
241*61046927SAndroid Build Coastguard Worker 
242*61046927SAndroid Build Coastguard Worker         /* A real error */
243*61046927SAndroid Build Coastguard Worker         if (ret == 0) ret = -1;
244*61046927SAndroid Build Coastguard Worker         break;
245*61046927SAndroid Build Coastguard Worker     }
246*61046927SAndroid Build Coastguard Worker     return ret;
247*61046927SAndroid Build Coastguard Worker }
248