Sign in Join

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

Mailing lists / fpc-pascal / 2009-07

Stack problem in externally called callback function

8 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

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

Wimpie Nortje

Hi everybody,

I am trying to use a shared lib written in C in my FPC program. The lib creates a number of threads and requires callbacks into the main app. It can call the callback from any of the threads.

When I compile without stack checking everything (seems) to work fine but when stack checking is on I get stack error (error 202) on entry to the callback function. I can break on the callback's 'begin' and see valid values for all the function parameters but when I step into the function body it crashes.

I say 'seems' when not using stack checking because when the app becomes large I get a lot of strange problems which would probably be explained by stack problems.

The .h file:
typedef int (*VortexOnAcceptedConnection) (VortexConnection * connection, axlPointer data);

The pascal file:
type
      PVortexConnection = Pointer;
      TaxlPointer = Pointer;
      TVortexOnAcceptedConnection = function
(connection:PVortexConnection;          data:TaxlPointer):longint;cdecl;
{This is the callback function called by the C library. It never gets
called from the pascal code.}
function on_accepted(connection: PVortexConnection; data: TaxlPointer):
longint;cdecl;
begin
  Result := 1;
end;

I have tried all the function modifiers, they all give the same problem. I run fpc 2.2.4 on Kubuntu 9.04.

I ran the C version of this test application using valgrind and it doesn't give a single problem.

Any ideas or opinions will be appreciated.

Wimpie

Reply by email

Jonas Maebe
to Wimpie Nortje
Wimpie Nortje wrote
I am trying to use a shared lib written in C in my FPC program. The lib creates a number of threads and requires callbacks into the main app. It can call the callback from any of the threads.

Calling FPC code from threads not created by FPC does not work at this time on any unix-like platform.

Show quoted text 5 lines
When I compile without stack checking everything (seems) to work fine but when stack checking is on I get stack error (error 202) on entry to the callback function. I can break on the callback's 'begin' and see valid values for all the function parameters but when I step into the function body it crashes.

That's because the stack checking has to be initialised per thread and this is normally done when you create a thread via tthread.create() or beginthread(). Disable stack checking.

I say 'seems' when not using stack checking because when the app becomes large I get a lot of strange problems which would probably be explained by stack problems.

No, the problems are probably due to the FPC rtl not being initialised for multi-threading. You will probably get slightly less problems if you include the "cthreads" unit in your uses-clause and create a dummy thread as soon as your program starts (after which you can destroy it again), but even then you will get memory leaks and sporadic random errors due to threadvars containing wrong values. As said above: it does not work at this time (under unix-like platforms; in 2.3.1, it should work on Windows).

The reason that it does not work on Unix-like platforms, is that there is no way to make libthread inform FPC whenever a thread is created (while this is possible on Windows), so the FPC rtl cannot initialise the per-thread information properly. There is no known way to fix this problem (although some people have guesses, no one really knows for sure).

Jonas

Reply by email

Wimpie Nortje
to Jonas Maebe

Thanks for the response.

The library uses a centralised function to start all its threads using pthread_create. If I can make this central function inform FPC about all the threads created, would this work?

Assuming it would work: what information would FPC require? When would this info be required, before or after thread creation? What needs to be done on the FPC side with this info?

Wimpie

Jonas Maebe wrote 48 lines
On 31 Jul 2009, at 19:05, Wimpie Nortje wrote: > I am trying to use a shared lib written in C in my FPC program. The > lib creates a number of threads and requires callbacks into the main > app. It can call the callback from any of the threads. Calling FPC code from threads not created by FPC does not work at this time on any unix-like platform. > When I compile without stack checking everything (seems) to work fine > but when stack checking is on I get stack error (error 202) on entry > to the callback function. I can break on the callback's 'begin' and > see valid values for all the function parameters but when I step into > the function body it crashes. That's because the stack checking has to be initialised per thread and this is normally done when you create a thread via tthread.create() or beginthread(). Disable stack checking. > I say 'seems' when not using stack checking because when the app > becomes large I get a lot of strange problems which would probably be > explained by stack problems. No, the problems are probably due to the FPC rtl not being initialised for multi-threading. You will probably get slightly less problems if you include the "cthreads" unit in your uses-clause and create a dummy thread as soon as your program starts (after which you can destroy it again), but even then you will get memory leaks and sporadic random errors due to threadvars containing wrong values. As said above: it does not work at this time (under unix-like platforms; in 2.3.1, it should work on Windows). The reason that it does not work on Unix-like platforms, is that there is no way to make libthread inform FPC whenever a thread is created (while this is possible on Windows), so the FPC rtl cannot initialise the per-thread information properly. There is no known way to fix this problem (although some people have guesses, no one really knows for sure). Jonas _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply by email

Jonas Maebe
to Wimpie Nortje
Wimpie Nortje wrote 5 lines
Thanks for the response. The library uses a centralised function to start all its threads using pthread_create. If I can make this central function inform FPC about all the threads created, would this work?

There is no interface in the RTL to inform it about newly created external threads, so it would be quite hard.

Assuming it would work: what information would FPC require? When would this info be required, before or after thread creation? What needs to be done on the FPC side with this info?

Look at rtl/unix/cthreads.pp, in the functions CBeginThread/ThreadMain and CEndThread (they also call generic code from rtl/inc/thread.inc, such as InitThread and DoneThread).

Jonas

Reply by email

Wimpie Nortje
to Jonas Maebe

Thanks, I'll have a look

Jonas Maebe wrote 27 lines
On 02 Aug 2009, at 20:02, Wimpie Nortje wrote: > Thanks for the response. > > The library uses a centralised function to start all its threads > using pthread_create. If I can make this central function inform FPC > about all the threads created, would this work? There is no interface in the RTL to inform it about newly created external threads, so it would be quite hard. > Assuming it would work: what information would FPC require? When > would this info be required, before or after thread creation? What > needs to be done on the FPC side with this info? Look at rtl/unix/cthreads.pp, in the functions CBeginThread/ThreadMain and CEndThread (they also call generic code from rtl/inc/thread.inc, such as InitThread and DoneThread). Jonas _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply by email

Wimpie Nortje
to Jonas Maebe: There is no interface in the RTL to inform it about newly created external threads, so it…

The FPC thread setup code (CAllocateThreadVars, InitThread) happens inside the newly created thread before the user's thread function starts.

The only viable way I see to get support from the C library is for it to inform FPC about a new thread after creation, but this means that the C user's thread function has already started executing when FPC gets the new ID. Is it possible to do the FPC thread setup from outside the new thread? Suppose this setup can be completed before the library starts calling FPC callbacks, would all the current memory problems then be solved?

Jonas Maebe wrote 27 lines
On 02 Aug 2009, at 20:02, Wimpie Nortje wrote: > Thanks for the response. > > The library uses a centralised function to start all its threads > using pthread_create. If I can make this central function inform FPC > about all the threads created, would this work? There is no interface in the RTL to inform it about newly created external threads, so it would be quite hard. > Assuming it would work: what information would FPC require? When > would this info be required, before or after thread creation? What > needs to be done on the FPC side with this info? Look at rtl/unix/cthreads.pp, in the functions CBeginThread/ThreadMain and CEndThread (they also call generic code from rtl/inc/thread.inc, such as InitThread and DoneThread). Jonas _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply by email

Jonas Maebe
to Wimpie Nortje
Wimpie Nortje wrote 9 lines
The FPC thread setup code (CAllocateThreadVars, InitThread) happens inside the newly created thread before the user's thread function starts. The only viable way I see to get support from the C library is for it to inform FPC about a new thread after creation, but this means that the C user's thread function has already started executing when FPC gets the new ID. Is it possible to do the FPC thread setup from outside the new thread?

No, because those functions need the thread ID. And e.g. CAllocateThreadVars calls pthread_setspecific(), which is defined as associating a value with the current thread.

I think the "easiest" way for you to do this would be to do something similar to what the FPC rtl does: write your own function that does all of this initialisation, and pass that one to pthread_create as the function to run in the new thread. Then from this function perform all initialisation, and finally call the original function.

Suppose this setup can be completed before the library starts calling FPC callbacks, would all the current memory problems then be solved?

Only if you can also guarantee that all thread exits can be hooked by your library (so no direct pthread_exit() calls from the user function) and that you then call FPC's DoneThread.

Jonas

Reply by email

Wimpie Nortje
to Jonas Maebe
Jonas Maebe wrote 5 lines
I think the "easiest" way for you to do this would be to do something similar to what the FPC rtl does: write your own function that does all of this initialisation, and pass that one to pthread_create as the function to run in the new thread. Then from this function perform all initialisation, and finally call the original function.

Thanks. I have done this and it is working. It is not the ideal solution though....BeginThread expects a 'register' function as the thread function, while the library provides a 'cdecl' function. This means I had to wrap the C thread function into another function call. So there are now quite a bit of layering happening on top of the original thread function. I think it would be good if BeginThread can accept both register functions and cdecl functions.

And then I hope the library author accept my changes.

Reply by email