o Haiku patches by Olivier Coursiere

+ add posix thread support
  * improve signal handling
  * synchronize haiku's baseunix unit with the unix one (maybe it will be possible to remove Haiku's one in a future patch, but i keep it for now)
  + add support for standard sockets
  * fix some functions import to use the right libraries under Haiku
  * fix packages compilation

git-svn-id: trunk@12636 -
This commit is contained in:
florian 2009-02-01 10:30:55 +00:00
parent f9556bad39
commit c127154efa
19 changed files with 236 additions and 684 deletions

2
.gitattributes vendored
View File

@ -5358,6 +5358,7 @@ rtl/haiku/i386/dllprt.cpp svneol=native#text/plain
rtl/haiku/i386/func.as svneol=native#text/plain
rtl/haiku/i386/prt0.as svneol=native#text/plain
rtl/haiku/i386/sighnd.inc svneol=native#text/plain
rtl/haiku/osdefs.inc svneol=native#text/plain
rtl/haiku/osmacro.inc svneol=native#text/plain
rtl/haiku/ossysc.inc svneol=native#text/plain
rtl/haiku/ostypes.inc svneol=native#text/plain
@ -5377,7 +5378,6 @@ rtl/haiku/system.pp svneol=native#text/plain
rtl/haiku/termio.pp svneol=native#text/plain
rtl/haiku/termios.inc svneol=native#text/plain
rtl/haiku/termiosproc.inc svneol=native#text/plain
rtl/haiku/tthread.inc svneol=native#text/plain
rtl/haiku/unixsock.inc svneol=native#text/plain
rtl/haiku/unxconst.inc svneol=native#text/plain
rtl/haiku/unxfunc.inc svneol=native#text/plain

View File

@ -15,10 +15,12 @@ dirs_arm_linux=graph
dirs_m68k_linux=graph
dirs_beos=fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick \
gdbint libpng x11 gdbm tcl syslog libcurl opengl bfd aspell svgalib \
imlib utmp fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 librsvg httpd13 httpd20 httpd22 pxlib numlib
imlib utmp fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 librsvg httpd13 httpd20 httpd22 pxlib numlib \
iconvenc
dirs_haiku=fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick \
gdbint libpng x11 gdbm tcl syslog libcurl opengl bfd aspell svgalib \
imlib utmp fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 librsvg httpd13 httpd20 httpd22 pxlib numlib
imlib utmp fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 librsvg httpd13 httpd20 httpd22 pxlib numlib \
iconvenc
dirs_freebsd=fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick \
gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo bfd aspell svgalib \
imlib utmp fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 librsvg httpd13 httpd20 httpd22 pxlib numlib \
@ -317,4 +319,4 @@ fcl-xml_shared: iconvenc_shared
fcl-xml_smart: iconvenc_smart
fcl-xml_debug: iconvenc_debug
fcl-xml_release: iconvenc_release
endif
endif

View File

@ -17,6 +17,8 @@ rsts=sax xpath htmlwriter xmlconf
[require]
packages=fcl-base
packages_beos=iconvenc
packages_haiku=iconvenc
packages_linux=iconvenc
packages_darwin=iconvenc
packages_freebsd=iconvenc
@ -32,4 +34,4 @@ fpcpackage=y
fpcdir=../..
[rules]
.NOTPARALLEL:
.NOTPARALLEL:

View File

@ -31,6 +31,10 @@ uses
const
n = 1;
{$ifdef beos}
ESysEILSEQ = EILSEQ;
{$endif}
type
piconv_t = ^iconv_t;
iconv_t = pointer;
@ -171,4 +175,3 @@ begin
end;
end.

View File

@ -35,7 +35,11 @@ uses initc,BaseUnix, unixtype;
{$else}
{$ifdef beos}
uses initc, ctypes, baseunix, unixtype;
{$i pthrbeos.inc}
{$ifdef haiku}
{$i pthrhaiku.inc}
{$else}
{$i pthrbeos.inc}
{$endif}
{$else}
{$error operating system not detected}
{$endif}
@ -45,4 +49,4 @@ uses initc,BaseUnix, unixtype;
implementation
end.
end.

View File

@ -364,3 +364,27 @@ const B_SYMBOL_TYPE_ANY = $5;
{ Constansts for MMAP }
const
MAP_ANONYMOUS =$1000;
const
POLLIN = $0001;
POLLOUT = $0002;
POLLERR = $0004;
POLLPRI = $0020;
POLLHUP = $0080;
POLLNVAL = $1000;
{ XOpen, XPG 4.2 }
POLLRDNORM = POLLIN;
POLLRDBAND = $0008;
POLLWRNORM = POLLOUT;
POLLWRBAND = $0010;
type
pollfd = record
fd: cint;
events: cshort;
revents: cshort;
end;
tpollfd = pollfd;
ppollfd = ^pollfd;

View File

@ -415,3 +415,9 @@ struct winsize {
Chr(VINTR), Chr(VQUIT), Chr(VERASE), Chr(VKILL), Chr(VEOF), Chr(VEOL),
Chr(VEOL2), Chr(VSWTCH), Chr(VSTART), Chr(VSTOP), Chr(VSUSP));
{
According to posix/sys/ioctl.h
/* these currently work only on sockets */
}
FIONBIO = $be000000;
FIONREAD = $be000001;

View File

@ -15,32 +15,28 @@
Unit BaseUnix;
Interface
{$inline on}
Uses UnixType;
uses UnixType;
{$i osdefs.inc} { Compile time defines }
{$i aliasptp.inc}
{$packrecords C}
{$define oldreaddir} // Keep using readdir system call instead
// of userland getdents stuff.
{$define usedomain} // Allow uname with "domain" entry.
// (which is a GNU extension)
{$define posixworkaround} // Temporary ugly workaround for signal handler.
// (mainly until baseunix migration is complete)
{$ifndef FPC_USE_LIBC}
{$define FPC_USE_SYSCALL}
{$define FPC_USE_SYSCALL}
{$endif}
{$i errno.inc} { Error numbers }
{$i errno.inc} { Error numbers }
{$i ostypes.inc}
{$ifdef FPC_USE_LIBC}
const clib = 'root';
const netlib = 'network';
{$i oscdeclh.inc}
const clib = 'root';
const netlib = 'network';
{$i oscdeclh.inc}
{$ELSE}
{$i bunxh.inc} { Functions}
{$i bunxh.inc} { Functions}
{$ENDIF}
function fpgeterrno:longint;
@ -62,6 +58,8 @@ Function FpNanoSleep (req : ptimespec;rem : ptimespec):cint;
{$endif}
{$endif}
{$i genfunch.inc}
{ Fairly portable constants. I'm not going to waste time to duplicate and alias
them anywhere}
@ -83,14 +81,20 @@ Const
implementation
{$ifdef hassysctl}
Uses Sysctl;
{$endif}
{$i genfuncs.inc} // generic calls. (like getenv)
{$I gensigset.inc} // general sigset funcs implementation.
{$I genfdset.inc} // general fdset funcs.
{$ifndef FPC_USE_LIBC}
{$ifdef FPC_USE_LIBC}
{$i oscdecl.inc} // implementation of wrappers in oscdeclh.inc
{$else}
{$i syscallh.inc} // do_syscall declarations themselves
{$i sysnr.inc} // syscall numbers.
{$i bsyscall.inc} // cpu specific syscalls
{$i bsyscall.inc} // cpu specific syscalls
{$i bunxsysc.inc} // syscalls in system unit.
// {$i settimeo.inc}
{$endif}
@ -151,4 +155,4 @@ begin
end;
end;
end.
end.

23
rtl/haiku/osdefs.inc Normal file
View File

@ -0,0 +1,23 @@
{
Copyright (c) 2000-2002 by Marco van de Voort
Target dependent defines used when compileing the baseunix unit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************}
{$define usedomain} // Allow uname with "domain" entry.
// (which is a GNU extension)

View File

@ -363,7 +363,10 @@ const B_SYMBOL_TYPE_ANY = $5;
{ Constansts for MMAP }
const
MAP_ANONYMOUS =$1000;
{$ifdef FPC_IS_SYSTEM}
MAP_PRIVATE =2;
{$endif}
MAP_ANONYMOUS =$08;
const
POLLIN = $0001;
@ -388,4 +391,3 @@ type
tpollfd = pollfd;
ppollfd = ^pollfd;

View File

@ -45,12 +45,10 @@ function pthread_getspecific (t : pthread_key_t):pointer; cdecl; external;
function pthread_setspecific (t : pthread_key_t;p:pointer):cint; cdecl; external;
function pthread_key_create (p : ppthread_key_t;f: __destr_func_t):cint; cdecl;external;
function pthread_attr_init (p : ppthread_attr_t):cint; cdecl; external;
{$ifndef haiku}
function pthread_attr_setinheritsched(p : ppthread_attr_t;i:cint):cint; cdecl; external;
//function pthread_attr_setinheritsched(p : ppthread_attr_t;i:cint):cint; cdecl; external;
function pthread_attr_setscope (p : ppthread_attr_t;i:cint):cint;cdecl;external;
function pthread_attr_setdetachstate (p : ppthread_attr_t;i:cint):cint;cdecl;external;
function pthread_attr_setstacksize(p: ppthread_attr_t; stacksize: size_t):cint;cdecl;external;
{$endif}
function pthread_create ( p: ppthread_t;attr : ppthread_attr_t;f:__startroutine_t;arg:pointer):cint;cdecl;external;
procedure pthread_exit ( p: pointer); cdecl;external;
function pthread_self:pthread_t; cdecl;external;
@ -68,7 +66,6 @@ function pthread_cond_wait(_para1:Ppthread_cond_t;_para2:Ppthread_mutex_t):cint;
function pthread_kill(__thread:pthread_t; __signo:cint):cint;cdecl;external;
function pthread_sigmask(how: cint; nset: psigset; oset: psigset): cint; cdecl; external;
{$ifndef haiku}
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 ;
@ -77,7 +74,7 @@ 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;
{$endif}
function pthread_mutexattr_init(_para1:Ppthread_mutexattr_t):cint;cdecl;external;
function pthread_mutexattr_destroy(_para1:Ppthread_mutexattr_t):cint;cdecl;external;
function pthread_mutexattr_gettype(_para1:Ppthread_mutexattr_t; _para2:Pcint):cint;cdecl;external;
@ -85,4 +82,3 @@ function pthread_mutexattr_settype(_para1:Ppthread_mutexattr_t; _para2:cint):cin
function pthread_cond_timedwait(__cond:ppthread_cond_t; __mutex:ppthread_mutex_t; __abstime:ptimespec):longint;cdecl;external;

View File

@ -15,31 +15,39 @@
Const { For sending a signal }
SA_NOCLDSTOP = 1;
// does not exist under BeOS i think !
SA_ONSTACK = $001; { take signal on signal stack }
SA_RESTART = $002; { restart system call on signal return }
SA_RESETHAND = $004; { reset to SIG_DFL when taking signal }
SA_NODEFER = $010; { don't mask the signal we're delivering }
SA_NOCLDWAIT = $020; { don't keep zombies around }
SA_SIGINFO = $040; { signal handler with SA_SIGINFO args }
SA_USERTRAMP = $100; { SUNOS compat: Do not bounce off kernel's sigtramp }
SA_NOCLDSTOP = $01;
SA_NOCLDWAIT = $02;
SA_RESETHAND = $03;
SA_NODEFER = $08;
SA_RESTART = $10;
SA_ONSTACK = $20;
SA_SIGINFO = $40;
SA_NOMASK = SA_NODEFER;
SA_STACK = SA_ONSTACK;
SA_ONESHOT = SA_RESETHAND;
SIG_BLOCK = 1;
SIG_UNBLOCK = 2;
SIG_SETMASK = 3;
{BeOS Checked}
{ values for ss_flags }
SS_ONSTACK = $1;
SS_DISABLE = $2;
MINSIGSTKSZ = 4096;
SIGSTKSZ = 16384;
{Haiku Checked}
{
The numbering of signals for BeOS attempts to maintain
some consistency with UN*X conventions so that things
like "kill -9" do what you expect.
}
SIG_DFL = 0 ;
SIG_IGN = 1 ;
SIG_ERR = -1 ;
SIG_DFL = 0;
SIG_IGN = 1;
SIG_ERR = -1;
SIG_HOLD = 3;
SIGHUP = 1;
SIGINT = 2;
@ -63,6 +71,14 @@ Const { For sending a signal }
SIGWINCH = 20;
SIGKILLTHR = 21;
SIGTRAP = 22;
SIGPOLL = 23;
SIGPROF = 24;
SIGSYS = 25;
SIGURG = 26;
SIGVTALRM = 27;
SIGXCPU = 28;
SIGXFSZ = 29;
SIGBUS = SIGSEGV;
{
@ -283,11 +299,20 @@ type
// end;
sa_Mask : SigSet;
sa_Flags : Longint;
sa_userdaa : pointer
sa_userdata : pointer
end;
PSigActionRec = ^SigActionRec;
pstack_t = ^stack_t;
stack_t = record
ss_sp: pChar; {* signal stack base *}
ss_size: size_t; {* signal stack length *}
ss_flags: cInt; {* SS_DISABLE and/or SS_ONSTACK *}
end;
TStack = stack_t;
PStack = pstack_t;
{
Change action of process upon receipt of a signal.
Signum specifies the signal (all except SigKill and SigStop).
@ -296,4 +321,3 @@ type
}

View File

@ -314,21 +314,52 @@ end;
{$i sighnd.inc}
//void set_signal_stack(void *ptr, size_t size);
//int sigaltstack(const stack_t *ss, stack_t *oss);
procedure set_signal_stack(ptr : pointer; size : size_t); external 'root' name 'set_signal_stack';
function sigaltstack(const ss : pstack_t; oss : pstack_t) : integer; external 'root' name 'sigaltstack';
type
TAlternateSignalStack = record
case Integer of
0 : (buffer : array[0..SIGSTKSZ] of Char);
1 : (ld : int64);
2 : (l : integer);
3 : (p : pointer);
end;
var
act: SigActionRec;
alternate_signal_stack : TAlternateSignalStack;
Procedure InstallSignals;
var
oldact: SigActionRec;
r : integer;
st : stack_t;
begin
FillChar(st, sizeof(st), 0);
st.ss_flags := 0;
st.ss_sp := alternate_signal_stack.buffer;
st.ss_size := SizeOf(alternate_signal_stack);
r := sigaltstack(@st, nil);
if (r <> 0) then
WriteLn('error sigalstack');
{ Initialize the sigaction structure }
{ all flags and information set to zero }
FillChar(act, sizeof(SigActionRec),0);
{ initialize handler }
act.sa_handler := SigActionHandler(@SignalToRunError);
act.sa_flags:=SA_SIGINFO;
FpSigAction(SIGFPE,@act,nil);
FpSigAction(SIGSEGV,@act,nil);
FpSigAction(SIGBUS,@act,nil);
FpSigAction(SIGILL,@act,nil);
act.sa_flags := SA_ONSTACK;
FpSigAction(SIGFPE,@act,@oldact);
FpSigAction(SIGSEGV,@act,@oldact);
FpSigAction(SIGBUS,@act,@oldact);
FpSigAction(SIGILL,@act,@oldact);
end;
procedure SysInitStdIO;
@ -352,7 +383,8 @@ begin
IsConsole := TRUE;
StackLength := CheckInitialStkLen(InitialStkLen);
StackBottom := Sptr - StackLength;
ReturnNilIfGrowHeapFails := False;
SysResetFPU;
if not(IsLibrary) then
SysInitFPU;
@ -362,11 +394,12 @@ begin
SysInitStdIO;
{ Setup heap }
myheapsize:=4096*1;// $ 20000;
myheaprealsize:=4096*1;// $ 20000;
myheapsize:=4096*100;// $ 20000;
myheaprealsize:=4096*100;// $ 20000;
heapstart:=nil;
heapstartpointer := nil;
heapstartpointer := Sbrk2(4096*1);
// heapstartpointer := Sbrk2(4096*1);
heapstartpointer := SysOSAlloc(4096*100);
{$IFDEF FPC_USE_LIBC}
// heap_handle := create_area('fpcheap',heapstart,0,myheaprealsize,0,3);//!!
{$ELSE}
@ -421,4 +454,4 @@ begin
initunicodestringmanager;
{$endif VER2_2}
setupexecname;
end.
end.

View File

@ -415,3 +415,9 @@ struct winsize {
Chr(VINTR), Chr(VQUIT), Chr(VERASE), Chr(VKILL), Chr(VEOF), Chr(VEOL),
Chr(VEOL2), Chr(VSWTCH), Chr(VSTART), Chr(VSTOP), Chr(VSUSP));
{
According to posix/sys/ioctl.h
/* these currently work only on sockets */
}
FIONBIO = $be000000;
FIONREAD = $be000001;

View File

@ -1,613 +0,0 @@
{
This file is part of the Free Component Library (FCL)
Copyright (c) 1999-2000 by Peter Vreman
BeOS TThread implementation
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
{$IFDEF VER1_0} // leaving the old implementation in for now...
type
PThreadRec=^TThreadRec;
TThreadRec=record
thread : TThread;
next : PThreadRec;
end;
var
ThreadRoot : PThreadRec;
ThreadsInited : boolean;
// MainThreadID: longint;
Const
ThreadCount: longint = 0;
function ThreadSelf:TThread;
var
hp : PThreadRec;
sp : Pointer;
begin
sp:=SPtr;
hp:=ThreadRoot;
while assigned(hp) do
begin
if (sp<=hp^.Thread.FStackPointer) and
(sp>(hp^.Thread.FStackPointer-hp^.Thread.FStackSize)) then
begin
Result:=hp^.Thread;
exit;
end;
hp:=hp^.next;
end;
Result:=nil;
end;
//function SIGCHLDHandler(Sig: longint): longint; cdecl;//this is std linux C declaration as function
procedure SIGCHLDHandler(Sig: longint); cdecl;
begin
fpwaitpid(-1, nil, WNOHANG);
end;
procedure InitThreads;
var
Act, OldAct: Baseunix.PSigActionRec;
begin
ThreadRoot:=nil;
ThreadsInited:=true;
// This will install SIGCHLD signal handler
// signal() installs "one-shot" handler,
// so it is better to install and set up handler with sigaction()
GetMem(Act, SizeOf(SigActionRec));
GetMem(OldAct, SizeOf(SigActionRec));
Act^.sa_handler := TSigAction(@SIGCHLDHandler);
Act^.sa_flags := SA_NOCLDSTOP {or SA_NOMASK or SA_RESTART};
Fillchar(Act^.sa_mask,sizeof(Act^.sa_mask),0); //Do not block all signals ??. Don't need if SA_NOMASK in flags
FpSigAction(SIGCHLD, Act, OldAct);
FreeMem(Act, SizeOf(SigActionRec));
FreeMem(OldAct, SizeOf(SigActionRec));
end;
procedure DoneThreads;
var
hp : PThreadRec;
begin
while assigned(ThreadRoot) do
begin
ThreadRoot^.Thread.Destroy;
hp:=ThreadRoot;
ThreadRoot:=ThreadRoot^.Next;
dispose(hp);
end;
ThreadsInited:=false;
end;
procedure AddThread(t:TThread);
var
hp : PThreadRec;
begin
{ Need to initialize threads ? }
if not ThreadsInited then
InitThreads;
{ Put thread in the linked list }
new(hp);
hp^.Thread:=t;
hp^.next:=ThreadRoot;
ThreadRoot:=hp;
inc(ThreadCount, 1);
end;
procedure RemoveThread(t:TThread);
var
lasthp,hp : PThreadRec;
begin
hp:=ThreadRoot;
lasthp:=nil;
while assigned(hp) do
begin
if hp^.Thread=t then
begin
if assigned(lasthp) then
lasthp^.next:=hp^.next
else
ThreadRoot:=hp^.next;
dispose(hp);
exit;
end;
lasthp:=hp;
hp:=hp^.next;
end;
Dec(ThreadCount, 1);
if ThreadCount = 0 then DoneThreads;
end;
{ TThread }
function ThreadProc(args:pointer): Integer;//cdecl;
var
FreeThread: Boolean;
Thread : TThread absolute args;
begin
while Thread.FHandle = 0 do fpsleep(1);
if Thread.FSuspended then Thread.suspend();
try
Thread.Execute;
except
Thread.FFatalException := TObject(AcquireExceptionObject);
end;
FreeThread := Thread.FFreeOnTerminate;
Result := Thread.FReturnValue;
Thread.FFinished := True;
Thread.DoTerminate;
if FreeThread then
Thread.Free;
fpexit(Result);
end;
constructor TThread.Create(CreateSuspended: Boolean);
var
Flags: Integer;
begin
inherited Create;
AddThread(self);
FSuspended := CreateSuspended;
Flags := CLONE_VM + CLONE_FS + CLONE_FILES + CLONE_SIGHAND + SIGCHLD;
{ Setup 16k of stack }
FStackSize:=16384;
Getmem(FStackPointer,FStackSize);
inc(FStackPointer,FStackSize);
FCallExitProcess:=false;
{ Clone }
FHandle:= Clone(@ThreadProc,FStackPointer,Flags,self);
// if FSuspended then Suspend;
FThreadID := FHandle;
IsMultiThread := TRUE;
FFatalException := nil;
end;
destructor TThread.Destroy;
begin
if not FFinished and not Suspended then
begin
Terminate;
WaitFor;
end;
if FHandle <> -1 then
fpkill(FHandle, SIGKILL);
dec(FStackPointer,FStackSize);
Freemem(FStackPointer);
FFatalException.Free;
FFatalException := nil;
inherited Destroy;
RemoveThread(self);
end;
procedure TThread.CallOnTerminate;
begin
FOnTerminate(Self);
end;
procedure TThread.DoTerminate;
begin
if Assigned(FOnTerminate) then
Synchronize(@CallOnTerminate);
end;
const
{ I Don't know idle or timecritical, value is also 20, so the largest other
possibility is 19 (PFV) }
Priorities: array [TThreadPriority] of Integer =
(-20,-19,-10,9,10,19,20);
function TThread.GetPriority: TThreadPriority;
var
P: Integer;
I: TThreadPriority;
begin
P := fpGetPriority(Prio_Process,FHandle);
Result := tpNormal;
for I := Low(TThreadPriority) to High(TThreadPriority) do
if Priorities[I] = P then
Result := I;
end;
procedure TThread.SetPriority(Value: TThreadPriority);
begin
fpSetPriority(Prio_Process,FHandle,Priorities[Value]);
end;
procedure TThread.Synchronize(Method: TThreadMethod);
begin
FSynchronizeException := nil;
FMethod := Method;
{ SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self)); }
if Assigned(FSynchronizeException) then
raise FSynchronizeException;
end;
procedure TThread.SetSuspended(Value: Boolean);
begin
if Value <> FSuspended then
if Value then
Suspend
else
Resume;
end;
procedure TThread.Suspend;
begin
FSuspended := true;
fpKill(FHandle, SIGSTOP);
end;
procedure TThread.Resume;
begin
fpKill(FHandle, SIGCONT);
FSuspended := False;
end;
procedure TThread.Terminate;
begin
FTerminated := True;
end;
function TThread.WaitFor: Integer;
var
status : longint;
begin
if FThreadID = MainThreadID then
fpwaitpid(0,@status,0)
else
fpwaitpid(FHandle,@status,0);
Result:=status;
end;
{$ELSE}
{
What follows, is a short description on my implementation of TThread.
Most information can also be found by reading the source and accompanying
comments.
A thread is created using BeginThread, which in turn calls
pthread_create. So the threads here are always posix threads.
Posix doesn't define anything for suspending threads as this is
inherintly unsafe. Just don't suspend threads at points they cannot
control. Therefore, I didn't implement .Suspend() if its called from
outside the threads execution flow (except on Linux _without_ NPTL).
The implementation for .suspend uses a semaphore, which is initialized
at thread creation. If the thread tries to suspend itself, we simply
let it wait on the semaphore until it is unblocked by someone else
who calls .Resume.
If a thread is supposed to be suspended (from outside its own path of
execution) on a system where the symbol LINUX is defined, two things
are possible.
1) the system has the LinuxThreads pthread implementation
2) the system has NPTL as the pthread implementation.
In the first case, each thread is a process on its own, which as far as
know actually violates posix with respect to signal handling.
But we can detect this case, because getpid(2) will
return a different PID for each thread. In that case, sending SIGSTOP
to the PID associated with a thread will actually stop that thread
only.
In the second case, this is not possible. But getpid(2) returns the same
PID across all threads, which is detected, and TThread.Suspend() does
nothing in that case. This should probably be changed, but I know of
no way to suspend a thread when using NPTL.
If the symbol LINUX is not defined, then the unimplemented
function SuspendThread is called.
Johannes Berg <johannes@sipsolutions.de>, Sunday, November 16 2003
}
// ========== semaphore stuff ==========
{
I don't like this. It eats up 2 filedescriptors for each thread,
and those are a limited resource. If you have a server programm
handling client connections (one per thread) it will not be able
to handle many if we use 2 fds already for internal structures.
However, right now I don't see a better option unless some sem_*
functions are added to systhrds.
I encapsulated all used functions here to make it easier to
change them completely.
}
{BeOS implementation}
function SemaphoreInit: Pointer;
begin
SemaphoreInit := GetMem(SizeOf(TFilDes));
fppipe(PFilDes(SemaphoreInit)^);
end;
procedure SemaphoreWait(const FSem: Pointer);
var
b: byte;
begin
fpread(PFilDes(FSem)^[0], b, 1);
end;
procedure SemaphorePost(const FSem: Pointer);
var
b : byte;
begin
b := 0;
fpwrite(PFilDes(FSem)^[1], b, 1);
end;
procedure SemaphoreDestroy(const FSem: Pointer);
begin
fpclose(PFilDes(FSem)^[0]);
fpclose(PFilDes(FSem)^[1]);
FreeMemory(FSem);
end;
// =========== semaphore end ===========
var
ThreadsInited: boolean = false;
{$IFDEF LINUX}
GMainPID: LongInt = 0;
{$ENDIF}
const
// stupid, considering its not even implemented...
Priorities: array [TThreadPriority] of Integer =
(-20,-19,-10,0,9,18,19);
procedure InitThreads;
begin
if not ThreadsInited then begin
ThreadsInited := true;
{$IFDEF LINUX}
GMainPid := fpgetpid();
{$ENDIF}
end;
end;
procedure DoneThreads;
begin
ThreadsInited := false;
end;
{ ok, so this is a hack, but it works nicely. Just never use
a multiline argument with WRITE_DEBUG! }
{$MACRO ON}
{$IFDEF DEBUG_MT}
{$define WRITE_DEBUG := writeln} // actually write something
{$ELSE}
{$define WRITE_DEBUG := //} // just comment out those lines
{$ENDIF}
function ThreadFunc(parameter: Pointer): LongInt; // cdecl;
var
LThread: TThread;
c: char;
begin
WRITE_DEBUG('ThreadFunc is here...');
LThread := TThread(parameter);
{$IFDEF LINUX}
// save the PID of the "thread"
// this is different from the PID of the main thread if
// the LinuxThreads implementation is used
LThread.FPid := fpgetpid();
{$ENDIF}
WRITE_DEBUG('thread initing, parameter = ', LongInt(LThread));
try
if LThread.FInitialSuspended then begin
SemaphoreWait(LThread.FSem);
if not LThread.FInitialSuspended then begin
WRITE_DEBUG('going into LThread.Execute');
LThread.Execute;
end;
end else begin
WRITE_DEBUG('going into LThread.Execute');
LThread.Execute;
end;
except
on e: exception do begin
WRITE_DEBUG('got exception: ',e.message);
LThread.FFatalException := TObject(AcquireExceptionObject);
// not sure if we should really do this...
// but .Destroy was called, so why not try FreeOnTerminate?
if e is EThreadDestroyCalled then LThread.FFreeOnTerminate := true;
end;
end;
WRITE_DEBUG('thread done running');
Result := LThread.FReturnValue;
WRITE_DEBUG('Result is ',Result);
LThread.FFinished := True;
LThread.DoTerminate;
if LThread.FreeOnTerminate then begin
WRITE_DEBUG('Thread should be freed');
LThread.Free;
WRITE_DEBUG('Thread freed');
end;
WRITE_DEBUG('thread func exiting');
end;
{ TThread }
constructor TThread.Create(CreateSuspended: Boolean; const StackSize: SizeUInt = DefaultStackSize);
var
data : pointer;
begin
// lets just hope that the user doesn't create a thread
// via BeginThread and creates the first TThread Object in there!
InitThreads;
inherited Create;
FSem := SemaphoreInit;
FSuspended := CreateSuspended;
FSuspendedExternal := false;
FInitialSuspended := CreateSuspended;
FFatalException := nil;
WRITE_DEBUG('creating thread, self = ',longint(self));
FHandle:= BeginThread(@ThreadFunc, Pointer(Self), FThreadID);
WRITE_DEBUG('TThread.Create done');
end;
destructor TThread.Destroy;
begin
if FThreadID = GetCurrentThreadID then begin
raise EThreadDestroyCalled.Create('A thread cannot destroy itself except by setting FreeOnTerminate and leaving!');
end;
// if someone calls .Free on a thread with
// FreeOnTerminate, then don't crash!
FFreeOnTerminate := false;
if not FFinished and not FSuspended then begin
Terminate;
WaitFor;
end;
if (FInitialSuspended) then begin
// thread was created suspended but never woken up.
SemaphorePost(FSem);
WaitFor;
end;
FFatalException.Free;
FFatalException := nil;
SemaphoreDestroy(FSem);
inherited Destroy;
end;
procedure TThread.SetSuspended(Value: Boolean);
begin
if Value <> FSuspended then
if Value then
Suspend
else
Resume;
end;
procedure TThread.Suspend;
begin
if not FSuspended then begin
if FThreadID = GetCurrentThreadID then begin
FSuspended := true;
SemaphoreWait(FSem);
end else begin
FSuspendedExternal := true;
{$IFDEF LINUX}
// naughty hack if the user doesn't have Linux with NPTL...
// in that case, the PID of threads will not be identical
// to the other threads, which means that our thread is a normal
// process that we can suspend via SIGSTOP...
// this violates POSIX, but is the way it works on the
// LinuxThreads pthread implementation. Not with NPTL, but in that case
// getpid(2) also behaves properly and returns the same PID for
// all threads. Thats actually (FINALLY!) native thread support :-)
if FPid <> GMainPID then begin
FSuspended := true;
fpkill(FPid, SIGSTOP);
end;
{$ELSE}
SuspendThread(FHandle);
{$ENDIF}
end;
end;
end;
procedure TThread.Resume;
begin
if (not FSuspendedExternal) then begin
if FSuspended then begin
SemaphorePost(FSem);
FInitialSuspended := false;
FSuspended := False;
end;
end else begin
{$IFDEF LINUX}
// see .Suspend
if FPid <> GMainPID then begin
fpkill(FPid, SIGCONT);
FSuspended := False;
end;
{$ELSE}
ResumeThread(FHandle);
{$ENDIF}
FSuspendedExternal := false;
end;
end;
procedure TThread.Terminate;
begin
FTerminated := True;
end;
function TThread.WaitFor: Integer;
begin
WRITE_DEBUG('waiting for thread ',FHandle);
WaitFor := WaitForThreadTerminate(FHandle, 0);
WRITE_DEBUG('thread terminated');
end;
procedure TThread.CallOnTerminate;
begin
// no need to check if FOnTerminate <> nil, because
// thats already done in DoTerminate
FOnTerminate(self);
end;
procedure TThread.DoTerminate;
begin
if Assigned(FOnTerminate) then
Synchronize(@CallOnTerminate);
end;
function TThread.GetPriority: TThreadPriority;
var
P: Integer;
I: TThreadPriority;
begin
P := ThreadGetPriority(FHandle);
Result := tpNormal;
for I := Low(TThreadPriority) to High(TThreadPriority) do
if Priorities[I] = P then
Result := I;
end;
(*
procedure TThread.Synchronize(Method: TThreadMethod);
begin
{$TODO someone with more clue of the GUI stuff will have to do this}
end;
*)
procedure TThread.SetPriority(Value: TThreadPriority);
begin
ThreadSetPriority(FHandle, Priorities[Value]);
end;
{$ENDIF}

View File

@ -14,7 +14,16 @@
{$define uselibc:=cdecl; external;}
const libname='c';
const
{$ifdef BEOS}
{$ifdef HAIKU}
libname = 'network';
{$else}
libname = 'net';
{$endif}
{$else}
libname='c';
{$endif}
function cfpaccept (s:cint; addrx : psockaddr; addrlen : psocklen):cint; cdecl; external libname name 'accept';
function cfpbind (s:cint; addrx : psockaddr; addrlen : tsocklen):cint; cdecl; external libname name 'bind';
@ -32,7 +41,12 @@ function cfpsendto (s:cint; msg:pointer; len:size_t; flags:cint; tox :psock
function cfpsetsockopt (s:cint; level:cint; optname:cint; optval:pointer; optlen :tsocklen):cint; cdecl; external libname name 'setsockopt';
function cfpshutdown (s:cint; how:cint):cint; cdecl; external libname name 'shutdown';
function cfpsocket (domain:cint; xtype:cint; protocol: cint):cint; cdecl; external libname name 'socket';
{$if defined(BEOS) and not defined(HAIKU)}
// function unavailable under BeOS
{$else}
function cfpsocketpair (d:cint; xtype:cint; protocol:cint; sv:pcint):cint; cdecl; external libname name 'socketpair';
{$endif}
function fpaccept (s:cint; addrx : psockaddr; addrlen : psocklen):cint;
@ -120,9 +134,16 @@ begin
internal_socketerror:=fpgeterrno;
end;
{$if defined(BEOS) and not defined(HAIKU)}
// function unavailable under BeOS
function fpsocketpair (d:cint; xtype:cint; protocol:cint; sv:pcint):cint;
begin
internal_socketerror:= -1; // TODO : check if it is an error
end;
{$else}
function fpsocketpair (d:cint; xtype:cint; protocol:cint; sv:pcint):cint;
begin
fpsocketpair:=cfpsocketpair(d,xtype,protocol,sv);
internal_socketerror:=fpgeterrno;
end;
{$endif}

View File

@ -47,7 +47,9 @@ interface
{$ifndef dynpthreads} // If you have problems compiling this on FreeBSD 5.x
{$linklib c} // try adding -Xf
{$ifndef Darwin}
{$linklib pthread}
{$ifndef haiku}
{$linklib pthread}
{$endif haiku}
{$endif darwin}
{$endif}
@ -278,7 +280,9 @@ Type PINTRTLEvent = ^TINTRTLEvent;
writeln('Starting new thread');
{$endif DEBUG_MT}
pthread_attr_init(@thread_attr);
{$ifndef HAIKU}
pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED);
{$endif}
// will fail under linux -- apparently unimplemented
pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS);
@ -1092,4 +1096,4 @@ initialization
end;
SetCThreadManager;
finalization
end.
end.

View File

@ -26,8 +26,12 @@ implementation
{$linklib c}
{$if not defined(linux) and not defined(solaris) and not defined(haiku)} // Linux (and maybe glibc platforms in general), have iconv in glibc.
{$linklib iconv}
{$if not defined(linux) and not defined(solaris)} // Linux (and maybe glibc platforms in general), have iconv in glibc.
{$if defined(haiku)}
{$linklib textencoding}
{$else}
{$linklib iconv}
{$endif}
{$define useiconv}
{$endif linux}
@ -42,7 +46,11 @@ Const
{$ifndef useiconv}
libiconvname='c'; // is in libc under Linux.
{$else}
{$ifdef haiku}
libiconvname='textencoding'; // is in libtextencoding under Haiku
{$else}
libiconvname='iconv';
{$endif}
{$endif}
{ helper functions from libc }
@ -89,7 +97,11 @@ const
{$ifdef beos}
{$warning check correct value for BeOS}
CODESET=49;
LC_ALL = 6; // Checked for BeOS, but 0 under Haiku...
{$ifdef haiku}
LC_ALL = 0; // Checked for Haiku
{$else}
LC_ALL = 6; // Checked for BeOS
{$endif}
ESysEILSEQ = EILSEQ;
{$else}
{$error lookup the value of CODESET in /usr/include/langinfo.h, and the value of LC_ALL in /usr/include/locale.h for your OS }
@ -124,7 +136,7 @@ type
function nl_langinfo(__item:nl_item):pchar;cdecl;external libiconvname name 'nl_langinfo';
{$endif}
{$if (not defined(bsd) and not defined(beos)) or defined(darwin) or defined(haiku)}
{$if (not defined(bsd) and not defined(beos)) or defined(darwin)}
function iconv_open(__tocode:pchar; __fromcode:pchar):iconv_t;cdecl;external libiconvname name 'iconv_open';
function iconv(__cd:iconv_t; __inbuf:ppchar; __inbytesleft:psize_t; __outbuf:ppchar; __outbytesleft:psize_t):size_t;cdecl;external libiconvname name 'iconv';
function iconv_close(__cd:iconv_t):cint;cdecl;external libiconvname name 'iconv_close';
@ -759,4 +771,3 @@ finalization
{ fini conversion tables for main program }
FiniThread;
end.

View File

@ -81,10 +81,10 @@ const
{$ifdef beos}
{$ifdef haiku}
Function FPSelect (N:cint;readfds,writefds,exceptfds:pfdSet;TimeOut:PTimeVal):cint; cdecl; external 'network' name 'select';
Function FpPoll (fds: ppollfd; nfds: cuint; timeout: clong): cint; cdecl; external 'network' name 'poll';
Function FpPoll (fds: ppollfd; nfds: cuint; timeout: clong): cint; cdecl; external clib name 'poll';
{$else}
Function FPSelect (N:cint;readfds,writefds,exceptfds:pfdSet;TimeOut:PTimeVal):cint; cdecl; external 'net' name 'select';
Function FpPoll (fds: ppollfd; nfds: cuint; timeout: clong): cint; cdecl; external 'net' name 'poll';
Function FpPoll (fds: ppollfd; nfds: cuint; timeout: clong): cint; cdecl; external clib name 'poll';
{$endif}
{$else}
Function FPSelect (N:cint;readfds,writefds,exceptfds:pfdSet;TimeOut:PTimeVal):cint; cdecl; external clib name 'select';
@ -158,4 +158,4 @@ const
{$ifdef linux}
function FpPrCtl(options : cInt; const args : ptruint) : cint; cdecl; external clib name 'prctl';
{$endif}
{$endif}