Sign in Join

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

Mailing lists / fpc-devel / 2006-11

calls to Fpc-made library from C not thread-safe

7 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

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

Dominique Leducq

Hi,

I have a library compiled with Fpc, used from C/C++ programs. When these C programs call functions of the library from different threads, things break.

As I understand it, the exception stack(s), the standard input/output streams, the threadID and stack checking variables use thread variables, and when the thread is created from C, this variables are not allocated nor initialized.

As a workaround, I thought I could export a function from the library, to be called in each thread before any other library call, which would call CurrentTM.AllocateThreadVars and System.InitThread. And symetrically, a function to be called after any other library call in the thread, which flushes the input/output streams and calls CurrentTM.ReleaseThreadVars.

Does that sound correct?

Dominique

Reply by email

Michael Van Canneyt
to Dominique Leducq
Dominique Leducq wrote
Hi, I have a library compiled with Fpc, used from C/C++ programs. When these C programs call functions of the library from different threads, things break.

This is unfortunately true :-)

As I understand it, the exception stack(s), the standard input/output streams, the threadID and stack checking variables use thread variables, and when the thread is created from C, this variables are not allocated nor initialized.

This is correct.

As a workaround, I thought I could export a function from the library, to be called in each thread before any other library call, which would call CurrentTM.AllocateThreadVars and System.InitThread.

This should no longer be needed. I implemented some fixes recently which fixes this. If you're working with an officially released version, then you have the right solution. Calling CurrentTM.AllocateThreadVars should be enough.

And symetrically, a function to be called after any other library call in the thread, which flushes the input/output streams and calls CurrentTM.ReleaseThreadVars.

Correct. The CurrentTM.Releasevars and flushing should be done just before your thread ends. This should be done always, with any version of FPC.

Michael.

Reply by email

Dominique Leducq
Show quoted text 26 lines
On Thu, 30 Nov 2006, Dominique Leducq wrote: > Hi, > > I have a library compiled with Fpc, used from C/C++ programs. > When these C programs call functions of the library from different threads, things break. This is unfortunately true :-) > > As I understand it, the exception stack(s), the standard input/output streams, the threadID > and stack checking variables use thread variables, and when the thread is created from C, > this variables are not allocated nor initialized. This is correct. > As a workaround, I thought I could export a function from the library, to be called in each > thread before any other library call, which would call CurrentTM.AllocateThreadVars and > System.InitThread. This should no longer be needed. I implemented some fixes recently which fixes this. If you're working with an officially released version, then you have the right solution. Calling CurrentTM.AllocateThreadVars should be enough.

I use Fpc 2.1.1 (currently rev 5448), and something still seems to be needed. In which revision have your fixes been applied ?

Show quoted text 10 lines
> And symetrically, a function to be called after any other library call in the thread, > which flushes the input/output streams and calls CurrentTM.ReleaseThreadVars. Correct. The CurrentTM.Releasevars and flushing should be done just before your thread ends. This should be done always, with any version of FPC. Michael.

Thanks Michael for your (very) fast answer !

Dominique

Reply by email

Dominique Leducq

Ooops. Did a 'reply to list', but that didn't work. Try again...

Show quoted text 37 lines
On Thu, 30 Nov 2006, Dominique Leducq wrote: > On Thu, 30 Nov 2006 10:11:17 +0100 (CET) > Michael Van Canneyt wrote: > > > > > > > On Thu, 30 Nov 2006, Dominique Leducq wrote: > > > > > Hi, > > > > > > I have a library compiled with Fpc, used from C/C++ programs. > > > When these C programs call functions of the library from different threads, things break. > > > > This is unfortunately true :-) > > > > > > > > As I understand it, the exception stack(s), the standard input/output streams, the threadID > > > and stack checking variables use thread variables, and when the thread is created from C, > > > this variables are not allocated nor initialized. > > > > This is correct. > > > > > As a workaround, I thought I could export a function from the library, to be called in each > > > thread before any other library call, which would call CurrentTM.AllocateThreadVars and > > > System.InitThread. > > > > This should no longer be needed. I implemented some fixes recently which > > fixes this. If you're working with an officially released version, then you > > have the right solution. Calling CurrentTM.AllocateThreadVars should be > > enough. > > I use Fpc 2.1.1 (currently rev 5448), and something still seems to be needed. In which revision have your fixes been applied ? Revision 5474 for linux, 5475 for Windows.

OK.

But: System.IniThread performs some initialization on system thread variables. Isn't this still needed ? OK, SysInitExceptions for now only sets two stack pointers to nil, and AllocateThreadVars already set the variables to zero (at least for Unices). But what about the standard IO streams (SysInitStdIO)? Does a WriteLn('string'), for example, work without that ? What about ThreadID ? Besides, what about this code from rtl/unix/cthreads.pp (CBeginThread):

      { Initialize multithreading if not done }
      if not IsMultiThread then
        begin
          if (InterLockedExchange(longint(IsMultiThread),1) = 0) then
            begin
              { We're still running in single thread mode, setup the TLS }
               pthread_key_create(@TLSKey,nil);
              InitThreadVars(@CRelocateThreadvar);
            end
        end;
?

If I haven't created a thread from within my FPC library before, this code has never been run, and thus IsMultiThread is still 0, TLSKey is not created, and thread variables not initialized. Right ?

Show quoted text 15 lines
> > > And symetrically, a function to be called after any other library call in the thread, > > > which flushes the input/output streams and calls CurrentTM.ReleaseThreadVars. > > > > > > Correct. The CurrentTM.Releasevars and flushing should be done just before your > > thread ends. This should be done always, with any version of FPC. > > > > Michael. > > Thanks Michael for your (very) fast answer ! De rien.. Michael.

Reply by email

Michael Van Canneyt
to Dominique Leducq
Dominique Leducq wrote 46 lines
Ooops. Did a 'reply to list', but that didn't work. Try again... On Thu, 30 Nov 2006 10:48:58 +0100 (CET) Michael Van Canneyt wrote: > > > On Thu, 30 Nov 2006, Dominique Leducq wrote: > > > On Thu, 30 Nov 2006 10:11:17 +0100 (CET) > > Michael Van Canneyt wrote: > > > > > > > > > > > On Thu, 30 Nov 2006, Dominique Leducq wrote: > > > > > > > Hi, > > > > > > > > I have a library compiled with Fpc, used from C/C++ programs. > > > > When these C programs call functions of the library from different threads, things break. > > > > > > This is unfortunately true :-) > > > > > > > > > > > As I understand it, the exception stack(s), the standard input/output streams, the threadID > > > > and stack checking variables use thread variables, and when the thread is created from C, > > > > this variables are not allocated nor initialized. > > > > > > This is correct. > > > > > > > As a workaround, I thought I could export a function from the library, to be called in each > > > > thread before any other library call, which would call CurrentTM.AllocateThreadVars and > > > > System.InitThread. > > > > > > This should no longer be needed. I implemented some fixes recently which > > > fixes this. If you're working with an officially released version, then you > > > have the right solution. Calling CurrentTM.AllocateThreadVars should be > > > enough. > > > > I use Fpc 2.1.1 (currently rev 5448), and something still seems to be needed. In which revision have your fixes been applied ? > > Revision 5474 for linux, 5475 for Windows. OK. But: System.IniThread performs some initialization on system thread variables. Isn't this still needed ?

Yes it is still needed.
The code I tested always created 1 thread in pascal, so that wasn't an issue.

So you should call this too.

Show quoted text 19 lines
OK, SysInitExceptions for now only sets two stack pointers to nil, and AllocateThreadVars already set the variables to zero (at least for Unices). But what about the standard IO streams (SysInitStdIO)? Does a WriteLn('string'), for example, work without that ? What about ThreadID ? Besides, what about this code from rtl/unix/cthreads.pp (CBeginThread): { Initialize multithreading if not done } if not IsMultiThread then begin if (InterLockedExchange(longint(IsMultiThread),1) = 0) then begin { We're still running in single thread mode, setup the TLS } pthread_key_create(@TLSKey,nil); InitThreadVars(@CRelocateThreadvar); end end; ? If I haven't created a thread from within my FPC library before, this code has never been run, and thus IsMultiThread is still 0, TLSKey is not created, and thread variables not initialized. Right ?

You are right.

Michael.

Reply by email

Vlad
to Dominique Leducq: I have a library compiled with Fpc, used from C/C++ programs. When these C programs call…
Show quoted text 14 lines
Hi, I have a library compiled with Fpc, used from C/C++ programs. When these C programs call functions of the library from different threads, things break. As I understand it, the exception stack(s), the standard input/output streams, the threadID and stack checking variables use thread variables, and when the thread is created from C, this variables are not allocated nor initialized. As a workaround, I thought I could export a function from the library, to be called in each thread before any other library call, which would call CurrentTM.AllocateThreadVars and System.InitThread. And symetrically, a function to be called after any other library call in the thread, which flushes the input/output streams and calls CurrentTM.ReleaseThreadVars. Does that sound correct? Dominique

Hi

I'm in similar situation under Mac OS X.
I have to create dummy thread when library loaded and then to use such functions in additional threads:

procedure thread_init;
var
  TM: TThreadManager;
begin
  GetThreadManager(TM);
  TM.AllocateThreadVars;
  InitThread(500000); // 500000 is the stack size, all threads have 512Kb stack, not sure must here be exact stack size or not.
end;
procedure thread_done;
var
  TM: TThreadManager;
begin
  GetThreadManager(TM);
  TM.ReleaseThreadVars;
end;

Reply by email

Dominique Leducq
to Vlad
Show quoted text 38 lines
> Hi, > > I have a library compiled with Fpc, used from C/C++ programs. > When these C programs call functions of the library from different threads, things break. > > As I understand it, the exception stack(s), the standard input/output streams, the threadID and stack checking variables use thread variables, and when the thread is created from C, this variables are not allocated nor initialized. > > As a workaround, I thought I could export a function from the library, to be called in each thread before any other library call, which would call CurrentTM.AllocateThreadVars and System.InitThread. > And symetrically, a function to be called after any other library call in the thread, which flushes the input/output streams and calls CurrentTM.ReleaseThreadVars. > > Does that sound correct? > > Dominique > Hi I'm in similar situation under Mac OS X. I have to create dummy thread when library loaded and then to use such functions in additional threads: procedure thread_init; var TM: TThreadManager; begin GetThreadManager(TM); TM.AllocateThreadVars; InitThread(500000); // 500000 is the stack size, all threads have 512Kb stack, not sure must here be exact stack size or not. end; procedure thread_done; var TM: TThreadManager; begin GetThreadManager(TM); TM.ReleaseThreadVars; end;

Thanks Vlad, that's precisely what I was going to try out (whithout AllocateThreadVars, not needed any more after the fix of Michael). In thread_done, I'll add

  Flush(Output);
  Flush(ErrOutput);
  Flush(StdOut);
  Flush(StdErr);

too (before releasing the thread variables, of course).

Dominique.

Reply by email