diff options
author | Jesse Hall <jessehall@google.com> | 2012-04-16 12:49:39 -0700 |
---|---|---|
committer | Jesse Hall <jessehall@google.com> | 2012-04-16 15:54:18 -0700 |
commit | ce6c3389061fb9fcdefc94fab2044a8e11600b52 (patch) | |
tree | fedd1a11cbd21ec14bf00be83b8712054f8c5506 /emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp | |
parent | ad0111a77b0f0908cc945dc6e8e8949b75cb8886 (diff) | |
download | sdk-ce6c3389061fb9fcdefc94fab2044a8e11600b52.zip sdk-ce6c3389061fb9fcdefc94fab2044a8e11600b52.tar.gz sdk-ce6c3389061fb9fcdefc94fab2044a8e11600b52.tar.bz2 |
Move emulator GLES from development.git to sdk.git
The emulator GLES support has two interfaces: a host shared library
interface used by QEMU, and a protocol between the platform and the
host. The host library interface is not versioned; QEMU and the GLES
renderer must match. The protocol on the other hand must be backwards
compatible: a new GLES renderer must support an older platform image.
Thus for branching purposes it makes more sense to put the GLES
renderer in sdk.git, which is branched along with qemu.git for SDK
releases. Platform images will be built against the protocol version
in the platform branch of sdk.git.
Change-Id: I2c3bce627ecfd0a4b3e688d1839fe10755a21e58
Diffstat (limited to 'emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp')
-rw-r--r-- | emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp b/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp new file mode 100644 index 0000000..e1a0b9b --- /dev/null +++ b/emulator/opengl/shared/OpenglCodecCommon/Win32PipeStream.cpp @@ -0,0 +1,239 @@ +/* +* 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 "Win32PipeStream.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <windows.h> + +#ifndef _WIN32 +#error ONLY BUILD THIS SOURCE FILE FOR WINDOWS! +#endif + +/* The official documentation states that the name of a given named + * pipe cannot be more than 256 characters long. + */ +#define NAMED_PIPE_MAX 256 + +Win32PipeStream::Win32PipeStream(size_t bufSize) : + SocketStream(bufSize), + m_pipe(INVALID_HANDLE_VALUE) +{ +} + +Win32PipeStream::Win32PipeStream(HANDLE pipe, size_t bufSize) : + SocketStream(-1, bufSize), + m_pipe(pipe) +{ +} + +Win32PipeStream::~Win32PipeStream() +{ + if (m_pipe != INVALID_HANDLE_VALUE) { + CloseHandle(m_pipe); + m_pipe = INVALID_HANDLE_VALUE; + } +} + +/* Initialize the pipe name corresponding to a given port + */ +static void +make_pipe_name(char *path, size_t pathlen, int port_number) +{ + snprintf(path, pathlen, "\\\\.\\pipe\\qemu-gles-%d", port_number); +} + + +/* Technical note: Named pipes work differently from BSD Sockets. + * One does not create/bind a pipe, and collect a new handle each + * time a client connects with accept(). + * + * Instead, the server creates a new pipe instance each time it wants + * to get a new client connection, then calls ConnectNamedPipe() to + * wait for a connection. + * + * So listen() is a no-op, and accept() really creates the pipe handle. + * + * Also, connect() must create a pipe handle with CreateFile() and + * wait for a server instance with WaitNamedPipe() + */ +int Win32PipeStream::listen(unsigned short port) +{ + // just save the port number for accept() + m_port = port; + return 0; +} + +SocketStream * Win32PipeStream::accept() +{ + char path[NAMED_PIPE_MAX+1]; + SocketStream* clientStream; + HANDLE pipe; + + make_pipe_name(path, sizeof(path), m_port); + + pipe = ::CreateNamedPipe( + path, // pipe name + PIPE_ACCESS_DUPLEX, // read-write access + PIPE_TYPE_BYTE | // byte-oriented writes + PIPE_READMODE_BYTE | // byte-oriented reads + PIPE_WAIT, // blocking operations + PIPE_UNLIMITED_INSTANCES, // no limit on clients + 4096, // input buffer size + 4096, // output buffer size + 0, // client time-out + NULL); // default security attributes + + if (pipe == INVALID_HANDLE_VALUE) { + ERR("%s: CreateNamedPipe failed %d\n", __FUNCTION__, (int)GetLastError()); + return NULL; + } + + // Stupid Win32 API design: If a client is already connected, then + // ConnectNamedPipe will return 0, and GetLastError() will return + // ERROR_PIPE_CONNECTED. This is not an error! It just means that the + // function didn't have to wait. + // + if (::ConnectNamedPipe(pipe, NULL) == 0 && GetLastError() != ERROR_PIPE_CONNECTED) { + ERR("%s: ConnectNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError()); + CloseHandle(pipe); + return NULL; + } + + clientStream = new Win32PipeStream(pipe, m_bufsize); + return clientStream; +} + +int Win32PipeStream::connect(unsigned short port) +{ + char path[NAMED_PIPE_MAX+1]; + HANDLE pipe; + int tries = 10; + + make_pipe_name(path, sizeof(path), port); + + /* We're going to loop in order to wait for the pipe server to + * be setup properly. + */ + for (; tries > 0; tries--) { + pipe = ::CreateFile( + path, // pipe name + GENERIC_READ | GENERIC_WRITE, // read & write + 0, // no sharing + NULL, // default security attrs + OPEN_EXISTING, // open existing pipe + 0, // default attributes + NULL); // no template file + + /* If we have a valid pipe handle, break from the loop */ + if (pipe != INVALID_HANDLE_VALUE) { + break; + } + + /* We can get here if the pipe is busy, i.e. if the server hasn't + * create a new pipe instance to service our request. In which case + * GetLastError() will return ERROR_PIPE_BUSY. + * + * If so, then use WaitNamedPipe() to wait for a decent time + * to try again. + */ + if (GetLastError() != ERROR_PIPE_BUSY) { + /* Not ERROR_PIPE_BUSY */ + ERR("%s: CreateFile failed: %d\n", __FUNCTION__, (int)GetLastError()); + errno = EINVAL; + return -1; + } + + /* Wait for 5 seconds */ + if ( !WaitNamedPipe(path, 5000) ) { + ERR("%s: WaitNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError()); + errno = EINVAL; + return -1; + } + } + + m_pipe = pipe; + return 0; +} + +/* Special buffer methods, since we can't use socket functions here */ + +int Win32PipeStream::commitBuffer(size_t size) +{ + if (m_pipe == INVALID_HANDLE_VALUE) + return -1; + + size_t res = size; + int retval = 0; + + while (res > 0) { + DWORD written; + if (! ::WriteFile(m_pipe, (const char *)m_buf + (size - res), res, &written, NULL)) { + retval = -1; + ERR("%s: failed: %d\n", __FUNCTION__, (int)GetLastError()); + break; + } + res -= written; + } + return retval; +} + +const unsigned char *Win32PipeStream::readFully(void *buf, size_t len) +{ + const unsigned char* ret = NULL; + + if (m_pipe == INVALID_HANDLE_VALUE) + return NULL; + + if (!buf) { + return NULL; // do not allow NULL buf in that implementation + } + + size_t res = len; + while (res > 0) { + DWORD readcount = 0; + if (! ::ReadFile(m_pipe, (char *)buf + (len - res), res, &readcount, NULL) || readcount == 0) { + errno = (int)GetLastError(); + return NULL; + } + res -= readcount; + } + return (const unsigned char *)buf; +} + +const unsigned char *Win32PipeStream::read( void *buf, size_t *inout_len) +{ + size_t len = *inout_len; + DWORD readcount; + + if (m_pipe == INVALID_HANDLE_VALUE) + return NULL; + + if (!buf) { + return NULL; // do not allow NULL buf in that implementation + } + + if (!::ReadFile(m_pipe, (char *)buf, len, &readcount, NULL)) { + errno = (int)GetLastError(); + return NULL; + } + + *inout_len = (size_t)readcount; + return (const unsigned char *)buf; +} |