Leaked source code of windows server 2003
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.

127 lines
4.0 KiB

  1. //** REFPTR.H - referenced pointer definitons.
  2. //
  3. // This file contains the definitions for the referenced-pointer package used
  4. // by the TCP/UDP/IP code.
  5. //
  6. //* Definition of a referenced pointer instance.
  7. //
  8. // The rp_valid field indicates whether the pointer is valid.
  9. // SetRefPtr(..., <value>) is used to install <value> as the pointer.
  10. // ClearRefPtr(...) clears the installed pointer value.
  11. //
  12. // N.B. The pointer value may only be set when invalid. All attempts to set
  13. // the pointer will fail until the installed value is cleared.
  14. //
  15. // If valid, a reference may be taken and the installed pointer captured
  16. // using AcquireRefPtr. The reference taken should then be released
  17. // using ReleaseRefPtr.
  18. //
  19. // N.B. Clearing a pointer may require a wait for all outstanding references
  20. // to be released, so ClearRefPtr(...) releases the object's lock and assumes
  21. // that the resulting IRQL is below DISPATCH_LEVEL.
  22. //
  23. struct RefPtr {
  24. void* rp_ptr;
  25. void* rp_dummy;
  26. CTELock* rp_lock;
  27. BOOLEAN rp_valid;
  28. uint rp_refcnt;
  29. CTEBlockStruc rp_block;
  30. };
  31. typedef struct RefPtr RefPtr;
  32. __inline void
  33. InitRefPtr(RefPtr* RP, CTELock* Lock, void* Dummy)
  34. {
  35. RP->rp_ptr = NULL;
  36. RP->rp_lock = Lock;
  37. RP->rp_valid = FALSE;
  38. RP->rp_refcnt = 0;
  39. RP->rp_dummy = Dummy;
  40. CTEInitBlockStruc(&RP->rp_block);
  41. }
  42. __inline BOOLEAN
  43. RefPtrValid(RefPtr* RP)
  44. {
  45. return RP->rp_valid;
  46. }
  47. __inline void*
  48. AcquireRefPtr(RefPtr* RP)
  49. {
  50. CTEInterlockedIncrementLong(&RP->rp_refcnt);
  51. return RP->rp_ptr;
  52. }
  53. __inline void
  54. ReleaseRefPtr(RefPtr* RP)
  55. {
  56. if (CTEInterlockedDecrementLong(&RP->rp_refcnt) == 0) {
  57. CTESignal(&RP->rp_block, IP_SUCCESS);
  58. }
  59. }
  60. __inline IP_STATUS
  61. SetRefPtr(RefPtr* RP, void* Ptr)
  62. {
  63. ASSERT(Ptr != NULL);
  64. // We must synchronize the pointer-installation with the execution
  65. // of all threads holding references. Again, a sequence of operations
  66. // is required, in the given order:
  67. // - make an initial reference for the pointer to be installed;
  68. // if there were any existing references then someone beat us
  69. // into the registration and we must fail this request.
  70. // - install the new pointer; this is done before setting the flag
  71. // to ensure that the pointer is available before any thread
  72. // attempts to refer to it.
  73. // - set the flag indicating the pointer has been enabled.
  74. if (CTEInterlockedIncrementLong(&RP->rp_refcnt) != 1) {
  75. ReleaseRefPtr(RP);
  76. return IP_GENERAL_FAILURE;
  77. }
  78. InterlockedExchangePointer((PVOID*)&RP->rp_ptr, Ptr);
  79. RP->rp_valid = TRUE;
  80. return IP_SUCCESS;
  81. }
  82. __inline IP_STATUS
  83. ClearRefPtr(RefPtr* RP, CTELockHandle* LockHandle)
  84. {
  85. if (!RP->rp_valid) {
  86. return IP_GENERAL_FAILURE;
  87. }
  88. // We must now synchronize the clearing of the pointer with
  89. // the execution of all threads holding references to it. This involves
  90. // the following operations, *in the given order*:
  91. // - clear the 'enabled' flag and install the dummy pointer value;
  92. // this ensures that no additional references will be made to the
  93. // pointer until we return control, and that any references begun
  94. // after we set the flag will hold the dummy rather than the
  95. // actual pointer.
  96. // - clear the event in case we need to wait for outstanding references
  97. // to be released; the event might still be signalled from a
  98. // superfluous dereference during a previous clearing.
  99. // - drop the initial reference made to the pointer, and wait for all
  100. // outstanding references (if any) to be released.
  101. RP->rp_valid = FALSE;
  102. InterlockedExchangePointer(&RP->rp_ptr, RP->rp_dummy);
  103. CTEClearSignal(&RP->rp_block);
  104. if (CTEInterlockedDecrementLong(&RP->rp_refcnt) != 0) {
  105. CTEFreeLock(RP->rp_lock, *LockHandle);
  106. CTEBlock(&RP->rp_block);
  107. CTEGetLock(RP->rp_lock, LockHandle);
  108. }
  109. return IP_SUCCESS;
  110. }