143bfc0395
Let the caller decide if stdout and stderr must be inherited on process creation, i.e. if stdout and stderr of the child process should be printed in the scrcpy console. This allows to get output and errors for specific adb commands depending on the context.
122 lines
3.2 KiB
C
122 lines
3.2 KiB
C
#include "process.h"
|
|
|
|
#include <assert.h>
|
|
#include <libgen.h>
|
|
#include "log.h"
|
|
|
|
enum sc_process_result
|
|
sc_process_execute(const char *const argv[], sc_pid *pid, unsigned inherit) {
|
|
return sc_process_execute_p(argv, pid, inherit, NULL, NULL, NULL);
|
|
}
|
|
|
|
bool
|
|
sc_process_check_success(sc_pid pid, const char *name, bool close) {
|
|
if (pid == SC_PROCESS_NONE) {
|
|
LOGE("Could not execute \"%s\"", name);
|
|
return false;
|
|
}
|
|
sc_exit_code exit_code = sc_process_wait(pid, close);
|
|
if (exit_code) {
|
|
if (exit_code != SC_EXIT_CODE_NONE) {
|
|
LOGE("\"%s\" returned with value %" SC_PRIexitcode, name,
|
|
exit_code);
|
|
} else {
|
|
LOGE("\"%s\" exited unexpectedly", name);
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
ssize_t
|
|
sc_pipe_read_all(sc_pipe pipe, char *data, size_t len) {
|
|
size_t copied = 0;
|
|
while (len > 0) {
|
|
ssize_t r = sc_pipe_read(pipe, data, len);
|
|
if (r <= 0) {
|
|
return copied ? (ssize_t) copied : r;
|
|
}
|
|
len -= r;
|
|
data += r;
|
|
copied += r;
|
|
}
|
|
return copied;
|
|
}
|
|
|
|
static int
|
|
run_observer(void *data) {
|
|
struct sc_process_observer *observer = data;
|
|
sc_process_wait(observer->pid, false); // ignore exit code
|
|
|
|
sc_mutex_lock(&observer->mutex);
|
|
observer->terminated = true;
|
|
sc_cond_signal(&observer->cond_terminated);
|
|
sc_mutex_unlock(&observer->mutex);
|
|
|
|
if (observer->listener) {
|
|
observer->listener->on_terminated(observer->listener_userdata);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
sc_process_observer_init(struct sc_process_observer *observer, sc_pid pid,
|
|
const struct sc_process_listener *listener,
|
|
void *listener_userdata) {
|
|
// Either no listener, or on_terminated() is defined
|
|
assert(!listener || listener->on_terminated);
|
|
|
|
bool ok = sc_mutex_init(&observer->mutex);
|
|
if (!ok) {
|
|
return false;
|
|
}
|
|
|
|
ok = sc_cond_init(&observer->cond_terminated);
|
|
if (!ok) {
|
|
sc_mutex_destroy(&observer->mutex);
|
|
return false;
|
|
}
|
|
|
|
observer->pid = pid;
|
|
observer->listener = listener;
|
|
observer->listener_userdata = listener_userdata;
|
|
observer->terminated = false;
|
|
|
|
ok = sc_thread_create(&observer->thread, run_observer, "process_observer",
|
|
observer);
|
|
if (!ok) {
|
|
sc_cond_destroy(&observer->cond_terminated);
|
|
sc_mutex_destroy(&observer->mutex);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
sc_process_observer_timedwait(struct sc_process_observer *observer,
|
|
sc_tick deadline) {
|
|
sc_mutex_lock(&observer->mutex);
|
|
bool timed_out = false;
|
|
while (!observer->terminated && !timed_out) {
|
|
timed_out = !sc_cond_timedwait(&observer->cond_terminated,
|
|
&observer->mutex, deadline);
|
|
}
|
|
bool terminated = observer->terminated;
|
|
sc_mutex_unlock(&observer->mutex);
|
|
|
|
return terminated;
|
|
}
|
|
|
|
void
|
|
sc_process_observer_join(struct sc_process_observer *observer) {
|
|
sc_thread_join(&observer->thread, NULL);
|
|
}
|
|
|
|
void
|
|
sc_process_observer_destroy(struct sc_process_observer *observer) {
|
|
sc_cond_destroy(&observer->cond_terminated);
|
|
sc_mutex_destroy(&observer->mutex);
|
|
}
|