Serenity Operating System
at hosted 505 lines 20 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/BufferStream.h> 28#include <AK/Function.h> 29#include <AK/HashMap.h> 30#include <AK/StringBuilder.h> 31#include <LibCore/File.h> 32#include <ctype.h> 33#include <stdio.h> 34 35//#define GENERATE_DEBUG_CODE 36 37struct Parameter { 38 String type; 39 String name; 40}; 41 42struct Message { 43 String name; 44 bool is_synchronous { false }; 45 Vector<Parameter> inputs; 46 Vector<Parameter> outputs; 47 48 String response_name() const 49 { 50 StringBuilder builder; 51 builder.append(name); 52 builder.append("Response"); 53 return builder.to_string(); 54 } 55}; 56 57struct Endpoint { 58 String name; 59 int magic; 60 Vector<Message> messages; 61}; 62 63int main(int argc, char** argv) 64{ 65 AK::dbg_raw(true); 66 67 if (argc != 2) { 68 printf("usage: %s <IPC endpoint definition file>\n", argv[0]); 69 return 0; 70 } 71 72 auto file = Core::File::construct(argv[1]); 73 if (!file->open(Core::IODevice::ReadOnly)) { 74 fprintf(stderr, "Error: Cannot open %s: %s\n", argv[1], file->error_string()); 75 return 1; 76 } 77 78 auto file_contents = file->read_all(); 79 80 Vector<Endpoint> endpoints; 81 82 Vector<char> buffer; 83 84 size_t index = 0; 85 86 auto peek = [&](size_t offset = 0) -> char { 87 if ((index + offset) < file_contents.size()) 88 return file_contents[index + offset]; 89 return 0; 90 }; 91 92 auto consume_one = [&]() -> char { 93 return file_contents[index++]; 94 }; 95 96 auto extract_while = [&](Function<bool(char)> condition) -> String { 97 StringBuilder builder; 98 while (condition(peek())) 99 builder.append(consume_one()); 100 return builder.to_string(); 101 }; 102 103 auto consume_specific = [&](char ch) { 104 if (peek() != ch) { 105 warn() << "consume_specific: wanted '" << ch << "', but got '" << peek() << "' at index " << index; 106 } 107 ASSERT(peek() == ch); 108 ++index; 109 return ch; 110 }; 111 112 auto consume_string = [&](const char* str) { 113 for (size_t i = 0, length = strlen(str); i < length; ++i) 114 consume_specific(str[i]); 115 }; 116 117 auto consume_whitespace = [&] { 118 while (isspace(peek())) 119 ++index; 120 if (peek() == '/' && peek(1) == '/') { 121 while (peek() != '\n') 122 ++index; 123 } 124 }; 125 126 auto parse_parameter = [&](Vector<Parameter>& storage) { 127 for (;;) { 128 Parameter parameter; 129 consume_whitespace(); 130 if (peek() == ')') 131 break; 132 parameter.type = extract_while([](char ch) { return !isspace(ch); }); 133 consume_whitespace(); 134 parameter.name = extract_while([](char ch) { return !isspace(ch) && ch != ',' && ch != ')'; }); 135 consume_whitespace(); 136 storage.append(move(parameter)); 137 if (peek() == ',') { 138 consume_one(); 139 continue; 140 } 141 if (peek() == ')') 142 break; 143 } 144 }; 145 146 auto parse_parameters = [&](Vector<Parameter>& storage) { 147 for (;;) { 148 consume_whitespace(); 149 parse_parameter(storage); 150 consume_whitespace(); 151 if (peek() == ',') { 152 consume_one(); 153 continue; 154 } 155 if (peek() == ')') 156 break; 157 } 158 }; 159 160 auto parse_message = [&] { 161 Message message; 162 consume_whitespace(); 163 Vector<char> buffer; 164 while (!isspace(peek()) && peek() != '(') 165 buffer.append(consume_one()); 166 message.name = String::copy(buffer); 167 consume_whitespace(); 168 consume_specific('('); 169 parse_parameters(message.inputs); 170 consume_specific(')'); 171 consume_whitespace(); 172 consume_specific('='); 173 174 auto type = consume_one(); 175 if (type == '>') 176 message.is_synchronous = true; 177 else if (type == '|') 178 message.is_synchronous = false; 179 else 180 ASSERT_NOT_REACHED(); 181 182 consume_whitespace(); 183 184 if (message.is_synchronous) { 185 consume_specific('('); 186 parse_parameters(message.outputs); 187 consume_specific(')'); 188 } 189 190 consume_whitespace(); 191 192 endpoints.last().messages.append(move(message)); 193 }; 194 195 auto parse_messages = [&] { 196 for (;;) { 197 consume_whitespace(); 198 parse_message(); 199 consume_whitespace(); 200 if (peek() == '}') 201 break; 202 } 203 }; 204 205 auto parse_endpoint = [&] { 206 endpoints.empend(); 207 consume_whitespace(); 208 consume_string("endpoint"); 209 consume_whitespace(); 210 endpoints.last().name = extract_while([](char ch) { return !isspace(ch); }); 211 consume_whitespace(); 212 consume_specific('='); 213 consume_whitespace(); 214 auto magic_string = extract_while([](char ch) { return !isspace(ch) && ch != '{'; }); 215 bool ok; 216 endpoints.last().magic = magic_string.to_int(ok); 217 ASSERT(ok); 218 consume_whitespace(); 219 consume_specific('{'); 220 parse_messages(); 221 consume_specific('}'); 222 consume_whitespace(); 223 }; 224 225 while (index < file_contents.size()) 226 parse_endpoint(); 227 228 out() << "#pragma once"; 229 out() << "#include <AK/BufferStream.h>"; 230 out() << "#include <AK/OwnPtr.h>"; 231 out() << "#include <LibGfx/Color.h>"; 232 out() << "#include <LibGfx/Rect.h>"; 233 out() << "#include <LibGfx/ShareableBitmap.h>"; 234 out() << "#include <LibIPC/Decoder.h>"; 235 out() << "#include <LibIPC/Encoder.h>"; 236 out() << "#include <LibIPC/Endpoint.h>"; 237 out() << "#include <LibIPC/Message.h>"; 238 out(); 239 240 for (auto& endpoint : endpoints) { 241 out() << "namespace Messages {"; 242 out() << "namespace " << endpoint.name << " {"; 243 out(); 244 245 HashMap<String, int> message_ids; 246 247 out() << "enum class MessageID : i32 {"; 248 for (auto& message : endpoint.messages) { 249 message_ids.set(message.name, message_ids.size() + 1); 250 out() << " " << message.name << " = " << message_ids.size() << ","; 251 if (message.is_synchronous) { 252 message_ids.set(message.response_name(), message_ids.size() + 1); 253 out() << " " << message.response_name() << " = " << message_ids.size() << ","; 254 } 255 } 256 out() << "};"; 257 out(); 258 259 auto constructor_for_message = [&](const String& name, const Vector<Parameter>& parameters) { 260 StringBuilder builder; 261 builder.append(name); 262 263 if (parameters.is_empty()) { 264 builder.append("() {}"); 265 return builder.to_string(); 266 } 267 268 builder.append('('); 269 for (size_t i = 0; i < parameters.size(); ++i) { 270 auto& parameter = parameters[i]; 271 builder.append("const "); 272 builder.append(parameter.type); 273 builder.append("& "); 274 builder.append(parameter.name); 275 if (i != parameters.size() - 1) 276 builder.append(", "); 277 } 278 builder.append(") : "); 279 for (size_t i = 0; i < parameters.size(); ++i) { 280 auto& parameter = parameters[i]; 281 builder.append("m_"); 282 builder.append(parameter.name); 283 builder.append("("); 284 builder.append(parameter.name); 285 builder.append(")"); 286 if (i != parameters.size() - 1) 287 builder.append(", "); 288 } 289 builder.append(" {}"); 290 return builder.to_string(); 291 }; 292 293 auto do_message = [&](const String& name, const Vector<Parameter>& parameters, const String& response_type = {}) { 294 out() << "class " << name << " final : public IPC::Message {"; 295 out() << "public:"; 296 if (!response_type.is_null()) 297 out() << " typedef class " << response_type << " ResponseType;"; 298 out() << " " << constructor_for_message(name, parameters); 299 out() << " virtual ~" << name << "() override {}"; 300 out() << " virtual i32 endpoint_magic() const override { return " << endpoint.magic << "; }"; 301 out() << " virtual i32 message_id() const override { return (int)MessageID::" << name << "; }"; 302 out() << " static i32 static_message_id() { return (int)MessageID::" << name << "; }"; 303 out() << " virtual const char* message_name() const override { return \"" << endpoint.name << "::" << name << "\"; }"; 304 out() << " static OwnPtr<" << name << "> decode(BufferStream& stream, size_t& size_in_bytes)"; 305 out() << " {"; 306 307 out() << " IPC::Decoder decoder(stream);"; 308 309 for (auto& parameter : parameters) { 310 String initial_value = "{}"; 311 if (parameter.type == "bool") 312 initial_value = "false"; 313 out() << " " << parameter.type << " " << parameter.name << " = " << initial_value << ";"; 314 315 if (parameter.type == "Vector<Gfx::Rect>") { 316 out() << " u64 " << parameter.name << "_size = 0;"; 317 out() << " stream >> " << parameter.name << "_size;"; 318 out() << " for (size_t i = 0; i < " << parameter.name << "_size; ++i) {"; 319 out() << " Gfx::Rect rect;"; 320 out() << " if (!decoder.decode(rect))"; 321 out() << " return nullptr;"; 322 out() << " " << parameter.name << ".append(move(rect));"; 323 out() << " }"; 324 } else { 325 out() << " if (!decoder.decode(" << parameter.name << "))"; 326 out() << " return nullptr;"; 327 } 328 } 329 330 StringBuilder builder; 331 for (size_t i = 0; i < parameters.size(); ++i) { 332 auto& parameter = parameters[i]; 333 builder.append(parameter.name); 334 if (i != parameters.size() - 1) 335 builder.append(", "); 336 } 337 out() << " size_in_bytes = stream.offset();"; 338 out() << " return make<" << name << ">(" << builder.to_string() << ");"; 339 out() << " }"; 340 out() << " virtual IPC::MessageBuffer encode() const override"; 341 out() << " {"; 342 out() << " IPC::MessageBuffer buffer;"; 343 out() << " IPC::Encoder stream(buffer);"; 344 out() << " stream << endpoint_magic();"; 345 out() << " stream << (int)MessageID::" << name << ";"; 346 for (auto& parameter : parameters) { 347 if (parameter.type == "Gfx::Color") { 348 out() << " stream << m_" << parameter.name << ".value();"; 349 } else if (parameter.type == "Gfx::Size") { 350 out() << " stream << m_" << parameter.name << ".width();"; 351 out() << " stream << m_" << parameter.name << ".height();"; 352 } else if (parameter.type == "Gfx::Point") { 353 out() << " stream << m_" << parameter.name << ".x();"; 354 out() << " stream << m_" << parameter.name << ".y();"; 355 } else if (parameter.type == "Gfx::Rect") { 356 out() << " stream << m_" << parameter.name << ".x();"; 357 out() << " stream << m_" << parameter.name << ".y();"; 358 out() << " stream << m_" << parameter.name << ".width();"; 359 out() << " stream << m_" << parameter.name << ".height();"; 360 } else if (parameter.type == "Vector<Gfx::Rect>") { 361 out() << " stream << (u64)m_" << parameter.name << ".size();"; 362 out() << " for (auto& rect : m_" << parameter.name << ") {"; 363 out() << " stream << rect.x();"; 364 out() << " stream << rect.y();"; 365 out() << " stream << rect.width();"; 366 out() << " stream << rect.height();"; 367 out() << " }"; 368 } else if (parameter.type == "Gfx::ShareableBitmap") { 369 out() << " stream << m_" << parameter.name << ".shbuf_id();"; 370 out() << " stream << m_" << parameter.name << ".width();"; 371 out() << " stream << m_" << parameter.name << ".height();"; 372 } else { 373 out() << " stream << m_" << parameter.name << ";"; 374 } 375 } 376 out() << " return buffer;"; 377 out() << " }"; 378 for (auto& parameter : parameters) { 379 out() << " const " << parameter.type << "& " << parameter.name << "() const { return m_" << parameter.name << "; }"; 380 } 381 out() << "private:"; 382 for (auto& parameter : parameters) { 383 out() << " " << parameter.type << " m_" << parameter.name << ";"; 384 } 385 out() << "};"; 386 out(); 387 }; 388 for (auto& message : endpoint.messages) { 389 String response_name; 390 if (message.is_synchronous) { 391 response_name = message.response_name(); 392 do_message(response_name, message.outputs); 393 } 394 do_message(message.name, message.inputs, response_name); 395 } 396 out() << "} // namespace " << endpoint.name; 397 out() << "} // namespace Messages"; 398 out(); 399 400 out() << "class " << endpoint.name << "Endpoint : public IPC::Endpoint {"; 401 out() << "public:"; 402 out() << " " << endpoint.name << "Endpoint() {}"; 403 out() << " virtual ~" << endpoint.name << "Endpoint() override {}"; 404 out() << " static int static_magic() { return " << endpoint.magic << "; }"; 405 out() << " virtual int magic() const override { return " << endpoint.magic << "; }"; 406 out() << " static String static_name() { return \"" << endpoint.name << "\"; };"; 407 out() << " virtual String name() const override { return \"" << endpoint.name << "\"; };"; 408 out() << " static OwnPtr<IPC::Message> decode_message(const ByteBuffer& buffer, size_t& size_in_bytes)"; 409 out() << " {"; 410 out() << " BufferStream stream(const_cast<ByteBuffer&>(buffer));"; 411 out() << " i32 message_endpoint_magic = 0;"; 412 out() << " stream >> message_endpoint_magic;"; 413 out() << " if (message_endpoint_magic != " << endpoint.magic << ") {"; 414#ifdef GENERATE_DEBUG_CODE 415 sout() << " sout() << \"endpoint magic \" << message_endpoint_magic << \" != " << endpoint.magic << "\";"; 416#endif 417 out() << " return nullptr;"; 418 out() << " }"; 419 out() << " i32 message_id = 0;"; 420 out() << " stream >> message_id;"; 421 out() << " switch (message_id) {"; 422 for (auto& message : endpoint.messages) { 423 auto do_decode_message = [&](const String& name) { 424 out() << " case (int)Messages::" << endpoint.name << "::MessageID::" << name << ":"; 425 out() << " return Messages::" << endpoint.name << "::" << name << "::decode(stream, size_in_bytes);"; 426 }; 427 do_decode_message(message.name); 428 if (message.is_synchronous) 429 do_decode_message(message.response_name()); 430 } 431 out() << " default:"; 432#ifdef GENERATE_DEBUG_CODE 433 sout() << " sout() << \"Failed to decode " << endpoint.name << ".(\" << message_id << \")\";"; 434#endif 435 out() << " return nullptr;"; 436 437 out() << " }"; 438 out() << " }"; 439 out(); 440 out() << " virtual OwnPtr<IPC::Message> handle(const IPC::Message& message) override"; 441 out() << " {"; 442 out() << " switch (message.message_id()) {"; 443 for (auto& message : endpoint.messages) { 444 auto do_decode_message = [&](const String& name, bool returns_something) { 445 out() << " case (int)Messages::" << endpoint.name << "::MessageID::" << name << ":"; 446 if (returns_something) { 447 out() << " return handle(static_cast<const Messages::" << endpoint.name << "::" << name << "&>(message));"; 448 } else { 449 out() << " handle(static_cast<const Messages::" << endpoint.name << "::" << name << "&>(message));"; 450 out() << " return nullptr;"; 451 } 452 }; 453 do_decode_message(message.name, message.is_synchronous); 454 if (message.is_synchronous) 455 do_decode_message(message.response_name(), false); 456 } 457 out() << " default:"; 458 out() << " return nullptr;"; 459 460 out() << " }"; 461 out() << " }"; 462 463 for (auto& message : endpoint.messages) { 464 String return_type = "void"; 465 if (message.is_synchronous) { 466 StringBuilder builder; 467 builder.append("OwnPtr<Messages::"); 468 builder.append(endpoint.name); 469 builder.append("::"); 470 builder.append(message.name); 471 builder.append("Response"); 472 builder.append(">"); 473 return_type = builder.to_string(); 474 } 475 out() << " virtual " << return_type << " handle(const Messages::" << endpoint.name << "::" << message.name << "&) = 0;"; 476 } 477 478 out() << "private:"; 479 out() << "};"; 480 } 481 482#ifdef IPC_DEBUG 483 for (auto& endpoint : endpoints) { 484 warn() << "Endpoint: '" << endpoint.name << "' (magic: " << endpoint.magic << ")"; 485 for (auto& message : endpoint.messages) { 486 warn() << " Message: '" << message.name << "'"; 487 warn() << " Sync: " << message.is_synchronous; 488 warn() << " Inputs:"; 489 for (auto& parameter : message.inputs) 490 warn() << " Parameter: " << parameter.name << " (" << parameter.type << ")"; 491 if (message.inputs.is_empty()) 492 warn() << " (none)"; 493 if (message.is_synchronous) { 494 warn() << " Outputs:"; 495 for (auto& parameter : message.outputs) 496 warn() << " Parameter: " << parameter.name << " (" << parameter.type << ")"; 497 if (message.outputs.is_empty()) 498 warn() << " (none)"; 499 } 500 } 501 } 502#endif 503 504 return 0; 505}