Added redirection functions
This commit is contained in:
parent
7038b2dcb5
commit
53c9edc23e
4 changed files with 163 additions and 18 deletions
41
include/criterion/redirect.h
Normal file
41
include/criterion/redirect.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright © 2015 Franklin "Snaipe" Mathieu <http://snai.pe/>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef CRITERION_REDIRECT_H_
|
||||||
|
# define CRITERION_REDIRECT_H_
|
||||||
|
|
||||||
|
# include "common.h"
|
||||||
|
|
||||||
|
CR_BEGIN_C_API
|
||||||
|
|
||||||
|
CR_API void cr_redirect_stdout(void);
|
||||||
|
CR_API void cr_redirect_stderr(void);
|
||||||
|
CR_API void cr_redirect_stdin(void);
|
||||||
|
|
||||||
|
CR_API FILE* cr_get_redirected_stdout(void);
|
||||||
|
CR_API FILE* cr_get_redirected_stderr(void);
|
||||||
|
CR_API FILE* cr_get_redirected_stdin(void);
|
||||||
|
|
||||||
|
CR_END_C_API
|
||||||
|
|
||||||
|
#endif /* !CRITERION_REDIRECT_H_ */
|
|
@ -24,6 +24,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "posix-compat.h"
|
#include "posix-compat.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
|
#include "criterion/assert.h"
|
||||||
|
|
||||||
#ifdef VANILLA_WIN32
|
#ifdef VANILLA_WIN32
|
||||||
# define VC_EXTRALEAN
|
# define VC_EXTRALEAN
|
||||||
|
@ -262,15 +263,17 @@ void wait_process(s_proc_handle *handle, int *status) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *pipe_in(s_pipe_handle *p) {
|
FILE *pipe_in(s_pipe_handle *p, int do_close) {
|
||||||
#ifdef VANILLA_WIN32
|
#ifdef VANILLA_WIN32
|
||||||
CloseHandle(p->fhs[1]);
|
if (do_close)
|
||||||
|
CloseHandle(p->fhs[1]);
|
||||||
int fd = _open_osfhandle((intptr_t) p->fhs[0], _O_RDONLY);
|
int fd = _open_osfhandle((intptr_t) p->fhs[0], _O_RDONLY);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
FILE *in = _fdopen(fd, "r");
|
FILE *in = _fdopen(fd, "r");
|
||||||
#else
|
#else
|
||||||
close(p->fds[1]);
|
if (do_close)
|
||||||
|
close(p->fds[1]);
|
||||||
FILE *in = fdopen(p->fds[0], "r");
|
FILE *in = fdopen(p->fds[0], "r");
|
||||||
#endif
|
#endif
|
||||||
if (!in)
|
if (!in)
|
||||||
|
@ -280,15 +283,17 @@ FILE *pipe_in(s_pipe_handle *p) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *pipe_out(s_pipe_handle *p) {
|
FILE *pipe_out(s_pipe_handle *p, int do_close) {
|
||||||
#ifdef VANILLA_WIN32
|
#ifdef VANILLA_WIN32
|
||||||
CloseHandle(p->fhs[0]);
|
if (do_close)
|
||||||
|
CloseHandle(p->fhs[0]);
|
||||||
int fd = _open_osfhandle((intptr_t) p->fhs[1], _O_WRONLY);
|
int fd = _open_osfhandle((intptr_t) p->fhs[1], _O_WRONLY);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
FILE *out = _fdopen(fd, "w");
|
FILE *out = _fdopen(fd, "w");
|
||||||
#else
|
#else
|
||||||
close(p->fds[0]);
|
if (do_close)
|
||||||
|
close(p->fds[0]);
|
||||||
FILE *out = fdopen(p->fds[1], "w");
|
FILE *out = fdopen(p->fds[1], "w");
|
||||||
#endif
|
#endif
|
||||||
if (!out)
|
if (!out)
|
||||||
|
@ -298,8 +303,7 @@ FILE *pipe_out(s_pipe_handle *p) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_pipe_handle *stdpipe() {
|
int stdpipe_stack(s_pipe_handle *out) {
|
||||||
s_pipe_handle *handle = smalloc(sizeof (s_pipe_handle));
|
|
||||||
#ifdef VANILLA_WIN32
|
#ifdef VANILLA_WIN32
|
||||||
HANDLE fhs[2];
|
HANDLE fhs[2];
|
||||||
SECURITY_ATTRIBUTES attr = {
|
SECURITY_ATTRIBUTES attr = {
|
||||||
|
@ -307,16 +311,22 @@ s_pipe_handle *stdpipe() {
|
||||||
.bInheritHandle = TRUE
|
.bInheritHandle = TRUE
|
||||||
};
|
};
|
||||||
if (!CreatePipe(fhs, fhs + 1, &attr, 0))
|
if (!CreatePipe(fhs, fhs + 1, &attr, 0))
|
||||||
return NULL;
|
return -1;
|
||||||
*handle = (s_pipe_handle) {{ fhs[0], fhs[1] }};
|
*out = (s_pipe_handle) {{ fhs[0], fhs[1] }};
|
||||||
return handle;
|
|
||||||
#else
|
#else
|
||||||
int fds[2] = { -1, -1 };
|
int fds[2] = { -1, -1 };
|
||||||
if (pipe(fds) == -1)
|
if (pipe(fds) == -1)
|
||||||
return NULL;
|
return -1;
|
||||||
*handle = (s_pipe_handle) {{ fds[0], fds[1] }};
|
*out = (s_pipe_handle) {{ fds[0], fds[1] }};
|
||||||
return handle;
|
|
||||||
#endif
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_pipe_handle *stdpipe() {
|
||||||
|
s_pipe_handle *handle = smalloc(sizeof (s_pipe_handle));
|
||||||
|
if (stdpipe_stack(handle) < 0)
|
||||||
|
return NULL;
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_proc_handle *get_current_process() {
|
s_proc_handle *get_current_process() {
|
||||||
|
@ -405,3 +415,97 @@ const char *basename_compat(const char *str) {
|
||||||
start = c + 1;
|
start = c + 1;
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef VANILLA_WIN32
|
||||||
|
typedef DWORD cr_std_fd;
|
||||||
|
#else
|
||||||
|
typedef int cr_std_fd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static s_pipe_handle stdout_redir;
|
||||||
|
static s_pipe_handle stderr_redir;
|
||||||
|
static s_pipe_handle stdin_redir;
|
||||||
|
|
||||||
|
enum criterion_std_fd {
|
||||||
|
CR_STDIN,
|
||||||
|
CR_STDOUT,
|
||||||
|
CR_STDERR
|
||||||
|
};
|
||||||
|
|
||||||
|
enum criterion_pipe_end {
|
||||||
|
PIPE_READ = 0,
|
||||||
|
PIPE_WRITE = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
cr_std_fd get_std_fd(int fd_kind) {
|
||||||
|
static int kinds[] = {
|
||||||
|
#ifdef VANILLA_WIN32
|
||||||
|
[CR_STDIN] = STD_INPUT_HANDLE,
|
||||||
|
[CR_STDOUT] = STD_OUTPUT_HANDLE,
|
||||||
|
[CR_STDERR] = STD_ERROR_HANDLE,
|
||||||
|
#else
|
||||||
|
[CR_STDIN] = STDIN_FILENO,
|
||||||
|
[CR_STDOUT] = STDOUT_FILENO,
|
||||||
|
[CR_STDERR] = STDERR_FILENO,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
return kinds[fd_kind];
|
||||||
|
}
|
||||||
|
|
||||||
|
void cr_redirect(int fd_kind, s_pipe_handle *pipe, int fd_index) {
|
||||||
|
if (stdpipe_stack(pipe) < 0)
|
||||||
|
cr_assert_fail("Could not redirect standard file descriptor.");
|
||||||
|
|
||||||
|
cr_std_fd fd = get_std_fd(fd_kind);
|
||||||
|
#ifdef VANILLA_WIN32
|
||||||
|
CloseHandle(GetStdHandle(fd));
|
||||||
|
SetStdHandle(fd, pipe->fds[fd_index]);
|
||||||
|
#else
|
||||||
|
close(fd);
|
||||||
|
dup2(fd, pipe->fds[fd_index]);
|
||||||
|
close(pipe->fds[fd_index]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void cr_redirect_stdout(void) {
|
||||||
|
cr_redirect(CR_STDOUT, &stdout_redir, PIPE_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cr_redirect_stderr(void) {
|
||||||
|
cr_redirect(CR_STDERR, &stderr_redir, PIPE_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cr_redirect_stdin(void) {
|
||||||
|
cr_redirect(CR_STDIN, &stdin_redir, PIPE_READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* cr_get_redirected_stdout(void) {
|
||||||
|
static FILE *f;
|
||||||
|
if (!f) {
|
||||||
|
f = pipe_in(&stdout_redir, 0);
|
||||||
|
if (!f)
|
||||||
|
cr_assert_fail("Could not get redirected stdout read end.");
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* cr_get_redirected_stderr(void) {
|
||||||
|
static FILE *f;
|
||||||
|
if (!f) {
|
||||||
|
f = pipe_in(&stderr_redir, 0);
|
||||||
|
if (!f)
|
||||||
|
cr_assert_fail("Could not get redirected stderr read end.");
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* cr_get_redirected_stdin(void) {
|
||||||
|
static FILE *f;
|
||||||
|
if (!f) {
|
||||||
|
f = pipe_out(&stdin_redir, 0);
|
||||||
|
if (!f)
|
||||||
|
cr_assert_fail("Could not get redirected stdin write end.");
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
|
@ -67,8 +67,8 @@ extern struct worker_context g_worker_context;
|
||||||
int resume_child(void);
|
int resume_child(void);
|
||||||
|
|
||||||
s_pipe_handle *stdpipe();
|
s_pipe_handle *stdpipe();
|
||||||
FILE *pipe_in(s_pipe_handle *p);
|
FILE *pipe_in(s_pipe_handle *p, int do_close);
|
||||||
FILE *pipe_out(s_pipe_handle *p);
|
FILE *pipe_out(s_pipe_handle *p, int do_close);
|
||||||
|
|
||||||
s_proc_handle *fork_process();
|
s_proc_handle *fork_process();
|
||||||
void wait_process(s_proc_handle *handle, int *status);
|
void wait_process(s_proc_handle *handle, int *status);
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct event *worker_read_event(struct process *proc) {
|
||||||
|
|
||||||
void run_worker(struct worker_context *ctx) {
|
void run_worker(struct worker_context *ctx) {
|
||||||
fclose(stdin);
|
fclose(stdin);
|
||||||
g_event_pipe = pipe_out(ctx->pipe);
|
g_event_pipe = pipe_out(ctx->pipe, 1);
|
||||||
|
|
||||||
ctx->func(ctx->test, ctx->suite);
|
ctx->func(ctx->test, ctx->suite);
|
||||||
fclose(g_event_pipe);
|
fclose(g_event_pipe);
|
||||||
|
@ -102,7 +102,7 @@ struct process *spawn_test_worker(struct criterion_test *test,
|
||||||
.kind = UNIQUE,
|
.kind = UNIQUE,
|
||||||
.dtor = close_process);
|
.dtor = close_process);
|
||||||
|
|
||||||
*ptr = (struct process) { .proc = proc, .in = pipe_in(pipe) };
|
*ptr = (struct process) { .proc = proc, .in = pipe_in(pipe, 1) };
|
||||||
cleanup:
|
cleanup:
|
||||||
sfree(pipe);
|
sfree(pipe);
|
||||||
return ptr;
|
return ptr;
|
||||||
|
|
Loading…
Add table
Reference in a new issue