Ejemplo n.º 1
0
            public static void RemoveChildProcessState(UnixChildProcessState childProcessState)
            {
                Debug.Assert(childProcessState._refCount == 0);

                lock (ChildProcessState)
                {
                    ChildProcessState.Remove(childProcessState.Token);
                }
            }
Ejemplo n.º 2
0
            public static UnixChildProcessState Create(UnixChildProcessStateHelper helper, bool allowSignal)
            {
                var token = IssueProcessToken();
                var state = new UnixChildProcessState(helper, token, allowSignal);

                lock (ChildProcessState)
                {
                    ChildProcessState.Add(token, state);
                }
                return(state);
Ejemplo n.º 3
0
        public IChildProcessStateHolder SpawnProcess(
            ref ChildProcessStartInfoInternal startInfo,
            string resolvedPath,
            SafeHandle stdIn,
            SafeHandle stdOut,
            SafeHandle stdErr)
        {
            var arguments            = startInfo.Arguments;
            var environmentVariables = startInfo.EnvironmentVariables;
            var workingDirectory     = startInfo.WorkingDirectory;

            Span <int> fds         = stackalloc int[3];
            int        handleCount = 0;
            uint       flags       = 0;

            if (stdIn != null)
            {
                fds[handleCount++] = stdIn.DangerousGetHandle().ToInt32();
                flags |= RequestFlagsRedirectStdin;
            }
            if (stdOut != null)
            {
                fds[handleCount++] = stdOut.DangerousGetHandle().ToInt32();
                flags |= RequestFlagsRedirectStdout;
            }
            if (stdErr != null)
            {
                fds[handleCount++] = stdErr.DangerousGetHandle().ToInt32();
                flags |= RequestFlagsRedirectStderr;
            }

            if (startInfo.CreateNewConsole)
            {
                flags |= RequestFlagsCreateNewProcessGroup;
            }
            else
            {
                Debug.Assert(!startInfo.AllowSignal);
            }

            // If AttachToCurrentConsole (== !startInfo.AllowSignal), leave the process running after we (the parent) exit.
            // After being orphaned (and possibly reparented to the shell), it may continue running or may be terminated by SIGTTIN/SIGTTOU.
            if (startInfo.AllowSignal)
            {
                flags |= RequestFlagsEnableAutoTermination;
            }

            using var bw = new MyBinaryWriter(InitialBufferCapacity);
            var stateHolder = UnixChildProcessState.Create(this, startInfo.AllowSignal);

            try
            {
                bw.Write(stateHolder.State.Token);
                bw.Write(flags);
                bw.Write(workingDirectory);
                bw.Write(resolvedPath);

                bw.Write((uint)(arguments.Count + 1));
                bw.Write(resolvedPath);
                foreach (var x in arguments)
                {
                    bw.Write(x);
                }

                if (!startInfo.UseCustomEnvironmentVariables)
                {
                    // Send the environment variables of this process to the helper process.
                    //
                    // NOTE: We cannot cache or detect updates to the environment block; only the runtime can.
                    //       Concurrently invoking getenv and setenv is a racy operation; therefore the runtime
                    //       employs a process-global lock.
                    //
                    //       Fortunately, the caller can take a snapshot of environment variables theirselves.
                    var processEnvVars = Environment.GetEnvironmentVariables();
                    var envVarCount    = processEnvVars.Count;
                    bw.Write((uint)envVarCount);

                    var sortedEnvVars = ArrayPool <KeyValuePair <string, string> > .Shared.Rent(envVarCount);

                    try
                    {
                        EnvironmentVariableListUtil.ToSortedKeyValuePairs(processEnvVars, sortedEnvVars);

                        foreach (var(name, value) in sortedEnvVars.AsSpan <KeyValuePair <string, string> >().Slice(0, envVarCount))
                        {
                            bw.WriteEnvironmentVariable(name, value);
                        }
                    }
                    finally
                    {
                        ArrayPool <KeyValuePair <string, string> > .Shared.Return(sortedEnvVars);
                    }
                }
                else
                {
                    bw.Write((uint)environmentVariables.Length);
                    foreach (var(name, value) in environmentVariables.Span)
                    {
                        bw.WriteEnvironmentVariable(name, value);
                    }
                }

                // Work around https://github.com/microsoft/WSL/issues/6490
                // On WSL 1, if you call recvmsg multiple times to fully receive data sent with sendmsg,
                // the fds will be duplicated for each recvmsg call.
                // Send only fixed length of of data with the fds and receive that much data with one recvmsg call.
                // That will be safer anyway.
                Span <byte> header = stackalloc byte[sizeof(uint) * 2];
                if (!BitConverter.TryWriteBytes(header, (uint)UnixHelperProcessCommand.SpawnProcess) ||
                    !BitConverter.TryWriteBytes(header.Slice(sizeof(uint)), bw.Length))
                {
                    Debug.Fail("Should never fail.");
                }

                var subchannel = _helperProcess.RentSubchannelAsync(default).AsTask().GetAwaiter().GetResult();
Ejemplo n.º 4
0
 public UnixChildProcessStateHolder(UnixChildProcessState state)
 {
     _state = state;
 }