Sign in Join

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

Mailing lists / fpc-devel / 2013-02

how to get same pthreads code to compile between Linux and FreeBSD

13 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

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

Graeme Geldenhuys

Hi,

I initially posted this in the fpc-pascal list, but I think fpc-devel is maybe more appropriate, because the pthreads include files might need amendment.

I'm trying to get tiOPF to compile under FreeBSD. It works under Linux and Windows without problems.

I got compiler errors using FPC 2.6.0 under FreeBSD, saying that the compiler couldn't decide which version of the sem_* methods to use.

I had code like this in tiOPF:

    {$IFDEF MSWINDOWS}
    FSemaphore: THandle;
    {$ENDIF MSWINDOWS}
    {$IFDEF UNIX}
    FSemaphore: TSemaphore;
    {$ENDIF UNIX}
...
procedure TtiPool.CreatePoolSemaphore;
begin
  {$IFDEF MSWINDOWS}
  if FSemaphore  0 then
    CloseHandle(FSemaphore);
  FSemaphore := CreateSemaphore(nil, FMaxPoolSize, FMaxPoolSize, nil);
  {$ENDIF MSWINDOWS}
  {$IFDEF UNIX}
  FillChar(FSemaphore, sizeof(FSemaphore), 0);
  // pShared = 0 means, shared between the threads of a process
  writeln('FMaxPoolSize = ', FMaxPoolSize);
  if sem_init(@FSemaphore, 0, FMaxPoolSize)  0 then
    raise EtiOPFInternalException.Create('Failed to initialize the
semaphore');
  {$ENDIF UNIX}
end;

Note the sem_init() call takes a pointer.

As you can see from the quoted code below, FreeBSD has two versions of the sem_* methods. The compiler couldn't decide which version to use:

Error: Can't determine which overloaded function to call

To get it to compiler under FreeBSD, I must change the sem_init() line too the following...

  if sem_init(FSemaphore, 0, FMaxPoolSize)  0 then

...but this breaks compiling under Linux again.

1) How do I get the tiOPF code to work under both Linux and FreeBSD using a single {$IFDEF UNIX}. I don't really want to introduce {$IFDEF LINUX} and {$IFDEF FREEBSD} in the code.

2) Why does FreeBSD have two versions of these methods and Linux only one? I had a look at the other pthr*.inc units. Linux and SunOS has a single version, BSD (which I believe is MacOSX too) and Haiku has two versions.

----------------[ pthrbsd.inc  freebsd ]-------------------
  function sem_init(__sem:Psem_t;
__pshared:cint;__value:dword):cint;cdecl; external;
  function sem_destroy(__sem:Psem_t):cint;cdecl;external ;
  function sem_close(__sem:Psem_t):cint;cdecl;external ;
  function sem_unlink(__name:Pchar):cint;cdecl;external ;
  function sem_wait(__sem:Psem_t):cint;cdecl;external ;
  function sem_trywait(__sem:Psem_t):cint;cdecl;external ;
  function sem_post(__sem:Psem_t):cint;cdecl;external ;
  function sem_getvalue(__sem:Psem_t; __sval:Pcint):cint;cdecl;external;
  function sem_init(var __sem: sem_t; __pshared:cint;
__value:dword):cint cdecl;external;
  function sem_destroy(var __sem: sem_t):cint;cdecl;external;
  function sem_close(var __sem: sem_t):cint;cdecl;external;
  function sem_wait(var __sem: sem_t):cint;cdecl;external;
  function sem_trywait(var __sem: sem_t):cint;cdecl;external;
  function sem_post(var __sem: sem_t):cint;cdecl;external;
  function sem_getvalue(var __sem: sem_t; var
__sval:cint):cint;cdecl;external;
--------------------[ end ]----------------------
-------------------[ pthrlinux.inc   linux ]---------------------
  function sem_init(__sem:Psem_t; __pshared:cint;
__value:dword):cint;cdecl;external libthreads;
  function sem_destroy(__sem:Psem_t):cint;cdecl;external libthreads;
  function sem_close(__sem:Psem_t):cint;cdecl;external libthreads;
  function sem_unlink(__name:Pchar):cint;cdecl;external libthreads;
  function sem_wait(__sem:Psem_t):cint;cdecl;external libthreads;
  function sem_trywait(__sem:Psem_t):cint;cdecl;external libthreads;
  function sem_post(__sem:Psem_t):cint;cdecl;external libthreads;
  function sem_getvalue(__sem:Psem_t; __sval:pcint):cint;cdecl;external
libthreads;
  function sem_timedwait(__sem: Psem_t; __abstime:
Ptimespec):cint;cdecl; external libthreads;
-------------------[ end ]-----------------------

Attached is a small test project using snippets of code that tiOPF uses. The current version of this test project will compiler under FreeBSD, but will not compiler under Linux.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/
Sven Barth
to Graeme Geldenhuys
Graeme Geldenhuys wrote 5 lines
Hi, I initially posted this in the fpc-pascal list, but I think fpc-devel is maybe more appropriate, because the pthreads include files might need amendment.

I personally think that the fpc-pascal list was the more approbiate, but nevertheless: your problem comes down to this code (in principal):

=== code begin ===

program semtest;
type
   sem_t_rec = record
   end; // from rtl/freebsd/ptypes.inc
   sem_t = ^sem_t_rec; // from rtl/freebsd/ptypes.inc
   psem_t = ^sem_t; // from packages/pthreads/src/pthrbsd.inc
procedure sem_init(sem: psem_t);
begin
end;
procedure sem_init(var sem: sem_t);
begin
end;
var
   s: sem_t;
begin
   sem_init(@s);
end.

=== code end ===

Now the problem is the "@s". This returns type "Pointer" and now you have two pointer types: sem_t and psem_t. Thus the compiler can not resolve this.

Solution: Typed addresses. Change your call the following way:

=== solution begin ===

begin
   {$push}
   {$typedaddress on}
   sem_init(@s);
   {$pop}
end.

=== solution end ===

In this case the return type of "@s" will be "^sem_t" instead of
"Pointer" and then the compiler will find the correct method.

Now one might nevertheless ask the question why the compiler considers the var variant with an "@s" valid at all? Maybe this is a bug indeed...

Regards,
Sven

Marco van de Voort
to Sven Barth

In our previous episode, Sven Barth said:

Show quoted text 5 lines
In this case the return type of "@s" will be "^sem_t" instead of "Pointer" and then the compiler will find the correct method. Now one might nevertheless ask the question why the compiler considers the var variant with an "@s" valid at all? Maybe this is a bug indeed...

Afaik Delphi allows that too since D4. It was one of the things 1.0.x couldn't do, but 1.9+ could.

Sven Barth
to Marco van de Voort
Marco van de Voort wrote 9 lines
In our previous episode, Sven Barth said: > In this case the return type of "@s" will be "^sem_t" instead of > "Pointer" and then the compiler will find the correct method. > > Now one might nevertheless ask the question why the compiler considers > the var variant with an "@s" valid at all? Maybe this is a bug indeed... Afaik Delphi allows that too since D4. It was one of the things 1.0.x couldn't do, but 1.9+ could.

But if the overload with the "psem_t" is removed the "var" variant doesn't compile either:

=== output begin ===

Free Pascal Compiler version 2.6.0 [2011/12/23] for i386 Copyright (c) 1993-2011 by Florian Klaempfl and others Target OS: Linux for i386
Compiling vartest.pas
vartest.pas(22,14) Error: Can't assign values to an address vartest.pas(24) Fatal: There were 1 errors compiling module, stopping Fatal: Compilation aborted
Error: /mnt/data/applications/fpc/2.6.0/bin/ppc386 returned an error exitcode (normal if you did not specify a source file to be compiled)

=== output end ===

So my personal opinion is still that this is a bug...

Regards,
Sven

Graeme Geldenhuys
to Sven Barth: I personally think that the fpc-pascal list was the more approbiate, but nevertheless:…
Sven Barth wrote
I personally think that the fpc-pascal list was the more approbiate, but nevertheless: your problem comes down to this code (in principal):

I thinking was that this problem seems to point towards a bug, or at least inconsistency between defined types and various platforms. But as you say, nevertheless. Thanks for replying.

Show quoted text 6 lines
type sem_t_rec = record end; // from rtl/freebsd/ptypes.inc sem_t = ^sem_t_rec; // from rtl/freebsd/ptypes.inc psem_t = ^sem_t; // from packages/pthreads/src/pthrbsd.inc

Indeed, the sem_t is differently defined between Linux and FreeBSD. Under Linux, sem_t is just a record defined as:

  // rtl/linux/ptypes.inc
  sem_t = record
     __sem_lock: _pthread_fastlock;
     __sem_value: cint;
     __sem_waiting: pointer;
  end;

In FreeBSD sem_t is pointer. Isn't that what psem_t is for? So under FreeBSD sem_t should be defined as

  sem_t_rec = record
  end;
  sem_t = sem_t_rec;
  psem_t = ^sem_t;

I would expect unix-types / posix-types supposed to be defined the same in all such related OSes (eg: *BSD, Linux, MacOSX, Haiku, *nix)?

Now the problem is the "@s". This returns type "Pointer" and now you have two pointer types: sem_t and psem_t. Thus the compiler can not resolve this.

Indeed. You just seem to have explained it better than I.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/
Marco van de Voort
to Graeme Geldenhuys

In our previous episode, Graeme Geldenhuys said:

In FreeBSD sem_t is pointer. Isn't that what psem_t is for?

No. That is a pointer to sem_t. It doesn't specify what sem_t should be.

struct sem;
typedef struct sem *    sem_t;

_sem_ is the record, sem_t is a pointer.

Show quoted text 10 lines
So under FreeBSD sem_t should be defined as sem_t_rec = record end; sem_t = sem_t_rec; psem_t = ^sem_t; I would expect unix-types / posix-types supposed to be defined the same in all such related OSes (eg: *BSD, Linux, MacOSX, Haiku, *nix)?

The reality is afaik that sem_t is abstract in POSIX. Keep in mind that POSIX is not an API, but more a set of common requirements for an api.

Assuming the type should not be
necessary. The VAR variants are probably leftovers from 1.0.x when headers were pascalized as much as possible.

During the *nix RTL reform of what would become 2.0 I insisted to at least have the pointer variant alongside of the 1.0.x declarations (to make examples in C translate 1:1)

The resulting overloading can cause problems. It can be reduced by deprecating the original pascallized versions, and removing them in some future version.

Sven Barth
to Graeme Geldenhuys: I thinking was that this problem seems to point towards a bug, or at least inconsistency…
Graeme Geldenhuys wrote 9 lines
On 2013-02-03 12:28, Sven Barth wrote: > > I personally think that the fpc-pascal list was the more approbiate, but > nevertheless: your problem comes down to this code (in principal): I thinking was that this problem seems to point towards a bug, or at least inconsistency between defined types and various platforms. But as you say, nevertheless. Thanks for replying.

I personally still think there is a bug, because the compiler should (in my opinion) not consider "sem_init(@sem)" a valid usage of "sem_init(var sem: sem_t)"...

Show quoted text 26 lines
> > type > sem_t_rec = record > end; // from rtl/freebsd/ptypes.inc > sem_t = ^sem_t_rec; // from rtl/freebsd/ptypes.inc > psem_t = ^sem_t; // from packages/pthreads/src/pthrbsd.inc Indeed, the sem_t is differently defined between Linux and FreeBSD. Under Linux, sem_t is just a record defined as: // rtl/linux/ptypes.inc sem_t = record __sem_lock: _pthread_fastlock; __sem_value: cint; __sem_waiting: pointer; end; In FreeBSD sem_t is pointer. Isn't that what psem_t is for? So under FreeBSD sem_t should be defined as sem_t_rec = record end; sem_t = sem_t_rec; psem_t = ^sem_t;

I would say that someone wanted to "honor" the "obfuscated type" idea of that structs... don't ask me why it was done that way though

I would expect unix-types / posix-types supposed to be defined the same in all such related OSes (eg: *BSD, Linux, MacOSX, Haiku, *nix)?

I you look at the POSIX definition at
http://pubs.opengroup.org/onlinepubs/007904975/basedefs/semaphore.h.html you'll see that they don't specify any specific fields so sem_t should be treated as opaque type and thus any kernel can implement it as it sees fit.

Show quoted text 7 lines
> Now the problem is the "@s". This returns type "Pointer" and now you > have two pointer types: sem_t and psem_t. Thus the compiler can not > resolve this. Indeed. You just seem to have explained it better than I.

Did at least the solution help you? AFAIK it should work for FreeBSD as well as Linux (and maybe the other *nix systems...)

Regards,
sven

Graeme Geldenhuys
to Marco van de Voort: In our previous episode, Graeme Geldenhuys said: No. That is a pointer to sem_t. It…
Marco van de Voort wrote
The resulting overloading can cause problems. It can be reduced by deprecating the original pascallized versions, and removing them in some future version.

So at this current point in time, my only solution is to have code as follows in tiOPF:

 procedure TtiPool.CreatePoolSemaphore;
 ...
 begin
   {$ifdef windows}
    ...
   {$endif}
   {$ifdef unix}
     {$ifdef linux}
     ...
     {$endif}
     {$ifdef freebsd}
     ...
     {$endif}
     {$ifdef macosx}  // I plan to test under MacOSX soon
     ...
     {$endif}
   {$endif}
 end;

And everywhere else in the TtiPool class where sem_* methods are used.

This is just yuck!!! I hate IFDEF's. :-/

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/
Sven Barth
to Graeme Geldenhuys
Graeme Geldenhuys wrote 29 lines
On 2013-02-03 18:08, Marco van de Voort wrote: > > The resulting overloading can cause problems. It can be reduced by > deprecating the original pascallized versions, and removing them in some > future version. So at this current point in time, my only solution is to have code as follows in tiOPF: procedure TtiPool.CreatePoolSemaphore; ... begin {$ifdef windows} ... {$endif} {$ifdef unix} {$ifdef linux} ... {$endif} {$ifdef freebsd} ... {$endif} {$ifdef macosx} // I plan to test under MacOSX soon ... {$endif} {$endif} end; And everywhere else in the TtiPool class where sem_* methods are used.

Why? The variant with the TYPEDADDRESS should work for the other *nix targets as well...

Regards,
Sven

Graeme Geldenhuys
to Sven Barth: I personally still think there is a bug, because the compiler should (in my opinion) not…
Sven Barth wrote
I personally still think there is a bug, because the compiler should (in my opinion) not consider "sem_init(@sem)" a valid usage of "sem_init(var sem: sem_t)"...

+1

I you look at the POSIX definition at http://pubs.opengroup.org/onlinepubs/007904975/basedefs/semaphore.h.html you'll see that they don't specify any specific fields so sem_t should

After reading Marco's reply I now understand. I didn't know this before.

Did at least the solution help you? AFAIK it should work for FreeBSD as well as Linux (and maybe the other *nix systems...)

[After my reply to Marco, I tried your solution]

Yes, that did work - thanks. I have never seen those {$....} you mentioned, but will read the FPC docs now to find out more.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/
Sven Barth
to Graeme Geldenhuys: +1 After reading Marco's reply I now understand. I didn't know this before. [After my…
Graeme Geldenhuys wrote 7 lines
> Did at least the solution help you? AFAIK it should work for FreeBSD as > well as Linux (and maybe the other *nix systems...) [After my reply to Marco, I tried your solution] Yes, that did work - thanks. I have never seen those {$....} you mentioned, but will read the FPC docs now to find out more.

I can suggest you to read
http://www.freepascal.org/docs-html/prog/progch1.html#x5-40001 if you've not already found it. :)
The 2.6.0 documentation is not completely up to date regarding the directives, but the 2.6.2 one will be (see
http://bugs.freepascal.org/view.php?id=21303 ).

Regards,
Sven