Esempio n. 1
0
        private async Task SubmitSnippetPostFeedback(string snippetId, string connectionId, long startTimestamp)
        {
            SnippetResult result;

            try {
                result = await hostConnector.RunSnippetAsync(snippetId);
            }
            catch (Exception ex) {
                result = new SnippetResult()
                {
                    status = SnippetStatus.InitializationError, exception = ex.Message
                };
            }

            var hubContext = GlobalHost.ConnectionManager.GetHubContext <ResultHub>();

            result.totalTime = StopwatchExtensions.GetTimestampMillis() - startTimestamp;
            hubContext.Clients.Client(connectionId).SendResult(connectionId, snippetId, result, result.status.ToHealth().ToColor());
        }
Esempio n. 2
0
        public async Task <ActionResult> SubmitRequest(string snippetId, string connectionId)
        {
            long startTimestamp = StopwatchExtensions.GetTimestampMillis();

            if (String.IsNullOrEmpty(snippetId))
            {
                return(new HttpStatusCodeResult(HttpStatusCode.BadRequest));
            }

            if (connectionId != null)
            {
                Task.Run(() => SubmitSnippetPostFeedback(snippetId, connectionId, startTimestamp)).FireAndForget();
                return(new HttpStatusCodeResult(HttpStatusCode.Accepted));
            }
            else
            {
                SnippetResult result = await hostConnector.RunSnippetAsync(snippetId);

                result.totalTime    = StopwatchExtensions.GetTimestampMillis() - startTimestamp;
                Response.StatusCode = (int)HttpStatusCode.OK;
                return(Json(new { connectionId = connectionId, message = result, newStatus = result.status.ToHealth().ToColor() }));
            }
        }
Esempio n. 3
0
        // This kind of customization (provide a custom HostSecurityManager, with custom DomainPolicy etc.)
        // is obsolete in .NET4. Setting the PermissionSet on the AppDomain (as we do here) is the right thing to do
        // See http://msdn.microsoft.com/en-us/library/ee191568(VS.100).aspx
        // and http://msdn.microsoft.com/en-us/library/bb763046(v=vs.100).aspx
        //public override HostSecurityManager HostSecurityManager {
        //   get { return new SimpleHostSecurityManager(); }
        //}

        //[SecuritySafeCritical]
        internal SnippetResult InternalRun(AppDomain appDomain, byte[] assembly, string mainTypeName, string methodName,
                                           bool runningInSandbox)
        {
            // Here we already are on the new domain
            SnippetResult result = new SnippetResult();

            try {
                // Use this "trick" to go through the standard loader path.
                // This MAY be something we want, or something to avoid

                // When loading the assembly, we need at least FileIOPermission.
                // Calling it with a full-trust stack. TODO: only what is needed
                (new PermissionSet(PermissionState.Unrestricted)).Assert();
                var clientAssembly = appDomain.Load(assembly);
                //var clientAssembly = Assembly.Load(assembly, null, SecurityContextSource.CurrentAppDomain);
                //AssemblyName an = AssemblyName.GetAssemblyName(assemblyFileName);
                //var clientAssembly = appDomain.Load(an);
                CodeAccessPermission.RevertAssert();

                //Load the MethodInfo for a method in the new Assembly. This might be a method you know, or
                //you can use Assembly.EntryPoint to get to the main function in an executable.
                var type = clientAssembly.GetTypes().Where(t => t.Name == mainTypeName || t.FullName == mainTypeName).SingleOrDefault();
                if (type == null)
                {
                    result.status = SnippetStatus.InitializationError;
                    return(result);
                }


                var monitorField = type.GetField(Pumpkin.Monitor.MonitorFieldName, BindingFlags.Public | BindingFlags.Static);
                if (monitorField != null)
                {
                    result.output = new List <string>();
                    var monitor = new Pumpkin.Monitor(result.output);
                    monitorField.SetValue(null, monitor);
                }

                // To allow code to invoke any nonpublic member: Your code must be granted ReflectionPermission with the ReflectionPermissionFlag.MemberAccess flag
                // To allow code to invoke any nonpublic member, as long as the grant set of the assembly that contains the invoked member is
                // the same as, or a subset of, the grant set of the assembly that contains the invoking code:
                // Your code must be granted ReflectionPermission with the ReflectionPermissionFlag.RestrictedMemberAccess flag.
                // See http://msdn.microsoft.com/en-us/library/stfy7tfc%28v=vs.110%29.aspx
                var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
                if (runningInSandbox)
                {
                    bindingFlags = BindingFlags.Public | BindingFlags.Static;
                }

                var target = type.GetMethod(methodName, bindingFlags);
                if (target == null)
                {
                    result.status = SnippetStatus.InitializationError;
                    return(result);
                }

                //Now invoke the method.
                target.Invoke(null, null);
                result.status = SnippetStatus.Success;
            }
            catch (TargetInvocationException ex) {
                result.exception = (ex.InnerException == null ? ex.Message : ex.InnerException.Message);

                // When we print informations from a SecurityException extra information can be printed if we are
                //calling it with a full-trust stack.
                (new PermissionSet(PermissionState.Unrestricted)).Assert();
                System.Diagnostics.Debug.WriteLine("Exception caught: =================" +
                                                   result.exception.ToString() +
                                                   "===================================");
                CodeAccessPermission.RevertAssert();

                result.status = SnippetStatus.ExecutionError;
            }
            catch (Exception ex) {
                (new PermissionSet(PermissionState.Unrestricted)).Assert();
                System.Diagnostics.Debug.WriteLine("Exception caught: =================" +
                                                   ex.ToString() +
                                                   "===================================");
                CodeAccessPermission.RevertAssert();
                result.exception = ex.Message;
                result.status    = SnippetStatus.ExecutionError;
            }
            return(result);
        }
Esempio n. 4
0
        private Thread CreateDomainThread(int threadIndex)
        {
            System.Diagnostics.Debug.WriteLine("CreateDomainThread: " + threadIndex);

            var myPoolDomain = poolDomains[threadIndex];

            var thread = new Thread(() => {
                Interlocked.Increment(ref numberOfThreadsInPool);
                // Here we enforce the "one domain, one thread" relationship
                try {
                    var appDomain = AppDomainHelpers.CreateSandbox("Host Sandbox");
                    var manager   = (SimpleHostAppDomainManager)appDomain.DomainManager;

                    lock (poolLock) {
                        myPoolDomain.domainId = appDomain.Id;
                    }

                    while (!snippetsQueue.IsCompleted)
                    {
                        defaultDomainManager.ResetContextFor(myPoolDomain);

                        // And here is were we "rent" one AppDomain and use it to run a snippet
                        SnippetInfo snippetToRun = null;
                        try {
                            snippetToRun = snippetsQueue.Take();
                        }
                        catch (InvalidOperationException) {
                            // Someone called "complete". No more snippets in this process.
                            // We want to exit the pool.
                            return;
                        }

                        if (snippetToRun != null)
                        {
                            System.Diagnostics.Debug.WriteLine("Starting snippet '" + snippetToRun.methodName + "' in domain " + myPoolDomain.domainId);

                            SnippetResult result = new SnippetResult();
                            bool recycleDomain   = false;

                            try {
                                Interlocked.Increment(ref myPoolDomain.numberOfUsages);
                                // Record when we started
                                long startTimestamp = StopwatchExtensions.GetTimestampMillis();
                                System.Diagnostics.Debug.WriteLine("Starting execution at " + startTimestamp);
                                Thread.VolatileWrite(ref myPoolDomain.timeOfSubmission, startTimestamp);

                                // Thread transitions into the AppDomain
                                // This function DOES NOT throw
                                result = manager.InternalRun(appDomain, snippetToRun.assemblyFile, snippetToRun.mainTypeName, snippetToRun.methodName, true);


                                // ...back to the main AppDomain
                                Debug.Assert(AppDomain.CurrentDomain.IsDefaultAppDomain());
                                long currentTime     = StopwatchExtensions.GetTimestampMillis();
                                result.executionTime = currentTime - Thread.VolatileRead(ref myPoolDomain.timeOfSubmission);
                                // Flag it as "not executing"
                                Thread.VolatileWrite(ref myPoolDomain.timeOfSubmission, 0);
                            }
                            catch (ThreadAbortException ex) {
                                // Someone called abort on us.
                                result.exception = ex.Message;

                                // It may be possible to use this domain again, otherwise we will recycle
                                if (Object.Equals(ex.ExceptionState, timeoutAbortToken))
                                {
                                    // The abort was issued by us because we timed out
                                    System.Diagnostics.Debug.WriteLine("Thread Abort due to timeout");
                                    result.status = SnippetStatus.Timeout;
                                }
                                else if (Object.Equals(ex.ExceptionState, threadsExaustedAbortToken))
                                {
                                    System.Diagnostics.Debug.WriteLine("Thread Abort due to thread exaustion");
                                    result.status = SnippetStatus.ResourceError;
                                }
                                else
                                {
                                    // If it wasn't us, give us time to record the result; we will recycle (unload) the domain
                                    System.Diagnostics.Debug.WriteLine("Thread Abort due to external factors");
                                    result.status = SnippetStatus.CriticalError;
                                    recycleDomain = true;
                                }

                                // Give us time to record the result; if needed, we will recycle (unload) the domain later
                                Thread.ResetAbort();
                            }
                            catch (Exception ex) {
                                result.exception = ex.Message;
                                // Check if someone is misbehaving, throwing something else to "mask" the TAE
                                if (Thread.CurrentThread.ThreadState == System.Threading.ThreadState.AbortRequested)
                                {
                                    result.status = SnippetStatus.CriticalError;
                                    recycleDomain = true;

                                    // Give us time to record the result; we will recycle (unload) the domain
                                    Thread.ResetAbort();
                                }
                                else
                                {
                                    result.status = SnippetStatus.ExecutionError;
                                }
                            }
                            // "Although C# only allows you to throw objects of type Exception and types deriving from it,
                            // other languages don’t have any such restriction."
                            // http://weblogs.asp.net/kennykerr/introduction-to-msil-part-5-exception-handling
                            // It turns out this is no longer necessary
                            // http://blogs.msdn.com/b/jmanning/archive/2005/09/16/469091.aspx
                            // catch { }

                            // No need to catch StackOverflowException; the Host will escalate to a (rude) domain unload
                            // for us
                            // TODO: check that AppDomain.DomainUnload is called anyway!

                            // Before looping, check if we are OK; we reuse the domain only if we are not leaking
                            int threadsInDomain = defaultDomainManager.GetThreadCount(appDomain.Id);
                            int memoryUsage     = defaultDomainManager.GetMemoryUsage(appDomain.Id);

                            System.Diagnostics.Debug.WriteLine("============= AppDomain {0} =============", appDomain.Id);
                            System.Diagnostics.Debug.WriteLine("Finished in: {0}", result.executionTime);
                            System.Diagnostics.Debug.WriteLine("Status: {0}", result.status);
                            if (result.exception != null)
                            {
                                System.Diagnostics.Debug.WriteLine("Exception: " + result.exception);
                            }
                            System.Diagnostics.Debug.WriteLine("Threads: {0}", threadsInDomain);
                            System.Diagnostics.Debug.WriteLine("Memory: {0}", memoryUsage);
                            System.Diagnostics.Debug.WriteLine("========================================");

                            if (threadsInDomain > 1)
                            {
                                // The snippet is leaking threads

                                // Flag snippet as "leaking"
                                result.status = SnippetStatus.CriticalError;
                                System.Diagnostics.Debug.WriteLine("Leaking snippet");

                                recycleDomain = true;
                            }
                            else if (MaxReuse > 0 && myPoolDomain.numberOfUsages >= MaxReuse)
                            {
                                System.Diagnostics.Debug.WriteLine("Domain too old");

                                // Same if the domain is too old
                                recycleDomain = true;
                            }

                            // Return the result to the caller
                            if (!String.IsNullOrEmpty(snippetToRun.submissionId))
                            {
                                var completion = submissionMap[snippetToRun.submissionId];
                                // TCS is thread-safe (can be called cross-thread)
                                completion.TrySetResult(result);
                            }

                            if (recycleDomain)
                            {
                                System.Diagnostics.Debug.WriteLine("Recycling domain...");
                                RecycleDomain(threadIndex);
                            }
                            else
                            {
                                // Otherwise, ensure that what was allocated by the snippet is freed
                                GC.Collect();
                                System.Diagnostics.Debug.WriteLine("MonitoringSurvivedMemorySize {0}", appDomain.MonitoringSurvivedMemorySize);
                                System.Diagnostics.Debug.WriteLine("MonitoringTotalAllocatedMemorySize {0}", appDomain.MonitoringTotalAllocatedMemorySize);
                                System.Diagnostics.Debug.WriteLine("MonitoringTotalProcessorTime {0}", appDomain.MonitoringTotalProcessorTime);
                            }
                        }
                    }
                }
                catch (Exception ex) {
                    System.Diagnostics.Debug.WriteLine("Exception caught:\n" + ex.ToString());
                    RecycleDomain(threadIndex);
                }
            });

            thread.Name             = "DomainPool thread " + threadIndex;
            myPoolDomain.mainThread = thread;
            thread.Priority         = ThreadPriority.BelowNormal;
            return(thread);
        }