// File: /workspace/github_c_makefile_star2_O2/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, %r13
movl %r8d, 0x24(%rsp)
movl %ecx, %ebx
movq %rdx, %r14
movl %esi, %r12d
movq %rdi, %r15
leaq 0xc(%rsp), %rdi
callq 0x3460
cmpl $-0x1, %eax
je 0x10c37
leaq 0x18(%rsp), %rdi
callq 0x3460
cmpl $-0x1, %eax
je 0x10c45
callq 0x30a0
cmpl $-0x1, %eax
je 0x10c60
movl %eax, 0x28(%rsp)
testl %eax, %eax
je 0x10cb0
andl $0x0, 0x14(%rsp)
movl 0xc(%rsp), %edi
movl %edi, 0x30(%rsp)
movl 0x18(%rsp), %ebp
movl %ebp, 0x34(%rsp)
callq 0x10dad
movl %ebp, %edi
callq 0x10dad
movl 0x10(%rsp), %edi
callq 0x3660
movl 0x1c(%rsp), %edi
callq 0x3660
testq %r13, %r13
je 0x10a19
leaq 0x3bab(%rip), %rdx      # 0x145b3
movl %ebx, %edi
movl $0xffffff38, %esi       # imm = 0xFFFFFF38
movq %r13, %rcx
xorl %eax, %eax
callq 0x1284e
cmpl $0x0, 0x24(%rsp)
je 0x10a38
leaq 0x3b8c(%rip), %rdx      # 0x145b3
movl %ebx, %edi
movl $0xffffff39, %esi       # imm = 0xFFFFFF39
movq %r15, %rcx
xorl %eax, %eax
callq 0x1284e
movq %r15, 0x38(%rsp)
movl %ebx, 0x2c(%rsp)
pushq $0x2
popq %rax
movl %eax, 0x20(%rsp)
xorl %r12d, %r12d
pushq $0x40
popq %rbp
leaq 0xd0(%rsp), %r14
pushq $0x1
popq %r15
movl 0x28(%rsp), %ebx
cmpl $0x0, 0x20(%rsp)
jle 0x10b5c
xorl %eax, %eax
cmpq $0x10, %rax
je 0x10a7c
andq $0x0, 0x50(%rsp,%rax,8)
incq %rax
jmp 0x10a6b
xorl %esi, %esi
xorl %edi, %edi
cmpq $0x2, %rsi
je 0x10ab0
movl 0x30(%rsp,%rsi,4), %ecx
testl %ecx, %ecx
je 0x10aab
cmpl %edi, %ecx
cmovgl %ecx, %edi
movl %ecx, %eax
cltd
idivl %ebp
movslq %eax, %rdx
shll $0x6, %eax
subl %eax, %ecx
movq %r15, %rax
shlq %cl, %rax
orq %rax, 0x50(%rsp,%rdx,8)
incq %rsi
jmp 0x10a80
incl %edi
andq $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 0x10a5e
xorl %ebx, %ebx
cmpq $0x2, %rbx
je 0x10b58
movl 0x30(%rsp,%rbx,4), %edi
testl %edi, %edi
je 0x10b38
movl %edi, %eax
cltd
idivl %ebp
cltq
movq 0x50(%rsp,%rax,8), %rax
btq %rdx, %rax
jae 0x10b38
leal 0x1(%r12), %r13d
movl $0x1fff, %edx           # imm = 0x1FFF
movq %r14, %rsi
callq 0x3490
testq %rax, %rax
jle 0x10b43
xorl %esi, %esi
cmpq $0x1, %rbx
sete %sil
movb $0x0, 0xd0(%rsp,%rax)
movl 0x2c(%rsp), %edi
movl %r12d, %edx
movq %r14, %rcx
movl %eax, %r8d
callq 0x124e5
jmp 0x10b3b
movl %r12d, %r13d
incq %rbx
movl %r13d, %r12d
jmp 0x10adb
callq 0x3050
cmpl $0xb, (%rax)
je 0x10b3b
andl $0x0, 0x30(%rsp,%rbx,4)
decl 0x20(%rsp)
jmp 0x10b3b
movl 0x28(%rsp), %ebx
andl $0x0, 0x14(%rsp)
xorl %edx, %edx
cmpl $0x0, 0x20(%rsp)
setg %dl
movl %ebx, %edi
leaq 0x14(%rsp), %rsi
callq 0x3280
testl %eax, %eax
je 0x10a5e
cmpl %ebx, %eax
jne 0x10c97
movl 0xc(%rsp), %edi
callq 0x3660
movl 0x18(%rsp), %edi
callq 0x3660
movl 0x14(%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 0x2c(%rsp), %r14d
movq 0x38(%rsp), %r8
jl 0x10be2
leaq 0x46b0(%rip), %rdx      # 0x15274
movl %r14d, %edi
movl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
xorl %eax, %eax
callq 0x1284e
movabsq $0x100000000, %rbx      # imm = 0x100000000
pushq $0x1
popq %rbp
jmp 0x10c18
cmpl $0x0, 0x24(%rsp)
setne %al
shrl $0x8, %ebp
andl $0xff, %ebp
sete %cl
orb %al, %cl
je 0x10bfe
xorl %ebx, %ebx
jmp 0x10c18
leaq 0x4696(%rip), %rdx      # 0x1529b
xorl %ebx, %ebx
movl %r14d, %edi
movl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
movl %ebp, %ecx
xorl %eax, %eax
callq 0x1284e
movl %r14d, %edi
callq 0x127d3
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 0x45e5(%rip), %rdi      # 0x15223
callq 0x32a0
jmp 0x10c90
leaq 0x45d7(%rip), %rdi      # 0x15223
callq 0x32a0
movl 0xc(%rsp), %edi
callq 0x3660
movl 0x10(%rsp), %edi
jmp 0x10c8b
leaq 0x45f2(%rip), %rdi      # 0x15259
callq 0x32a0
movl 0xc(%rsp), %edi
callq 0x3660
movl 0x18(%rsp), %edi
callq 0x3660
movl 0x10(%rsp), %edi
callq 0x3660
movl 0x1c(%rsp), %edi
callq 0x3660
pushq $0x1
popq %rax
xorl %ebx, %ebx
jmp 0x10c22
movl $0x1, 0x14(%rsp)
leaq 0x45bf(%rip), %rdi      # 0x15265
callq 0x32a0
jmp 0x10b87
leaq 0x4578(%rip), %rax      # 0x1522f
movq %rax, 0x50(%rsp)
leaq 0x4574(%rip), %rax      # 0x15237
movq %rax, 0x58(%rsp)
movq %r15, 0x60(%rsp)
andq $0x0, 0x68(%rsp)
movl 0xc(%rsp), %edi
callq 0x3660
movl 0x18(%rsp), %edi
callq 0x3660
movl 0x10(%rsp), %edi
pushq $0x1
popq %rsi
callq 0x3310
cmpl $-0x1, %eax
jne 0x10d02
leaq 0x453d(%rip), %rdi      # 0x1523a
callq 0x32a0
movl 0x1c(%rsp), %edi
pushq $0x2
popq %rsi
callq 0x3310
cmpl $-0x1, %eax
jne 0x10d1f
leaq 0x4520(%rip), %rdi      # 0x1523a
callq 0x32a0
movl 0x10(%rsp), %edi
callq 0x3660
movl 0x1c(%rsp), %edi
callq 0x3660
leaq 0xd0(%rsp), %rbx
movq %rbx, %rdi
callq 0x30d0
xorl %r15d, %r15d
pushq $0x1
popq %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x3180
testl %eax, %eax
je 0x10d61
leaq 0x44ea(%rip), %rdi      # 0x15246
callq 0x32a0
testl %r12d, %r12d
cmovlel %r15d, %r12d
shlq $0x4, %r12
pushq $0x1
popq %rbx
cmpq %r15, %r12
je 0x10d8a
movq (%r14,%r15), %rdi
movq 0x8(%r14,%r15), %rsi
movl %ebx, %edx
callq 0x3510
addq $0x10, %r15
jmp 0x10d6f
leaq 0x449e(%rip), %rdi      # 0x1522f
leaq 0x50(%rsp), %rsi
callq 0x32e0
cmpl $-0x1, %eax
jne 0x10da8
pushq $0x1
popq %rdi
callq 0x33f0
callq 0x31c0