Arcane  4.2.1.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-2026 */
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#include <iostream>
20
21/*
22 * NOTE: for now this class is only implemented for Linux
23 * (it should however work with other Unix systems).
24 */
25
26#ifdef ARCCORE_OS_LINUX
27#include <unistd.h>
28#include <sys/wait.h>
29#include <fcntl.h>
30#endif
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
34
35namespace Arcane
36{
37
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
40
41ProcessExecArgs::ExecStatus Process::
42execute(ProcessExecArgs& args)
43{
44#ifdef ARCCORE_OS_LINUX
45 args.m_output_bytes.clear();
46 ByteConstArrayView input_bytes = args.inputBytes();
47
48 // Create two pipes to redirect the inputs and outputs of the
49 // process we are going to launch.
50 int pipefd_out[2];
51 int pipefd_in[2];
52 int r0 = pipe2(pipefd_out, O_CLOEXEC);
53 if (r0 != 0)
54 return ProcessExecArgs::ExecStatus::CanNotCreatePipe;
55 r0 = pipe2(pipefd_in, O_CLOEXEC);
56 if (r0 != 0)
57 return ProcessExecArgs::ExecStatus::CanNotCreatePipe;
58 pid_t cpid = ::fork();
59 if (cpid < 0)
60 return ProcessExecArgs::ExecStatus::CanNotFork;
61
62 ProcessExecArgs::ExecStatus exec_status = ProcessExecArgs::ExecStatus::OK;
63 if (cpid == 0) {
64 // I am the child process.
65
66 // TODO: check errors for close() and dup2().
67
68 // Indicates that pipefd_out[1] corresponds to my STDOUT
69 ::close(STDOUT_FILENO);
70 ::close(pipefd_out[0]);
71 ::dup2(pipefd_out[1], STDOUT_FILENO);
72
73 // Indicates that pipefd_in[0] corresponds to my STDIN
74 ::close(STDIN_FILENO);
75 ::close(pipefd_in[1]);
76 ::dup2(pipefd_in[0], STDIN_FILENO);
77
78 const char* cmd_name = args.command().localstr();
79
80 ConstArrayView<String> arguments = args.arguments();
81 Integer nb_arg = arguments.size();
82 // The array passed to execve() for arguments must end with NULL
83 // and start with the name of the executable
84 UniqueArray<const char*> command_args(nb_arg + 2);
85 for (Integer i = 0; i < nb_arg; ++i)
86 command_args[i + 1] = arguments[i].localstr();
87 command_args[0] = cmd_name;
88 command_args[nb_arg + 1] = nullptr;
89
90 const char* const newenviron[] = { NULL };
91 ::execve(cmd_name, (char* const*)command_args.data(), (char* const*)newenviron);
92 // The execve() call does not return.
93 }
94 else {
95 ::close(pipefd_out[1]);
96 ::close(pipefd_in[0]);
97 // Write the bytes of \a input_bytes to the input pipe
98 Int64 nb_wanted_write = input_bytes.size();
99 Int64 nb_written = ::write(pipefd_in[1], input_bytes.data(), nb_wanted_write);
100 if (nb_written != nb_wanted_write)
101 std::cerr << "Error writing to pipe\n";
102 ::close(pipefd_in[1]);
103 const int BUF_SIZE = 4096;
105 buf[BUF_SIZE] = '\0';
106 Int32 max_iteration = 1000000;
107 Int32 current_iteration = 0;
108 // Uses a finite loop to avoid coverity/codacy warnings
109 for (Int32 i = 0; i < max_iteration; ++i) {
110 ssize_t nb_read = ::read(pipefd_out[0], buf.data(), BUF_SIZE);
111 if (nb_read == EINTR)
112 continue;
113 if (nb_read <= 0)
114 break;
115 Int32 i_nb_read = static_cast<Int32>(nb_read);
116 buf[i_nb_read] = '\0';
117 args.m_output_bytes.addRange(buf.view().subView(0, i_nb_read));
118 //::write(STDOUT_FILENO, buf, r);
119 }
120
121 // Wait for the child process to finish.
122 int status = 0;
123 pid_t child_pid = 0;
124 do {
125 child_pid = ::waitpid(cpid, &status, 0); /* Wait for child */
126 } while (child_pid == -1 && errno == EINTR);
127
128 if (WIFEXITED(status)) {
129 args.m_exit_code = WEXITSTATUS(status);
130 //printf("exited, status=%d\n", WEXITSTATUS(status));
131 }
132 else
133 exec_status = ProcessExecArgs::ExecStatus::AbnormalExit;
134
135 close(pipefd_out[0]);
136
137 // Adds a terminal '\0' to the output stream.
138 args.m_output_bytes.add('\0');
139 }
140 return exec_status;
141#else
142 throw NotImplementedException(A_FUNCINFO);
143#endif
144}
145
146/*---------------------------------------------------------------------------*/
147/*---------------------------------------------------------------------------*/
148
149} // namespace Arcane
150
151/*---------------------------------------------------------------------------*/
152/*---------------------------------------------------------------------------*/
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:470
std::int32_t Int32
Signed integer type of 32 bits.