1
1
submodule (stdlib_system) stdlib_system_subprocess
2
2
use iso_c_binding
3
3
use iso_fortran_env, only: int64, real64
4
- use stdlib_system
5
4
use stdlib_strings, only: to_c_string, join
6
5
use stdlib_linalg_state, only: linalg_state_type, LINALG_ERROR, linalg_error_handling
7
6
implicit none (type, external )
@@ -85,7 +84,7 @@ module subroutine sleep(millisec)
85
84
86
85
end subroutine sleep
87
86
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)
89
88
! > The command line string to execute.
90
89
character (* ), intent (in ) :: cmd
91
90
! > 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
94
93
logical , optional , intent (in ) :: want_stdout
95
94
! > Whether to collect standard error output.
96
95
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
97
100
! > The output process handler.
98
101
type (process_type) :: process
99
102
100
- process = process_open([cmd],.false. ,stdin,want_stdout,want_stderr)
103
+ process = process_open([cmd],.false. ,stdin,want_stdout,want_stderr,callback,payload )
101
104
102
105
end function run_async_cmd
103
106
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)
105
108
! > List of arguments for the process to execute.
106
109
character (* ), intent (in ) :: args(:)
107
110
! > 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
110
113
logical , optional , intent (in ) :: want_stdout
111
114
! > Whether to collect standard error output.
112
115
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
113
120
! > The output process handler.
114
121
type (process_type) :: process
115
122
116
- process = process_open(args,.false. ,stdin,want_stdout,want_stderr)
123
+ process = process_open(args,.false. ,stdin,want_stdout,want_stderr,callback,payload )
117
124
118
125
end function run_async_args
119
126
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)
121
128
! > The command line string to execute.
122
129
character (* ), intent (in ) :: cmd
123
130
! > 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
126
133
logical , optional , intent (in ) :: want_stdout
127
134
! > Whether to collect standard error output.
128
135
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
129
140
! > The output process handler.
130
141
type (process_type) :: process
131
142
132
- process = process_open([cmd],.true. ,stdin,want_stdout,want_stderr)
143
+ process = process_open([cmd],.true. ,stdin,want_stdout,want_stderr,callback,payload )
133
144
134
145
end function run_sync_cmd
135
146
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)
137
148
! > List of arguments for the process to execute.
138
149
character (* ), intent (in ) :: args(:)
139
150
! > 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
142
153
logical , optional , intent (in ) :: want_stdout
143
154
! > Whether to collect standard error output.
144
155
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
145
160
! > The output process handler.
146
161
type (process_type) :: process
147
162
148
- process = process_open(args,.true. ,stdin,want_stdout,want_stderr)
163
+ process = process_open(args,.true. ,stdin,want_stdout,want_stderr,callback,payload )
149
164
150
165
end function run_sync_args
151
166
152
167
! > 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)
154
169
! > The command and arguments
155
170
character (* ), intent (in ) :: cmd
156
171
! > 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
159
174
logical , intent (in ) :: wait
160
175
! > Require collecting output
161
176
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
162
181
! > The output process handler
163
182
type (process_type) :: process
164
183
165
- process = process_open([cmd],wait,stdin,want_stdout,want_stderr)
184
+ process = process_open([cmd],wait,stdin,want_stdout,want_stderr,callback,payload )
166
185
167
186
end function process_open_cmd
168
187
169
188
! > 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)
171
190
! > The command and arguments
172
191
character (* ), intent (in ) :: args(:)
173
192
! > 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)
176
195
logical , intent (in ) :: wait
177
196
! > Require collecting output
178
197
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
179
202
! > The output process handler
180
203
type (process_type) :: process
181
204
@@ -197,6 +220,19 @@ function process_open(args,wait,stdin,want_stdout,want_stderr) result(process)
197
220
if (collect_stdout) process% stdout_file = scratch_name(' out' )
198
221
if (collect_stderr) process% stderr_file = scratch_name(' err' )
199
222
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
+
200
236
! Save the process's generation time
201
237
call system_clock (process% start_time,count_rate,count_max)
202
238
process% last_update = process% start_time
@@ -452,23 +488,33 @@ subroutine save_completed_state(process,delete_files)
452
488
! Clean up process state using waitpid
453
489
if (process% id/= FORKED_PROCESS) call process_query_status(process% id, C_TRUE, running, exit_code)
454
490
455
- ! Process is over: load stdout/ stderr if requested
491
+ ! Process is over: load stderr if requested
456
492
if (allocated (process% stderr_file)) then
457
493
process% stderr = getfile(process% stderr_file,delete= delete_files)
458
494
deallocate (process% stderr_file)
459
495
endif
460
496
497
+ ! Process is over: load stdout if requested
461
498
if (allocated (process% stdout_file)) then
462
499
process% stdout = getfile(process% stdout_file,delete= delete_files)
463
500
deallocate (process% stdout_file)
464
501
endif
465
502
503
+ ! Process is over: delete stdin file if it was provided
466
504
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)
469
506
deallocate (process% stdin_file)
470
507
end if
471
508
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
+
472
518
end subroutine save_completed_state
473
519
474
520
! > Live check if a process is running
0 commit comments