9
9
10
10
#include "provider_tracking.h"
11
11
#include "critnib.h"
12
+ #include "utils_concurrency.h"
12
13
13
14
#include <umf/memory_pool.h>
14
15
#include <umf/memory_provider.h>
15
16
#include <umf/memory_provider_ops.h>
16
17
17
18
#include <assert.h>
18
19
#include <errno.h>
20
+ #include <stdio.h>
19
21
#include <stdlib.h>
20
22
21
23
typedef struct tracker_value_t {
@@ -32,7 +34,7 @@ static umf_result_t umfMemoryTrackerAdd(umf_memory_tracker_handle_t hTracker,
32
34
value -> pool = pool ;
33
35
value -> size = size ;
34
36
35
- int ret = critnib_insert (( critnib * ) hTracker , (uintptr_t )ptr , value , 0 );
37
+ int ret = critnib_insert (hTracker -> map , (uintptr_t )ptr , value , 0 );
36
38
37
39
if (ret == 0 ) {
38
40
return UMF_RESULT_SUCCESS ;
@@ -59,7 +61,7 @@ static umf_result_t umfMemoryTrackerRemove(umf_memory_tracker_handle_t hTracker,
59
61
// umfMemoryTrackerRemove call with the same ptr value.
60
62
(void )size ;
61
63
62
- void * value = critnib_remove (( critnib * ) hTracker , (uintptr_t )ptr );
64
+ void * value = critnib_remove (hTracker -> map , (uintptr_t )ptr );
63
65
if (!value ) {
64
66
// This should not happen
65
67
// TODO: add logging here
@@ -77,7 +79,7 @@ umfMemoryTrackerGetPool(umf_memory_tracker_handle_t hTracker, const void *ptr) {
77
79
78
80
uintptr_t rkey ;
79
81
tracker_value_t * rvalue ;
80
- int found = critnib_find (( critnib * ) hTracker , (uintptr_t )ptr , FIND_LE ,
82
+ int found = critnib_find (hTracker -> map , (uintptr_t )ptr , FIND_LE ,
81
83
(void * )& rkey , (void * * )& rvalue );
82
84
if (!found ) {
83
85
return NULL ;
@@ -119,6 +121,158 @@ static umf_result_t trackingAlloc(void *hProvider, size_t size,
119
121
return ret ;
120
122
}
121
123
124
+ static umf_result_t trackingAllocationSplit (void * provider , void * ptr ,
125
+ size_t totalSize , size_t leftSize ) {
126
+ umf_result_t ret = UMF_RESULT_ERROR_UNKNOWN ;
127
+ umf_tracking_memory_provider_t * p =
128
+ (umf_tracking_memory_provider_t * )provider ;
129
+
130
+ tracker_value_t * splitValue =
131
+ (tracker_value_t * )malloc (sizeof (tracker_value_t ));
132
+ splitValue -> pool = p -> pool ;
133
+ splitValue -> size = leftSize ;
134
+
135
+ int r = util_mutex_lock (p -> hTracker -> splitMergeMutex );
136
+ if (r ) {
137
+ goto err_lock ;
138
+ }
139
+
140
+ tracker_value_t * value =
141
+ (tracker_value_t * )critnib_get (p -> hTracker -> map , (uintptr_t )ptr );
142
+ if (!value ) {
143
+ fprintf (stderr , "tracking split: no such value\n" );
144
+ ret = UMF_RESULT_ERROR_INVALID_ARGUMENT ;
145
+ goto err ;
146
+ }
147
+ if (value -> size != totalSize ) {
148
+ fprintf (stderr , "tracking split: %zu != %zu\n" , value -> size , totalSize );
149
+ ret = UMF_RESULT_ERROR_INVALID_ARGUMENT ;
150
+ goto err ;
151
+ }
152
+
153
+ ret = umfMemoryProviderAllocationSplit (p -> hUpstream , ptr , totalSize ,
154
+ leftSize );
155
+ if (ret != UMF_RESULT_SUCCESS ) {
156
+ fprintf (stderr ,
157
+ "tracking split: umfMemoryProviderAllocationSplit failed\n" );
158
+ goto err ;
159
+ }
160
+
161
+ void * highPtr = (void * )(((uintptr_t )ptr ) + leftSize );
162
+ size_t rightSize = totalSize - leftSize ;
163
+
164
+ // We'll have duplicate entry for the range [highPtr, rightValue->size] but this is fine,
165
+ // the value is the same anyway and we forbid splitting/removing that range concurrently
166
+ ret = umfMemoryTrackerAdd (p -> hTracker , p -> pool , highPtr , rightSize );
167
+ if (ret != UMF_RESULT_SUCCESS ) {
168
+ fprintf (stderr , "tracking split: umfMemoryTrackerAdd failed\n" );
169
+ // TODO: what now? should we rollback the split? This is can only happen due to ENOMEM
170
+ // so it's unlikely but probably the best solution would be to try to preallocate everything
171
+ // (value and critnib nodes) before calling umfMemoryProviderAllocationSplit.
172
+ goto err ;
173
+ }
174
+
175
+ int cret = critnib_insert (p -> hTracker -> map , (uintptr_t )ptr ,
176
+ (void * )splitValue , 1 /* update */ );
177
+ // this cannot fail since we know the element exists (nothing to allocate)
178
+ assert (cret == 0 );
179
+ (void )cret ;
180
+
181
+ // free the original value
182
+ free (value );
183
+ util_mutex_unlock (p -> hTracker -> splitMergeMutex );
184
+
185
+ return UMF_RESULT_SUCCESS ;
186
+
187
+ err :
188
+ util_mutex_unlock (p -> hTracker -> splitMergeMutex );
189
+ err_lock :
190
+ free (splitValue );
191
+ return ret ;
192
+ }
193
+
194
+ static umf_result_t trackingAllocationMerge (void * provider , void * lowPtr ,
195
+ void * highPtr , size_t totalSize ) {
196
+ umf_result_t ret = UMF_RESULT_ERROR_UNKNOWN ;
197
+ umf_tracking_memory_provider_t * p =
198
+ (umf_tracking_memory_provider_t * )provider ;
199
+
200
+ tracker_value_t * mergedValue =
201
+ (tracker_value_t * )malloc (sizeof (tracker_value_t ));
202
+ mergedValue -> pool = p -> pool ;
203
+ mergedValue -> size = totalSize ;
204
+
205
+ if (!mergedValue ) {
206
+ return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
207
+ }
208
+
209
+ int r = util_mutex_lock (p -> hTracker -> splitMergeMutex );
210
+ if (r ) {
211
+ goto err_lock ;
212
+ }
213
+
214
+ tracker_value_t * leftValue =
215
+ (tracker_value_t * )critnib_get (p -> hTracker -> map , (uintptr_t )lowPtr );
216
+ if (!leftValue ) {
217
+ fprintf (stderr , "tracking merge: no left value\n" );
218
+ ret = UMF_RESULT_ERROR_INVALID_ARGUMENT ;
219
+ goto err ;
220
+ }
221
+ tracker_value_t * rightValue =
222
+ (tracker_value_t * )critnib_get (p -> hTracker -> map , (uintptr_t )highPtr );
223
+ if (!rightValue ) {
224
+ fprintf (stderr , "tracking merge: no right value\n" );
225
+ ret = UMF_RESULT_ERROR_INVALID_ARGUMENT ;
226
+ goto err ;
227
+ }
228
+ if (leftValue -> pool != rightValue -> pool ) {
229
+ fprintf (stderr , "tracking merge: pool mismatch\n" );
230
+ ret = UMF_RESULT_ERROR_INVALID_ARGUMENT ;
231
+ goto err ;
232
+ }
233
+ if (leftValue -> size + rightValue -> size != totalSize ) {
234
+ fprintf (stderr , "tracking merge: leftValue->size + rightValue->size != "
235
+ "totalSize\n" );
236
+ ret = UMF_RESULT_ERROR_INVALID_ARGUMENT ;
237
+ goto err ;
238
+ }
239
+
240
+ ret = umfMemoryProviderAllocationMerge (p -> hUpstream , lowPtr , highPtr ,
241
+ totalSize );
242
+ if (ret != UMF_RESULT_SUCCESS ) {
243
+ fprintf (stderr ,
244
+ "tracking merge: umfMemoryProviderAllocationMerge failed\n" );
245
+ goto err ;
246
+ }
247
+
248
+ // We'll have duplicate entry for the range [highPtr, rightValue->size] but this is fine,
249
+ // the value is the same anyway and we forbid splitting/removing that range concurrently
250
+ int cret = critnib_insert (p -> hTracker -> map , (uintptr_t )lowPtr ,
251
+ (void * )mergedValue , 1 /* update */ );
252
+ // this cannot fail since we know the element exists (nothing to allocate)
253
+ assert (cret == 0 );
254
+ (void )cret ;
255
+
256
+ // free old value that we just replaced with mergedValue
257
+ free (leftValue );
258
+
259
+ void * erasedRightValue =
260
+ critnib_remove (p -> hTracker -> map , (uintptr_t )highPtr );
261
+ assert (erasedRightValue == rightValue );
262
+
263
+ free (erasedRightValue );
264
+
265
+ util_mutex_unlock (p -> hTracker -> splitMergeMutex );
266
+
267
+ return UMF_RESULT_SUCCESS ;
268
+
269
+ err :
270
+ util_mutex_unlock (p -> hTracker -> splitMergeMutex );
271
+ err_lock :
272
+ free (mergedValue );
273
+ return ret ;
274
+ }
275
+
122
276
static umf_result_t trackingFree (void * hProvider , void * ptr , size_t size ) {
123
277
umf_result_t ret ;
124
278
umf_tracking_memory_provider_t * p =
@@ -214,7 +368,8 @@ umf_memory_provider_ops_t UMF_TRACKING_MEMORY_PROVIDER_OPS = {
214
368
.purge_force = trackingPurgeForce ,
215
369
.purge_lazy = trackingPurgeLazy ,
216
370
.get_name = trackingName ,
217
- };
371
+ .allocation_split = trackingAllocationSplit ,
372
+ .allocation_merge = trackingAllocationMerge };
218
373
219
374
umf_result_t umfTrackingMemoryProviderCreate (
220
375
umf_memory_provider_handle_t hUpstream , umf_memory_pool_handle_t hPool ,
0 commit comments