Process.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2022, MacDue <macdue@dueutil.tech>
  4. * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
  5. * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause
  8. */
  9. #pragma once
  10. #include <AK/ByteString.h>
  11. #include <AK/Forward.h>
  12. #include <AK/Span.h>
  13. #include <LibCore/File.h>
  14. namespace Core {
  15. namespace FileAction {
  16. struct OpenFile {
  17. ByteString path;
  18. File::OpenMode mode = File::OpenMode::NotOpen;
  19. int fd = -1;
  20. mode_t permissions = 0600;
  21. };
  22. struct CloseFile {
  23. int fd { -1 };
  24. };
  25. // FIXME: Implement other file actions
  26. }
  27. struct ProcessSpawnOptions {
  28. StringView name {};
  29. ByteString executable {};
  30. bool search_for_executable_in_path { false };
  31. Vector<ByteString> const& arguments {};
  32. Optional<ByteString> working_directory {};
  33. using FileActionType = Variant<FileAction::OpenFile, FileAction::CloseFile>;
  34. Vector<FileActionType> file_actions {};
  35. };
  36. class IPCProcess;
  37. class Process {
  38. AK_MAKE_NONCOPYABLE(Process);
  39. public:
  40. enum class KeepAsChild {
  41. Yes,
  42. No
  43. };
  44. Process(Process&& other)
  45. : m_pid(exchange(other.m_pid, 0))
  46. , m_should_disown(exchange(other.m_should_disown, false))
  47. {
  48. }
  49. Process& operator=(Process&& other)
  50. {
  51. m_pid = exchange(other.m_pid, 0);
  52. m_should_disown = exchange(other.m_should_disown, false);
  53. return *this;
  54. }
  55. ~Process()
  56. {
  57. (void)disown();
  58. }
  59. static ErrorOr<Process> spawn(ProcessSpawnOptions const& options);
  60. // FIXME: Make the following 2 functions return Process instance or delete them.
  61. static ErrorOr<pid_t> spawn(StringView path, ReadonlySpan<ByteString> arguments, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No);
  62. static ErrorOr<pid_t> spawn(StringView path, ReadonlySpan<StringView> arguments, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No);
  63. // FIXME: Remove this. char const* should not exist on this level of abstraction.
  64. static ErrorOr<pid_t> spawn(StringView path, ReadonlySpan<char const*> arguments = {}, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No);
  65. static ErrorOr<String> get_name();
  66. enum class SetThreadName {
  67. No,
  68. Yes,
  69. };
  70. static ErrorOr<void> set_name(StringView, SetThreadName = SetThreadName::No);
  71. static void wait_for_debugger_and_break();
  72. static ErrorOr<bool> is_being_debugged();
  73. pid_t pid() const { return m_pid; }
  74. ErrorOr<void> disown();
  75. // FIXME: Make it return an exit code.
  76. ErrorOr<bool> wait_for_termination();
  77. private:
  78. friend IPCProcess;
  79. Process(pid_t pid)
  80. : m_pid(pid)
  81. , m_should_disown(true)
  82. {
  83. }
  84. pid_t m_pid;
  85. bool m_should_disown;
  86. };
  87. class IPCProcess {
  88. public:
  89. template<typename ClientType>
  90. struct ProcessAndIPCClient {
  91. Process process;
  92. NonnullRefPtr<ClientType> client;
  93. };
  94. template<typename ClientType, typename... ClientArguments>
  95. static ErrorOr<ProcessAndIPCClient<ClientType>> spawn(ProcessSpawnOptions const& options, ClientArguments&&... client_arguments)
  96. {
  97. auto [process, socket] = TRY(spawn_and_connect_to_process(options));
  98. auto client = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) ClientType { move(socket), forward<ClientArguments>(client_arguments)... }));
  99. return ProcessAndIPCClient<ClientType> { move(process), move(client) };
  100. }
  101. template<typename ClientType, typename... ClientArguments>
  102. static ErrorOr<ProcessAndIPCClient<ClientType>> spawn_singleton(ProcessSpawnOptions const& options, ClientArguments&&... client_arguments)
  103. {
  104. auto [process, socket] = TRY(spawn_singleton_and_connect_to_process(options));
  105. auto client = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) ClientType { move(socket), forward<ClientArguments>(client_arguments)... }));
  106. return ProcessAndIPCClient<ClientType> { move(process), move(client) };
  107. }
  108. pid_t pid() const { return m_process.pid(); }
  109. private:
  110. struct ProcessAndIPCSocket {
  111. Process process;
  112. NonnullOwnPtr<Core::LocalSocket> m_ipc_socket;
  113. };
  114. static ErrorOr<ProcessAndIPCSocket> spawn_and_connect_to_process(ProcessSpawnOptions const& options);
  115. static ErrorOr<ProcessAndIPCSocket> spawn_singleton_and_connect_to_process(ProcessSpawnOptions const& options);
  116. Process m_process;
  117. };
  118. }