Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/docs/release.dox
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ Further non-compatibility-affecting changes include:
Vectors of a program given a user-defined instruction interval.
- Added a new drmemtrace option -exit_after_instrs which applies to all
tools and exits after N instructions.
- Added drvector_clear() API that clears a drvector storage without decallocating it.
- Added zero_alloc field in #drvector_t that when set to true sets every entry pointer
of drvector's storage to 0 using memset().

**************************************************
<hr>
Expand Down
31 changes: 31 additions & 0 deletions ext/drcontainers/drvector.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ drvector_init(drvector_t *vec, uint initial_capacity, bool synch,
vec->synch = synch;
vec->lock = dr_mutex_create();
vec->free_data_func = free_data_func;
vec->zero_alloc = false;
return true;
}

Expand All @@ -79,6 +80,8 @@ static void
drvector_increase_size(drvector_t *vec, uint newcap)
{
void **newarray = dr_global_alloc(newcap * sizeof(void *));
if (vec->zero_alloc)
memset(newarray, 0, newcap * sizeof(void *));
if (vec->array != NULL) {
memcpy(newarray, vec->array, vec->entries * sizeof(void *));
dr_global_free(vec->array, vec->capacity * sizeof(void *));
Expand Down Expand Up @@ -160,6 +163,34 @@ drvector_delete(drvector_t *vec)
return true;
}

bool
drvector_clear(drvector_t *vec)
{
if (vec == NULL)
return false;

if (vec->synch)
dr_mutex_lock(vec->lock);

/* Since we lazily initialize the array, vec->array could be NULL if we
* called drvector_init with capacity 0 and never inserted an element into
* the vec. We check vec->array here and below before access.
* */
if (vec->free_data_func != NULL && vec->array != NULL) {
for (uint i = 0; i < vec->entries; i++) {
(vec->free_data_func)(vec->array[i]);
}
}

if (vec->array != NULL && vec->zero_alloc)
memset(vec->array, 0, vec->capacity * sizeof(void *));

if (vec->synch)
dr_mutex_unlock(vec->lock);

return true;
}

void
drvector_lock(drvector_t *vec)
{
Expand Down
11 changes: 11 additions & 0 deletions ext/drcontainers/drvector.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ typedef struct _drvector_t {
bool synch; /**< Whether to automatically synchronize each operation. */
void *lock; /**< The lock used for synchronization. */
void (*free_data_func)(void *); /**< The routine called when freeing each entry. */
bool zero_alloc; /**< Set the vector storage to 0 when resizing, or clearing it. */
} drvector_t;

/**
Expand Down Expand Up @@ -112,6 +113,16 @@ drvector_append(drvector_t *vec, void *data);
bool
drvector_delete(drvector_t *vec);

/**
* Clears the internal storage of the vector without freeing its storage memory. If
* free_payload_func was specified, calls it for each payload first, then, if zero_alloc
* is true, sets every entry pointer to 0. If free_payload_func was not specified but the
* vector entries are pointers to heap objects, clearing the vector can cause memory leaks
* if zero_alloc is true.
*/
bool
drvector_clear(drvector_t *vec);

/** Acquires the vector lock. */
void
drvector_lock(drvector_t *vec);
Expand Down
21 changes: 21 additions & 0 deletions suite/tests/client-interface/drcontainers-test.dll.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,27 @@ test_vector(void)

ok = drvector_delete(&vec);
CHECK(ok, "drvector_delete failed");

/* Test zero_alloc feature. */
ok = drvector_init(&vec, 1, false /*!synch*/, NULL);
vec.zero_alloc = true;
CHECK(ok, "drvector_init failed");
drvector_set_entry(&vec, 0, (void *)&vec);
CHECK(vec.capacity == 1, "resizing should not be triggered");
drvector_append(&vec, (void *)&vec);
CHECK(vec.capacity == 2, "resizing should double the capacity to 2 elements");
drvector_append(&vec, (void *)&vec);
CHECK(vec.capacity == 4, "resizing should double the capacity to 4 elements");
/* The last element should be 0 because of zero_alloc. */
CHECK(drvector_get_entry(&vec, 3) == (void *)0, "entries not equal");
drvector_clear(&vec);
/* drvector_clear() should set every element to zero. */
CHECK(drvector_get_entry(&vec, 0) == (void *)0, "entries not equal");
CHECK(drvector_get_entry(&vec, 1) == (void *)0, "entries not equal");
CHECK(drvector_get_entry(&vec, 2) == (void *)0, "entries not equal");
CHECK(drvector_get_entry(&vec, 3) == (void *)0, "entries not equal");
ok = drvector_delete(&vec);
CHECK(ok, "drvector_delete failed");
}

unsigned int c;
Expand Down
Loading