unit THREADS;
(*
**
** Serial and TCP/IP communication routines for DOS, OS/2 and Win9x/NT.
** Tested with: TurboPascal   v7.0,    (DOS)
**              VirtualPascal v2.1,    (OS/2, Win32)
**              FreePascal    v0.99.12 (DOS, Win32)
**              Delphi        v4.0.    (Win32)
**
** Version : 1.01
** Created : 07-Mar-1999
** Last update : 26-Sep-1999
**
** Note: (c) 1998-1999 by Maarten Bekers
**
*)

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)
 INTERFACE
(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

{$IFDEF OS2}
 uses Os2Base;
{$ENDIF}

{$IFDEF WIN32}
 uses Windows;
{$ENDIF}

{$IFDEF OS2}
  Type THandle = Longint;
       DWORD   = Longint;
{$ENDIF}

{$IFDEF WIN32}
 {$IFDEF FPC}
   Type THandle = Handle;
 {$ENDIF}
{$ENDIF}

type TSysEventObj = Object
       {$IFDEF OS2}
         SemHandle: HEV;
       {$ENDIF}

       {$IFDEF WIN32}
         SemHandle: THandle;
       {$ENDIF}

       constructor init;
       destructor done;

       procedure DisposeEvent;
       procedure SignalEvent;
       procedure ResetEvent;
       function  CreateEvent(InitialState: Boolean): Boolean;
       function  WaitForEvent(TimeOut: Longint): Boolean;
     end; { TSysEventObj }

Type PSysEventObj = ^TSysEventObj;

type TExclusiveObj = Object
       {$IFDEF OS2}
         Exclusive: PHMtx;
       {$ENDIF}

       {$IFDEF WIN32}
         Exclusive: PRTLCriticalSection;
       {$ENDIF}

       constructor Init;
       destructor Done;

       procedure CreateExclusive;
       procedure DisposeExclusive;

       procedure EnterExclusive;
       procedure LeaveExclusive;
     end; { TExclusiveObj }

Type PExclusiveObj = ^TExclusiveObj;


type TThreadsObj = Object
       ThreadHandle : THandle;
       ThreadID     : DWORD;
       ThreadClosed : Boolean;

       constructor Init;
       destructor Done;

       function CreateThread(StackSize    : Longint;
                             CallProc,
                             Parameters   : Pointer;
                             CreationFlags: Longint): Boolean;
       procedure CloseThread;
       procedure TerminateThread(ExitCode: Longint);
     end; { TThreadsObj }

Type PThreadsObj = ^TThreadsObj;

procedure ExitThisThread;

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)
 IMPLEMENTATION
(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

constructor TSysEventObj.Init;
begin
  SemHandle := 0;
end; { constructor Init }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

destructor TSysEventObj.Done;
begin
  if Longint(SemHandle) <> -1 then
    begin
      SignalEvent;
      DisposeEvent;
    end; { if }
end; { destructor Done }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TSysEventObj.CreateEvent(InitialState: Boolean): Boolean;
{$IFDEF OS2}
var Returncode: longint;
{$ENDIF}
begin
  CreateEvent := true;

  {$IFDEF WIN32}
    SemHandle := Windows.CreateEvent(nil, true, InitialState, nil);
    if Longint(SemHandle) = -1 then CreateEvent := false;
  {$ENDIF}

  {$IFDEF OS2}
    returncode := DosCreateEventSem(nil, SemHandle, 0, InitialState);
    CreateEvent := (returncode=0);
  {$ENDIF}
end; { func. CreateEvent }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TSysEventObj.SignalEvent;
{$IFDEF OS2}
var RC: Longint;
{$ENDIF}
begin
  {$IFDEF WIN32}
    if Longint(SemHandle) <> -1 then
      SetEvent(SemHandle);
  {$ENDIF}

  {$IFDEF OS2}
    if SemHandle <> -1 then
      RC := DosPostEventSem(SemHandle);
  {$ENDIF}
end; { proc. SignalEvent }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TSysEventObj.ResetEvent;
{$IFDEF OS2}
var Flag: Longint;
    RC  : Longint;
{$ENDIF}
begin
  {$IFDEF WIN32}
    if SemHandle <> THandle(-1) then
      Windows.ResetEvent(SemHandle);
  {$ENDIF}

  {$IFDEF OS2}
    Flag := 0;
    if SemHandle <> -1 then
      RC := DosResetEventSem(SemHandle, Flag);
  {$ENDIF}
end; { proc. ResetEvent }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TSysEventObj.WaitForEvent(TimeOut: Longint): Boolean;
var ReturnCode: Longint;
{$IFDEF OS2}
    Flag      : Longint;
{$ENDIF}
begin
  {$IFDEF WIN32}
    if SemHandle <> THandle(-1) then
      ReturnCode := WaitForSingleObject(SemHandle, Timeout)
       else ReturnCode := 0;

    WaitForEvent := (ReturnCode = WAIT_OBJECT_0);
  {$ENDIF}

  {$IFDEF OS2}
    if SemHandle <> -1 then
      ReturnCode := DosWaitEventSem(SemHandle, TimeOut);

    Flag := 0;
    DosResetEventSem(SemHandle, Flag);
    WaitForEvent := (ReturnCode = 0);
{$ENDIF}
end; { func. WaitForEvent }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TSysEventObj.DisposeEvent;
{$IFDEF OS2}
var Flag: Longint;
{$ENDIF}
begin
  {$IFDEF WIN32}
    if SemHandle <> THandle(-1) then CloseHandle(SemHandle);
    SemHandle := 0;
  {$ENDIF}

  {$IFDEF OS2}
    Flag := 0;
    if SemHandle <> -1 then DosCloseEventSem(SemHandle);
    SemHandle := -1;
  {$ENDIF}
end; { proc. DisposeEvent }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

constructor TExclusiveObj.Init;
begin
  Exclusive := nil;
end; { constructor Init }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

destructor TExclusiveObj.Done;
begin
  if Exclusive <> nil then
    DisposeExclusive;
end; { destructor Done }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TExclusiveObj.CreateExclusive;
begin
  {$IFDEF WIN32}
    New(Exclusive);
    InitializeCriticalSection(Exclusive^);
  {$ENDIF}

  {$IFDEF OS2}
    New(Exclusive);
    DosCreateMutexSem(nil, Exclusive^, dcmw_Wait_All, false);
  {$ENDIF}
end; { proc. CreateExclusive }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TExclusiveObj.DisposeExclusive;
begin
  {$IFDEF WIN32}
    if Exclusive <> nil then
      begin
        DeleteCriticalSection(Exclusive^);
        Dispose(Exclusive);
      end; { if }

    Exclusive := nil;
  {$ENDIF}

  {$IFDEF OS2}
    if Exclusive <> nil then
      begin
        DosCloseMutexSem(Exclusive^);
        Dispose(Exclusive);
      end; { if }

    Exclusive := nil;
  {$ENDIF}
end; { proc. DisposeExclusive }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TExclusiveObj.EnterExclusive;
begin
  {$IFDEF WIN32}
     EnterCriticalSection(Exclusive^);
  {$ENDIF}

  {$IFDEF OS2}
    DosRequestMutexSem(Exclusive^, sem_Indefinite_Wait);
  {$ENDIF}
end; { proc. EnterExclusive }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TExclusiveObj.LeaveExclusive;
begin
  {$IFDEF WIN32}
    LeaveCriticalSection(Exclusive^);
  {$ENDIF}

  {$IFDEF OS2}
    DosReleaseMutexSem(Exclusive^);
  {$ENDIF}
end; { proc. LeaveExclusive }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

constructor TThreadsObj.Init;
begin
  ThreadHandle := 0;
  ThreadId := 0;
end; { constructor Init }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

destructor TThreadsObj.Done;
begin
  CloseThread;
  ThreadHandle := 0;
end; { destructor Done }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

function TThreadsObj.CreateThread(StackSize    : Longint;
                                  CallProc,
                                  Parameters   : Pointer;
                                  CreationFlags: Longint): Boolean;
var ReturnCode: Longint;
begin
  ThreadClosed := FALSE;

 {$IFNDEF VirtualPascal}
  {$IFDEF WIN32}
    ThreadHandle := Windows.CreateThread(nil,               { Security attrs }
                                 StackSize,                     { Stack size }
                                 CallProc,                { Actual procedure }
                                 Parameters,                    { Parameters }
                                 CreationFlags,             { Creation flags }
                                 ThreadID);                   { Thread ID ?? }

     CreateThread := (ThreadHandle <> THandle(-1));
  {$ENDIF}

  {$IFDEF OS2}
    ReturnCode :=
      DosCreateThread(ThreadHandle,                           { ThreadHandle }
                      CallProc,                           { Actual procedure }
                      Longint(Parameters),                      { Parameters }
                      CreationFlags,                        { Creation flags }
                      StackSize);                                { Stacksize }

     CreateThread := (ReturnCode = 0);
     if ReturnCode <> 0 then ThreadHandle := -1;
  {$ENDIF}

  {$IFDEF LINUX}

  {$ENDIF}


 {$ELSE}
   ThreadHandle := BeginThread(nil, StackSize, CallProc, Parameters, 0, ReturnCode);
   CreateThread := (ThreadHandle > THandle(-1));
 {$ENDIF}
end; { proc. CreateThread }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TThreadsObj.CloseThread;
begin
  ThreadClosed := TRUE;

  {$IFDEF WIN32}
    if ThreadHandle <> Thandle(-1) then CloseHandle(ThreadHandle);
    ThreadHandle := 0;
  {$ENDIF}

  {$IFDEF OS2}
    {!! DosClose() on a ThreadHandle doesn't work - will eventually close }
    {!! other handles ... }
    { if ThreadHandle <> -1 then DosClose(ThreadHandle); }
    ThreadHandle := -1;
  {$ENDIF}
end; { proc. CloseThread }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure TThreadsObj.TerminateThread(ExitCode: Longint);
begin
  ThreadClosed := TRUE;

  {$IFDEF WIN32}
    if ThreadHandle <> Thandle(-1) then
      Windows.TerminateThread(ThreadHandle, ExitCode);
    ThreadHandle := 00;
  {$ENDIF}

  {$IFDEF OS2}
    if ThreadHandle <> -1 then DosKillThread(ThreadHandle);
    ThreadHandle := -1;
  {$ENDIF}
end; { proc. TerminateThread }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

procedure ExitThisThread;
begin
  {$IFDEF WIN32}
    Windows.ExitThread(0);
  {$ENDIF}

  {$IFDEF OS2}
    Os2Base.DosExit(exit_Thread, 0);
  {$ENDIF}
end; { proc. ExitThread }

(*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-+-*-*)

end.
