Arcane  v4.1.2.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
Process.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 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/* Gestion des processus. */
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: pour l'instant cette classe n'est implémentée que pour Linux
21 * (elle devrait cependant fonctionner avec les autres Unix).
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 // Créé deux pipes pour rediriger les entrées et les sorties du
47 // processus qu'on va lancer.
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 // Je suis le processus fils.
63
64 // TODO: vérifier les erreurs des close() et dup2().
65
66 // Indique que pipefd_out[1] correspond à mon STDOUT
67 ::close(STDOUT_FILENO);
68 ::close(pipefd_out[0]);
69 ::dup2(pipefd_out[1], STDOUT_FILENO);
70
71 // Indique que pipefd_in[0] correspond à mon 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 // Le tableau passé à execve() pour les arguments doit se terminer par NULL
81 // et commencer par le nom de l'exécutable
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 // L'appel à execve() ne retourne pas.
91 }
92 else {
93 ::close(pipefd_out[1]);
94 ::close(pipefd_in[0]);
95 // Ecrit sur le pipe d'entrée les octets de \a input_bytes
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 // Utilise une boucle finie pour éviter les avertissements de coverity/codacy
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 // Attend que le processus fils soit fini.
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 // Ajoute un '\0' terminal au flux de sortie.
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/*---------------------------------------------------------------------------*/
Vue constante d'un tableau de type T.
Vecteur 1D de données avec sémantique par valeur (style STL).
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
ConstArrayView< Byte > ByteConstArrayView
Equivalent C d'un tableau à une dimension de caractères.
Definition UtilsTypes.h:480
std::int32_t Int32
Type entier signé sur 32 bits.