mirror of
https://github.com/Genymobile/scrcpy
synced 2025-01-03 13:12:06 +00:00
f801d8b312
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. PR #2827 <https://github.com/Genymobile/scrcpy/pull/2827>
181 lines
4.3 KiB
C
181 lines
4.3 KiB
C
#ifndef SC_PROCESS_H
|
|
#define SC_PROCESS_H
|
|
|
|
#include "common.h"
|
|
|
|
#include <stdbool.h>
|
|
#include "util/thread.h"
|
|
|
|
#ifdef _WIN32
|
|
|
|
// not needed here, but winsock2.h must never be included AFTER windows.h
|
|
# include <winsock2.h>
|
|
# include <windows.h>
|
|
# define SC_PRIexitcode "lu"
|
|
// <https://stackoverflow.com/a/44383330/1987178>
|
|
# define SC_PRIsizet "Iu"
|
|
# define SC_PROCESS_NONE NULL
|
|
# define SC_EXIT_CODE_NONE -1u // max value as unsigned
|
|
typedef HANDLE sc_pid;
|
|
typedef DWORD sc_exit_code;
|
|
typedef HANDLE sc_pipe;
|
|
|
|
#else
|
|
|
|
# include <sys/types.h>
|
|
# define SC_PRIsizet "zu"
|
|
# define SC_PRIexitcode "d"
|
|
# define SC_PROCESS_NONE -1
|
|
# define SC_EXIT_CODE_NONE -1
|
|
typedef pid_t sc_pid;
|
|
typedef int sc_exit_code;
|
|
typedef int sc_pipe;
|
|
|
|
#endif
|
|
|
|
struct sc_process_listener {
|
|
void (*on_terminated)(void *userdata);
|
|
};
|
|
|
|
/**
|
|
* Tool to observe process termination
|
|
*
|
|
* To keep things simple and multiplatform, it runs a separate thread to wait
|
|
* for process termination (without closing the process to avoid race
|
|
* conditions).
|
|
*
|
|
* It allows a caller to block until the process is terminated (with a
|
|
* timeout), and to be notified asynchronously from the observer thread.
|
|
*
|
|
* The process is not owned by the observer (the observer will never close it).
|
|
*/
|
|
struct sc_process_observer {
|
|
sc_pid pid;
|
|
|
|
sc_mutex mutex;
|
|
sc_cond cond_terminated;
|
|
bool terminated;
|
|
|
|
sc_thread thread;
|
|
const struct sc_process_listener *listener;
|
|
void *listener_userdata;
|
|
};
|
|
|
|
enum sc_process_result {
|
|
SC_PROCESS_SUCCESS,
|
|
SC_PROCESS_ERROR_GENERIC,
|
|
SC_PROCESS_ERROR_MISSING_BINARY,
|
|
};
|
|
|
|
#define SC_PROCESS_NO_STDOUT (1 << 0)
|
|
#define SC_PROCESS_NO_STDERR (1 << 1)
|
|
|
|
/**
|
|
* Execute the command and write the process id to `pid`
|
|
*
|
|
* The `flags` argument is a bitwise OR of the following values:
|
|
* - SC_PROCESS_NO_STDOUT
|
|
* - SC_PROCESS_NO_STDERR
|
|
*
|
|
* It indicates if stdout and stderr must be inherited from the scrcpy process
|
|
* (i.e. if the process must output to the scrcpy console).
|
|
*/
|
|
enum sc_process_result
|
|
sc_process_execute(const char *const argv[], sc_pid *pid, unsigned flags);
|
|
|
|
/**
|
|
* Execute the command and write the process id to `pid`
|
|
*
|
|
* If not NULL, provide a pipe for stdin (`pin`), stdout (`pout`) and stderr
|
|
* (`perr`).
|
|
*
|
|
* The `flags` argument has the same semantics as in `sc_process_execute()`.
|
|
*/
|
|
enum sc_process_result
|
|
sc_process_execute_p(const char *const argv[], sc_pid *pid, unsigned flags,
|
|
sc_pipe *pin, sc_pipe *pout, sc_pipe *perr);
|
|
|
|
/**
|
|
* Kill the process
|
|
*/
|
|
bool
|
|
sc_process_terminate(sc_pid pid);
|
|
|
|
/**
|
|
* Wait and close the process (similar to waitpid())
|
|
*
|
|
* The `close` flag indicates if the process must be _closed_ (reaped) (passing
|
|
* false is equivalent to enable WNOWAIT in waitid()).
|
|
*/
|
|
sc_exit_code
|
|
sc_process_wait(sc_pid pid, bool close);
|
|
|
|
/**
|
|
* Close (reap) the process
|
|
*
|
|
* Semantically:
|
|
* sc_process_wait(close) = sc_process_wait(noclose) + sc_process_close()
|
|
*/
|
|
void
|
|
sc_process_close(sc_pid pid);
|
|
|
|
/**
|
|
* Read from the pipe
|
|
*
|
|
* Same semantic as read().
|
|
*/
|
|
ssize_t
|
|
sc_pipe_read(sc_pipe pipe, char *data, size_t len);
|
|
|
|
/**
|
|
* Read exactly `len` chars from a pipe (unless EOF)
|
|
*/
|
|
ssize_t
|
|
sc_pipe_read_all(sc_pipe pipe, char *data, size_t len);
|
|
|
|
/**
|
|
* Close the pipe
|
|
*/
|
|
void
|
|
sc_pipe_close(sc_pipe pipe);
|
|
|
|
/**
|
|
* Start observing process
|
|
*
|
|
* The listener is optional. If set, its callback will be called from the
|
|
* observer thread once the process is terminated.
|
|
*/
|
|
bool
|
|
sc_process_observer_init(struct sc_process_observer *observer, sc_pid pid,
|
|
const struct sc_process_listener *listener,
|
|
void *listener_userdata);
|
|
|
|
/**
|
|
* Wait for process termination until a deadline
|
|
*
|
|
* Return true if the process is already terminated. Return false if the
|
|
* process terminatation has not been detected yet (however, it may have
|
|
* terminated in the meantime).
|
|
*
|
|
* To wait without timeout/deadline, just use sc_process_wait() instead.
|
|
*/
|
|
bool
|
|
sc_process_observer_timedwait(struct sc_process_observer *observer,
|
|
sc_tick deadline);
|
|
|
|
/**
|
|
* Join the observer thread
|
|
*/
|
|
void
|
|
sc_process_observer_join(struct sc_process_observer *observer);
|
|
|
|
/**
|
|
* Destroy the observer
|
|
*
|
|
* This does not close the associated process.
|
|
*/
|
|
void
|
|
sc_process_observer_destroy(struct sc_process_observer *observer);
|
|
|
|
#endif
|