1 //* Copyright 2019 The Dawn Authors 2 //* 3 //* Licensed under the Apache License, Version 2.0 (the "License"); 4 //* you may not use this file except in compliance with the License. 5 //* You may obtain a copy of the License at 6 //* 7 //* http://www.apache.org/licenses/LICENSE-2.0 8 //* 9 //* Unless required by applicable law or agreed to in writing, software 10 //* distributed under the License is distributed on an "AS IS" BASIS, 11 //* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 //* See the License for the specific language governing permissions and 13 //* limitations under the License. 14 15 #include "common/Assert.h" 16 #include "dawn_wire/server/Server.h" 17 18 namespace dawn_wire { namespace server { 19 {% for command in cmd_records["command"] %} 20 {% set method = command.derived_method %} 21 {% set is_method = method != None %} 22 {% set returns = is_method and method.return_type.name.canonical_case() != "void" %} 23 24 {% set Suffix = command.name.CamelCase() %} 25 //* The generic command handlers 26 bool Server::Handle{{Suffix}}(DeserializeBuffer* deserializeBuffer) { 27 {{Suffix}}Cmd cmd; 28 WireResult deserializeResult = cmd.Deserialize(deserializeBuffer, &mAllocator 29 {%- if command.may_have_dawn_object -%} 30 , *this 31 {%- endif -%} 32 ); 33 34 if (deserializeResult == WireResult::FatalError) { 35 return false; 36 } 37 38 {% if Suffix in server_custom_pre_handler_commands %} 39 if (!PreHandle{{Suffix}}(cmd)) { 40 return false; 41 } 42 {% endif %} 43 44 //* Allocate any result objects 45 {%- for member in command.members if member.is_return_value -%} 46 {{ assert(member.handle_type) }} 47 {% set Type = member.handle_type.name.CamelCase() %} 48 {% set name = as_varName(member.name) %} 49 50 auto* {{name}}Data = {{Type}}Objects().Allocate(cmd.{{name}}.id); 51 if ({{name}}Data == nullptr) { 52 return false; 53 } 54 {{name}}Data->generation = cmd.{{name}}.generation; 55 56 //* TODO(crbug.com/dawn/384): This is a hack to make sure that all child objects 57 //* are destroyed before their device. The dawn_native device needs to track all child objects so 58 //* it can destroy them if the device is destroyed first. 59 {% if command.derived_object %} 60 {% set type = command.derived_object %} 61 {% if type.name.get() == "device" %} 62 {{name}}Data->deviceInfo = DeviceObjects().Get(cmd.selfId)->info.get(); 63 {% else %} 64 auto* selfData = {{type.name.CamelCase()}}Objects().Get(cmd.selfId); 65 {{name}}Data->deviceInfo = selfData->deviceInfo; 66 {% endif %} 67 if ({{name}}Data->deviceInfo != nullptr) { 68 if (!TrackDeviceChild({{name}}Data->deviceInfo, ObjectType::{{Type}}, cmd.{{name}}.id)) { 69 return false; 70 } 71 } 72 {% endif %} 73 {% endfor %} 74 75 //* Do command 76 bool success = Do{{Suffix}}( 77 {%- for member in command.members -%} 78 {%- if member.is_return_value -%} 79 {%- if member.handle_type -%} 80 &{{as_varName(member.name)}}Data->handle //* Pass the handle of the output object to be written by the doer 81 {%- else -%} 82 &cmd.{{as_varName(member.name)}} 83 {%- endif -%} 84 {%- else -%} 85 cmd.{{as_varName(member.name)}} 86 {%- endif -%} 87 {%- if not loop.last -%}, {% endif %} 88 {%- endfor -%} 89 ); 90 91 if (!success) { 92 return false; 93 } 94 95 {%- for member in command.members if member.is_return_value and member.handle_type -%} 96 {% set Type = member.handle_type.name.CamelCase() %} 97 {% set name = as_varName(member.name) %} 98 99 {% if Type in server_reverse_lookup_objects %} 100 //* For created objects, store a mapping from them back to their client IDs 101 {{Type}}ObjectIdTable().Store({{name}}Data->handle, cmd.{{name}}.id); 102 {% endif %} 103 {% endfor %} 104 105 return true; 106 } 107 {% endfor %} 108 109 const volatile char* Server::HandleCommandsImpl(const volatile char* commands, size_t size) { 110 DeserializeBuffer deserializeBuffer(commands, size); 111 112 while (deserializeBuffer.AvailableSize() >= sizeof(CmdHeader) + sizeof(WireCmd)) { 113 // Start by chunked command handling, if it is done, then it means the whole buffer 114 // was consumed by it, so we return a pointer to the end of the commands. 115 switch (HandleChunkedCommands(deserializeBuffer.Buffer(), deserializeBuffer.AvailableSize())) { 116 case ChunkedCommandsResult::Consumed: 117 return commands + size; 118 case ChunkedCommandsResult::Error: 119 return nullptr; 120 case ChunkedCommandsResult::Passthrough: 121 break; 122 } 123 124 WireCmd cmdId = *static_cast<const volatile WireCmd*>(static_cast<const volatile void*>( 125 deserializeBuffer.Buffer() + sizeof(CmdHeader))); 126 bool success = false; 127 switch (cmdId) { 128 {% for command in cmd_records["command"] %} 129 case WireCmd::{{command.name.CamelCase()}}: 130 success = Handle{{command.name.CamelCase()}}(&deserializeBuffer); 131 break; 132 {% endfor %} 133 default: 134 success = false; 135 } 136 137 if (!success) { 138 return nullptr; 139 } 140 mAllocator.Reset(); 141 } 142 143 if (deserializeBuffer.AvailableSize() != 0) { 144 return nullptr; 145 } 146 147 return commands; 148 } 149 150 }} // namespace dawn_wire::server 151