Skip to content

Commit cb47700

Browse files
authored
i#7690: hashtable_t key-exposing iterator (#7691)
Adds a new iterator `hashtable_apply_to_all_key_payload_pairs_user_data()` over DynamoRIO's container `hashtable_t` that exposes the key and payload pair of every element. Adds a test for the new iterator using count and sum of hashtable elements. Adds the new iterator to release doc. Fixes #7690
1 parent b6df8df commit cb47700

File tree

4 files changed

+86
-4
lines changed

4 files changed

+86
-4
lines changed

api/docs/release.dox

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ Further non-compatibility-affecting changes include:
269269
PC in the trace, which is from the next instruction or the next
270270
#dynamorio::drmemtrace::TRACE_MARKER_TYPE_KERNEL_EVENT marker, whichever comes
271271
first.
272+
- Added a new #hashtable_t iterator hashtable_apply_to_all_key_payload_pairs_user_data()
273+
that exposes the key of every element in the table.
272274

273275
**************************************************
274276
<hr>

ext/drcontainers/hashtable.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,19 @@ hashtable_apply_to_all_payloads_user_data(hashtable_t *table,
504504
}
505505
}
506506

507+
void
508+
hashtable_apply_to_all_key_payload_pairs_user_data(
509+
hashtable_t *table, void (*apply_func)(void *key, void *payload, void *user_data),
510+
void *user_data)
511+
{
512+
DR_ASSERT_MSG(apply_func != NULL, "The apply_func ptr cannot be NULL.");
513+
for (uint i = 0; i < HASHTABLE_SIZE(table->table_bits); i++) {
514+
for (hash_entry_t *e = table->table[i]; e != NULL; e = e->next) {
515+
apply_func(e->key, e->payload, user_data);
516+
}
517+
}
518+
}
519+
507520
static void
508521
hashtable_clear_internal(hashtable_t *table)
509522
{

ext/drcontainers/hashtable.h

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ typedef struct _hashtable_config_t {
8787
void (*free_key_func)(void *);
8888
} hashtable_config_t;
8989

90+
/** The storage for a hashtable. */
9091
typedef struct _hashtable_t {
9192
hash_entry_t **table;
9293
hash_type_t hashtype;
@@ -205,17 +206,19 @@ hashtable_remove_range(hashtable_t *table, void *start, void *end);
205206
* Calls the \p apply_func for each payload.
206207
* @param table The hashtable to apply the function.
207208
* @param apply_func A pointer to a function that is called for all payloads
208-
* stored in the map.
209+
* stored in the map. The function is not allowed to add or remove elements to/from the
210+
* hashtable being iterated.
209211
*/
210212
void
211213
hashtable_apply_to_all_payloads(hashtable_t *table, void (*apply_func)(void *payload));
212214

213215
/**
214-
* Calls the \p apply_func for each payload with user data. Similar to
215-
* hashtable_apply_to_all_payloads().
216+
* Calls the \p apply_func for each payload with user data.
217+
* Similar to hashtable_apply_to_all_payloads().
216218
* @param table The hashtable to apply the function.
217219
* @param apply_func A pointer to a function that is called for all payloads
218-
* stored in the map. It also takes user data as a parameter.
220+
* stored in the map. It also takes user data as a parameter. The function is not allowed
221+
* to add or remove elements to/from the hashtable being iterated.
219222
* @param user_data User data that is available when iterating through payloads.
220223
*/
221224
void
@@ -224,6 +227,20 @@ hashtable_apply_to_all_payloads_user_data(hashtable_t *table,
224227
void *user_data),
225228
void *user_data);
226229

230+
/**
231+
* Calls the \p apply_func for each key-payload pair with user data.
232+
* Similar to hashtable_apply_to_all_payloads_user_data().
233+
* @param table The hashtable to apply the function.
234+
* @param apply_func A pointer to a function that is called for all key-payload pairs
235+
* stored in the map. It also takes user data as a parameter. The function is not allowed
236+
* to add or remove elements to/from the hashtable being iterated.
237+
* @param user_data User data that is available when iterating through payloads.
238+
*/
239+
void
240+
hashtable_apply_to_all_key_payload_pairs_user_data(
241+
hashtable_t *table, void (*apply_func)(void *key, void *payload, void *user_data),
242+
void *user_data);
243+
227244
/**
228245
* Removes all entries from the table. If free_payload_func was specified
229246
* calls it for each payload.

suite/tests/client-interface/drcontainers-test.dll.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
#include "hashtable.h"
3939
#include "stdint.h"
4040

41+
typedef struct _accumulators_t {
42+
uintptr_t key_acc;
43+
uintptr_t payload_acc;
44+
} accumulators_t;
45+
4146
static void
4247
test_vector(void)
4348
{
@@ -105,6 +110,16 @@ count_user_data(void *payload, void *user_data)
105110
CHECK(user_data == (void *)apply_payload_user_data_test, "user data not correct");
106111
}
107112

113+
static void
114+
count_key_payload_user_data(void *key, void *payload, void *user_data)
115+
{
116+
accumulators_t *counters = (accumulators_t *)user_data;
117+
/* Count key. */
118+
++counters->key_acc;
119+
/* Count payload. */
120+
++counters->payload_acc;
121+
}
122+
108123
static void
109124
count_null_user_data(void *payload, void *user_data)
110125
{
@@ -125,6 +140,14 @@ sum_user_data(void *payload, void *user_data)
125140
total += (uintptr_t)user_data;
126141
}
127142

143+
static void
144+
sum_key_payload_user_data(void *key, void *payload, void *user_data)
145+
{
146+
accumulators_t *sums = (accumulators_t *)user_data;
147+
sums->key_acc += (uintptr_t)key;
148+
sums->payload_acc += (uintptr_t)payload;
149+
}
150+
128151
static void
129152
test_hashtable_apply_all(void)
130153
{
@@ -182,6 +205,32 @@ test_hashtable_apply_all_user_data(void)
182205
hashtable_delete(&hash_table);
183206
}
184207

208+
static void
209+
test_hashtable_apply_all_key_payload_pairs_user_data(void)
210+
{
211+
hashtable_t hash_table;
212+
hashtable_init(&hash_table, 8, HASH_INTPTR, false);
213+
214+
hashtable_add_replace(&hash_table, (void *)1, (void *)1);
215+
hashtable_add_replace(&hash_table, (void *)2, (void *)2);
216+
hashtable_add_replace(&hash_table, (void *)3, (void *)3);
217+
218+
accumulators_t counters = { .key_acc = 0, .payload_acc = 0 };
219+
hashtable_apply_to_all_key_payload_pairs_user_data(
220+
&hash_table, count_key_payload_user_data, (void *)&counters);
221+
accumulators_t sums = { .key_acc = 0, .payload_acc = 0 };
222+
hashtable_apply_to_all_key_payload_pairs_user_data(
223+
&hash_table, sum_key_payload_user_data, (void *)&sums);
224+
225+
CHECK((counters.key_acc == (uintptr_t)hash_table.entries) &&
226+
(counters.payload_acc == (uintptr_t)hash_table.entries),
227+
"hashtable_apply_to_all_key_payload_pairs_user_data (count test) failed");
228+
CHECK((sums.key_acc == 6) && (sums.payload_acc == 6),
229+
"hashtable_apply_to_all_key_payload_pairs_user_data (sum test) failed");
230+
231+
hashtable_delete(&hash_table);
232+
}
233+
185234
#define KEY 42
186235
#define PAYLOAD ((void *)12)
187236
static bool free_func_called;
@@ -217,6 +266,7 @@ dr_init(client_id_t id)
217266
test_vector();
218267
test_hashtable_apply_all();
219268
test_hashtable_apply_all_user_data();
269+
test_hashtable_apply_all_key_payload_pairs_user_data();
220270
test_dr_hashtable();
221271

222272
/* XXX: test other data structures */

0 commit comments

Comments
 (0)