From 8b604d19515c4be18403047045faa363d4de217b Mon Sep 17 00:00:00 2001 From: Jeff Hostetler Date: Wed, 6 Sep 2017 15:43:48 +0000 Subject: hashmap: add API to disable item counting when threaded This is to address concerns raised by ThreadSanitizer on the mailing list about threaded unprotected R/W access to map.size with my previous "disallow rehash" change (0607e10009ee4e37cb49b4cec8d28a9dda1656a4). See: https://public-inbox.org/git/adb37b70139fd1e2bac18bfd22c8b96683ae18eb.1502780344.git.martin.agren@gmail.com/ Add API to hashmap to disable item counting and thus automatic rehashing. Also include API to later re-enable them. When item counting is disabled, the map.size field is invalid. So to prevent accidents, the field has been renamed and an accessor function hashmap_get_size() has been added. All direct references to this field have been been updated. And the name of the field changed to map.private_size to communicate this. Here is the relevant output from ThreadSanitizer showing the problem: WARNING: ThreadSanitizer: data race (pid=10554) Read of size 4 at 0x00000082d488 by thread T2 (mutexes: write M16): #0 hashmap_add hashmap.c:209 #1 hash_dir_entry_with_parent_and_prefix name-hash.c:302 #2 handle_range_dir name-hash.c:347 #3 handle_range_1 name-hash.c:415 #4 lazy_dir_thread_proc name-hash.c:471 #5 Previous write of size 4 at 0x00000082d488 by thread T1 (mutexes: write M31): #0 hashmap_add hashmap.c:209 #1 hash_dir_entry_with_parent_and_prefix name-hash.c:302 #2 handle_range_dir name-hash.c:347 #3 handle_range_1 name-hash.c:415 #4 handle_range_dir name-hash.c:380 #5 handle_range_1 name-hash.c:415 #6 lazy_dir_thread_proc name-hash.c:471 #7 Martin gives instructions for running TSan on test t3008 in this post: https://public-inbox.org/git/CAN0heSoJDL9pWELD6ciLTmWf-a=oyxe4EXXOmCKvsG5MSuzxsA@mail.gmail.com/ Signed-off-by: Jeff Hostetler Signed-off-by: Junio C Hamano --- attr.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'attr.c') diff --git a/attr.c b/attr.c index 2f49151736..dfc3a558d8 100644 --- a/attr.c +++ b/attr.c @@ -151,10 +151,12 @@ struct all_attrs_item { static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check) { int i; + unsigned int size; hashmap_lock(map); - if (map->map.size < check->all_attrs_nr) + size = hashmap_get_size(&map->map); + if (size < check->all_attrs_nr) die("BUG: interned attributes shouldn't be deleted"); /* @@ -163,13 +165,13 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check) * field), reallocate the provided attr_check instance's all_attrs * field and fill each entry with its corresponding git_attr. */ - if (map->map.size != check->all_attrs_nr) { + if (size != check->all_attrs_nr) { struct attr_hash_entry *e; struct hashmap_iter iter; hashmap_iter_init(&map->map, &iter); - REALLOC_ARRAY(check->all_attrs, map->map.size); - check->all_attrs_nr = map->map.size; + REALLOC_ARRAY(check->all_attrs, size); + check->all_attrs_nr = size; while ((e = hashmap_iter_next(&iter))) { const struct git_attr *a = e->value; @@ -237,10 +239,11 @@ static const struct git_attr *git_attr_internal(const char *name, int namelen) if (!a) { FLEX_ALLOC_MEM(a, name, name, namelen); - a->attr_nr = g_attr_hashmap.map.size; + a->attr_nr = hashmap_get_size(&g_attr_hashmap.map); attr_hashmap_add(&g_attr_hashmap, a->name, namelen, a); - assert(a->attr_nr == (g_attr_hashmap.map.size - 1)); + assert(a->attr_nr == + (hashmap_get_size(&g_attr_hashmap.map) - 1)); } hashmap_unlock(&g_attr_hashmap); -- cgit v1.3-6-g1900