You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
4.2 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using IPA.Logging;
  8. namespace IPA.Utilities
  9. {
  10. /// <summary>
  11. /// Provides utilities for managing various critical sections.
  12. /// </summary>
  13. public static class CriticalSection
  14. {
  15. internal static void Configure()
  16. {
  17. Logger.log.Debug("Configuring exit handlers");
  18. ResetExitHandlers();
  19. }
  20. #region Execute section
  21. private static readonly Win32.EventHandler registeredHandler = HandleExit;
  22. internal static void ResetExitHandlers()
  23. {
  24. Win32.SetConsoleCtrlHandler(registeredHandler, false);
  25. Win32.SetConsoleCtrlHandler(registeredHandler, true);
  26. }
  27. private static partial class Win32 {
  28. [DllImport("Kernel32")]
  29. public static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
  30. public enum CtrlType
  31. {
  32. CTRL_C_EVENT = 0,
  33. CTRL_BREAK_EVENT = 1,
  34. CTRL_CLOSE_EVENT = 2,
  35. CTRL_LOGOFF_EVENT = 5,
  36. CTRL_SHUTDOWN_EVENT = 6
  37. }
  38. public delegate bool EventHandler(CtrlType sig);
  39. }
  40. private static Win32.EventHandler _handler = null;
  41. private static bool HandleExit(Win32.CtrlType type)
  42. {
  43. if (_handler != null)
  44. return _handler(type);
  45. return false;
  46. }
  47. private static volatile bool exitRecieved = false;
  48. /// <summary>
  49. /// Enters a critical execution section. Does not nest.
  50. /// </summary>
  51. /// <note>
  52. /// During a critical execution section, the program must execute until the end of the section before
  53. /// exiting. If an exit signal is recieved during the section, it will be canceled, and the process
  54. /// will terminate at the end of the section.
  55. /// </note>
  56. public static void EnterExecuteSection()
  57. {
  58. ResetExitHandlers();
  59. exitRecieved = false;
  60. _handler = sig => exitRecieved = true;
  61. }
  62. /// <summary>
  63. /// Exits a critical execution section. Does not nest.
  64. /// </summary>
  65. /// <note>
  66. /// During a critical execution section, the program must execute until the end of the section before
  67. /// exiting. If an exit signal is recieved during the section, it will be canceled, and the process
  68. /// will terminate at the end of the section.
  69. /// </note>
  70. public static void ExitExecuteSection()
  71. {
  72. _handler = null;
  73. if (exitRecieved)
  74. Environment.Exit(1);
  75. }
  76. #endregion
  77. #region GC section
  78. // i wish i could reference GC_enable and GC_disable directly
  79. [DllImport("mono-2.0-bdwgc")]
  80. private static extern void mono_unity_gc_enable();
  81. [DllImport("mono-2.0-bdwgc")]
  82. private static extern void mono_unity_gc_disable();
  83. /// <summary>
  84. /// Enters a GC critical section. Each call to this must be paired with a call to <see cref="ExitGCSection"/>.
  85. /// </summary>
  86. /// <note>
  87. /// During a GC critical section, no GCs will occur.
  88. ///
  89. /// This may throw an <see cref="EntryPointNotFoundException"/> if the build of Mono the game is running on does
  90. /// not have `mono_unity_gc_disable` exported. Use with caution.
  91. /// </note>
  92. public static void EnterGCSection()
  93. {
  94. mono_unity_gc_disable();
  95. }
  96. /// <summary>
  97. /// Exits a GC critical section. Each call to this must have a preceding call to <see cref="EnterGCSection"/>.
  98. /// </summary>
  99. /// <note>
  100. /// During a GC critical section, no GCs will occur.
  101. ///
  102. /// This may throw an <see cref="EntryPointNotFoundException"/> if the build of Mono the game is running on does
  103. /// not have `mono_unity_gc_enable` exported. Use with caution.
  104. /// </note>
  105. public static void ExitGCSection()
  106. {
  107. mono_unity_gc_enable();
  108. }
  109. #endregion
  110. }
  111. }