tracking_allocator.odin 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. //+build !freestanding
  2. package mem
  3. import "base:runtime"
  4. import "core:sync"
  5. Tracking_Allocator_Entry :: struct {
  6. memory: rawptr,
  7. size: int,
  8. alignment: int,
  9. mode: Allocator_Mode,
  10. err: Allocator_Error,
  11. location: runtime.Source_Code_Location,
  12. }
  13. Tracking_Allocator_Bad_Free_Entry :: struct {
  14. memory: rawptr,
  15. location: runtime.Source_Code_Location,
  16. }
  17. Tracking_Allocator :: struct {
  18. backing: Allocator,
  19. allocation_map: map[rawptr]Tracking_Allocator_Entry,
  20. bad_free_array: [dynamic]Tracking_Allocator_Bad_Free_Entry,
  21. mutex: sync.Mutex,
  22. clear_on_free_all: bool,
  23. }
  24. tracking_allocator_init :: proc(t: ^Tracking_Allocator, backing_allocator: Allocator, internals_allocator := context.allocator) {
  25. t.backing = backing_allocator
  26. t.allocation_map.allocator = internals_allocator
  27. t.bad_free_array.allocator = internals_allocator
  28. if .Free_All in query_features(t.backing) {
  29. t.clear_on_free_all = true
  30. }
  31. }
  32. tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) {
  33. delete(t.allocation_map)
  34. delete(t.bad_free_array)
  35. }
  36. tracking_allocator_clear :: proc(t: ^Tracking_Allocator) {
  37. sync.mutex_lock(&t.mutex)
  38. clear(&t.allocation_map)
  39. clear(&t.bad_free_array)
  40. sync.mutex_unlock(&t.mutex)
  41. }
  42. @(require_results)
  43. tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator {
  44. return Allocator{
  45. data = data,
  46. procedure = tracking_allocator_proc,
  47. }
  48. }
  49. tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
  50. size, alignment: int,
  51. old_memory: rawptr, old_size: int, loc := #caller_location) -> (result: []byte, err: Allocator_Error) {
  52. data := (^Tracking_Allocator)(allocator_data)
  53. sync.mutex_guard(&data.mutex)
  54. if mode == .Query_Info {
  55. info := (^Allocator_Query_Info)(old_memory)
  56. if info != nil && info.pointer != nil {
  57. if entry, ok := data.allocation_map[info.pointer]; ok {
  58. info.size = entry.size
  59. info.alignment = entry.alignment
  60. }
  61. info.pointer = nil
  62. }
  63. return
  64. }
  65. if mode == .Free && old_memory != nil && old_memory not_in data.allocation_map {
  66. append(&data.bad_free_array, Tracking_Allocator_Bad_Free_Entry{
  67. memory = old_memory,
  68. location = loc,
  69. })
  70. } else {
  71. result = data.backing.procedure(data.backing.data, mode, size, alignment, old_memory, old_size, loc) or_return
  72. }
  73. result_ptr := raw_data(result)
  74. if data.allocation_map.allocator.procedure == nil {
  75. data.allocation_map.allocator = context.allocator
  76. }
  77. switch mode {
  78. case .Alloc, .Alloc_Non_Zeroed:
  79. data.allocation_map[result_ptr] = Tracking_Allocator_Entry{
  80. memory = result_ptr,
  81. size = size,
  82. mode = mode,
  83. alignment = alignment,
  84. err = err,
  85. location = loc,
  86. }
  87. case .Free:
  88. delete_key(&data.allocation_map, old_memory)
  89. case .Free_All:
  90. if data.clear_on_free_all {
  91. clear_map(&data.allocation_map)
  92. }
  93. case .Resize, .Resize_Non_Zeroed:
  94. if old_memory != result_ptr {
  95. delete_key(&data.allocation_map, old_memory)
  96. }
  97. data.allocation_map[result_ptr] = Tracking_Allocator_Entry{
  98. memory = result_ptr,
  99. size = size,
  100. mode = mode,
  101. alignment = alignment,
  102. err = err,
  103. location = loc,
  104. }
  105. case .Query_Features:
  106. set := (^Allocator_Mode_Set)(old_memory)
  107. if set != nil {
  108. set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features, .Query_Info}
  109. }
  110. return nil, nil
  111. case .Query_Info:
  112. unreachable()
  113. }
  114. return
  115. }