Arcane  v4.1.2.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
arcane/src/arcane/utils/PlatformUtils.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/* PlatformUtils.cc (C) 2000-2025 */
9/* */
10/* Fonctions utilitaires dépendant de la plateforme. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/String.h"
16#include "arcane/utils/StdHeader.h"
17#include "arcane/utils/StackTrace.h"
18#include "arcane/utils/IStackTraceService.h"
19#include "arcane/utils/IOnlineDebuggerService.h"
20#include "arcane/utils/Iostream.h"
21#include "arcane/utils/StringBuilder.h"
22#include "arcane/utils/NotSupportedException.h"
23#include "arcane/utils/NotImplementedException.h"
24#include "arcane/utils/FatalErrorException.h"
25#include "arcane/utils/Array.h"
26#include "arcane/utils/StringList.h"
28#include "arcane/utils/CheckedConvert.h"
29#include "arccore/common/internal/MemoryUtilsInternal.h"
30
32
33#include <chrono>
34
35#ifndef ARCANE_OS_WIN32
36#define ARCANE_OS_UNIX
37#endif
38
39#ifdef ARCANE_OS_WIN32
40#include <sys/types.h>
41#include <sys/timeb.h>
42#include <sys/stat.h>
43#include <direct.h>
44#include <process.h>
45#include <windows.h>
46#include <shlobj.h>
47#endif
48
49#ifdef ARCANE_OS_UNIX
50#include <unistd.h>
51#include <sys/resource.h>
52#include <time.h>
53#include <sys/types.h>
54#include <sys/stat.h>
55#include <sys/time.h>
56#include <fcntl.h>
57#endif
58
59#ifdef ARCANE_OS_MACOS
60#include <cstdlib>
61#include <mach-o/dyld.h>
62#include <crt_externs.h>
63#else
64#include <malloc.h>
65#endif
66
67
68#if !defined(ARCANE_OS_CYGWIN) && !defined(ARCANE_OS_WIN32)
69#if defined(__i386__)
70#define ARCANE_HAS_I386_FPU_CONTROL_H
71#include <fpu_control.h>
72#endif
73#endif
74
75#ifndef ARCANE_OS_WIN32
76#include <pwd.h>
77#include <sys/types.h>
78#include <unistd.h>
79#endif
80
81// Support pour gérer les exceptions flottantes:
82// - sous Linux avec la GlibC, cela se fait via les méthodes
83// feenableexcept(), fedisableexcept() et fegetexcept()
84// - sous Win32, cela se fait via la méthode _controlfp() mais pour
85// l'instant ce n'est pas utilisé dans Arcane.
86#if defined(ARCANE_OS_LINUX) && defined(__USE_GNU)
87# include <fenv.h>
88# define ARCANE_GLIBC_FENV
89#endif
90
91/*---------------------------------------------------------------------------*/
92/*---------------------------------------------------------------------------*/
93
94namespace Arcane
95{
96
97/*---------------------------------------------------------------------------*/
98/*---------------------------------------------------------------------------*/
99
100namespace platform
101{
102 IOnlineDebuggerService* global_online_debugger_service = nullptr;
103 ISymbolizerService* global_symbolizer_service = nullptr;
104 IProfilingService* global_profiling_service = nullptr;
105 IProcessorAffinityService* global_processor_affinity_service = nullptr;
106 IPerformanceCounterService* global_performance_counter_service = nullptr;
107 bool global_has_color_console = false;
108}
109
110/*---------------------------------------------------------------------------*/
111/*---------------------------------------------------------------------------*/
112
113extern "C++" ARCANE_UTILS_EXPORT ISymbolizerService* platform::
115{
116 return global_symbolizer_service;
117}
118
119/*---------------------------------------------------------------------------*/
120/*---------------------------------------------------------------------------*/
121
122extern "C++" ARCANE_UTILS_EXPORT ISymbolizerService* platform::
124{
125 ISymbolizerService* old_service = global_symbolizer_service;
126 global_symbolizer_service = service;
127 return old_service;
128}
129
130/*---------------------------------------------------------------------------*/
131/*---------------------------------------------------------------------------*/
132
133extern "C++" ARCANE_UTILS_EXPORT IOnlineDebuggerService* platform::
135{
136 return global_online_debugger_service;
137}
138
139/*---------------------------------------------------------------------------*/
140/*---------------------------------------------------------------------------*/
141
142extern "C++" ARCANE_UTILS_EXPORT IOnlineDebuggerService* platform::
144{
145 IOnlineDebuggerService* old_service = global_online_debugger_service;
146 global_online_debugger_service = service;
147 return old_service;
148}
149
150/*---------------------------------------------------------------------------*/
151/*---------------------------------------------------------------------------*/
152
153extern "C++" ARCANE_UTILS_EXPORT IProfilingService* platform::
155{
156 return global_profiling_service;
157}
158
159/*---------------------------------------------------------------------------*/
160/*---------------------------------------------------------------------------*/
161
162extern "C++" ARCANE_UTILS_EXPORT IProfilingService* platform::
164{
165 IProfilingService* old_service = global_profiling_service;
166 global_profiling_service = service;
167 return old_service;
168}
169
170/*---------------------------------------------------------------------------*/
171/*---------------------------------------------------------------------------*/
172
173extern "C++" ARCANE_UTILS_EXPORT IProcessorAffinityService* platform::
175{
176 return global_processor_affinity_service;
177}
178
179/*---------------------------------------------------------------------------*/
180/*---------------------------------------------------------------------------*/
181
182extern "C++" ARCANE_UTILS_EXPORT IProcessorAffinityService* platform::
184{
185 IProcessorAffinityService* old_service = global_processor_affinity_service;
186 global_processor_affinity_service = service;
187 return old_service;
188}
189
190/*---------------------------------------------------------------------------*/
191/*---------------------------------------------------------------------------*/
192
193extern "C++" ARCANE_UTILS_EXPORT IPerformanceCounterService* platform::
195{
196 return global_performance_counter_service;
197}
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201
202extern "C++" ARCANE_UTILS_EXPORT IPerformanceCounterService* platform::
204{
205 auto* old_service = global_performance_counter_service;
206 global_performance_counter_service = service;
207 return old_service;
208}
209
210/*---------------------------------------------------------------------------*/
211/*---------------------------------------------------------------------------*/
212
218
219/*---------------------------------------------------------------------------*/
220/*---------------------------------------------------------------------------*/
221
227
228/*---------------------------------------------------------------------------*/
229/*---------------------------------------------------------------------------*/
230
236
237/*---------------------------------------------------------------------------*/
238/*---------------------------------------------------------------------------*/
239
240extern "C++" ARCANE_UTILS_EXPORT IMemoryRessourceMng* platform::
241setDataMemoryRessourceMng(IMemoryRessourceMng* mng)
242{
244}
245
246/*---------------------------------------------------------------------------*/
247/*---------------------------------------------------------------------------*/
248
249IMemoryRessourceMng* platform::
251{
253}
254
255/*---------------------------------------------------------------------------*/
256/*---------------------------------------------------------------------------*/
257
258extern "C++" ARCANE_UTILS_EXPORT IThreadImplementation* platform::
260{
261 return Arccore::Concurrency::getThreadImplementation();
262}
263
264/*---------------------------------------------------------------------------*/
265/*---------------------------------------------------------------------------*/
266
267extern "C++" ARCANE_UTILS_EXPORT IThreadImplementation* platform::
269{
270 return Arccore::Concurrency::setThreadImplementation(service);
271}
272
273/*---------------------------------------------------------------------------*/
274/*---------------------------------------------------------------------------*/
275
276extern "C++" ARCANE_UTILS_EXPORT void platform::
277resetAlarmTimer(Integer nb_second)
278{
279#ifdef ARCANE_OS_UNIX
280 struct itimerval time_val;
281 struct itimerval otime_val;
282 time_val.it_value.tv_sec = nb_second;
283 time_val.it_value.tv_usec = 0;
284 time_val.it_interval.tv_sec = 0;
285 time_val.it_interval.tv_usec = 0;
286 // Utilise le temps virtuel et pas le temps réel.
287 // Cela permet de suspendre temporairement un job (par exemple
288 // pour régler des problèmes systèmes) sans déclencher l'alarme.
289 int r = setitimer(ITIMER_VIRTUAL,&time_val,&otime_val);
290 if (r!=0)
291 cout << "** ERROR in setitimer r=" << r << '\n';
292#endif
293}
294
295/*---------------------------------------------------------------------------*/
296/*---------------------------------------------------------------------------*/
297
298extern "C++" ARCANE_UTILS_EXPORT void platform::
300{
302}
303
304/*---------------------------------------------------------------------------*/
305/*---------------------------------------------------------------------------*/
306
307extern "C++" ARCANE_UTILS_EXPORT void platform::
309{
311}
312
313/*---------------------------------------------------------------------------*/
314/*---------------------------------------------------------------------------*/
315
316namespace
317{
318template<typename ByteType> bool
319_readAllFile(StringView filename, bool is_binary, Array<ByteType>& out_bytes)
320{
321 using namespace std;
322 long unsigned int file_length = platform::getFileLength(filename);
323 if (file_length == 0) {
324 //cerr << "** FAIL LENGTH\n";
325 return true;
326 }
327 ifstream ifile;
328 ios::openmode mode = ios::in;
329 if (is_binary)
330 mode |= ios::binary;
331 ifile.open(filename.toStdStringView().data());
332 if (ifile.fail()) {
333 //cerr << "** FAIL OPEN\n";
334 return true;
335 }
336 out_bytes.resize(file_length);
337 ifile.read((char*)(out_bytes.data()), file_length);
338 if (ifile.bad()) {
339 // cerr << "** BAD READ\n";
340 return true;
341 }
342 // Il est possible que le nombre d'octets lus soit inférieur
343 // à la longueur du fichier, notamment sous Windows avec les fichiers
344 // texte et la conversion des retour-chariots. Il faut donc redimensionner
345 // \a bytes à la bonne longueur.
346 size_t nb_read = ifile.gcount();
347 out_bytes.resize(nb_read);
348 //cerr << "** READ " << file_length << " bytes " << (const char*)(bytes.begin()) << "\n";
349 return false;
350}
351}
352
353/*---------------------------------------------------------------------------*/
354/*---------------------------------------------------------------------------*/
355
357readAllFile(StringView filename, bool is_binary, ByteArray& out_bytes)
358{
359 return _readAllFile(filename,is_binary,out_bytes);
360}
361
362/*---------------------------------------------------------------------------*/
363/*---------------------------------------------------------------------------*/
364
366readAllFile(StringView filename, bool is_binary, Array<std::byte>& out_bytes)
367{
368 return _readAllFile(filename,is_binary,out_bytes);
369}
370
371/*---------------------------------------------------------------------------*/
372/*---------------------------------------------------------------------------*/
373
374static bool global_has_dotnet_runtime = false;
375extern "C++" bool platform::
377{
378 return global_has_dotnet_runtime;
379}
380
381extern "C++" void platform::
383{
384 global_has_dotnet_runtime = v;
385}
386
387/*---------------------------------------------------------------------------*/
388/*---------------------------------------------------------------------------*/
389
390extern "C++" String platform::
392{
393 String full_path;
394#if defined(ARCANE_OS_LINUX)
395 char* buf = ::realpath("/proc/self/exe",nullptr);
396 if (buf){
397 full_path = StringView(buf);
398 ::free(buf);
399 }
400#elif defined(ARCANE_OS_WIN32)
401 char buf[2048];
402 int r = GetModuleFileNameA(NULL,buf,2000);
403 if (r>0){
404 full_path = StringView(buf);
405 }
406#elif defined(ARCANE_OS_MACOS)
407 char buf[2048];
408 uint32_t bufSize = 2000;
409 int r = _NSGetExecutablePath(buf, &bufSize);
410 if (r==0) { // success returns 0
411 full_path = StringView(buf);
412 }
413#else
414#error "platform::getExeFullPath() not implemented for this platform"
415#endif
416 return full_path;
417}
418
419/*---------------------------------------------------------------------------*/
420/*---------------------------------------------------------------------------*/
421
422extern "C++" void platform::
424{
425 arg_list.clear();
426#if defined(ARCANE_OS_LINUX)
427
428 const int BUFSIZE = 1024;
429 char buffer[BUFSIZE + 1];
430
431 UniqueArray<char> bytes;
432 bytes.reserve(1024);
433
434 {
435 const char* filename = "/proc/self/cmdline";
436 int fd = open(filename, O_RDONLY);
437 if (fd<0)
438 return;
439 ssize_t nb_read = 0;
440 // TODO: traiter les interruptions
441 while ((nb_read = read(fd, buffer, BUFSIZE)) > 0) {
442 buffer[BUFSIZE] = '\0';
443 bytes.addRange(Span<const char>(buffer, nb_read));
444 }
445 close(fd);
446 }
447
448 int size = bytes.size();
449 const char* ptr = bytes.data();
450 const char* end = ptr + size;
451 while (ptr < end) {
452 arg_list.add(StringView(ptr));
453 while (*ptr++ && ptr < end)
454 ;
455 }
456#elif defined(ARCANE_OS_WIN32)
457 LPWSTR* w_arg_list = nullptr;
458 int nb_arg = 0;
459
460 w_arg_list = ::CommandLineToArgvW(GetCommandLineW(), &nb_arg);
461 if (!w_arg_list)
462 ARCANE_FATAL("Can not get arguments from command line");
463
464 for (int i = 0; i < nb_arg; i++) {
465 std::wstring_view wstr_view(w_arg_list[i]);
467 arg_list.add(str);
468 }
469
470 ::LocalFree(w_arg_list);
471#elif defined(ARCANE_OS_MACOS)
472 int argc = *_NSGetArgc();
473 char** argv = *_NSGetArgv();
474 for (int i = 0; i < argc; i++) {
475 arg_list.add(StringView(argv[i]));
476 }
477#else
478 ARCANE_THROW(NotImplementedException, "not implemented for this platform");
479#endif
480}
481
482/*---------------------------------------------------------------------------*/
483/*---------------------------------------------------------------------------*/
484
485namespace
486{
487 String _getDebuggerStack(const char* command)
488 {
489 char filename[4096];
490 long pid = (long)getpid();
491 sprintf(filename, "errlog.%ld", pid);
492 int ret_value = system(command);
493 if (ret_value != 0) {
494 UniqueArray<Byte> bytes;
495 if (!platform::readAllFile(filename, false, bytes))
496 return String(bytes);
497 }
498 return {};
499 }
500} // namespace
501
502extern "C++" ARCANE_UTILS_EXPORT String platform::
504{
505 String result;
506#if defined(ARCANE_OS_LINUX)
507 const size_t cmd_size = 4096;
508 char cmd[cmd_size + 1];
509 //sprintf (cmd, "gdb --ex 'attach %ld' --ex 'info threads' --ex 'thread apply all bt'", (long)getpid ());
510 //sprintf (cmd, "gdb --ex 'attach %ld' --ex 'info threads' --ex 'thread apply all bt' --batch", (long)getpid ());
511 long pid = (long)getpid();
512 snprintf(cmd, cmd_size, "gdb --ex 'set debuginfod enabled off' --ex 'attach %ld' --ex 'info threads' --ex 'thread apply all bt full' --batch", pid);
513 result = _getDebuggerStack(cmd);
514#endif
515 return result;
516}
517
518/*---------------------------------------------------------------------------*/
519/*---------------------------------------------------------------------------*/
520
521extern "C++" ARCANE_UTILS_EXPORT String platform::
523{
524 String result;
525#if defined(ARCANE_OS_LINUX)
526 const size_t cmd_size = 4096;
527 char cmd[cmd_size + 1];
528 long pid = (long)getpid();
529 // Les commandes 'clrthreads', 'clrstack' et 'dumpstack' nécessitent
530 // d'avoir installé 'dotnet-sos'.
531 snprintf(cmd, cmd_size, "lldb -p %ld -o 'bt' -o 'bt all' -o 'clrthreads' -o 'clrstack' -o 'dumpstack' --batch", pid);
532 result = _getDebuggerStack(cmd);
533#endif
534 return result;
535}
536
537/*---------------------------------------------------------------------------*/
538/*---------------------------------------------------------------------------*/
539
540namespace
541{
542void (*global_garbage_collector_delegate)() = nullptr;
543}
544
545extern "C" ARCANE_UTILS_EXPORT void
546_ArcaneSetCallGarbageCollectorDelegate(void(*f)())
547{
548 global_garbage_collector_delegate = f;
549}
550
551extern "C++" void platform::
553{
554 if (global_garbage_collector_delegate)
555 (*global_garbage_collector_delegate)();
556}
557
558/*---------------------------------------------------------------------------*/
559/*---------------------------------------------------------------------------*/
560
561} // End namespace Arcane
562
563/*---------------------------------------------------------------------------*/
564/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Fonctions utilitaires sur les chaînes de caractères.
ARCCORE_BASE_EXPORT String convertToArcaneString(const std::wstring_view &wstr)
Convertie wstr en une String.
Definition String.cc:1305
Fonctions de gestion mémoire et des allocateurs.
Integer size() const
Nombre d'éléments du vecteur.
Tableau d'items de types quelconques.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void reserve(Int64 new_capacity)
Réserve le mémoire pour new_capacity éléments.
const T * data() const
Accès à la racine du tableau hors toute protection.
void addRange(ConstReferenceType val, Int64 n)
Ajoute n élément de valeur val à la fin du tableau.
void clear()
Supprime tous les éléments de la collection.
Interface d'un allocateur pour la mémoire.
Interface d'un service de debugger hybrid.
Interface d'un service d'accès aux compteurs de performance.
Interface d'un service de gestion de l'affinité des coeurs CPU.
Interface d'un service de profiling.
Interface d'un service de récupération des symboles du code source.
Interface d'un service implémentant le support des threads.
Exception lorsqu'une fonction n'est pas implémentée.
Vue d'un tableau d'éléments de type T.
Definition Span.h:633
Vue sur une chaîne de caractères UTF-8.
Definition StringView.h:47
std::string_view toStdStringView() const ARCCORE_NOEXCEPT
Retourne une vue de la STL de la vue actuelle.
Definition StringView.h:112
Chaîne de caractères unicode.
Vecteur 1D de données avec sémantique par valeur (style STL).
ARCCORE_COMMON_EXPORT IMemoryRessourceMng * setDataMemoryResourceMng(IMemoryRessourceMng *mng)
Positionne le gestionnaire de ressource mémoire pour les données.
ARCCORE_COMMON_EXPORT IMemoryRessourceMng * getDataMemoryResourceMng()
Gestionnaire de ressource mémoire pour les données.
ARCCORE_COMMON_EXPORT IMemoryAllocator * setAcceleratorHostMemoryAllocator(IMemoryAllocator *a)
Positionne l'allocateur spécifique pour les accélérateurs.
ARCCORE_COMMON_EXPORT IMemoryAllocator * getDefaultDataAllocator()
Allocateur par défaut pour les données.
ARCCORE_COMMON_EXPORT IMemoryAllocator * getAcceleratorHostMemoryAllocator()
Allocateur spécifique pour les accélérateurs.
ARCCORE_BASE_EXPORT void platformTerminate()
Routines de fin de programme spécifiques à une platforme.
ARCCORE_BASE_EXPORT void platformInitialize()
Initialisations spécifiques à une platforme.
Espace de nom pour les fonctions dépendant de la plateforme.
IPerformanceCounterService * setPerformanceCounterService(IPerformanceCounterService *service)
Positionne le service utilisé pour gérer les compteurs interne du processeur.
void callDotNETGarbageCollector()
Appelle le Garbage Collector de '.Net' s'il est disponible.
String getLLDBStack()
Récupère la pile d'appel via lldb.
ISymbolizerService * setSymbolizerService(ISymbolizerService *service)
Positionne le service pour obtenir des informations sur les symboles du code source.
void fillCommandLineArguments(StringList &arg_list)
Remplit arg_list avec les arguments de la ligne de commande.
IMemoryRessourceMng * setDataMemoryRessourceMng(IMemoryRessourceMng *mng)
Positionne le gestionnaire de ressource mémoire pour les données.
void platformInitialize()
Initialisations spécifiques à une platforme.
IOnlineDebuggerService * setOnlineDebuggerService(IOnlineDebuggerService *service)
Positionne le service a utiliser pour l'architecture en ligne de debug.
ISymbolizerService * getSymbolizerService()
Service utilisé pour obtenir des informations sur les symboles du code source.
IProfilingService * getProfilingService()
Service utilisé pour obtenir pour obtenir des informations de profiling.
IMemoryRessourceMng * getDataMemoryRessourceMng()
Gestionnaire de ressource mémoire pour les données.
void resetAlarmTimer(Integer nb_second)
Remet à timer d'alarme à nb_second.
void platformTerminate()
Routines de fin de programme spécifiques à une platforme.
ARCCORE_BASE_EXPORT long unsigned int getFileLength(const String &filename)
Longueur du fichier filename. Si le fichier n'est pas lisible ou n'existe pas, retourne 0.
IProfilingService * setProfilingService(IProfilingService *service)
Positionne le service utilisé pour obtenir des informations de profiling.
IMemoryAllocator * getAcceleratorHostMemoryAllocator()
Allocateur spécifique pour les accélérateurs.
IMemoryAllocator * getDefaultDataAllocator()
Allocateur par défaut pour les données.
String getExeFullPath()
Retourne le nom complet avec le chemin de l'exécutable.
bool readAllFile(StringView filename, bool is_binary, ByteArray &out_bytes)
Lit le contenu d'un fichier et le conserve dans out_bytes.
IProcessorAffinityService * setProcessorAffinityService(IProcessorAffinityService *service)
Positionne le service utilisé pour la gestion de l'affinité des processeurs.
void setHasDotNETRuntime(bool v)
Positionne si le code s'exécute avec le runtime .NET.
IProcessorAffinityService * getProcessorAffinityService()
Service utilisé pour la gestion de l'affinité des processeurs.
IMemoryAllocator * setAcceleratorHostMemoryAllocator(IMemoryAllocator *a)
Positionne l'allocateur spécifique pour les accélérateurs.
IThreadImplementation * getThreadImplementationService()
Service utilisé pour gérer les threads.
IPerformanceCounterService * getPerformanceCounterService()
Service utilisé pour obtenir pour obtenir les compteurs interne du processeur.
bool hasDotNETRuntime()
Vrai si le code s'exécute avec le runtime .NET.
String getGDBStack()
Récupère la pile d'appel via gdb.
IThreadImplementation * setThreadImplementationService(IThreadImplementation *service)
Positionne le service utilisé pour gérer les threads.
IOnlineDebuggerService * getOnlineDebuggerService()
Service utilisé pour obtenir la mise en place d'une architecture en ligne de debug.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Int32 Integer
Type représentant un entier.
Array< Byte > ByteArray
Tableau dynamique à une dimension de caractères.
Definition UtilsTypes.h:121
List< String > StringList
Tableau de chaînes de caractères unicode.
Definition UtilsTypes.h:509