File: CustomRuntimeManager.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (95 lines) | stat: -rw-r--r-- 4,272 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//------------------------------------------------------------------------------
// <copyright file="CustomRuntimeSuspendManager.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------

namespace System.Web.Hosting {
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Web.Util;

    // Handles calling suspend and resume methods, including issues around
    // synchronization and timeout handling.

    internal sealed class CustomRuntimeManager : ICustomRuntimeManager {

        private readonly ConcurrentDictionary<CustomRuntimeRegistration, object> _activeRegistrations = new ConcurrentDictionary<CustomRuntimeRegistration, object>();

        private List<IProcessSuspendListener> GetAllSuspendListeners() {
            List<IProcessSuspendListener> suspendListeners = new List<IProcessSuspendListener>();

            foreach (var registration in _activeRegistrations.Keys) {
                var suspendListener = registration.CustomRuntime as IProcessSuspendListener;
                if (suspendListener != null) {
                    suspendListeners.Add(suspendListener);
                }
            }

            return suspendListeners;
        }

        public ICustomRuntimeRegistrationToken Register(ICustomRuntime customRuntime) {
            CustomRuntimeRegistration registration = new CustomRuntimeRegistration(this, customRuntime);
            _activeRegistrations[registration] = null;
            return registration;
        }

        // Custom runtimes are expected to be well-behaved so will be suspended sequentially and aren't
        // subject to the 5-second timeout that normal applications are subject to.
        public Action SuspendAllCustomRuntimes() {
            var suspendListeners = GetAllSuspendListeners();
            if (suspendListeners == null || suspendListeners.Count == 0) {
                return null;
            }

            List<IProcessResumeCallback> callbacks = new List<IProcessResumeCallback>(suspendListeners.Count);
            foreach (var suspendListener in suspendListeners) {
                IProcessResumeCallback callback = null;
                try {
                    callback = suspendListener.Suspend();
                }
                catch (AppDomainUnloadedException) {
                    // There exists a race condition where a custom runtime could have been stopped (unloaded)
                    // while a call to Suspend is in progress, so AD unloads may leak out. Don't treat this
                    // as a failure; just move on.
                }

                if (callback != null) {
                    callbacks.Add(callback);
                }
            }

            return () => {
                foreach (var callback in callbacks) {
                    try {
                        callback.Resume();
                    }
                    catch (AppDomainUnloadedException) {
                        // There exists a race condition where a custom runtime could have been stopped (unloaded)
                        // while a call to Suspend is in progress, so AD unloads may leak out. Don't treat this
                        // as a failure; just move on.
                    }
                }
            };
        }

        private sealed class CustomRuntimeRegistration : ICustomRuntimeRegistrationToken {
            private readonly CustomRuntimeManager _customRuntimeManager;

            public CustomRuntimeRegistration(CustomRuntimeManager customRuntimeManager, ICustomRuntime customRuntime) {
                _customRuntimeManager = customRuntimeManager;
                CustomRuntime = customRuntime;
            }

            public ICustomRuntime CustomRuntime { get; private set; }

            public void Unregister() {
                object dummy;
                bool removed = _customRuntimeManager._activeRegistrations.TryRemove(this, out dummy);

                Debug.Assert(removed, "Entry did not exist in the dictionary; was it removed twice?");
            }
        }
    }
}