Free Pascal > Unix

Why TProcess gives deadlock, whereas the same thing can be run in the terminal ?

(1/2) > >>

comingnine:
I would like to use TProcess to run a simple series of shell commands and collect the tiny amount of output.

As can be shown from ~/test.sh or ~/test_oneline.sh, this series of commands start script1 and then look for script2, and reports script2's PID and stops when script2 is found.

Both script file runs well in the terminal. However, when using with TProcess as shown below, the executable hangs for ever, indicating certain deadlock. However, the output is really small and the output pipe should not be full. I am really lost about the reason why the deadlock occurs here... Can you help me to solve this problem ? Many thanks ! :)


--- Code: Bash  window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---[vagrant@localhost ~]$ ps aux | grep [^]]script[vagrant@localhost ~]$ ps aux | grep [^]]sleep[vagrant@localhost ~]$ cat ~/script1#!/bin/bash -xsleep 20~/script2 [vagrant@localhost ~]$ cat ~/script2#!/bin/bash -xsleep 4320[vagrant@localhost ~]$ cat ~/test.sh#!/bin/bash -x nohup ~/script1 & bg_id=$!disown -awhile true ; do   if ! ps -p $bg_id > /dev/null 2>&1 ; then     echo "script1 terminated"    break  fi  str=$(ps aux | grep [^]]script2)  BashRegex='^[[:alnum:]_]+\s+([[:alnum:]_]+)'  if [[ $str =~ $BashRegex ]] ; then     for (( i=1 ; i<${#BASH_REMATCH[@]} ; i++)) ; do       echo ${BASH_REMATCH[$i]}    done    break  else     sleep 5  fidone[vagrant@localhost ~]$ cat ~/test_oneline.sh#!/bin/bash -xnohup ~/script1 & bg_id=$! ; disown -a ; while true ; do if ! ps -p $bg_id > /dev/null 2>&1 ; then echo "script1 terminated" ; break; fi ; str=$(ps aux | grep [^]]script2) ; BashRegex='^[[:alnum:]_]+\s+([[:alnum:]_]+)' ; if [[ $str =~ $BashRegex ]] ; then for (( i=1 ; i<${#BASH_REMATCH[@]} ; i++)) ; do echo ${BASH_REMATCH[$i]} ; done ; break ; else sleep 5 ; fi ; done[vagrant@localhost ~]$  


--- Code: Pascal  window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---program test_freepascal;{$IFDEF FPC} {$MODE Delphi} {$ELSE} {$APPTYPE CONSOLE} {$ENDIF}uses SysUtils, Classes, Process; procedure Test_TProcess_Executable_parameters; // http://wiki.freepascal.org/Executing_External_Programs#Reading_large_outputconst BUF_SIZE = 2048; // Buffer size for reading the output in chunksvar  Proc: TProcess;  OutStream, ErrStream: TStream;  OutLines, ErrLines: TStrings;  BytesRead: LongInt;  Buffer: array[1..BUF_SIZE] of Byte;begin  Proc := TProcess.Create(nil);  try    Proc.Executable := '/bin/bash';    Proc.Parameters.Add('-c');    Proc.Parameters.Add('nohup ~/script1 & bg_id=$! ; disown -a ; while true ; do if ! ps -p $bg_id > /dev/null 2>&1 ; then echo "script1 terminated" ; break; fi ; str=$(ps aux | grep [^]]script2) ; BashRegex=''^[[:alnum:]_]+\s+([[:alnum:]_]+)'' ; if [[ $str =~ $BashRegex ]] ; then for (( i=1 ; i<${#BASH_REMATCH[@]} ; i++)) ; do echo ${BASH_REMATCH[$i]} ; done ; break ; else sleep 5 ; fi ; done');    //Proc.Options := [poUsePipes, poWaitOnExit]; // Does not work...    Proc.Options := [poUsePipes]; // Does not work...    Proc.Execute;     OutStream := nil; ErrStream := nil; OutLines := nil; ErrLines := nil;    try      OutStream := TMemoryStream.Create; ErrStream := TMemoryStream.Create; OutLines := TStringList.Create; ErrLines := TStringList.Create;       repeat        BytesRead := Proc.Output.Read(Buffer, BUF_SIZE);        OutStream.Write(Buffer, BytesRead)      until BytesRead = 0;      OutStream.Position := 0;      OutLines.LoadFromStream(OutStream);       repeat        BytesRead := Proc.StdErr.Read(Buffer, BUF_SIZE);        ErrStream.Write(Buffer, BytesRead)      until BytesRead = 0;      ErrStream.Position := 0;      ErrLines.LoadFromStream(ErrStream);       Writeln('##### Out #####' + sLineBreak + OutLines.Text + sLineBreak + '##### Err #####' + sLineBreak + ErrLines.Text);    finally      OutStream.Free; ErrStream.Free; OutLines.Free; ErrLines.Free;    end;   finally    Proc.Free;  end;end; begin  Test_TProcess_Executable_parameters;end. 

tudi_x:
for mere mortals would you mind uploading the two script files and the app folder.
i think i have a mint box.

comingnine:
Many thanks for your efforts !
The binary file is rather large and could not be uploaded as attachment.
The two script and the .lpr/.lpi files are attached.   :)

tudi_x:
i would place the code in the scripts instead of TProcess parameters.
cat ~/test.sh in your initial post gives a lot of content whereas the scripts you loaded are very few lines.

if you have several commands maybe loop them in a TProcess execution for each.

comingnine:
As shown in the .lpr content below, the RunCommand version works as expected.   :)
However, it seems that RunCommand can only provide merged StdOut & StdErr, and I would like to retrieve StdErr content separately to see more clearly if something goes wrong.

There must be some root difference between RunCommand internal and the wiki usage of TProcess. Your insights will be appreciated very much  :o


--- Code: Pascal  window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---program test_freepascal_runcommand;{$IFDEF FPC} {$MODE Delphi} {$ELSE} {$APPTYPE CONSOLE} {$ENDIF}uses SysUtils, Classes, Process; // http://wiki.freepascal.org/Executing_External_Programs// http://forum.lazarus.freepascal.org/index.php/topic,38398.0.htmlprocedure Test_RunCommand;var  Output: string;begin  RunCommand(    '/bin/bash',    ['-c',     'nohup ~/script1 & bg_id=$! ; disown -a ; while true ; do if ! ps -p $bg_id > /dev/null 2>&1 ; then echo "script1 terminated" ; break; fi ; str=$(ps aux | grep [^]]script2) ; BashRegex=''^[[:alnum:]_]+\s+([[:alnum:]_]+)'' ; if [[ $str =~ $BashRegex ]] ; then for (( i=1 ; i<${#BASH_REMATCH[@]} ; i++)) ; do echo ${BASH_REMATCH[$i]} ; done ; break ; else sleep 5 ; fi ; done'    ],    Output,    []  );  Writeln(Output);end; begin  Test_RunCommand;end.   

Navigation

[0] Message Index

[#] Next page

Go to full version