Initial work
This commit is contained in:
commit
3222551702
374 changed files with 40290 additions and 0 deletions
2
external/android-emugl/shared/CMakeLists.txt
vendored
Normal file
2
external/android-emugl/shared/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
add_subdirectory(emugl)
|
||||
add_subdirectory(OpenglCodecCommon)
|
||||
24
external/android-emugl/shared/OpenglCodecCommon/Android.mk
vendored
Normal file
24
external/android-emugl/shared/OpenglCodecCommon/Android.mk
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# This build script corresponds to a library containing many definitions
|
||||
# common to both the guest and the host. They relate to
|
||||
#
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
commonSources := \
|
||||
glUtils.cpp \
|
||||
ChecksumCalculator.cpp \
|
||||
ChecksumCalculatorThreadInfo.cpp \
|
||||
|
||||
host_commonSources := $(commonSources)
|
||||
|
||||
host_commonLdLibs := $(CXX_STD_LIB)
|
||||
|
||||
### OpenglCodecCommon host ##############################################
|
||||
$(call emugl-begin-host-static-library,libOpenglCodecCommon)
|
||||
|
||||
LOCAL_SRC_FILES := $(host_commonSources)
|
||||
$(call emugl-import, libemugl_common)
|
||||
$(call emugl-export,C_INCLUDES,$(EMUGL_PATH)/host/include/libOpenglRender $(LOCAL_PATH))
|
||||
$(call emugl-export,LDLIBS,$(host_commonLdLibs))
|
||||
$(call emugl-end-module)
|
||||
|
||||
|
||||
6
external/android-emugl/shared/OpenglCodecCommon/CMakeLists.txt
vendored
Normal file
6
external/android-emugl/shared/OpenglCodecCommon/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
set(SOURCES
|
||||
glUtils.cpp
|
||||
ChecksumCalculator.cpp
|
||||
ChecksumCalculatorThreadInfo.cpp)
|
||||
|
||||
add_library(OpenglCodecCommon ${SOURCES})
|
||||
154
external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculator.cpp
vendored
Normal file
154
external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculator.cpp
vendored
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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 "ChecksumCalculator.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
|
||||
// Checklist when implementing new protocol:
|
||||
// 1. update CHECKSUMHELPER_MAX_VERSION
|
||||
// 2. update maxChecksumSize()
|
||||
// 3. update checksumByteSize()
|
||||
// 4. update addBuffer, writeChecksum, resetChecksum, validate
|
||||
|
||||
// change CHECKSUMHELPER_MAX_VERSION when you want to update the protocol version
|
||||
#define CHECKSUMHELPER_MAX_VERSION 1
|
||||
|
||||
// checksum buffer size
|
||||
// Please add a new checksum buffer size when implementing a new protocol,
|
||||
// as well as modifying the maxChecksumSize function.
|
||||
static const size_t kV1ChecksumSize = 8;
|
||||
|
||||
static constexpr size_t maxChecksumSize() {
|
||||
return 0 > kV1ChecksumSize ? 0 : kV1ChecksumSize;
|
||||
}
|
||||
|
||||
static const size_t kMaxChecksumSize = maxChecksumSize();
|
||||
|
||||
// utility macros to create checksum string at compilation time
|
||||
#define CHECKSUMHELPER_VERSION_STR_PREFIX "ANDROID_EMU_CHECKSUM_HELPER_v"
|
||||
#define CHECKSUMHELPER_MACRO_TO_STR(x) #x
|
||||
#define CHECKSUMHELPER_MACRO_VAL_TO_STR(x) CHECKSUMHELPER_MACRO_TO_STR(x)
|
||||
|
||||
static const uint32_t kMaxVersion = CHECKSUMHELPER_MAX_VERSION;
|
||||
static const char* kMaxVersionStrPrefix = CHECKSUMHELPER_VERSION_STR_PREFIX;
|
||||
static const char* kMaxVersionStr = CHECKSUMHELPER_VERSION_STR_PREFIX CHECKSUMHELPER_MACRO_VAL_TO_STR(CHECKSUMHELPER_MAX_VERSION);
|
||||
|
||||
#undef CHECKSUMHELPER_MAX_VERSION
|
||||
#undef CHECKSUMHELPER_VERSION_STR_PREFIX
|
||||
#undef CHECKSUMHELPER_MACRO_TO_STR
|
||||
#undef CHECKSUMHELPER_MACRO_VAL_TO_STR
|
||||
|
||||
uint32_t ChecksumCalculator::getMaxVersion() {return kMaxVersion;}
|
||||
const char* ChecksumCalculator::getMaxVersionStr() {return kMaxVersionStr;}
|
||||
const char* ChecksumCalculator::getMaxVersionStrPrefix() {return kMaxVersionStrPrefix;}
|
||||
|
||||
bool ChecksumCalculator::setVersion(uint32_t version) {
|
||||
if (version > kMaxVersion) { // unsupported version
|
||||
LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Unsupported version Version %d\n",
|
||||
__FUNCTION__, m_version);
|
||||
return false;
|
||||
}
|
||||
if (m_isEncodingChecksum) { // setVersion is called in the middle of encoding checksums
|
||||
LOG_CHECKSUMHELPER("%s: called between addBuffer and writeChecksum\n",
|
||||
__FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
m_version = version;
|
||||
LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Version %d\n", __FUNCTION__,
|
||||
m_version);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t ChecksumCalculator::checksumByteSize() const {
|
||||
switch (m_version) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return sizeof(uint32_t) + sizeof(m_numWrite);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ChecksumCalculator::addBuffer(const void* buf, size_t packetLen) {
|
||||
m_isEncodingChecksum = true;
|
||||
switch (m_version) {
|
||||
case 1:
|
||||
m_v1BufferTotalLength += packetLen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool ChecksumCalculator::writeChecksum(void* outputChecksum, size_t outputChecksumLen) {
|
||||
if (outputChecksumLen < checksumByteSize()) return false;
|
||||
char *checksumPtr = (char *)outputChecksum;
|
||||
switch (m_version) {
|
||||
case 1: { // protocol v1 is to reverse the packetLen and write it at the end
|
||||
uint32_t val = computeV1Checksum();
|
||||
memcpy(checksumPtr, &val, sizeof(val));
|
||||
memcpy(checksumPtr+sizeof(val), &m_numWrite, sizeof(m_numWrite));
|
||||
break;
|
||||
}
|
||||
}
|
||||
resetChecksum();
|
||||
m_numWrite++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChecksumCalculator::resetChecksum() {
|
||||
switch (m_version) {
|
||||
case 1:
|
||||
m_v1BufferTotalLength = 0;
|
||||
break;
|
||||
}
|
||||
m_isEncodingChecksum = false;
|
||||
}
|
||||
|
||||
bool ChecksumCalculator::validate(const void* expectedChecksum, size_t expectedChecksumLen) {
|
||||
size_t checksumSize = checksumByteSize();
|
||||
if (expectedChecksumLen != checksumSize) {
|
||||
m_numRead++;
|
||||
resetChecksum();
|
||||
return false;
|
||||
}
|
||||
// buffers for computing the checksum
|
||||
unsigned char sChecksumBuffer[kMaxChecksumSize];
|
||||
switch (m_version) {
|
||||
case 1: {
|
||||
uint32_t val = computeV1Checksum();
|
||||
memcpy(sChecksumBuffer, &val, sizeof(val));
|
||||
memcpy(sChecksumBuffer+sizeof(val), &m_numRead, sizeof(m_numRead));
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool isValid = !memcmp(sChecksumBuffer, expectedChecksum, checksumSize);
|
||||
m_numRead++;
|
||||
resetChecksum();
|
||||
return isValid;
|
||||
}
|
||||
|
||||
uint32_t ChecksumCalculator::computeV1Checksum() {
|
||||
uint32_t revLen = m_v1BufferTotalLength;
|
||||
revLen = (revLen & 0xffff0000) >> 16 | (revLen & 0x0000ffff) << 16;
|
||||
revLen = (revLen & 0xff00ff00) >> 8 | (revLen & 0x00ff00ff) << 8;
|
||||
revLen = (revLen & 0xf0f0f0f0) >> 4 | (revLen & 0x0f0f0f0f) << 4;
|
||||
revLen = (revLen & 0xcccccccc) >> 2 | (revLen & 0x33333333) << 2;
|
||||
revLen = (revLen & 0xaaaaaaaa) >> 1 | (revLen & 0x55555555) << 1;
|
||||
return revLen;
|
||||
}
|
||||
181
external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculator.h
vendored
Normal file
181
external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculator.h
vendored
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Set TRACE_CHECKSUMHELPER to 1 to debug creation/destruction of GLprotocol
|
||||
// instances.
|
||||
#define TRACE_CHECKSUMHELPER 0
|
||||
|
||||
#if TRACE_CHECKSUMHELPER
|
||||
#define LOG_CHECKSUMHELPER(x...) fprintf(stderr, x)
|
||||
#else
|
||||
#define LOG_CHECKSUMHELPER(x...)
|
||||
#endif
|
||||
|
||||
// ChecksumCalculator adds checksum as an array of bytes to GL pipe communication, which
|
||||
// size depends on the protocol version. Each pipe should use one ChecksumCalculator.
|
||||
// It can:
|
||||
// (1) take a list of buffers one by one and compute their checksum string,
|
||||
// in this case the checksum should be as the data in those buffers are
|
||||
// concatenated;
|
||||
// (2) compute the checksum of the buffer list, then either write them into
|
||||
// a buffer provided by user, or compare it against a checksum provided
|
||||
// by user
|
||||
// (3) support different checksum version in future.
|
||||
//
|
||||
// For backward compatibility, checksum version 0 behaves the same as there is
|
||||
// no checksum (i.e., checksumByteSize returns 0, validate always returns true,
|
||||
// addBuffer and writeCheckSum does nothing).
|
||||
//
|
||||
// Notice that to detect package lost, ChecksumCalculator also keeps track of how
|
||||
// many times it generates/validates checksums, and might use it as part of the
|
||||
// checksum.
|
||||
//
|
||||
// To evaluate checksums from a list of data buffers buf1, buf2... Please call
|
||||
// addBuffer(buf1, buf1len), addBuffer(buf2, buf2len) ... in order.
|
||||
// Then if the checksum needs to be encoded into a buffer, one needs to allocate
|
||||
// a checksum buffer with size checksumByteSize(), and call
|
||||
// writeChecksum(checksumBuffer) to write the checksum to the buffer.
|
||||
// If the checksum needs to be validated against an existing one, one needs to
|
||||
// call validate(existChecksum, existChecksumLen).
|
||||
//
|
||||
// The checksum generator and validator must be set to the same version, and
|
||||
// the validator must check ALL checksums in the order they are generated,
|
||||
// otherwise the validation function will return false.
|
||||
//
|
||||
// It is allowed to change the checksum version between calculating two
|
||||
// checksums. This is designed for backward compatibility reason.
|
||||
//
|
||||
// Example 1, encoding and decoding:
|
||||
//
|
||||
// bool testChecksum(void* buf, size_t bufLen) {
|
||||
// // encoding message
|
||||
// ChecksumCalculator encoder;
|
||||
// encoder.setVersion(1);
|
||||
// encoder.addBuffer(buf, bufLen);
|
||||
// std::vector<unsigned char> message(bufLen + encoder.checksumByteSize());
|
||||
// memcpy(&message[0], buf, bufLen);
|
||||
// encoder.writeChecksum(&message[0] + bufLen, encoder.checksumByteSize());
|
||||
//
|
||||
// // decoding message
|
||||
// ChecksumCalculator decoder;
|
||||
// decoder.setVersion(1);
|
||||
// decoder.addBuffer(&message[0], bufLen);
|
||||
// return decoder.validate(&message[0] + bufLen, decoder.checksumByteSize());
|
||||
// }
|
||||
// The return value is true.
|
||||
//
|
||||
// Example 2, decoding will fail if the order of messages is wrong:
|
||||
//
|
||||
// bool testChecksumOrder(void* buf1, size_t bufLen1,
|
||||
// void* buf2, size_t bufLen2) {
|
||||
// // encoding messages
|
||||
// ChecksumCalculator encoder;
|
||||
// encoder.setVersion(1);
|
||||
//
|
||||
// std::vector<unsigned char> message1(bufLen1 + encoder.checksumByteSize());
|
||||
// std::vector<unsigned char> message2(bufLen2 + encoder.checksumByteSize());
|
||||
//
|
||||
// encoder.addBuffer(buf1, bufLen1);
|
||||
// std::vector<unsigned char> message1(bufLen1 + encoder.checksumByteSize());
|
||||
// memcpy(&message1[0], buf1, bufLen1);
|
||||
// encoder.writeChecksum(&message1[0] + bufLen1, encoder.checksumByteSize());
|
||||
//
|
||||
// encoder.addBuffer(buf2, bufLen2);
|
||||
// std::vector<unsigned char> message2(bufLen2 + encoder.checksumByteSize());
|
||||
// memcpy(&message2[0], buf2, bufLen2);
|
||||
// encoder.writeChecksum(&message2[0] + bufLen2, encoder.checksumByteSize());
|
||||
//
|
||||
// // decoding messages
|
||||
// ChecksumCalculator decoder;
|
||||
// decoder.setVersion(1);
|
||||
// decoder.addBuffer(&message2[0], bufLen2);
|
||||
// // returns false because the decoding order is not consistent with
|
||||
// // encoding order
|
||||
// if (!decoder.validate(&message2[0]+bufLen2, decoder.checksumByteSize())) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// decoder.addBuffer(&message1[0], bufLen1);
|
||||
// if (!decoder.validate(&message1[0]+bufLen1, decoder.checksumByteSize())) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
|
||||
class ChecksumCalculator {
|
||||
public:
|
||||
// Get and set current checksum version
|
||||
uint32_t getVersion() const { return m_version; }
|
||||
// Call setVersion to set a checksum version. It should be called before
|
||||
// addBuffer(), writeChecksum() and validate(). And it should be called
|
||||
// exact once per rendering thread if both host and guest support checksum.
|
||||
// It won't be called if either host or guest does not support checksum.
|
||||
bool setVersion(uint32_t version);
|
||||
|
||||
// Maximum supported checksum version
|
||||
static uint32_t getMaxVersion();
|
||||
// A version string that looks like "ANDROID_EMU_CHECKSUM_HELPER_v1"
|
||||
// Used multiple times when the guest queries the maximum supported version
|
||||
// from the host.
|
||||
// The library owns the returned pointer. The returned pointer will be
|
||||
// deconstructed when unloading library.
|
||||
static const char* getMaxVersionStr();
|
||||
static const char* getMaxVersionStrPrefix();
|
||||
|
||||
// Size of checksum in the current version
|
||||
size_t checksumByteSize() const;
|
||||
|
||||
// Update the current checksum value from the data
|
||||
// at |buf| of |bufLen| bytes. Once all buffers
|
||||
// have been added, call writeChecksum() to store
|
||||
// the final checksum value and reset its state.
|
||||
void addBuffer(const void* buf, size_t bufLen);
|
||||
// Write the checksum from the list of buffers to outputChecksum
|
||||
// Will reset the list of buffers by calling resetChecksum.
|
||||
// Return false if the buffer is not long enough
|
||||
// Please query buffer size from checksumByteSize()
|
||||
bool writeChecksum(void* outputChecksum, size_t outputChecksumLen);
|
||||
// Restore the states for computing checksums.
|
||||
// Automatically called at the end of writeChecksum and validate.
|
||||
// Can also be used to abandon the current checksum being calculated.
|
||||
// Notes: it doesn't update the internal read / write counter
|
||||
void resetChecksum();
|
||||
|
||||
// Calculate the checksum from the list of buffers and
|
||||
// compare it with the checksum encoded in expectedChecksum
|
||||
// Will reset the list of buffers by calling resetChecksum.
|
||||
bool validate(const void* expectedChecksum, size_t expectedChecksumLen);
|
||||
protected:
|
||||
uint32_t m_version = 0;
|
||||
// A temporary state used to compute the total length of a list of buffers,
|
||||
// if addBuffer is called.
|
||||
uint32_t m_numRead = 0;
|
||||
uint32_t m_numWrite = 0;
|
||||
// m_isEncodingChecksum is true when between addBuffer and writeChecksum
|
||||
bool m_isEncodingChecksum = false;
|
||||
private:
|
||||
// Compute a 32bit checksum
|
||||
// Used in protocol v1
|
||||
uint32_t computeV1Checksum();
|
||||
// The buffer used in protocol version 1 to compute checksum.
|
||||
uint32_t m_v1BufferTotalLength = 0;
|
||||
};
|
||||
103
external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.cpp
vendored
Normal file
103
external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.cpp
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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 "ChecksumCalculatorThreadInfo.h"
|
||||
|
||||
#include "emugl/common/crash_reporter.h"
|
||||
#include "emugl/common/lazy_instance.h"
|
||||
#include "emugl/common/thread_store.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
|
||||
class ChecksumCalculatorThreadStore : public ::emugl::ThreadStore {
|
||||
public:
|
||||
ChecksumCalculatorThreadStore() : ::emugl::ThreadStore(NULL) {}
|
||||
};
|
||||
|
||||
#ifdef TRACE_CHECKSUMHELPER
|
||||
std::atomic<size_t> sNumInstances(0);
|
||||
#endif // TRACE_CHECKSUMHELPER
|
||||
|
||||
}
|
||||
|
||||
static ::emugl::LazyInstance<ChecksumCalculatorThreadStore> s_tls =
|
||||
LAZY_INSTANCE_INIT;
|
||||
|
||||
static ChecksumCalculatorThreadInfo* getChecksumCalculatorThreadInfo() {
|
||||
return static_cast<ChecksumCalculatorThreadInfo*>(s_tls->get());
|
||||
}
|
||||
|
||||
ChecksumCalculatorThreadInfo::ChecksumCalculatorThreadInfo() {
|
||||
LOG_CHECKSUMHELPER(
|
||||
"%s: Checksum thread created (%u instances)\n", __FUNCTION__,
|
||||
(size_t)sNumInstances);
|
||||
s_tls->set(this);
|
||||
}
|
||||
|
||||
ChecksumCalculatorThreadInfo::~ChecksumCalculatorThreadInfo() {
|
||||
LOG_CHECKSUMHELPER(
|
||||
"%s: GLprotocol destroyed (%u instances)\n", __FUNCTION__,
|
||||
(size_t)sNumInstances);
|
||||
s_tls->set(NULL);
|
||||
}
|
||||
|
||||
uint32_t ChecksumCalculatorThreadInfo::getVersion() {
|
||||
return getChecksumCalculatorThreadInfo()->m_protocol.getVersion();
|
||||
}
|
||||
|
||||
bool ChecksumCalculatorThreadInfo::setVersion(uint32_t version) {
|
||||
return getChecksumCalculatorThreadInfo()->m_protocol.setVersion(version);
|
||||
}
|
||||
|
||||
size_t ChecksumCalculatorThreadInfo::checksumByteSize() {
|
||||
return getChecksumCalculatorThreadInfo()->m_protocol.checksumByteSize();
|
||||
}
|
||||
|
||||
bool ChecksumCalculatorThreadInfo::writeChecksum(void* buf,
|
||||
size_t bufLen,
|
||||
void* outputChecksum,
|
||||
size_t outputChecksumLen) {
|
||||
ChecksumCalculator& protocol =
|
||||
getChecksumCalculatorThreadInfo()->m_protocol;
|
||||
protocol.addBuffer(buf, bufLen);
|
||||
return protocol.writeChecksum(outputChecksum, outputChecksumLen);
|
||||
}
|
||||
|
||||
bool ChecksumCalculatorThreadInfo::validate(void* buf,
|
||||
size_t bufLen,
|
||||
void* checksum,
|
||||
size_t checksumLen) {
|
||||
ChecksumCalculator& protocol =
|
||||
getChecksumCalculatorThreadInfo()->m_protocol;
|
||||
protocol.addBuffer(buf, bufLen);
|
||||
return protocol.validate(checksum, checksumLen);
|
||||
}
|
||||
|
||||
void ChecksumCalculatorThreadInfo::validOrDie(void* buf,
|
||||
size_t bufLen,
|
||||
void* checksum,
|
||||
size_t checksumLen,
|
||||
const char* message) {
|
||||
// We should actually call crashhandler_die(message), but I don't think we
|
||||
// can link to that library from here
|
||||
if (!validate(buf, bufLen, checksum, checksumLen)) {
|
||||
emugl_crash_reporter(message);
|
||||
}
|
||||
}
|
||||
56
external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.h
vendored
Normal file
56
external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.h
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ChecksumCalculator.h"
|
||||
|
||||
// ChecksumCalculatorThreadInfo is the class that makes ChecksumCalculator
|
||||
// thread-safe. On the host, please only use ChecksumCalculator through this
|
||||
// class.
|
||||
|
||||
class ChecksumCalculatorThreadInfo {
|
||||
public:
|
||||
ChecksumCalculatorThreadInfo();
|
||||
~ChecksumCalculatorThreadInfo();
|
||||
|
||||
static uint32_t getVersion();
|
||||
static bool setVersion(uint32_t version);
|
||||
|
||||
static uint32_t getMaxVersion();
|
||||
static const char* getMaxVersionString() {
|
||||
return ChecksumCalculator::getMaxVersionStr();
|
||||
}
|
||||
|
||||
static size_t checksumByteSize();
|
||||
static bool writeChecksum(void* buf,
|
||||
size_t bufLen,
|
||||
void* outputChecksum,
|
||||
size_t outputChecksumLen);
|
||||
|
||||
static bool validate(void* buf,
|
||||
size_t bufLen,
|
||||
void* checksum,
|
||||
size_t checksumLen);
|
||||
static void validOrDie(void* buf,
|
||||
size_t bufLen,
|
||||
void* checksum,
|
||||
size_t checksumLen,
|
||||
const char* message);
|
||||
|
||||
private:
|
||||
ChecksumCalculator m_protocol;
|
||||
};
|
||||
28
external/android-emugl/shared/OpenglCodecCommon/ErrorLog.h
vendored
Normal file
28
external/android-emugl/shared/OpenglCodecCommon/ErrorLog.h
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _ERROR_LOG_H_
|
||||
#define _ERROR_LOG_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#define ERR(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define EMUGL_DEBUG
|
||||
#ifdef EMUGL_DEBUG
|
||||
# define DBG(...) fprintf(stderr, __VA_ARGS__)
|
||||
#else
|
||||
# define DBG(...) ((void)0)
|
||||
#endif
|
||||
|
||||
#endif // _ERROR_LOG_H_
|
||||
82
external/android-emugl/shared/OpenglCodecCommon/GLDecoderContextData.h
vendored
Normal file
82
external/android-emugl/shared/OpenglCodecCommon/GLDecoderContextData.h
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
// Convenient class used to hold the common context data shared
|
||||
// by both the GLESv1 and GLESv2 decoders. This corresponds to
|
||||
// vertex attribute buffers.
|
||||
class GLDecoderContextData {
|
||||
public:
|
||||
// List of supported vertex attribute indices, as they appear in
|
||||
// a glVertexAttribPointer() call.
|
||||
typedef enum {
|
||||
VERTEX_LOCATION = 0,
|
||||
NORMAL_LOCATION = 1,
|
||||
COLOR_LOCATION = 2,
|
||||
POINTSIZE_LOCATION = 3,
|
||||
TEXCOORD0_LOCATION = 4,
|
||||
TEXCOORD1_LOCATION = 5,
|
||||
TEXCOORD2_LOCATION = 6,
|
||||
TEXCOORD3_LOCATION = 7,
|
||||
TEXCOORD4_LOCATION = 8,
|
||||
TEXCOORD5_LOCATION = 9,
|
||||
TEXCOORD6_LOCATION = 10,
|
||||
TEXCOORD7_LOCATION = 11,
|
||||
MATRIXINDEX_LOCATION = 12,
|
||||
WEIGHT_LOCATION = 13,
|
||||
LAST_LOCATION = 14
|
||||
} PointerDataLocation;
|
||||
|
||||
// Default constructor.
|
||||
GLDecoderContextData(int numLocations = kMaxVertexAttributes)
|
||||
: mPointerData(),
|
||||
mNumLocations(static_cast<unsigned>(numLocations)) {
|
||||
mPointerData.resize(mNumLocations);
|
||||
}
|
||||
|
||||
// Store |len| bytes from |data| into the buffer associated with
|
||||
// vertex attribute index |loc|.
|
||||
void storePointerData(unsigned int loc, void *data, size_t len) {
|
||||
if (loc < mNumLocations) {
|
||||
std::string& ptrData = mPointerData[loc];
|
||||
ptrData.assign(reinterpret_cast<char*>(data), len);
|
||||
} else {
|
||||
// User error, don't do anything here
|
||||
}
|
||||
}
|
||||
|
||||
// Return pointer to data associated with vertex attribute index |loc|
|
||||
void* pointerData(unsigned int loc) const {
|
||||
if (loc < mNumLocations) {
|
||||
return const_cast<char*>(mPointerData[loc].c_str());
|
||||
} else {
|
||||
// User error. Return nullptr.
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kMaxVertexAttributes = 64;
|
||||
|
||||
std::vector<std::string> mPointerData;
|
||||
unsigned mNumLocations = 0;
|
||||
};
|
||||
13
external/android-emugl/shared/OpenglCodecCommon/Makefile
vendored
Normal file
13
external/android-emugl/shared/OpenglCodecCommon/Makefile
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
ROOT=../..
|
||||
|
||||
include $(ROOT)/make/commondefs
|
||||
|
||||
CXXFILES = TcpStream.cpp GLClientState.cpp glUtils.cpp
|
||||
CXXINCS += -I$(ROOT)/libs/GLESv1 -I$(ROOT)/include
|
||||
|
||||
LIBRARY_NAME = libcodecCommon.a
|
||||
|
||||
include $(COMMONRULES)
|
||||
|
||||
|
||||
193
external/android-emugl/shared/OpenglCodecCommon/ProtocolUtils.h
vendored
Normal file
193
external/android-emugl/shared/OpenglCodecCommon/ProtocolUtils.h
vendored
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
#ifndef EMUGL_PROTOCOL_UTILS_H
|
||||
#define EMUGL_PROTOCOL_UTILS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// Helper macro
|
||||
#define COMPILE_ASSERT(cond) static char kAssert##__LINE__[1 - 2 * !(cond)] __attribute__((unused)) = { 0 }
|
||||
|
||||
// Helper template: is_pointer.
|
||||
// is_pointer<T>::value is true iff |T| is a pointer type.
|
||||
template <typename T> struct is_pointer {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename T> struct is_pointer<T*> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
// A helper template to extract values form the wire protocol stream
|
||||
// and convert them to appropriate host values.
|
||||
//
|
||||
// The wire protocol uses 32-bit exclusively when transferring
|
||||
// GLintptr or GLsizei values, as well as opaque handles like GLeglImage,
|
||||
// from the guest (even when the guest is 64-bit).
|
||||
//
|
||||
// The corresponding host definitions depend on the host bitness. For
|
||||
// example, GLintptr is 64-bit on linux-x86_64. The following is a set
|
||||
// of templates that can simplify the conversion of protocol values
|
||||
// into host ones.
|
||||
//
|
||||
// The most important one is:
|
||||
//
|
||||
// unpack<HOST_TYPE,SIZE_TYPE>(const void* ptr)
|
||||
//
|
||||
// Which reads bytes from |ptr|, using |SIZE_TYPE| as the underlying
|
||||
// sized-integer specifier (e.g. 'uint32_t'), and converting the result
|
||||
// into a |HOST_TYPE| value. For example:
|
||||
//
|
||||
// unpack<EGLImage,uint32_t>(ptr + 12);
|
||||
//
|
||||
// will read a 4-byte value from |ptr + 12| and convert it into
|
||||
// an EGLImage, which is a host void*. The template detects host
|
||||
// pointer types to perform proper type casting.
|
||||
//
|
||||
// TODO(digit): Add custom unpackers to handle generic opaque void* values.
|
||||
// and map them to unique 32-bit values.
|
||||
|
||||
template <typename T, typename S, bool IS_POINTER>
|
||||
struct UnpackerT {};
|
||||
|
||||
template <typename T, typename S>
|
||||
struct UnpackerT<T,S,false> {
|
||||
static inline T unpack(const void* ptr) {
|
||||
COMPILE_ASSERT(sizeof(T) == sizeof(S));
|
||||
return (T)(*(S*)(ptr));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename S>
|
||||
struct UnpackerT<T,S,true> {
|
||||
static inline T unpack(const void* ptr) {
|
||||
return (T)(uintptr_t)(*(S*)(ptr));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct UnpackerT<float,uint32_t,false> {
|
||||
static inline float unpack(const void* ptr) {
|
||||
union {
|
||||
float f;
|
||||
uint32_t u;
|
||||
} v;
|
||||
v.u = *(uint32_t*)(ptr);
|
||||
return v.f;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct UnpackerT<double,uint64_t,false> {
|
||||
static inline double unpack(const void* ptr) {
|
||||
union {
|
||||
double d;
|
||||
uint32_t u;
|
||||
} v;
|
||||
v.u = *(uint64_t*)(ptr);
|
||||
return v.d;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct UnpackerT<ssize_t,uint32_t,false> {
|
||||
static inline ssize_t unpack(const void* ptr) {
|
||||
return (ssize_t)*(int32_t*)(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename S>
|
||||
inline T Unpack(const void* ptr) {
|
||||
return UnpackerT<T, S, is_pointer<T>::value>::unpack(ptr);
|
||||
}
|
||||
|
||||
// Helper class used to ensure input buffers passed to EGL/GL functions
|
||||
// are properly aligned (preventing crashes with some backends).
|
||||
// Usage example:
|
||||
//
|
||||
// InputBuffer inputBuffer(ptr, size);
|
||||
// glDoStuff(inputBuffer.get());
|
||||
//
|
||||
// inputBuffer.get() will return the original value of |ptr| if it was
|
||||
// aligned on an 8-byte boundary. Otherwise, it will return the address
|
||||
// of an aligned heap-allocated copy of the original |size| bytes starting
|
||||
// from |ptr|. The heap block is released at scope exit.
|
||||
class InputBuffer {
|
||||
public:
|
||||
InputBuffer(const void* input, size_t size, size_t align = 8) :
|
||||
mBuff(input), mIsCopy(false) {
|
||||
if (((uintptr_t)input & (align - 1U)) != 0) {
|
||||
void* newBuff = malloc(size);
|
||||
memcpy(newBuff, input, size);
|
||||
mBuff = newBuff;
|
||||
mIsCopy = true;
|
||||
}
|
||||
}
|
||||
|
||||
~InputBuffer() {
|
||||
if (mIsCopy) {
|
||||
free((void*)mBuff);
|
||||
}
|
||||
}
|
||||
|
||||
const void* get() const {
|
||||
return mBuff;
|
||||
}
|
||||
|
||||
private:
|
||||
const void* mBuff;
|
||||
bool mIsCopy;
|
||||
};
|
||||
|
||||
// Helper class used to ensure that output buffers passed to EGL/GL functions
|
||||
// are aligned on 8-byte addresses.
|
||||
// Usage example:
|
||||
//
|
||||
// ptr = stream->alloc(size);
|
||||
// OutputBuffer outputBuffer(ptr, size);
|
||||
// glGetStuff(outputBuffer.get());
|
||||
// outputBuffer.flush();
|
||||
//
|
||||
// outputBuffer.get() returns the original value of |ptr| if it was already
|
||||
// aligned on an 8=byte boundary. Otherwise, it returns the size of an heap
|
||||
// allocated zeroed buffer of |size| bytes.
|
||||
//
|
||||
// outputBuffer.flush() copies the content of the heap allocated buffer back
|
||||
// to |ptr| explictly, if needed. If a no-op if |ptr| was aligned.
|
||||
class OutputBuffer {
|
||||
public:
|
||||
OutputBuffer(unsigned char* ptr, size_t size, size_t align = 8) :
|
||||
mOrgBuff(ptr), mBuff(ptr), mSize(size) {
|
||||
if (((uintptr_t)ptr & (align - 1U)) != 0) {
|
||||
void* newBuff = calloc(1, size);
|
||||
mBuff = newBuff;
|
||||
}
|
||||
}
|
||||
|
||||
~OutputBuffer() {
|
||||
if (mBuff != mOrgBuff) {
|
||||
free(mBuff);
|
||||
}
|
||||
}
|
||||
|
||||
void* get() const {
|
||||
return mBuff;
|
||||
}
|
||||
|
||||
void flush() {
|
||||
if (mBuff != mOrgBuff) {
|
||||
memcpy(mOrgBuff, mBuff, mSize);
|
||||
}
|
||||
}
|
||||
private:
|
||||
unsigned char* mOrgBuff;
|
||||
void* mBuff;
|
||||
size_t mSize;
|
||||
};
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_PROTOCOL_UTILS_H
|
||||
416
external/android-emugl/shared/OpenglCodecCommon/glUtils.cpp
vendored
Normal file
416
external/android-emugl/shared/OpenglCodecCommon/glUtils.cpp
vendored
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* 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 "glUtils.h"
|
||||
|
||||
#include "ErrorLog.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
size_t glSizeof(GLenum type)
|
||||
{
|
||||
size_t retval = 0;
|
||||
switch(type) {
|
||||
case GL_BYTE:
|
||||
case GL_UNSIGNED_BYTE:
|
||||
retval = 1;
|
||||
break;
|
||||
case GL_SHORT:
|
||||
case GL_UNSIGNED_SHORT:
|
||||
case GL_HALF_FLOAT_OES:
|
||||
retval = 2;
|
||||
break;
|
||||
case GL_INT:
|
||||
case GL_FLOAT:
|
||||
case GL_FIXED:
|
||||
case GL_BOOL:
|
||||
retval = 4;
|
||||
break;
|
||||
#ifdef GL_DOUBLE
|
||||
case GL_DOUBLE:
|
||||
retval = 8;
|
||||
break;
|
||||
#endif
|
||||
case GL_FLOAT_VEC2:
|
||||
case GL_INT_VEC2:
|
||||
case GL_BOOL_VEC2:
|
||||
retval = 8;
|
||||
break;
|
||||
case GL_INT_VEC3:
|
||||
case GL_BOOL_VEC3:
|
||||
case GL_FLOAT_VEC3:
|
||||
retval = 12;
|
||||
break;
|
||||
case GL_FLOAT_VEC4:
|
||||
case GL_BOOL_VEC4:
|
||||
case GL_INT_VEC4:
|
||||
case GL_FLOAT_MAT2:
|
||||
retval = 16;
|
||||
break;
|
||||
case GL_FLOAT_MAT3:
|
||||
retval = 36;
|
||||
break;
|
||||
case GL_FLOAT_MAT4:
|
||||
retval = 64;
|
||||
break;
|
||||
case GL_SAMPLER_2D:
|
||||
case GL_SAMPLER_CUBE:
|
||||
retval = 4;
|
||||
break;
|
||||
default:
|
||||
ERR("**** ERROR unknown type 0x%x (%s,%d)\n", type, __FUNCTION__,__LINE__);
|
||||
}
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
size_t glUtilsParamSize(GLenum param)
|
||||
{
|
||||
size_t s = 0;
|
||||
|
||||
switch(param)
|
||||
{
|
||||
case GL_DEPTH_TEST:
|
||||
case GL_DEPTH_FUNC:
|
||||
case GL_DEPTH_BITS:
|
||||
case GL_MAX_CLIP_PLANES:
|
||||
case GL_GREEN_BITS:
|
||||
case GL_MAX_MODELVIEW_STACK_DEPTH:
|
||||
case GL_MAX_PROJECTION_STACK_DEPTH:
|
||||
case GL_MAX_TEXTURE_STACK_DEPTH:
|
||||
case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
|
||||
case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
|
||||
case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
|
||||
case GL_MAX_TEXTURE_SIZE:
|
||||
case GL_TEXTURE_GEN_MODE_OES:
|
||||
case GL_TEXTURE_ENV_MODE:
|
||||
case GL_FOG_MODE:
|
||||
case GL_FOG_DENSITY:
|
||||
case GL_FOG_START:
|
||||
case GL_FOG_END:
|
||||
case GL_SPOT_EXPONENT:
|
||||
case GL_CONSTANT_ATTENUATION:
|
||||
case GL_LINEAR_ATTENUATION:
|
||||
case GL_QUADRATIC_ATTENUATION:
|
||||
case GL_SHININESS:
|
||||
case GL_LIGHT_MODEL_TWO_SIDE:
|
||||
case GL_POINT_SIZE:
|
||||
case GL_POINT_SIZE_MIN:
|
||||
case GL_POINT_SIZE_MAX:
|
||||
case GL_POINT_FADE_THRESHOLD_SIZE:
|
||||
case GL_CULL_FACE_MODE:
|
||||
case GL_FRONT_FACE:
|
||||
case GL_SHADE_MODEL:
|
||||
case GL_DEPTH_WRITEMASK:
|
||||
case GL_DEPTH_CLEAR_VALUE:
|
||||
case GL_STENCIL_FAIL:
|
||||
case GL_STENCIL_PASS_DEPTH_FAIL:
|
||||
case GL_STENCIL_PASS_DEPTH_PASS:
|
||||
case GL_STENCIL_REF:
|
||||
case GL_STENCIL_WRITEMASK:
|
||||
case GL_MATRIX_MODE:
|
||||
case GL_MODELVIEW_STACK_DEPTH:
|
||||
case GL_PROJECTION_STACK_DEPTH:
|
||||
case GL_TEXTURE_STACK_DEPTH:
|
||||
case GL_ALPHA_TEST_FUNC:
|
||||
case GL_ALPHA_TEST_REF:
|
||||
case GL_ALPHA_TEST:
|
||||
case GL_BLEND_DST:
|
||||
case GL_BLEND_SRC:
|
||||
case GL_BLEND:
|
||||
case GL_LOGIC_OP_MODE:
|
||||
case GL_SCISSOR_TEST:
|
||||
case GL_MAX_TEXTURE_UNITS:
|
||||
case GL_ACTIVE_TEXTURE:
|
||||
case GL_ALPHA_BITS:
|
||||
case GL_ARRAY_BUFFER_BINDING:
|
||||
case GL_BLUE_BITS:
|
||||
case GL_CLIENT_ACTIVE_TEXTURE:
|
||||
case GL_CLIP_PLANE0:
|
||||
case GL_CLIP_PLANE1:
|
||||
case GL_CLIP_PLANE2:
|
||||
case GL_CLIP_PLANE3:
|
||||
case GL_CLIP_PLANE4:
|
||||
case GL_CLIP_PLANE5:
|
||||
case GL_COLOR_ARRAY:
|
||||
case GL_COLOR_ARRAY_BUFFER_BINDING:
|
||||
case GL_COLOR_ARRAY_SIZE:
|
||||
case GL_COLOR_ARRAY_STRIDE:
|
||||
case GL_COLOR_ARRAY_TYPE:
|
||||
case GL_COLOR_LOGIC_OP:
|
||||
case GL_COLOR_MATERIAL:
|
||||
case GL_PACK_ALIGNMENT:
|
||||
case GL_PERSPECTIVE_CORRECTION_HINT:
|
||||
case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
|
||||
case GL_POINT_SIZE_ARRAY_STRIDE_OES:
|
||||
case GL_POINT_SIZE_ARRAY_TYPE_OES:
|
||||
case GL_POINT_SMOOTH:
|
||||
case GL_POINT_SMOOTH_HINT:
|
||||
case GL_POINT_SPRITE_OES:
|
||||
case GL_COORD_REPLACE_OES:
|
||||
case GL_COMBINE_ALPHA:
|
||||
case GL_SRC0_RGB:
|
||||
case GL_SRC1_RGB:
|
||||
case GL_SRC2_RGB:
|
||||
case GL_OPERAND0_RGB:
|
||||
case GL_OPERAND1_RGB:
|
||||
case GL_OPERAND2_RGB:
|
||||
case GL_SRC0_ALPHA:
|
||||
case GL_SRC1_ALPHA:
|
||||
case GL_SRC2_ALPHA:
|
||||
case GL_OPERAND0_ALPHA:
|
||||
case GL_OPERAND1_ALPHA:
|
||||
case GL_OPERAND2_ALPHA:
|
||||
case GL_RGB_SCALE:
|
||||
case GL_ALPHA_SCALE:
|
||||
case GL_COMBINE_RGB:
|
||||
case GL_POLYGON_OFFSET_FACTOR:
|
||||
case GL_POLYGON_OFFSET_FILL:
|
||||
case GL_POLYGON_OFFSET_UNITS:
|
||||
case GL_RED_BITS:
|
||||
case GL_RESCALE_NORMAL:
|
||||
case GL_SAMPLE_ALPHA_TO_COVERAGE:
|
||||
case GL_SAMPLE_ALPHA_TO_ONE:
|
||||
case GL_SAMPLE_BUFFERS:
|
||||
case GL_SAMPLE_COVERAGE:
|
||||
case GL_SAMPLE_COVERAGE_INVERT:
|
||||
case GL_SAMPLE_COVERAGE_VALUE:
|
||||
case GL_SAMPLES:
|
||||
case GL_STENCIL_BITS:
|
||||
case GL_STENCIL_CLEAR_VALUE:
|
||||
case GL_STENCIL_FUNC:
|
||||
case GL_STENCIL_TEST:
|
||||
case GL_STENCIL_VALUE_MASK:
|
||||
case GL_STENCIL_BACK_FUNC:
|
||||
case GL_STENCIL_BACK_VALUE_MASK:
|
||||
case GL_STENCIL_BACK_REF:
|
||||
case GL_STENCIL_BACK_FAIL:
|
||||
case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
|
||||
case GL_STENCIL_BACK_PASS_DEPTH_PASS:
|
||||
case GL_STENCIL_BACK_WRITEMASK:
|
||||
case GL_TEXTURE_2D:
|
||||
case GL_TEXTURE_BINDING_2D:
|
||||
case GL_TEXTURE_BINDING_CUBE_MAP:
|
||||
case GL_TEXTURE_BINDING_EXTERNAL_OES:
|
||||
case GL_TEXTURE_COORD_ARRAY:
|
||||
case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
|
||||
case GL_TEXTURE_COORD_ARRAY_SIZE:
|
||||
case GL_TEXTURE_COORD_ARRAY_STRIDE:
|
||||
case GL_TEXTURE_COORD_ARRAY_TYPE:
|
||||
case GL_UNPACK_ALIGNMENT:
|
||||
case GL_VERTEX_ARRAY:
|
||||
case GL_VERTEX_ARRAY_BUFFER_BINDING:
|
||||
case GL_VERTEX_ARRAY_SIZE:
|
||||
case GL_VERTEX_ARRAY_STRIDE:
|
||||
case GL_VERTEX_ARRAY_TYPE:
|
||||
case GL_SPOT_CUTOFF:
|
||||
case GL_TEXTURE_MIN_FILTER:
|
||||
case GL_TEXTURE_MAG_FILTER:
|
||||
case GL_TEXTURE_WRAP_S:
|
||||
case GL_TEXTURE_WRAP_T:
|
||||
case GL_GENERATE_MIPMAP:
|
||||
case GL_GENERATE_MIPMAP_HINT:
|
||||
case GL_RENDERBUFFER_WIDTH_OES:
|
||||
case GL_RENDERBUFFER_HEIGHT_OES:
|
||||
case GL_RENDERBUFFER_INTERNAL_FORMAT_OES:
|
||||
case GL_RENDERBUFFER_RED_SIZE_OES:
|
||||
case GL_RENDERBUFFER_GREEN_SIZE_OES:
|
||||
case GL_RENDERBUFFER_BLUE_SIZE_OES:
|
||||
case GL_RENDERBUFFER_ALPHA_SIZE_OES:
|
||||
case GL_RENDERBUFFER_DEPTH_SIZE_OES:
|
||||
case GL_RENDERBUFFER_STENCIL_SIZE_OES:
|
||||
case GL_RENDERBUFFER_BINDING:
|
||||
case GL_FRAMEBUFFER_BINDING:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES:
|
||||
case GL_FENCE_STATUS_NV:
|
||||
case GL_FENCE_CONDITION_NV:
|
||||
case GL_TEXTURE_WIDTH_QCOM:
|
||||
case GL_TEXTURE_HEIGHT_QCOM:
|
||||
case GL_TEXTURE_DEPTH_QCOM:
|
||||
case GL_TEXTURE_INTERNAL_FORMAT_QCOM:
|
||||
case GL_TEXTURE_FORMAT_QCOM:
|
||||
case GL_TEXTURE_TYPE_QCOM:
|
||||
case GL_TEXTURE_IMAGE_VALID_QCOM:
|
||||
case GL_TEXTURE_NUM_LEVELS_QCOM:
|
||||
case GL_TEXTURE_TARGET_QCOM:
|
||||
case GL_TEXTURE_OBJECT_VALID_QCOM:
|
||||
case GL_BLEND_EQUATION_RGB_OES:
|
||||
case GL_BLEND_EQUATION_ALPHA_OES:
|
||||
case GL_BLEND_DST_RGB_OES:
|
||||
case GL_BLEND_SRC_RGB_OES:
|
||||
case GL_BLEND_DST_ALPHA_OES:
|
||||
case GL_BLEND_SRC_ALPHA_OES:
|
||||
case GL_MAX_LIGHTS:
|
||||
case GL_SHADER_TYPE:
|
||||
case GL_DELETE_STATUS:
|
||||
case GL_COMPILE_STATUS:
|
||||
case GL_INFO_LOG_LENGTH:
|
||||
case GL_SHADER_SOURCE_LENGTH:
|
||||
case GL_CURRENT_PROGRAM:
|
||||
case GL_LINK_STATUS:
|
||||
case GL_VALIDATE_STATUS:
|
||||
case GL_ATTACHED_SHADERS:
|
||||
case GL_ACTIVE_UNIFORMS:
|
||||
case GL_ACTIVE_ATTRIBUTES:
|
||||
case GL_SUBPIXEL_BITS:
|
||||
case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
|
||||
case GL_NUM_SHADER_BINARY_FORMATS:
|
||||
case GL_SHADER_COMPILER:
|
||||
case GL_MAX_VERTEX_ATTRIBS:
|
||||
case GL_MAX_VERTEX_UNIFORM_VECTORS:
|
||||
case GL_MAX_VARYING_VECTORS:
|
||||
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
|
||||
case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
|
||||
case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
|
||||
case GL_MAX_RENDERBUFFER_SIZE:
|
||||
case GL_MAX_TEXTURE_IMAGE_UNITS:
|
||||
case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES:
|
||||
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
|
||||
case GL_LINE_WIDTH:
|
||||
s = 1;
|
||||
break;
|
||||
case GL_ALIASED_LINE_WIDTH_RANGE:
|
||||
case GL_ALIASED_POINT_SIZE_RANGE:
|
||||
case GL_DEPTH_RANGE:
|
||||
case GL_MAX_VIEWPORT_DIMS:
|
||||
case GL_SMOOTH_POINT_SIZE_RANGE:
|
||||
case GL_SMOOTH_LINE_WIDTH_RANGE:
|
||||
s= 2;
|
||||
break;
|
||||
case GL_SPOT_DIRECTION:
|
||||
case GL_POINT_DISTANCE_ATTENUATION:
|
||||
case GL_CURRENT_NORMAL:
|
||||
s = 3;
|
||||
break;
|
||||
case GL_CURRENT_VERTEX_ATTRIB:
|
||||
case GL_CURRENT_TEXTURE_COORDS:
|
||||
case GL_CURRENT_COLOR:
|
||||
case GL_FOG_COLOR:
|
||||
case GL_AMBIENT:
|
||||
case GL_DIFFUSE:
|
||||
case GL_SPECULAR:
|
||||
case GL_EMISSION:
|
||||
case GL_POSITION:
|
||||
case GL_LIGHT_MODEL_AMBIENT:
|
||||
case GL_TEXTURE_ENV_COLOR:
|
||||
case GL_SCISSOR_BOX:
|
||||
case GL_VIEWPORT:
|
||||
case GL_TEXTURE_CROP_RECT_OES:
|
||||
case GL_COLOR_CLEAR_VALUE:
|
||||
case GL_COLOR_WRITEMASK:
|
||||
case GL_AMBIENT_AND_DIFFUSE:
|
||||
case GL_BLEND_COLOR:
|
||||
s = 4;
|
||||
break;
|
||||
case GL_MODELVIEW_MATRIX:
|
||||
case GL_PROJECTION_MATRIX:
|
||||
case GL_TEXTURE_MATRIX:
|
||||
s = 16;
|
||||
break;
|
||||
default:
|
||||
ERR("glUtilsParamSize: unknow param 0x%08x\n", param);
|
||||
s = 1; // assume 1
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void glUtilsPackPointerData(unsigned char *dst, unsigned char *src,
|
||||
int size, GLenum type, unsigned int stride,
|
||||
unsigned int datalen)
|
||||
{
|
||||
unsigned int vsize = size * glSizeof(type);
|
||||
if (stride == 0) stride = vsize;
|
||||
|
||||
if (stride == vsize) {
|
||||
memcpy(dst, src, datalen);
|
||||
} else {
|
||||
for (unsigned int i = 0; i < datalen; i += vsize) {
|
||||
memcpy(dst, src, vsize);
|
||||
dst += vsize;
|
||||
src += stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int glUtilsPixelBitSize(GLenum format, GLenum type)
|
||||
{
|
||||
int components = 0;
|
||||
int componentsize = 0;
|
||||
int pixelsize = 0;
|
||||
switch(type) {
|
||||
case GL_BYTE:
|
||||
case GL_UNSIGNED_BYTE:
|
||||
componentsize = 8;
|
||||
break;
|
||||
case GL_SHORT:
|
||||
case GL_UNSIGNED_SHORT:
|
||||
case GL_UNSIGNED_SHORT_5_6_5:
|
||||
case GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case GL_RGB565_OES:
|
||||
case GL_RGB5_A1_OES:
|
||||
case GL_RGBA4_OES:
|
||||
pixelsize = 16;
|
||||
break;
|
||||
case GL_INT:
|
||||
case GL_UNSIGNED_INT:
|
||||
case GL_FLOAT:
|
||||
case GL_FIXED:
|
||||
case GL_UNSIGNED_INT_24_8_OES:
|
||||
pixelsize = 32;
|
||||
break;
|
||||
default:
|
||||
ERR("glUtilsPixelBitSize: unknown pixel type - assuming pixel data 0\n");
|
||||
componentsize = 0;
|
||||
}
|
||||
|
||||
if (pixelsize == 0) {
|
||||
switch(format) {
|
||||
#if 0
|
||||
case GL_RED:
|
||||
case GL_GREEN:
|
||||
case GL_BLUE:
|
||||
#endif
|
||||
case GL_ALPHA:
|
||||
case GL_LUMINANCE:
|
||||
case GL_DEPTH_COMPONENT:
|
||||
case GL_DEPTH_STENCIL_OES:
|
||||
components = 1;
|
||||
break;
|
||||
case GL_LUMINANCE_ALPHA:
|
||||
components = 2;
|
||||
break;
|
||||
case GL_RGB:
|
||||
#if 0
|
||||
case GL_BGR:
|
||||
#endif
|
||||
components = 3;
|
||||
break;
|
||||
case GL_RGBA:
|
||||
case GL_BGRA_EXT:
|
||||
components = 4;
|
||||
break;
|
||||
default:
|
||||
ERR("glUtilsPixelBitSize: unknown pixel format...\n");
|
||||
components = 0;
|
||||
}
|
||||
pixelsize = components * componentsize;
|
||||
}
|
||||
|
||||
return pixelsize;
|
||||
}
|
||||
41
external/android-emugl/shared/OpenglCodecCommon/glUtils.h
vendored
Normal file
41
external/android-emugl/shared/OpenglCodecCommon/glUtils.h
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/glext.h>
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
size_t glSizeof(GLenum type);
|
||||
|
||||
size_t glUtilsParamSize(GLenum param);
|
||||
|
||||
void glUtilsPackPointerData(unsigned char *dst, unsigned char *str,
|
||||
int size, GLenum type, unsigned int stride,
|
||||
unsigned int datalen);
|
||||
|
||||
int glUtilsPixelBitSize(GLenum format, GLenum type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
62
external/android-emugl/shared/OpenglCodecCommon/gl_base_types.h
vendored
Normal file
62
external/android-emugl/shared/OpenglCodecCommon/gl_base_types.h
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __GL_BASE_TYPES__H
|
||||
#define __GL_BASE_TYPES__H
|
||||
|
||||
#include <KHR/khrplatform.h>
|
||||
|
||||
#ifndef gles1_APIENTRY
|
||||
#define gles1_APIENTRY KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
#ifndef gles2_APIENTRY
|
||||
#define gles2_APIENTRY KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
typedef void GLvoid;
|
||||
typedef unsigned int GLenum;
|
||||
typedef unsigned char GLboolean;
|
||||
typedef unsigned int GLbitfield;
|
||||
typedef char GLchar;
|
||||
typedef khronos_int8_t GLbyte;
|
||||
typedef short GLshort;
|
||||
typedef int GLint;
|
||||
typedef int GLsizei;
|
||||
typedef khronos_uint8_t GLubyte;
|
||||
typedef unsigned short GLushort;
|
||||
typedef unsigned int GLuint;
|
||||
typedef khronos_float_t GLfloat;
|
||||
typedef khronos_float_t GLclampf;
|
||||
typedef khronos_int32_t GLfixed;
|
||||
typedef khronos_int32_t GLclampx;
|
||||
typedef khronos_intptr_t GLintptr;
|
||||
typedef khronos_ssize_t GLsizeiptr;
|
||||
typedef char *GLstr;
|
||||
/* JR XXX Treating this as an in handle - is this correct? */
|
||||
typedef void * GLeglImageOES;
|
||||
|
||||
/* ErrorCode */
|
||||
#ifndef GL_INVALID_ENUM
|
||||
#define GL_NO_ERROR 0
|
||||
#define GL_INVALID_ENUM 0x0500
|
||||
#define GL_INVALID_VALUE 0x0501
|
||||
#define GL_INVALID_OPERATION 0x0502
|
||||
#define GL_STACK_OVERFLOW 0x0503
|
||||
#define GL_STACK_UNDERFLOW 0x0504
|
||||
#define GL_OUT_OF_MEMORY 0x0505
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1
external/android-emugl/shared/emugl/CMakeLists.txt
vendored
Normal file
1
external/android-emugl/shared/emugl/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(common)
|
||||
65
external/android-emugl/shared/emugl/common/Android.mk
vendored
Normal file
65
external/android-emugl/shared/emugl/common/Android.mk
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# This build script corresponds to a library containing many definitions
|
||||
# common to both the guest and the host. They relate to
|
||||
#
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
### emugl_common host library ###########################################
|
||||
|
||||
commonSources := \
|
||||
crash_reporter.cpp \
|
||||
id_to_object_map.cpp \
|
||||
lazy_instance.cpp \
|
||||
logging.cpp \
|
||||
message_channel.cpp \
|
||||
pod_vector.cpp \
|
||||
shared_library.cpp \
|
||||
smart_ptr.cpp \
|
||||
sockets.cpp \
|
||||
thread_store.cpp \
|
||||
|
||||
host_commonSources := $(commonSources)
|
||||
|
||||
host_commonLdLibs := $(CXX_STD_LIB)
|
||||
|
||||
ifneq (windows,$(BUILD_TARGET_OS))
|
||||
host_commonSources += \
|
||||
thread_pthread.cpp \
|
||||
|
||||
host_commonLdLibs += -ldl -lpthread
|
||||
else
|
||||
host_commonSources += \
|
||||
condition_variable_win32.cpp \
|
||||
thread_win32.cpp \
|
||||
|
||||
endif
|
||||
|
||||
$(call emugl-begin-host-static-library,libemugl_common)
|
||||
LOCAL_SRC_FILES := $(host_commonSources)
|
||||
$(call emugl-export,C_INCLUDES,$(EMUGL_PATH)/shared)
|
||||
$(call emugl-export,LDLIBS,$(host_commonLdLibs))
|
||||
$(call emugl-end-module)
|
||||
|
||||
### emugl_common_unittests ##############################################
|
||||
|
||||
host_commonSources := \
|
||||
condition_variable_unittest.cpp \
|
||||
id_to_object_map_unittest.cpp \
|
||||
lazy_instance_unittest.cpp \
|
||||
pod_vector_unittest.cpp \
|
||||
message_channel_unittest.cpp \
|
||||
mutex_unittest.cpp \
|
||||
shared_library_unittest.cpp \
|
||||
smart_ptr_unittest.cpp \
|
||||
thread_store_unittest.cpp \
|
||||
thread_unittest.cpp \
|
||||
unique_integer_map_unittest.cpp \
|
||||
|
||||
$(call emugl-begin-host-executable,emugl$(BUILD_TARGET_SUFFIX)_common_host_unittests)
|
||||
LOCAL_SRC_FILES := $(host_commonSources)
|
||||
$(call emugl-import,libemugl_common libemugl_gtest)
|
||||
$(call emugl-end-module)
|
||||
|
||||
$(call emugl-begin-host-shared-library,lib$(BUILD_TARGET_SUFFIX)emugl_test_shared_library)
|
||||
LOCAL_SRC_FILES := testing/test_shared_library.cpp
|
||||
LOCAL_CFLAGS := -fvisibility=default
|
||||
$(call emugl-end-module)
|
||||
16
external/android-emugl/shared/emugl/common/CMakeLists.txt
vendored
Normal file
16
external/android-emugl/shared/emugl/common/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
set(COMMON_SOURCES
|
||||
crash_reporter.cpp
|
||||
id_to_object_map.cpp
|
||||
lazy_instance.cpp
|
||||
logging.cpp
|
||||
message_channel.cpp
|
||||
pod_vector.cpp
|
||||
shared_library.cpp
|
||||
smart_ptr.cpp
|
||||
sockets.cpp
|
||||
thread_store.cpp
|
||||
thread_pthread.cpp)
|
||||
|
||||
add_library(emugl_common ${COMMON_SOURCES})
|
||||
target_link_libraries(emugl_common
|
||||
dl pthread)
|
||||
91
external/android-emugl/shared/emugl/common/condition_variable.h
vendored
Normal file
91
external/android-emugl/shared/emugl/common/condition_variable.h
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_CONDITION_VARIABLE_H
|
||||
#define EMUGL_CONDITION_VARIABLE_H
|
||||
|
||||
#include "emugl/common/mutex.h"
|
||||
#include "emugl/common/pod_vector.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// A class that implements a condition variable, which can be used in
|
||||
// association with a Mutex to blocking-wait for specific conditions.
|
||||
// Useful to implement various synchronization data structures.
|
||||
// For an example, see ::emugl::MessageChannel.
|
||||
class ConditionVariable {
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
|
||||
// Default constructor.
|
||||
ConditionVariable();
|
||||
|
||||
// Destructor.
|
||||
~ConditionVariable();
|
||||
|
||||
// Wait until the condition variable is signaled. Note that spurious
|
||||
// wakeups are always a possibility, so always check the condition
|
||||
// in a loop, i.e. do:
|
||||
//
|
||||
// while (!condition) { condVar.wait(&lock); }
|
||||
//
|
||||
// instead of:
|
||||
//
|
||||
// if (!condition) { condVar.wait(&lock); }
|
||||
//
|
||||
void wait(Mutex* userLock);
|
||||
|
||||
// Signal that a condition was reached. This will wake at most one
|
||||
// waiting thread that is blocked on wait().
|
||||
void signal();
|
||||
|
||||
private:
|
||||
PodVector<HANDLE> mWaiters;
|
||||
Mutex mLock;
|
||||
|
||||
#else // !_WIN32
|
||||
|
||||
// Note: on Posix systems, make it a naive wrapper around pthread_cond_t.
|
||||
|
||||
ConditionVariable() {
|
||||
pthread_cond_init(&mCond, NULL);
|
||||
}
|
||||
|
||||
~ConditionVariable() {
|
||||
pthread_cond_destroy(&mCond);
|
||||
}
|
||||
|
||||
void wait(Mutex* userLock) {
|
||||
pthread_cond_wait(&mCond, &userLock->mLock);
|
||||
}
|
||||
|
||||
void signal() {
|
||||
pthread_cond_signal(&mCond);
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_cond_t mCond;
|
||||
|
||||
#endif // !_WIN32
|
||||
};
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_CONDITION_VARIABLE_H
|
||||
27
external/android-emugl/shared/emugl/common/condition_variable_unittest.cpp
vendored
Normal file
27
external/android-emugl/shared/emugl/common/condition_variable_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/condition_variable.h"
|
||||
|
||||
#include "emugl/common/mutex.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
TEST(ConditionVariable, init) {
|
||||
ConditionVariable cond;
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
114
external/android-emugl/shared/emugl/common/condition_variable_win32.cpp
vendored
Normal file
114
external/android-emugl/shared/emugl/common/condition_variable_win32.cpp
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/condition_variable.h"
|
||||
|
||||
#include "emugl/common/lazy_instance.h"
|
||||
#include "emugl/common/mutex.h"
|
||||
#include "emugl/common/pod_vector.h"
|
||||
|
||||
// Technical note: this is loosely based on the Chromium implementation
|
||||
// of ConditionVariable. This version works on Windows XP and above and
|
||||
// doesn't try to use Vista's CONDITION_VARIABLE types.
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper class which implements a free list of event handles.
|
||||
class WaitEventStorage {
|
||||
public:
|
||||
WaitEventStorage() : mFreeHandles(), mLock() {}
|
||||
|
||||
~WaitEventStorage() {
|
||||
for (size_t n = 0; n < mFreeHandles.size(); ++n) {
|
||||
CloseHandle(mFreeHandles[n]);
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE alloc() {
|
||||
HANDLE handle;
|
||||
mLock.lock();
|
||||
size_t size = mFreeHandles.size();
|
||||
if (size > 0) {
|
||||
handle = mFreeHandles[size - 1U];
|
||||
mFreeHandles.remove(size - 1U);
|
||||
} else {
|
||||
handle = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
}
|
||||
mLock.unlock();
|
||||
return handle;
|
||||
}
|
||||
|
||||
void free(HANDLE h) {
|
||||
mLock.lock();
|
||||
ResetEvent(h);
|
||||
mFreeHandles.push_back(h);
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
PodVector<HANDLE> mFreeHandles;
|
||||
Mutex mLock;
|
||||
};
|
||||
|
||||
LazyInstance<WaitEventStorage> sWaitEvents = LAZY_INSTANCE_INIT;
|
||||
|
||||
} // namespace
|
||||
|
||||
ConditionVariable::ConditionVariable() : mWaiters(), mLock() {}
|
||||
|
||||
ConditionVariable::~ConditionVariable() {
|
||||
mLock.lock();
|
||||
for (size_t n = 0; n < mWaiters.size(); ++n) {
|
||||
CloseHandle(mWaiters[n]);
|
||||
}
|
||||
mWaiters.resize(0U);
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
void ConditionVariable::wait(Mutex* userLock) {
|
||||
// Grab new waiter event handle.
|
||||
mLock.lock();
|
||||
HANDLE handle = sWaitEvents->alloc();
|
||||
mWaiters.push_back(handle);
|
||||
mLock.unlock();
|
||||
|
||||
// Unlock user lock then wait for event.
|
||||
userLock->unlock();
|
||||
WaitForSingleObject(handle, INFINITE);
|
||||
// NOTE: The handle has been removed from mWaiters here,
|
||||
// see signal() below. Close/recycle the event.
|
||||
sWaitEvents->free(handle);
|
||||
userLock->lock();
|
||||
}
|
||||
|
||||
void ConditionVariable::signal() {
|
||||
mLock.lock();
|
||||
size_t size = mWaiters.size();
|
||||
if (size > 0U) {
|
||||
// NOTE: This wakes up the thread that went to sleep most
|
||||
// recently (LIFO) for performance reason. For better
|
||||
// fairness, using (FIFO) would be appropriate.
|
||||
HANDLE handle = mWaiters[size - 1U];
|
||||
mWaiters.remove(size - 1U);
|
||||
SetEvent(handle);
|
||||
// NOTE: The handle will be closed/recycled by the waiter.
|
||||
} else {
|
||||
// Nothing to signal.
|
||||
}
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
33
external/android-emugl/shared/emugl/common/crash_reporter.cpp
vendored
Normal file
33
external/android-emugl/shared/emugl/common/crash_reporter.cpp
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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 "crash_reporter.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
void default_crash_reporter(const char* format, ...) {
|
||||
abort();
|
||||
}
|
||||
|
||||
crash_reporter_t emugl_crash_reporter = default_crash_reporter;
|
||||
|
||||
void set_emugl_crash_reporter(crash_reporter_t crash_reporter) {
|
||||
if (crash_reporter) {
|
||||
emugl_crash_reporter = crash_reporter;
|
||||
} else {
|
||||
emugl_crash_reporter = default_crash_reporter;
|
||||
}
|
||||
}
|
||||
22
external/android-emugl/shared/emugl/common/crash_reporter.h
vendored
Normal file
22
external/android-emugl/shared/emugl/common/crash_reporter.h
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef void (*crash_reporter_t)(const char* format, ...);
|
||||
|
||||
extern crash_reporter_t emugl_crash_reporter;
|
||||
void set_emugl_crash_reporter(crash_reporter_t crash_reporter);
|
||||
236
external/android-emugl/shared/emugl/common/id_to_object_map.cpp
vendored
Normal file
236
external/android-emugl/shared/emugl/common/id_to_object_map.cpp
vendored
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/id_to_object_map.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
typedef IdToObjectMapBase::KeyType KeyType;
|
||||
|
||||
enum {
|
||||
kMinShift = 3,
|
||||
kMaxShift = 31,
|
||||
kMinCapacity = (1 << kMinShift),
|
||||
kLoadScale = 1024,
|
||||
kMinLoad = kLoadScale/4, // 25% minimum load.
|
||||
kMaxLoad = kLoadScale*3/4, // 75% maximum load.
|
||||
|
||||
kInvalidKey = IdToObjectMapBase::kMaxId + 1U,
|
||||
kTombstone = IdToObjectMapBase::kMaxId + 2U,
|
||||
};
|
||||
|
||||
// Return a number that indicates if the current |capacity| is appropriate
|
||||
// to hold |size| items in our map.
|
||||
// -1 -> the capacity is too small and needs to be increased.
|
||||
// 0 -> the capacity is ok.
|
||||
// +1 -> the capacity is too large and needs to be decreased.
|
||||
int capacityCompare(size_t shift, size_t size) {
|
||||
size_t capacity = 1U << shift;
|
||||
// Essentially, one can rewrite:
|
||||
// load < minLoad
|
||||
// as:
|
||||
// size / capacity < minLoad
|
||||
// capacity * minLoad > size
|
||||
if (capacity * kMinLoad > size * kLoadScale)
|
||||
return +1;
|
||||
|
||||
// Similarly, one can rewrite:
|
||||
// load > maxLoad
|
||||
// as:
|
||||
// size / capacity > maxLoad
|
||||
// capacity * maxLoad < size
|
||||
if (capacity * kMaxLoad < size * kLoadScale)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t probeKeys(const KeyType* keys, size_t shift, KeyType key) {
|
||||
static const int kPrimes[] = {
|
||||
1, /* For 1 << 0 */
|
||||
2,
|
||||
3,
|
||||
7,
|
||||
13,
|
||||
31,
|
||||
61,
|
||||
127,
|
||||
251,
|
||||
509,
|
||||
1021,
|
||||
2039,
|
||||
4093,
|
||||
8191,
|
||||
16381,
|
||||
32749,
|
||||
65521, /* For 1 << 16 */
|
||||
131071,
|
||||
262139,
|
||||
524287,
|
||||
1048573,
|
||||
2097143,
|
||||
4194301,
|
||||
8388593,
|
||||
16777213,
|
||||
33554393,
|
||||
67108859,
|
||||
134217689,
|
||||
268435399,
|
||||
536870909,
|
||||
1073741789,
|
||||
2147483647 /* For 1 << 31 */
|
||||
};
|
||||
|
||||
size_t slot = key % kPrimes[shift];
|
||||
size_t step = 0;
|
||||
for (;;) {
|
||||
KeyType k = keys[slot];
|
||||
if (k == kInvalidKey || k == kTombstone || k == key)
|
||||
return slot;
|
||||
|
||||
step += 1;
|
||||
slot = (slot + step) & (1U << shift);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
IdToObjectMapBase::IdToObjectMapBase() :
|
||||
mCount(0), mShift(kMinShift) {
|
||||
size_t capacity = 1U << mShift;
|
||||
mKeys = static_cast<KeyType*>(::calloc(sizeof(mKeys[0]), capacity));
|
||||
mValues = static_cast<void**>(::calloc(sizeof(mValues[0]), capacity));
|
||||
for (size_t n = 0; n < capacity; ++n) {
|
||||
mKeys[n] = kInvalidKey;
|
||||
}
|
||||
}
|
||||
|
||||
IdToObjectMapBase::~IdToObjectMapBase() {
|
||||
mShift = 0;
|
||||
mCount = 0;
|
||||
::free(mKeys);
|
||||
::free(mValues);
|
||||
}
|
||||
|
||||
bool IdToObjectMapBase::contains(KeyType key) const {
|
||||
size_t slot = probeKeys(mKeys, mShift, key);
|
||||
switch (mKeys[slot]) {
|
||||
case kInvalidKey:
|
||||
case kTombstone:
|
||||
return false;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IdToObjectMapBase::find(KeyType key, void** value) const {
|
||||
size_t slot = probeKeys(mKeys, mShift, key);
|
||||
if (!isValidKey(mKeys[slot])) {
|
||||
*value = NULL;
|
||||
return false;
|
||||
}
|
||||
*value = mValues[slot];
|
||||
return true;
|
||||
}
|
||||
|
||||
void* IdToObjectMapBase::set(KeyType key, void* value) {
|
||||
if (!value)
|
||||
return remove(key);
|
||||
|
||||
size_t slot = probeKeys(mKeys, mShift, key);
|
||||
void* result;
|
||||
if (isValidKey(mKeys[slot])) {
|
||||
result = mValues[slot];
|
||||
mValues[slot] = value;
|
||||
} else {
|
||||
mKeys[slot] = key;
|
||||
mValues[slot] = value;
|
||||
result = NULL;
|
||||
mCount++;
|
||||
resize(mCount);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void* IdToObjectMapBase::remove(KeyType key) {
|
||||
size_t slot = probeKeys(mKeys, mShift, key);
|
||||
if (!isValidKey(mKeys[slot]))
|
||||
return NULL;
|
||||
|
||||
void* result = mValues[slot];
|
||||
mValues[slot] = NULL;
|
||||
mKeys[slot] = kTombstone;
|
||||
mCount--;
|
||||
return result;
|
||||
}
|
||||
|
||||
void IdToObjectMapBase::resize(size_t newSize) {
|
||||
int ret = capacityCompare(mShift, newSize);
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
size_t oldCapacity = 1U << mShift;
|
||||
size_t newShift = mShift;
|
||||
|
||||
if (ret < 0) {
|
||||
// Capacity is too small and must be increased.
|
||||
do {
|
||||
if (newShift == kMaxShift)
|
||||
break;
|
||||
++newShift;
|
||||
} while (capacityCompare(newShift, newSize) < 0);
|
||||
} else {
|
||||
// Capacity is too large and must be decreased.
|
||||
do {
|
||||
if (newShift == kMinShift)
|
||||
break;
|
||||
newShift--;
|
||||
} while (capacityCompare(newShift, newSize) > 0);
|
||||
}
|
||||
if (newShift == mShift)
|
||||
return;
|
||||
|
||||
// Allocate new arrays.
|
||||
size_t newCapacity = 1U << newShift;
|
||||
KeyType* newKeys = static_cast<KeyType*>(
|
||||
::calloc(sizeof(newKeys[0]), newCapacity));
|
||||
void** newValues = static_cast<void**>(
|
||||
::calloc(sizeof(newValues[0]), newCapacity));
|
||||
for (size_t n = 0; n < newCapacity; ++n)
|
||||
newKeys[n] = kInvalidKey;
|
||||
|
||||
// Copy old entries into new arrays.
|
||||
for (size_t n = 0; n < oldCapacity; ++n) {
|
||||
KeyType key = mKeys[n];
|
||||
if (isValidKey(key)) {
|
||||
size_t newSlot = probeKeys(newKeys, newShift, key);
|
||||
newKeys[newSlot] = key;
|
||||
newValues[newSlot] = mValues[n];
|
||||
}
|
||||
}
|
||||
|
||||
// Swap arrays, and get rid of old ones.
|
||||
::free(mKeys);
|
||||
::free(mValues);
|
||||
mKeys = newKeys;
|
||||
mValues = newValues;
|
||||
mShift = newShift;
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
176
external/android-emugl/shared/emugl/common/id_to_object_map.h
vendored
Normal file
176
external/android-emugl/shared/emugl/common/id_to_object_map.h
vendored
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_ID_TO_OBJECT_MAP_H
|
||||
#define EMUGL_COMMON_ID_TO_OBJECT_MAP_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// Base implementation class for IdToObjectMap template.
|
||||
// Used to reduce template-instanciated code generation.
|
||||
class IdToObjectMapBase {
|
||||
public:
|
||||
// The type of keys in this map.
|
||||
typedef unsigned KeyType;
|
||||
|
||||
// Values higher than kMaxId cannot be used as map keys.
|
||||
enum {
|
||||
kMaxId = 0xfffffffdU,
|
||||
};
|
||||
|
||||
static inline bool isValidKey(KeyType key) {
|
||||
return key <= kMaxId;
|
||||
}
|
||||
|
||||
protected:
|
||||
IdToObjectMapBase();
|
||||
|
||||
~IdToObjectMapBase();
|
||||
|
||||
void clear();
|
||||
|
||||
// Return size
|
||||
inline size_t size() const { return mCount; }
|
||||
|
||||
inline size_t capacity() const { return 1U << mShift; }
|
||||
|
||||
// Return true iff the map contains a given key.
|
||||
bool contains(KeyType key) const;
|
||||
|
||||
// Find a value associated with a given |key| in the map.
|
||||
// On success, return true and sets |*value| to the value/pointer,
|
||||
// which is _still_ owned by the map.
|
||||
// On failure, return false and sets |*value| to NULL.
|
||||
bool find(KeyType key, void** value) const;
|
||||
|
||||
// Associate a value with a given |key| in the map.
|
||||
// Return the old value for the key, if any. Caller is responsible
|
||||
// for freeing it.
|
||||
void* set(KeyType key, void* value);
|
||||
|
||||
// Remove the value associated with a given |key|.
|
||||
// Return the old value, if any. Caller is responsible for
|
||||
// freeing it.
|
||||
void* remove(KeyType key);
|
||||
|
||||
size_t mCount;
|
||||
size_t mShift;
|
||||
KeyType* mKeys;
|
||||
void** mValues;
|
||||
|
||||
private:
|
||||
// Resize the map if needed to ensure it can hold at least |newSize|
|
||||
// entries.
|
||||
void resize(size_t newSize);
|
||||
};
|
||||
|
||||
// A templated data container that acts as a dictionary mapping unsigned
|
||||
// integer keys to heap-allocated objects of type T. The dictionary
|
||||
// owns the objects associated with its keys, and automatically destroys
|
||||
// them when it is destroyed, or during replacement or removal.
|
||||
template <class T>
|
||||
class IdToObjectMap : public IdToObjectMapBase {
|
||||
public:
|
||||
// Initialize an empty instance.
|
||||
IdToObjectMap() : IdToObjectMapBase() {}
|
||||
|
||||
// Destroy this instance.
|
||||
~IdToObjectMap() {
|
||||
clear();
|
||||
}
|
||||
|
||||
// Return the number of items in this map.
|
||||
inline size_t size() const { return IdToObjectMapBase::size(); }
|
||||
|
||||
// Return true iff the map is empty.
|
||||
inline bool empty() const { return !IdToObjectMapBase::size(); }
|
||||
|
||||
// Remove all items from the map.
|
||||
void clear();
|
||||
|
||||
// Returns true iff the dictionary contains a value for |key|.
|
||||
inline bool contains(KeyType key) const {
|
||||
return IdToObjectMapBase::contains(key);
|
||||
}
|
||||
|
||||
// Find the value corresponding to |key| in this map.
|
||||
// On success, return true, and sets |*value| to point to the
|
||||
// value (still owned by the instance). On failure, return false.
|
||||
inline bool find(KeyType key, T** value) const {
|
||||
return IdToObjectMapBase::find(key, reinterpret_cast<void**>(value));
|
||||
}
|
||||
|
||||
// Return the value associated with a given |key|, or NULL if it is
|
||||
// not in the map. Result is still owned by the map.
|
||||
inline T* get(KeyType key) const {
|
||||
T* result = NULL;
|
||||
this->find(key, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Associate |value| with a given |key|. Returns true if a previous
|
||||
// value was replaced, and false if this is the first time a value
|
||||
// was associated with the given key. IMPORTANT: This transfers
|
||||
// ownership of |value| to the map instance. In case of replacement,
|
||||
// the old value is automatically destroyed. Using NULL as the value
|
||||
// is equivalent to calling remove().
|
||||
bool set(KeyType key, T* value);
|
||||
|
||||
// Remove any value associated with |key|.
|
||||
// Return true iff a value was associated with the key and destroyed
|
||||
// by this function, false if there was no value associated with the
|
||||
// key (or if it was NULL).
|
||||
bool remove(KeyType key);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void IdToObjectMap<T>::clear() {
|
||||
size_t n = capacity();
|
||||
while (n > 0) {
|
||||
--n;
|
||||
if (!isValidKey(mKeys[n]))
|
||||
continue;
|
||||
|
||||
delete static_cast<T*>(mValues[n]);
|
||||
mValues[n] = NULL;
|
||||
mKeys[n] = kMaxId + 1U;
|
||||
}
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool IdToObjectMap<T>::set(KeyType key, T* value) {
|
||||
T* oldValue = static_cast<T*>(IdToObjectMapBase::set(key, value));
|
||||
if (!oldValue) {
|
||||
return false;
|
||||
}
|
||||
delete oldValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool IdToObjectMap<T>::remove(KeyType key) {
|
||||
T* oldValue = static_cast<T*>(IdToObjectMapBase::remove(key));
|
||||
if (!oldValue)
|
||||
return false;
|
||||
delete oldValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
|
||||
#endif // EMUGL_COMMON_ID_TO_OBJECT_MAP_H
|
||||
116
external/android-emugl/shared/emugl/common/id_to_object_map_unittest.cpp
vendored
Normal file
116
external/android-emugl/shared/emugl/common/id_to_object_map_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/id_to_object_map.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
typedef IdToObjectMapBase::KeyType KeyType;
|
||||
|
||||
class Foo {
|
||||
public:
|
||||
Foo() : mVal(0) {}
|
||||
Foo(int val) : mVal(val) {}
|
||||
~Foo() {}
|
||||
int val() const { return mVal; }
|
||||
void setVal(int val) { mVal = val; }
|
||||
private:
|
||||
int mVal;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(IdToObjectMap, Empty) {
|
||||
IdToObjectMap<Foo> map;
|
||||
EXPECT_TRUE(map.empty());
|
||||
EXPECT_EQ(0U, map.size());
|
||||
}
|
||||
|
||||
TEST(IdToObjectMap, SetIntegerRange) {
|
||||
IdToObjectMap<Foo> map;
|
||||
KeyType kMax = 10000;
|
||||
|
||||
// Add all items in the map.
|
||||
for (KeyType n = 0; n < kMax; ++n) {
|
||||
EXPECT_FALSE(map.set(n, new Foo(n))) << "For key " << n;
|
||||
}
|
||||
|
||||
// Check final size.
|
||||
EXPECT_EQ(static_cast<size_t>(kMax), map.size());
|
||||
|
||||
// Find all items in the map.
|
||||
for (KeyType n = 0; n < kMax; ++n) {
|
||||
EXPECT_TRUE(map.contains(n)) << "For key " << n;
|
||||
Foo* foo = NULL;
|
||||
EXPECT_TRUE(map.find(n, &foo)) << "For key " << n;
|
||||
if (foo) {
|
||||
EXPECT_EQ(static_cast<int>(n), foo->val()) << "For key " << n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IdToObjectMap, RemoveAll) {
|
||||
IdToObjectMap<Foo> map;
|
||||
KeyType kMax = 10000;
|
||||
|
||||
// Add all items in the map.
|
||||
for (KeyType n = 0; n < kMax; ++n) {
|
||||
EXPECT_FALSE(map.set(n, new Foo(n))) << "For key " << n;
|
||||
}
|
||||
|
||||
EXPECT_EQ(static_cast<size_t>(kMax), map.size());
|
||||
|
||||
for (KeyType n = 0; n < kMax; ++n) {
|
||||
EXPECT_TRUE(map.remove(n)) << "For key " << n;
|
||||
}
|
||||
EXPECT_EQ(0U, map.size());
|
||||
}
|
||||
|
||||
TEST(IdToObjectMap, RemoveOdd) {
|
||||
IdToObjectMap<Foo> map;
|
||||
KeyType kMax = 10000;
|
||||
|
||||
// Add all items in the map.
|
||||
for (KeyType n = 0; n < kMax; ++n) {
|
||||
EXPECT_FALSE(map.set(n, new Foo(n))) << "For key " << n;
|
||||
}
|
||||
|
||||
EXPECT_EQ(static_cast<size_t>(kMax), map.size());
|
||||
|
||||
for (KeyType n = 0; n < kMax; ++n) {
|
||||
if (n & 1) {
|
||||
EXPECT_TRUE(map.remove(n)) << "For key " << n;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(static_cast<size_t>(kMax / 2), map.size());
|
||||
|
||||
for (KeyType n = 0; n < kMax; ++n) {
|
||||
if (n & 1) {
|
||||
EXPECT_FALSE(map.contains(n)) << "For key " << n;
|
||||
} else {
|
||||
EXPECT_TRUE(map.contains(n)) << "For key " << n;
|
||||
Foo* foo = NULL;
|
||||
EXPECT_TRUE(map.find(n, &foo)) << "For key " << n;
|
||||
if (foo) {
|
||||
EXPECT_EQ(static_cast<int>(n), foo->val());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
101
external/android-emugl/shared/emugl/common/lazy_instance.cpp
vendored
Normal file
101
external/android-emugl/shared/emugl/common/lazy_instance.cpp
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/lazy_instance.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN 1
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <sched.h>
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
namespace internal {
|
||||
|
||||
typedef LazyInstanceState::AtomicType AtomicType;
|
||||
|
||||
#if defined(__GNUC__)
|
||||
static inline void compilerBarrier() {
|
||||
__asm__ __volatile__ ("" : : : "memory");
|
||||
}
|
||||
#else
|
||||
#error "Your compiler is not supported"
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
|
||||
# define acquireBarrier() compilerBarrier()
|
||||
# define releaseBarrier() compilerBarrier()
|
||||
#else
|
||||
# error "Your CPU is not supported"
|
||||
#endif
|
||||
|
||||
static inline AtomicType loadAcquire(AtomicType volatile* ptr) {
|
||||
AtomicType ret = *ptr;
|
||||
acquireBarrier();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void storeRelease(AtomicType volatile* ptr, AtomicType value) {
|
||||
releaseBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
static int atomicCompareAndSwap(AtomicType volatile* ptr,
|
||||
int expected,
|
||||
int value) {
|
||||
#ifdef _WIN32
|
||||
return InterlockedCompareExchange(ptr, value, expected);
|
||||
#elif defined(__GNUC__)
|
||||
return __sync_val_compare_and_swap(ptr, expected, value);
|
||||
#else
|
||||
#error "Your compiler is not supported"
|
||||
#endif
|
||||
}
|
||||
|
||||
static void yieldThread() {
|
||||
#ifdef _WIN32
|
||||
::Sleep(0);
|
||||
#else
|
||||
sched_yield();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LazyInstanceState::inInitState() {
|
||||
return loadAcquire(&mState) == STATE_INIT;
|
||||
}
|
||||
|
||||
bool LazyInstanceState::needConstruction() {
|
||||
AtomicType state = loadAcquire(&mState);
|
||||
if (mState == STATE_DONE)
|
||||
return false;
|
||||
|
||||
state = atomicCompareAndSwap(&mState, STATE_INIT, STATE_CONSTRUCTING);
|
||||
if (state == STATE_INIT)
|
||||
return true;
|
||||
|
||||
do {
|
||||
yieldThread();
|
||||
state = loadAcquire(&mState);
|
||||
} while (state != STATE_DONE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LazyInstanceState::doneConstructing() {
|
||||
storeRelease(&mState, STATE_DONE);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace emugl
|
||||
156
external/android-emugl/shared/emugl/common/lazy_instance.h
vendored
Normal file
156
external/android-emugl/shared/emugl/common/lazy_instance.h
vendored
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_LAZY_INSTANCE_H
|
||||
#define EMUGL_COMMON_LAZY_INSTANCE_H
|
||||
|
||||
#include <new>
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN 1
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
namespace internal {
|
||||
|
||||
// A LazyInstance is a helper template that can be used to perform
|
||||
// thread-safe lazy initialization of static C++ objects without forcing
|
||||
// the generation of C++ static constructors in the final executable.
|
||||
//
|
||||
// In a nutshell, you can replace a statement like:
|
||||
//
|
||||
// static Foo gFoo;
|
||||
//
|
||||
// With:
|
||||
//
|
||||
// static LazyInstance<Foo> gFoo = LAZY_INSTANCE_INIT;
|
||||
//
|
||||
// In the first case, a hidden static C++ constructor is embedded in the
|
||||
// final executable, and executed at *load* *time* to call the Foo::Foo
|
||||
// constructor on the gFoo object.
|
||||
//
|
||||
// On the second case, gFoo will only be initialized lazily, i.e. the first
|
||||
// time any code actually tries to access the variable.
|
||||
//
|
||||
// Note that access is slightly different, i.e.:
|
||||
//
|
||||
// gFoo.get() returns a reference to the lazy-initialized object.
|
||||
// gFoo.ptr() returns a pointer to it.
|
||||
// gFoo->Something() is equivalent to doing gFoo.ptr()->Something().
|
||||
//
|
||||
// 'gFoo' is stored in the .bss section and this doesn't use heap allocation.
|
||||
// This class can only be used to perform lazy initialization through the
|
||||
// class' default constructor. For more specialized cases, you will have
|
||||
// to create a derived class, e.g.:
|
||||
//
|
||||
// class FoorWithDefaultParams : public Foo {
|
||||
// public:
|
||||
// FooWithDefaultParams() : Foo(<default-parameters>) {}
|
||||
// };
|
||||
//
|
||||
// LazyInstance<FooWithDefaultParams> gFoo = LAZY_INSTANCE_INIT;
|
||||
//
|
||||
// The implementation of LazyInstance relies on atomic operations and
|
||||
// POD-struct class definitions, i.e. one that doesn't have any constructor,
|
||||
// destructor, virtual members, or private ones, and that can be
|
||||
// zero-initialized at link time.
|
||||
//
|
||||
// You can also use LazyInstance<> instances as static local variables,
|
||||
// e.g.:
|
||||
//
|
||||
// Foo* getFooSingleton() {
|
||||
// static LazyInstance<Foo> sFoo = LAZY_INSTANCE_INIT;
|
||||
// return sFoo.ptr();
|
||||
// }
|
||||
//
|
||||
// This is useful on Windows which doesn't support thread-safe lazy
|
||||
// initialization of static C++ local variables, or when the code is
|
||||
// compiled with -fno-threadsafe-statics.
|
||||
//
|
||||
// This class is heavily inspired by Chromium's implementation of the
|
||||
// same-named class (see $CHROMIUM/src/base/lazy_instance.h).
|
||||
|
||||
// Atomic state variable type. Used to ensure to synchronize concurrent
|
||||
// initialization and access without incurring the full cost of a mutex
|
||||
// lock/unlock.
|
||||
struct LazyInstanceState {
|
||||
enum {
|
||||
STATE_INIT = 0,
|
||||
STATE_CONSTRUCTING = 1,
|
||||
STATE_DONE = 2,
|
||||
};
|
||||
|
||||
bool inInitState();
|
||||
bool needConstruction();
|
||||
void doneConstructing();
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef LONG volatile AtomicType;
|
||||
#else
|
||||
typedef int volatile AtomicType;
|
||||
#endif
|
||||
|
||||
volatile AtomicType mState;
|
||||
};
|
||||
|
||||
#define LAZY_INSTANCE_STATE_INIT \
|
||||
{ ::emugl::internal::LazyInstanceState::STATE_INIT }
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// LazyInstance template definition, see comment above for usage
|
||||
// instructions. It is crucial to make this a POD-struct compatible
|
||||
// type [1].
|
||||
//
|
||||
// [1] http://en.wikipedia.org/wiki/Plain_Old_Data_Structures
|
||||
//
|
||||
template <class T>
|
||||
struct LazyInstance {
|
||||
bool hasInstance() const { return !mState.inInitState(); }
|
||||
|
||||
T& get() const { return *ptr(); }
|
||||
|
||||
T* ptr() const;
|
||||
|
||||
const T* operator->() const { return ptr(); }
|
||||
|
||||
T* operator->() { return ptr(); }
|
||||
|
||||
T& operator*() { return get(); }
|
||||
|
||||
// Really private, do not use.
|
||||
union {
|
||||
mutable internal::LazyInstanceState mState;
|
||||
double mPadding;
|
||||
};
|
||||
mutable char mStorage[sizeof(T)];
|
||||
};
|
||||
|
||||
// Initialization value, must resolve to all-0 to ensure the object
|
||||
// instance is actually placed in the .bss
|
||||
#define LAZY_INSTANCE_INIT { { LAZY_INSTANCE_STATE_INIT }, { 0 } }
|
||||
|
||||
template <class T>
|
||||
T* LazyInstance<T>::ptr() const {
|
||||
if (mState.needConstruction()) {
|
||||
new (mStorage) T();
|
||||
mState.doneConstructing();
|
||||
}
|
||||
return reinterpret_cast<T*>(mStorage);
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_COMMON_LAZY_INSTANCE_H
|
||||
146
external/android-emugl/shared/emugl/common/lazy_instance_unittest.cpp
vendored
Normal file
146
external/android-emugl/shared/emugl/common/lazy_instance_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/lazy_instance.h"
|
||||
|
||||
#include "emugl/common/mutex.h"
|
||||
#include "emugl/common/testing/test_thread.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
class Foo {
|
||||
public:
|
||||
Foo() : mValue(42) {}
|
||||
int get() const { return mValue; }
|
||||
void set(int value) { mValue = value; }
|
||||
~Foo() { mValue = 13; }
|
||||
private:
|
||||
int mValue;
|
||||
};
|
||||
|
||||
class StaticCounter {
|
||||
public:
|
||||
StaticCounter() {
|
||||
Mutex::AutoLock lock(mMutex);
|
||||
mCounter++;
|
||||
}
|
||||
|
||||
int getValue() const {
|
||||
Mutex::AutoLock lock(mMutex);
|
||||
return mCounter;
|
||||
}
|
||||
|
||||
private:
|
||||
static Mutex mMutex;
|
||||
static int mCounter;
|
||||
};
|
||||
|
||||
// NOTE: This introduces a static C++ constructor for this object file,
|
||||
// but that's ok because a LazyInstance<Mutex> should not be used to
|
||||
// test the behaviour of LazyInstance :-)
|
||||
Mutex StaticCounter::mMutex;
|
||||
int StaticCounter::mCounter = 0;
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(LazyInstance, HasInstance) {
|
||||
LazyInstance<Foo> foo_instance = LAZY_INSTANCE_INIT;
|
||||
EXPECT_FALSE(foo_instance.hasInstance());
|
||||
EXPECT_FALSE(foo_instance.hasInstance());
|
||||
foo_instance.ptr();
|
||||
EXPECT_TRUE(foo_instance.hasInstance());
|
||||
}
|
||||
|
||||
TEST(LazyInstance, Simple) {
|
||||
LazyInstance<Foo> foo_instance = LAZY_INSTANCE_INIT;
|
||||
Foo* foo1 = foo_instance.ptr();
|
||||
EXPECT_TRUE(foo1);
|
||||
EXPECT_EQ(42, foo_instance->get());
|
||||
foo1->set(10);
|
||||
EXPECT_EQ(10, foo_instance->get());
|
||||
EXPECT_EQ(foo1, foo_instance.ptr());
|
||||
}
|
||||
|
||||
// For the following test, launch 1000 threads that each try to get
|
||||
// the instance pointer of a lazy instance. Then verify that they're all
|
||||
// the same value.
|
||||
//
|
||||
// The lazy instance has a special constructor that will increment a
|
||||
// global counter. This allows us to ensure that it is only called once.
|
||||
//
|
||||
|
||||
namespace {
|
||||
|
||||
// The following is the shared structure between all threads.
|
||||
struct MultiState {
|
||||
MultiState(LazyInstance<StaticCounter>* staticCounter) :
|
||||
mMutex(), mStaticCounter(staticCounter), mCount(0) {}
|
||||
|
||||
enum {
|
||||
kMaxThreads = 1000,
|
||||
};
|
||||
|
||||
Mutex mMutex;
|
||||
LazyInstance<StaticCounter>* mStaticCounter;
|
||||
size_t mCount;
|
||||
void* mValues[kMaxThreads];
|
||||
TestThread* mThreads[kMaxThreads];
|
||||
};
|
||||
|
||||
// The thread function for the test below.
|
||||
static void* threadFunc(void* param) {
|
||||
MultiState* state = static_cast<MultiState*>(param);
|
||||
Mutex::AutoLock lock(state->mMutex);
|
||||
if (state->mCount < MultiState::kMaxThreads) {
|
||||
state->mValues[state->mCount++] = state->mStaticCounter->ptr();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(LazyInstance, MultipleThreads) {
|
||||
LazyInstance<StaticCounter> counter_instance = LAZY_INSTANCE_INIT;
|
||||
MultiState state(&counter_instance);
|
||||
const size_t kNumThreads = MultiState::kMaxThreads;
|
||||
|
||||
// Create all threads.
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
state.mThreads[n] = new TestThread(threadFunc, &state);
|
||||
}
|
||||
|
||||
// Wait for their completion.
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
state.mThreads[n]->join();
|
||||
}
|
||||
|
||||
// Now check that the constructor was only called once.
|
||||
EXPECT_EQ(1, counter_instance->getValue());
|
||||
|
||||
// Now compare all the store values, they should be the same.
|
||||
StaticCounter* expectedValue = counter_instance.ptr();
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
EXPECT_EQ(expectedValue, state.mValues[n]) << "For thread " << n;
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
delete state.mThreads[n];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
38
external/android-emugl/shared/emugl/common/logging.cpp
vendored
Normal file
38
external/android-emugl/shared/emugl/common/logging.cpp
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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 "emugl/common/logging.h"
|
||||
|
||||
void default_logger(const char* fmt, ...) { }
|
||||
|
||||
logger_t emugl_logger = default_logger;
|
||||
logger_t emugl_cxt_logger = default_logger;
|
||||
|
||||
void set_emugl_logger(logger_t f) {
|
||||
if (!f) {
|
||||
emugl_logger = default_logger;
|
||||
} else {
|
||||
emugl_logger = f;
|
||||
}
|
||||
}
|
||||
|
||||
void set_emugl_cxt_logger(logger_t f) {
|
||||
if (!f) {
|
||||
emugl_cxt_logger = default_logger;
|
||||
} else {
|
||||
emugl_cxt_logger = f;
|
||||
}
|
||||
}
|
||||
37
external/android-emugl/shared/emugl/common/logging.h
vendored
Normal file
37
external/android-emugl/shared/emugl/common/logging.h
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
typedef void (*logger_t)(const char* fmt, ...);
|
||||
extern logger_t emugl_logger;
|
||||
extern logger_t emugl_cxt_logger;
|
||||
void set_emugl_logger(logger_t f);
|
||||
void set_emugl_cxt_logger(logger_t f);
|
||||
|
||||
#define GL_LOGGING 1
|
||||
|
||||
#if GL_LOGGING
|
||||
|
||||
#define GL_LOG(...) do { \
|
||||
emugl_logger(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define GL_CXT_LOG(...) do { \
|
||||
emugl_cxt_logger(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#define GL_LOG(...) 0
|
||||
#endif
|
||||
64
external/android-emugl/shared/emugl/common/message_channel.cpp
vendored
Normal file
64
external/android-emugl/shared/emugl/common/message_channel.cpp
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2014 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 "emugl/common/message_channel.h"
|
||||
|
||||
namespace emugl {
|
||||
|
||||
MessageChannelBase::MessageChannelBase(size_t capacity) :
|
||||
mPos(0U),
|
||||
mCount(0U),
|
||||
mCapacity(capacity),
|
||||
mLock(),
|
||||
mCanRead(),
|
||||
mCanWrite() {}
|
||||
|
||||
MessageChannelBase::~MessageChannelBase() {}
|
||||
|
||||
size_t MessageChannelBase::beforeWrite() {
|
||||
mLock.lock();
|
||||
while (mCount >= mCapacity) {
|
||||
mCanWrite.wait(&mLock);
|
||||
}
|
||||
size_t result = mPos + mCount;
|
||||
if (result >= mCapacity) {
|
||||
result -= mCapacity;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MessageChannelBase::afterWrite() {
|
||||
mCount++;
|
||||
mCanRead.signal();
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
size_t MessageChannelBase::beforeRead() {
|
||||
mLock.lock();
|
||||
while (mCount == 0) {
|
||||
mCanRead.wait(&mLock);
|
||||
}
|
||||
return mPos;
|
||||
}
|
||||
|
||||
void MessageChannelBase::afterRead() {
|
||||
if (++mPos == mCapacity) {
|
||||
mPos = 0U;
|
||||
}
|
||||
mCount--;
|
||||
mCanWrite.signal();
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
98
external/android-emugl/shared/emugl/common/message_channel.h
vendored
Normal file
98
external/android-emugl/shared/emugl/common/message_channel.h
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_MESSAGE_CHANNEL_H
|
||||
#define EMUGL_COMMON_MESSAGE_CHANNEL_H
|
||||
|
||||
#include "emugl/common/condition_variable.h"
|
||||
#include "emugl/common/mutex.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// Base non-templated class used to reduce the amount of template
|
||||
// specialization.
|
||||
class MessageChannelBase {
|
||||
public:
|
||||
// Constructor. |capacity| is the buffer capacity in messages.
|
||||
MessageChannelBase(size_t capacity);
|
||||
|
||||
// Destructor.
|
||||
~MessageChannelBase();
|
||||
|
||||
protected:
|
||||
// Call this method in the sender thread before writing a new message.
|
||||
// This returns the position of the available slot in the message array
|
||||
// where to copy the new fixed-size message. After the copy, call
|
||||
// afterWrite().
|
||||
size_t beforeWrite();
|
||||
|
||||
// To be called after beforeWrite() and copying a new fixed-size message
|
||||
// into the array. This signal the receiver thread that there is a new
|
||||
// incoming message.
|
||||
void afterWrite();
|
||||
|
||||
// Call this method in the receiver thread before reading a new message.
|
||||
// This returns the position in the message array where the new message
|
||||
// can be read. Caller must process the message, then call afterRead().
|
||||
size_t beforeRead();
|
||||
|
||||
// To be called in the receiver thread after beforeRead() and processing
|
||||
// the corresponding message.
|
||||
void afterRead();
|
||||
|
||||
private:
|
||||
size_t mPos;
|
||||
size_t mCount;
|
||||
size_t mCapacity;
|
||||
Mutex mLock;
|
||||
ConditionVariable mCanRead;
|
||||
ConditionVariable mCanWrite;
|
||||
};
|
||||
|
||||
// Helper class used to implement an uni-directional IPC channel between
|
||||
// two threads. The channel can be used to send fixed-size messages of type
|
||||
// |T|, with an internal buffer size of |CAPACITY| items. All calls are
|
||||
// blocking.
|
||||
//
|
||||
// Usage is pretty straightforward:
|
||||
//
|
||||
// - From the sender thread, call send(msg);
|
||||
// - From the receiver thread, call receive(&msg);
|
||||
//
|
||||
template <typename T, size_t CAPACITY>
|
||||
class MessageChannel : public MessageChannelBase {
|
||||
public:
|
||||
MessageChannel() : MessageChannelBase(CAPACITY) {}
|
||||
|
||||
void send(const T& msg) {
|
||||
size_t pos = beforeWrite();
|
||||
mItems[pos] = msg;
|
||||
afterWrite();
|
||||
}
|
||||
|
||||
void receive(T* msg) {
|
||||
size_t pos = beforeRead();
|
||||
*msg = mItems[pos];
|
||||
afterRead();
|
||||
}
|
||||
|
||||
private:
|
||||
T mItems[CAPACITY];
|
||||
};
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_COMMON_MESSAGE_CHANNEL_H
|
||||
101
external/android-emugl/shared/emugl/common/message_channel_unittest.cpp
vendored
Normal file
101
external/android-emugl/shared/emugl/common/message_channel_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright 2014 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 "emugl/common/message_channel.h"
|
||||
|
||||
#include "emugl/common/testing/test_thread.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
struct PingPongState {
|
||||
MessageChannel<std::string, 3U> in;
|
||||
MessageChannel<std::string, 3U> out;
|
||||
};
|
||||
|
||||
void* pingPongFunction(void* param) {
|
||||
for (;;) {
|
||||
PingPongState* s = static_cast<PingPongState*>(param);
|
||||
std::string str;
|
||||
s->in.receive(&str);
|
||||
s->out.send(str);
|
||||
if (str == "quit") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(MessageChannel, SingleThreadWithInt) {
|
||||
MessageChannel<int, 3U> channel;
|
||||
channel.send(1);
|
||||
channel.send(2);
|
||||
channel.send(3);
|
||||
|
||||
int ret;
|
||||
channel.receive(&ret);
|
||||
EXPECT_EQ(1, ret);
|
||||
channel.receive(&ret);
|
||||
EXPECT_EQ(2, ret);
|
||||
channel.receive(&ret);
|
||||
EXPECT_EQ(3, ret);
|
||||
}
|
||||
|
||||
TEST(MessageChannel, SingleThreadWithStdString) {
|
||||
MessageChannel<std::string, 5U> channel;
|
||||
channel.send(std::string("foo"));
|
||||
channel.send(std::string("bar"));
|
||||
channel.send(std::string("zoo"));
|
||||
|
||||
std::string str;
|
||||
channel.receive(&str);
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
channel.receive(&str);
|
||||
EXPECT_STREQ("bar", str.c_str());
|
||||
channel.receive(&str);
|
||||
EXPECT_STREQ("zoo", str.c_str());
|
||||
}
|
||||
|
||||
TEST(MessageChannel, TwoThreadsPingPong) {
|
||||
PingPongState state;
|
||||
TestThread* thread = new TestThread(pingPongFunction, &state);
|
||||
|
||||
std::string str;
|
||||
const size_t kCount = 100;
|
||||
for (size_t n = 0; n < kCount; ++n) {
|
||||
state.in.send(std::string("foo"));
|
||||
state.in.send(std::string("bar"));
|
||||
state.in.send(std::string("zoo"));
|
||||
state.out.receive(&str);
|
||||
EXPECT_STREQ("foo", str.c_str());
|
||||
state.out.receive(&str);
|
||||
EXPECT_STREQ("bar", str.c_str());
|
||||
state.out.receive(&str);
|
||||
EXPECT_STREQ("zoo", str.c_str());
|
||||
}
|
||||
state.in.send(std::string("quit"));
|
||||
state.out.receive(&str);
|
||||
EXPECT_STREQ("quit", str.c_str());
|
||||
|
||||
thread->join();
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
95
external/android-emugl/shared/emugl/common/mutex.h
vendored
Normal file
95
external/android-emugl/shared/emugl/common/mutex.h
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_MUTEX_H
|
||||
#define EMUGL_MUTEX_H
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN 1
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
|
||||
class ConditionVariable;
|
||||
|
||||
// Simple wrapper class for mutexes.
|
||||
class Mutex {
|
||||
public:
|
||||
// Constructor.
|
||||
Mutex() {
|
||||
#ifdef _WIN32
|
||||
::InitializeCriticalSection(&mLock);
|
||||
#else
|
||||
::pthread_mutex_init(&mLock, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Destructor.
|
||||
~Mutex() {
|
||||
#ifdef _WIN32
|
||||
::DeleteCriticalSection(&mLock);
|
||||
#else
|
||||
::pthread_mutex_destroy(&mLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Acquire the mutex.
|
||||
void lock() {
|
||||
#ifdef _WIN32
|
||||
::EnterCriticalSection(&mLock);
|
||||
#else
|
||||
::pthread_mutex_lock(&mLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Release the mutex.
|
||||
void unlock() {
|
||||
#ifdef _WIN32
|
||||
::LeaveCriticalSection(&mLock);
|
||||
#else
|
||||
::pthread_mutex_unlock(&mLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Helper class to lock / unlock a mutex automatically on scope
|
||||
// entry and exit.
|
||||
class AutoLock {
|
||||
public:
|
||||
AutoLock(Mutex& mutex) : mMutex(&mutex) {
|
||||
mMutex->lock();
|
||||
}
|
||||
|
||||
~AutoLock() {
|
||||
mMutex->unlock();
|
||||
}
|
||||
private:
|
||||
Mutex* mMutex;
|
||||
};
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
CRITICAL_SECTION mLock;
|
||||
#else
|
||||
friend class ConditionVariable;
|
||||
pthread_mutex_t mLock;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_MUTEX_H
|
||||
108
external/android-emugl/shared/emugl/common/mutex_unittest.cpp
vendored
Normal file
108
external/android-emugl/shared/emugl/common/mutex_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/mutex.h"
|
||||
|
||||
#include "emugl/common/testing/test_thread.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// Check that construction and destruction doesn't crash.
|
||||
TEST(Mutex, ConstructionDestruction) {
|
||||
Mutex lock;
|
||||
}
|
||||
|
||||
// Check that a simple lock + unlock works.
|
||||
TEST(Mutex, LockUnlock) {
|
||||
Mutex lock;
|
||||
lock.lock();
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
// Check that AutoLock compiles and doesn't crash.
|
||||
TEST(Mutex, AutoLock) {
|
||||
Mutex mutex;
|
||||
Mutex::AutoLock lock(mutex);
|
||||
}
|
||||
|
||||
// Wrapper class for threads. Does not use emugl::Thread intentionally.
|
||||
// Common data type used by the following tests below.
|
||||
struct ThreadParams {
|
||||
ThreadParams() : mutex(), counter(0) {}
|
||||
|
||||
Mutex mutex;
|
||||
int counter;
|
||||
};
|
||||
|
||||
// This thread function uses Mutex::lock/unlock to synchronize a counter
|
||||
// increment operation.
|
||||
static void* threadFunction(void* param) {
|
||||
ThreadParams* p = static_cast<ThreadParams*>(param);
|
||||
|
||||
p->mutex.lock();
|
||||
p->counter++;
|
||||
p->mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TEST(Mutex, Synchronization) {
|
||||
const size_t kNumThreads = 2000;
|
||||
TestThread* threads[kNumThreads];
|
||||
ThreadParams p;
|
||||
|
||||
// Create and launch all threads.
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
threads[n] = new TestThread(threadFunction, &p);
|
||||
}
|
||||
|
||||
// Wait until their completion.
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
threads[n]->join();
|
||||
delete threads[n];
|
||||
}
|
||||
|
||||
EXPECT_EQ(static_cast<int>(kNumThreads), p.counter);
|
||||
}
|
||||
|
||||
// This thread function uses a Mutex::AutoLock to protect the counter.
|
||||
static void* threadAutoLockFunction(void* param) {
|
||||
ThreadParams* p = static_cast<ThreadParams*>(param);
|
||||
|
||||
Mutex::AutoLock lock(p->mutex);
|
||||
p->counter++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TEST(Mutex, AutoLockSynchronization) {
|
||||
const size_t kNumThreads = 2000;
|
||||
TestThread* threads[kNumThreads];
|
||||
ThreadParams p;
|
||||
|
||||
// Create and launch all threads.
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
threads[n] = new TestThread(threadAutoLockFunction, &p);
|
||||
}
|
||||
|
||||
// Wait until their completion.
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
threads[n]->join();
|
||||
delete threads[n];
|
||||
}
|
||||
|
||||
EXPECT_EQ(static_cast<int>(kNumThreads), p.counter);
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
150
external/android-emugl/shared/emugl/common/pod_vector.cpp
vendored
Normal file
150
external/android-emugl/shared/emugl/common/pod_vector.cpp
vendored
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/pod_vector.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define USE_MALLOC_USABLE_SIZE 0
|
||||
|
||||
namespace emugl {
|
||||
|
||||
static inline void swapPointers(char** p1, char** p2) {
|
||||
char* tmp = *p1;
|
||||
*p1 = *p2;
|
||||
*p2 = tmp;
|
||||
}
|
||||
|
||||
PodVectorBase::PodVectorBase(const PodVectorBase& other) {
|
||||
initFrom(other.begin(), other.byteSize());
|
||||
}
|
||||
|
||||
PodVectorBase& PodVectorBase::operator=(const PodVectorBase& other) {
|
||||
initFrom(other.begin(), other.byteSize());
|
||||
return *this;
|
||||
}
|
||||
|
||||
PodVectorBase::~PodVectorBase() {
|
||||
if (mBegin) {
|
||||
// Sanity.
|
||||
::memset(mBegin, 0xee, byteSize());
|
||||
::free(mBegin);
|
||||
mBegin = NULL;
|
||||
mEnd = NULL;
|
||||
mLimit = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void PodVectorBase::initFrom(const void* from, size_t fromLen) {
|
||||
if (!fromLen || !from) {
|
||||
mBegin = NULL;
|
||||
mEnd = NULL;
|
||||
mLimit = NULL;
|
||||
} else {
|
||||
mBegin = static_cast<char*>(::malloc(fromLen));
|
||||
mEnd = mLimit = mBegin + fromLen;
|
||||
::memcpy(mBegin, from, fromLen);
|
||||
}
|
||||
}
|
||||
|
||||
void PodVectorBase::assignFrom(const PodVectorBase& other) {
|
||||
resize(other.byteSize(), 1U);
|
||||
::memmove(begin(), other.begin(), byteSize());
|
||||
}
|
||||
|
||||
void PodVectorBase::resize(size_t newSize, size_t itemSize) {
|
||||
const size_t kMaxSize = maxItemCapacity(itemSize);
|
||||
size_t oldCapacity = itemCapacity(itemSize);
|
||||
const size_t kMinCapacity = 256 / itemSize;
|
||||
|
||||
if (newSize < oldCapacity) {
|
||||
// Only shrink if the new size is really small.
|
||||
if (newSize < oldCapacity / 2 && oldCapacity > kMinCapacity) {
|
||||
reserve(newSize, itemSize);
|
||||
}
|
||||
} else if (newSize > oldCapacity) {
|
||||
size_t newCapacity = oldCapacity;
|
||||
while (newCapacity < newSize) {
|
||||
size_t newCapacity2 = newCapacity + (newCapacity >> 2) + 8;
|
||||
if (newCapacity2 < newCapacity || newCapacity > kMaxSize) {
|
||||
newCapacity = kMaxSize;
|
||||
} else {
|
||||
newCapacity = newCapacity2;
|
||||
}
|
||||
}
|
||||
reserve(newCapacity, itemSize);
|
||||
}
|
||||
mEnd = mBegin + newSize * itemSize;
|
||||
}
|
||||
|
||||
void PodVectorBase::reserve(size_t newSize, size_t itemSize) {
|
||||
if (newSize == 0) {
|
||||
::free(mBegin);
|
||||
mBegin = NULL;
|
||||
mEnd = NULL;
|
||||
mLimit = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t oldByteSize = byteSize();
|
||||
size_t newByteCapacity = newSize * itemSize;
|
||||
char* newBegin = static_cast<char*>(::realloc(mBegin, newByteCapacity));
|
||||
mBegin = newBegin;
|
||||
mEnd = newBegin + oldByteSize;
|
||||
#if USE_MALLOC_USABLE_SIZE
|
||||
size_t usableSize = malloc_usable_size(mBegin);
|
||||
if (usableSize > newByteCapacity) {
|
||||
newByteCapacity = usableSize - (usableSize % itemSize);
|
||||
}
|
||||
#endif
|
||||
mLimit = newBegin + newByteCapacity;
|
||||
// Sanity.
|
||||
if (newByteCapacity > oldByteSize) {
|
||||
::memset(mBegin + oldByteSize, 0, newByteCapacity - oldByteSize);
|
||||
}
|
||||
}
|
||||
|
||||
void PodVectorBase::removeAt(size_t itemPos, size_t itemSize) {
|
||||
size_t count = itemCount(itemSize);
|
||||
if (itemPos < count) {
|
||||
size_t pos = itemPos * itemSize;
|
||||
::memmove(mBegin + pos,
|
||||
mBegin + pos + itemSize,
|
||||
byteSize() - pos - itemSize);
|
||||
resize(count - 1U, itemSize);
|
||||
}
|
||||
}
|
||||
|
||||
void* PodVectorBase::insertAt(size_t itemPos, size_t itemSize) {
|
||||
size_t count = this->itemCount(itemSize);
|
||||
resize(count + 1, itemSize);
|
||||
size_t pos = itemPos * itemSize;
|
||||
if (itemPos < count) {
|
||||
::memmove(mBegin + pos + itemSize,
|
||||
mBegin + pos,
|
||||
count * itemSize - pos);
|
||||
// Sanity to avoid copying pointers and other bad stuff.
|
||||
::memset(mBegin + pos, 0, itemSize);
|
||||
}
|
||||
return mBegin + pos;
|
||||
}
|
||||
|
||||
void PodVectorBase::swapAll(PodVectorBase* other) {
|
||||
swapPointers(&mBegin, &other->mBegin);
|
||||
swapPointers(&mEnd, &other->mEnd);
|
||||
swapPointers(&mLimit, &other->mLimit);
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
265
external/android-emugl/shared/emugl/common/pod_vector.h
vendored
Normal file
265
external/android-emugl/shared/emugl/common/pod_vector.h
vendored
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_POD_VECTOR_H
|
||||
#define EMUGL_COMMON_POD_VECTOR_H
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
#define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS 1
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#error "You must define __STDC_LIMIT_MACROS before including <stddint.h>"
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// A PodVector is a templated vector-like type that is used to store
|
||||
// POD-struct compatible items only. This allows the implementation to
|
||||
// use ::memmove() to move items, and also malloc_usable_size() to
|
||||
// determine the best capacity.
|
||||
//
|
||||
// std::vector<> is capable of doing this in theory, using horrible
|
||||
// templating tricks that make error messages very difficult to
|
||||
// understand.
|
||||
//
|
||||
// Note that a PodVector can be used to store items that contain pointers,
|
||||
// as long as these do not point to items in the same container.
|
||||
//
|
||||
// The PodVector provides methods that also follow the std::vector<>
|
||||
// conventions, i.e. push_back() is an alias for append().
|
||||
//
|
||||
|
||||
// NOTE: This is a re-implementation of
|
||||
// external/qemu/android/base/containers/PodVector.h for emugl.
|
||||
|
||||
// PodVectorBase is a base, non-templated, implementation class that all
|
||||
// PodVector instances derive from. This is used to reduce template
|
||||
// specialization. Do not use directly, i..e it's an implementation detail.
|
||||
class PodVectorBase {
|
||||
protected:
|
||||
PodVectorBase() : mBegin(NULL), mEnd(NULL), mLimit(NULL) {}
|
||||
explicit PodVectorBase(const PodVectorBase& other);
|
||||
PodVectorBase& operator=(const PodVectorBase& other);
|
||||
~PodVectorBase();
|
||||
|
||||
bool empty() const { return mEnd == mBegin; }
|
||||
|
||||
size_t byteSize() const { return mEnd - mBegin; }
|
||||
|
||||
size_t byteCapacity() const { return mLimit - mBegin; }
|
||||
|
||||
void* begin() { return mBegin; }
|
||||
const void* begin() const { return mBegin; }
|
||||
void* end() { return mEnd; }
|
||||
const void* end() const { return mEnd; }
|
||||
|
||||
void* itemAt(size_t pos, size_t itemSize) {
|
||||
return mBegin + pos * itemSize;
|
||||
}
|
||||
|
||||
const void* itemAt(size_t pos, size_t itemSize) const {
|
||||
return mBegin + pos * itemSize;
|
||||
}
|
||||
|
||||
void assignFrom(const PodVectorBase& other);
|
||||
|
||||
inline size_t itemCount(size_t itemSize) const {
|
||||
return byteSize() / itemSize;
|
||||
}
|
||||
|
||||
inline size_t itemCapacity(size_t itemSize) const {
|
||||
return byteCapacity() / itemSize;
|
||||
}
|
||||
|
||||
inline size_t maxItemCapacity(size_t itemSize) const {
|
||||
return SIZE_MAX / itemSize;
|
||||
}
|
||||
|
||||
void resize(size_t newSize, size_t itemSize);
|
||||
void reserve(size_t newSize, size_t itemSize);
|
||||
|
||||
void removeAt(size_t index, size_t itemSize);
|
||||
void* insertAt(size_t index, size_t itemSize);
|
||||
void swapAll(PodVectorBase* other);
|
||||
|
||||
char* mBegin;
|
||||
char* mEnd;
|
||||
char* mLimit;
|
||||
|
||||
private:
|
||||
void initFrom(const void* from, size_t fromLen);
|
||||
};
|
||||
|
||||
|
||||
// A PodVector<T> holds a vector (dynamically resizable array) or items
|
||||
// that must be POD-struct compatible (i.e. they cannot have constructors,
|
||||
// destructors, or virtual members). This allows the implementation to be
|
||||
// small, fast and efficient, memory-wise.
|
||||
//
|
||||
// If you want to implement a vector of C++ objects, consider using
|
||||
// std::vector<> instead, but keep in mind that this implies a non-trivial
|
||||
// cost when appending, inserting, removing items in the collection.
|
||||
//
|
||||
template <typename T>
|
||||
class PodVector : public PodVectorBase {
|
||||
public:
|
||||
// Default constructor for an empty PodVector<T>
|
||||
PodVector() : PodVectorBase() {}
|
||||
|
||||
// Copy constructor. This copies all items from |other| into
|
||||
// the new instance with ::memmove().
|
||||
PodVector(const PodVector& other) : PodVectorBase(other) {}
|
||||
|
||||
// Assignment operator.
|
||||
PodVector& operator=(const PodVector& other) {
|
||||
this->assignFrom(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Destructor, this simply releases the internal storage block that
|
||||
// holds all the items, but doesn't touch them otherwise.
|
||||
~PodVector() {}
|
||||
|
||||
// Return true iff the PodVector<T> instance is empty, i.e. does not
|
||||
// have any items.
|
||||
bool empty() const { return PodVectorBase::empty(); }
|
||||
|
||||
// Return the number of items in the current PodVector<T> instance.
|
||||
size_t size() const { return PodVectorBase::itemCount(sizeof(T)); }
|
||||
|
||||
// Return the current capacity in the current PodVector<T> instance.
|
||||
// Do not use directly, except if you know what you're doing. Try to
|
||||
// use resize() or reserve() instead.
|
||||
size_t capacity() const {
|
||||
return PodVectorBase::itemCapacity(sizeof(T));
|
||||
}
|
||||
|
||||
// Return the maximum capacity of any PodVector<T> instance.
|
||||
static inline size_t maxCapacity() { return SIZE_MAX / sizeof(T); }
|
||||
|
||||
// Resize the vector to ensure it can hold |newSize|
|
||||
// items. This may or may not call reserve() under the hood.
|
||||
// It's a fatal error to try to resize above maxCapacity().
|
||||
void resize(size_t newSize) {
|
||||
PodVectorBase::resize(newSize, sizeof(T));
|
||||
}
|
||||
|
||||
// Resize the vector's storage array to ensure that it can hold at
|
||||
// least |newSize| items. It's a fatal error to try to resize above
|
||||
// maxCapacity().
|
||||
void reserve(size_t newSize) {
|
||||
PodVectorBase::reserve(newSize, sizeof(T));
|
||||
}
|
||||
|
||||
// Return a pointer to the first item in the vector. This is only
|
||||
// valid until the next call to any function that changes the size
|
||||
// or capacity of the vector. Can be NULL if the vector is empty.
|
||||
T* begin() {
|
||||
return reinterpret_cast<T*>(PodVectorBase::begin());
|
||||
}
|
||||
|
||||
// Return a constant pointer to the first item in the vector. This is
|
||||
// only valid until the next call to any function that changes the
|
||||
// size of capacity of the vector.
|
||||
const T* begin() const {
|
||||
return reinterpret_cast<T*>(PodVectorBase::begin());
|
||||
}
|
||||
|
||||
// Return a pointer past the last item in the vector. I.e. if the
|
||||
// result is not NULL, then |result - 1| points to the last item.
|
||||
// Can be NULL if the vector is empty.
|
||||
T* end() {
|
||||
return reinterpret_cast<T*>(PodVectorBase::end());
|
||||
}
|
||||
|
||||
// Return a constant pointer past the last item in the vector. I.e. if
|
||||
// the result is not NULL, then |result - 1| points to the last item.
|
||||
// Can be NULL if the vector is empty.
|
||||
const T* end() const {
|
||||
return reinterpret_cast<T*>(PodVectorBase::end());
|
||||
}
|
||||
|
||||
// Returns a reference to the item a position |index| in the vector.
|
||||
// It may be a fatal error to access an out-of-bounds position.
|
||||
T& operator[](size_t index) {
|
||||
return *reinterpret_cast<T*>(
|
||||
PodVectorBase::itemAt(index, sizeof(T)));
|
||||
}
|
||||
|
||||
const T& operator[](size_t index) const {
|
||||
return *reinterpret_cast<const T*>(
|
||||
PodVectorBase::itemAt(index, sizeof(T)));
|
||||
}
|
||||
|
||||
// Increase the vector's size by 1, then move all items past a given
|
||||
// position to the right. Return the position of the insertion point
|
||||
// to let the caller copy the content it desires there. It's preferrable
|
||||
// to use insert() directly, which will do the item copy for you.
|
||||
T* emplace(size_t index) {
|
||||
return reinterpret_cast<T*>(
|
||||
PodVectorBase::insertAt(index, sizeof(T)));
|
||||
}
|
||||
|
||||
// Insert an item at a given position. |index| is the insertion position
|
||||
// which must be between 0 and size() included, or a fatal error may
|
||||
// occur. |item| is a reference to an item to copy into the array,
|
||||
// byte-by-byte.
|
||||
void insert(size_t index, const T& item) {
|
||||
*(this->emplace(index)) = item;
|
||||
}
|
||||
|
||||
// Prepend an item at the start of a vector. This moves all vector items
|
||||
// to the right, and is thus costly. |item| is a reference to an item
|
||||
// to copy to the start of the vector.
|
||||
void prepend(const T& item) {
|
||||
*(this->emplace(0U)) = item;
|
||||
}
|
||||
|
||||
// Append an item at the end of a vector. Specialized version of insert()
|
||||
// which always uses size() as the insertion position.
|
||||
void append(const T& item) {
|
||||
*(this->emplace(this->size())) = item;
|
||||
}
|
||||
|
||||
// Remove the item at a given position. |index| is the position of the
|
||||
// item to delete. It must be between 0 and size(), included, or
|
||||
// a fatal error may occur. Deleting the item at position size()
|
||||
// doesn't do anything.
|
||||
void remove(size_t index) {
|
||||
PodVectorBase::removeAt(index, sizeof(T));
|
||||
}
|
||||
|
||||
void swap(PodVector* other) {
|
||||
PodVectorBase::swapAll(other);
|
||||
}
|
||||
|
||||
// Compatibility methods for std::vector<>
|
||||
void push_back(const T& item) { append(item); }
|
||||
void pop() { remove(0U); }
|
||||
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
};
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_COMMON_POD_VECTOR_H
|
||||
127
external/android-emugl/shared/emugl/common/pod_vector_unittest.cpp
vendored
Normal file
127
external/android-emugl/shared/emugl/common/pod_vector_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/pod_vector.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
static int hashIndex(size_t n) {
|
||||
return static_cast<int>(((n >> 14) * 13773) + (n * 51));
|
||||
}
|
||||
|
||||
TEST(PodVector, Empty) {
|
||||
PodVector<int> v;
|
||||
EXPECT_TRUE(v.empty());
|
||||
EXPECT_EQ(0U, v.size());
|
||||
}
|
||||
|
||||
TEST(PodVector, AppendOneItem) {
|
||||
PodVector<int> v;
|
||||
v.append(10234);
|
||||
EXPECT_FALSE(v.empty());
|
||||
EXPECT_EQ(1U, v.size());
|
||||
EXPECT_EQ(10234, v[0]);
|
||||
}
|
||||
|
||||
TEST(PodVector, AppendLotsOfItems) {
|
||||
PodVector<int> v;
|
||||
const size_t kMaxCount = 10000;
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
v.append(hashIndex(n));
|
||||
}
|
||||
EXPECT_EQ(kMaxCount, v.size());
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
EXPECT_EQ(hashIndex(n), v[n]) << "At index " << n;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PodVector, RemoveFrontItems) {
|
||||
PodVector<int> v;
|
||||
const size_t kMaxCount = 100;
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
v.append(hashIndex(n));
|
||||
}
|
||||
EXPECT_EQ(kMaxCount, v.size());
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
EXPECT_EQ(hashIndex(n), v[0]) << "At index " << n;
|
||||
v.remove(0U);
|
||||
EXPECT_EQ(kMaxCount - n - 1U, v.size()) << "At index " << n;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PodVector, PrependItems) {
|
||||
PodVector<int> v;
|
||||
const size_t kMaxCount = 100;
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
v.prepend(hashIndex(n));
|
||||
}
|
||||
EXPECT_EQ(kMaxCount, v.size());
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
EXPECT_EQ(hashIndex(kMaxCount - n - 1), v[n]) << "At index " << n;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PodVector, ResizeExpands) {
|
||||
PodVector<int> v;
|
||||
const size_t kMaxCount = 100;
|
||||
const size_t kMaxCount2 = 10000;
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
v.append(hashIndex(n));
|
||||
}
|
||||
EXPECT_EQ(kMaxCount, v.size());
|
||||
v.resize(kMaxCount2);
|
||||
EXPECT_EQ(kMaxCount2, v.size());
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
EXPECT_EQ(hashIndex(n), v[n]) << "At index " << n;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PodVector, ResizeTruncates) {
|
||||
PodVector<int> v;
|
||||
const size_t kMaxCount = 10000;
|
||||
const size_t kMaxCount2 = 10;
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
v.append(hashIndex(n));
|
||||
}
|
||||
EXPECT_EQ(kMaxCount, v.size());
|
||||
v.resize(kMaxCount2);
|
||||
EXPECT_EQ(kMaxCount2, v.size());
|
||||
for (size_t n = 0; n < kMaxCount2; ++n) {
|
||||
EXPECT_EQ(hashIndex(n), v[n]) << "At index " << n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(PodVector, AssignmentOperator) {
|
||||
PodVector<int> v1;
|
||||
const size_t kMaxCount = 10000;
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
v1.append(hashIndex(n));
|
||||
}
|
||||
EXPECT_EQ(kMaxCount, v1.size());
|
||||
|
||||
PodVector<int> v2;
|
||||
v2 = v1;
|
||||
|
||||
v1.reserve(0);
|
||||
|
||||
EXPECT_EQ(kMaxCount, v2.size());
|
||||
for (size_t n = 0; n < kMaxCount; ++n) {
|
||||
EXPECT_EQ(hashIndex(n), v2[n]) << "At index " << n;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
27
external/android-emugl/shared/emugl/common/scoped_pointer_vector.h
vendored
Normal file
27
external/android-emugl/shared/emugl/common/scoped_pointer_vector.h
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_SCOPED_POINTER_VECTOR_H
|
||||
#define EMUGL_COMMON_SCOPED_POINTER_VECTOR_H
|
||||
|
||||
namespace emugl {
|
||||
|
||||
template <class T>
|
||||
class ScopedPointerVector {
|
||||
ScopedPointerVector
|
||||
};
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_COMMON_SCOPED_POINTER_VECTOR_H
|
||||
169
external/android-emugl/shared/emugl/common/shared_library.cpp
vendored
Normal file
169
external/android-emugl/shared/emugl/common/shared_library.cpp
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/shared_library.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// static
|
||||
SharedLibrary* SharedLibrary::open(const char* libraryName) {
|
||||
char error[1];
|
||||
return open(libraryName, error, sizeof(error));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// static
|
||||
SharedLibrary* SharedLibrary::open(const char* libraryName,
|
||||
char* error,
|
||||
size_t errorSize) {
|
||||
HMODULE lib = LoadLibrary(libraryName);
|
||||
if (lib) {
|
||||
return new SharedLibrary(lib);
|
||||
}
|
||||
|
||||
if (errorSize == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Convert error into human-readable message.
|
||||
DWORD errorCode = ::GetLastError();
|
||||
LPSTR message = NULL;
|
||||
size_t messageLen = FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
errorCode,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR) &message,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
int ret = snprintf(error, errorSize, "%.*s", (int)messageLen, message);
|
||||
if (ret < 0 || ret == static_cast<int>(errorSize)) {
|
||||
// snprintf() on Windows doesn't behave as expected by C99,
|
||||
// this path is to ensure that the result is always properly
|
||||
// zero-terminated.
|
||||
ret = static_cast<int>(errorSize - 1);
|
||||
error[ret] = '\0';
|
||||
}
|
||||
// Remove any trailing \r\n added by FormatMessage
|
||||
if (ret > 0 && error[ret - 1] == '\n') {
|
||||
error[--ret] = '\0';
|
||||
}
|
||||
if (ret > 0 && error[ret - 1] == '\r') {
|
||||
error[--ret] = '\0';
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {}
|
||||
|
||||
SharedLibrary::~SharedLibrary() {
|
||||
if (mLib) {
|
||||
FreeLibrary(mLib);
|
||||
}
|
||||
}
|
||||
|
||||
SharedLibrary::FunctionPtr SharedLibrary::findSymbol(
|
||||
const char* symbolName) const {
|
||||
if (!mLib || !symbolName) {
|
||||
return NULL;
|
||||
}
|
||||
return reinterpret_cast<FunctionPtr>(
|
||||
GetProcAddress(mLib, symbolName));
|
||||
}
|
||||
|
||||
#else // !_WIN32
|
||||
|
||||
// static
|
||||
SharedLibrary* SharedLibrary::open(const char* libraryName,
|
||||
char* error,
|
||||
size_t errorSize) {
|
||||
const char* libPath = libraryName;
|
||||
char* path = NULL;
|
||||
|
||||
const char* libBaseName = strrchr(libraryName, '/');
|
||||
if (!libBaseName) {
|
||||
libBaseName = libraryName;
|
||||
}
|
||||
|
||||
if (!strchr(libBaseName, '.')) {
|
||||
// There is no extension in this library name, so append one.
|
||||
#ifdef __APPLE__
|
||||
static const char kDllExtension[] = ".dylib";
|
||||
#else
|
||||
static const char kDllExtension[] = ".so";
|
||||
#endif
|
||||
size_t pathLen = strlen(libraryName) + sizeof(kDllExtension);
|
||||
path = static_cast<char*>(malloc(pathLen));
|
||||
snprintf(path, pathLen, "%s%s", libraryName, kDllExtension);
|
||||
libPath = path;
|
||||
}
|
||||
|
||||
dlerror(); // clear error.
|
||||
|
||||
#ifdef __APPLE__
|
||||
// On OSX, some libraries don't include an extension (notably OpenGL)
|
||||
// On OSX we try to open |libraryName| first. If that doesn't exist,
|
||||
// we try |libraryName|.dylib
|
||||
void* lib = dlopen(libraryName, RTLD_NOW);
|
||||
if (lib == NULL) {
|
||||
lib = dlopen(libPath, RTLD_NOW);
|
||||
}
|
||||
#else
|
||||
void* lib = dlopen(libPath, RTLD_NOW);
|
||||
#endif
|
||||
|
||||
if (path) {
|
||||
free(path);
|
||||
}
|
||||
|
||||
if (lib) {
|
||||
return new SharedLibrary(lib);
|
||||
}
|
||||
|
||||
snprintf(error, errorSize, "%s", dlerror());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {}
|
||||
|
||||
SharedLibrary::~SharedLibrary() {
|
||||
if (mLib) {
|
||||
dlclose(mLib);
|
||||
}
|
||||
}
|
||||
|
||||
SharedLibrary::FunctionPtr SharedLibrary::findSymbol(
|
||||
const char* symbolName) const {
|
||||
if (!mLib || !symbolName) {
|
||||
return NULL;
|
||||
}
|
||||
return reinterpret_cast<FunctionPtr>(dlsym(mLib, symbolName));
|
||||
}
|
||||
|
||||
#endif // !_WIN32
|
||||
|
||||
} // namespace emugl
|
||||
106
external/android-emugl/shared/emugl/common/shared_library.h
vendored
Normal file
106
external/android-emugl/shared/emugl/common/shared_library.h
vendored
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_SHARED_LIBRARY_H
|
||||
#define EMUGL_COMMON_SHARED_LIBRARY_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// A class used to open a platform-specific shared library, and probe
|
||||
// it for symbols. Usage is the following:
|
||||
//
|
||||
// // Open the library.
|
||||
// SharedLibrary* library = SharedLibrary::open("libFoo");
|
||||
// if (!library) {
|
||||
// ... could not find / open library!
|
||||
// }
|
||||
//
|
||||
// //Probe for function symbol.
|
||||
// FunctionPtr my_func = library->findSymbol("my_func");
|
||||
//
|
||||
// // Closes library/
|
||||
// delete library;
|
||||
//
|
||||
class SharedLibrary {
|
||||
public:
|
||||
// Open a given library. If |libraryName| has no extension, a
|
||||
// platform-appropriate extension is added and that path is opened.
|
||||
// If the |libraryName| has an extension, that form is opened.
|
||||
//
|
||||
// On OSX, some libraries don't include an extension (notably OpenGL)
|
||||
// On OSX we try to open |libraryName| first. If that doesn't exist,
|
||||
// we try |libraryName|.dylib
|
||||
//
|
||||
// On success, returns a new SharedLibrary instance that must be
|
||||
// deleted by the caller.
|
||||
static SharedLibrary* open(const char* libraryName);
|
||||
|
||||
// A variant of open() that can report a human-readable error if loading
|
||||
// the library fails. |error| is a caller-provided buffer of |errorSize|
|
||||
// bytes that will be filled with snprintf() and always zero terminated.
|
||||
//
|
||||
// On success, return a new SharedLibrary instance, and do not touch
|
||||
// the content of |error|. On failure, return NULL, and sets the content
|
||||
// of |error|.
|
||||
static SharedLibrary* open(const char* libraryName,
|
||||
char* error,
|
||||
size_t errorSize);
|
||||
|
||||
// Closes an existing SharedLibrary instance.
|
||||
~SharedLibrary();
|
||||
|
||||
// Generic function pointer type, for values returned by the
|
||||
// findSymbol() method.
|
||||
typedef void (*FunctionPtr)(void);
|
||||
|
||||
// Probe a given SharedLibrary instance to find a symbol named
|
||||
// |symbolName| in it. Return its address as a FunctionPtr, or
|
||||
// NULL if the symbol is not found.
|
||||
FunctionPtr findSymbol(const char* symbolName) const;
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
typedef HMODULE HandleType;
|
||||
#else
|
||||
typedef void* HandleType;
|
||||
#endif
|
||||
|
||||
// Constructor intentionally hidden.
|
||||
SharedLibrary(HandleType);
|
||||
|
||||
HandleType mLib;
|
||||
};
|
||||
|
||||
// Macro to compose emugl shared library name under various OS and bitness
|
||||
// eg.
|
||||
// on x86_64, EMUGL_LIBNAME("foo") --> "lib64foo"
|
||||
|
||||
#if defined(__x86_64__)
|
||||
# define EMUGL_LIBNAME(name) "lib64" name
|
||||
#elif defined(__i386__)
|
||||
# define EMUGL_LIBNAME(name) "lib" name
|
||||
#else
|
||||
/* This header is included by target w/o using EMUGL_LIBNAME(). Don't #error, leave it undefined */
|
||||
# define EMUGL_LIBNAME(name) "lib" name
|
||||
#endif
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_COMMON_SHARED_LIBRARY_H
|
||||
177
external/android-emugl/shared/emugl/common/shared_library_unittest.cpp
vendored
Normal file
177
external/android-emugl/shared/emugl/common/shared_library_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/shared_library.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
// Hack to get the current executable's full path.
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
extern std::string g_executable_path;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
// Return the name/path of the test shared library to load.
|
||||
// Note that this doesn't include a platform-specific extension.
|
||||
// This assumes that the test shared library is under the lib/ sub-directory
|
||||
// of the current executable's path!
|
||||
std::string GetTestLibraryName() {
|
||||
#ifdef __x86_64__
|
||||
static const char kLibraryPrefix[] = "lib64";
|
||||
static const char kSubDir[] = "lib64/";
|
||||
#else
|
||||
static const char kLibraryPrefix[] = "lib";
|
||||
static const char kSubDir[] = "lib/";
|
||||
#endif
|
||||
static const char kTestLibrarySuffix[] = "emugl_test_shared_library";
|
||||
|
||||
const char* exec_path = testing::internal::g_executable_path.c_str();
|
||||
|
||||
#ifdef _WIN32
|
||||
const char* p = strrchr(exec_path, '/');
|
||||
const char* p2 = strrchr(exec_path, '\\');
|
||||
if (p2) {
|
||||
if (!p || p2 > p) {
|
||||
p = p2;
|
||||
}
|
||||
}
|
||||
#else
|
||||
const char* p = strrchr(exec_path, '/');
|
||||
#endif
|
||||
|
||||
std::string path;
|
||||
|
||||
if (!p) {
|
||||
path = "./";
|
||||
} else {
|
||||
path = std::string(exec_path, p - exec_path + 1U);
|
||||
}
|
||||
path += kSubDir;
|
||||
path += kLibraryPrefix;
|
||||
path += kTestLibrarySuffix;
|
||||
printf("Library path: %s\n", path.c_str());
|
||||
return path;
|
||||
}
|
||||
|
||||
class SharedLibraryTest : public testing::Test {
|
||||
public:
|
||||
SharedLibraryTest() {
|
||||
// Locate the shared library
|
||||
mLibraryPath = GetTestLibraryName();
|
||||
}
|
||||
|
||||
~SharedLibraryTest() {}
|
||||
|
||||
const char* library_path() const { return mLibraryPath.c_str(); }
|
||||
|
||||
private:
|
||||
std::string mLibraryPath;
|
||||
};
|
||||
|
||||
class ScopedSharedLibrary {
|
||||
public:
|
||||
explicit ScopedSharedLibrary(const SharedLibrary* lib) : mLib(lib) {}
|
||||
~ScopedSharedLibrary() {
|
||||
delete mLib;
|
||||
}
|
||||
const SharedLibrary* get() const { return mLib; }
|
||||
|
||||
const SharedLibrary* operator->() { return mLib; }
|
||||
|
||||
void release() {
|
||||
delete mLib;
|
||||
mLib = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
const SharedLibrary* mLib;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(SharedLibraryTest, Open) {
|
||||
ScopedSharedLibrary lib(SharedLibrary::open(library_path()));
|
||||
EXPECT_TRUE(lib.get());
|
||||
}
|
||||
|
||||
TEST_F(SharedLibraryTest, OpenFailureWithError) {
|
||||
char error[256];
|
||||
error[0] = '\0';
|
||||
SharedLibrary* lib = SharedLibrary::open("/tmp/does/not/exists",
|
||||
error,
|
||||
sizeof(error));
|
||||
EXPECT_FALSE(lib);
|
||||
EXPECT_TRUE(error[0])
|
||||
<< "Could not get error string when failing to load library";
|
||||
printf("Expected library load failure: [%s]\n", error);
|
||||
}
|
||||
|
||||
TEST_F(SharedLibraryTest, OpenLibraryWithExtension) {
|
||||
std::string path = library_path();
|
||||
|
||||
// test extension append
|
||||
ScopedSharedLibrary libNoExtension(SharedLibrary::open(path.c_str()));
|
||||
EXPECT_TRUE(libNoExtension.get());
|
||||
libNoExtension.release();
|
||||
|
||||
#ifdef _WIN32
|
||||
path += ".dll";
|
||||
#elif defined(__APPLE__)
|
||||
// try to open the library without an extension
|
||||
|
||||
path += ".dylib";
|
||||
#else
|
||||
path += ".so";
|
||||
#endif
|
||||
|
||||
// test open with prepended extension
|
||||
ScopedSharedLibrary lib(SharedLibrary::open(path.c_str()));
|
||||
EXPECT_TRUE(lib.get());
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
TEST_F(SharedLibraryTest, OpenLibraryWithoutExtension) {
|
||||
const char* library = "/System/Library/Frameworks/OpenGL.framework/OpenGL";
|
||||
ScopedSharedLibrary lib(SharedLibrary::open(library));
|
||||
EXPECT_TRUE(lib.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(SharedLibraryTest, FindSymbol) {
|
||||
ScopedSharedLibrary lib(SharedLibrary::open(library_path()));
|
||||
EXPECT_TRUE(lib.get());
|
||||
|
||||
if (lib.get()) {
|
||||
typedef int (*FooFunction)(void);
|
||||
|
||||
FooFunction foo_func = reinterpret_cast<FooFunction>(
|
||||
lib->findSymbol("foo_function"));
|
||||
EXPECT_TRUE(foo_func);
|
||||
EXPECT_EQ(42, (*foo_func)());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
113
external/android-emugl/shared/emugl/common/smart_ptr.cpp
vendored
Normal file
113
external/android-emugl/shared/emugl/common/smart_ptr.cpp
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/smart_ptr.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// Thread-safe atomic reference-counting type.
|
||||
class RefCount {
|
||||
public:
|
||||
RefCount() : mCount(1) {}
|
||||
~RefCount() {}
|
||||
|
||||
// Technically not thread-safe, use only for testing.
|
||||
int count() const { return (int)mCount; }
|
||||
|
||||
void increment() {
|
||||
#ifdef _WIN32
|
||||
InterlockedIncrement(&mCount);
|
||||
#else
|
||||
__sync_fetch_and_add(&mCount, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool decrement() {
|
||||
#ifdef _WIN32
|
||||
return InterlockedDecrement(&mCount) == 0;
|
||||
#else
|
||||
return __sync_add_and_fetch(&mCount, -1) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
LONG mCount;
|
||||
#else
|
||||
int mCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// SmartPtrBase implementation.
|
||||
|
||||
SmartPtrBase::SmartPtrBase(void* ptr) : mPtr(ptr), mRefCount(NULL) {
|
||||
if (mPtr)
|
||||
mRefCount = new RefCount();
|
||||
}
|
||||
|
||||
|
||||
SmartPtrBase::SmartPtrBase(const SmartPtrBase& other)
|
||||
: mPtr(other.mPtr), mRefCount(other.mRefCount) {
|
||||
if (mRefCount)
|
||||
mRefCount->increment();
|
||||
}
|
||||
|
||||
|
||||
int SmartPtrBase::getRefCount() const {
|
||||
return mRefCount ? mRefCount->count() : 0;
|
||||
}
|
||||
|
||||
|
||||
void SmartPtrBase::addRef() {
|
||||
if (mRefCount)
|
||||
mRefCount->increment();
|
||||
}
|
||||
|
||||
|
||||
void* SmartPtrBase::copyFrom(const SmartPtrBase& other) {
|
||||
void* old_ptr = release();
|
||||
|
||||
mPtr = other.mPtr;
|
||||
mRefCount = other.mRefCount;
|
||||
if (mRefCount)
|
||||
mRefCount->increment();
|
||||
|
||||
return old_ptr;
|
||||
}
|
||||
|
||||
|
||||
void* SmartPtrBase::release() {
|
||||
void* old_ptr = mPtr;
|
||||
RefCount* old_refcount = mRefCount;
|
||||
|
||||
if (old_refcount) {
|
||||
mPtr = NULL;
|
||||
mRefCount = NULL;
|
||||
|
||||
if (old_refcount->decrement()) {
|
||||
delete old_refcount;
|
||||
return old_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
150
external/android-emugl/shared/emugl/common/smart_ptr.h
vendored
Normal file
150
external/android-emugl/shared/emugl/common/smart_ptr.h
vendored
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
// Copyright (C) 2014 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.
|
||||
#ifndef EMUGL_SMART_PTR_H
|
||||
#define EMUGL_SMART_PTR_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// Hidden atomic ref-counting implementation.
|
||||
class RefCount;
|
||||
|
||||
// Base class for all templated SmartPtr<> instances. Reduces
|
||||
// template expansion and code. Consider this to be an implementation
|
||||
// detail of SmartPtr<>, so don't rely on anything here.
|
||||
class SmartPtrBase {
|
||||
public:
|
||||
// Defrault constructor.
|
||||
SmartPtrBase() : mPtr(NULL), mRefCount(NULL) {}
|
||||
|
||||
// Normal constructor. This takes ownership of |ptr|, though only
|
||||
// template instances are capable of destroying the object.
|
||||
explicit SmartPtrBase(void* ptr);
|
||||
|
||||
// Copy-constructor, this increments the reference count.
|
||||
SmartPtrBase(const SmartPtrBase& other);
|
||||
|
||||
// Assignment operator, also increments the reference count.
|
||||
SmartPtrBase& operator=(const SmartPtrBase& other);
|
||||
|
||||
// Nothing happens in this destructor, the real work must be performed
|
||||
// in subclasses.
|
||||
~SmartPtrBase() {}
|
||||
|
||||
|
||||
// Used to enable 'if (smart_ptr) { ... }' properly.
|
||||
operator void*() const {
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
// Return internal reference count value, only use for unit testing.
|
||||
int getRefCount() const;
|
||||
|
||||
protected:
|
||||
// Used internally to increment the reference count.
|
||||
void addRef();
|
||||
|
||||
// Copy the |other| into this instance, returns the old pointer value
|
||||
// if it needs to be destroyed by the caller, or NULL otherwise.
|
||||
void* copyFrom(const SmartPtrBase& other);
|
||||
|
||||
// Used internally to decrement the reference count, if it reaches 0,
|
||||
// returns the pointer to be destroyed, NULL otherwise.
|
||||
void* release();
|
||||
|
||||
void* mPtr;
|
||||
RefCount* mRefCount;
|
||||
};
|
||||
|
||||
|
||||
// The real template class to be used for smart pointers.
|
||||
// Typical uses:
|
||||
//
|
||||
// SmartPtr<Foo> ptr(new Foo()); // takes ownership.
|
||||
// SmartPtr<Foo> ptr2; // empty pointer.
|
||||
// ptr2 = ptr; // copies pointer + increment reference count.
|
||||
// Foo* obj = ptr.Ptr(); // access pointed object.
|
||||
// ptr->DoStuff(); // operate directly on pointed object.
|
||||
// (*ptr)->DoStuff(); // same here.
|
||||
//
|
||||
// On scope exit, the internal reference count is decremented and the
|
||||
// object is deleted automatically when it reaches 0, indicating that
|
||||
// there are no more owners.
|
||||
//
|
||||
// IMPORTANT: You need to be sure that only one 'chain' of smart pointers
|
||||
// own a given object. I.e. the following is incorrect:
|
||||
//
|
||||
// Foo* foo = new Foo(); // create new instance.
|
||||
// SmartPtr<Foo> ptr(foo); // |ptr| takes ownership of |foo|.
|
||||
// SmartPtr<Foo> ptr2(foo); // |ptr2| takes also ownership of |foo|.
|
||||
//
|
||||
// The problem is that |ptr| and |ptr2| don't know anything about each
|
||||
// other, and will not share the same reference count. Once a smart pointer
|
||||
// owns an object, only use other smart pointers that are copy-constructed
|
||||
// or assigned with the initial one to keep everything consistent.
|
||||
template <class T>
|
||||
class SmartPtr : public emugl::SmartPtrBase {
|
||||
public:
|
||||
// Default constructor. The instance holds a NULL pointer.
|
||||
SmartPtr() : SmartPtrBase() {}
|
||||
|
||||
// Regular constructor, takes ownership of |ptr|.
|
||||
explicit SmartPtr(T* ptr) : SmartPtrBase(ptr) {}
|
||||
|
||||
// Copy-constructor, |this| and |other| will share the same internal
|
||||
// reference count, which is incremented by 1.
|
||||
SmartPtr(const SmartPtr& other)
|
||||
: SmartPtrBase(reinterpret_cast<const SmartPtrBase&>(other)) {}
|
||||
|
||||
// Assignment operator, same semantics as copy-constructor.
|
||||
SmartPtr& operator=(const SmartPtr& other) {
|
||||
void* old_ptr = copyFrom(static_cast<const SmartPtrBase&>(other));
|
||||
if (old_ptr)
|
||||
delete reinterpret_cast<T*>(old_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Destructor, decrements reference count and destroys the object
|
||||
// if it reaches 0 (indicating this was the last owning smart pointer).
|
||||
~SmartPtr() {
|
||||
void* ptr = release();
|
||||
if (ptr)
|
||||
delete reinterpret_cast<T*>(ptr);
|
||||
}
|
||||
|
||||
// Return owned object instance, or NULL.
|
||||
T* Ptr() const {
|
||||
return reinterpret_cast<T*>(mPtr);
|
||||
}
|
||||
|
||||
// Return owned object instance, or NULL
|
||||
const T* constPtr() const {
|
||||
return reinterpret_cast<const T*>(mPtr);
|
||||
}
|
||||
|
||||
// Operate directly on owned object.
|
||||
T* operator->() const {
|
||||
return Ptr();
|
||||
}
|
||||
|
||||
// Return reference to owned object.
|
||||
T& operator*() const {
|
||||
return *Ptr();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_SMART_PTR_H
|
||||
140
external/android-emugl/shared/emugl/common/smart_ptr_unittest.cpp
vendored
Normal file
140
external/android-emugl/shared/emugl/common/smart_ptr_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/smart_ptr.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// This Test sub-class is used to track allocations and deallocations of
|
||||
// the MyTestClass instances that are created through newInstance().
|
||||
// See below for typical usage.
|
||||
class SmartPtrTest : public testing::Test {
|
||||
public:
|
||||
SmartPtrTest() : mNewCount(0), mDeleteCount(0), mDoCount(0) {}
|
||||
|
||||
~SmartPtrTest() {
|
||||
mNewCount = 0;
|
||||
mDoCount = 0;
|
||||
mDeleteCount = 0;
|
||||
}
|
||||
|
||||
class MyClass;
|
||||
|
||||
MyClass* newInstance() {
|
||||
return new MyClass(this);
|
||||
}
|
||||
|
||||
class MyClass {
|
||||
public:
|
||||
MyClass(SmartPtrTest* test) : mTest(test) {
|
||||
mTest->mNewCount++;
|
||||
}
|
||||
|
||||
void doStuff() {
|
||||
mTest->mDoCount++;
|
||||
}
|
||||
|
||||
~MyClass() {
|
||||
mTest->mDeleteCount++;
|
||||
}
|
||||
private:
|
||||
SmartPtrTest* mTest;
|
||||
};
|
||||
|
||||
int mNewCount;
|
||||
int mDeleteCount;
|
||||
int mDoCount;
|
||||
};
|
||||
|
||||
|
||||
TEST_F(SmartPtrTest, Empty) {
|
||||
SmartPtr<MyClass> ptr;
|
||||
EXPECT_FALSE(ptr.Ptr());
|
||||
|
||||
EXPECT_EQ(0, mNewCount);
|
||||
EXPECT_EQ(0, mDeleteCount);
|
||||
EXPECT_EQ(0, mDoCount);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SmartPtrTest, SingleRef) {
|
||||
MyClass* obj = newInstance();
|
||||
EXPECT_EQ(1, mNewCount);
|
||||
|
||||
{
|
||||
SmartPtr<MyClass> ptr(obj);
|
||||
EXPECT_EQ(obj, ptr.Ptr());
|
||||
|
||||
EXPECT_EQ(1, mNewCount);
|
||||
EXPECT_EQ(0, mDeleteCount);
|
||||
EXPECT_EQ(0, mDoCount);
|
||||
}
|
||||
// Check that the object was deleted.
|
||||
EXPECT_EQ(1, mDeleteCount);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SmartPtrTest, CopyConstructor) {
|
||||
MyClass* obj = newInstance();
|
||||
EXPECT_EQ(1, mNewCount);
|
||||
|
||||
{
|
||||
SmartPtr<MyClass> ptr1(obj);
|
||||
{
|
||||
SmartPtr<MyClass> ptr2(ptr1);
|
||||
EXPECT_EQ(2, ptr1.getRefCount());
|
||||
EXPECT_EQ(2, ptr2.getRefCount());
|
||||
EXPECT_EQ(1, mNewCount);
|
||||
EXPECT_EQ(0, mDeleteCount);
|
||||
EXPECT_EQ(0, mDoCount);
|
||||
}
|
||||
EXPECT_EQ(1, mNewCount);
|
||||
EXPECT_EQ(0, mDeleteCount);
|
||||
EXPECT_EQ(0, mDoCount);
|
||||
}
|
||||
EXPECT_EQ(1, mNewCount);
|
||||
EXPECT_EQ(1, mDeleteCount);
|
||||
EXPECT_EQ(0, mDoCount);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SmartPtrTest, AssignmentOperator) {
|
||||
SmartPtr<MyClass> ptr1(newInstance());
|
||||
SmartPtr<MyClass> ptr2(newInstance());
|
||||
EXPECT_EQ(2, mNewCount);
|
||||
EXPECT_EQ(0, mDeleteCount);
|
||||
EXPECT_EQ(0, mDoCount);
|
||||
|
||||
ptr2 = ptr1;
|
||||
EXPECT_EQ(2, mNewCount);
|
||||
EXPECT_EQ(1, mDeleteCount);
|
||||
|
||||
EXPECT_EQ(ptr1.Ptr(), ptr2.Ptr());
|
||||
EXPECT_EQ(2, ptr1.getRefCount());
|
||||
EXPECT_EQ(2, ptr2.getRefCount());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SmartPtrTest, ArrowOperator) {
|
||||
SmartPtr<MyClass> ptr(newInstance());
|
||||
ptr->doStuff();
|
||||
EXPECT_EQ(1, mDoCount);
|
||||
|
||||
(*ptr).doStuff();
|
||||
EXPECT_EQ(2, mDoCount);
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
247
external/android-emugl/shared/emugl/common/sockets.cpp
vendored
Normal file
247
external/android-emugl/shared/emugl/common/sockets.cpp
vendored
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/sockets.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
static void socketSetDontLinger(int s) {
|
||||
#ifdef _WIN32
|
||||
// TODO: Verify default behavior on WINDOWS
|
||||
#else
|
||||
// Ungraceful shutdown, no reason to linger at all
|
||||
struct linger so_linger;
|
||||
so_linger.l_onoff = 1;
|
||||
so_linger.l_linger = 0;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger) < 0)
|
||||
perror("Setting socket option SO_LINGER={on, 0} failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void socketSetReuseAddress(int s) {
|
||||
#ifdef _WIN32
|
||||
// The default behaviour on Windows is equivalent to SO_REUSEADDR
|
||||
// so we don't need to set this option. Moreover, one should never
|
||||
// set this option with WinSock because it's badly implemented and
|
||||
// generates a huge security issue. See:
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx
|
||||
#else
|
||||
int val = 1;
|
||||
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
|
||||
perror("Setting socket option SO_REUSEADDR failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Helper union to store a socket address.
|
||||
struct SockAddr {
|
||||
socklen_t len;
|
||||
union {
|
||||
sockaddr generic;
|
||||
sockaddr_in inet;
|
||||
#ifndef _WIN32
|
||||
sockaddr_un local;
|
||||
#endif
|
||||
};
|
||||
|
||||
int getFamily() const { return generic.sa_family; }
|
||||
|
||||
void initEmpty() {
|
||||
::memset(this, 0, sizeof(*this));
|
||||
this->len = static_cast<socklen_t>(sizeof(*this));
|
||||
}
|
||||
|
||||
int initFromInet(uint32_t ip_address, int port) {
|
||||
if (port < 0 || port >= 65536)
|
||||
return -EINVAL;
|
||||
|
||||
::memset(this, 0, sizeof(*this));
|
||||
this->inet.sin_family = AF_INET;
|
||||
this->inet.sin_port = htons(port);
|
||||
this->inet.sin_addr.s_addr = htonl(ip_address);
|
||||
this->len = sizeof(this->inet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int initFromLocalhost(int port) {
|
||||
return initFromInet(0x7f000001, port);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
// Initialize the SockAddr from a Unix path. Returns 0 on success,
|
||||
// or -errno code on failure.
|
||||
int initFromUnixPath(const char* path) {
|
||||
if (!path || !path[0])
|
||||
return -EINVAL;
|
||||
|
||||
size_t pathLen = ::strlen(path);
|
||||
if (pathLen >= sizeof(local.sun_path))
|
||||
return -E2BIG;
|
||||
|
||||
::memset(this, 0, sizeof(*this));
|
||||
this->local.sun_family = AF_LOCAL;
|
||||
::memcpy(this->local.sun_path, path, pathLen + 1U);
|
||||
this->len = pathLen + offsetof(sockaddr_un, sun_path);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int socketBindInternal(const SockAddr* addr, int socketType) {
|
||||
int s = ::socket(addr->getFamily(), socketType, 0);
|
||||
if (s < 0) {
|
||||
perror("Could not create socket to bind");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
socketSetDontLinger(s);
|
||||
socketSetReuseAddress(s);
|
||||
|
||||
// Bind to the socket.
|
||||
if (::bind(s, &addr->generic, addr->len) < 0 ||
|
||||
::listen(s, 5) < 0) {
|
||||
int ret = -errno;
|
||||
perror("Could not bind or listen to socket");
|
||||
::close(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int socketConnectInternal(const SockAddr* addr, int socketType) {
|
||||
int s = ::socket(addr->getFamily(), socketType, 0);
|
||||
if (s < 0) {
|
||||
perror("Could not create socket to connect");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
socketSetDontLinger(s);
|
||||
socketSetReuseAddress(s);
|
||||
|
||||
int ret;
|
||||
do {
|
||||
ret = ::connect(s, &addr->generic, addr->len);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
::close(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void socketTcpDisableNagle(int s) {
|
||||
// disable Nagle algorithm to improve bandwidth of small
|
||||
// packets which are quite common in our implementation.
|
||||
#ifdef _WIN32
|
||||
DWORD flag;
|
||||
#else
|
||||
int flag;
|
||||
#endif
|
||||
flag = 1;
|
||||
setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
|
||||
(const char*)&flag, sizeof(flag));
|
||||
}
|
||||
|
||||
int socketGetPort(int s) {
|
||||
SockAddr addr;
|
||||
addr.initEmpty();
|
||||
if (getsockname(s, &addr.generic, &addr.len) < 0) {
|
||||
return -errno;
|
||||
}
|
||||
switch (addr.generic.sa_family) {
|
||||
case AF_INET:
|
||||
return ntohs(addr.inet.sin_port);
|
||||
default:
|
||||
;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
int socketLocalServer(const char* path, int socketType) {
|
||||
SockAddr addr;
|
||||
int ret = addr.initFromUnixPath(path);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return socketBindInternal(&addr, socketType);
|
||||
}
|
||||
|
||||
int socketLocalClient(const char* path, int socketType) {
|
||||
SockAddr addr;
|
||||
int ret = addr.initFromUnixPath(path);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return socketConnectInternal(&addr, socketType);
|
||||
}
|
||||
#endif // !_WIN32
|
||||
|
||||
int socketTcpLoopbackServer(int port, int socketType) {
|
||||
SockAddr addr;
|
||||
int ret = addr.initFromLocalhost(port);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return socketBindInternal(&addr, socketType);
|
||||
}
|
||||
|
||||
int socketTcpLoopbackClient(int port, int socketType) {
|
||||
SockAddr addr;
|
||||
int ret = addr.initFromLocalhost(port);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return socketConnectInternal(&addr, socketType);
|
||||
}
|
||||
|
||||
int socketTcpClient(const char* hostname, int port, int socketType) {
|
||||
// TODO(digit): Implement this.
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int socketAccept(int serverSocket) {
|
||||
int ret;
|
||||
do {
|
||||
ret = ::accept(serverSocket, NULL, NULL);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
57
external/android-emugl/shared/emugl/common/sockets.h
vendored
Normal file
57
external/android-emugl/shared/emugl/common/sockets.h
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_SOCKETS_H
|
||||
#define EMUGL_COMMON_SOCKETS_H
|
||||
|
||||
// A set of helper functions used to deal with sockets in a portable way.
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// Disable Nagle's algorithm for socket descriptor |s|. This assumes
|
||||
// that |s| is a TCP socket descriptor.
|
||||
void socketTcpDisableNagle(int s);
|
||||
|
||||
// Return the port associated with a given IP or IPv6 socket,
|
||||
// or -errno code on failure.
|
||||
int socketGetPort(int s);
|
||||
|
||||
// Bind to a local/Unix path, and return its socket descriptor on success,
|
||||
// or -errno code on failure.
|
||||
int socketLocalServer(const char* path, int socketType);
|
||||
|
||||
// Connect to a Unix local path, and return a new socket descriptor
|
||||
// on success, or -errno code on failure.
|
||||
int socketLocalClient(const char* path, int socketType);
|
||||
|
||||
// Bind to a localhost TCP socket, and return its socket descriptor on
|
||||
// success, or -errno code on failure.
|
||||
int socketTcpLoopbackServer(int port, int socketType);
|
||||
|
||||
// Connect to a localhost TCP port, and return a new socket descriptor on
|
||||
// success, or -errno code on failure.
|
||||
int socketTcpLoopbackClient(int port, int socketType);
|
||||
|
||||
// Connect to a TCP host, and return a new socket descriptor on
|
||||
// success, or -errno code on failure.
|
||||
int socketTcpClient(const char* hostname, int port, int socketType);
|
||||
|
||||
// Accept a new connection. |serverSocket| must be a bound server socket
|
||||
// descriptor. Returns new socket descriptor on success, or -errno code
|
||||
// on failure.
|
||||
int socketAccept(int serverSocket);
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_COMMON_SOCKETS_H
|
||||
22
external/android-emugl/shared/emugl/common/testing/test_shared_library.cpp
vendored
Normal file
22
external/android-emugl/shared/emugl/common/testing/test_shared_library.cpp
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
// This source file must be compiled into a simple shared library which
|
||||
// will be used by shared_library_unittest.cpp to verify that the
|
||||
// emugl::SharedLibrary class works properly.
|
||||
|
||||
|
||||
extern "C" int foo_function(void) {
|
||||
return 42;
|
||||
}
|
||||
78
external/android-emugl/shared/emugl/common/testing/test_thread.h
vendored
Normal file
78
external/android-emugl/shared/emugl/common/testing/test_thread.h
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_TESTING_TEST_THREAD_H
|
||||
#define EMUGL_COMMON_TESTING_TEST_THREAD_H
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN 1
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// Very basic platform thread wrapper that only uses a tiny stack.
|
||||
// This shall only be used during unit testing, and allows test code
|
||||
// to not depend on the implementation of emugl::Thread.
|
||||
class TestThread {
|
||||
public:
|
||||
// Main thread function type.
|
||||
typedef void* (ThreadFunction)(void* param);
|
||||
|
||||
// Constructor actually launches a new platform thread.
|
||||
TestThread(ThreadFunction* func, void* funcParam) {
|
||||
#ifdef _WIN32
|
||||
mThread = CreateThread(NULL,
|
||||
16384,
|
||||
(DWORD WINAPI (*)(void*))func,
|
||||
funcParam,
|
||||
0,
|
||||
NULL);
|
||||
#else
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setstacksize(&attr, 16384);
|
||||
pthread_create(&mThread, &attr, func, funcParam);
|
||||
pthread_attr_destroy(&attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
~TestThread() {
|
||||
#ifdef _WIN32
|
||||
CloseHandle(mThread);
|
||||
#endif
|
||||
}
|
||||
|
||||
void join() {
|
||||
#ifdef _WIN32
|
||||
WaitForSingleObject(mThread, INFINITE);
|
||||
#else
|
||||
void* ret = NULL;
|
||||
pthread_join(mThread, &ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
HANDLE mThread;
|
||||
#else
|
||||
pthread_t mThread;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_COMMON_TESTING_TEST_THREAD_H
|
||||
103
external/android-emugl/shared/emugl/common/thread.h
vendored
Normal file
103
external/android-emugl/shared/emugl/common/thread.h
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_THREAD_H
|
||||
#define EMUGL_COMMON_THREAD_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// Wrapper class for platform-specific threads.
|
||||
// To create your own thread, define a sub-class of emugl::Thread
|
||||
// and override its main() method.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// class MyThread : public emugl::Thread {
|
||||
// public:
|
||||
// MyThread() : Thread() {}
|
||||
//
|
||||
// virtual intptr_t main() {
|
||||
// ... main thread loop implementation
|
||||
// return 0;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// ...
|
||||
//
|
||||
// // Create new instance, but does not start it.
|
||||
// MyThread* thread = new MyThread();
|
||||
//
|
||||
// // Start the thread.
|
||||
// thread->start();
|
||||
//
|
||||
// // Wait for thread completion, and gets result into |exitStatus|.
|
||||
// int exitStatus;
|
||||
// thread->wait(&exitStatus);
|
||||
//
|
||||
class Thread {
|
||||
public:
|
||||
// Public constructor.
|
||||
Thread();
|
||||
|
||||
// Virtual destructor.
|
||||
virtual ~Thread();
|
||||
|
||||
// Override this method in your own thread sub-classes. This will
|
||||
// be called when start() is invoked on the Thread instance.
|
||||
virtual intptr_t main() = 0;
|
||||
|
||||
// Start a thread instance. Return true on success, false otherwise
|
||||
// (e.g. if the thread was already started or terminated).
|
||||
bool start();
|
||||
|
||||
// Wait for thread termination and retrieve exist status into
|
||||
// |*exitStatus|. Return true on success, false otherwise.
|
||||
// NOTE: |exitStatus| can be NULL.
|
||||
bool wait(intptr_t *exitStatus);
|
||||
|
||||
// Check whether a thread has terminated. On success, return true
|
||||
// and sets |*exitStatus|. On failure, return false.
|
||||
// NOTE: |exitStatus| can be NULL.
|
||||
bool tryWait(intptr_t *exitStatus);
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
static DWORD WINAPI thread_main(void* arg);
|
||||
|
||||
HANDLE mThread;
|
||||
DWORD mThreadId;
|
||||
CRITICAL_SECTION mLock;
|
||||
#else // !WIN32
|
||||
static void* thread_main(void* arg);
|
||||
|
||||
pthread_t mThread;
|
||||
pthread_mutex_t mLock;
|
||||
bool mJoined;
|
||||
#endif
|
||||
intptr_t mExitStatus;
|
||||
bool mIsRunning;
|
||||
};
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_COMMON_THREAD_H
|
||||
|
||||
136
external/android-emugl/shared/emugl/common/thread_pthread.cpp
vendored
Normal file
136
external/android-emugl/shared/emugl/common/thread_pthread.cpp
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/thread.h"
|
||||
|
||||
#include "emugl/common/thread_store.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
class ScopedLocker {
|
||||
public:
|
||||
ScopedLocker(pthread_mutex_t* mutex) : mMutex(mutex) {
|
||||
pthread_mutex_lock(mMutex);
|
||||
}
|
||||
|
||||
~ScopedLocker() {
|
||||
pthread_mutex_unlock(mMutex);
|
||||
}
|
||||
private:
|
||||
pthread_mutex_t* mMutex;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
Thread::Thread() :
|
||||
mThread((pthread_t)NULL),
|
||||
mLock(),
|
||||
mJoined(false),
|
||||
mExitStatus(0),
|
||||
mIsRunning(false) {
|
||||
pthread_mutex_init(&mLock, NULL);
|
||||
}
|
||||
|
||||
Thread::~Thread() {
|
||||
assert(!mIsRunning);
|
||||
assert(mJoined);
|
||||
pthread_mutex_destroy(&mLock);
|
||||
}
|
||||
|
||||
bool Thread::start() {
|
||||
bool ret = true;
|
||||
pthread_mutex_lock(&mLock);
|
||||
mIsRunning = true;
|
||||
if (pthread_create(&mThread, NULL, thread_main, this)) {
|
||||
ret = false;
|
||||
mIsRunning = false;
|
||||
}
|
||||
pthread_mutex_unlock(&mLock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Thread::wait(intptr_t *exitStatus) {
|
||||
{
|
||||
ScopedLocker locker(&mLock);
|
||||
if (!mIsRunning) {
|
||||
// Thread already stopped.
|
||||
if (exitStatus) {
|
||||
*exitStatus = mExitStatus;
|
||||
}
|
||||
if (!mJoined) {
|
||||
// reclaim thread stack
|
||||
pthread_join(mThread, NULL);
|
||||
mJoined = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Do not hold the lock when waiting for the thread to ensure
|
||||
// it can update mIsRunning and mExitStatus properly in thread_main
|
||||
// without blocking.
|
||||
void *retval;
|
||||
if (pthread_join(mThread, &retval)) {
|
||||
return false;
|
||||
}
|
||||
if (exitStatus) {
|
||||
*exitStatus = (intptr_t)retval;
|
||||
}
|
||||
// Note: Updating mJoined must be performed inside the lock to avoid
|
||||
// race conditions between two threads waiting for the same thread
|
||||
// that just completed its execution.
|
||||
{
|
||||
ScopedLocker locker(&mLock);
|
||||
mJoined = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Thread::tryWait(intptr_t *exitStatus) {
|
||||
ScopedLocker locker(&mLock);
|
||||
if (mIsRunning) {
|
||||
return false;
|
||||
}
|
||||
if (!mJoined) {
|
||||
// Reclaim stack.
|
||||
pthread_join(mThread, NULL);
|
||||
mJoined = true;
|
||||
}
|
||||
if (exitStatus) {
|
||||
*exitStatus = mExitStatus;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void* Thread::thread_main(void *arg) {
|
||||
Thread* self = reinterpret_cast<Thread*>(arg);
|
||||
intptr_t ret = self->main();
|
||||
|
||||
pthread_mutex_lock(&self->mLock);
|
||||
self->mIsRunning = false;
|
||||
self->mExitStatus = ret;
|
||||
pthread_mutex_unlock(&self->mLock);
|
||||
|
||||
::emugl::ThreadStore::OnThreadExit();
|
||||
|
||||
return (void*)ret;
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
242
external/android-emugl/shared/emugl/common/thread_store.cpp
vendored
Normal file
242
external/android-emugl/shared/emugl/common/thread_store.cpp
vendored
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/thread_store.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "emugl/common/lazy_instance.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Set to 1 to print debug messages.
|
||||
#define DEBUG_THREAD_STORE 0
|
||||
|
||||
#if DEBUG_THREAD_STORE
|
||||
# define D(...) do { printf("%s:%d: ", __FUNCTION__, __LINE__); printf(__VA_ARGS__); fflush(stdout); } while (0)
|
||||
#else
|
||||
# define D(...) ((void)0)
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
namespace {
|
||||
|
||||
// The ThreadStore implementation on Windows is very tricky, because
|
||||
// TlsAlloc() doesn't allow one to provide a destructor function. As
|
||||
// such threads are expected to destroy all TLS values explicitely.
|
||||
//
|
||||
// To solve this issue, this source file provides a static method called
|
||||
// ThreadStore::OnThreadExit() that must be called when a thread exits,
|
||||
// which will cleanup all values for the current thread.
|
||||
//
|
||||
// But this forces us to track thread-specific values ourselves.
|
||||
|
||||
// Maximum amount of thread-specific slots supported by this implementation.
|
||||
enum {
|
||||
kMaxTlsSlots = 64
|
||||
};
|
||||
|
||||
// TlsSlotArray is a thread-specific array of values. Instances will
|
||||
// be stored in a Win32 TLS value controlled by a single master TLS
|
||||
// key.
|
||||
//
|
||||
typedef void* TlsSlotArray[kMaxTlsSlots];
|
||||
|
||||
// Global state shared by all threads
|
||||
class GlobalState {
|
||||
public:
|
||||
GlobalState() {
|
||||
D("Entering\n");
|
||||
mMasterTls = TlsAlloc();
|
||||
D("Master TLS = %d\n", (int)mMasterTls);
|
||||
InitializeCriticalSection(&mSection);
|
||||
mLastIndex = 0;
|
||||
::memset(mDestructors, 0, sizeof(mDestructors));
|
||||
D("Exiting\n");
|
||||
}
|
||||
|
||||
// Register a new TLS key, or return -1 on error (too many keys).
|
||||
// |destroy| is the destructor function for the key.
|
||||
int registerKey(ThreadStore::Destructor* destroy) {
|
||||
D("Entering destroy=%p\n", destroy);
|
||||
int ret = -1;
|
||||
EnterCriticalSection(&mSection);
|
||||
if (mLastIndex < kMaxTlsSlots) {
|
||||
ret = mLastIndex++;
|
||||
mDestructors[ret] = destroy;
|
||||
}
|
||||
LeaveCriticalSection(&mSection);
|
||||
D("Exiting newKey=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void unregisterKey(int key) {
|
||||
D("key=%d\n", key);
|
||||
if (key < 0 || key >= kMaxTlsSlots) {
|
||||
D("Invalid key\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: keys are not reusable, but remove the destructor to avoid
|
||||
// crashes in leaveCurrentThread() when it points to a function that
|
||||
// is going to be unloaded from the process' address space.
|
||||
EnterCriticalSection(&mSection);
|
||||
mDestructors[key] = NULL;
|
||||
LeaveCriticalSection(&mSection);
|
||||
D("Exiting\n");
|
||||
}
|
||||
|
||||
// Get the current thread-local value for a given |key|.
|
||||
void* getValue(int key) const {
|
||||
D("Entering key=%d\n", key);
|
||||
if (key < 0 || key >= kMaxTlsSlots) {
|
||||
D("Invalid key, result=NULL\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TlsSlotArray* array = getArray();
|
||||
void* ret = (*array)[key];
|
||||
D("Exiting keyValue=%p\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Set the current thread-local |value| for a given |key|.
|
||||
void setValue(int key, void* value) {
|
||||
D("Entering key=%d\n",key);
|
||||
if (key < 0 || key >= kMaxTlsSlots) {
|
||||
D("Invalid key, returning\n");
|
||||
return;
|
||||
}
|
||||
|
||||
TlsSlotArray* array = getArray();
|
||||
(*array)[key] = value;
|
||||
D("Exiting\n");
|
||||
}
|
||||
|
||||
// Call this when a thread exits to destroy all its thread-local values.
|
||||
void leaveCurrentThread() {
|
||||
D("Entering\n");
|
||||
TlsSlotArray* array =
|
||||
reinterpret_cast<TlsSlotArray*>(TlsGetValue(mMasterTls));
|
||||
if (!array) {
|
||||
D("Exiting, no thread-local data in this thread\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < kMaxTlsSlots; ++n) {
|
||||
void* value = array[n];
|
||||
if (value) {
|
||||
(*array)[n] = NULL;
|
||||
// NOTE: In theory, a destructor could reset the slot to
|
||||
// a new value, and we would have to loop in this function
|
||||
// in interesting ways. In practice, ignore the issue.
|
||||
EnterCriticalSection(&mSection);
|
||||
ThreadStore::Destructor* destroy = mDestructors[n];
|
||||
LeaveCriticalSection(&mSection);
|
||||
if (destroy) {
|
||||
D("Calling destructor %p for key=%d, with value=%p\n",
|
||||
destroy, (int)n, value);
|
||||
(*destroy)(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
TlsSetValue(mMasterTls, NULL);
|
||||
::free(array);
|
||||
D("Exiting\n");
|
||||
}
|
||||
|
||||
private:
|
||||
// Return the thread-local array of TLS slots for the current thread.
|
||||
// Cannot return NULL.
|
||||
TlsSlotArray* getArray() const {
|
||||
D("Entering\n");
|
||||
TlsSlotArray* array =
|
||||
reinterpret_cast<TlsSlotArray*>(TlsGetValue(mMasterTls));
|
||||
if (!array) {
|
||||
array = reinterpret_cast<TlsSlotArray*>(
|
||||
::calloc(sizeof(*array), 1));
|
||||
TlsSetValue(mMasterTls, array);
|
||||
D("Allocated new array at %p\n", array);
|
||||
} else {
|
||||
D("Retrieved array at %p\n", array);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
DWORD mMasterTls;
|
||||
CRITICAL_SECTION mSection;
|
||||
int mLastIndex;
|
||||
ThreadStore::Destructor* mDestructors[kMaxTlsSlots];
|
||||
};
|
||||
|
||||
LazyInstance<GlobalState> gGlobalState = LAZY_INSTANCE_INIT;
|
||||
|
||||
} // namespace
|
||||
|
||||
ThreadStore::ThreadStore(Destructor* destroy) {
|
||||
D("Entering this=%p destroy=%p\n", this, destroy);
|
||||
mKey = gGlobalState->registerKey(destroy);
|
||||
D("Exiting this=%p key=%d\n", this, mKey);
|
||||
}
|
||||
|
||||
ThreadStore::~ThreadStore() {
|
||||
D("Entering this=%p\n", this);
|
||||
GlobalState* state = gGlobalState.ptr();
|
||||
state->unregisterKey(mKey);
|
||||
D("Exiting this=%p\n", this);
|
||||
}
|
||||
|
||||
void* ThreadStore::get() const {
|
||||
D("Entering this=%p\n", this);
|
||||
void* ret = gGlobalState->getValue(mKey);
|
||||
D("Exiting this=%p value=%p\n", this, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ThreadStore::set(void* value) {
|
||||
D("Entering this=%p value=%p\n", this, value);
|
||||
gGlobalState->setValue(mKey, value);
|
||||
D("Exiting this=%p\n", this);
|
||||
}
|
||||
|
||||
// static
|
||||
void ThreadStore::OnThreadExit() {
|
||||
gGlobalState->leaveCurrentThread();
|
||||
}
|
||||
|
||||
#else // !_WIN32
|
||||
|
||||
ThreadStore::ThreadStore(Destructor* destroy) {
|
||||
int ret = pthread_key_create(&mKey, destroy);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr,
|
||||
"Could not create thread store key: %s\n",
|
||||
strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
ThreadStore::~ThreadStore() {
|
||||
pthread_key_delete(mKey);
|
||||
}
|
||||
|
||||
#endif // !_WIN32
|
||||
|
||||
} // namespace emugl
|
||||
110
external/android-emugl/shared/emugl/common/thread_store.h
vendored
Normal file
110
external/android-emugl/shared/emugl/common/thread_store.h
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_THREAD_STORE_H
|
||||
#define EMUGL_COMMON_THREAD_STORE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN 1
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// A class to model storage of thread-specific values, that can be
|
||||
// destroyed on thread exit.
|
||||
//
|
||||
// Note that on Windows, a thread must call OnThreadExit() explicitly
|
||||
// here to ensure that the values are probably discarded. This is an
|
||||
// unfortunate requirement of the Win32 API, which doesn't support
|
||||
// destructors at all.
|
||||
//
|
||||
// There are various hacks on the web to try to achieve this automatically
|
||||
// (e.g. [1]) but they rely on using the Microsoft build tools,
|
||||
// which doesn't work for us.
|
||||
//
|
||||
// Note another important issue with ThreadStore instances: if you create
|
||||
// one instance in a shared library, you need to make sure that it is
|
||||
// always destroyed before the library is unloaded. Otherwise, future
|
||||
// thread exit will likely crash, due to calling a destructor function
|
||||
// that is no longer in the process' address space.
|
||||
//
|
||||
// Finally, destroying an instance does _not_ free the corresponding values,
|
||||
// because doing so properly requires coordinating all participating threads,
|
||||
// which is impossible to achieve in the most general case. Thus, consider
|
||||
// that thread-local values are always leaked on library unload, or on
|
||||
// program exit.
|
||||
//
|
||||
// [1] http://stackoverflow.com/questions/14538159/about-tls-callback-in-windows
|
||||
|
||||
class ThreadStore {
|
||||
public:
|
||||
// Type of a function used to destroy a thread-specific value that
|
||||
// was previously assigned by calling set().
|
||||
typedef void (Destructor)(void* value);
|
||||
|
||||
// Initialize instance so that is hold keys that must be destroyed
|
||||
// on thread exit by calling |destroy|.
|
||||
explicit ThreadStore(Destructor* destroy);
|
||||
|
||||
// NOTE: Destructor don't free the thread-local values, but are required
|
||||
// to avoid crashes (see note above).
|
||||
~ThreadStore();
|
||||
|
||||
// Retrieve current thread-specific value from store.
|
||||
#ifdef _WIN32
|
||||
void* get() const;
|
||||
#else
|
||||
inline void* get() const {
|
||||
return pthread_getspecific(mKey);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set the new thread-specific value.
|
||||
#ifdef _WIN32
|
||||
void set(void* value);
|
||||
#else
|
||||
inline void set(void* value) {
|
||||
pthread_setspecific(mKey, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// Each thread should call this function on exit to ensure that
|
||||
// all corresponding TLS values are properly freed.
|
||||
static void OnThreadExit();
|
||||
#else
|
||||
// Nothing to do on Posix.
|
||||
static inline void OnThreadExit() {}
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Ensure you can't create an empty ThreadStore instance, or simply
|
||||
// copy it in any way.
|
||||
ThreadStore();
|
||||
ThreadStore(const ThreadStore&);
|
||||
ThreadStore& operator=(const ThreadStore&);
|
||||
|
||||
#ifdef _WIN32
|
||||
int mKey;
|
||||
#else
|
||||
pthread_key_t mKey;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_COMMON_THREAD_STORE_H
|
||||
146
external/android-emugl/shared/emugl/common/thread_store_unittest.cpp
vendored
Normal file
146
external/android-emugl/shared/emugl/common/thread_store_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/thread_store.h"
|
||||
|
||||
#include "emugl/common/mutex.h"
|
||||
#include "emugl/common/testing/test_thread.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper class used to count instance creation and destruction.
|
||||
class StaticCounter {
|
||||
public:
|
||||
enum {
|
||||
kMaxInstances = 1000,
|
||||
};
|
||||
|
||||
StaticCounter() {
|
||||
Mutex::AutoLock lock(mMutex);
|
||||
if (mCreationCount < kMaxInstances)
|
||||
mInstances[mCreationCount] = this;
|
||||
mCreationCount++;
|
||||
}
|
||||
|
||||
~StaticCounter() {
|
||||
Mutex::AutoLock lock(mMutex);
|
||||
mDestructionCount++;
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
Mutex::AutoLock lock(mMutex);
|
||||
mCreationCount = 0;
|
||||
mDestructionCount = 0;
|
||||
}
|
||||
|
||||
static size_t getCreationCount() {
|
||||
Mutex::AutoLock lock(mMutex);
|
||||
return mCreationCount;
|
||||
}
|
||||
|
||||
static size_t getDestructionCount() {
|
||||
Mutex::AutoLock lock(mMutex);
|
||||
return mDestructionCount;
|
||||
}
|
||||
|
||||
static void freeAll() {
|
||||
for (size_t n = 0; n < kMaxInstances; ++n)
|
||||
delete mInstances[n];
|
||||
}
|
||||
|
||||
private:
|
||||
static Mutex mMutex;
|
||||
static size_t mCreationCount;
|
||||
static size_t mDestructionCount;
|
||||
static StaticCounter* mInstances[kMaxInstances];
|
||||
};
|
||||
|
||||
Mutex StaticCounter::mMutex;
|
||||
size_t StaticCounter::mCreationCount = 0;
|
||||
size_t StaticCounter::mDestructionCount = 0;
|
||||
StaticCounter* StaticCounter::mInstances[kMaxInstances];
|
||||
|
||||
} // namespace
|
||||
|
||||
// Just check that we can create a new ThreadStore with an empty
|
||||
// destructor, and use it in the current thread.
|
||||
TEST(ThreadStore, MainThreadWithoutDestructor) {
|
||||
ThreadStore store(NULL);
|
||||
static int x = 42;
|
||||
store.set(&x);
|
||||
EXPECT_EQ(&x, store.get());
|
||||
}
|
||||
|
||||
// The following test checks that exiting a thread correctly deletes
|
||||
// any thread-local value stored in it.
|
||||
static void simplyDestroy(void* value) {
|
||||
delete (StaticCounter*) value;
|
||||
}
|
||||
|
||||
static void* simpleThreadFunc(void* param) {
|
||||
ThreadStore* store = static_cast<ThreadStore*>(param);
|
||||
store->set(new StaticCounter());
|
||||
ThreadStore::OnThreadExit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TEST(ThreadStore, ThreadsWithDestructor) {
|
||||
ThreadStore store(simplyDestroy);
|
||||
const size_t kNumThreads = 1000;
|
||||
TestThread* threads[kNumThreads];
|
||||
StaticCounter::reset();
|
||||
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
threads[n] = new TestThread(&simpleThreadFunc, &store);
|
||||
}
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
threads[n]->join();
|
||||
}
|
||||
|
||||
EXPECT_EQ(kNumThreads, StaticCounter::getCreationCount());
|
||||
EXPECT_EQ(kNumThreads, StaticCounter::getDestructionCount());
|
||||
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
delete threads[n];
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ThreadStore, ThreadsWithoutDestructor) {
|
||||
ThreadStore store(NULL);
|
||||
const size_t kNumThreads = 1000;
|
||||
TestThread* threads[kNumThreads];
|
||||
StaticCounter::reset();
|
||||
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
threads[n] = new TestThread(&simpleThreadFunc, &store);
|
||||
}
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
threads[n]->join();
|
||||
}
|
||||
|
||||
EXPECT_EQ(kNumThreads, StaticCounter::getCreationCount());
|
||||
EXPECT_EQ(0U, StaticCounter::getDestructionCount());
|
||||
|
||||
StaticCounter::freeAll();
|
||||
|
||||
for (size_t n = 0; n < kNumThreads; ++n) {
|
||||
delete threads[n];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
164
external/android-emugl/shared/emugl/common/thread_unittest.cpp
vendored
Normal file
164
external/android-emugl/shared/emugl/common/thread_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/thread.h"
|
||||
|
||||
#include "emugl/common/mutex.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
// A simple thread instance that does nothing at all and exits immediately.
|
||||
class EmptyThread : public ::emugl::Thread {
|
||||
public:
|
||||
intptr_t main() { return 42; }
|
||||
};
|
||||
|
||||
class CountingThread : public ::emugl::Thread {
|
||||
public:
|
||||
class State {
|
||||
public:
|
||||
State() : mLock(), mCount(0) {}
|
||||
~State() {}
|
||||
|
||||
void increment() {
|
||||
mLock.lock();
|
||||
mCount++;
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
int count() const {
|
||||
int ret;
|
||||
mLock.lock();
|
||||
ret = mCount;
|
||||
mLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable Mutex mLock;
|
||||
int mCount;
|
||||
};
|
||||
|
||||
CountingThread(State* state) : mState(state) {}
|
||||
|
||||
intptr_t main() {
|
||||
mState->increment();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
State* mState;
|
||||
};
|
||||
|
||||
class WaitingThread : public ::emugl::Thread {
|
||||
public:
|
||||
WaitingThread(Mutex* lock) : mLock(lock) {}
|
||||
|
||||
intptr_t main() {
|
||||
// Try to acquire lock.
|
||||
mLock->lock();
|
||||
|
||||
// Then try to release it.
|
||||
mLock->unlock();
|
||||
return 0;
|
||||
}
|
||||
private:
|
||||
Mutex* mLock;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ThreadTest, WaitForSimpleThread) {
|
||||
Thread* thread = new EmptyThread();
|
||||
EXPECT_TRUE(thread);
|
||||
EXPECT_TRUE(thread->start());
|
||||
intptr_t status;
|
||||
EXPECT_TRUE(thread->wait(&status));
|
||||
EXPECT_EQ(42, status);
|
||||
}
|
||||
|
||||
TEST(ThreadTest, WaitForMultipleThreads) {
|
||||
CountingThread::State state;
|
||||
const size_t kMaxThreads = 100;
|
||||
Thread* threads[kMaxThreads];
|
||||
|
||||
// Create all threads.
|
||||
for (size_t n = 0; n < kMaxThreads; ++n) {
|
||||
threads[n] = new CountingThread(&state);
|
||||
EXPECT_TRUE(threads[n]) << "thread " << n;
|
||||
}
|
||||
|
||||
// Start them all.
|
||||
for (size_t n = 0; n < kMaxThreads; ++n) {
|
||||
EXPECT_TRUE(threads[n]->start()) << "thread " << n;
|
||||
}
|
||||
|
||||
// Wait for them all.
|
||||
for (size_t n = 0; n < kMaxThreads; ++n) {
|
||||
EXPECT_TRUE(threads[n]->wait(NULL)) << "thread " << n;
|
||||
}
|
||||
|
||||
// Check state.
|
||||
EXPECT_EQ((int)kMaxThreads, state.count());
|
||||
|
||||
// Delete them all.
|
||||
for (size_t n = 0; n < kMaxThreads; ++n) {
|
||||
delete threads[n];
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ThreadTest, TryWaitForMultipleThreads) {
|
||||
Mutex lock;
|
||||
const size_t kMaxThreads = 100;
|
||||
Thread* threads[kMaxThreads];
|
||||
|
||||
// Create all threads.
|
||||
for (size_t n = 0; n < kMaxThreads; ++n) {
|
||||
threads[n] = new WaitingThread(&lock);
|
||||
EXPECT_TRUE(threads[n]) << "thread " << n;
|
||||
}
|
||||
|
||||
// Acquire the lock, this will block all threads.
|
||||
lock.lock();
|
||||
|
||||
// Start them all.
|
||||
for (size_t n = 0; n < kMaxThreads; ++n) {
|
||||
EXPECT_TRUE(threads[n]->start()) << "thread " << n;
|
||||
}
|
||||
|
||||
// Check that tryWait() fails for all threads.
|
||||
for (size_t n = 0; n < kMaxThreads; ++n) {
|
||||
EXPECT_FALSE(threads[n]->tryWait(NULL)) << "thread" << n;
|
||||
}
|
||||
|
||||
// Release the lock, this will unblock all threads.
|
||||
lock.unlock();
|
||||
|
||||
// Wait for them all.
|
||||
for (size_t n = 0; n < kMaxThreads; ++n) {
|
||||
EXPECT_TRUE(threads[n]->wait(NULL)) << "thread " << n;
|
||||
EXPECT_TRUE(threads[n]->tryWait(NULL)) << "thread " << n;
|
||||
}
|
||||
|
||||
// Delete them all.
|
||||
for (size_t n = 0; n < kMaxThreads; ++n) {
|
||||
delete threads[n];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
121
external/android-emugl/shared/emugl/common/thread_win32.cpp
vendored
Normal file
121
external/android-emugl/shared/emugl/common/thread_win32.cpp
vendored
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/thread.h"
|
||||
|
||||
#include "emugl/common/thread_store.h"
|
||||
|
||||
namespace emugl {
|
||||
|
||||
namespace {
|
||||
|
||||
class ScopedLocker {
|
||||
public:
|
||||
ScopedLocker(CRITICAL_SECTION* section) : mSection(section) {
|
||||
EnterCriticalSection(mSection);
|
||||
}
|
||||
|
||||
~ScopedLocker() {
|
||||
LeaveCriticalSection(mSection);
|
||||
}
|
||||
private:
|
||||
CRITICAL_SECTION* mSection;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
Thread::Thread() :
|
||||
mThread(INVALID_HANDLE_VALUE),
|
||||
mThreadId(0),
|
||||
mExitStatus(0),
|
||||
mIsRunning(false) {
|
||||
InitializeCriticalSection(&mLock);
|
||||
}
|
||||
|
||||
Thread::~Thread() {
|
||||
if(mThread != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(mThread);
|
||||
}
|
||||
DeleteCriticalSection(&mLock);
|
||||
}
|
||||
|
||||
bool Thread::start() {
|
||||
ScopedLocker locker(&mLock);
|
||||
|
||||
bool ret = true;
|
||||
mIsRunning = true;
|
||||
mThread = CreateThread(NULL, 0, &Thread::thread_main, this, 0, &mThreadId);
|
||||
if (!mThread) {
|
||||
ret = false;
|
||||
mIsRunning = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Thread::wait(intptr_t* exitStatus) {
|
||||
{
|
||||
ScopedLocker locker(&mLock);
|
||||
if (!mIsRunning) {
|
||||
// Thread already stopped.
|
||||
if (exitStatus) {
|
||||
*exitStatus = mExitStatus;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Do not hold lock during wait to aloow thread_main to
|
||||
// properly update mIsRunning and mExitStatus on thread exit.
|
||||
if (WaitForSingleObject(mThread, INFINITE) == WAIT_FAILED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exitStatus) {
|
||||
ScopedLocker locker(&mLock);
|
||||
*exitStatus = mExitStatus;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Thread::tryWait(intptr_t* exitStatus) {
|
||||
ScopedLocker locker(&mLock);
|
||||
|
||||
if (mIsRunning && WaitForSingleObject(mThread, 0) != WAIT_OBJECT_0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exitStatus) {
|
||||
*exitStatus = mExitStatus;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
DWORD WINAPI Thread::thread_main(void *arg)
|
||||
{
|
||||
Thread* self = reinterpret_cast<Thread*>(arg);
|
||||
intptr_t ret = self->main();
|
||||
|
||||
EnterCriticalSection(&self->mLock);
|
||||
self->mIsRunning = false;
|
||||
self->mExitStatus = ret;
|
||||
LeaveCriticalSection(&self->mLock);
|
||||
|
||||
// Ensure all thread-local values are released for this thread.
|
||||
::emugl::ThreadStore::OnThreadExit();
|
||||
|
||||
return static_cast<DWORD>(ret);
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
225
external/android-emugl/shared/emugl/common/unique_integer_map.h
vendored
Normal file
225
external/android-emugl/shared/emugl/common/unique_integer_map.h
vendored
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
// Copyright (C) 2014 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.
|
||||
|
||||
#ifndef EMUGL_COMMON_UNIQUE_INTEGER_MAP_H
|
||||
#define EMUGL_COMMON_UNIQUE_INTEGER_MAP_H
|
||||
|
||||
#include "emugl/common/pod_vector.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
// Helper template class that implements a bi-directional mapping between
|
||||
// two integer types |A| and |B|. More specifically:
|
||||
//
|
||||
// - The map allocates values of type |B| when a key of type |A| is entered
|
||||
// in the map.
|
||||
//
|
||||
// - keys and values cannot be 0, which is reserved (i.e. means 'invalid').
|
||||
//
|
||||
// This is used in EmuGL to map liberal 'void*' values (e.g. EGLimages ones)
|
||||
// to unique 32-bit IDs that can be written to / read from the wire protocol.
|
||||
template <typename A, typename B>
|
||||
class UniqueIntegerMap {
|
||||
public:
|
||||
UniqueIntegerMap() : mForwardPairs(), mBackwardPairs() {}
|
||||
~UniqueIntegerMap() {}
|
||||
|
||||
// Return true iff the map is empty.
|
||||
const bool empty() const { return mForwardPairs.empty(); }
|
||||
|
||||
// Return the number of (key,value) pairs in the map.
|
||||
size_t size() const { return mForwardPairs.size(); }
|
||||
|
||||
// Find the value associated with |key| in the map.
|
||||
// Returns 0 in case of failure, or if |key| is 0.
|
||||
B find(const A key) const;
|
||||
|
||||
// Find the key associated with a given |value| in the map.
|
||||
// Returns 0 if |value| is 0, or in case of failure.
|
||||
A findKeyFor(const B value) const;
|
||||
|
||||
// Add |key| to the map and return an automatically-allocated
|
||||
// unique value for it. Return 0 if |key| is 0.
|
||||
B add(const A key);
|
||||
|
||||
// Delete the entry associated with a given |key|. The
|
||||
// corresponding value may be recycled by future calls to add().
|
||||
void del(const A key);
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
A first;
|
||||
B second;
|
||||
} ForwardPair;
|
||||
|
||||
typedef struct {
|
||||
B first;
|
||||
A second;
|
||||
} BackwardPair;
|
||||
|
||||
size_t findKeyIndexPlusOne(const A key) const;
|
||||
size_t findValueIndexPlusOne(const B value) const;
|
||||
|
||||
B allocValue();
|
||||
void freeValue(B value);
|
||||
|
||||
PodVector<ForwardPair> mForwardPairs;
|
||||
PodVector<BackwardPair> mBackwardPairs;
|
||||
|
||||
B mLastValue;
|
||||
PodVector<B> mFreeValues;
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
B UniqueIntegerMap<A,B>::find(const A key) const {
|
||||
size_t keyIndex = findKeyIndexPlusOne(key);
|
||||
if (!keyIndex) {
|
||||
return 0;
|
||||
}
|
||||
return mForwardPairs[keyIndex - 1U].second;
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
A UniqueIntegerMap<A,B>::findKeyFor(const B value) const {
|
||||
size_t valueIndex = findValueIndexPlusOne(value);
|
||||
if (!valueIndex) {
|
||||
return 0;
|
||||
}
|
||||
return mBackwardPairs[valueIndex - 1U].second;
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
B UniqueIntegerMap<A,B>::add(const A key) {
|
||||
// Binary search to find the proper insertion point for the key.
|
||||
// Also checks that the key isn't already in the set.
|
||||
size_t min = 0;
|
||||
size_t max = mForwardPairs.size();
|
||||
while (min < max) {
|
||||
size_t mid = min + ((max - min) >> 1);
|
||||
A midKey = mForwardPairs[mid].first;
|
||||
if (midKey < key) {
|
||||
min = mid + 1U;
|
||||
} else if (midKey > key) {
|
||||
max = mid;
|
||||
} else {
|
||||
// Already in the set.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate new unique value
|
||||
B value = allocValue();
|
||||
|
||||
ForwardPair* pair = mForwardPairs.emplace(min);
|
||||
pair->first = key;
|
||||
pair->second = value;
|
||||
|
||||
// Binary search to find proper insertion point for the value.
|
||||
min = 0;
|
||||
max = mBackwardPairs.size();
|
||||
while (min < max) {
|
||||
size_t mid = min + ((max - min) >> 1);
|
||||
B midValue = mBackwardPairs[mid].first;
|
||||
if (midValue < value) {
|
||||
min = mid + 1U;
|
||||
} else {
|
||||
max = mid;
|
||||
}
|
||||
}
|
||||
|
||||
BackwardPair* backPair = mBackwardPairs.emplace(min);
|
||||
backPair->first = value;
|
||||
backPair->second = key;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
void UniqueIntegerMap<A,B>::del(const A key) {
|
||||
size_t keyIndex = findKeyIndexPlusOne(key);
|
||||
if (!keyIndex) {
|
||||
return;
|
||||
}
|
||||
B value = mForwardPairs[keyIndex - 1U].second;
|
||||
size_t valueIndex = findValueIndexPlusOne(value);
|
||||
mForwardPairs.remove(keyIndex - 1U);
|
||||
mBackwardPairs.remove(valueIndex - 1U);
|
||||
freeValue(value);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
size_t UniqueIntegerMap<A,B>::findKeyIndexPlusOne(const A key) const {
|
||||
// Binary search in forward pair array.
|
||||
size_t min = 0;
|
||||
size_t max = mForwardPairs.size();
|
||||
while (min < max) {
|
||||
size_t mid = min + ((max - min) >> 1);
|
||||
A midKey = mForwardPairs[mid].first;
|
||||
if (midKey < key) {
|
||||
min = mid + 1U;
|
||||
} else if (midKey > key) {
|
||||
max = mid;
|
||||
} else {
|
||||
return mid + 1U;
|
||||
}
|
||||
}
|
||||
return 0U;
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
size_t UniqueIntegerMap<A,B>::findValueIndexPlusOne(const B value) const {
|
||||
// Binary search in revere pair array.
|
||||
size_t min = 0;
|
||||
size_t max = mBackwardPairs.size();
|
||||
while (min < max) {
|
||||
size_t mid = min + ((max - min) >> 1);
|
||||
B midValue = mBackwardPairs[mid].first;
|
||||
if (midValue < value) {
|
||||
min = mid + 1U;
|
||||
} else if (midValue > value) {
|
||||
max = mid;
|
||||
} else {
|
||||
return mid + 1U;
|
||||
}
|
||||
}
|
||||
return 0U;
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
B UniqueIntegerMap<A,B>::allocValue() {
|
||||
if (!mFreeValues.empty()) {
|
||||
B result = mFreeValues[0];
|
||||
mFreeValues.pop();
|
||||
return result;
|
||||
}
|
||||
return ++mLastValue;
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
void UniqueIntegerMap<A,B>::freeValue(B value) {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
if (value == mLastValue) {
|
||||
mLastValue--;
|
||||
return;
|
||||
}
|
||||
mFreeValues.append(value);
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
|
||||
#endif // EMUGL_COMMON_INTEGER_MAP_H
|
||||
103
external/android-emugl/shared/emugl/common/unique_integer_map_unittest.cpp
vendored
Normal file
103
external/android-emugl/shared/emugl/common/unique_integer_map_unittest.cpp
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (C) 2014 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 "emugl/common/unique_integer_map.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace emugl {
|
||||
|
||||
typedef UniqueIntegerMap<uintptr_t,uint32_t> MyMap;
|
||||
|
||||
TEST(UniqueIntegerMap, Empty) {
|
||||
MyMap map;
|
||||
|
||||
EXPECT_TRUE(map.empty());
|
||||
EXPECT_EQ(0U, map.size());
|
||||
EXPECT_EQ(0U, map.find(0U));
|
||||
EXPECT_EQ(0U, map.find(1U));
|
||||
EXPECT_EQ(0U, map.find(2U));
|
||||
EXPECT_EQ(0U, map.find(4U));
|
||||
}
|
||||
|
||||
TEST(UniqueIntegerMap, AddOne) {
|
||||
MyMap map;
|
||||
uintptr_t key1 = 1U;
|
||||
uint32_t val1 = map.add(key1);
|
||||
|
||||
EXPECT_NE(0U, val1);
|
||||
EXPECT_EQ(val1, map.find(key1));
|
||||
EXPECT_EQ(key1, map.findKeyFor(val1));
|
||||
|
||||
EXPECT_FALSE(map.empty());
|
||||
EXPECT_EQ(1U, map.size());
|
||||
|
||||
EXPECT_EQ(0U, map.find(0));
|
||||
EXPECT_EQ(0U, map.findKeyFor(0));
|
||||
|
||||
EXPECT_EQ(0U, map.find(key1 + 1));
|
||||
EXPECT_EQ(0U, map.findKeyFor(val1 + 1));
|
||||
}
|
||||
|
||||
TEST(UniqueIntegerMap, AddMultiple) {
|
||||
MyMap map;
|
||||
const size_t kCount = 100;
|
||||
const size_t kKeyMultiplier = 3U; // must be >= 2.
|
||||
uint32_t values[kCount];
|
||||
|
||||
for (size_t n = 0; n < kCount; ++n) {
|
||||
uintptr_t key = 1U + n * kKeyMultiplier;
|
||||
values[n] = map.add(key);
|
||||
EXPECT_NE(0U, values[n]) << "key #" << n;
|
||||
}
|
||||
|
||||
EXPECT_EQ(kCount, map.size());
|
||||
|
||||
for (size_t n = 0; n < kCount; ++n) {
|
||||
uintptr_t key = 1U + n * kKeyMultiplier;
|
||||
EXPECT_EQ(values[n], map.find(key)) << "key #" << n;
|
||||
EXPECT_EQ(0U, map.find(key + 1U)) << "key #" << n;
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < kCount; ++n) {
|
||||
uintptr_t key = 1U + n * kKeyMultiplier;
|
||||
EXPECT_EQ(key, map.findKeyFor(values[n]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UniqueIntegerMap, Del) {
|
||||
MyMap map;
|
||||
const size_t kCount = 100;
|
||||
const size_t kKeyMultiplier = 3U; // must be >= 2.
|
||||
uint32_t values[kCount];
|
||||
|
||||
for (size_t n = 0; n < kCount; ++n) {
|
||||
uintptr_t key = 1U + n * kKeyMultiplier;
|
||||
values[n] = map.add(key);
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < kCount; ++n) {
|
||||
uintptr_t key = 1U + n * kKeyMultiplier;
|
||||
map.del(key);
|
||||
EXPECT_EQ(kCount - 1U - n, map.size());
|
||||
EXPECT_EQ(0U, map.find(key));
|
||||
EXPECT_EQ(0U, map.findKeyFor(values[n]));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(map.empty());
|
||||
}
|
||||
|
||||
} // namespace emugl
|
||||
Loading…
Add table
Add a link
Reference in a new issue