| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 3e4ebac commit 45b9130
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -74,5 +74,65 @@ public void ReInitialize() | |||
| 74 | 74 | } | |
| 75 | 75 | PythonEngine.Shutdown(); | |
| 76 | 76 | } | |
| 77 | + | ||
| 78 | + [Test] | ||
| 79 | + public void TestScopeIsShutdown() | ||
| 80 | + { | ||
| 81 | + PythonEngine.Initialize(); | ||
| 82 | + var scope = PyScopeManager.Global.Create("test"); | ||
| 83 | + PythonEngine.Shutdown(); | ||
| 84 | + Assert.That(PyScopeManager.Global.Contains("test"), Is.False); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /// <summary> | ||
| 88 | + /// Helper for testing the shutdown handlers. | ||
| 89 | + /// </summary> | ||
| 90 | + int shutdown_count = 0; | ||
| 91 | + void OnShutdownIncrement() | ||
| 92 | + { | ||
| 93 | + shutdown_count++; | ||
| 94 | + } | ||
| 95 | + void OnShutdownDouble() | ||
| 96 | + { | ||
| 97 | + shutdown_count *= 2; | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + /// <summary> | ||
| 101 | + /// Test the shutdown handlers. | ||
| 102 | + /// </summary> | ||
| 103 | + [Test] | ||
| 104 | + public void ShutdownHandlers() | ||
| 105 | + { | ||
| 106 | + // Test we can run one shutdown handler. | ||
| 107 | + shutdown_count = 0; | ||
| 108 | + PythonEngine.Initialize(); | ||
| 109 | + PythonEngine.AddShutdownHandler(OnShutdownIncrement); | ||
| 110 | + PythonEngine.Shutdown(); | ||
| 111 | + Assert.That(shutdown_count, Is.EqualTo(1)); | ||
| 112 | + | ||
| 113 | + // Test we can run multiple shutdown handlers in the right order. | ||
| 114 | + shutdown_count = 4; | ||
| 115 | + PythonEngine.Initialize(); | ||
| 116 | + PythonEngine.AddShutdownHandler(OnShutdownIncrement); | ||
| 117 | + PythonEngine.AddShutdownHandler(OnShutdownDouble); | ||
| 118 | + PythonEngine.Shutdown(); | ||
| 119 | + // Correct: 4 * 2 + 1 = 9 | ||
| 120 | + // Wrong: (4 + 1) * 2 = 10 | ||
| 121 | + Assert.That(shutdown_count, Is.EqualTo(9)); | ||
| 122 | + | ||
| 123 | + // Test we can remove shutdown handlers, handling duplicates. | ||
| 124 | + shutdown_count = 4; | ||
| 125 | + PythonEngine.Initialize(); | ||
| 126 | + PythonEngine.AddShutdownHandler(OnShutdownIncrement); | ||
| 127 | + PythonEngine.AddShutdownHandler(OnShutdownIncrement); | ||
| 128 | + PythonEngine.AddShutdownHandler(OnShutdownDouble); | ||
| 129 | + PythonEngine.AddShutdownHandler(OnShutdownIncrement); | ||
| 130 | + PythonEngine.AddShutdownHandler(OnShutdownDouble); | ||
| 131 | + PythonEngine.RemoveShutdownHandler(OnShutdownDouble); | ||
| 132 | + PythonEngine.Shutdown(); | ||
| 133 | + // Correct: (4 + 1) * 2 + 1 + 1 = 12 | ||
| 134 | + // Wrong: (4 * 2) + 1 + 1 + 1 = 11 | ||
| 135 | + Assert.That(shutdown_count, Is.EqualTo(12)); | ||
| 136 | + } | ||
| 77 | 137 | } | |
| 78 | 138 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -168,6 +168,16 @@ public static void Initialize(IEnumerable<string> args, bool setSysArgv = true) | |||
| 168 | 168 | initialized = true; | |
| 169 | 169 | Exceptions.Clear(); | |
| 170 | 170 | ||
| 171 | + // Make sure we clean up properly on app domain unload. | ||
| 172 | + AppDomain.CurrentDomain.DomainUnload += OnDomainUnload; | ||
| 173 | + | ||
| 174 | + // Remember to shut down the runtime. | ||
| 175 | + AddShutdownHandler(Runtime.Shutdown); | ||
| 176 | + | ||
| 177 | + // The global scope gets used implicitly quite early on, remember | ||
| 178 | + // to clear it out when we shut down. | ||
| 179 | + AddShutdownHandler(PyScopeManager.Global.Clear); | ||
| 180 | + | ||
| 171 | 181 | if (setSysArgv) | |
| 172 | 182 | { | |
| 173 | 183 | Py.SetArgv(args); | |
@@ -220,9 +230,6 @@ public static void Initialize(IEnumerable<string> args, bool setSysArgv = true) | |||
| 220 | 230 | { | |
| 221 | 231 | locals.Dispose(); | |
| 222 | 232 | } | |
| 223 | - | ||
| 224 | - // Make sure we clean up properly on app domain unload. | ||
| 225 | - AppDomain.CurrentDomain.DomainUnload += OnDomainUnload; | ||
| 226 | 233 | } | |
| 227 | 234 | } | |
| 228 | 235 | ||
@@ -302,21 +309,86 @@ public static void Shutdown() | |||
| 302 | 309 | { | |
| 303 | 310 | if (initialized) | |
| 304 | 311 | { | |
| 305 | - PyScopeManager.Global.Clear(); | ||
| 312 | + // If the shutdown handlers trigger a domain unload, | ||
| 313 | + // don't call shutdown again. | ||
| 314 | + AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload; | ||
| 315 | + | ||
| 316 | + ExecuteShutdownHandlers(); | ||
| 317 | + | ||
| 306 | 318 | Marshal.FreeHGlobal(_pythonHome); | |
| 307 | 319 | _pythonHome = IntPtr.Zero; | |
| 308 | 320 | Marshal.FreeHGlobal(_programName); | |
| 309 | 321 | _programName = IntPtr.Zero; | |
| 310 | 322 | Marshal.FreeHGlobal(_pythonPath); | |
| 311 | 323 | _pythonPath = IntPtr.Zero; | |
| 312 | 324 | ||
| 313 | - Runtime.Shutdown(); | ||
| 314 | - | ||
| 315 | - AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload; | ||
| 316 | 325 | initialized = false; | |
| 317 | 326 | } | |
| 318 | 327 | } | |
| 319 | 328 | ||
| 329 | + /// <summary> | ||
| 330 | + /// Called when the engine is shut down. | ||
| 331 | + /// | ||
| 332 | + /// Shutdown handlers are run in reverse order they were added, so that | ||
| 333 | + /// resources available when running a shutdown handler are the same as | ||
| 334 | + /// what was available when it was added. | ||
| 335 | + /// </summary> | ||
| 336 | + public delegate void ShutdownHandler(); | ||
| 337 | + | ||
| 338 | + static List<ShutdownHandler> ShutdownHandlers = new List<ShutdownHandler>(); | ||
| 339 | + | ||
| 340 | + /// <summary> | ||
| 341 | + /// Add a function to be called when the engine is shut down. | ||
| 342 | + /// | ||
| 343 | + /// Shutdown handlers are executed in the opposite order they were | ||
| 344 | + /// added, so that you can be sure that everything that was initialized | ||
| 345 | + /// when you added the handler is still initialized when you need to shut | ||
| 346 | + /// down. | ||
| 347 | + /// | ||
| 348 | + /// If the same shutdown handler is added several times, it will be run | ||
| 349 | + /// several times. | ||
| 350 | + /// | ||
| 351 | + /// Don't add shutdown handlers while running a shutdown handler. | ||
| 352 | + /// </summary> | ||
| 353 | + public static void AddShutdownHandler(ShutdownHandler handler) | ||
| 354 | + { | ||
| 355 | + ShutdownHandlers.Add(handler); | ||
| 356 | + } | ||
| 357 | + | ||
| 358 | + /// <summary> | ||
| 359 | + /// Remove a shutdown handler. | ||
| 360 | + /// | ||
| 361 | + /// If the same shutdown handler is added several times, only the last | ||
| 362 | + /// one is removed. | ||
| 363 | + /// | ||
| 364 | + /// Don't remove shutdown handlers while running a shutdown handler. | ||
| 365 | + /// </summary> | ||
| 366 | + public static void RemoveShutdownHandler(ShutdownHandler handler) | ||
| 367 | + { | ||
| 368 | + for (int index = ShutdownHandlers.Count - 1; index >= 0; --index) | ||
| 369 | + { | ||
| 370 | + if (ShutdownHandlers[index] == handler) | ||
| 371 | + { | ||
| 372 | + ShutdownHandlers.RemoveAt(index); | ||
| 373 | + break; | ||
| 374 | + } | ||
| 375 | + } | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + /// <summary> | ||
| 379 | + /// Run all the shutdown handlers. | ||
| 380 | + /// | ||
| 381 | + /// They're run in opposite order they were added. | ||
| 382 | + /// </summary> | ||
| 383 | + static void ExecuteShutdownHandlers() | ||
| 384 | + { | ||
| 385 | + while(ShutdownHandlers.Count > 0) | ||
| 386 | + { | ||
| 387 | + var handler = ShutdownHandlers[ShutdownHandlers.Count - 1]; | ||
| 388 | + ShutdownHandlers.RemoveAt(ShutdownHandlers.Count - 1); | ||
| 389 | + handler(); | ||
| 390 | + } | ||
| 391 | + } | ||
| 320 | 392 | ||
| 321 | 393 | /// <summary> | |
| 322 | 394 | /// AcquireLock Method | |
| Back | FazBrowse Home | New Git URL |
0 commit comments