2015-04-01 7 views
1

J'essaye d'intégrer la bibliothèque d'octave dans un programme plus grand. Il est nécessaire que je puisse démarrer et arrêter l'interprète d'octave à volonté à partir de ce programme plus grand. Cependant, la seule fonction permettant d'arrêter proprement l'interpréteur d'octave appelle également exit(), ce qui tue également le plus grand programme. La fonction de la bibliothèque d'octave est clean_up_and_exit().Appeler une fonction de bibliothèque avec une torsion - modifier une partie de son comportement

Idéalement, je voudrais appeler seulement la partie de nettoyage (do_octave_atexit), et passer l'appel pour quitter.

J'ai essayé les éléments suivants:

1) appelant do_octave_atexit, mais le symbole est pas exporté dans la bibliothèque d'octave. J'ai essayé d'y accéder de toute façon mais en vain.

2) J'ai essayé de me connecter à l'appel pour quitter et de le remplacer par une fonction qui ne se termine pas, via ld_preload. Cela a gâché tout comme tous les autres appels à la sortie ont été accrochés aussi.

3) J'ai essayé de détecter quand la sortie était appelée par octave seulement pour l'empêcher seulement alors, en détectant la fonction d'appel avec un appel de backtrace. Ceci pour une raison quelconque n'a pas montré ce que je m'attendrais à être la vraie hiérarchie d'appel. Pour une raison quelconque, il n'a montré que la fonction principale, et aucun contenu de la hiérarchie d'appel à travers la bibliothèque d'octave. Donc dans n'a pas pu détecter l'appel venant d'octave.

Le code J'utilise pour appeler les fonctions d'octave ressemble:

// 
// Octave Setup Functions 
// 
extern "C" void oct_init (const char * path) { 
    string_vector argv (2); 
    argv(0) = "embedded"; 
    argv(1) = "-q"; 

    octave_main (2, argv.c_str_vec(), 1); 
    if(strlen(path) > 1) { 
    oct_addpath(path); 
    } 
} 

extern "C" void oct_exit (void) { 
    printf("Exiting!"); 
    clean_up_and_exit (1,1); 
} 

La fonction clé ici est clean_up_and_exit - qui est mis en œuvre dans la source d'octave comme:

void clean_up_and_exit (int retval, bool safe_to_return) 
{ 
    do_octave_atexit(); 

    if (octave_link::exit (retval)) 
    { 
    if (safe_to_return) 
     return; 
    else 
    { 
     gnulib::sleep (86400); 
    } 
} 
else 
{ 
    if (octave_exit) 
    (*octave_exit) (retval); 
} 
} 

Ainsi, le ci-dessus code appelle la fonction que je veux (do_octave_atexit), mais continue à appeler * octave_exit - qui est un pointeur de fonction à exit().

Idéalement, je veux soit a) empêcher cet appel de quitter(), soit b) intercepter l'appel quand il vient d'octave seulement et l'empêcher, et l'autoriser quand il vient d'autres sources. Je n'ai pas été capable de faire a) ou b) jusqu'à présent!

Donc à ce stade, je suis à court d'idées. Je pourrais recompiler l'octave, mais cette solution est supposée fonctionner avec une installation octave en stock.

Cela ne devait fonctionner que sur un environnement linux/gcc.

Toutes les suggestions à ce problème très délicat ont été grandement appréciées.

+1

pourriez-vous montrer votre exemple de code, celui où vous démarrez l'interpréteur d'octave, quittez, et l'amène également à quitter votre propre programme? – carandraug

+1

Qu'en est-il de l'exécution d'octave en tant que processus séparé et de communication par tuyau? – fukanchik

+0

@fukanchik Cela semble très intéressant comme alternative. Avez-vous des exemples de comment cela peut être fait à partir de C? Le tuyau peut-il être ouvert comme un «handle» qui persiste entre plusieurs appels jusqu'à ce qu'il soit fermé? –

Répondre

1

Vous devrez bifurquer et exécuter Octave dans un processus séparé. Voici un exemple simple sur la façon de le faire:

#include <unistd.h> 
#include <iostream> 

#include <octave/oct.h> 
#include <octave/octave.h> 
#include <octave/parse.h> 
#include <octave/toplev.h> 

int 
main_octave (void) 
{ 
    string_vector argv (2); 
    argv(0) = "embedded"; 
    argv(1) = "-q"; 

    octave_main (2, argv.c_str_vec(), 1); 

    octave_value_list out = feval ("pi", octave_value_list (0), 1); 
    if (! error_state && out.length() > 0) 
    std::cout << "pi is " << out(0).double_value() << std::endl; 
    else 
    std::cout << "invalid\n"; 

    clean_up_and_exit (0); 
} 

int 
main (void) 
{ 
    pid_t pid = fork(); 
    if (pid == 0) 
    main_octave(); 
    else if (pid > 0) 
    { 
     std::cout << "Parent process going for a nap" << std::endl; 
     sleep (5); 
    } 
    else 
    { 
     std::cout << "Unable to fork()" << std::endl; 
     return 1; 
    } 
    std::cout << "Leaving standalone application" << std::endl; 
    return 0; 
} 

Ce qui sur mon système retourne:

$ mkoctfile --link-stand-alone embedded.cc -o embedded 
$ ./embedded 
Parent process going for a nap 
pi is 3.14159 
Leaving standalone application 

vous pouvez donc continuer à courir votre application après la sortie du processus Octave. Bien sûr, si vous voulez démarrer et arrêter Octave plusieurs fois, vous devrez le faire plusieurs fois. De plus, je vous recommande de poser de telles questions sur la liste de diffusion d'aide d'Octave, vous aurez plus de chances d'obtenir des réponses utiles plus rapidement.

+0

Merci pour cela. J'ai soumis cette question à la liste de diffusion d'Octave-General, même si, malheureusement, elle n'a pas attiré beaucoup d'attention. Une chose que je ne comprends pas avec la méthode fork est de savoir comment accéder au processus fils à plusieurs reprises depuis le processus parent. Les fonctions de départ et de sortie séparées de l'original étaient parce que le parent commence octave, puis exécute N appels à feval (qui ne sont pas prédéterminés au moment de la compilation), puis quitte l'octave. Ce processus peut répéter plusieurs fois. Donc, votre méthode fonctionnerait - mais je pense que j'aurais besoin d'un 'handle' pour communiquer avec le processus de l'enfant? –