11submodule (stdlib_system) stdlib_system_subprocess
22 use iso_c_binding
33 use iso_fortran_env, only: int64, real64
4- use stdlib_system
54 use stdlib_strings, only: to_c_string, join
65 use stdlib_linalg_state, only: linalg_state_type, LINALG_ERROR, linalg_error_handling
76 implicit none (type, external )
@@ -85,7 +84,7 @@ module subroutine sleep(millisec)
8584
8685 end subroutine sleep
8786
88- module function run_async_cmd (cmd , stdin , want_stdout , want_stderr ) result(process)
87+ module function run_async_cmd (cmd , stdin , want_stdout , want_stderr , callback , payload ) result(process)
8988 ! > The command line string to execute.
9089 character (* ), intent (in ) :: cmd
9190 ! > Optional input sent to the process via standard input (stdin).
@@ -94,14 +93,18 @@ module function run_async_cmd(cmd, stdin, want_stdout, want_stderr) result(proce
9493 logical , optional , intent (in ) :: want_stdout
9594 ! > Whether to collect standard error output.
9695 logical , optional , intent (in ) :: want_stderr
96+ ! > Optional callback function to be called on process completion
97+ procedure (process_callback), optional :: callback
98+ ! > Optional payload to pass to the callback on completion
99+ class(* ), optional , intent (inout ), target :: payload
97100 ! > The output process handler.
98101 type (process_type) :: process
99102
100- process = process_open([cmd],.false. ,stdin,want_stdout,want_stderr)
103+ process = process_open([cmd],.false. ,stdin,want_stdout,want_stderr,callback,payload )
101104
102105 end function run_async_cmd
103106
104- module function run_async_args (args , stdin , want_stdout , want_stderr ) result(process)
107+ module function run_async_args (args , stdin , want_stdout , want_stderr , callback , payload ) result(process)
105108 ! > List of arguments for the process to execute.
106109 character (* ), intent (in ) :: args(:)
107110 ! > Optional input sent to the process via standard input (stdin).
@@ -110,14 +113,18 @@ module function run_async_args(args, stdin, want_stdout, want_stderr) result(pro
110113 logical , optional , intent (in ) :: want_stdout
111114 ! > Whether to collect standard error output.
112115 logical , optional , intent (in ) :: want_stderr
116+ ! > Optional callback function to be called on process completion
117+ procedure (process_callback), optional :: callback
118+ ! > Optional payload to pass to the callback on completion
119+ class(* ), optional , intent (inout ), target :: payload
113120 ! > The output process handler.
114121 type (process_type) :: process
115122
116- process = process_open(args,.false. ,stdin,want_stdout,want_stderr)
123+ process = process_open(args,.false. ,stdin,want_stdout,want_stderr,callback,payload )
117124
118125 end function run_async_args
119126
120- module function run_sync_cmd (cmd , stdin , want_stdout , want_stderr ) result(process)
127+ module function run_sync_cmd (cmd , stdin , want_stdout , want_stderr , callback , payload ) result(process)
121128 ! > The command line string to execute.
122129 character (* ), intent (in ) :: cmd
123130 ! > Optional input sent to the process via standard input (stdin).
@@ -126,14 +133,18 @@ module function run_sync_cmd(cmd, stdin, want_stdout, want_stderr) result(proces
126133 logical , optional , intent (in ) :: want_stdout
127134 ! > Whether to collect standard error output.
128135 logical , optional , intent (in ) :: want_stderr
136+ ! > Optional callback function to be called on process completion
137+ procedure (process_callback), optional :: callback
138+ ! > Optional payload to pass to the callback on completion
139+ class(* ), optional , intent (inout ), target :: payload
129140 ! > The output process handler.
130141 type (process_type) :: process
131142
132- process = process_open([cmd],.true. ,stdin,want_stdout,want_stderr)
143+ process = process_open([cmd],.true. ,stdin,want_stdout,want_stderr,callback,payload )
133144
134145 end function run_sync_cmd
135146
136- module function run_sync_args (args , stdin , want_stdout , want_stderr ) result(process)
147+ module function run_sync_args (args , stdin , want_stdout , want_stderr , callback , payload ) result(process)
137148 ! > List of arguments for the process to execute.
138149 character (* ), intent (in ) :: args(:)
139150 ! > Optional input sent to the process via standard input (stdin).
@@ -142,15 +153,19 @@ module function run_sync_args(args, stdin, want_stdout, want_stderr) result(proc
142153 logical , optional , intent (in ) :: want_stdout
143154 ! > Whether to collect standard error output.
144155 logical , optional , intent (in ) :: want_stderr
156+ ! > Optional callback function to be called on process completion
157+ procedure (process_callback), optional :: callback
158+ ! > Optional payload to pass to the callback on completion
159+ class(* ), optional , intent (inout ), target :: payload
145160 ! > The output process handler.
146161 type (process_type) :: process
147162
148- process = process_open(args,.true. ,stdin,want_stdout,want_stderr)
163+ process = process_open(args,.true. ,stdin,want_stdout,want_stderr,callback,payload )
149164
150165 end function run_sync_args
151166
152167 ! > Internal function: open a new process from a command line
153- function process_open_cmd (cmd ,wait ,stdin ,want_stdout ,want_stderr ) result(process)
168+ function process_open_cmd (cmd ,wait ,stdin ,want_stdout ,want_stderr , callback , payload ) result(process)
154169 ! > The command and arguments
155170 character (* ), intent (in ) :: cmd
156171 ! > Optional character input to be sent to the process via pipe
@@ -159,15 +174,19 @@ function process_open_cmd(cmd,wait,stdin,want_stdout,want_stderr) result(process
159174 logical , intent (in ) :: wait
160175 ! > Require collecting output
161176 logical , optional , intent (in ) :: want_stdout, want_stderr
177+ ! > Optional callback function to be called on process completion
178+ procedure (process_callback), optional :: callback
179+ ! > Optional payload to pass to the callback on completion
180+ class(* ), optional , intent (inout ), target :: payload
162181 ! > The output process handler
163182 type (process_type) :: process
164183
165- process = process_open([cmd],wait,stdin,want_stdout,want_stderr)
184+ process = process_open([cmd],wait,stdin,want_stdout,want_stderr,callback,payload )
166185
167186 end function process_open_cmd
168187
169188 ! > Internal function: open a new process from arguments
170- function process_open (args ,wait ,stdin ,want_stdout ,want_stderr ) result(process)
189+ function process_open (args ,wait ,stdin ,want_stdout ,want_stderr , callback , payload ) result(process)
171190 ! > The command and arguments
172191 character (* ), intent (in ) :: args(:)
173192 ! > Optional character input to be sent to the process via pipe
@@ -176,6 +195,10 @@ function process_open(args,wait,stdin,want_stdout,want_stderr) result(process)
176195 logical , intent (in ) :: wait
177196 ! > Require collecting output
178197 logical , optional , intent (in ) :: want_stdout, want_stderr
198+ ! > Optional callback function to be called on process completion
199+ procedure (process_callback), optional :: callback
200+ ! > Optional payload to pass to the callback on completion
201+ class(* ), optional , intent (inout ), target :: payload
179202 ! > The output process handler
180203 type (process_type) :: process
181204
@@ -197,6 +220,19 @@ function process_open(args,wait,stdin,want_stdout,want_stderr) result(process)
197220 if (collect_stdout) process% stdout_file = scratch_name(' out' )
198221 if (collect_stderr) process% stderr_file = scratch_name(' err' )
199222
223+ ! Attach callback function and payload
224+ if (present (callback)) then
225+ process% oncomplete = > callback
226+ else
227+ nullify(process% oncomplete)
228+ end if
229+
230+ if (present (payload)) then
231+ process% payload = > payload
232+ else
233+ nullify(process% payload)
234+ end if
235+
200236 ! Save the process's generation time
201237 call system_clock (process% start_time,count_rate,count_max)
202238 process% last_update = process% start_time
@@ -452,23 +488,33 @@ subroutine save_completed_state(process,delete_files)
452488 ! Clean up process state using waitpid
453489 if (process% id/= FORKED_PROCESS) call process_query_status(process% id, C_TRUE, running, exit_code)
454490
455- ! Process is over: load stdout/ stderr if requested
491+ ! Process is over: load stderr if requested
456492 if (allocated (process% stderr_file)) then
457493 process% stderr = getfile(process% stderr_file,delete= delete_files)
458494 deallocate (process% stderr_file)
459495 endif
460496
497+ ! Process is over: load stdout if requested
461498 if (allocated (process% stdout_file)) then
462499 process% stdout = getfile(process% stdout_file,delete= delete_files)
463500 deallocate (process% stdout_file)
464501 endif
465502
503+ ! Process is over: delete stdin file if it was provided
466504 if (allocated (process% stdin_file)) then
467- open (newunit= delete,file= process% stdin_file,access= ' stream' ,action= ' write' )
468- close (delete,status= ' delete' )
505+ process% stdin = getfile(process% stdin_file,delete= delete_files)
469506 deallocate (process% stdin_file)
470507 end if
471508
509+ ! Process is over: invoke callback if requested
510+ if (associated (process% oncomplete)) &
511+ call process% oncomplete(process% id, &
512+ process% exit_code, &
513+ process% stderr, &
514+ process% stdout, &
515+ process% stderr, &
516+ process% payload)
517+
472518 end subroutine save_completed_state
473519
474520 ! > Live check if a process is running
0 commit comments