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.

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