rktio: processes

This commit is contained in:
Matthew Flatt 2017-06-12 09:01:39 -06:00
parent 6c2f71bf80
commit 9e68886b26
9 changed files with 1751 additions and 15 deletions

View File

@ -13,6 +13,8 @@ OBJS = rktio_filesystem.o \
rktio_poll_set.o \
rktio_ltps.o \
rktio_network.o \
rktio_process.o \
rktio_envvars.o \
rktio_error.o \
rktio_main.o
@ -42,6 +44,12 @@ rktio_ltps.o: $(srcdir)/rktio_ltps.c $(RKTIO_HEADERS)
rktio_network.o: $(srcdir)/rktio_network.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_network.o -c $(srcdir)/rktio_network.c
rktio_process.o: $(srcdir)/rktio_process.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_process.o -c $(srcdir)/rktio_process.c
rktio_envvars.o: $(srcdir)/rktio_envvars.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_envvars.o -c $(srcdir)/rktio_envvars.c
rktio_error.o: $(srcdir)/rktio_error.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.o -c $(srcdir)/rktio_error.c

View File

@ -9,8 +9,9 @@ The library is meant to be
* always non-blocking;
* independent of global state (except on Windows, where internal
global state is managed appropriately with locks), so that it works
with or without threads; and
global state is managed appropriately with locks, and except for
Unix process handling without pthreads), so that it works with or
without threads; and
* easily callable though a FFI.

View File

@ -5,6 +5,8 @@
static void do_check_valid(rktio_t *rktio, int ok, int where)
{
/* Beware that a reported error is nonsense if the failure
was an unexpected result insteda of an error result. */
if (!ok) {
printf("error at %d: %d@%d = %s\n",
where,
@ -190,13 +192,12 @@ static void wait_read(rktio_t *rktio, rktio_fd_t *fd)
rktio_poll_set_close(rktio, ps);
}
static void check_read_write_pair(rktio_t *rktio, rktio_fd_t *fd, rktio_fd_t *fd2)
static void check_read_write_pair(rktio_t *rktio, rktio_fd_t *fd, rktio_fd_t *fd2, int immediate_available)
{
rktio_ltps_t *lt;
rktio_ltps_handle_t *h1, *h2;
intptr_t amt, i;
char buffer[256];
int immediate_available = (!rktio_fd_is_socket(rktio, fd) && !rktio_fd_is_socket(rktio, fd2));
lt = try_check_ltps(rktio, fd, fd2, &h1, &h2);
/* We expect `lt` to work everywhere exception Windows and with kqueue on non-sockets: */
@ -566,7 +567,7 @@ int main()
check_valid(fd2);
check_valid(!rktio_poll_read_ready(rktio, fd));
check_read_write_pair(rktio, fd, fd2);
check_read_write_pair(rktio, fd, fd2, 1);
/* Open pipe ends again: */
fd2 = rktio_open(rktio, "demo_fifo", RKTIO_OPEN_WRITE | RKTIO_OPEN_CAN_EXIST);
@ -637,7 +638,7 @@ int main()
free(strs);
}
check_read_write_pair(rktio, fd, fd2);
check_read_write_pair(rktio, fd, fd2, 0);
fd = connect_loop(rktio, addr, NULL);
rktio_free_addrinfo(rktio, addr);
@ -675,7 +676,7 @@ int main()
check_valid(addr);
check_valid(rktio_udp_connect(rktio, fd2, addr));
check_read_write_pair(rktio, fd, fd2);
check_read_write_pair(rktio, fd, fd2, 0);
/* Again, this time to fill & drain: */
@ -701,6 +702,51 @@ int main()
check_valid(rktio_close(rktio, fd));
check_valid(rktio_close(rktio, fd2));
}
/* Processes */
{
rktio_status_t *status;
rktio_process_result_t *result;
char *argv[2] = { "/bin/cat", NULL };
rktio_envvars_t *envvars = NULL;
rktio_fd_t *err_fd = rktio_system_fd(rktio, 2, RKTIO_OPEN_WRITE);
int done;
result = rktio_process(rktio, "/bin/cat", 1, argv,
NULL, NULL, err_fd,
rktio_get_current_directory(rktio), envvars,
0,
NULL);
check_valid(result);
status = rktio_process_status(rktio, result->process);
check_valid(status);
check_valid(status->running);
check_valid(!result->stderr_fd);
free(status);
check_valid(!rktio_poll_subprocess_done(rktio, result->process));
check_read_write_pair(rktio, result->stdout_fd, result->stdin_fd, 0);
check_valid(rktio_poll_subprocess_done(rktio, result->process) != RKTIO_PROCESS_ERROR);
do {
rktio_poll_set_t *ps;
ps = rktio_make_poll_set(rktio);
check_valid(ps);
rktio_poll_add_process(rktio, result->process, ps);
rktio_sleep(rktio, 0, ps, NULL);
rktio_poll_set_close(rktio, ps);
done = rktio_poll_subprocess_done(rktio, result->process);
check_valid(done != RKTIO_PROCESS_ERROR);
} while (!done);
rktio_process_forget(rktio, result->process);
free(result);
check_valid(rktio_close(rktio, err_fd));
}
return 0;
}

View File

@ -48,7 +48,6 @@ void rktio_forget(rktio_t *rktio, rktio_fd_t *fd);
#define RKTIO_WRITE_ERROR (-2)
#define RKTIO_POLL_ERROR (-2)
#define RKTIO_POLL_READY 1
#define RKTIO_PROP_ERROR (-2)
intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
@ -110,6 +109,8 @@ typedef struct rktio_length_and_addrinfo_t {
rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len);
#define RKTIO_PROP_ERROR (-2)
/* The following accessors return RKTIO_PROP_ERROR on failure */
int rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd);
int rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, int on);
@ -133,6 +134,51 @@ int rktio_udp_change_multicast_group(rktio_t *rktio, rktio_fd_t *rfd,
rktio_addrinfo_t *intf_addr,
int action);
/*************************************************/
/* Environment variables */
typedef struct rktio_envvars_t rktio_envvars_t;
/*************************************************/
/* Processes */
typedef struct rktio_process_t rktio_process_t;
#define RKTIO_PROCESS_NEW_GROUP (1<<0)
#define RKTIO_PROCESS_STDOUT_AS_STDERR (1<<1)
#define RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE (1<<2)
#define RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION (1<<3)
typedef struct rktio_process_result_t {
rktio_process_t *process;
rktio_fd_t *stdin_fd, *stdout_fd, *stderr_fd;
} rktio_process_result_t;
rktio_process_result_t *rktio_process(rktio_t *rktio,
const char *command, int argc, char **argv,
rktio_fd_t *stdout_fd, rktio_fd_t *stdin_fd, rktio_fd_t *stderr_fd,
const char *current_directory, rktio_envvars_t *envvars,
int flags,
void (*unix_child_process_callback)());
int rktio_process_kill(rktio_t *rktio, rktio_process_t *sp);
int rktio_process_interrupt(rktio_t *rktio, rktio_process_t *sp);
void rktio_process_forget(rktio_t *rktio, rktio_process_t *sp);
#define RKTIO_PROCESS_ERROR (-2)
#define RKTIO_PROCESS_DONE 1
int rktio_poll_subprocess_done(rktio_t *rktio, rktio_process_t *sp);
typedef struct rktio_status_t {
int running;
int result;
} rktio_status_t;
rktio_status_t *rktio_process_status(rktio_t *rktio, rktio_process_t *sp);
void rktio_block_child_signals(rktio_t*rktio, int block);
/*************************************************/
/* File-descriptor sets for polling */
@ -151,12 +197,13 @@ void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int
void rktio_poll_add_receive(rktio_t *rktio, rktio_listener_t *listener, rktio_poll_set_t *fds);
void rktio_poll_add_connect(rktio_t *rktio, rktio_connect_t *conn, rktio_poll_set_t *fds);
void rktio_poll_add_addrinfo_lookup(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup, rktio_poll_set_t *fds);
void rktio_poll_add_process(rktio_t *rktio, rktio_process_t *sp, rktio_poll_set_t *fds);
void rktio_poll_set_add_nosleep(rktio_t *rktio, rktio_poll_set_t *fds);
#ifdef RKTIO_SYSTEM_WINDOWS
void rktio_poll_set_add_handle(HANDLE h, rktio_poll_set_t *fds, int repost);
void rktio_poll_set_add_eventmask(rktio_poll_set_t *fds, int mask);
void rktio_poll_set_add_handle(rktio_t *rktio, HANDLE h, rktio_poll_set_t *fds, int repost);
void rktio_poll_set_add_eventmask(rktio_t *rktio, rktio_poll_set_t *fds, int mask);
#endif
/*************************************************/
@ -204,7 +251,7 @@ int rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail);
int rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok);
char *rktio_get_current_directory(rktio_t *rktio);
int rktio_set_current_directory(rktio_t *rktio, char *expanded);
int rktio_set_current_directory(rktio_t *rktio, const char *path);
int rktio_make_directory(rktio_t *rktio, char *filename);
int rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directory, int enable_write_on_fail);

View File

@ -0,0 +1,12 @@
#include "rktio.h"
#include "rktio_private.h"
#include <stdlib.h>
#include <string.h>
void *rktio_envvars_to_block(rktio_t *rktio, rktio_envvars_t *envvars)
{
void *p;
p = malloc(sizeof(char *));
*(char **)p = NULL;
return p;
}

View File

@ -630,12 +630,12 @@ char *rktio_get_current_directory(rktio_t *rktio)
#endif
}
int rktio_set_current_directory(rktio_t *rktio, char *expanded)
int rktio_set_current_directory(rktio_t *rktio, const char *path)
{
int err;
while (1) {
err = MSC_W_IZE(chdir)(MSC_WIDE_PATH_temp(expanded));
err = MSC_W_IZE(chdir)(MSC_WIDE_PATH_temp(path));
if (!err || (errno != EINTR))
break;
}
@ -914,7 +914,7 @@ int rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directo
# ifdef RKTIO_SYSTEM_WINDOWS
else if ((errno == EACCES) && !tried_cwd) {
/* Maybe we're using the target directory. Try a real setcwd. */
(void)rktio_set_current_directory(current_directory);
(void)rktio_set_current_directory(rktio, current_directory);
tried_cwd = 1;
} else if ((errno == EACCES) && !tried_perm && enable_write_on_fail) {
/* Maybe the directory doesn't have write permission. */

View File

@ -15,12 +15,18 @@ rktio_t *rktio_init(void)
rktio_destroy(rktio);
return NULL;
}
if (!rktio_process_init(rktio)) {
rktio_destroy(rktio);
return NULL;
}
return rktio;
}
void rktio_destroy(rktio_t *rktio)
{
rktio_process_deinit(rktio);
rktio_free_ghbn(rktio);
rktio_free_global_poll_set(rktio);
free(rktio);

View File

@ -72,6 +72,16 @@ struct rktio_t {
HANDLE ghbn_start;
# endif
#endif
#if defined(RKTIO_SYSTEM_UNIX) && !defined(RKTIO_USE_PTHREADS)
struct System_Child *system_children;
int need_to_check_children;
int in_sigchld_chain;
struct rktio_t *next; /* chaining for SIGCHLD handling */
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
uintptr_t process_children_msecs;
#endif
};
/*========================================================================*/
@ -165,6 +175,13 @@ intptr_t rktio_socket_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr
void rktio_free_ghbn(rktio_t *rktio);
const char *rktio_gai_strerror(int errnum);
/*========================================================================*/
/* Processes */
/*========================================================================*/
int rktio_process_init(rktio_t *rktio);
void rktio_process_deinit(rktio_t *rktio);
/*========================================================================*/
/* Misc */
@ -196,3 +213,5 @@ void rktio_get_windows_error(rktio_t *rktio);
#else
# define RKTIO_NONBLOCKING FNDELAY
#endif
void *rktio_envvars_to_block(rktio_t *rktio, rktio_envvars_t *envvars);

File diff suppressed because it is too large Load Diff