diff options
author | gman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-11 00:29:35 +0000 |
---|---|---|
committer | gman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-11 00:29:35 +0000 |
commit | 6689dbbb7832c151d6d846b6ed55445a6c979f20 (patch) | |
tree | 3b570d0bd063a1e50b821d924d13f6beb8741ef4 /o3d/core | |
parent | f68b7fa0fc9b002a9db4d499cc7e0c7c7636be8a (diff) | |
download | chromium_src-6689dbbb7832c151d6d846b6ed55445a6c979f20.zip chromium_src-6689dbbb7832c151d6d846b6ed55445a6c979f20.tar.gz chromium_src-6689dbbb7832c151d6d846b6ed55445a6c979f20.tar.bz2 |
Add UpdateTexure2DRect to IMC
Also refactored IMC for to be more safe and easy
to use.
It still needs:
*) structures/wrappers for message responces
*) Some of the error checking could probably be
moved out of the inidivdual message processing
functions
*) Need some constants or wrappers for the
handles so a message isn't pulling things
out of handles by magic numbers.
Review URL: http://codereview.chromium.org/165266
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22987 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/core')
-rw-r--r-- | o3d/core/build.scons | 1 | ||||
-rw-r--r-- | o3d/core/core.gyp | 3 | ||||
-rw-r--r-- | o3d/core/cross/message_commands.cc | 50 | ||||
-rw-r--r-- | o3d/core/cross/message_commands.h | 292 | ||||
-rw-r--r-- | o3d/core/cross/message_commands_test.cc | 47 | ||||
-rw-r--r-- | o3d/core/cross/message_queue.cc | 344 | ||||
-rw-r--r-- | o3d/core/cross/message_queue.h | 129 | ||||
-rw-r--r-- | o3d/core/cross/message_queue_test.cc | 483 | ||||
-rw-r--r-- | o3d/core/cross/packing.h | 66 |
9 files changed, 983 insertions, 432 deletions
diff --git a/o3d/core/build.scons b/o3d/core/build.scons index e155919..c332368 100644 --- a/o3d/core/build.scons +++ b/o3d/core/build.scons @@ -74,6 +74,7 @@ cross_inputs = [ 'cross/matrix4_composition.cc', 'cross/matrix4_scale.cc', 'cross/matrix4_translation.cc', + 'cross/message_commands.cc', 'cross/message_queue.cc', 'cross/named_object.cc', 'cross/object_base.cc', diff --git a/o3d/core/core.gyp b/o3d/core/core.gyp index e0644a1..2cf7794 100644 --- a/o3d/core/core.gyp +++ b/o3d/core/core.gyp @@ -144,6 +144,8 @@ 'cross/matrix4_scale.h', 'cross/matrix4_translation.cc', 'cross/matrix4_translation.h', + 'cross/message_commands.cc', + 'cross/message_commands.h', 'cross/message_queue.cc', 'cross/message_queue.h', 'cross/named_object.cc', @@ -380,6 +382,7 @@ 'cross/matrix4_composition_test.cc', 'cross/matrix4_scale_test.cc', 'cross/matrix4_translation_test.cc', + 'cross/message_commands_test.cc', 'cross/message_queue_test.cc', 'cross/object_base_test.cc', 'cross/pack_test.cc', diff --git a/o3d/core/cross/message_commands.cc b/o3d/core/cross/message_commands.cc new file mode 100644 index 0000000..631f518 --- /dev/null +++ b/o3d/core/cross/message_commands.cc @@ -0,0 +1,50 @@ +/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file contains string descriptions of various IMC messages for O3D.
+
+#include "core/cross/precompile.h"
+#include "core/cross/message_commands.h"
+
+namespace o3d {
+
+const char* IMCMessage::GetMessageDescription(IMCMessage::MessageId id) {
+ const char* const message_descriptions[] = {
+ #define O3D_IMC_MESSAGE_OP(id, class_name) #id,
+ O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP)
+ #undef O3D_IMC_MESSAGE_OP
+ };
+ return message_descriptions[id];
+}
+
+} // namespace o3d
+
+
diff --git a/o3d/core/cross/message_commands.h b/o3d/core/cross/message_commands.h new file mode 100644 index 0000000..bb14f9b --- /dev/null +++ b/o3d/core/cross/message_commands.h @@ -0,0 +1,292 @@ +/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This file contains the declarations of various IMC messages for O3D.
+
+#ifndef O3D_CORE_CROSS_MESSAGE_COMMANDS_H_
+#define O3D_CORE_CROSS_MESSAGE_COMMANDS_H_
+
+#include "core/cross/types.h"
+#include "core/cross/packing.h"
+
+namespace o3d {
+
+// Make sure the compiler does not add extra padding to any of the message
+// structures.
+O3D_PUSH_STRUCTURE_PACKING_1;
+
+// This macro is used to safely and convienently expand the list of possible IMC
+// messages in to various lists and never have them get out of sync. To add a
+// new message add a this list, the first argument is the enum Id, the second
+// argument is the name of the structure that describes the message. Once you've
+// added it to this list, create the structure below and then add a function in
+// message_queue.cc called ProcessMessageStructureName where
+// MessageStructureName is the name of your message structure.
+//
+// NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
+#define O3D_IMC_MESSAGE_LIST(OP) \
+ OP(INVALID_ID, MessageInvalidId) \
+ OP(HELLO, MessageHello) \
+ OP(ALLOCATE_SHARED_MEMORY, MessageAllocateSharedMemory) \
+ OP(UPDATE_TEXTURE2D, MessageUpdateTexture2D) \
+ OP(REGISTER_SHARED_MEMORY, MessageRegisterSharedMemory) \
+ OP(UNREGISTER_SHARED_MEMORY, MessageUnregisterSharedMemory) \
+ OP(UPDATE_TEXTURE2D_RECT, MessageUpdateTexture2DRect) \
+
+
+// The base of all IMCMessages
+struct IMCMessage {
+ enum MessageId {
+ #define O3D_IMC_MESSAGE_OP(id, class_name) id,
+ O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP)
+ #undef O3D_IMC_MESSAGE_OP
+
+ MAX_NUM_IDS,
+
+ ID_FORCE_DWORD = 0x7fffffff // Forces a 32-bit size enum
+ };
+
+ explicit IMCMessage(MessageId id) : message_id(id) {
+ }
+
+ // Returns a string by message ID.
+ static const char* GetMessageDescription(MessageId id);
+
+ int32 message_id;
+};
+
+// An invalid message. This is mostly a place holder for id 0.
+struct MessageInvalidId : public IMCMessage {
+ static const IMCMessage::MessageId kMessageId = INVALID_ID;
+
+ MessageInvalidId()
+ : IMCMessage(kMessageId) {
+ }
+};
+
+// The first message you send.
+struct MessageHello : public IMCMessage {
+ static const IMCMessage::MessageId kMessageId = HELLO;
+
+ MessageHello()
+ : IMCMessage(kMessageId) {
+ }
+};
+
+// A message to allocate shared memory
+struct MessageAllocateSharedMemory : public IMCMessage {
+ static const MessageId kMessageId = ALLOCATE_SHARED_MEMORY;
+ static const int32 kMaxSharedMemSize = 1024 * 1024 * 128; // 128MB
+
+ MessageAllocateSharedMemory()
+ : IMCMessage(kMessageId) {
+ }
+
+ // Parameters:
+ // in_mem_size: The number of bytes to allocate.
+ explicit MessageAllocateSharedMemory(int32 in_mem_size)
+ : IMCMessage(kMessageId),
+ mem_size(in_mem_size) {
+ }
+
+ // The amount of memory to allocate.
+ int32 mem_size;
+};
+
+// A message to register shared memory.
+struct MessageRegisterSharedMemory : public IMCMessage {
+ static const MessageId kMessageId = REGISTER_SHARED_MEMORY;
+ static const int32 kMaxSharedMemSize = 1024 * 1024 * 128; // 128MB
+
+ MessageRegisterSharedMemory()
+ : IMCMessage(kMessageId) {
+ }
+ explicit MessageRegisterSharedMemory(int32 in_mem_size)
+ : IMCMessage(kMessageId),
+ mem_size(in_mem_size) {
+ }
+
+ int32 mem_size;
+};
+
+// A message to unregister shared memory.
+struct MessageUnregisterSharedMemory : public IMCMessage {
+ static const MessageId kMessageId = UNREGISTER_SHARED_MEMORY;
+
+ MessageUnregisterSharedMemory()
+ : IMCMessage(kMessageId) {
+ }
+
+ // Parameters:
+ // in_buffer_id: The id of the buffer to unregister.
+ explicit MessageUnregisterSharedMemory(int32 in_buffer_id)
+ : IMCMessage(kMessageId),
+ buffer_id(in_buffer_id) {
+ }
+
+ int32 buffer_id;
+};
+
+// A message to update the entire contents of a 2D texture. The number
+// of bytes MUST equal the size of the entire texture to be updated including
+// all mips.
+struct MessageUpdateTexture2D : public IMCMessage {
+ static const MessageId kMessageId = UPDATE_TEXTURE2D;
+
+ MessageUpdateTexture2D()
+ : IMCMessage(kMessageId) {
+ }
+
+ // Parameters:
+ // in_texture_id: The id of the texture to set.
+ // in_level: The mip level of the texture to set.
+ // in_shared_memory_id: The id of the shared memory the contains the data
+ // to use to set the texture.
+ // in_offset: The offset inside the shared memory where the texture data
+ // starts.
+ // in_number_of_bytes: The number of bytes to get out of shared memory.
+ // NOTE: this number MUST match the size of the texture. For example for
+ // an ARGB texture it must be mip_width * mip_height * 4 * sizeof(uint8)
+ MessageUpdateTexture2D(Id in_texture_id,
+ int32 in_level,
+ int32 in_shared_memory_id,
+ int32 in_offset,
+ int32 in_number_of_bytes)
+ : IMCMessage(kMessageId),
+ texture_id(in_texture_id),
+ level(in_level),
+ shared_memory_id(in_shared_memory_id),
+ offset(in_offset),
+ number_of_bytes(in_number_of_bytes) {
+ }
+
+ // The id of the texture to set.
+ Id texture_id;
+
+ // The mip level of the texture to set.
+ int32 level;
+
+ // The id of the shared memory the contains the data to use to set the
+ // texture.
+ int32 shared_memory_id;
+
+ // The offset inside the shared memory where the texture data starts.
+ int32 offset;
+
+ // The number of bytes to get out of shared memory.
+ // NOTE: this number MUST match the size of the texture. For example for an
+ // ARGB texture it must be mip_width * mip_height * 4 * sizeof(uint8)
+ int32 number_of_bytes;
+};
+
+// A message to update a portion of a 2D texture. The number of bytes MUST equal
+// the size of the portion of the texture to be updated.
+struct MessageUpdateTexture2DRect : public IMCMessage {
+ static const MessageId kMessageId = UPDATE_TEXTURE2D_RECT;
+
+ MessageUpdateTexture2DRect()
+ : IMCMessage(kMessageId) {
+ }
+
+ // Parameters:
+ // in_texture_id: The id of the texture to set.
+ // in_level: The mip level of the texture to set.
+ // in_x: The left edge of the rectangle to update in the texture.
+ // in_y: The top edge of the rectangle to update in the texture.
+ // in_width: The width of the rectangle to update in the texture.
+ // in_height: The height of the rectangle to update in the texture.
+ // in_shared_memory_id: The id of the shared memory the contains the data to
+ // use to set the texture.
+ // in_offset: The offset inside the shared memory where the texture data
+ // starts.
+ // in_number_of_bytes: The number of bytes to get out of shared memory.
+ // NOTE: this number MUST match the size of the area in the texture to
+ // be updated. For example for an ARGB texture it must be
+ // width * height 4 * sizeof(uint8)
+ MessageUpdateTexture2DRect(Id in_texture_id,
+ int32 in_level,
+ int32 in_x,
+ int32 in_y,
+ int32 in_width,
+ int32 in_height,
+ int32 in_shared_memory_id,
+ int32 in_offset,
+ int32 in_number_of_bytes)
+ : IMCMessage(kMessageId),
+ texture_id(in_texture_id),
+ level(in_level),
+ x(in_x),
+ y(in_y),
+ width(in_width),
+ height(in_height),
+ shared_memory_id(in_shared_memory_id),
+ offset(in_offset),
+ number_of_bytes(in_number_of_bytes) {
+ }
+
+ // The id of the texture to set.
+ Id texture_id;
+
+ // The mip level of the texture to set.
+ int32 level;
+
+ // The left edge of the rectangle to update in the texture.
+ int32 x;
+
+ // The top edge of the rectangle to update in the texture.
+ int32 y;
+
+ // The width of the rectangle to update in the texture.
+ int32 width;
+
+ // The height of the rectangle to update in the texture.
+ int32 height;
+
+ // The id of the shared memory the contains the data to use to set the
+ // texture.
+ int32 shared_memory_id;
+
+ // The offset inside the shared memory where the texture data starts.
+ int32 offset;
+
+ // The number of bytes to get out of shared memory.
+ // NOTE: this number MUST match the size of the area in the texture to be
+ // updated. For example for an ARGB texture it must be
+ // width * height 4 * sizeof(uint8)
+ int32 number_of_bytes;
+};
+
+O3D_POP_STRUCTURE_PACKING;
+
+} // namespace o3d
+
+#endif // O3D_CORE_CROSS_MESSAGE_COMMANDS_H_
+
diff --git a/o3d/core/cross/message_commands_test.cc b/o3d/core/cross/message_commands_test.cc new file mode 100644 index 0000000..93459a2 --- /dev/null +++ b/o3d/core/cross/message_commands_test.cc @@ -0,0 +1,47 @@ +/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/cross/message_commands.h"
+#include "tests/common/win/testing_common.h"
+
+namespace o3d {
+
+class MessageCommandsTest : public testing::Test {
+};
+
+TEST_F(MessageCommandsTest, GetMessageDescription) {
+ EXPECT_STREQ(IMCMessage::GetMessageDescription(
+ IMCMessage::ALLOCATE_SHARED_MEMORY), "ALLOCATE_SHARED_MEMORY");
+};
+
+} // namespace o3d
+
+
diff --git a/o3d/core/cross/message_queue.cc b/o3d/core/cross/message_queue.cc index 7e24767..9b6e6bf 100644 --- a/o3d/core/cross/message_queue.cc +++ b/o3d/core/cross/message_queue.cc @@ -44,6 +44,7 @@ #include "core/cross/bitmap.h" #include "core/cross/texture.h" #include "core/cross/error.h" +#include "core/cross/pointer_utils.h" #ifdef OS_WIN #include "core/cross/core_metrics.h" @@ -77,8 +78,8 @@ ConnectedClient::~ConnectedClient() { // Unmap and close shared memory. for (iter = shared_memory_array_.begin(); iter < shared_memory_array_.end(); ++iter) { - nacl::Unmap(iter->mapped_address_, iter->size_); - nacl::Close(iter->shared_memory_handle_); + nacl::Unmap(iter->mapped_address, iter->size); + nacl::Close(iter->shared_memory_handle); } } @@ -90,10 +91,10 @@ void ConnectedClient::RegisterSharedMemory(int32 buffer_id, void *address, int32 size) { SharedMemoryInfo shared_mem; - shared_mem.buffer_id_ = buffer_id; - shared_mem.shared_memory_handle_ = handle; - shared_mem.mapped_address_ = address; - shared_mem.size_ = size; + shared_mem.buffer_id = buffer_id; + shared_mem.shared_memory_handle = handle; + shared_mem.mapped_address = address; + shared_mem.size = size; shared_memory_array_.push_back(shared_mem); } @@ -104,9 +105,9 @@ bool ConnectedClient::UnregisterSharedMemory(int32 buffer_id) { std::vector<SharedMemoryInfo>::iterator iter; for (iter = shared_memory_array_.begin(); iter < shared_memory_array_.end(); ++iter) { - if (iter->buffer_id_ == buffer_id) { - nacl::Unmap(iter->mapped_address_, iter->size_); - nacl::Close(iter->shared_memory_handle_); + if (iter->buffer_id == buffer_id) { + nacl::Unmap(iter->mapped_address, iter->size); + nacl::Close(iter->shared_memory_handle); shared_memory_array_.erase(iter); return true; } @@ -121,7 +122,7 @@ const SharedMemoryInfo* ConnectedClient::GetSharedMemoryInfo(int32 id) const { std::vector<SharedMemoryInfo>::const_iterator iter; for (iter = shared_memory_array_.begin(); iter < shared_memory_array_.end(); ++iter) { - if (iter->buffer_id_ == id) { + if (iter->buffer_id == id) { return &(*iter); } } @@ -220,13 +221,13 @@ bool MessageQueue::CheckForNewMessages() { // ReceiveMessageFromSocket also returns true if there are no // messages in the queue in which case message_length will be equal // to -1. - MessageId message_id; + IMCMessage::MessageId message_id; int message_length = 0; if (ReceiveMessageFromSocket(server_socket_handle_, &header, &message_id, &message_length)) { - if (message_id == HELLO) { + if (message_id == IMCMessage::HELLO) { ProcessHelloMessage(&header, handles); #ifdef OS_WIN metric_imc_hello_msg.Set(true); @@ -276,9 +277,9 @@ bool MessageQueue::CheckForNewMessages() { // return the ID in message_id. bool MessageQueue::ReceiveMessageFromSocket(nacl::Handle socket, nacl::MessageHeader* header, - MessageId* message_id, + IMCMessage::MessageId* message_id, int* length) { - *message_id = INVALID_ID; + *message_id = IMCMessage::INVALID_ID; // Check if there's a new message but don't block waiting for it. int message_length = nacl::ReceiveDatagram(socket, @@ -323,8 +324,10 @@ bool MessageQueue::ReceiveMessageFromSocket(nacl::Handle socket, } // Extract the ID of the message just received. - MessageId id_found = *(reinterpret_cast<MessageId*>(header->iov[0].base)); - if (id_found <= INVALID_ID || id_found >= MAX_NUM_IDS) { + IMCMessage::MessageId id_found = + *(reinterpret_cast<IMCMessage::MessageId*>(header->iov[0].base)); + if (id_found <= IMCMessage::INVALID_ID || + id_found >= IMCMessage::MAX_NUM_IDS) { LOG(ERROR) << "Unknown ID found in message :" << id_found; } *message_id = id_found; @@ -339,36 +342,35 @@ bool MessageQueue::ReceiveMessageFromSocket(nacl::Handle socket, bool MessageQueue::ProcessClientRequest(ConnectedClient* client, int message_length, - MessageId message_id, + IMCMessage::MessageId message_id, nacl::MessageHeader* header, nacl::Handle* handles) { + static size_t expected_message_lengths[] = { + #define O3D_IMC_MESSAGE_OP(id, class_name) sizeof(class_name), + O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP) + #undef O3D_IMC_MESSAGE_OP + }; + + if (message_id == IMCMessage::INVALID_ID || + message_id >= arraysize(expected_message_lengths)) { + LOG(ERROR) << "Unrecognized message id " << message_id; + return false; + } + + if (message_length != expected_message_lengths[message_id]) { + LOG(ERROR) << "Bad message length for " + << IMCMessage::GetMessageDescription(message_id); + return false; + } + switch (message_id) { - case ALLOCATE_SHARED_MEMORY: - return ProcessAllocateSharedMemory(client, - message_length, - message_id, - header, - handles); - case UPDATE_TEXTURE2D: - return ProcessUpdateTexture2D(client, - message_length, - message_id, - header, - handles); - case REGISTER_SHARED_MEMORY: - return ProcessRegisterSharedMemory(client, - message_length, - message_id, - header, - handles); - case UNREGISTER_SHARED_MEMORY: - return ProcessUnregisterSharedMemory(client, - message_length, - message_id, - header, - handles); + #define O3D_IMC_MESSAGE_OP(id, class_name) \ + case IMCMessage::id: return Process ## class_name( \ + client, message_length, header, handles, \ + *static_cast<const class_name*>(header->iov[0].base)); + O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP) + #undef O3D_IMC_MESSAGE_OP default: - LOG(ERROR) << "Unrecognized message id " << message_id; return false; } @@ -434,34 +436,50 @@ bool MessageQueue::ProcessHelloMessage(nacl::MessageHeader *header, return false; } +// All emums need a Process function. +bool MessageQueue::ProcessMessageInvalidId( + ConnectedClient* client, + int message_length, + nacl::MessageHeader* header, + nacl::Handle* handles, + const MessageInvalidId& message) { + return false; +} + +bool MessageQueue::ProcessMessageHello( + ConnectedClient* client, + int message_length, + nacl::MessageHeader* header, + nacl::Handle* handles, + const MessageHello& message) { + // Hello is handled special. + return false; +} // Processes a request to allocate a shared memory buffer on behalf of a // connected client. Parses the arguments of the message to determine how // much space is requested, it creates the shared memory buffer, maps it in // the local address space and sends a message back to the client with the // newly created memory handle. -bool MessageQueue::ProcessAllocateSharedMemory(ConnectedClient* client, - int message_length, - MessageId message_id, - nacl::MessageHeader* header, - nacl::Handle* handles) { - int32 mem_size = 0; - int expected_message_length = sizeof(message_id) + sizeof(mem_size); - - if (message_length != expected_message_length || - header->iov_length != 1 || +bool MessageQueue::ProcessMessageAllocateSharedMemory( + ConnectedClient* client, + int message_length, + nacl::MessageHeader* header, + nacl::Handle* handles, + const MessageAllocateSharedMemory& message) { + + if (header->iov_length != 1 || header->handle_count != 0) { LOG(ERROR) << "Malformed message for ALLOCATE_SHARED_MEMORY"; return false; } - char* message_buffer = static_cast<char*>(header->iov[0].base); - message_buffer += sizeof(message_id); - mem_size = *(reinterpret_cast<int32*>(message_buffer)); - const int32 kMaxSharedMemSize = 1024 * 1024 * 100; // 100MB - if (mem_size <= 0 || mem_size > kMaxSharedMemSize) { + int32 mem_size = message.mem_size; + if (mem_size <= 0 || + mem_size > MessageAllocateSharedMemory::kMaxSharedMemSize) { LOG(ERROR) << "Invalid mem size requested: " << mem_size - << "(max size = " << kMaxSharedMemSize << ")"; + << "(max size = " + << MessageAllocateSharedMemory::kMaxSharedMemSize << ")"; return false; } @@ -523,92 +541,163 @@ bool MessageQueue::ProcessAllocateSharedMemory(ConnectedClient* client, // Texture object, the level to be modified and the number of bytes to copy. // This is essentially asynchronous as the client will not receive a response // back from the server -bool MessageQueue::ProcessUpdateTexture2D(ConnectedClient* client, - int message_length, - MessageId message_id, - nacl::MessageHeader* header, - nacl::Handle* handles) { - int32 offset = 0; - Id texture_id = 0; - int32 level = 0; - int32 number_of_bytes = 0; - int32 shared_memory_id = -1; - +bool MessageQueue::ProcessMessageUpdateTexture2D( + ConnectedClient* client, + int message_length, + nacl::MessageHeader* header, + nacl::Handle* handles, + const MessageUpdateTexture2D& message) { // Check the length of the message to make sure it contains the size of // the requested buffer. - int expected_message_length = sizeof(message_id)+ - sizeof(texture_id)+ - sizeof(level)+ - sizeof(shared_memory_id)+ - sizeof(offset)+ - sizeof(number_of_bytes); - - if (message_length != expected_message_length || - header->iov_length != 1 || + if (header->iov_length != 1 || header->handle_count != 0) { LOG(ERROR) << "Malformed message for UPDATE_TEXTURE"; SendBooleanResponse(client->client_handle(), false); return false; } - char* message_buffer = static_cast<char*>(header->iov[0].base); - message_buffer += sizeof(message_id); - texture_id = *(reinterpret_cast<Id*>(message_buffer)); - message_buffer += sizeof(texture_id); - level = *(reinterpret_cast<int32*>(message_buffer)); - message_buffer += sizeof(level); - shared_memory_id = *(reinterpret_cast<int*>(message_buffer)); - message_buffer += sizeof(shared_memory_id); - offset = *(reinterpret_cast<int32*>(message_buffer)); - message_buffer += sizeof(offset); - number_of_bytes = *(reinterpret_cast<int32*>(message_buffer)); - message_buffer += sizeof(number_of_bytes); - // Check that this client did actually allocate the shared memory // corresponding to this handle. const SharedMemoryInfo* info = - client->GetSharedMemoryInfo(shared_memory_id); + client->GetSharedMemoryInfo(message.shared_memory_id); + if (info == NULL) { + O3D_ERROR(service_locator_) + << "shared memory id " << message.shared_memory_id << " not found"; + SendBooleanResponse(client->client_handle(), false); + return false; + } // Check that the Id passed in actually corresponds to a texture. Texture2D* texture_object = - object_manager_->GetById<Texture2D>(texture_id); + object_manager_->GetById<Texture2D>(message.texture_id); if (texture_object == NULL) { O3D_ERROR(service_locator_) - << "Texture with id " << texture_id << " not found"; + << "Texture with id " << message.texture_id << " not found"; SendBooleanResponse(client->client_handle(), false); return false; } // Check that we will not be reading past the end of the allocated shared // memory. - if (offset + number_of_bytes > info->size_) { + if (message.offset + message.number_of_bytes > info->size) { O3D_ERROR(service_locator_) << "Offset + texture size exceed allocated shared memory size (" - << offset << " + " << number_of_bytes << " > " << info->size_; + << message.offset << " + " << message.number_of_bytes << " > " + << info->size; SendBooleanResponse(client->client_handle(), false); return false; } unsigned int mip_width = - image::ComputeMipDimension(level, texture_object->width()); + image::ComputeMipDimension(message.level, texture_object->width()); unsigned int mip_height = - image::ComputeMipDimension(level, texture_object->height()); + image::ComputeMipDimension(message.level, texture_object->height()); - if (static_cast<unsigned>(number_of_bytes) != + if (static_cast<unsigned>(message.number_of_bytes) != image::ComputeMipChainSize(mip_width, mip_height, texture_object->format(), 1)) { O3D_ERROR(service_locator_) << "texture_size does not match size of texture level (" - << offset << " + " << number_of_bytes << " > " << info->size_; + << message.offset << " + " << message.number_of_bytes << " > " + << info->size; + SendBooleanResponse(client->client_handle(), false); + return false; + } + + void *target_address = + static_cast<char*>(info->mapped_address) + message.offset; + texture_object->SetRect( + message.level, 0, 0, mip_width, mip_height, target_address, + image::ComputePitch(texture_object->format(), mip_width)); + + SendBooleanResponse(client->client_handle(), true); + return true; +} + +bool MessageQueue::ProcessMessageUpdateTexture2DRect( + ConnectedClient* client, + int message_length, + nacl::MessageHeader* header, + nacl::Handle* handles, + const MessageUpdateTexture2DRect& message) { + // Check the length of the message to make sure it contains the size of + // the requested buffer. + if (header->iov_length != 1 || + header->handle_count != 0) { + LOG(ERROR) << "Malformed message for UPDATE_TEXTURE_RECT"; + SendBooleanResponse(client->client_handle(), false); + return false; + } + + // Check that this client did actually allocate the shared memory + // corresponding to this handle. + const SharedMemoryInfo* info = + client->GetSharedMemoryInfo(message.shared_memory_id); + if (info == NULL) { + O3D_ERROR(service_locator_) + << "shared memory id " << message.shared_memory_id << " not found"; + SendBooleanResponse(client->client_handle(), false); + return false; + } + + // Check that the Id passed in actually corresponds to a texture. + Texture2D* texture_object = + object_manager_->GetById<Texture2D>(message.texture_id); + + if (texture_object == NULL) { + O3D_ERROR(service_locator_) + << "Texture with id " << message.texture_id << " not found"; + SendBooleanResponse(client->client_handle(), false); + return false; + } + + // Check that we will not be reading past the end of the allocated shared + // memory. + if (message.offset + message.number_of_bytes > info->size) { + O3D_ERROR(service_locator_) + << "Offset + texture size exceed allocated shared memory size (" + << message.offset << " + " << message.number_of_bytes << " > " + << info->size; + SendBooleanResponse(client->client_handle(), false); + return false; + } + + unsigned int mip_width = + image::ComputeMipDimension(message.level, texture_object->width()); + unsigned int mip_height = + image::ComputeMipDimension(message.level, texture_object->height()); + + if (message.x < 0 || message.width < 0 || + message.y < 0 || message.height < 0 || + message.x + message.width > mip_width || + message.y + message.height > mip_height) { + O3D_ERROR(service_locator_) + << "rect out of range (" + << message.x << ", " << message.y << ", " << message.width + << message.height << ")"; SendBooleanResponse(client->client_handle(), false); return false; } - void *target_address = static_cast<char*>(info->mapped_address_) + offset; + if (static_cast<unsigned>(message.number_of_bytes) != + image::ComputeMipChainSize(message.width, message.height, + texture_object->format(), + 1)) { + O3D_ERROR(service_locator_) + << "number of bytes does not match size of texture rect (" + << message.offset << " + " << message.number_of_bytes << " > " + << info->size; + SendBooleanResponse(client->client_handle(), false); + return false; + } + + void *target_address = + static_cast<char*>(info->mapped_address) + message.offset; texture_object->SetRect( - level, 0, 0, mip_width, mip_height, target_address, + message.level, message.x, message.y, message.width, message.height, + target_address, image::ComputePitch(texture_object->format(), mip_width)); SendBooleanResponse(client->client_handle(), true); @@ -621,28 +710,24 @@ bool MessageQueue::ProcessUpdateTexture2D(ConnectedClient* client, // the shared memory buffer into the local address space and sends a // message back to the client with the newly allocated shared memory // ID. -bool MessageQueue::ProcessRegisterSharedMemory(ConnectedClient* client, - int message_length, - MessageId message_id, - nacl::MessageHeader* header, - nacl::Handle* handles) { - int32 mem_size = 0; - int expected_message_length = sizeof(message_id) + sizeof(mem_size); - - if (message_length != expected_message_length || - header->iov_length != 1 || +bool MessageQueue::ProcessMessageRegisterSharedMemory( + ConnectedClient* client, + int message_length, + nacl::MessageHeader* header, + nacl::Handle* handles, + const MessageRegisterSharedMemory& message) { + if (header->iov_length != 1 || header->handle_count != 1) { LOG(ERROR) << "Malformed message for REGISTER_SHARED_MEMORY"; return false; } - char* message_buffer = static_cast<char*>(header->iov[0].base); - message_buffer += sizeof(message_id); - mem_size = *(reinterpret_cast<int32*>(message_buffer)); - const int32 kMaxSharedMemSize = 1024 * 1024 * 100; // 100MB - if (mem_size <= 0 || mem_size > kMaxSharedMemSize) { + int32 mem_size = message.mem_size; + if (mem_size <= 0 || + mem_size > MessageRegisterSharedMemory::kMaxSharedMemSize) { LOG(ERROR) << "Invalid mem size sent: " << mem_size - << "(max size = " << kMaxSharedMemSize << ")"; + << "(max size = " + << MessageRegisterSharedMemory::kMaxSharedMemSize << ")"; return false; } @@ -699,26 +784,19 @@ bool MessageQueue::ProcessRegisterSharedMemory(ConnectedClient* client, // Processes a request to unregister a client-allocated shared memory // buffer, referenced by ID. -bool MessageQueue::ProcessUnregisterSharedMemory(ConnectedClient* client, - int message_length, - MessageId message_id, - nacl::MessageHeader* header, - nacl::Handle* handles) { - int32 buffer_id = 0; - int expected_message_length = sizeof(message_id) + sizeof(buffer_id); - - if (message_length != expected_message_length || - header->iov_length != 1 || +bool MessageQueue::ProcessMessageUnregisterSharedMemory( + ConnectedClient* client, + int message_length, + nacl::MessageHeader* header, + nacl::Handle* handles, + const MessageUnregisterSharedMemory& message) { + if (header->iov_length != 1 || header->handle_count != 0) { LOG(ERROR) << "Malformed message for UNREGISTER_SHARED_MEMORY"; return false; } - char* message_buffer = static_cast<char*>(header->iov[0].base); - message_buffer += sizeof(message_id); - buffer_id = *(reinterpret_cast<int32*>(message_buffer)); - - bool res = client->UnregisterSharedMemory(buffer_id); + bool res = client->UnregisterSharedMemory(message.buffer_id); SendBooleanResponse(client->client_handle(), res); return res; } diff --git a/o3d/core/cross/message_queue.h b/o3d/core/cross/message_queue.h index 50e7f4d..7226064 100644 --- a/o3d/core/cross/message_queue.h +++ b/o3d/core/cross/message_queue.h @@ -40,6 +40,7 @@ #include <vector> #include "native_client/src/shared/imc/nacl_imc.h" #include "core/cross/types.h" +#include "core/cross/message_commands.h" namespace o3d { @@ -48,17 +49,17 @@ class ObjectManager; // Structure keeping information about shared memory regions created on the // request of a client connection. -typedef struct { +struct SharedMemoryInfo { // Unique (to the MessageQueue object that created it) id of the shared // memory buffer. - int buffer_id_; + int buffer_id; // Handle to the shared memory. - nacl::Handle shared_memory_handle_; + nacl::Handle shared_memory_handle; // Address to which it maps in the local memory space. - void* mapped_address_; + void* mapped_address; // Size in bytes - int32 size_; -} SharedMemoryInfo; + int32 size; +}; // The ConnectedClient class holds information about clients that have made // contact with the this instance of the server. @@ -97,8 +98,9 @@ class ConnectedClient { nacl::Handle client_handle_; std::vector<SharedMemoryInfo> shared_memory_array_; -}; + DISALLOW_COPY_AND_ASSIGN(ConnectedClient); +}; // The MessageQueue class handles the communcation between external code and // O3D. It provides methods for initializing the communcation channel @@ -106,20 +108,6 @@ class ConnectedClient { // the NativeClient Inter-Module Communication (IMC) library. class MessageQueue { public: - enum MessageId { - INVALID_ID = 0, - HELLO, // Handshake between the client and the server - ALLOCATE_SHARED_MEMORY, // Request to allocate a shared memory buffer - UPDATE_TEXTURE2D, // Request to update a 2D texture bitmap - REGISTER_SHARED_MEMORY, // Register a client-allocated shared memory - // buffer, returning a shared memory ID - UNREGISTER_SHARED_MEMORY, // Unregister a client-allocated shared - // memory ID - MAX_NUM_IDS, - - ID_FORCE_DWORD = 0x7fffffff // Forces a 32-bit size enum - }; - // Creates a MessageQueue that is able to receive messages and execute calls // to the given Client object. explicit MessageQueue(ServiceLocator* service_locator); @@ -156,7 +144,7 @@ class MessageQueue { // Client. bool ProcessClientRequest(ConnectedClient* client, int message_length, - MessageId message_id, + IMCMessage::MessageId message_id, nacl::MessageHeader* header, nacl::Handle* handles); @@ -170,86 +158,17 @@ class MessageQueue { // true if the new client connected successfully. bool ProcessHelloMessage(nacl::MessageHeader* header, nacl::Handle* handles); - // Processes a request by a connected client to allocate a shared memory - // buffer. The size of the requested buffer is determined from the data - // passed in the message. Once the memory is allocated, a message containing - // the shared memory handle is sent back to the client. - // Parameters: - // client - pointer to the ConnectedClient the request came from. - // message_length - length of the received message in bytes. - // message_id - id of the request received by the message - // header - message header containing information about the received - // message. - // handles - the array of handles referenced by the header. - // Returns: - // true if the message is properly formed and is succesfully handled by the - // Client. - bool ProcessAllocateSharedMemory(ConnectedClient* client, - int message_length, - MessageId message_id, - nacl::MessageHeader* header, - nacl::Handle* handles); - - // Processes a request by a connected client to update the contents of the - // bitmap corresponding to a Texture2D object. - // Parameters: - // client - pointer to the ConnectedClient the request came from. - // message_length - length of the received message in bytes. - // message_id - id of the request received by the message - // header - message header containing information about the received - // message. - // handles - the array of handles referenced by the header. - // Returns: - // true if the message is properly formed and is succesfully handled by the - // Client. - bool ProcessUpdateTexture2D(ConnectedClient* client, - int message_length, - MessageId message_id, - nacl::MessageHeader* header, - nacl::Handle* handles); - - // Processes a request by a connected client to register a - // client-allocated shared memory buffer with O3D. The size of the - // buffer is determined from the data passed in the message. Once - // the shared memory buffer has been mapped and registered, a - // message containing the shared memory ID is sent back to the - // client. This ID can be used to update the contents of a Texture2D - // object. - // Parameters: - // client - pointer to the ConnectedClient the request came from. - // message_length - length of the received message in bytes. - // message_id - id of the request received by the message - // header - message header containing information about the received - // message. - // handles - the array of handles referenced by the header. - // Returns: - // true if the message is properly formed and is succesfully handled by the - // Client. - bool ProcessRegisterSharedMemory(ConnectedClient* client, - int message_length, - MessageId message_id, - nacl::MessageHeader* header, - nacl::Handle* handles); - - // Processes a request by a connected client to unregister a shared - // memory buffer previously registered with O3D. The shared memory - // buffer is referenced by the ID returned from - // RegisterSharedMemory. - // Parameters: - // client - pointer to the ConnectedClient the request came from. - // message_length - length of the received message in bytes. - // message_id - id of the request received by the message - // header - message header containing information about the received - // message. - // handles - the array of handles referenced by the header. - // Returns: - // true if the message is properly formed and is succesfully handled by the - // Client. - bool ProcessUnregisterSharedMemory(ConnectedClient* client, - int message_length, - MessageId message_id, - nacl::MessageHeader* header, - nacl::Handle* handles); + // Declare all the message processing functions. For each type of message + // will declare a function called Process<MessageName>. + #define O3D_IMC_MESSAGE_OP(id, class_name) \ + bool Process ## class_name( \ + ConnectedClient* client, \ + int message_length, \ + nacl::MessageHeader* header, \ + nacl::Handle* handles, \ + const class_name& message); + O3D_IMC_MESSAGE_LIST(O3D_IMC_MESSAGE_OP) + #undef O3D_IMC_MESSAGE_OP // Sends a true of false (1 or 0) message using the given socket handle. // Parameters: @@ -271,11 +190,9 @@ class MessageQueue { // false in every other case. bool ReceiveMessageFromSocket(nacl::Handle socket, nacl::MessageHeader* header, - MessageId* message_id, + IMCMessage::MessageId* message_id, int* message_length); - private: - ServiceLocator* service_locator_; ObjectManager* object_manager_; @@ -296,6 +213,8 @@ class MessageQueue { // us to create multiple instances of the MessageQueue, each with a unique // address. static int next_message_queue_id_; + + DISALLOW_COPY_AND_ASSIGN(MessageQueue); }; diff --git a/o3d/core/cross/message_queue_test.cc b/o3d/core/cross/message_queue_test.cc index 5a0d30f..ac34ad8 100644 --- a/o3d/core/cross/message_queue_test.cc +++ b/o3d/core/cross/message_queue_test.cc @@ -49,6 +49,7 @@ using ::base::TimeDelta; namespace o3d { +namespace { //---------------------------------------------------------------------- // These are helper classes for the little multithreaded test harness // below. @@ -207,128 +208,6 @@ class TestProvider { }; //---------------------------------------------------------------------- -// This is the main class containing all of the other ones. It knows -// how to run multiple concurrent PerThreadConnectedTests. -class MessageQueueTest : public testing::Test { - protected: - MessageQueueTest() - : object_manager_(g_service_locator), - socket_handles_(NULL), - num_socket_handles_(0) {} - - virtual void SetUp(); - virtual void TearDown(); - - // This is the entry point for test cases that need to be run in one - // or more threads. - void RunTests(int num_threads, - TimeDelta timeout, - TestProvider* test_provider); - - Pack* pack() { return pack_; } - - private: - ServiceDependency<ObjectManager> object_manager_; - Pack *pack_; - nacl::Handle* socket_handles_; - int num_socket_handles_; - - // This can't be part of SetUp since it needs to be called from each - // individual test. - void ConfigureSockets(int number_of_clients); - - nacl::Handle GetSocketHandle(int i) { - // We would use ASSERT_ here, but that doesn't seem to work from - // within methods that have non-void return types. - EXPECT_TRUE(socket_handles_ != NULL); - EXPECT_LT(i, num_socket_handles_); - return socket_handles_[i]; - } -}; - -void MessageQueueTest::SetUp() { - pack_ = object_manager_->CreatePack(); - pack_->set_name("MessageQueueTest pack"); -} - -void MessageQueueTest::ConfigureSockets(int number_of_clients) { - ASSERT_GT(number_of_clients, 0); - num_socket_handles_ = number_of_clients; - socket_handles_ = new nacl::Handle[num_socket_handles_]; - ASSERT_TRUE(socket_handles_ != NULL); - for (int i = 0; i < num_socket_handles_; i++) { - nacl::SocketAddress socket_address; - ::base::snprintf(socket_address.path, - sizeof(socket_address.path), - "%s%d", - "test-client", - i); - socket_handles_[i] = nacl::BoundSocket(&socket_address); - ASSERT_NE(nacl::kInvalidHandle, socket_handles_[i]); - } -} - -void MessageQueueTest::TearDown() { - if (socket_handles_ != NULL) { - for (int i = 0; i < num_socket_handles_; i++) { - nacl::Close(socket_handles_[i]); - } - delete[] socket_handles_; - socket_handles_ = NULL; - num_socket_handles_ = 0; - } - - object_manager_->DestroyPack(pack_); -} - -void MessageQueueTest::RunTests(int num_threads, - TimeDelta timeout, - TestProvider* provider) { - MessageQueue* message_queue = new MessageQueue(g_service_locator); - message_queue->Initialize(); - - TimeSource* time_source = new WallClockTimeSource(); - TestWatchdog* watchdog = new TestWatchdog(num_threads, - timeout, - time_source); - PerThreadConnectedTest** tests = new PerThreadConnectedTest*[num_threads]; - ASSERT_TRUE(tests != NULL); - PlatformThreadHandle* thread_handles = new PlatformThreadHandle[num_threads]; - ASSERT_TRUE(thread_handles != NULL); - ConfigureSockets(num_threads); - for (int i = 0; i < num_threads; i++) { - tests[i] = provider->CreateTest(); - ASSERT_TRUE(tests[i] != NULL); - tests[i]->Configure(message_queue, GetSocketHandle(i), watchdog); - } - // Now that all tests are created, start them up - for (int i = 0; i < num_threads; i++) { - ASSERT_TRUE(PlatformThread::Create(0, tests[i], &thread_handles[i])); - } - // Wait for completion - while (!watchdog->Done()) { - ASSERT_TRUE(message_queue->CheckForNewMessages()); - watchdog->WaitBrieflyForSignal(); - } - ASSERT_FALSE(watchdog->Expired()); - ASSERT_TRUE(watchdog->Succeeded()); - for (int i = 0; i < num_threads; i++) { - PerThreadConnectedTest* test = tests[i]; - ASSERT_TRUE(test->Passed()) << test->FailureMessage(); - // Only join the thread and delete the test if it completed - if (test->Completed()) { - PlatformThread::Join(thread_handles[i]); - delete test; - } - } - delete[] thread_handles; - delete[] tests; - delete watchdog; - delete time_source; - delete message_queue; -} - -//---------------------------------------------------------------------- // This is a helper class that handles connecting to the MessageQueue // and issuing commands to it. class TextureUpdateHelper { @@ -351,6 +230,17 @@ class TextureUpdateHelper { size_t offset, size_t number_of_bytes); + // Makes a request to update a portion of a texture. + bool RequestTextureRectUpdate(unsigned int texture_id, + int level, + int x, + int y, + int width, + int height, + int shared_memory_id, + size_t offset, + size_t number_of_bytes); + // Registers a client-allocated shared memory segment with O3D, // returning O3D's shared memory ID for later updating. Returns -1 // upon failure. @@ -402,17 +292,11 @@ bool TextureUpdateHelper::ConnectToO3D(const char* o3d_address, return false; } - char buffer[128]; - int message_size = 0; - MessageQueue::MessageId *msg_id = - reinterpret_cast<MessageQueue::MessageId*>(buffer); - *msg_id = MessageQueue::HELLO; - message_size += sizeof(*msg_id); - + MessageHello msg; nacl::MessageHeader header; nacl::IOVec vec; - vec.base = buffer; - vec.length = message_size; + vec.base = &msg; + vec.length = sizeof(msg); nacl::SocketAddress socket_address; ::base::snprintf(socket_address.path, @@ -428,8 +312,8 @@ bool TextureUpdateHelper::ConnectToO3D(const char* o3d_address, 0, &socket_address); - EXPECT_EQ(message_size, result); - if (result != message_size) { + EXPECT_EQ(sizeof(msg), static_cast<size_t>(result)); + if (static_cast<size_t>(result) != sizeof(msg)) { return false; } @@ -458,22 +342,12 @@ bool TextureUpdateHelper::RequestSharedMemory(size_t requested_size, return false; } - MessageQueue::MessageId message_id = MessageQueue::ALLOCATE_SHARED_MEMORY; - + MessageAllocateSharedMemory msg(requested_size); nacl::MessageHeader header; nacl::IOVec vec; - char buffer[256]; - char *buffer_ptr = &buffer[0]; - // Message contains the ID and one argument (the size of the shared memory - // buffer to be allocated). - *(reinterpret_cast<MessageQueue::MessageId*>(buffer_ptr)) = message_id; - buffer_ptr += sizeof(message_id); - *(reinterpret_cast<size_t*>(buffer_ptr)) = requested_size; - buffer_ptr += sizeof(requested_size); - - vec.base = buffer; - vec.length = buffer_ptr - &buffer[0]; + vec.base = &msg; + vec.length = sizeof(msg); header.iov = &vec; header.iov_length = 1; @@ -541,37 +415,63 @@ bool TextureUpdateHelper::RequestTextureUpdate(unsigned int texture_id, int shared_memory_id, size_t offset, size_t number_of_bytes) { - MessageQueue::MessageId message_id = MessageQueue::UPDATE_TEXTURE2D; + MessageUpdateTexture2D msg( + texture_id, level, shared_memory_id, offset, number_of_bytes); nacl::MessageHeader header; nacl::IOVec vec; - char buffer[256]; - char *buffer_ptr = &buffer[0]; - - // Message contains the message ID and two arguments, the id of the Texture - // object in O3D and the offset in the shared memory region where the - // bitmap is stored. - *(reinterpret_cast<MessageQueue::MessageId*>(buffer_ptr)) = message_id; - buffer_ptr += sizeof(message_id); - *(reinterpret_cast<unsigned int*>(buffer_ptr)) = texture_id; - buffer_ptr += sizeof(texture_id); - *(reinterpret_cast<int*>(buffer_ptr)) = level; - buffer_ptr += sizeof(level); - *(reinterpret_cast<int*>(buffer_ptr)) = shared_memory_id; - buffer_ptr += sizeof(shared_memory_id); - *(reinterpret_cast<size_t*>(buffer_ptr)) = offset; - buffer_ptr += sizeof(offset); - *(reinterpret_cast<size_t*>(buffer_ptr)) = number_of_bytes; - buffer_ptr += sizeof(number_of_bytes); - - vec.base = buffer; - vec.length = buffer_ptr - &buffer[0]; + + vec.base = &msg; + vec.length = sizeof(msg); header.iov = &vec; header.iov_length = 1; header.handles = NULL; header.handle_count = 0; + // Send message. + int result = nacl::SendDatagram(o3d_handle_, &header, 0); + + EXPECT_EQ(vec.length, static_cast<unsigned>(result)); + + if (static_cast<unsigned>(result) != vec.length) { + return false; + } + + // Wait for a response from the server. If the server returns true then + // the texture update was successfully procesed. + bool texture_updated = ReceiveBooleanResponse(); + + EXPECT_TRUE(texture_updated); + + return texture_updated; +} + +// Sends a message to O3D to update the a potion of the contents of a texture +// using the data stored in shared memory. +bool TextureUpdateHelper::RequestTextureRectUpdate(unsigned int texture_id, + int level, + int x, + int y, + int width, + int height, + int shared_memory_id, + size_t offset, + size_t number_of_bytes) { + MessageUpdateTexture2DRect msg( + texture_id, level, x, y, width, height, + shared_memory_id, offset, number_of_bytes); + + nacl::MessageHeader header; + nacl::IOVec vec; + + vec.base = &msg; + vec.length = sizeof(msg); + + header.iov = &vec; + header.iov_length = 1; + header.handles = NULL; + header.handle_count = 0; // Send message. int result = nacl::SendDatagram(o3d_handle_, &header, 0); @@ -600,22 +500,13 @@ int TextureUpdateHelper::RegisterSharedMemory(nacl::Handle shared_memory, return false; } - MessageQueue::MessageId message_id = MessageQueue::REGISTER_SHARED_MEMORY; + MessageRegisterSharedMemory msg(static_cast<int32>(shared_memory_size)); nacl::MessageHeader header; nacl::IOVec vec; - char buffer[256]; - char *buffer_ptr = &buffer[0]; - - // Message contains the ID and one argument (the size of the shared memory - // buffer which has been allocated). - *(reinterpret_cast<MessageQueue::MessageId*>(buffer_ptr)) = message_id; - buffer_ptr += sizeof(message_id); - *(reinterpret_cast<size_t*>(buffer_ptr)) = shared_memory_size; - buffer_ptr += sizeof(shared_memory_size); - vec.base = buffer; - vec.length = buffer_ptr - &buffer[0]; + vec.base = &msg; + vec.length = sizeof(msg); header.iov = &vec; header.iov_length = 1; @@ -653,21 +544,12 @@ int TextureUpdateHelper::RegisterSharedMemory(nacl::Handle shared_memory, // Unregisters a previously-registered client-allocated shared // memory segment. bool TextureUpdateHelper::UnregisterSharedMemory(int shared_memory_id) { - MessageQueue::MessageId message_id = MessageQueue::UNREGISTER_SHARED_MEMORY; + MessageUnregisterSharedMemory msg(shared_memory_id); nacl::MessageHeader header; nacl::IOVec vec; - char buffer[256]; - char *buffer_ptr = &buffer[0]; - - // Message contains the message ID and the ID of the shared memory - // segment to release - *(reinterpret_cast<MessageQueue::MessageId*>(buffer_ptr)) = message_id; - buffer_ptr += sizeof(message_id); - *(reinterpret_cast<int*>(buffer_ptr)) = shared_memory_id; - buffer_ptr += sizeof(shared_memory_id); - - vec.base = buffer; - vec.length = buffer_ptr - buffer; + + vec.base = &msg; + vec.length = sizeof(msg); header.iov = &vec; header.iov_length = 1; header.handles = NULL; @@ -682,6 +564,131 @@ bool TextureUpdateHelper::UnregisterSharedMemory(int shared_memory_id) { return reply; } + +} // anonymous namespace. + +//---------------------------------------------------------------------- +// This is the main class containing all of the other ones. It knows +// how to run multiple concurrent PerThreadConnectedTests. +class MessageQueueTest : public testing::Test { + protected: + MessageQueueTest() + : object_manager_(g_service_locator), + socket_handles_(NULL), + num_socket_handles_(0) {} + + virtual void SetUp(); + virtual void TearDown(); + + // This is the entry point for test cases that need to be run in one + // or more threads. + void RunTests(int num_threads, + TimeDelta timeout, + TestProvider* test_provider); + + Pack* pack() { return pack_; } + + private: + ServiceDependency<ObjectManager> object_manager_; + Pack *pack_; + nacl::Handle* socket_handles_; + int num_socket_handles_; + + // This can't be part of SetUp since it needs to be called from each + // individual test. + void ConfigureSockets(int number_of_clients); + + nacl::Handle GetSocketHandle(int i) { + // We would use ASSERT_ here, but that doesn't seem to work from + // within methods that have non-void return types. + EXPECT_TRUE(socket_handles_ != NULL); + EXPECT_LT(i, num_socket_handles_); + return socket_handles_[i]; + } +}; + +void MessageQueueTest::SetUp() { + pack_ = object_manager_->CreatePack(); + pack_->set_name("MessageQueueTest pack"); +} + +void MessageQueueTest::ConfigureSockets(int number_of_clients) { + ASSERT_GT(number_of_clients, 0); + num_socket_handles_ = number_of_clients; + socket_handles_ = new nacl::Handle[num_socket_handles_]; + ASSERT_TRUE(socket_handles_ != NULL); + for (int i = 0; i < num_socket_handles_; i++) { + nacl::SocketAddress socket_address; + ::base::snprintf(socket_address.path, + sizeof(socket_address.path), + "%s%d", + "test-client", + i); + socket_handles_[i] = nacl::BoundSocket(&socket_address); + ASSERT_NE(nacl::kInvalidHandle, socket_handles_[i]); + } +} + +void MessageQueueTest::TearDown() { + if (socket_handles_ != NULL) { + for (int i = 0; i < num_socket_handles_; i++) { + nacl::Close(socket_handles_[i]); + } + delete[] socket_handles_; + socket_handles_ = NULL; + num_socket_handles_ = 0; + } + + object_manager_->DestroyPack(pack_); +} + +void MessageQueueTest::RunTests(int num_threads, + TimeDelta timeout, + TestProvider* provider) { + MessageQueue* message_queue = new MessageQueue(g_service_locator); + message_queue->Initialize(); + + TimeSource* time_source = new WallClockTimeSource(); + TestWatchdog* watchdog = new TestWatchdog(num_threads, + timeout, + time_source); + PerThreadConnectedTest** tests = new PerThreadConnectedTest*[num_threads]; + ASSERT_TRUE(tests != NULL); + PlatformThreadHandle* thread_handles = new PlatformThreadHandle[num_threads]; + ASSERT_TRUE(thread_handles != NULL); + ConfigureSockets(num_threads); + for (int i = 0; i < num_threads; i++) { + tests[i] = provider->CreateTest(); + ASSERT_TRUE(tests[i] != NULL); + tests[i]->Configure(message_queue, GetSocketHandle(i), watchdog); + } + // Now that all tests are created, start them up + for (int i = 0; i < num_threads; i++) { + ASSERT_TRUE(PlatformThread::Create(0, tests[i], &thread_handles[i])); + } + // Wait for completion + while (!watchdog->Done()) { + ASSERT_TRUE(message_queue->CheckForNewMessages()); + watchdog->WaitBrieflyForSignal(); + } + ASSERT_FALSE(watchdog->Expired()); + ASSERT_TRUE(watchdog->Succeeded()); + for (int i = 0; i < num_threads; i++) { + PerThreadConnectedTest* test = tests[i]; + ASSERT_TRUE(test->Passed()) << test->FailureMessage(); + // Only join the thread and delete the test if it completed + if (test->Completed()) { + PlatformThread::Join(thread_handles[i]); + delete test; + } + } + delete[] thread_handles; + delete[] tests; + delete watchdog; + delete time_source; + delete message_queue; +} + //---------------------------------------------------------------------- // Test cases follow. @@ -810,7 +817,7 @@ TEST_F(MessageQueueTest, UpdateTexture2D) { FAIL_TEST("Memory request failed"); } - int texture_buffer_size = 128*128*4; + int texture_buffer_size = 128 * 128 * 4; if (!helper.RequestTextureUpdate(texture_id_, 0, @@ -848,6 +855,92 @@ TEST_F(MessageQueueTest, UpdateTexture2D) { RunTests(1, TimeDelta::FromSeconds(1), &provider); } +// Tests a request to update a texture. +TEST_F(MessageQueueTest, UpdateTexture2DRect) { + class UpdateTexture2DRectTest : public PerThreadConnectedTest { + private: + int texture_id_; + + public: + explicit UpdateTexture2DRectTest(int texture_id) { + texture_id_ = texture_id; + } + + void Run(MessageQueue* queue, + nacl::Handle socket_handle) { + String socket_addr = queue->GetSocketAddress(); + TextureUpdateHelper helper; + if (!helper.ConnectToO3D(socket_addr.c_str(), + socket_handle)) { + FAIL_TEST("Failed to connect to O3D"); + } + + void *shared_mem_address = NULL; + int shared_mem_id = -1; + bool memory_ok = helper.RequestSharedMemory(65536, + &shared_mem_id, + &shared_mem_address); + if (shared_mem_id == -1) { + FAIL_TEST("Shared memory id was -1"); + } + + if (shared_mem_address == NULL) { + FAIL_TEST("Shared memory address was NULL"); + } + + if (!memory_ok) { + FAIL_TEST("Memory request failed"); + } + + const int kLevel = 0; + const int kX = 10; + const int kY = 11; + const int kWidth = 12; + const int kHeight = 13; + const int kTextureRectSize = kWidth * kHeight * 4; + + if (!helper.RequestTextureRectUpdate(texture_id_, + kLevel, + kX, + kY, + kWidth, + kHeight, + shared_mem_id, + 0, + kTextureRectSize)) { + FAIL_TEST("RequestTextureRectUpdate failed"); + } + + Pass(); + } + }; + + class Provider : public TestProvider { + private: + int texture_id_; + + public: + explicit Provider(int texture_id) : texture_id_(texture_id) {} + + virtual PerThreadConnectedTest* CreateTest() { + return new UpdateTexture2DRectTest(texture_id_); + } + }; + + Texture2D* texture = pack()->CreateTexture2D(128, + 128, + Texture::ARGB8, + 0, + false); + + ASSERT_TRUE(texture != NULL); + + Provider provider(texture->id()); + RunTests(1, TimeDelta::FromSeconds(1), &provider); +} + +namespace { + // This helper class is used for both single-threaded and concurrent // shared memory registration / unregistration tests. class SharedMemoryRegisterUnregisterTest : public PerThreadConnectedTest { @@ -897,6 +990,8 @@ class SharedMemoryRegisterUnregisterTest : public PerThreadConnectedTest { } }; +} // anonymous namespace. + // Tests that a simple shared memory registration and unregistration // pair appear to work. TEST_F(MessageQueueTest, RegisterAndUnregisterSharedMemory) { diff --git a/o3d/core/cross/packing.h b/o3d/core/cross/packing.h new file mode 100644 index 0000000..674ef09 --- /dev/null +++ b/o3d/core/cross/packing.h @@ -0,0 +1,66 @@ +/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file defines Packing macros for the packing of structures.
+
+#ifndef O3D_UTILS_CROSS_PACKING_H_
+#define O3D_UTILS_CROSS_PACKING_H_
+
+#if defined(COMPILER_GCC)
+
+// NOTE: I tried building the string as in
+// #define O3D_SET_STRUCTURE_PACKING(p) _Pragma("pack(" #p ")")
+// but gcc doesn't like that. :-(
+#define O3D_SET_STRUCTURE_PACKING_1 _Pragma("pack(1)")
+#define O3D_SET_STRUCTURE_PACKING_2 _Pragma("pack(2)")
+#define O3D_SET_STRUCTURE_PACKING_4 _Pragma("pack(4)")
+#define O3D_PUSH_STRUCTURE_PACKING_1 _Pragma("pack(push, 1)")
+#define O3D_PUSH_STRUCTURE_PACKING_2 _Pragma("pack(push, 2)")
+#define O3D_PUSH_STRUCTURE_PACKING_4 _Pragma("pack(push, 4)")
+#define O3D_POP_STRUCTURE_PACKING _Pragma("pack(pop)")
+
+#elif defined(COMPILER_MSVC)
+
+#define O3D_SET_STRUCTURE_PACKING_1 __pragma(pack(1))
+#define O3D_SET_STRUCTURE_PACKING_2 __pragma(pack(2))
+#define O3D_SET_STRUCTURE_PACKING_4 __pragma(pack(4))
+#define O3D_PUSH_STRUCTURE_PACKING_1 __pragma(pack(push, 1))
+#define O3D_PUSH_STRUCTURE_PACKING_2 __pragma(pack(push, 2))
+#define O3D_PUSH_STRUCTURE_PACKING_4 __pragma(pack(push, 4))
+#define O3D_POP_STRUCTURE_PACKING __pragma(pack(pop))
+
+#else
+#error Need Packing Macros
+#endif
+
+#endif // O3D_UTILS_CROSS_PACKING_H_
+
|