Skip to content

Commit 68dfa22

Browse files
committed
Merge branch 'master' into longlit
2 parents 4f1b3f0 + fd8e5ed commit 68dfa22

File tree

6 files changed

+323
-45
lines changed

6 files changed

+323
-45
lines changed

src/vm/parrot/QAST/Operations.nqp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2749,6 +2749,7 @@ QAST::Operations.add_core_pirop_mapping('sleep', 'sleep', '0n', :inlinable(1));
27492749
QAST::Operations.add_core_pirop_mapping('gethostname', 'nqp_gethostname', 'S');
27502750
QAST::Operations.add_core_pirop_mapping('spawn', 'nqp_spawn', 'IPsP');
27512751
QAST::Operations.add_core_pirop_mapping('shell', 'nqp_shell', 'IssP');
2752+
QAST::Operations.add_core_pirop_mapping('openpipe', 'nqp_openpipe', 'PssPs');
27522753
QAST::Operations.add_core_pirop_mapping('getenvhash', 'nqp_getenvhash', 'P');
27532754

27542755
QAST::Operations.add_core_op('getpid', -> $qastcomp, $op {

src/vm/parrot/ops/nqp.ops

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ BEGIN_OPS_PREAMBLE
66
#include "parrot/parrot.h"
77
#include "parrot/extend.h"
88
#include "parrot/dynext.h"
9+
#include "parrot/io.h"
10+
#include "pmc/pmc_filehandle.h"
911

1012
/* 6modely includes. */
1113
#include "../6model/sixmodelobject.h"
@@ -563,6 +565,97 @@ static char *create_command_line(const char *const *args) {
563565
return cmd;
564566
}
565567

568+
static PIOHANDLE Run_OS_Command_Piped(PARROT_INTERP, PMC *command, PMC *env_hash, INTVAL flags,
569+
INTVAL *pid, INTVAL *status) {
570+
HANDLE current = GetCurrentProcess();
571+
HANDLE hnull = INVALID_HANDLE_VALUE;
572+
HANDLE hread = INVALID_HANDLE_VALUE;
573+
HANDLE hwrite = INVALID_HANDLE_VALUE;
574+
HANDLE hchild = INVALID_HANDLE_VALUE;
575+
STARTUPINFO si;
576+
PROCESS_INFORMATION pi;
577+
SECURITY_ATTRIBUTES sec;
578+
const char *env = pack_env_hash(interp, env_hash);
579+
const char *const *argv = pack_arg_array(interp, command);
580+
const char *cmd = create_command_line(argv);
581+
PIOHANDLE os_handle;
582+
583+
pi.hThread = INVALID_HANDLE_VALUE;
584+
pi.hProcess = INVALID_HANDLE_VALUE;
585+
sec.nLength = sizeof sec;
586+
sec.lpSecurityDescriptor = NULL;
587+
sec.bInheritHandle = TRUE;
588+
589+
si.cb = sizeof si;
590+
GetStartupInfo(&si);
591+
si.dwFlags = STARTF_USESTDHANDLES;
592+
if (CreatePipe(&hread, &hwrite, NULL, 0) == 0)
593+
goto fail;
594+
if (DuplicateHandle(current, flags & PARROT_EXEC_STDOUT ? hwrite : hread,
595+
current, &hchild,
596+
0, TRUE,
597+
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)
598+
== 0)
599+
goto fail;
600+
if (hchild == INVALID_HANDLE_VALUE)
601+
goto fail;
602+
603+
if (flags & PARROT_EXEC_STDOUT) {
604+
/* Redirect input to NULL. This is to avoid
605+
* interferences in case both the child and
606+
* the parent tries to read from stdin.
607+
* May be unnecessary or even interfere
608+
* with valid usages, need more feedback. */
609+
hnull = CreateFile("NUL", GENERIC_READ|GENERIC_WRITE,
610+
0, &sec, OPEN_EXISTING,
611+
FILE_ATTRIBUTE_NORMAL, NULL);
612+
if (hnull == INVALID_HANDLE_VALUE)
613+
goto fail;
614+
si.hStdInput = hnull;
615+
si.hStdOutput = hchild;
616+
si.hStdError = hchild;
617+
}
618+
else {
619+
si.hStdInput = hchild;
620+
}
621+
622+
if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, env, NULL, &si, &pi) == 0)
623+
goto fail;
624+
625+
if (flags & PARROT_EXEC_STDOUT) {
626+
os_handle = hread;
627+
CloseHandle(hwrite);
628+
}
629+
else {
630+
os_handle = hwrite;
631+
CloseHandle(hread);
632+
}
633+
634+
Parrot_str_free_cstring(cmd);
635+
CloseHandle(pi.hThread);
636+
637+
*pid = (INTVAL)pi.hProcess;
638+
639+
return os_handle;
640+
641+
fail:
642+
if (cmd != NULL)
643+
Parrot_str_free_cstring(cmd);
644+
if (hnull != INVALID_HANDLE_VALUE)
645+
CloseHandle(hnull);
646+
if (hread != INVALID_HANDLE_VALUE)
647+
CloseHandle(hread);
648+
if (hwrite != INVALID_HANDLE_VALUE)
649+
CloseHandle(hwrite);
650+
if (hchild != INVALID_HANDLE_VALUE)
651+
CloseHandle(hchild);
652+
if (pi.hThread != INVALID_HANDLE_VALUE)
653+
CloseHandle(pi.hThread);
654+
if (pi.hProcess != INVALID_HANDLE_VALUE)
655+
CloseHandle(pi.hProcess);
656+
Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_UNIMPLEMENTED,
657+
"pipe open error");
658+
}
566659
static INTVAL Run_OS_Command(PARROT_INTERP, PMC *command, PMC *env_hash)
567660
{
568661
DWORD status = 0;
@@ -667,6 +760,129 @@ static INTVAL Run_OS_Command(PARROT_INTERP, PMC *command, PMC *env_hash)
667760
/* make gcc happy */
668761
return 1;
669762
}
763+
static PIOHANDLE Run_OS_Command_Piped(PARROT_INTERP, PMC *command, PMC *env_hash, INTVAL flags,
764+
INTVAL *pid, INTVAL *status) {
765+
char **saved = environ;
766+
char **cmd = pack_arg_array(interp, command);
767+
char **env = pack_env_hash(interp, env_hash);
768+
char *prog = cmd[0];
769+
PIOHANDLE handles[3];
770+
int in_fds[2];
771+
int out_fds[2];
772+
int err_fds[2];
773+
774+
if (flags & PARROT_EXEC_STDIN
775+
&& pipe(in_fds) < 0)
776+
goto error_pipe_in;
777+
778+
if (flags & PARROT_EXEC_STDOUT
779+
&& pipe(out_fds) < 0)
780+
goto error_pipe_out;
781+
782+
if (flags & PARROT_EXEC_STDERR
783+
&& pipe(err_fds) < 0)
784+
goto error_pipe_err;
785+
786+
*pid = fork();
787+
788+
if (*pid < 0)
789+
goto error_fork;
790+
791+
if (*pid > 0) {
792+
if (flags & PARROT_EXEC_STDIN) {
793+
/* close fd for reading */
794+
close(in_fds[0]);
795+
handles[0] = in_fds[1];
796+
}
797+
798+
if (flags & PARROT_EXEC_STDOUT) {
799+
/* close fd for writing */
800+
close(out_fds[1]);
801+
handles[1] = out_fds[0];
802+
}
803+
804+
if (flags & PARROT_EXEC_STDERR) {
805+
/* close fd for writing */
806+
close(err_fds[1]);
807+
handles[2] = err_fds[0];
808+
}
809+
}
810+
else /* (pid == 0) */ {
811+
/* Child - exec process */
812+
813+
if (flags & PARROT_EXEC_STDIN) {
814+
/* redirect stdin to pipe */
815+
close(in_fds[1]);
816+
close(STDIN_FILENO);
817+
818+
if (dup(in_fds[0]) != STDIN_FILENO)
819+
PARROT_FORCE_EXIT(EXIT_FAILURE);
820+
}
821+
822+
if (flags & PARROT_EXEC_STDOUT) {
823+
/* redirect stdout to pipe */
824+
close(out_fds[0]);
825+
close(STDOUT_FILENO);
826+
827+
if (dup(out_fds[1]) != STDOUT_FILENO)
828+
PARROT_FORCE_EXIT(EXIT_FAILURE);
829+
830+
if (!(flags & PARROT_EXEC_STDERR)) {
831+
close(STDERR_FILENO);
832+
833+
if (dup(out_fds[1]) != STDERR_FILENO)
834+
PARROT_FORCE_EXIT(EXIT_FAILURE);
835+
}
836+
}
837+
838+
if (flags & PARROT_EXEC_STDERR) {
839+
/* redirect stderr to pipe */
840+
close(err_fds[0]);
841+
close(STDERR_FILENO);
842+
843+
if (dup(err_fds[1]) != STDERR_FILENO)
844+
PARROT_FORCE_EXIT(EXIT_FAILURE);
845+
}
846+
847+
environ = env;
848+
849+
*status = execvp(prog, cmd);
850+
851+
/* if we get here, something's horribly wrong, but free anyway... */
852+
free_packed(env);
853+
free_packed(cmd);
854+
environ = saved;
855+
856+
/* Will never reach this unless exec fails.
857+
* No need to clean up, we're just going to exit */
858+
perror("execvp");
859+
PARROT_FORCE_EXIT(EXIT_FAILURE);
860+
}
861+
862+
return handles[1];
863+
864+
error_fork:
865+
if (flags & PARROT_EXEC_STDERR) {
866+
close(err_fds[0]);
867+
close(err_fds[1]);
868+
}
869+
870+
error_pipe_err:
871+
if (flags & PARROT_EXEC_STDOUT) {
872+
close(out_fds[0]);
873+
close(out_fds[1]);
874+
}
875+
876+
error_pipe_out:
877+
if (flags & PARROT_EXEC_STDIN) {
878+
close(in_fds[0]);
879+
close(in_fds[1]);
880+
}
881+
882+
error_pipe_in:
883+
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
884+
"Error executing process: %s", strerror(errno));
885+
}
670886
#endif
671887

672888
/*
@@ -3787,6 +4003,58 @@ inline op nqp_delete_f(out INT, in STR) :base_core {
37874003
#endif
37884004
}
37894005

4006+
inline op nqp_openpipe(out PMC, in STR, in STR, in PMC, in STR) {
4007+
STRING *dir = $3;
4008+
PMC *env = $4;
4009+
STRING * const old_cwd = Parrot_file_getcwd(interp);
4010+
INTVAL status = 0;
4011+
const INTVAL typenum = Parrot_hll_get_ctx_HLL_type(interp, enum_class_FileHandle);
4012+
PMC *handle = Parrot_pmc_new(interp, typenum);
4013+
IO_BUFFER * read_buffer = IO_GET_READ_BUFFER(interp, handle);
4014+
PMC * command = Parrot_pmc_new(interp, enum_class_ResizableStringArray);
4015+
const VTABLE * vtable = Parrot_io_get_vtable(interp, IO_VTABLE_PIPE, NULL);
4016+
PIOHANDLE os_handle;
4017+
INTVAL pid;
4018+
#ifdef WIN32
4019+
const STRING *comspec = Parrot_str_new(interp, "ComSpec", 0);
4020+
VTABLE_push_string(interp, command, Parrot_getenv(interp, comspec));
4021+
VTABLE_push_string(interp, command, Parrot_str_new_constant(interp, "/c"));
4022+
#else
4023+
VTABLE_push_string(interp, command, Parrot_str_new_constant(interp, "sh"));
4024+
VTABLE_push_string(interp, command, Parrot_str_new_constant(interp, "-c"));
4025+
#endif
4026+
VTABLE_push_string(interp, command, $2);
4027+
4028+
Parrot_file_chdir(interp, dir);
4029+
os_handle = Run_OS_Command_Piped(interp, command, env, PARROT_EXEC_STDOUT, &pid, &status);
4030+
Parrot_file_chdir(interp, old_cwd);
4031+
4032+
SETATTR_FileHandle_io_vtable(interp, handle, vtable);
4033+
SETATTR_FileHandle_process_id(interp, handle, pid);
4034+
SETATTR_FileHandle_exit_status(interp, handle, status);
4035+
SETATTR_FileHandle_os_handle(interp, handle, os_handle);
4036+
SETATTR_FileHandle_flags(interp, handle, PIO_F_PIPE | PIO_F_READ);
4037+
SETATTR_FileHandle_mode(interp, handle, Parrot_str_new_constant(interp, "rp"));
4038+
SETATTR_FileHandle_file_pos(interp, handle, 0);
4039+
4040+
if (!read_buffer) {
4041+
read_buffer = (IO_BUFFER *)Parrot_gc_allocate_fixed_size_storage(interp,
4042+
sizeof(IO_BUFFER));
4043+
read_buffer->encoding = NULL;
4044+
read_buffer->buffer_size = 2048; /* PIO_BUFFER_MIN_SIZE */
4045+
read_buffer->buffer_ptr = (char *)mem_sys_allocate(2048);
4046+
read_buffer->buffer_start = read_buffer->buffer_ptr;
4047+
read_buffer->buffer_end = read_buffer->buffer_ptr;
4048+
PARROT_ASSERT(BUFFER_IS_EMPTY(read_buffer));
4049+
read_buffer->raw_reads = 0;
4050+
read_buffer->flags |= PIO_BF_MALLOC;
4051+
4052+
SETATTR_FileHandle_read_buffer(interp, handle, read_buffer);
4053+
}
4054+
4055+
$1 = handle;
4056+
}
4057+
37904058
inline op nqp_spawn(out INT, in PMC, in STR, in PMC) {
37914059
STRING *dir = $3;
37924060
PMC *env = $4;

t/jvm/02-pipes.t

Lines changed: 0 additions & 22 deletions
This file was deleted.

t/moar/02-pipes.t

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)