[PB 6.30b5] ProgramExitCode() seemingly fails -1 randomly
Posted: Fri Dec 12, 2025 2:32 pm
I can reproduce this in PB6.20 and PB6.30 beta on Xubuntu18.04, Arch and Debian 12/13
The ProgramExitCode() function returns -1 at random, the shell program executes correctly, both stderr and stdout appear to be captured correctly however ProgramExitCode() throws a -1 at the exit code randomly, this has been driving me mad for a week until I realised it was a random occurrence
Sometimes it takes a few attempts to trigger it, some times thousands of attempts, it happens with any command, the example belows uses the ls and the route command the problem can happen after a few runs or after many thousands of rounds.
If someone else could please validate this and confirm it would be great.
The ProgramExitCode() function returns -1 at random, the shell program executes correctly, both stderr and stdout appear to be captured correctly however ProgramExitCode() throws a -1 at the exit code randomly, this has been driving me mad for a week until I realised it was a random occurrence
Sometimes it takes a few attempts to trigger it, some times thousands of attempts, it happens with any command, the example belows uses the ls and the route command the problem can happen after a few runs or after many thousands of rounds.
If someone else could please validate this and confirm it would be great.
Code: Select all
EnableExplicit
OpenConsole()
; Shell output
Structure uds_shell_output
List lst_std_output.s()
List lst_err_output.s()
EndStructure
; Just prints out a list to the console
; Permits prefix and suffixes to the output
Procedure.i ListPrint(List lst_lines.s(), str_prefix.s = "", str_suffix.s = "")
ForEach lst_lines()
PrintN(str_prefix + lst_lines() + str_suffix)
Next
ProcedureReturn #True
EndProcedure
; Runs a program and captures its output in a list
; asyncronously waiting for the program to finish on its own
; the program's exit code is returned by the function return
; value
Procedure.i get_RunOutputSync(str_program.s, str_parameters.s, *udt_shell_output.uds_shell_output)
Protected int_pbprocessid.i = 0
Protected int_exitcode.i = 0
Protected int_result.i = 0
Protected str_stdout.s = ""
Protected str_stderr.s = ""
; Cleanup the output lists if they contain any data
If ListSize(*udt_shell_output\lst_std_output())
ClearList(*udt_shell_output\lst_std_output())
EndIf
If ListSize(*udt_shell_output\lst_err_output())
ClearList(*udt_shell_output\lst_err_output())
EndIf
int_pbprocessid = RunProgram(str_program, str_parameters, "", #PB_Program_Open | #PB_Program_Read | #PB_Program_Error | #PB_Program_UTF8)
If int_pbprocessid < 0
PrintN("Peeky PID: " + int_pbprocessid) ; DEBUG DEBUG DEBUG
EndIf
If int_pbprocessid
While ProgramRunning(int_pbprocessid)
; stderr has to be read first or it will fail
str_stderr = ReadProgramError(int_pbprocessid)
If str_stderr
AddElement(*udt_shell_output\lst_err_output())
*udt_shell_output\lst_err_output() + str_stderr
EndIf
If AvailableProgramOutput(int_pbprocessid)
str_stdout = ReadProgramString(int_pbprocessid)
If str_stdout
AddElement(*udt_shell_output\lst_std_output())
*udt_shell_output\lst_std_output() = str_stdout
EndIf
EndIf
Wend
int_result = WaitProgram(int_pbprocessid, 30000) ; 30s
If int_result
int_exitcode = ProgramExitCode(int_pbprocessid)
PrintN("Peeky exit code2: " + int_exitcode)
If int_pbprocessid < 0
PrintN("Peeky exit code1: " + int_exitcode) ; DEBUG DEBUG DEBUG
EndIf
Else
; Timeout
int_exitcode = -2000
EndIf
CloseProgram(int_pbprocessid) ; Close the connection to the program
Else
; If we can't run the program
int_exitcode = -1000
EndIf
ListPrint(*udt_shell_output\lst_std_output(), "std: ")
ListPrint(*udt_shell_output\lst_err_output(), "stderr: ")
; We return the program exit code we use values >= 1000 to be 100% sure the errors are ours
ProcedureReturn int_exitcode
EndProcedure
Define udt_route_output.uds_shell_output
Define int_return_code.i = 0
Define qua_counter.q = 0
Define str_error.s = ""
Repeat
qua_counter + 1
PrintN("Run: " + StrD(qua_counter))
; Run the command
;int_return_code = get_RunOutputSync("ls", "-l /etc", @udt_route_output)
int_return_code = get_RunOutputSync("route", "-n", @udt_route_output)
; If error code
If int_return_code
Select int_return_code
Case -1000
str_error = "ERROR: Command not available aborting."
Break
Case -2000
str_error = "ERROR: Command timed out on execution."
Break
Default
str_error = "ERROR: Cmmand returned non 0 error code: " + Str(int_return_code) + " aborting."
Break
EndSelect
EndIf
ForEver
CompilerIf #PB_Compiler_Debugger
PrintN(Chr(10) + Chr(10) + "--- Program ended, Press esc to exit ---")
Define str_keypress.s = ""
Repeat
Delay(20)
str_keypress = Inkey()
Until str_keypress = Chr(27)
CompilerEndIf