Skip to content

Commit 1c00131

Browse files
authored
Merge pull request #5922 from hjelmn/opal_free_list_really_old_race_we_should_really_fix_now
opal/free_list: fix race condition
2 parents 1ff3cfe + 5c770a7 commit 1c00131

File tree

2 files changed

+31
-17
lines changed

2 files changed

+31
-17
lines changed

opal/class/opal_free_list.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Copyright (c) 2006-2007 Mellanox Technologies. All rights reserved.
1414
* Copyright (c) 2010-2013 Cisco Systems, Inc. All rights reserved.
1515
* Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
16-
* Copyright (c) 2012-2016 Los Alamos National Security, LLC. All rights
16+
* Copyright (c) 2012-2018 Los Alamos National Security, LLC. All rights
1717
* reserved.
1818
* $COPYRIGHT$
1919
*
@@ -155,13 +155,13 @@ int opal_free_list_init (opal_free_list_t *flist, size_t frag_size, size_t frag_
155155
flist->ctx = ctx;
156156

157157
if (num_elements_to_alloc) {
158-
return opal_free_list_grow_st (flist, num_elements_to_alloc);
158+
return opal_free_list_grow_st (flist, num_elements_to_alloc, NULL);
159159
}
160160

161161
return OPAL_SUCCESS;
162162
}
163163

164-
int opal_free_list_grow_st (opal_free_list_t* flist, size_t num_elements)
164+
int opal_free_list_grow_st (opal_free_list_t* flist, size_t num_elements, opal_free_list_item_t **item_out)
165165
{
166166
unsigned char *ptr, *payload_ptr = NULL;
167167
opal_free_list_memory_t *alloc_ptr;
@@ -263,10 +263,16 @@ int opal_free_list_grow_st (opal_free_list_t* flist, size_t num_elements)
263263
/* NTH: in case the free list may be accessed from multiple threads
264264
* use the atomic lifo push. The overhead is small compared to the
265265
* overall overhead of opal_free_list_grow(). */
266-
opal_lifo_push_atomic (&flist->super, &item->super);
266+
if (item_out && 0 == i) {
267+
/* ensure the thread that is growing the free list always gets an item
268+
* if one is available */
269+
*item_out = item;
270+
} else {
271+
opal_lifo_push_atomic (&flist->super, &item->super);
272+
}
273+
267274
ptr += head_size;
268275
payload_ptr += elem_size;
269-
270276
}
271277

272278
if (OPAL_SUCCESS != rc && 0 == num_elements) {
@@ -298,7 +304,7 @@ int opal_free_list_resize_mt(opal_free_list_t *flist, size_t size)
298304

299305
opal_mutex_lock (&flist->fl_lock);
300306
do {
301-
ret = opal_free_list_grow_st (flist, flist->fl_num_per_alloc);
307+
ret = opal_free_list_grow_st (flist, flist->fl_num_per_alloc, NULL);
302308
if (OPAL_SUCCESS != ret) {
303309
break;
304310
}

opal/class/opal_free_list.h

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* All rights reserved.
1313
* Copyright (c) 2010 IBM Corporation. All rights reserved.
1414
* Copyright (c) 2010-2015 Cisco Systems, Inc. All rights reserved.
15-
* Copyright (c) 2014-2015 Los Alamos National Security, LLC. All rights
15+
* Copyright (c) 2014-2018 Los Alamos National Security, LLC. All rights
1616
* reserved.
1717
* $COPYRIGHT$
1818
*
@@ -146,6 +146,7 @@ OPAL_DECLSPEC int opal_free_list_init (opal_free_list_t *free_list,
146146
*
147147
* @param flist (IN) Free list to grow
148148
* @param num_elements (IN) Number of elements to add
149+
* @param item_out (OUT) Location to store new free list item (can be NULL)
149150
*
150151
* @returns OPAL_SUCCESS if any elements were added
151152
* @returns OPAL_ERR_OUT_OF_RESOURCE if no elements could be added
@@ -155,8 +156,14 @@ OPAL_DECLSPEC int opal_free_list_init (opal_free_list_t *free_list,
155156
* that may be accessed by multiple threads simultaneously. Note: this is an
156157
* internal function that will be used when needed by opal_free_list_get* and
157158
* opal_free_list_wait*.
159+
*
160+
* The item_out parameter can be used to ensure that the thread calling this
161+
* function always gets a free list item if the list is successfully grown.
162+
* This eliminates a race condition with code that simply calls free_list_get
163+
* and assumes NULL is an out of memory condition (which it wasn't necessarily
164+
* before this parameter was added).
158165
*/
159-
OPAL_DECLSPEC int opal_free_list_grow_st (opal_free_list_t *flist, size_t num_elements);
166+
OPAL_DECLSPEC int opal_free_list_grow_st (opal_free_list_t *flist, size_t num_elements, opal_free_list_item_t **item_out);
160167

161168
/**
162169
* Grow the free list to be at least size elements.
@@ -195,9 +202,8 @@ static inline opal_free_list_item_t *opal_free_list_get_mt (opal_free_list_t *fl
195202

196203
if (OPAL_UNLIKELY(NULL == item)) {
197204
opal_mutex_lock (&flist->fl_lock);
198-
opal_free_list_grow_st (flist, flist->fl_num_per_alloc);
205+
opal_free_list_grow_st (flist, flist->fl_num_per_alloc, &item);
199206
opal_mutex_unlock (&flist->fl_lock);
200-
item = (opal_free_list_item_t *) opal_lifo_pop_atomic (&flist->super);
201207
}
202208

203209
return item;
@@ -209,8 +215,7 @@ static inline opal_free_list_item_t *opal_free_list_get_st (opal_free_list_t *fl
209215
(opal_free_list_item_t*) opal_lifo_pop_st (&flist->super);
210216

211217
if (OPAL_UNLIKELY(NULL == item)) {
212-
opal_free_list_grow_st (flist, flist->fl_num_per_alloc);
213-
item = (opal_free_list_item_t *) opal_lifo_pop_atomic (&flist->super);
218+
opal_free_list_grow_st (flist, flist->fl_num_per_alloc, &item);
214219
}
215220

216221
return item;
@@ -253,7 +258,7 @@ static inline opal_free_list_item_t *opal_free_list_wait_mt (opal_free_list_t *f
253258
while (NULL == item) {
254259
if (!opal_mutex_trylock (&fl->fl_lock)) {
255260
if (fl->fl_max_to_alloc <= fl->fl_num_allocated ||
256-
OPAL_SUCCESS != opal_free_list_grow_st (fl, fl->fl_num_per_alloc)) {
261+
OPAL_SUCCESS != opal_free_list_grow_st (fl, fl->fl_num_per_alloc, &item)) {
257262
fl->fl_num_waiting++;
258263
opal_condition_wait (&fl->fl_condition, &fl->fl_lock);
259264
fl->fl_num_waiting--;
@@ -274,7 +279,9 @@ static inline opal_free_list_item_t *opal_free_list_wait_mt (opal_free_list_t *f
274279
opal_mutex_lock (&fl->fl_lock);
275280
}
276281
opal_mutex_unlock (&fl->fl_lock);
277-
item = (opal_free_list_item_t *) opal_lifo_pop_atomic (&fl->super);
282+
if (NULL == item) {
283+
item = (opal_free_list_item_t *) opal_lifo_pop_atomic (&fl->super);
284+
}
278285
}
279286

280287
return item;
@@ -287,12 +294,13 @@ static inline opal_free_list_item_t *opal_free_list_wait_st (opal_free_list_t *f
287294

288295
while (NULL == item) {
289296
if (fl->fl_max_to_alloc <= fl->fl_num_allocated ||
290-
OPAL_SUCCESS != opal_free_list_grow_st (fl, fl->fl_num_per_alloc)) {
297+
OPAL_SUCCESS != opal_free_list_grow_st (fl, fl->fl_num_per_alloc, &item)) {
291298
/* try to make progress */
292299
opal_progress ();
293300
}
294-
295-
item = (opal_free_list_item_t *) opal_lifo_pop (&fl->super);
301+
if (NULL == item) {
302+
item = (opal_free_list_item_t *) opal_lifo_pop (&fl->super);
303+
}
296304
}
297305

298306
return item;

0 commit comments

Comments
 (0)