1
//============================================================================
2
// Main API functions for CFD_Proxy component
3
//============================================================================
6
This file is part of Code_Saturne, a general-purpose CFD tool.
8
Copyright (C) 1998-2011 EDF S.A.
10
This program is free software; you can redistribute it and/or modify it under
11
the terms of the GNU General Public License as published by the Free Software
12
Foundation; either version 2 of the License, or (at your option) any later
15
This program is distributed in the hope that it will be useful, but WITHOUT
16
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20
You should have received a copy of the GNU General Public License along with
21
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22
Street, Fifth Floor, Boston, MA 02110-1301, USA.
25
#include "cs_config.h"
27
//----------------------------------------------------------------------------
29
//----------------------------------------------------------------------------
41
#include "cfd_proxy_defs.h"
42
#include "cfd_proxy_comm.h"
43
#include "cfd_proxy_child.h"
44
#include "cfd_proxy_loader.h"
46
#include "cfd_proxy_api.h"
48
//----------------------------------------------------------------------------
53
} /* Fake brace to force back Emacs auto-indentation back to column 0 */
55
#endif /* __cplusplus */
57
//============================================================================
58
// Local type and structure definitions
59
//============================================================================
63
CFD_PROXY_UNDEF, // Mode not defined yet
64
CFD_PROXY_LOAD, // Load a shared library
65
CFD_PROXY_SPAWN // Execute a sub-process
69
// Main CFD_proxy object
73
cfd_proxy_mode_t mode; // CFD code execution mode
85
//============================================================================
86
// Static global variables
87
//============================================================================
89
static _cfd_proxy_t _proxy = {CFD_PROXY_UNDEF, 0, 0, NULL, NULL, NULL, NULL};
91
//============================================================================
92
// Private function definitions
93
//============================================================================
95
//----------------------------------------------------------------------------
96
// Set arguments in a structure.
99
// n_args <-- number of arguments defined
100
// args <-- array of argument strings.
101
// s_n_args <-> pointer to structure's n_args
102
// s_args <-> pointer to structure's args
103
//----------------------------------------------------------------------------
106
_set_args_by_list(int n_args,
112
size_t args_size = 0;
114
int _n_args = *s_n_args;
115
char **_args = *s_args;
122
for (i = 0; i < n_args; i++) {
125
args_size += (strlen(args[i]) + 1);
129
CFDP_MALLOC(_args, _n_args, char*);
130
CFDP_MALLOC(_args[0], args_size, char);
135
for (i = 1, args_size = strlen(args[0]) + 1;
138
_args[i] = _args[0] + args_size;
139
args_size += (strlen(args[i]) + 1);
142
for (i = 0, args_size; i < _n_args; i++)
143
strcpy(_args[i], args[i]);
151
//----------------------------------------------------------------------------
152
// Set arguments in a structure, using a complete arguments string.
155
// args <-- argument string
156
// s_n_args <-> pointer to structure's n_args
157
// s_args <-> pointer to structure's args
158
//----------------------------------------------------------------------------
161
_set_args_by_string(const char *args,
165
size_t i, tok_len, start_quote_id;
167
int protected; // 0 for unprotected, 1 for protected char, 2 for substring,
168
// 3 for protected char in substring
169
size_t args_size = 0, s_size = 0;
171
int _n_args = *s_n_args;
172
char **_args = *s_args;
185
args_size = strlen(args);
187
// Estimate number of arguments (may overestimate, not underestimate)
189
for (i = 0, _n_args = 1; i < args_size; i++) {
191
if (c == ' ' || c == '\t' || c == '\n'|| c == '\r')
195
// Prepare tokenization of the arguments string
197
CFDP_MALLOC(_args, _n_args, char*);
198
CFDP_MALLOC(_args[0], args_size + 1, char);
206
i = 0; // String position marker
207
start_quote_id = args_size; // Start position marker for quoted strings
208
// (unset if j == j, set if j < args_size)
213
while (i < args_size) {
217
// Regular case, where previous character was not protected
219
if (protected == 0) {
221
// Protection character
226
// Fully protected string
228
else if (c == '"' || c == '\'') {
235
else if (c == ' ' || c == '\t' || c == '\n'|| c == '\r') {
236
if (tok_len > 0) { // Finish previous token
237
_args[_n_args] = s + s_size;
238
s[s_size + tok_len] = '\0';
245
// Regular characters (token)
248
s[s_size + tok_len] = args[i];
250
_args[_n_args] = s + s_size;
256
// Cases where previous character was protected
258
else if (protected == 1) {
261
s[s_size + tok_len] = args[i];
263
_args[_n_args] = s + s_size;
268
else if (protected == 2) {
270
// Single protection character
275
// End of string protection
277
else if (c == args[start_quote_id]) {
279
start_quote_id = args_size;
283
s[s_size + tok_len] = args[i];
285
_args[_n_args] = s + s_size;
291
else { // if (protected == 3)
293
s[s_size + tok_len] = args[i];
295
_args[_n_args] = s + s_size;
303
} /* End of loop in infix string characters */
305
if (tok_len > 0) { /* Finish previous token */
306
_args[_n_args] = s + s_size;
307
s[s_size + tok_len] = '\0';
314
cfd_proxy_error(__FILE__, __LINE__, 0,
315
_("Error tokenizing expression:\n"
317
"Missing character after \\\n"),
319
else if (protected >= 2)
320
cfd_proxy_error(__FILE__, __LINE__, 0,
321
_("Error tokenizing expression:\n"
323
"Missing closing quote for subexpression:\n"
325
args, args + start_quote_id);
327
// Resize to adjusted size (do not resize _args[0], as _args[i]
328
// would then need to be updated, and extra size is limited.
330
CFDP_REALLOC(_args, _n_args, char *);
332
for (i = s_size; i < args_size; i++)
341
//----------------------------------------------------------------------------
342
// Set working directory.
345
// path <-- new working directory
348
// 0 on success, -1 on error
349
//----------------------------------------------------------------------------
352
_change_dir(const char *path)
358
retval = chdir(path);
361
cfd_proxy_error(__FILE__, __LINE__, errno,
362
_("Error setting the working directory to:\n"
370
//============================================================================
372
//============================================================================
374
//----------------------------------------------------------------------------
375
// Set the proxy's associated supervisable SALOME component.
377
// Multiple components may be asociated with the proxy if necessary,
378
// using a different id for each (0 for the first). This may be useful
379
// in threaded cases used for multiple couplings.
382
// component <-- pointer of type Superv_Component_i* to the
383
// supervisable SALOME component
384
// component_id <-- id of component (0 by default, >= 0 if multiple
385
// components are managed in the same process space,
386
// which may be possible with multiple threads)
387
//----------------------------------------------------------------------------
390
cfd_proxy_set_component(void *component,
393
if (component_id < 0)
396
if (component_id > cfd_proxy_glob_n_components) {
398
if (cfd_proxy_glob_n_components == 1)
399
// pointed to stack value, see cfd_proxy_defs.c
400
cfd_proxy_glob_component = NULL;
402
CFDP_REALLOC(cfd_proxy_glob_component, component_id+1, void *);
406
cfd_proxy_glob_component[component_id] = component;
409
//----------------------------------------------------------------------------
410
// Set command-line arguments for execution, using an argument array.
412
// Only user arguments need to be defined (i.e. the executable file
413
// at argv[0] is set automatically, so only argv[1] to argv[argc-1]
414
// need to be defined here.
417
// n_args <-- number of arguments defined
418
// args <-- array of argument strings.
419
//----------------------------------------------------------------------------
422
cfd_proxy_set_args_by_list(int n_args,
425
_set_args_by_list(n_args, args, &(_proxy.n_args), &(_proxy.args));
428
//----------------------------------------------------------------------------
429
// Set command-line arguments for execution, using a single string.
431
// Arguments are separated by whitespace. Whitespaces may be protected
432
// using couples of " or ' quotes, or single \ escape characters.
434
// Only user arguments need to be defined (i.e. the executable file
435
// at argv[0] is set automatically, so only argv[1] to argv[argc-1]
436
// need to be defined here.
439
// args <-- arguments string.
440
//----------------------------------------------------------------------------
443
cfd_proxy_set_args(const char *args)
445
_set_args_by_string(args, &(_proxy.n_args), &(_proxy.args));
448
//----------------------------------------------------------------------------
449
// Set working directory.
452
// path <-- new working directory
453
//----------------------------------------------------------------------------
456
cfd_proxy_set_dir(const char *path)
459
CFDP_REALLOC(_proxy.dirname, strlen(path) + 1, char);
460
strcpy(_proxy.dirname, path);
464
//----------------------------------------------------------------------------
465
// Set shared library (also setting the shared library proxy mode)
468
// filename <-- name of dynamic library file
469
//----------------------------------------------------------------------------
472
cfd_proxy_set_lib(const char *filename)
474
#if defined(HAVE_DLOPEN)
476
size_t alloc_size = strlen(filename) + 1;
478
// Avoid valgrind warning on Linux which seems to be due to dlopen
479
// reading in multiples of size_t by allocating a slightly larger buffer.
481
if (alloc_size % sizeof(size_t))
482
alloc_size += sizeof(size_t) - (alloc_size % sizeof(size_t));
484
_proxy.mode = CFD_PROXY_LOAD;
486
CFDP_REALLOC(_proxy.filename, alloc_size, char);
487
memset(_proxy.filename, '\0', alloc_size);
489
strcpy(_proxy.filename, filename);
494
//----------------------------------------------------------------------------
495
// Set executable (also setting the child/IPC proxy mode)
498
// filename <-- name of executable file
499
//----------------------------------------------------------------------------
502
cfd_proxy_set_exe(const char *filename)
504
_proxy.mode = CFD_PROXY_SPAWN;
506
CFDP_REALLOC(_proxy.filename, strlen(filename) + 1, char);
507
strcpy(_proxy.filename, filename);
510
//----------------------------------------------------------------------------
511
// Define intermediate launcher and associated arguments (only of use for
512
// the child/IPC proxy mode), using an argument array.
514
// This allows running the child executable through another process, such
515
// as mpiexec (for parallel runs), or a debugger.
518
// n_launcher_args <-- number of arguments defined
519
// launcher_args <-- array of string arguments (the first of which
520
// should be the launcher executable file name)
521
//----------------------------------------------------------------------------
524
cfd_proxy_set_launcher_by_list(int n_launcher_args,
525
const char *launcher_args[])
527
_set_args_by_list(n_launcher_args,
529
&(_proxy.n_launcher_args),
530
&(_proxy.launcher_args));
533
//----------------------------------------------------------------------------
534
// Define intermediate launcher and associated arguments (only of use for
535
// the child/IPC proxy mode), using a single string.
537
// This allows running the child executable through another process, such
538
// as mpiexec (for parallel runs), or a debugger.
540
// Arguments are separated by whitespace. Whitespaces may be protected
541
// using couples of " or ' quotes, or single \ escape characters.
544
// launcher_args <-- string of launcher arguments (the first of which
545
// should be the launcher executable file name)
546
//----------------------------------------------------------------------------
549
cfd_proxy_set_launcher(const char *launcher_args)
551
_set_args_by_string(launcher_args,
552
&(_proxy.n_launcher_args),
553
&(_proxy.launcher_args));
556
//----------------------------------------------------------------------------
557
// Run full execution of the CFD code
560
// execution's return value (or prior error code if execution impossible);
561
//----------------------------------------------------------------------------
572
extern char **environ;
574
if (_proxy.dirname != NULL) {
576
size_t old_wd_size = 128;
579
// Save old working directory
581
CFDP_MALLOC(old_wd, old_wd_size, char);
583
wd = getcwd(old_wd, old_wd_size);
584
while (wd == NULL && errno == ERANGE) {
586
CFDP_REALLOC(old_wd, old_wd_size, char);
587
wd = getcwd(old_wd, old_wd_size);
590
CFDP_REALLOC(old_wd, strlen(old_wd) + 1, char);
594
(_("Could not obtain and save current working directory.\n"));
597
// Switch to working directory
599
retval = _change_dir(_proxy.dirname);
604
// Handle shared library mode
605
//---------------------------
607
#if defined(HAVE_DLOPEN)
609
if (_proxy.mode == CFD_PROXY_LOAD) {
613
CFDP_MALLOC(_argv, 1 + _proxy.n_args + 1, char *);
615
_argv[n_args++] = _proxy.filename;
617
for (arg_id = 0; arg_id < _proxy.n_args; arg_id++)
618
_argv[n_args++] = _proxy.args[arg_id];
620
_argv[n_args] = NULL;
622
retval = cfd_proxy_loader_init(_proxy.filename);
625
retval = cfd_proxy_loader_run(1 + _proxy.n_args, _argv);
627
cfd_proxy_loader_finalize();
632
#endif // defined(HAVE_DLOPEN)
637
#if defined(HAVE_POSIX_SPAWN) || defined(HAVE_FORK_EXECVE)
639
if (_proxy.mode == CFD_PROXY_SPAWN) {
641
cfd_proxy_child_t *child = NULL;
642
char **child_argv = NULL;
644
CFDP_MALLOC(child_argv,
645
_proxy.n_launcher_args + 1 + _proxy.n_args + 1,
648
for (arg_id = 0; arg_id < _proxy.n_launcher_args; arg_id++)
649
child_argv[n_args++] = _proxy.launcher_args[arg_id];
651
child_argv[n_args++] = _proxy.filename;
653
for (arg_id = 0; arg_id < _proxy.n_args; arg_id++)
654
child_argv[n_args++] = _proxy.args[arg_id];
656
child_argv[n_args] = NULL;
658
child = cfd_proxy_child_start(child_argv[0],
660
CFD_PROXY_COMM_TYPE_SOCKET, 10);
664
cfd_proxy_child_forward_all(child);
666
retval = cfd_proxy_child_stop(&child);
673
CFDP_FREE(child_argv);
676
#endif // if defined(HAVE_POSIX_SPAWN) || defined(HAVE_FORK_EXECVE)
678
if (old_wd != NULL) {
686
//----------------------------------------------------------------------------
690
#endif /* __cplusplus */