// File: /workspace/github_c_makefile_star2_O3/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 $0x20d8, %rsp           # imm = 0x20D8
movq %r9, %r12
movl %r8d, 0x2c(%rsp)
movl %ecx, 0x20(%rsp)
movq %rdx, %r14
movl %esi, %ebp
movq %rdi, 0x38(%rsp)
leaq 0x14(%rsp), %rdi
callq 0x3460
cmpl $-0x1, %eax
je 0x1232b
leaq 0x24(%rsp), %rdi
callq 0x3460
cmpl $-0x1, %eax
je 0x12339
callq 0x30a0
cmpl $-0x1, %eax
je 0x12345
movl %eax, 0x30(%rsp)
testl %eax, %eax
je 0x12376
movl $0x0, 0x10(%rsp)
movl 0x14(%rsp), %edi
movl %edi, 0x34(%rsp)
movl 0x24(%rsp), %ebp
movl %ebp, 0xc(%rsp)
callq 0x12480
movl %ebp, %edi
callq 0x12480
movl 0x18(%rsp), %edi
callq 0x3660
movl 0x28(%rsp), %edi
callq 0x3660
testq %r12, %r12
movl 0x20(%rsp), %ebx
je 0x120af
leaq 0x4517(%rip), %rdx      # 0x165b5
movl %ebx, %edi
movl $0xffffff38, %esi       # imm = 0xFFFFFF38
movq %r12, %rcx
xorl %eax, %eax
callq 0x14209
cmpl $0x0, 0x2c(%rsp)
je 0x120d0
leaq 0x44f8(%rip), %rdx      # 0x165b5
movl %ebx, %edi
movl $0xffffff39, %esi       # imm = 0xFFFFFF39
movq 0x38(%rsp), %rcx
xorl %eax, %eax
callq 0x14209
movl $0x2, %ebx
xorl %r12d, %r12d
leaq 0xc(%rsp), %r14
testl %ebx, %ebx
jle 0x12237
xorps %xmm0, %xmm0
movaps %xmm0, 0xc0(%rsp)
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)
xorl %edi, %edi
movb $0x1, %al
leaq 0x34(%rsp), %rcx
movl (%rcx), %ecx
testl %ecx, %ecx
je 0x12155
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, 0x50(%rsp,%rcx,8)
movq %r14, %rcx
testb $0x1, %al
movl $0x0, %eax
jne 0x12128
incl %edi
movq $0x0, 0x40(%rsp)
movq $0x7a120, 0x48(%rsp)    # imm = 0x7A120
leaq 0x50(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
leaq 0x40(%rsp), %r8
callq 0x3330
cmpl $-0x1, %eax
je 0x120dd
movl %ebx, 0x1c(%rsp)
movb $0x1, %bl
xorl %r13d, %r13d
leaq 0x34(%rsp), %r15
movl (%r15), %edi
testl %edi, %edi
je 0x121fc
leal 0x3f(%rdi), %eax
testl %edi, %edi
cmovnsl %edi, %eax
sarl $0x6, %eax
cltq
movq 0x50(%rsp,%rax,8), %rax
btq %rdi, %rax
jae 0x121fc
leal 0x1(%r12), %ebp
movl $0x1fff, %edx           # imm = 0x1FFF
leaq 0xd0(%rsp), %r14
movq %r14, %rsi
callq 0x3490
testq %rax, %rax
jle 0x12201
movb $0x0, 0xd0(%rsp,%rax)
movl 0x20(%rsp), %edi
movl %r13d, %esi
movl %r12d, %edx
movq %r14, %rcx
movl %eax, %r8d
callq 0x13dea
jmp 0x12216
movl %r12d, %ebp
jmp 0x1221b
callq 0x3050
cmpl $0xb, (%rax)
je 0x12216
movl $0x0, (%r15)
decl 0x1c(%rsp)
leaq 0xc(%rsp), %r14
movl $0x1, %r13d
movq %r14, %r15
movl %ebp, %r12d
testb $0x1, %bl
movl $0x0, %ebx
jne 0x1219f
jmp 0x1223e
movl %ebx, 0x1c(%rsp)
movl %r12d, %ebp
movl $0x0, 0x10(%rsp)
xorl %edx, %edx
movl 0x1c(%rsp), %ebx
testl %ebx, %ebx
setg %dl
movl 0x30(%rsp), %edi
leaq 0x10(%rsp), %rsi
callq 0x3280
movl %ebp, %r12d
testl %eax, %eax
je 0x120dd
cmpl 0x30(%rsp), %eax
jne 0x1235d
movl 0x14(%rsp), %edi
callq 0x3660
movl 0x24(%rsp), %edi
callq 0x3660
movl 0x10(%rsp), %ebp
movl %ebp, %ecx
andl $0x7f, %ecx
movl %ecx, %eax
shll $0x18, %eax
addl $0x1000000, %eax        # imm = 0x1000000
cmpl $0x2000000, %eax        # imm = 0x2000000
movl 0x20(%rsp), %r14d
jl 0x122d1
leaq 0x4fd0(%rip), %rdx      # 0x1727c
movl %r14d, %edi
movl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
movq 0x38(%rsp), %r8
xorl %eax, %eax
callq 0x14209
movabsq $0x100000000, %rbx      # imm = 0x100000000
movl $0x1, %ebp
jmp 0x1230c
cmpl $0x0, 0x2c(%rsp)
setne %al
shrl $0x8, %ebp
andl $0xff, %ebp
sete %cl
orb %al, %cl
je 0x122ed
xorl %ebx, %ebx
jmp 0x1230c
leaq 0x4faf(%rip), %rdx      # 0x172a3
xorl %ebx, %ebx
movl %r14d, %edi
movl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
movl %ebp, %ecx
movq 0x38(%rsp), %r8
xorl %eax, %eax
callq 0x14209
movl %r14d, %edi
callq 0x1414d
movl %ebp, %eax
orq %rbx, %rax
addq $0x20d8, %rsp           # imm = 0x20D8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x4ef9(%rip), %rdi      # 0x1722b
callq 0x32a0
jmp 0x12354
leaq 0x14(%rsp), %rdi
callq 0x38b0
jmp 0x12354
leaq 0x14(%rsp), %rdi
leaq 0x24(%rsp), %rsi
callq 0x3872
movl $0x1, %eax
xorl %ebx, %ebx
jmp 0x12316
movl $0x1, 0x10(%rsp)
leaq 0x4f01(%rip), %rdi      # 0x1726d
callq 0x32a0
jmp 0x12274
leaq 0x4eba(%rip), %rax      # 0x17237
movq %rax, 0x50(%rsp)
leaq 0x4eb6(%rip), %rax      # 0x1723f
movq %rax, 0x58(%rsp)
movq 0x38(%rsp), %rax
movq %rax, 0x60(%rsp)
movq $0x0, 0x68(%rsp)
movl 0x14(%rsp), %edi
callq 0x3660
movl 0x24(%rsp), %edi
callq 0x3660
movl 0x18(%rsp), %edi
movl $0x1, %esi
callq 0x3310
cmpl $-0x1, %eax
jne 0x123d2
leaq 0x4e75(%rip), %rdi      # 0x17242
callq 0x32a0
movl 0x28(%rsp), %edi
movl $0x2, %esi
callq 0x3310
cmpl $-0x1, %eax
jne 0x123f1
leaq 0x4e56(%rip), %rdi      # 0x17242
callq 0x32a0
movl 0x18(%rsp), %edi
callq 0x3660
movl 0x28(%rsp), %edi
callq 0x3660
leaq 0xd0(%rsp), %rbx
movq %rbx, %rdi
callq 0x30d0
movl $0x1, %edi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x3180
testl %eax, %eax
je 0x12432
leaq 0x4e21(%rip), %rdi      # 0x1724e
callq 0x32a0
testl %ebp, %ebp
jle 0x1245b
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 0x1243f
leaq 0x4dd5(%rip), %rdi      # 0x17237
leaq 0x50(%rsp), %rsi
callq 0x32e0
cmpl $-0x1, %eax
jne 0x1247b
movl $0x1, %edi
callq 0x33f0
callq 0x31c0