Guest User

Untitled

a guest
Feb 19th, 2017
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.69 KB | None | 0 0
  1. #define _CRT_SECURE_NO_DEPRECATE
  2.  
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <Windows.h>
  6.  
  7. // This allocates a "magic ring buffer" that is mapped twice, with the two
  8. // copies being contiguous in (virtual) memory. The advantage of this is
  9. // that this allows any function that expects data to be contiguous in
  10. // memory to read from (or write to) such a buffer. It also means that
  11. // block reads/writes never need to be split into two halves, and makes
  12. // wraparound handling quite cheap.
  13. //
  14. // The flipside is that allocating such a beast is a bit dicey (see
  15. // comments below) and subject to various restrictions (e.g. on Windows,
  16. // the size of such a buffer must be a multiple of 64k). So the usual
  17. // disclaimer applies: code responsibly, with great power comes great
  18. // responsibility, and when you use this code to shoot yourself in the
  19. // foot it might blow off your face instead (what with the wraparound
  20. // and all).
  21. class MagicRingBuffer
  22. {
  23. HANDLE mapping;
  24. size_t size;
  25. char *baseptr;
  26.  
  27. public:
  28. MagicRingBuffer()
  29. : mapping(0), size(0), baseptr(0)
  30. {
  31. }
  32.  
  33. ~MagicRingBuffer()
  34. {
  35. free();
  36. }
  37.  
  38. // Allocate a magic ring buffer at a given target address.
  39. // ring_size size of one copy of the ring; must be a multiple of 64k.
  40. // desired_addr location where you'd like it.
  41. void *alloc_at(size_t ring_size, void *desired_addr=0)
  42. {
  43. // if we already hold one allocation, refuse to make another.
  44. if (baseptr)
  45. return 0;
  46.  
  47. // is ring_size a multiple of 64k? if not, this won't ever work!
  48. if ((ring_size & 0xffff) != 0)
  49. return 0;
  50.  
  51. // try to allocate and map our space
  52. size_t alloc_size = ring_size * 2;
  53. if (!(mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, (unsigned long long)alloc_size >> 32, alloc_size & 0xffffffffu, 0)) ||
  54. !(baseptr = (char *)MapViewOfFileEx(mapping, FILE_MAP_ALL_ACCESS, 0, 0, ring_size, desired_addr)) ||
  55. !MapViewOfFileEx(mapping, FILE_MAP_ALL_ACCESS, 0, 0, ring_size, (char *)desired_addr + ring_size))
  56. {
  57. // something went wrong - clean up
  58. free();
  59. }
  60. else // success!
  61. size = ring_size;
  62.  
  63. return baseptr;
  64. }
  65.  
  66. // This function will allocate a magic ring buffer at a system-determined base address.
  67. //
  68. // Sadly, there's no way (that I can see) in the Win32 API to first reserve
  69. // a memory region then fill it in using mmaps; you can reserve memory via
  70. // VirtualAlloc, but that address range can then only be used to commit
  71. // memory via another VirtualAlloc, and can not be mmap'ed. Furthermore,
  72. // there's also no way to do the two back-to-back mmaps atomically. What we
  73. // do here is to reserve enough memory via VirtualAlloc, then immediately
  74. // free it and try to put our allocation there. This is subject to a race
  75. // condition - another thread might end up allocating that very memory
  76. // region in the interim. What this means is that even when an alloc should
  77. // work (i.e. there's enough memory available) it can still fail spuriously
  78. // sometimes. Hence the "dicey" comment above.
  79. //
  80. // What we do here is just retry the alloc a given number of times and hope
  81. // that we don't get screwed every single time. This increases the
  82. // likelihood of success, but doesn't eliminate the chance of spurious
  83. // failure, so be religious about checking return values!
  84. void *alloc(size_t ring_size, int num_retries=5)
  85. {
  86. void *ptr = 0;
  87. while (!ptr && num_retries-- != 0)
  88. {
  89. void *target_addr = determine_viable_addr(ring_size * 2);
  90. if (target_addr)
  91. ptr = alloc_at(ring_size, target_addr);
  92. }
  93.  
  94. return ptr;
  95. }
  96.  
  97. // Frees the allocated region again.
  98. void free()
  99. {
  100. if (baseptr)
  101. {
  102. UnmapViewOfFile(baseptr);
  103. UnmapViewOfFile(baseptr + size);
  104. baseptr = 0;
  105. }
  106.  
  107. if (mapping)
  108. {
  109. CloseHandle(mapping);
  110. mapping = 0;
  111. }
  112.  
  113. size = 0;
  114. }
  115.  
  116. private:
  117. // Determine a viable target address of "size" memory mapped bytes by
  118. // allocating memory using VirtualAlloc and immediately freeing it. This
  119. // is subject to a potential race condition, see notes above.
  120. static void *determine_viable_addr(size_t size)
  121. {
  122. void *ptr = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
  123. if (!ptr)
  124. return 0;
  125.  
  126. VirtualFree(ptr, 0, MEM_RELEASE);
  127. return ptr;
  128. }
  129. };
  130.  
  131. int main()
  132. {
  133. static const int ringsize = 64*1024;
  134.  
  135. MagicRingBuffer mrb;
  136. char *buf = (char *)mrb.alloc(ringsize);
  137. if (!buf)
  138. {
  139. printf("MRB allocation failed!\n");
  140. return 0;
  141. }
  142.  
  143. // Okay, now get ready for a magic trick!
  144. memset(buf, 0, ringsize * 2); // clear it all to zeroes
  145.  
  146. strcpy(buf + ringsize - 3, "Hello world!");
  147. printf("%s\n", buf + ringsize - 3);
  148. printf("%s\n", buf);
  149.  
  150. // nothing up my sleeve!
  151.  
  152. return 0;
  153. }
Add Comment
Please, Sign In to add comment