Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2012-04

Callback and Threads problem

11 messages · 5 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Leonardo M. Ramé

I have a similar problem to this:

http://www.lazarus.freepascal.org/index.php?topic=10571.0

My main program launches a thread, that loads a shared library, then execute a function who receives as a parameter a pointer to a callback function and an instance of the caller, as this:

procedure TMythread.execute;
begin
  ...
  // external function
  runcode(@MyCallBack, @Self);
  ...
end;
procedure MyCallback(const Result: PAnsiChar; const ACaller: pointer);
cdecl;
var
  lCaller: TMythread;
begin
  // the parameter ACaller is used because callbacks can't be of type
  // procedure of object.
  lCaller := TMyThread(ACaller);
  lCaller.TestVar := Result; // <--- Ok.
  lCaller.ListOfThings.Add;  // <--- SIGSEGV
  ...
end;

The problem is that every time I try to execute the method Add of a TCollection or TObjectList I get a SIGSEGV.

I must point out that the method "runcode" in the shared library is not multithreaded. Also the shared library was linked against pthreads library, and the main program uses cthreads. I also tried to enclose the Callback inside a CriticalSection but the problem persists.

Thanks in advance,

Leonardo M. Ram? Medical IT - Griensu S.A. Av. Col?n 636 - Piso 8 Of. A X5000EPT -- C?rdoba Tel.: +54(351)4246924 +54(351)4247788 +54(351)4247979 int. 19 Cel.: +54(351)156629292

Reply by email

Unknown author
to Leonardo M. Ramé
Leonardo M. Ram? wrote 26 lines
I have a similar problem to this: http://www.lazarus.freepascal.org/index.php?topic=10571.0 My main program launches a thread, that loads a shared library, then execute a function who receives as a parameter a pointer to a callback function and an instance of the caller, as this: procedure TMythread.execute; begin ... // external function runcode(@MyCallBack, @Self); ... end; procedure MyCallback(const Result: PAnsiChar; const ACaller: pointer); cdecl; var lCaller: TMythread; begin // the parameter ACaller is used because callbacks can't be of type // procedure of object. lCaller := TMyThread(ACaller); lCaller.TestVar := Result; // <--- Ok. lCaller.ListOfThings.Add; // <--- SIGSEGV

IMHO the problem is not in threads.

You cannot pass objects to libraries or vice versa. The VMTs will differ.

Michael.

Reply by email

Leonardo M. Ramé
to Unknown author
Show quoted text 37 lines
On Fri, 6 Apr 2012, Leonardo M. Ram? wrote: >I have a similar problem to this: > >http://www.lazarus.freepascal.org/index.php?topic=10571.0 > >My main program launches a thread, that loads a shared library, then >execute a function who receives as a parameter a pointer to a callback >function and an instance of the caller, as this: > >procedure TMythread.execute; >begin > ... > // external function > runcode(@MyCallBack, @Self); > ... >end; > >procedure MyCallback(const Result: PAnsiChar; const ACaller: pointer); >cdecl; >var > lCaller: TMythread; >begin > // the parameter ACaller is used because callbacks can't be of type > // procedure of object. > lCaller := TMyThread(ACaller); > lCaller.TestVar := Result; // <--- Ok. > lCaller.ListOfThings.Add; // <--- SIGSEGV IMHO the problem is not in threads. You cannot pass objects to libraries or vice versa. The VMTs will differ. Michael.

But, I'm passing the object as a pointer that is received as (void *) and returned back to the callback as a parameter, the library doesn't touch it. Even in this case I can't pass an object?.

Reply by email

Mattias Gaertner
to Leonardo M. Ramé
Show quoted text 42 lines
On 2012-04-06 14:39:10 +0200, wrote: > > > On Fri, 6 Apr 2012, Leonardo M. Ram? wrote: > > >I have a similar problem to this: > > > >http://www.lazarus.freepascal.org/index.php?topic=10571.0 > > > >My main program launches a thread, that loads a shared library, then > >execute a function who receives as a parameter a pointer to a callback > >function and an instance of the caller, as this: > > > >procedure TMythread.execute; > >begin > > ... > > // external function > > runcode(@MyCallBack, @Self); > > ... > >end; > > > >procedure MyCallback(const Result: PAnsiChar; const ACaller: pointer); > >cdecl; > >var > > lCaller: TMythread; > >begin > > // the parameter ACaller is used because callbacks can't be of type > > // procedure of object. > > lCaller := TMyThread(ACaller); > > lCaller.TestVar := Result; // <--- Ok. > > lCaller.ListOfThings.Add; // <--- SIGSEGV > > IMHO the problem is not in threads. > > You cannot pass objects to libraries or vice versa. > The VMTs will differ. > > Michael. But, I'm passing the object as a pointer that is received as (void *) and returned back to the callback as a parameter, the library doesn't touch it. Even in this case I can't pass an object?.

Have you checked the calling convention. E.g. 'cdecl;'?

Mattias

Reply by email

Unknown author
to Leonardo M. Ramé: But, I'm passing the object as a pointer that is received as (void *) and returned back…
Leonardo M. Ram? wrote 42 lines
On 2012-04-06 14:39:10 +0200, wrote: > > > On Fri, 6 Apr 2012, Leonardo M. Ram? wrote: > >> I have a similar problem to this: >> >> http://www.lazarus.freepascal.org/index.php?topic=10571.0 >> >> My main program launches a thread, that loads a shared library, then >> execute a function who receives as a parameter a pointer to a callback >> function and an instance of the caller, as this: >> >> procedure TMythread.execute; >> begin >> ... >> // external function >> runcode(@MyCallBack, @Self); >> ... >> end; >> >> procedure MyCallback(const Result: PAnsiChar; const ACaller: pointer); >> cdecl; >> var >> lCaller: TMythread; >> begin >> // the parameter ACaller is used because callbacks can't be of type >> // procedure of object. >> lCaller := TMyThread(ACaller); >> lCaller.TestVar := Result; // <--- Ok. >> lCaller.ListOfThings.Add; // <--- SIGSEGV > > IMHO the problem is not in threads. > > You cannot pass objects to libraries or vice versa. > The VMTs will differ. > > Michael. But, I'm passing the object as a pointer that is received as (void *) and returned back to the callback as a parameter, the library doesn't touch it. Even in this case I can't pass an object?.

Ah. In that case you can, yes.

Is the calling convention correct ?

Michael.

Reply by email

Leonardo M. Ramé
to Mattias Gaertner: On Fri, 6 Apr 2012 09:45:38 -0300 Have you checked the calling convention. E.g. 'cdecl;'?…
Mattias Gaertner wrote 50 lines
On Fri, 6 Apr 2012 09:45:38 -0300 Leonardo M. Ram? wrote: > On 2012-04-06 14:39:10 +0200, wrote: > > > > > > On Fri, 6 Apr 2012, Leonardo M. Ram? wrote: > > > > >I have a similar problem to this: > > > > > >http://www.lazarus.freepascal.org/index.php?topic=10571.0 > > > > > >My main program launches a thread, that loads a shared library, then > > >execute a function who receives as a parameter a pointer to a callback > > >function and an instance of the caller, as this: > > > > > >procedure TMythread.execute; > > >begin > > > ... > > > // external function > > > runcode(@MyCallBack, @Self); > > > ... > > >end; > > > > > >procedure MyCallback(const Result: PAnsiChar; const ACaller: pointer); > > >cdecl; > > >var > > > lCaller: TMythread; > > >begin > > > // the parameter ACaller is used because callbacks can't be of type > > > // procedure of object. > > > lCaller := TMyThread(ACaller); > > > lCaller.TestVar := Result; // <--- Ok. > > > lCaller.ListOfThings.Add; // <--- SIGSEGV > > > > IMHO the problem is not in threads. > > > > You cannot pass objects to libraries or vice versa. > > The VMTs will differ. > > > > Michael. > > But, I'm passing the object as a pointer that is received as (void *) and > returned back to the callback as a parameter, the library doesn't touch > it. Even in this case I can't pass an object?. Have you checked the calling convention. E.g. 'cdecl;'? Mattias

Yes, I'm using cdecl. The library is a C++ library running on Linux, defined as this:

typedef void (* CFindCallBack)(const char *, const void *);

So, correct me if I'm wrong, the calling convention should be cdecl.

Reply by email

Leonardo M. Ramé
to Unknown author: Ah. In that case you can, yes. Is the calling convention correct ? Michael.
Show quoted text 52 lines
On Fri, 6 Apr 2012, Leonardo M. Ram? wrote: >On 2012-04-06 14:39:10 +0200, wrote: >> >> >>On Fri, 6 Apr 2012, Leonardo M. Ram? wrote: >> >>>I have a similar problem to this: >>> >>>http://www.lazarus.freepascal.org/index.php?topic=10571.0 >>> >>>My main program launches a thread, that loads a shared library, then >>>execute a function who receives as a parameter a pointer to a callback >>>function and an instance of the caller, as this: >>> >>>procedure TMythread.execute; >>>begin >>>... >>>// external function >>>runcode(@MyCallBack, @Self); >>>... >>>end; >>> >>>procedure MyCallback(const Result: PAnsiChar; const ACaller: pointer); >>>cdecl; >>>var >>>lCaller: TMythread; >>>begin >>>// the parameter ACaller is used because callbacks can't be of type >>>// procedure of object. >>>lCaller := TMyThread(ACaller); >>>lCaller.TestVar := Result; // <--- Ok. >>>lCaller.ListOfThings.Add; // <--- SIGSEGV >> >>IMHO the problem is not in threads. >> >>You cannot pass objects to libraries or vice versa. >>The VMTs will differ. >> >>Michael. > >But, I'm passing the object as a pointer that is received as (void *) and >returned back to the callback as a parameter, the library doesn't touch >it. Even in this case I can't pass an object?. Ah. In that case you can, yes. Is the calling convention correct ? Michael.

Yes, I'm using cdecl.

BTW. I somewhat fixed the issue by defining a global variable of the same type of my thread, the var points to "Self" just before calling the external function and assigned to nil when the function ends.

This way, the callback can use the thread by pointing to the global var.

I hate to use global variables, but, as the function is called only once, I know it won't be overlapped by many callers.

Regards,

Reply by email

Sergei Gorelkin
to Leonardo M. Ramé: I have a similar problem to this: http://www.lazarus.freepascal.org/index.php?topic=10571.…

06.04.2012 16:31, Leonardo M. Ram? ?????:

Show quoted text 16 lines
I have a similar problem to this: http://www.lazarus.freepascal.org/index.php?topic=10571.0 My main program launches a thread, that loads a shared library, then execute a function who receives as a parameter a pointer to a callback function and an instance of the caller, as this: procedure TMythread.execute; begin ... // external function runcode(@MyCallBack, @Self); ... end;

You should pass 'Self' here, not '@Self'. The latter would be correct for TP-style objects, but TThread descendant is a class.

Regards,
Sergei

Reply by email

Antonio Fortuny
to Leonardo M. Ramé: Yes, I'm using cdecl. BTW. I somewhat fixed the issue by defining a global variable of the

Le 06/04/2012 15:04, Leonardo M. Ram? a ?crit :

Show quoted text 53 lines
On 2012-04-06 14:53:13 +0200, wrote: > > On Fri, 6 Apr 2012, Leonardo M. Ram? wrote: > >> On 2012-04-06 14:39:10 +0200, wrote: >>> >>> On Fri, 6 Apr 2012, Leonardo M. Ram? wrote: >>> >>>> I have a similar problem to this: >>>> >>>> http://www.lazarus.freepascal.org/index.php?topic=10571.0 >>>> >>>> My main program launches a thread, that loads a shared library, then >>>> execute a function who receives as a parameter a pointer to a callback >>>> function and an instance of the caller, as this: >>>> >>>> procedure TMythread.execute; >>>> begin >>>> ... >>>> // external function >>>> runcode(@MyCallBack, @Self); >>>> ... >>>> end; >>>> >>>> procedure MyCallback(const Result: PAnsiChar; const ACaller: pointer); >>>> cdecl; >>>> var >>>> lCaller: TMythread; >>>> begin >>>> // the parameter ACaller is used because callbacks can't be of type >>>> // procedure of object. >>>> lCaller := TMyThread(ACaller); >>>> lCaller.TestVar := Result; //<--- Ok. >>>> lCaller.ListOfThings.Add; //<--- SIGSEGV >>> IMHO the problem is not in threads. >>> >>> You cannot pass objects to libraries or vice versa. >>> The VMTs will differ. >>> >>> Michael. >> But, I'm passing the object as a pointer that is received as (void *) and >> returned back to the callback as a parameter, the library doesn't touch >> it. Even in this case I can't pass an object?. > Ah. In that case you can, yes. > > Is the calling convention correct ? > > Michael. Yes, I'm using cdecl. BTW. I somewhat fixed the issue by defining a global variable of the same type of my thread, the var points to "Self" just before calling the external function and assigned to nil when the function ends.

Not exactly a fix but the good way. If I undertsand well, with this form: runcode(@MyCallBack, @Self);
the second parameter is not a pointer pointing to some address but the address itself.

doing a previous
var

     PP: Pointer;

anf then
pp := @MyThread
runcode(@MyCallBack, pp);
passes a real pointer whose data effectively points to the desired object (the thread in the example).
I wonder if the same rule applies to the first paramaeter

This can explain why your second method works.

Antonio.

Show quoted text 7 lines
This way, the callback can use the thread by pointing to the global var. I hate to use global variables, but, as the function is called only once, I know it won't be overlapped by many callers. Regards,

Reply by email

Leonardo M. Ramé
to Sergei Gorelkin: 06.04.2012 16:31, Leonardo M. Ram? ?????: You should pass 'Self' here, not '@Self'. The…
Sergei Gorelkin wrote 23 lines
06.04.2012 16:31, Leonardo M. Ram? ?????: >I have a similar problem to this: > >http://www.lazarus.freepascal.org/index.php?topic=10571.0 > >My main program launches a thread, that loads a shared library, then >execute a function who receives as a parameter a pointer to a callback >function and an instance of the caller, as this: > >procedure TMythread.execute; >begin > ... > // external function > runcode(@MyCallBack, @Self); > ... >end; > You should pass 'Self' here, not '@Self'. The latter would be correct for TP-style objects, but TThread descendant is a class. Regards, Sergei

Yes!!!, you are right. That was the problem.

Regards,

Reply by email

Leonardo M. Ramé
to Antonio Fortuny: Le 06/04/2012 15:04, Leonardo M. Ram? a ?crit : Not exactly a fix but the good way. If I…
Antonio Fortuny wrote 85 lines
Le 06/04/2012 15:04, Leonardo M. Ram? a ?crit : >On 2012-04-06 14:53:13 +0200, wrote: >> >>On Fri, 6 Apr 2012, Leonardo M. Ram? wrote: >> >>>On 2012-04-06 14:39:10 +0200, wrote: >>>> >>>>On Fri, 6 Apr 2012, Leonardo M. Ram? wrote: >>>> >>>>>I have a similar problem to this: >>>>> >>>>>http://www.lazarus.freepascal.org/index.php?topic=10571.0 >>>>> >>>>>My main program launches a thread, that loads a shared library, then >>>>>execute a function who receives as a parameter a pointer to a callback >>>>>function and an instance of the caller, as this: >>>>> >>>>>procedure TMythread.execute; >>>>>begin >>>>>... >>>>>// external function >>>>>runcode(@MyCallBack, @Self); >>>>>... >>>>>end; >>>>> >>>>>procedure MyCallback(const Result: PAnsiChar; const ACaller: pointer); >>>>>cdecl; >>>>>var >>>>>lCaller: TMythread; >>>>>begin >>>>>// the parameter ACaller is used because callbacks can't be of type >>>>>// procedure of object. >>>>>lCaller := TMyThread(ACaller); >>>>>lCaller.TestVar := Result; //<--- Ok. >>>>>lCaller.ListOfThings.Add; //<--- SIGSEGV >>>>IMHO the problem is not in threads. >>>> >>>>You cannot pass objects to libraries or vice versa. >>>>The VMTs will differ. >>>> >>>>Michael. >>>But, I'm passing the object as a pointer that is received as (void *) and >>>returned back to the callback as a parameter, the library doesn't touch >>>it. Even in this case I can't pass an object?. >>Ah. In that case you can, yes. >> >>Is the calling convention correct ? >> >>Michael. >Yes, I'm using cdecl. > >BTW. I somewhat fixed the issue by defining a global variable of the >same type of my thread, the var points to "Self" just before calling the >external function and assigned to nil when the function ends. Not exactly a fix but the good way. If I undertsand well, with this form: runcode(@MyCallBack, @Self); the second parameter is not a pointer pointing to some address but the address itself. doing a previous var PP: Pointer; anf then pp := @MyThread runcode(@MyCallBack, pp); passes a real pointer whose data effectively points to the desired object (the thread in the example). I wonder if the same rule applies to the first paramaeter This can explain why your second method works. Antonio. > >This way, the callback can use the thread by pointing to the global var. > >I hate to use global variables, but, as the function is called only >once, I know it won't be overlapped by many callers. > >Regards,

Yes Antonio, Sergei noted the same error in my code, that fixed the issue.

Reply by email