| /* |
| * Copyright (C) 2011 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 "RenderServer.h" |
| |
| #include "RenderThread.h" |
| #include "render_api.h" |
| #include "TcpStream.h" |
| #ifndef _WIN32 |
| #include "UnixStream.h" |
| #include <signal.h> |
| #include <pthread.h> |
| #endif |
| #ifdef _WIN32 |
| #include "Win32PipeStream.h" |
| #endif |
| |
| #include <set> |
| |
| #include <string.h> |
| |
| typedef std::set<RenderThread *> RenderThreadsSet; |
| |
| RenderServer::RenderServer() : |
| m_lock(), |
| m_listenSock(NULL), |
| m_exiting(false) |
| { |
| } |
| |
| RenderServer::~RenderServer() |
| { |
| delete m_listenSock; |
| } |
| |
| |
| extern "C" int gRendererStreamMode; |
| |
| RenderServer *RenderServer::create(char* addr, size_t addrLen) |
| { |
| RenderServer *server = new RenderServer(); |
| if (!server) { |
| return NULL; |
| } |
| |
| if (gRendererStreamMode == STREAM_MODE_TCP) { |
| server->m_listenSock = new TcpStream(); |
| } else { |
| #ifdef _WIN32 |
| server->m_listenSock = new Win32PipeStream(); |
| #else |
| server->m_listenSock = new UnixStream(); |
| #endif |
| } |
| |
| char addrstr[SocketStream::MAX_ADDRSTR_LEN]; |
| if (server->m_listenSock->listen(addrstr) < 0) { |
| ERR("RenderServer::create failed to listen\n"); |
| delete server; |
| return NULL; |
| } |
| |
| size_t len = strlen(addrstr) + 1; |
| if (len > addrLen) { |
| ERR("RenderServer address name too big for provided buffer: %zu > %zu\n", |
| len, addrLen); |
| delete server; |
| return NULL; |
| } |
| memcpy(addr, addrstr, len); |
| |
| return server; |
| } |
| |
| intptr_t RenderServer::main() |
| { |
| RenderThreadsSet threads; |
| |
| #ifndef _WIN32 |
| sigset_t set; |
| sigfillset(&set); |
| pthread_sigmask(SIG_SETMASK, &set, NULL); |
| #endif |
| |
| while(1) { |
| SocketStream *stream = m_listenSock->accept(); |
| if (!stream) { |
| fprintf(stderr,"Error accepting connection, aborting\n"); |
| break; |
| } |
| |
| unsigned int clientFlags; |
| if (!stream->readFully(&clientFlags, sizeof(unsigned int))) { |
| fprintf(stderr,"Error reading clientFlags\n"); |
| delete stream; |
| continue; |
| } |
| |
| DBG("RenderServer: Got new stream!\n"); |
| |
| // check if we have been requested to exit while waiting on accept |
| if ((clientFlags & IOSTREAM_CLIENT_EXIT_SERVER) != 0) { |
| m_exiting = true; |
| delete stream; |
| break; |
| } |
| |
| RenderThread *rt = RenderThread::create(stream, &m_lock); |
| if (!rt) { |
| fprintf(stderr,"Failed to create RenderThread\n"); |
| delete stream; |
| } else if (!rt->start()) { |
| fprintf(stderr,"Failed to start RenderThread\n"); |
| delete rt; |
| delete stream; |
| } |
| |
| // |
| // remove from the threads list threads which are |
| // no longer running |
| // |
| for (RenderThreadsSet::iterator n,t = threads.begin(); |
| t != threads.end(); |
| t = n) { |
| // first find next iterator |
| n = t; |
| n++; |
| |
| // delete and erase the current iterator |
| // if thread is no longer running |
| if ((*t)->isFinished()) { |
| delete (*t); |
| threads.erase(t); |
| } |
| } |
| |
| // if the thread has been created and started, insert it to the list |
| if (rt) { |
| threads.insert(rt); |
| DBG("Started new RenderThread\n"); |
| } |
| } |
| |
| // |
| // Wait for all threads to finish |
| // |
| for (RenderThreadsSet::iterator t = threads.begin(); |
| t != threads.end(); |
| t++) { |
| #ifndef _WIN32 |
| // Note: temporarily disable following steps so emulator does not |
| // freeze on windows when it is shut down, will fix in 1.2 |
| (*t)->forceStop(); |
| (*t)->wait(NULL); |
| #endif |
| delete (*t); |
| } |
| threads.clear(); |
| |
| return 0; |
| } |