Anmelden

Archiv verlassen und diese Seite im Standarddesign anzeigen : Erneute Frage zu dlopen und allem was dazugehört



ufosworld
28-06-2007, 13:28
Habe hier ein kleines Problem mit dem dlopen

also Files lädt es, das passt... ich kann auch auf die Funktion in der Datei zugreifen...

nun das Problem:

ich habe eine verkettete Liste... in der stehn Parameter.. z.b. für einen Schnittstelle...

dann habe ich verschiedene .so dateien in dennen ich diese Liste benötige...

is ja kein Problem, weil ich kann ja was übergeben bei dem Aufruf der .so datei... das sieht bei mir soo aus... mal auf das nötigste beschränkt...

modulHandle = dlopen(filename_der_so_file, RTLD_LAZY);
//Fehlerabgfragen...
modul= dlsym(modulHandle,functionsname_in_der_so_file);
//Fehlerabfragen...

// Aufruf der Funktion mit Übergabe der Verketteten Liste *LoadModul
// das muss natürlich so sein, das man zurückgelieferte Werte auch
// empfangen kann
printf("\n",(*modul)(*LoadModul));


in dem Modul wird dann folgendes gemacht

1. die verkettete Liste LoadModul ausgewertet, indem die gespeicherten Werte darin verwendet werden, um z.b. Verbindung zu einer Schnittstelle auszubauen... (hier unrelevant, da ich nur die Parameter bereitstellen soll
den Aufbau der Verbindung macht jemand anderes)

2. in die typedef std::list<boost::any> many;
many values;
werden mittels push_back() Werte reingeschrieben, die von der
Schnittstelle kommen( das macht ich testhalber per Hand und das geht
auch ... also z.B. values.push_back(value);)

3. Nun werden am Ende des Moduls der Alias values (in der die ganzen Werte
gespeichert sind) zurückgegeben... jetzt kommen wir dem Problem langsam
näher...

Im Hauptprogramm soll nun eine weitere .so File geöffnet werden, an die wiederum eine weitere ParameterListe (mit anderen SchnittstellenParametern) und eben die Liste values gesendet werden soll, die ich aus dem ersten modul zurückgeliefert bekommen habe...

nur leider bekomme ich das nicht hin...

Probleme sind folgende...

1. Wie es aussieht kann man bei dem Aufruf der .so Datei bzw dem Aufruf der
Funktion in der .so Datei ( siehe oben: printf("\n",(*modul)(*LoadModul)); )
nur einen Parameter mit übergeben, und dieser wird ja schon von der
ParameterListe *LoadModul besetzt !!

2. Wie muss der Aufruf der Funktion in der .so Datei aussehn
so das ich im Hauptprogramm auf die zurückgegebenen Daten in
many values zugreifen kann??
values = (*input)(*LoadModul);

3. was muss ich im Hauptprogramm einbinden?

using boost::any_cast;
typedef std::list<boost::any> many;
many values;

4. Wie kann ich das ganze so machen das in der Art rauskommt...
values = (*work) (*LoadModul,*values);

also Rückgabewert = (ModulHandle) (ParameterListe, DatenListe)



Was ich schlichtweg will, ist eine Parameterübergabe in das nächste Modul (.so File) mit Zwischenstation im Main Programm.

Kann mir irgendwer Tips geben... bin hier echt am verzweifeln... jeden Versuch den ich mache beurteilt der Compiler mit Fehlern...
im Modul 1 kann ich wenn ich die per Hand gespeicherten Werte ausgeben... kein Problem... also drin sind welche...
nur muss ich die irgendwie in die zweite .so bekommen, damit ich diese weiter bearbeiten kann... und dann noch in die dritte, um die veränderten Werte in values auf eine andere Schnittstelle ausgeben zu können...

is echt wichtig... wie es aussieht ist das der Knackpunkt beim ganzen Programm

anda_skoa
28-06-2007, 17:49
Nachdem du bei der dlsym Funktion auf C Möglichkeiten angewiesen bist, hast du ein paar Einschränkungen, etwa keine Referenzen oder Typedefs von Templates.

Du kannst zum Beispiel den Typedef durch eine "leere" Ableitung ersetzen, ca. so


class many : public std::list<any> {};

bzw. dann bei der Deklaration der C Funktionen


struct many;

many* process(many* data);
// oder
int process(many* data); // Fehlercodes als Rückgabe, data wird geändert


Eine andere Möglichkeit ist, als C Funktionen die Erzeugung und Löschung eines C++ Objekts zu nehmen, d.h. eine gemeinsame C++ Basisklasse für Plugins.

In etwa so



typedef std::list<any> many;

class PluginBase
{
public:
virtual ~PluginBase();

many process(const many& data);
// oder
bool process(many& data);
// oder mit einem Error Enum
PluginError process(many& data);
// oder auch mit exceptions, etc
};

Die C Funktionen sehen dann etwa so aus


struct PluginBase;

PluginBase* createPlugin();

void deletePlugin(PluginBase* plugin)


Ciao,
_

ufosworld
29-06-2007, 08:42
??? sry aber ich hab keinen plan was du meinst... vielleicht weil freitag is.. ^^

ich kann also in Verbindung mit
dlsym keinen 3ten Parameter beim Auftruf angeben

newvalues = (*work) (*LoadModul,*values);

ich bin immer auf den Aufruf (*work) (*LoadModul) beschränkt...

das kann doch net sein....

ich hab doch oben das definiert...

void *(*work)(TModulK);

kann man da net einfach

many (*work)(TModulK)(many)

machen?


oder

kann ich eventl das

typedef std::list<boost::any> many;
many values;

aus dem 1sten Modul, so global machen das ich auf die Werte, ohne Übergabe zurück in Hauptprogramm, zugreifen kann...

panzi
01-07-2007, 15:29
Das ist ein allgemeines Beispiel (nicht deine Angabe). Eventuell hilft dir funktionierenden Code zu sehn, der ähnliches macht:

modul.hpp

#ifndef PANZI_MODUL_HPP__
#define PANZI_MODUL_HPP__

#include <list>
#include <string>

class Modul {
public:
virtual ~Modul() {}
virtual int method(std::list<int> & arg1, int arg2, const std::string & arg3) = 0;
};

#endif /* PANZI_MODUL_HPP__ */

modul-a.cpp (modul-a.so)

#include <iostream>
#include <boost/smart_ptr.hpp>
#include "modul.hpp"

class ModulA : public Modul {
public:
ModulA() {
std::cout << "new" << std::endl;
}

virtual ~ModulA() {
std::cout << "delete" << std::endl;
}

virtual int method(std::list<int> & arg1, int arg2, const std::string & arg3) {
std::cout << "arg1.size(): " << arg1.size() << std::endl
<< "arg2: " << arg2 << std::endl
<< "arg3: " << arg3 << std::endl;
return 42;
}
};

/**
* Damit keine Warnings kommen exportiere ich ein Objekt und keine Funktion.
* Ist auch schöner Objektorientiert.
* Pointer auf Funktionen haben auf manchen exotischen Plattformen eine andere
* größe als Pointer auf Objekte und dlsym() liefert void* (Pointer auf Objekt)
* und nicht void (*)() (Pointer auf Funktion). Deswegen schreit gcc wenn man
* eine Funktion mit dlsym() lädt.
*/
extern "C" { boost::shared_ptr<Modul> modul( new ModulA() ); }

Kompelieren:

g++ -Wall -pedantic -shared -o modul-a.so modul-a.cpp

Programm, welches das Modul verwendet:
modul-test.cpp (modul-test)

#include <dlfcn.h>
#include <iostream>
#include <boost/smart_ptr.hpp>
#include "modul.hpp"

int main(int argc, char * argv[]) {
if(argc != 3) {
std::cerr << "usage: modul-test <modul.so> <method>" << std::endl;
return 1;
}
void * handle = dlopen(argv[1],RTLD_LAZY);

if(!handle) {
std::cerr << "error dlopen(): " << dlerror() << std::endl;
return 1;
}
{
/**
* Der Smartpointer in der .so muss das Objekt löschen.
* Wenn der hier es zu löschen versucht gibt's einen Segmentation Fault
* (d.h. Speicherzugriffsfehler). Deswegen dieses Scope hier, um
* sicher zu stellen welcher Smartpointer löscht.
*/
void * ptr = dlsym(handle,argv[2]);

if(!ptr) {
std::cerr << "error dlsym(): " << dlerror() << std::endl;
dlclose(handle);
return 1;
}

boost::shared_ptr<Modul> modul( *((boost::shared_ptr<Modul>*)ptr) );

std::list<int> l;
l.push_back(23);
l.push_back(5);

int x = modul->method(l, 128, "foo bar");

std::cout << "return value: " << x << std::endl;
}
dlclose(handle);
return 0;
}

Kompelieren:

g++ -Wall -pedantic -o modul-test modul-test.cpp -ldl

Ausführen:

./modul-test ./modul-a.so modul

Ausgabe:

new
arg1.size(): 2
arg2: 128
arg3: foo bar
return value: 42
delete

Zu den Smartpointern:
Das kann man auch einfacher machen. Die Sache ist nur die, dass ich das Objekt in modul-a.so per new anlege und es auch von code in modul-a.so gelöscht werden muss. Um dies zu gewährleisten hab ich einen Smartpointer verwendet. Altanativ könnte man auch das Objekt direkt am Stack anlegen (also ohne new), aber da muss es dann genau vom richtigen Typ sein (nicht von einen abgeleiteten Typ von Modul sondern genau Modul). Wenn ich es trotzdem vom Typ ModulA machen würde, täte es sicher oft trotzdem funktionieren, bis ich Mehrfachvererbung verwende. Dann ist nach dem cast von void* -> Modul* der Objektzeiger nicht richtig korrigiert und zeigt auf einen falschen Bereich im Speicher -> Segmentation Fault. Also hab ichs mit den Smartpointern gmacht. Die haben in Zusammenhang mit dlopen aber einen Nachteil: Ein objekt das in einer .so angelegt wird, muss auch wieder in dieser .so gelöscht werden (und nicht von anderem Code). Deswegen hab ich den Scope im modul-test.cpp eingebaut, um sicherzustellen, dass der richtige Smartpointer das Objekt löscht.


MfG, panzi

PS: So jetzt muss ich für den Test morgen weiter lernen.

ufosworld
02-07-2007, 11:57
Ich bekomme nach der Rückgabe der Werte aus dem ersten Modul
und beim Aufruf des zweiten Moduls mit Übergabe-Parameter eine
Speicherschutzverletzung.

folgenden Code für den Aufruf der Funktionen habe ich erstellt:


im Hauptprogramm:

using boost::any_cast;
typedef std::list<boost::any> many; //definiere Typ Standardliste mit Datentyp <boost::any>
many values;
many values_from_input;
many values_from_work;

many (*input)(TModulK LoadModul,many values);
many (*work) (TModulK LoadModul,many values);

//Laden des Moduls Input
....
inputHandle = dlopen(filename, RTLD_LAZY);
....
input= dlsym(inputHandle,funcname);
....
Jetzt kommt der Aufruf der Funktion im Modul Input
values ist bisher nicht belegt...nur erstellt..

values_from_input = (*input)(*LoadModul,values);

im Modul Input hat dann folgenden gekürzten Code:

using boost::any_cast;
typedef std::list<boost::any> many;

using namespace std;

extern "C" many input(TModulK* LoadModul, many values)
{
//fülle values mit Werten

// in einer Schleife von 1 - 100 damit mal 800 Werte gespeichert werden
// is übrigens egal ... ob nur 8 oder 800 werte gespeichert werden... der
// fehler kommt immer
append_any(values,12345);
append_any(values,67890);
append_any(values,"wird gelöscht");
append_int(values,5);
append_any(values,"als Char_ptr");
append_nothing(values); // nichts anfügen...
append_string(values,"ich bin String-Wert");
append_int(values,999);

//ausgabe der Anzahl der gespeicherten Werte (geht und stimmt auch)
count_all(values);

return (values);
}


zurück in das Hauptprogramm:
Lade das Work Modul

... (filename mit anderem Wert gefüllt)
workHandle = dlopen(filename, RTLD_LAZY);
...
work = dlsym(workHandle,funcname);

Aufruf des Moduls Work mit Übergabe LoadModul und values_from_input

cout << "Hier kackt er ab!!" <<endl;
values_from_work = (*work)(*LoadModul,values_from_input);

....


im Modul work wenn ich da gleich am anfang der Funktion ein Cout mache kommt er da gar nicht mehr hin...

wenn ich das ganze dann kompiliere und ausführe kommt folgende Meldung:


Aufruf:


projektxml test2.xml


File: test2.xml successfully loaded.
// ( in ihr stehen dann mal die Schnittstellenparameter drin)

Library : input.so loaded! // das erste Modul wurde erfolgreich geladen
#empty == 100
#int == 400
#const char * == 200
#string == 100
//das war die Ausgabe die count_all(values); liefert


Input-Handle closed

Library : work.so loaded!
Hier kackt er ab!! //siehe Quellecode (cout <<"Hier kackt er ab!!" <<endl;)
Speicherschutzverletzung



warum kommt da nee Speicherschutzverletzung??
werden die Werte von der Input Funktion nicht sauber zurückgegeben??
hab ich nen Fehler mit der values Variable?
Übergabeparameter falsch??



merci UFOSWORLD

p.s. (die Zahlen == 400 usw... stellen die Anzahl der gespeicherten Werte dar)

bevor ich das many Zeugs eingebaut habe lief das Programm einwandfrei durch... aber es wurden keine in Modulen gespeicherte Werte von Funktion zu Funktion übergeben, sondern nur immer das *LoadModul das ich aus der XML file rausziehe und dann in die verkettete Liste LoadModul speichere
Das funktionierte alles TOP!!

panzi
02-07-2007, 17:45
im Hauptprogramm:

using boost::any_cast;
typedef std::list<boost::any> many; //definiere Typ Standardliste mit Datentyp <boost::any>
many values;
many values_from_input;
many values_from_work;

/* der erste Parameter muss doch wohl ein Pointer sein, sprich TModulK * LoadModul
* (so wie in der Funktion im Modul. Siehe weiter untern.)
*/
many (*input)(TModulK LoadModul,many values);
many (*work) (TModulK LoadModul,many values);

//Laden des Moduls Input
....
inputHandle = dlopen(filename, RTLD_LAZY);
....
input= dlsym(inputHandle,funcname);
....
Jetzt kommt der Aufruf der Funktion im Modul Input
values ist bisher nicht belegt...nur erstellt..

/* Das hier sollte auch schon abstürzen, oder? */
values_from_input = (*input)(*LoadModul,values);

im Modul Input hat dann folgenden gekürzten Code:

using boost::any_cast;
typedef std::list<boost::any> many;

using namespace std;

extern "C" many input(TModulK* LoadModul, many values)
{
//fülle values mit Werten

// in einer Schleife von 1 - 100 damit mal 800 Werte gespeichert werden
// is übrigens egal ... ob nur 8 oder 800 werte gespeichert werden... der
// fehler kommt immer
append_any(values,12345);
append_any(values,67890);
append_any(values,"wird gelöscht");
append_int(values,5);
append_any(values,"als Char_ptr");
append_nothing(values); // nichts anfügen...
append_string(values,"ich bin String-Wert");
append_int(values,999);

//ausgabe der Anzahl der gespeicherten Werte (geht und stimmt auch)
count_all(values);

return (values);
}


zurück in das Hauptprogramm:
Lade das Work Modul

... (filename mit anderem Wert gefüllt)
workHandle = dlopen(filename, RTLD_LAZY);
...
work = dlsym(workHandle,funcname);

Aufruf des Moduls Work mit Übergabe LoadModul und values_from_input

cout << "Hier kackt er ab!!" <<endl;
/* Ist ja auch logisch. Im Modul hast du den ersten Parameter
* der Funktion als Pointer deklariert, hier aber castest du die Funktion zu
* einen Typen die als ersten Parameter einen Wert will (deswegen machst
* du ja auch das * vorm LoadModul).
*/
values_from_work = (*work)(*LoadModul,values_from_input);

....

ufosworld
03-07-2007, 15:10
hab etz mal ein paar fragen dazu, weil irgendwie geht da gar nix wenn ich da die Sterne einfüge...




im Hauptprogramm:

using boost::any_cast;
typedef std::list<boost::any> many; //definiere Typ Standardliste mit Datentyp <boost::any>
many values;
many values_from_input;
many values_from_work;

/* der erste Parameter muss doch wohl ein Pointer sein, sprich TModulK * LoadModul
* (so wie in der Funktion im Modul. Siehe weiter untern.)
*/

also muss das dann heissen
many (*input)(TModulK * LoadModul,many values); ???


many (*input)(TModulK LoadModul,many values);
many (*work) (TModulK LoadModul,many values);

//Laden des Moduls Input
....
inputHandle = dlopen(filename, RTLD_LAZY);
....
input= dlsym(inputHandle,funcname);
....
Jetzt kommt der Aufruf der Funktion im Modul Input
values ist bisher nicht belegt...nur erstellt..

/* Das hier sollte auch schon abstürzen, oder? */
Na eben nicht.... er geht ganz normal in die Funktion in dem Modul und befüllt many values
values_from_input = (*input)(*LoadModul,values);

im Modul Input hat dann folgenden gekürzten Code:

using boost::any_cast;
typedef std::list<boost::any> many;

using namespace std;

Wie sollte der Funktionskopf dann sein, damit das funzt...
mit Stern, ohne Stern, mit & ohne & ???
extern "C" many input(TModulK* LoadModul, many values)
{
//fülle values mit Werten

// in einer Schleife von 1 - 100 damit mal 800 Werte gespeichert werden
// is übrigens egal ... ob nur 8 oder 800 werte gespeichert werden... der
// fehler kommt immer
append_any(values,12345);
append_any(values,67890);
append_any(values,"wird gelöscht");
append_int(values,5);
append_any(values,"als Char_ptr");
append_nothing(values); // nichts anfügen...
append_string(values,"ich bin String-Wert");
append_int(values,999);

//ausgabe der Anzahl der gespeicherten Werte (geht und stimmt auch)
count_all(values);

return (values);
}


zurück in das Hauptprogramm:
Lade das Work Modul

... (filename mit anderem Wert gefüllt)
workHandle = dlopen(filename, RTLD_LAZY);
...
work = dlsym(workHandle,funcname);

Aufruf des Moduls Work mit Übergabe LoadModul und values_from_input

cout << "Hier kackt er ab!!" <<endl;
/* Ist ja auch logisch. Im Modul hast du den ersten Parameter
* der Funktion als Pointer deklariert, hier aber castest du die Funktion zu
* einen Typen die als ersten Parameter einen Wert will (deswegen machst
* du ja auch das * vorm LoadModul).
*/
wie sollte der Aufruf dann deiner Meinung nach sein?


values_from_work = (*work)(*LoadModul,values_from_input);

....

ufosworld
04-07-2007, 15:37
Dieses DLOPEN und die Parameterübergabe bringt mich noch in Grab...
:( :mad: :( :mad:

Hab noch ein bischen gegoogelt und da folgende Möglichkeit gefunden.

modul-test.cpp


// Aufruf modul-test modul-a.so modul
// Wenn modul-a.so in Lib Verzeichniss kopiert wurde


/*
Zu den Smartpointern:
Das kann man auch einfacher machen. Die Sache ist nur die,
dass ich das Objekt in modul-a.so per new anlege und es
auch von code in modul-a.so gelöscht werden muss. Um dies
zu gewährleisten hab ich einen Smartpointer verwendet.
Altanativ könnte man auch das Objekt direkt am Stack anlegen
(also ohne new), aber da muss es dann genau vom richtigen
Typ sein (nicht von einen abgeleiteten Typ von Modul sondern
genau Modul). Wenn ich es trotzdem vom Typ ModulA machen
würde, täte es sicher oft trotzdem funktionieren, bis ich
Mehrfachvererbung verwende. Dann ist nach dem cast von
void* -> Modul* der Objektzeiger nicht richtig korrigiert und
zeigt auf einen falschen Bereich im Speicher -> Segmentation
Fault. Also hab ichs mit den Smartpointern gmacht. Die haben
in Zusammenhang mit dlopen aber einen Nachteil: Ein objekt
das in einer .so angelegt wird, muss auch wieder in dieser
.so gelöscht werden (und nicht von anderem Code). Deswegen
hab ich den Scope im modul-test.cpp eingebaut, um
sicherzustellen, dass der richtige Smartpointer das Objekt
löscht.
*/

#include <dlfcn.h>
#include <iostream>
#include <boost/smart_ptr.hpp>
#include "modul.hpp"

int main(int argc, char * argv[]) {
if(argc != 3) {
std::cerr << "usage: modul-test <modul.so> <method>" << std::endl;
return 1;
}
void * handle = dlopen(argv[1],RTLD_LAZY);

if(!handle) {
std::cerr << "error dlopen(): " << dlerror() << std::endl;
return 1;
}
{
/**
* Der Smartpointer in der .so muss das Objekt löschen.
* Wenn der hier es zu löschen versucht gibt's einen Segmentation Fault
* (d.h. Speicherzugriffsfehler). Deswegen dieses Scope hier, um
* sicher zu stellen welcher Smartpointer löscht.
*/
void * ptr = dlsym(handle,argv[2]);

if(!ptr) {
std::cerr << "error dlsym(): " << dlerror() << std::endl;
dlclose(handle);
return 1;
}

boost::shared_ptr<Modul> modul( *((boost::shared_ptr<Modul>*)ptr) );

std::list<int> l;
l.push_back(23);
l.push_back(5);
l.push_back(5);
l.push_back(5);

int x = modul->method(l, 128, "foo bar");

std::cout << "return value: " << x << std::endl;
}
dlclose(handle);
return 0;
}


dazu dann folgenden Modulcode
modul-a.cpp => modul-a.so


#include <iostream>
#include <boost/smart_ptr.hpp>
#include "modul.hpp"

class ModulA : public Modul {
public:
ModulA() {
std::cout << "new" << std::endl;
}

virtual ~ModulA() {
std::cout << "delete" << std::endl;
}

virtual std::int method(std::list<int> & arg1, int arg2, const std::string & arg3) {
std::cout << "arg1.size(): " << arg1.size() << std::endl
<< "arg2: " << arg2 << std::endl
<< "arg3: " << arg3 << std::endl;
return 42;
}
};

/**
* Damit keine Warnings kommen exportiere ich ein Objekt und keine Funktion.
* Ist auch schöner Objektorientiert.
* Pointer auf Funktionen haben auf manchen exotischen Plattformen eine andere
* größe als Pointer auf Objekte und dlsym() liefert void* (Pointer auf Objekt)
* und nicht void (*)() (Pointer auf Funktion). Deswegen schreit gcc wenn man
* eine Funktion mit dlsym() lädt.
*/
extern "C" {boost::shared_ptr<Modul> modul( new ModulA() ); }


und noch den Code für die hpp file


#ifndef PANZI_MODUL_HPP__
#define PANZI_MODUL_HPP__

#include <list>
#include <string>

class Modul {
public:
virtual ~Modul() {}
virtual int method(std::list<int> & arg1, int arg2, const std::string & arg3) = 0;
};

#endif /* PANZI_MODUL_HPP__ */



ist das dein Code @ Panzi... wäre ja zu geil wenn ich auf den tausenden Hits genau deinen gefunden hätte??

nun wollte ich meinen Code darauf anpassen...

also folgende Modullesefunktion geschrieben...



void LoadLibs(int queue_id)
{

// Hier kommen jetzt ein paar Ausleseroutinen, aus einer verketteten Liste, in der Functionsname und Modulname sowie Parameter abgespeichert wurden in einem anderen Modul...

const char *filename;
const char *funcname;
//const char *dlsym_error;


TModulK *LoadModul = NULL;
TQueueK *LoadQueue = NULL;

LoadQueue = SearchQueue(queue_id);

// Input

LoadModul = SearchModul(LoadQueue->queue_input);
filename = LoadModul->mod_name.c_str();

cout <<"name der Datei:"<< filename <<endl;

void* inputHand = dlopen(filename, RTLD_LAZY);


if (!inputHand)
{
cerr << "Cannot load library: " << dlerror() << endl;
// return 1;
}
{

funcname = LoadModul->func_name.c_str();

cout <<"name der Datei:"<< filename <<endl;
cout << "Name der Funktion: "<< funcname<< endl;

void * input = dlsym(inputHand,funcname);

if(!input) {
std::cerr << "error dlsym(): " << dlerror() << std::endl;
dlclose(inputHand);
// return 1;
}


cout << "da sind wir1"<<endl;

boost::shared_ptr<Modul> modul( *((boost::shared_ptr<Modul>*)input) );

cout << "da sind wir2"<<endl;

values_from_input = modul->inputer(*LoadModul, values);



}
dlclose(inputHand);

}


mein Modul sieht dann folglich aus...

input.cpp => input.so





#include <string>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <list>
#include <boost/any.hpp> // include muss vor "boostfunc.h" kommen
#include <boost/smart_ptr.hpp>
#include "standardstructs.h" // in "standardstructs.h" stehen die StandardStructs
// für die Listen drin und der typedef für
// std::list<boost::any> many;
using boost::any_cast;
typedef std::list<boost::any> many; //definiere Typ Standardliste mit Datentyp <boost::any>

#include "modul.hpp"
#include "boostfunc.h"

using namespace std;


class ModulA : public Modul
{
public:
ModulA() {
std::cout << "new" << std::endl;
}

virtual ~ModulA() {
std::cout << "delete" << std::endl;
}

virtual many inputer(TModulK & LoadModul, many & values)
{
cout << "Vor Einfügen der 800 Werte" << endl;

for (int a = 1; a<=100; a++)
{
append_any(values,12345);
append_any(values,67890);
append_any(values,"wird gelöscht");
append_int(values,5);
append_any(values,"als Char_ptr");
append_nothing(values); // nichts anfügen...
append_string(values,"ich bin String-Wert");
append_int(values,999);
}

cout << "Nach Einfügen der 800 Werte" << endl;

count_all(values);
print_all(values);

return values;

}
};
extern "C" {boost::shared_ptr<Modul> modul( new ModulA() ); }


die modul.hpp hab ich auch abgeändert...



#ifndef PANZI_MODUL_HPP__
#define PANZI_MODUL_HPP__

#include <list>
#include <string>

using boost::any_cast;
typedef std::list<boost::any> many;

class Modul {
public:
virtual ~Modul() {}
virtual many inputer(TModulK & LoadModul, many & values) =0;
};

#endif /* PANZI_MODUL_HPP__ */



Nach dem ich dann alles kompilier... keine Fehler kommen
kommt beim ausführen des Programms als Fehlermeldung
dann immer:

projektxml/projektxml> ./projektxml test2.xml
File: test2.xml successfully loaded.

SETTINGS
name der Datei:input.so
new
name der Datei:input.so
Name der Funktion: inputer
error dlsym(): ./projektxml: undefined symbol: inputer
delete
Speicherschutzverletzung

erstens... warum findet der das inputer nicht.. obwohl es im Modul existiert?
wo kommt die Speicherschutzverletzung her??

ich muss das ding unbedingt zum laufen bekommen das die software daten einliest und von modul zu modul schaufelt und dann am ende wieder rauswirft...

panzi
04-07-2007, 17:28
Ja das ist mein Code. In der Tat ist das mein Code aus DIESEM THREAD hier! scroll ein wenig weiter rauf, dort siehst du ihn!

Das Symbol "inputer" existiert tatsächlich nicht. Das einzige (C) Symbol das existiert ist "modul".
Siehe:
...
extern "C" { boost::shared_ptr<Modul> modul( new ModulA() ); }

Der Segfault kommt wohl weil du das return im Fehlerfall auskommenteirt hast.
Wenn das Symbol nicht ladbar ist, dann musst du natürlich irgendwie abbrechen. Am besten mit einen Fehlerstatus/einer Exception. Also wenn es den C sein muss, würde ich der Funktion einen int Returnwert verpassen, der 0 in OK-Fall zurückgibt und -1 oder irgendeinen Error-Code in Fehlerfall. Wenn das nicht geht, dann bleibt dir wohl nicht viel anderes über als an der stelle des auskommentierten returns ein exit(1); zu machen, sprich Programmabsturz. Aber ich würde das laden der .so und des Symbols nicht immer in der Funktion machen. Ich würde das an einer globaleren Stelle machen um mir das Symbol merken zu können. So brauchst es nicht immer wieder laden.

Was du auch noch machen solltes ist rund um deinen ganzen C++ Code herum ein:

try {
/* code */
}
catch(std::exception & e) {
/* try to handle known exception */
}
catch(...) {
/* try to handle unknown exception */
}
(Der Code braucht wohl noch ein #include <exception> denk ich.)

Denn ein throw durch einen C Code durch führt relativ sicher zu einen Absturz.


lg,
panzi

ufosworld
10-07-2007, 12:26
@panzi... ja klar... bin irgendwie zur Zeit planlos... :confused:

ok hab den Symbolnamen geändert...

anbei mal der Code der Libcall Funktion im Hauptprogramm

oben im Hauptprogramm folgender Code...



using boost::any_cast;
typedef std::list<boost::any> many; //definiere Typ Standardliste mit Datentyp <boost::any>
many values;
many values_from_input;
many values_from_work;




void LoadLibs(int queue_id)
{
const char *filename;
const char *funcname;
//const char *dlsym_error;

TModulK *LoadModul = NULL;
TQueueK *LoadQueue = NULL;

LoadQueue = SearchQueue(queue_id); holt aus dem Ding die Modulnamen


// Input

LoadModul = SearchModul(LoadQueue->queue_input);
filename = LoadModul->mod_name.c_str();

void* inputHand = dlopen(filename, RTLD_LAZY);


if (!inputHand)
{
cerr << "Cannot load library: " << dlerror() << endl;
return 1;
}
{

funcname = LoadModul->func_name.c_str();

cout <<"name der Datei:"<< filename <<endl;
cout << "Name der Funktion: "<< funcname<< endl;

void * input = dlsym(inputHand,funcname);

if(!input) {
std::cerr << "error dlsym(): " << dlerror() << std::endl;
dlclose(input);
return 1; //wenn dieses Return 1 fehlt dann Speicherschutzverletzung
}


boost::shared_ptr<ModulInput> modul( *((boost::shared_ptr<ModulInput>*)input) );
values_from_input = modul->inputer(*LoadModul, values);


// return 1; //sobald hier return 0 oder 1 geht er nicht mehr weiter
}

// Hier dlclose(inputHand); beendet funktion und er gibt das Hier1 gar nicht mehr aus...
// wenn ich dlclose(inputHand); weglasse dann geht er weiter



cout << "Hier1"<<endl;

// WORK

LoadModul = SearchModul(LoadQueue->queue_work);
cout << "Hier1a"<<endl;
filename = LoadModul->mod_name.c_str();

cout << "Hier2"<<endl;

void* workHand = dlopen(filename, RTLD_LAZY);


if (!workHand)
{
cerr << "Cannot load library: " << dlerror() << endl;
return 1;
}
{

cout << "Hier3"<<endl;
funcname = LoadModul->func_name.c_str();

cout <<"name der Datei:"<< filename <<endl;
cout << "Name der Funktion: "<< funcname<< endl;

void * work = dlsym(workHand,funcname);

if(!work) {
std::cerr << "error dlsym(): " << dlerror() << std::endl;
dlclose(workHand);
return 1; //wenn dieses Return 1 fehlt dann Speicherschutzverletzung
}


boost::shared_ptr<ModulWork> wmodul( *((boost::shared_ptr<ModulWork>*)work) );
values_from_work = wmodul->worker(*LoadModul, values_from_input);

// return 0;
}

if (!workHand)
{ // Do nothing
}
else
{
dlclose(workHand);
cout << "Work-Handle closed"<< endl;
}

if (!inputHand)
{ // Do nothing
}
else
{
dlclose(inputHand);
cout << "Input-Handle closed"<< endl;
}

return EXIT_SUCCESS;
}


sooo nachdem die Funktion so umgeschrieben wurde lädt er jetzt das Input modul... Schreibt daten in values rein gibt dieses values an die obige Funktion zurück ... lädt dann das work modul und übergibt values_from_input
an die Funktion

bei ausführen der des gesammten Progs kommt dann folgendes...
auf dem Bildschirm



projektxml/projektxml> ./projektxml test2.xml
File: test2.xml successfully loaded.

new
name der Datei:input.so
Name der Funktion: inputer

Hier steht der in TModulK* LoadModul übermittelte Modulname und der erste Parameter
Mod_Name: input.so
Parameter 1: test3_0

1ter Parameter
string
test3_0
2ter Parameter
string
test3_1
3ter Parameter
string
test3_2

IN INPUT MODUL ANGEKOMMEN!!!
#int == 41
#empty == 10
#string == 10 // 10 String Werte ist korrekt und werden falls print_all(values) im Code steht ausgegeben
#const char * == 20

new
name der Datei:work.so
Name der Funktion: worker

In WORK MODUL ANGEKOMMEN!!!
#int == 41
#empty == 10
#string == 0 // Wieso sind hier keine String Werte mehr
#const char * == 20

Int: 12345
Int: 11111
Char_Ptr: löschen
Int: 22222
Char_Ptr: als Char_ptr
Empty:
Int: 54321
....
.usw (insgesamt 10 mal)
.Stringwerte werden nicht mit ausgegeben
....
....
Int: 12345
Int: 11111
Char_Ptr: löschen
Int: 22222
Char_Ptr: als Char_ptr
Empty:
Int: 54321
Int: 12345
Int: 11111
Char_Ptr: löschen
Int: 22222
Char_Ptr: als Char_ptr
Empty:
Int: 54321
Int: 9999999 // Dieser Wert wurde händisch noch hinten angefügt ... is ok

delete
Work-Handle closed
delete
Input-Handle closed
Speicherschutzverletzung
projektxml/projektxml>




1. was auffällt... er kackt wieder am Ende ab... :mad: wieso das etz wieder...
2. die zehn String Werte in values verschwinden ??? :eek:
wo zum Teufel sind die hin...????????? :confused:
3. wenn ich in der LoadLibs Funktion die dlclose direkt nach der Rückgabe setzte dann führt er die FUnktion nicht weiter aus... (siehe KOmmentare) im ersten Code..

das zählen der Werte passiert mit
count_all(values);



/************************************************** *****
BOOST count_all FUNCTION
************************************************** *****/

void count_all(many & values)
{
std::cout << "#int == "
<< std::count_if(values.begin(), values.end(), is_int) << std::endl;
std::cout << "#empty == "
<< std::count_if(values.begin(), values.end(), is_empty) << std::endl;
std::cout << "#string == "
<< std::count_if(values.begin(), values.end(), is_string) << std::endl;

std::cout << "#const char * == "
<< std::count_if(values.begin(), values.end(), is_char_ptr) << std::endl;

std::cout<<std::endl;
}

ufosworld
11-07-2007, 13:44
Vermutung:

Können die Speicherschutzverletzungen daher kommen, da ich wie es aussieht nie ein
new oder ein
delete mache?

z.b. hier mal ein Modul.... (Input-Modul)



#include <string>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <list>
#include <boost/any.hpp> // include muss vor "boostfunc.h" kommen
#include <boost/smart_ptr.hpp>
#include "standardstructs.h" // in "standardstructs.h" stehen die StandardStructs
// für die Listen drin und der typedef für
// std::list<boost::any> many;
#include "outputfunc.h"

using boost::any_cast;
typedef std::list<boost::any> many; //definiere Typ Standardliste mit Datentyp <boost::any>

#include "modul.hpp"
#include "boostfunc.h"

using namespace std;

class ModulI : public ModulInput
{
public:
ModulI() {
std::cout << "new" << std::endl;
}

virtual ~ModulI() {
std::cout << "delete" << std::endl;
}

virtual many inputer(TModulK & LoadModul, many & values)
{


std::string Filename;
std::string Parameter;

cout<< endl<<"Hier steht der in TModulK* LoadModul übermittelte Modulname und der erste Parameter"<<endl;

Filename = LoadModul.mod_name;
cout<< "Mod_Name: " << Filename<<endl;
// Zugriff auf die Parameter ist etwas komisch, aber geht
// erst Punkt dann Pfeil
Parameter = LoadModul.ParaHook->par_value;
cout << "Parameter 1: "<< Parameter<<endl<<endl;

// für diese Funktion muss die Header Datein outputfunc.h eingebunden werden
// und beim compilieren die outputfunc.cpp angegeben werden

OutputParameter(LoadModul.ParaHook);


cout <<endl<< "IN INPUT MODUL ANGEKOMMEN!!!" << endl;

for (int a = 1; a<=10; a++)
{
append_any(values,12345);
append_any(values,11111);
append_any(values,"löschen");
append_int(values,22222);
append_any(values,"als Char_ptr");
append_nothing(values); // nichts anfügen...
append_string(values,"ich bin String-Wert");
append_int(values,54321);
}


// Werte via Variable hinzufügen
int wert;
wert = 9999999;
append_any(values,wert);

count_all(values);
// print_all(values);

return values;

}
};
extern "C" {boost::shared_ptr<ModulInput> inputer( new ModulI() ); }






desweiteren vermute ich wegen dem nichübernehmen der String Werte:
kann es sein, das durch die einfach Rückgabe aus dem Modul

return values;

der Zuweisung in der LoadLib-Function

values_from_input = modul->inputer(*LoadModul, values);

und der Übergabe der Variable values_from_input
an das Work Modul


boost::shared_ptr<ModulWork> wmodul( *((boost::shared_ptr<ModulWork>*)work) );
values_from_work = wmodul->worker(*LoadModul, values_from_input);

das alte Problem hat... String-Werte werden bei Zuweisung nicht kopiert...

Beispiel...


string a;
string b;
a="test";
a=b;
cout << b ;


wie kann ich die Problemchen lösen???

merci UFO