@@ -27,9 +27,9 @@ extern CUresult cuMemoryFree(CUdeviceptr dptr);
2727pthread_once_t allocator_allocate_flag = PTHREAD_ONCE_INIT ;
2828pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER ;
2929
30- /* Optional delay after the unlocked oom pre-check in add_chunk .
31- * Used only by the race-reproduce harness to widen the TOCTOU window
32- * between check and usage accounting across processes .
30+ /* Optional delay after reservation, before the expensive CUDA alloc .
31+ * With reserve-then-alloc this only stretches the CUDA window; shared usage
32+ * is already committed so a concurrent peer must OOM .
3333 * Env: HAMI_ALLOC_RACE_WINDOW_US=<microseconds>, unset/0 = no delay. */
3434static void maybe_widen_alloc_race_window (void ) {
3535 const char * env = getenv ("HAMI_ALLOC_RACE_WINDOW_US" );
@@ -52,6 +52,23 @@ size_t round_up(size_t size, size_t unit) {
5252 return size ;
5353}
5454
55+ int reserve_device_memory (CUdevice dev , size_t size ) {
56+ lock_shrreg ();
57+ if (oom_check (dev , size )) {
58+ unlock_shrreg ();
59+ return CUDA_ERROR_OUT_OF_MEMORY ;
60+ }
61+ add_gpu_device_memory_usage (getpid (), dev , size , 2 );
62+ unlock_shrreg ();
63+ return 0 ;
64+ }
65+
66+ void release_device_memory (CUdevice dev , size_t size ) {
67+ lock_shrreg ();
68+ rm_gpu_device_memory_usage (getpid (), dev , size , 2 );
69+ unlock_shrreg ();
70+ }
71+
5572int oom_check (const int dev , size_t addon ) {
5673 CUdevice d ;
5774 if (dev == -1 )
@@ -131,8 +148,10 @@ int add_chunk(CUdeviceptr *address, size_t size) {
131148
132149 cuCtxGetDevice (& dev );
133150
134- /* OOM pre-check without lock */
135- if (oom_check (dev , size ))
151+ /* Reserve under the shared-region lock so concurrent processes cannot
152+ * both pass oom_check before either commits usage. CUDA alloc stays
153+ * outside the lock. */
154+ if (reserve_device_memory (dev , size ) != 0 )
136155 return CUDA_ERROR_OUT_OF_MEMORY ;
137156
138157 maybe_widen_alloc_race_window ();
@@ -145,44 +164,28 @@ int add_chunk(CUdeviceptr *address, size_t size) {
145164 }
146165 if (res != CUDA_SUCCESS ) {
147166 LOG_ERROR ("cuMemoryAllocate failed res=%d" , res );
167+ release_device_memory (dev , size );
148168 return res ;
149169 }
150170
151- /* Tracking inside lock — pure in-memory ops, microseconds */
171+ /* Local list tracking only — usage already reserved */
152172 pthread_mutex_lock (& mutex );
153-
154- if (oom_check (dev , size )) {
155- /* Another process consumed memory between our pre-check and now */
156- pthread_mutex_unlock (& mutex );
157- CUDA_OVERRIDE_CALL (cuda_library_entry , cuMemFree_v2 , * address );
158- return CUDA_ERROR_OUT_OF_MEMORY ;
159- }
160-
161173 allocated_list_entry * e ;
162174 INIT_ALLOCATED_LIST_ENTRY (e , 0 , size , dev );
163175 e -> entry -> address = * address ;
164176 LIST_ADD (device_overallocated , e );
165- add_gpu_device_memory_usage (getpid (), dev , size , 2 );
166-
167177 pthread_mutex_unlock (& mutex );
168178 return 0 ;
169179}
170180
181+ /* Track a pointer in the local list. Caller must already have reserved
182+ * `size` via reserve_device_memory() (or equivalent usage accounting). */
171183int add_chunk_only (CUdeviceptr address , size_t size , CUdevice dev ) {
172184 pthread_mutex_lock (& mutex );
173- size_t addr = 0 ;
174- size_t allocsize ;
175- if (oom_check (dev ,size )){
176- pthread_mutex_unlock (& mutex );
177- return -1 ;
178- }
179185 allocated_list_entry * e ;
180- INIT_ALLOCATED_LIST_ENTRY (e , addr , size , dev );
181- LIST_ADD (device_overallocated ,e );
182- //uint64_t t_size;
183- e -> entry -> address = address ;
184- allocsize = size ;
185- add_gpu_device_memory_usage (getpid (), dev , allocsize , 2 );
186+ INIT_ALLOCATED_LIST_ENTRY (e , 0 , size , dev );
187+ e -> entry -> address = address ;
188+ LIST_ADD (device_overallocated , e );
186189 pthread_mutex_unlock (& mutex );
187190 return 0 ;
188191}
0 commit comments