// File: /workspace/github_c_makefile_star2_O1/deplinenoise[P]tundra/src/ExecUnix.cpp
// Function: t2::ExecuteProcess(char const*, int, t2::EnvVariable const*, int, int, char const*)
ExecResult
ExecuteProcess(
		const char* cmd_line,
		int env_count,
		const EnvVariable *env_vars,
		int job_id,
		int echo_cmdline,
		const char *annotation)
{
  ExecResult result;

  result.m_ReturnCode   = 1;
  result.m_WasSignalled = false;

	pid_t child;
	const int pipe_read = 0;
	const int pipe_write = 1;

	/* Create a pair of pipes to read back stdout, stderr */
	int stdout_pipe[2], stderr_pipe[2];

	if (-1 == pipe(stdout_pipe))
	{
		perror("pipe failed");
		return result;
	}

	if (-1 == pipe(stderr_pipe))
	{
		perror("pipe failed");
		close(stdout_pipe[0]);
		close(stdout_pipe[1]);
		return result;
	}

	if (0 == (child = fork()))
	{
		const char *args[] = { "/bin/sh", "-c", cmd_line, NULL };

		close(stdout_pipe[pipe_read]);
		close(stderr_pipe[pipe_read]);

		if (-1 == dup2(stdout_pipe[pipe_write], STDOUT_FILENO))
			perror("dup2 failed");
		if (-1 == dup2(stderr_pipe[pipe_write], STDERR_FILENO))
			perror("dup2 failed");

		close(stdout_pipe[pipe_write]);
		close(stderr_pipe[pipe_write]);

		sigset_t sigs;
		sigfillset(&sigs);
		if (0 != sigprocmask(SIG_UNBLOCK, &sigs, 0))
			perror("sigprocmask failed");

		for (int i = 0; i < env_count; ++i)
		{
			setenv(env_vars[i].m_Name, env_vars[i].m_Value, /*overwrite:*/ 1);
		}

		if (-1 == execv("/bin/sh", (char **) args))
			exit(1);
		/* we never get here */
		abort();
	}
	else if (-1 == child)
	{
		perror("fork failed");
		close(stdout_pipe[pipe_read]);
		close(stderr_pipe[pipe_read]);
		close(stdout_pipe[pipe_write]);
		close(stderr_pipe[pipe_write]);
		return result;
	}
	else
	{
		pid_t p;
		int return_code = 0;
		int sort_key = 0;
		int rfd_count = 2;
		int rfds[2];
		fd_set read_fds;

		rfds[0] = stdout_pipe[pipe_read];
		rfds[1] = stderr_pipe[pipe_read];

		SetFdNonBlocking(rfds[0]);
		SetFdNonBlocking(rfds[1]);

		/* Close write end of the pipe, we're just going to be reading */
		close(stdout_pipe[pipe_write]);
		close(stderr_pipe[pipe_write]);

		if (annotation)
			TerminalIoPrintf(job_id, -200, "%s\n", annotation);

		if (echo_cmdline)
			TerminalIoPrintf(job_id, -199, "%s\n", cmd_line);

		/* Sit in a select loop over the two fds */

		for (;;)
		{
			int fd;
			int count;
			int max_fd = 0;
			struct timeval timeout;

			/* don't select if we know both pipes are closed */
			if (rfd_count > 0)
			{
				FD_ZERO(&read_fds);

				for (fd = 0; fd < 2; ++fd)
				{
					if (rfds[fd])
					{
						if (rfds[fd] > max_fd)
							max_fd = rfds[fd];
						FD_SET(rfds[fd], &read_fds);
					}
				}

				++max_fd;

				timeout.tv_sec = 0;
				timeout.tv_usec = 500000;

				count = select(max_fd, &read_fds, NULL, NULL, &timeout);

				if (-1 == count) // happens in gdb due to syscall interruption
					continue;

				for (fd = 0; fd < 2; ++fd)
				{
					if (0 != rfds[fd] && FD_ISSET(rfds[fd], &read_fds))
					{
						if (0 != EmitData(job_id, /*is_stderr:*/ 1 == fd, sort_key++, rfds[fd]))
						{
							/* Done with this FD. */
							rfds[fd] = 0;
							--rfd_count;
						}
					}
				}
			}

			return_code = 0;
			p = waitpid(child, &return_code, rfd_count > 0 ? WNOHANG : 0);

			if (0 == p)
			{
				/* child still running */
				continue;
			}
			else if (p != child)
			{
				return_code = 1;
				perror("waitpid failed");
				break;
			}
			else
			{
				/* fall out of the loop here - process has exited. */
				/* FIXME - is there a race between getting the last data out of
				 * the pipes vs quitting here? Probably there is. But it seems
				 * to work well in practice. If I put a blocking waitpid()
				 * after the loop I got deadlocks on Mac OS X in select. */
				break;
			}
		}

		close(stdout_pipe[pipe_read]);
		close(stderr_pipe[pipe_read]);

		if (WIFSIGNALED(return_code))
    {
			result.m_ReturnCode   = 1;
			result.m_WasSignalled = true;

			int sig = WTERMSIG(return_code);
			TerminalIoPrintf(job_id, INT_MAX, "child process exited on signal %d: %s\n", sig, cmd_line);
		}
		else
    {
			result.m_ReturnCode   = WEXITSTATUS(return_code);

			if (0 != result.m_ReturnCode && !echo_cmdline)
			{
				TerminalIoPrintf(job_id, INT_MAX, "child process failed with exit code %d: %s\n", result.m_ReturnCode, cmd_line);
			}
    }

		TerminalIoJobExit(job_id);

		return result;
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x20c8, %rsp           # imm = 0x20C8
movq %r9, %r12
movl %r8d, %r13d
movl %ecx, %ebx
movq %rdx, %r14
movl %esi, %ebp
movq %rdi, %r15
leaq 0x8(%rsp), %rdi
callq 0x3460
cmpl $-0x1, %eax
je 0x12a59
leaq 0x10(%rsp), %rdi
callq 0x3460
cmpl $-0x1, %eax
je 0x12a67
callq 0x30a0
cmpl $-0x1, %eax
je 0x12a73
movl %eax, 0x24(%rsp)
testl %eax, %eax
je 0x12a8c
movl $0x0, 0x4(%rsp)
movl 0x8(%rsp), %edi
movl %edi, 0x18(%rsp)
movl 0x10(%rsp), %ebp
movl %ebp, 0x1c(%rsp)
callq 0x12b91
movl %ebp, %edi
callq 0x12b91
movl 0xc(%rsp), %edi
callq 0x3660
movl 0x14(%rsp), %edi
callq 0x3660
testq %r12, %r12
je 0x127e1
leaq 0x3df5(%rip), %rdx      # 0x165c5
movl %ebx, %edi
movl $0xffffff38, %esi       # imm = 0xFFFFFF38
movq %r12, %rcx
xorl %eax, %eax
callq 0x1496a
movl %r13d, 0x20(%rsp)
testl %r13d, %r13d
je 0x12803
leaq 0x3dd3(%rip), %rdx      # 0x165c5
movl %ebx, %edi
movl $0xffffff39, %esi       # imm = 0xFFFFFF39
movq %r15, %rcx
xorl %eax, %eax
callq 0x1496a
movq %r15, 0x28(%rsp)
movl $0x2, %r13d
xorl %r12d, %r12d
leaq 0xc0(%rsp), %r14
testl %r13d, %r13d
jle 0x1294d
xorps %xmm0, %xmm0
movaps %xmm0, 0xb0(%rsp)
movaps %xmm0, 0xa0(%rsp)
movaps %xmm0, 0x90(%rsp)
movaps %xmm0, 0x80(%rsp)
movaps %xmm0, 0x70(%rsp)
movaps %xmm0, 0x60(%rsp)
movaps %xmm0, 0x50(%rsp)
movaps %xmm0, 0x40(%rsp)
xorl %eax, %eax
xorl %edi, %edi
movl 0x18(%rsp,%rax,4), %ecx
testl %ecx, %ecx
je 0x1288c
cmpl %edi, %ecx
cmovgl %ecx, %edi
leal 0x3f(%rcx), %edx
testl %ecx, %ecx
cmovnsl %ecx, %edx
movl %edx, %esi
andl $-0x40, %esi
subl %esi, %ecx
movl $0x1, %esi
shlq %cl, %rsi
sarl $0x6, %edx
movslq %edx, %rcx
orq %rsi, 0x40(%rsp,%rcx,8)
incq %rax
cmpq $0x1, %rax
je 0x1285d
incl %edi
movq $0x0, 0x30(%rsp)
movq $0x7a120, 0x38(%rsp)    # imm = 0x7A120
leaq 0x40(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
leaq 0x30(%rsp), %r8
callq 0x3330
cmpl $-0x1, %eax
je 0x12986
xorl %r15d, %r15d
movl 0x18(%rsp,%r15,4), %edi
testl %edi, %edi
je 0x12924
leal 0x3f(%rdi), %eax
testl %edi, %edi
cmovnsl %edi, %eax
sarl $0x6, %eax
cltq
movq 0x40(%rsp,%rax,8), %rax
btq %rdi, %rax
jae 0x12924
leal 0x1(%r12), %ebp
movl $0x1fff, %edx           # imm = 0x1FFF
movq %r14, %rsi
callq 0x3490
testq %rax, %rax
jle 0x12935
xorl %esi, %esi
cmpq $0x1, %r15
sete %sil
movb $0x0, 0xc0(%rsp,%rax)
movl %ebx, %edi
movl %r12d, %edx
movq %r14, %rcx
movl %eax, %r8d
callq 0x1454a
jmp 0x12927
movl %r12d, %ebp
incq %r15
movl %ebp, %r12d
cmpq $0x1, %r15
je 0x128c8
jmp 0x12950
callq 0x3050
cmpl $0xb, (%rax)
je 0x12927
movl $0x0, 0x18(%rsp,%r15,4)
decl %r13d
jmp 0x12927
movl %r12d, %ebp
movl $0x0, 0x4(%rsp)
xorl %edx, %edx
testl %r13d, %r13d
setg %dl
movl 0x24(%rsp), %r15d
movl %r15d, %edi
leaq 0x4(%rsp), %rsi
callq 0x3280
testl %eax, %eax
je 0x1297f
cmpl %r15d, %eax
jne 0x12992
xorl %eax, %eax
jmp 0x12981
movb $0x1, %al
movl %ebp, %r12d
jmp 0x12988
movb $0x1, %al
testb %al, %al
jne 0x12819
jmp 0x129a8
movl $0x1, 0x4(%rsp)
leaq 0x48cc(%rip), %rdi      # 0x1726d
callq 0x32a0
jmp 0x1297b
movl 0x8(%rsp), %edi
callq 0x3660
movl 0x10(%rsp), %edi
callq 0x3660
movl 0x4(%rsp), %ebp
movl %ebp, %ecx
andl $0x7f, %ecx
movl %ecx, %eax
shll $0x18, %eax
addl $0x1000000, %eax        # imm = 0x1000000
cmpl $0x2000000, %eax        # imm = 0x2000000
jl 0x129ff
leaq 0x48a1(%rip), %rdx      # 0x1727c
movl %ebx, %edi
movl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
movq 0x28(%rsp), %r8
xorl %eax, %eax
callq 0x1496a
movabsq $0x100000000, %r14      # imm = 0x100000000
movl $0x1, %ebp
jmp 0x12a3b
cmpl $0x0, 0x20(%rsp)
setne %al
shrl $0x8, %ebp
andl $0xff, %ebp
sete %cl
orb %al, %cl
movq 0x28(%rsp), %r8
je 0x12a21
xorl %r14d, %r14d
jmp 0x12a3b
leaq 0x487b(%rip), %rdx      # 0x172a3
xorl %r14d, %r14d
movl %ebx, %edi
movl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
movl %ebp, %ecx
xorl %eax, %eax
callq 0x1496a
movl %ebx, %edi
callq 0x148ae
movl %ebp, %eax
orq %r14, %rax
addq $0x20c8, %rsp           # imm = 0x20C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x47cb(%rip), %rdi      # 0x1722b
callq 0x32a0
jmp 0x12a82
leaq 0x8(%rsp), %rdi
callq 0x38b0
jmp 0x12a82
leaq 0x8(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x3872
movl $0x1, %eax
xorl %r14d, %r14d
jmp 0x12a44
leaq 0x47a4(%rip), %rax      # 0x17237
movq %rax, 0x40(%rsp)
leaq 0x47a0(%rip), %rax      # 0x1723f
movq %rax, 0x48(%rsp)
movq %r15, 0x50(%rsp)
movq $0x0, 0x58(%rsp)
movl 0x8(%rsp), %edi
callq 0x3660
movl 0x10(%rsp), %edi
callq 0x3660
movl 0xc(%rsp), %edi
movl $0x1, %esi
callq 0x3310
cmpl $-0x1, %eax
jne 0x12ae3
leaq 0x4764(%rip), %rdi      # 0x17242
callq 0x32a0
movl 0x14(%rsp), %edi
movl $0x2, %esi
callq 0x3310
cmpl $-0x1, %eax
jne 0x12b02
leaq 0x4745(%rip), %rdi      # 0x17242
callq 0x32a0
movl 0xc(%rsp), %edi
callq 0x3660
movl 0x14(%rsp), %edi
callq 0x3660
leaq 0xc0(%rsp), %rbx
movq %rbx, %rdi
callq 0x30d0
movl $0x1, %edi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x3180
testl %eax, %eax
je 0x12b43
leaq 0x4710(%rip), %rdi      # 0x1724e
callq 0x32a0
testl %ebp, %ebp
jle 0x12b6c
movl %ebp, %ebx
shlq $0x4, %rbx
xorl %r15d, %r15d
movq (%r14,%r15), %rdi
movq 0x8(%r14,%r15), %rsi
movl $0x1, %edx
callq 0x3510
addq $0x10, %r15
cmpq %r15, %rbx
jne 0x12b50
leaq 0x46c4(%rip), %rdi      # 0x17237
leaq 0x40(%rsp), %rsi
callq 0x32e0
cmpl $-0x1, %eax
jne 0x12b8c
movl $0x1, %edi
callq 0x33f0
callq 0x31c0