Arcane  4.1.12.0
User documentation
Loading...
Searching...
No Matches
Process.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* Process.cc (C) 2000-2025 */
9/* */
10/* Process management. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arccore/common/internal/Process.h"
15
16#include "arccore/base/NotImplementedException.h"
17#include "arccore/base/FixedArray.h"
18
19/*
20 * NOTE: for now this class is only implemented for Linux
21 * (it should however work with other Unix systems).
22 */
23
24#ifdef ARCCORE_OS_LINUX
25#include <unistd.h>
26#include <sys/wait.h>
27#include <fcntl.h>
28#endif
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32
33namespace Arcane
34{
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39ProcessExecArgs::ExecStatus Process::
40execute(ProcessExecArgs& args)
41{
42#ifdef ARCCORE_OS_LINUX
43 args.m_output_bytes.clear();
44 ByteConstArrayView input_bytes = args.inputBytes();
45
46 // Create two pipes to redirect the inputs and outputs of the
47 // process we are going to launch.
48 int pipefd_out[2];
49 int pipefd_in[2];
50 int r0 = pipe2(pipefd_out, O_CLOEXEC);
51 if (r0 != 0)
52 return ProcessExecArgs::ExecStatus::CanNotCreatePipe;
53 r0 = pipe2(pipefd_in, O_CLOEXEC);
54 if (r0 != 0)
55 return ProcessExecArgs::ExecStatus::CanNotCreatePipe;
56 pid_t cpid = ::fork();
57 if (cpid < 0)
58 return ProcessExecArgs::ExecStatus::CanNotFork;
59
60 ProcessExecArgs::ExecStatus exec_status = ProcessExecArgs::ExecStatus::OK;
61 if (cpid == 0) {
62 // I am the child process.
63
64 // TODO: check errors for close() and dup2().
65
66 // Indicates that pipefd_out[1] corresponds to my STDOUT
67 ::close(STDOUT_FILENO);
68 ::close(pipefd_out[0]);
69 ::dup2(pipefd_out[1], STDOUT_FILENO);
70
71 // Indicates that pipefd_in[0] corresponds to my STDIN
72 ::close(STDIN_FILENO);
73 ::close(pipefd_in[1]);
74 ::dup2(pipefd_in[0], STDIN_FILENO);
75
76 const char* cmd_name = args.command().localstr();
77
78 ConstArrayView<String> arguments = args.arguments();
79 Integer nb_arg = arguments.size();
80 // The array passed to execve() for arguments must end with NULL
81 // and start with the name of the executable
82 UniqueArray<const char*> command_args(nb_arg + 2);
83 for (Integer i = 0; i < nb_arg; ++i)
84 command_args[i + 1] = arguments[i].localstr();
85 command_args[0] = cmd_name;
86 command_args[nb_arg + 1] = nullptr;
87
88 const char* const newenviron[] = { NULL };
89 ::execve(cmd_name, (char* const*)command_args.data(), (char* const*)newenviron);
90 // The execve() call does not return.
91 }
92 else {
93 ::close(pipefd_out[1]);
94 ::close(pipefd_in[0]);
95 // Write the bytes of \a input_bytes to the input pipe
96 Int64 nb_wanted_write = input_bytes.size();
97 Int64 nb_written = ::write(pipefd_in[1], input_bytes.data(), nb_wanted_write);
98 if (nb_written != nb_wanted_write)
99 std::cerr << "Error writing to pipe\n";
100 ::close(pipefd_in[1]);
101 const int BUF_SIZE = 4096;
103 buf[BUF_SIZE] = '\0';
104 Int32 max_iteration = 1000000;
105 Int32 current_iteration = 0;
106 // Uses a finite loop to avoid coverity/codacy warnings
107 for (Int32 i = 0; i < max_iteration; ++i) {
108 ssize_t nb_read = ::read(pipefd_out[0], buf.data(), BUF_SIZE);
109 if (nb_read == EINTR)
110 continue;
111 if (nb_read <= 0)
112 break;
113 Int32 i_nb_read = static_cast<Int32>(nb_read);
114 buf[i_nb_read] = '\0';
115 args.m_output_bytes.addRange(buf.view().subView(0, i_nb_read));
116 //::write(STDOUT_FILENO, buf, r);
117 }
118
119 // Wait for the child process to finish.
120 int status = 0;
121 pid_t child_pid = 0;
122 do {
123 child_pid = ::waitpid(cpid, &status, 0); /* Wait for child */
124 } while (child_pid == -1 && errno == EINTR);
125
126 if (WIFEXITED(status)) {
127 args.m_exit_code = WEXITSTATUS(status);
128 //printf("exited, status=%d\n", WEXITSTATUS(status));
129 }
130 else
131 exec_status = ProcessExecArgs::ExecStatus::AbnormalExit;
132
133 close(pipefd_out[0]);
134
135 // Adds a terminal '\0' to the output stream.
136 args.m_output_bytes.add('\0');
137 }
138 return exec_status;
139#else
140 throw NotImplementedException(A_FUNCINFO);
141#endif
142}
143
144/*---------------------------------------------------------------------------*/
145/*---------------------------------------------------------------------------*/
146
147} // namespace Arcane
148
149/*---------------------------------------------------------------------------*/
150/*---------------------------------------------------------------------------*/
Constant view of an array of type T.
1D data vector with value semantics (STL style).
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ConstArrayView< Byte > ByteConstArrayView
C equivalent of a 1D array of characters.
Definition UtilsTypes.h:476
std::int32_t Int32
Signed integer type of 32 bits.