dead.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /**
  2. * @file dead.h
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * This file is part of BadVPN.
  8. *
  9. * BadVPN is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2
  11. * as published by the Free Software Foundation.
  12. *
  13. * BadVPN is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. *
  22. * @section DESCRIPTION
  23. *
  24. * Dead mechanism definitions.
  25. *
  26. * The dead mechanism is a way for a piece of code to detect whether some
  27. * specific event has occured during some operation (usually during calling
  28. * a user-provided handler function), without requiring access to memory
  29. * that might no longer be available because of the event.
  30. *
  31. * It works somehow like that:
  32. *
  33. * First a dead variable ({@link dead_t}) is allocated somewhere, and
  34. * initialized with {@link DEAD_INIT}, e.g.:
  35. * DEAD_INIT(dead);
  36. *
  37. * When the event that needs to be caught occurs, {@link DEAD_KILL} is
  38. * called, e.g.:
  39. * DEAD_KILL(dead);
  40. * The memory used by the dead variable is no longer needed after
  41. * that.
  42. *
  43. * If a piece of code needs to know whether the event occured during some
  44. * operation (but it must not have occured before!), it puts {@link DEAD_ENTER}}
  45. * in front of the operation, and does {@link DEAD_LEAVE} at the end. If
  46. * {@link DEAD_LEAVE} returned nonzero, the event occured, otherwise it did
  47. * not. Example:
  48. * DEAD_ENTER(dead)
  49. * HandlerFunction();
  50. * if (DEAD_LEAVE(dead)) {
  51. * (event occured)
  52. * }
  53. *
  54. * If is is needed to check for the event more than once in a single block,
  55. * {@link DEAD_DECLARE} should be put somewhere before, and {@link DEAD_ENTER2}
  56. * should be used instead of {@link DEAD_ENTER}.
  57. *
  58. * If it is needed to check for multiple events (dead variables) at the same
  59. * time, DEAD_*_N macros should be used instead, specifying different
  60. * identiers as the first argument for different dead variables.
  61. */
  62. #ifndef BADVPN_MISC_DEAD_H
  63. #define BADVPN_MISC_DEAD_H
  64. #include <stdlib.h>
  65. /**
  66. * Dead variable.
  67. */
  68. typedef int *dead_t;
  69. /**
  70. * Initializes a dead variable.
  71. */
  72. #define DEAD_INIT(ptr) ({ptr = NULL;})
  73. /**
  74. * Kills the dead variable,
  75. */
  76. #define DEAD_KILL(ptr) ({if (ptr) *(ptr) = 1;})
  77. /**
  78. * Kills the dead variable with the given value, or does nothing
  79. * if the value is 0. The value will seen by {@link DEAD_LEAVE} and
  80. * {@link DEAD_KILLED}.
  81. */
  82. #define DEAD_KILL_WITH(ptr, val) ({if (ptr) *(ptr) = (val);})
  83. /**
  84. * Declares dead catching variables.
  85. */
  86. #define DEAD_DECLARE int __dead; dead_t __prev_ptr;
  87. /**
  88. * Enters a dead catching using already declared dead catching variables.
  89. * The dead variable must have been initialized with {@link DEAD_INIT},
  90. * and {@link DEAD_KILL} must not have been called yet.
  91. * {@link DEAD_LEAVE} must be called before the current scope is left.
  92. */
  93. #define DEAD_ENTER2(ptr) {__dead = 0; __prev_ptr = ptr; ptr = &__dead;}
  94. /**
  95. * Declares dead catching variables and enters a dead catching.
  96. * The dead variable must have been initialized with {@link DEAD_INIT},
  97. * and {@link DEAD_KILL} must not have been called yet.
  98. * {@link DEAD_LEAVE} must be called before the current scope is left.
  99. */
  100. #define DEAD_ENTER(ptr) DEAD_DECLARE DEAD_ENTER2(ptr)
  101. /**
  102. * Leaves a dead catching.
  103. * Returns 1 if {@link DEAD_KILL} was called for the dead variable, 0 otherwise.
  104. * Must be called after entering a dead catching and before leaving it.
  105. */
  106. #define DEAD_LEAVE(ptr) ({if (!__dead) ptr = __prev_ptr; if (__prev_ptr) *__prev_ptr = __dead; __dead;})
  107. /**
  108. * Returns 1 if {@link DEAD_KILL} was called for the dead variable, 0 otherwise.
  109. * Must be called after entering a dead catching.
  110. */
  111. #define DEAD_KILLED (__dead)
  112. #define DEAD_DECLARE_N(n) int __dead##n; dead_t __prev_ptr##n;
  113. #define DEAD_ENTER2_N(n, ptr) {__dead##n = 0; __prev_ptr##n = ptr; ptr = &__dead##n;}
  114. #define DEAD_ENTER_N(n, ptr) DEAD_DECLARE_N(n) DEAD_ENTER2_N(n, ptr)
  115. #define DEAD_LEAVE_N(n, ptr) ({if (!__dead##n) ptr = __prev_ptr##n; if (__prev_ptr##n) *__prev_ptr##n = __dead##n; __dead##n;})
  116. #define DEAD_KILLED_N(n) (__dead##n)
  117. #endif