Browse Source

* fix DosExitCode for sessions of other types, consider ExecFlags for other session types

git-svn-id: trunk@19398 -
Tomas Hajny 14 years ago
parent
commit
af03a73af2
1 changed files with 110 additions and 37 deletions
  1. 110 37
      rtl/os2/dos.pas

+ 110 - 37
rtl/os2/dos.pas

@@ -54,6 +54,14 @@ Type
 threadvar
 (* For compatibility with VP/2, used for runflags in Exec procedure. *)
     ExecFlags: cardinal;
+(* Note that the TP/BP compatible method for retrieval of exit codes    *)
+(* is limited to only one (the last) execution! Including the following *)
+(* two variables in the interface part allows querying the status of    *)
+(* of asynchronously started programs using DosWaitChild with dtNoWait  *)
+(* parameter, i.e. without waiting for the final program result (as     *)
+(* opposed to calling DosExitCode which would wait for the exit code).  *)
+    LastExecRes: TResultCodes;
+    LastExecFlags: cardinal;
 
 {$i dosh.inc}
 
@@ -64,12 +72,15 @@ function GetEnvPChar (EnvVar: string): PChar;
 function DosErrorModuleName: string;
 (* In case of an error in Dos.Exec returns the name of the module *)
 (* causing the problem - e.g. name of a missing or corrupted DLL. *)
+(* It may also contain a queue name in case of a failed attempt *)
+(* to create queue for reading results of started sessions.     *)
 
 
 
 implementation
 
 {$DEFINE HAS_GETMSCOUNT}
+{$DEFINE HAS_DOSEXITCODE}
 
 {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
 {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
@@ -79,7 +90,6 @@ implementation
 
 threadvar
   LastDosErrorModuleName: string;
-  ExecCounter: cardinal;
 
 
 const   FindResvdMask = $00003737; {Allowed bits in attribute
@@ -142,13 +152,40 @@ begin
 end;
 
 
+function DosExitCode: word;
+var
+  Res: TResultCodes;
+  PPID: cardinal;
+  RC: cardinal;
+begin
+  if (LastExecFlags = deAsyncResult) or (LastExecFlags = deAsyncResultDb) then
+   begin
+    RC := DosWaitChild (DCWA_PROCESS, dtWait, Res, PPID, LastExecRes.PID);
+    if RC = 0 then
+(* If we succeeded, the process is finished - possible future querying
+   of DosExitCode shall return the result immediately as with synchronous
+   execution. *)
+     begin
+      LastExecFlags := deSync;
+      LastExecRes := Res;
+     end
+    else
+     LastExecRes.ExitCode := RC shl 16;
+   end;
+  if LastExecRes.ExitCode > high (word) then
+    DosExitCode := high (word)
+  else
+    DosExitCode := LastExecRes.ExitCode and $FFFF;
+end;
+
+
 procedure Exec (const Path: PathStr; const ComLine: ComStr);
 {Execute a program.}
 var
   Args0, Args: PByteArray;
   ArgSize: word;
-  Res: TResultCodes;
   ObjName: string;
+  Res: TResultCodes;
   RC: cardinal;
   ExecAppType: cardinal;
   HQ: THandle;
@@ -186,7 +223,7 @@ begin
     GetMem (Args0, MaxArgsSize);
     Args := Args0;
 (* Work around a bug in OS/2 - argument to DosExecPgm *)
-(* should not cross 64K boundary. *)
+(* should not cross a 64K boundary. *)
     if ((PtrUInt (Args) + 1024) and $FFFF) < 1024 then
      Inc (pointer (Args), 1024);
     ArgSize := 0;
@@ -211,7 +248,8 @@ begin
     RC := DosExecPgm (ObjName, cardinal (ExecFlags), Args, nil, Res, Path);
     if RC = 0 then
      begin
-      LastDosExitCode := Res.ExitCode;
+      LastExecFlags := ExecFlags;
+      LastExecRes := Res;
       LastDosErrorModuleName := '';
      end
     else
@@ -222,55 +260,90 @@ begin
    DSS := true;
   if DSS then
    begin
-    FillChar (SD, SizeOf (SD), 0);
-    SD.Length := SizeOf (SD);
-    SD.Related := ssf_Related_Child;
-    if Args = nil then
-(* No parameters passed, Args not allocated for DosExecPgm, so allocate now. *)
-     begin
-      GetMem (Args0, MaxArgsSize);
-      Args := Args0;
-      Move (QName [1], Args^ [0], Length (QName));
-      Args^ [Length (QName)] := 0;
-     end
-    else
-     SD.PgmInputs := PChar (@Args^ [Length (QName) + 1]);
-    SD.PgmName := PChar (Args);
-    SD.InheritOpt := ssf_InhertOpt_Parent;
     Str (GetProcessID, SPID);
     Str (ThreadID, STID);
-    Str (ExecCounter, SCtr);
-    Inc (ExecCounter);
     QName := '\QUEUES\FPC_Dos_Exec_p' + SPID + 't' + STID + '.QUE'#0;
-    SD.TermQ := @QName [1];
-    SD.ObjectBuffer := @ObjName [1];
-    SD.ObjectBuffLen := SizeOf (ObjName) - 1;
-    RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
+    FillChar (SD, SizeOf (SD), 0);
+    SD.Length := SizeOf (SD);
+    RC := 0;
+    case ExecFlags of
+     deSync:
+      begin
+       SD.Related := ssf_Related_Child;
+       LastExecFlags := ExecFlags;
+       SD.TermQ := @QName [1];
+       RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
+      end;
+     deAsync,
+     deAsyncResult:
+      begin
+(* Current implementation of DosExitCode does not support retrieval *)
+(* of result codes for other session types started asynchronously.  *)
+       LastExecFlags := deAsync;
+       SD.Related := ssf_Related_Independent;
+      end;
+     deBackground:
+      begin
+(* Current implementation of DosExitCode does not support retrieval *)
+(* of result codes for other session types started asynchronously.  *)
+       LastExecFlags := ExecFlags;
+       SD.Related := ssf_Related_Independent;
+       SD.FgBg := ssf_FgBg_Back;
+      end;
+     deAsyncResultDB:
+      begin
+(* Current implementation of DosExitCode does not support retrieval *)
+(* of result codes for other session types started asynchronously.  *)
+       LastExecFlags := ExecFlags;
+       SD.Related := ssf_Related_Child;
+       SD.TraceOpt := ssf_TraceOpt_Trace;
+      end;
+    end;
     if RC <> 0 then
      ObjName := Copy (QName, 1, Pred (Length (QName)))
     else
      begin
+      if Args = nil then
+(* No parameters passed, Args not allocated for DosExecPgm, so allocate now. *)
+       begin
+        GetMem (Args0, MaxArgsSize);
+        Args := Args0;
+        Move (QName [1], Args^ [0], Length (QName));
+        Args^ [Length (QName)] := 0;
+       end
+      else
+       SD.PgmInputs := PChar (@Args^ [Length (QName) + 1]);
+      SD.PgmName := PChar (Args);
+      SD.InheritOpt := ssf_InhertOpt_Parent;
+      SD.ObjectBuffer := @ObjName [1];
+      SD.ObjectBuffLen := SizeOf (ObjName) - 1;
       RC := DosStartSession (SD, SID, PID);
       if (RC = 0) or (RC = 457) then
        begin
-        RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
-        if RC = 0 then
+        LastExecRes.PID := PID;
+        if ExecFlags = deSync then
          begin
-          LastDosExitCode := PCI^.Return;
-          DosCloseQueue (HQ);
-          DosFreeMem (PCI);
-         end
-        else
-         DosCloseQueue (HQ);
+          RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
+          if (RC = 0) and (PCI^.SessionID = SID) then
+           begin
+            LastExecRes.ExitCode := PCI^.Return;
+            DosCloseQueue (HQ);
+            DosFreeMem (PCI);
+           end
+          else
+           DosCloseQueue (HQ);
+         end;
        end
-      else
+      else if ExecFlags = deSync then
        DosCloseQueue (HQ);
      end;
    end;
   if RC <> 0 then
    begin
     LastDosErrorModuleName := ObjName;
-    LastDosExitCode := 0; (* Needed for TP/BP compatibility *)
+    LastExecFlags := deSync;
+    LastExecRes.ExitCode := 0; (* Needed for TP/BP compatibility *)
+    LastExecRes.TerminateReason := $FFFFFFFF;
    end;
   DosError := RC;
   if Args0 <> nil then
@@ -561,8 +634,8 @@ begin
 
 
 begin
- LastDosExitCode := 0;
+ FillChar (LastExecRes, SizeOf (LastExecRes), 0);
  LastDosErrorModuleName := '';
  ExecFlags := 0;
- ExecCounter := 0;
+ LastExecFlags := deSync;
 end.