/* Perform per-file snap operations. */
static void
-snap_file (const void *item, void *arg)
+snap_file (struct file *f, const struct dep *deps)
{
- struct file *f = (struct file*)item;
struct dep *prereqs = NULL;
struct dep *d;
}
}
else if (f->is_target)
- prereqs = copy_dep_chain (arg);
+ prereqs = copy_dep_chain (deps);
if (prereqs)
{
{
struct dep *prereqs = expand_extra_prereqs (lookup_variable (STRING_SIZE_TUPLE(".EXTRA_PREREQS")));
- /* Perform per-file snap operations. */
- hash_map_arg(&files, snap_file, prereqs);
+ /* Perform per-file snap operations.
+ We can't use hash_map*() here because snap_file may add new elements
+ into the files hash, which is not allowed in the map. Instead make a
+ dump of the files and walk through that. */
+ void** filedump = hash_dump (&files, NULL, 0);
+ for (void** filep = filedump; *filep; ++filep)
+ snap_file (*filep, prereqs);
+
+ free (filedump);
free_dep_chain (prereqs);
}
ht->ht_collisions = 0;
ht->ht_lookups = 0;
ht->ht_rehashes = 0;
+ ht->ht_in_map = 0;
ht->ht_hash_1 = hash_1;
ht->ht_hash_2 = hash_2;
ht->ht_compare = hash_cmp;
hash_insert_at (struct hash_table *ht, const void *item, const void *slot)
{
const void *old_item = *(void **) slot;
+
+ /* It's illegal to insert while in hash_map*(). */
+ assert (! ht->ht_in_map);
+
if (HASH_VACANT (old_item))
{
ht->ht_fill++;
{
void **vec = ht->ht_vec;
void **end = &vec[ht->ht_size];
+
+ /* It's illegal to free items while in hash_map*(). */
+ assert (! ht->ht_in_map);
+
for (; vec < end; vec++)
{
void *item = *vec;
{
void **vec = ht->ht_vec;
void **end = &vec[ht->ht_size];
+
+ /* It's illegal to delete all items while in hash_map*(). */
+ assert (! ht->ht_in_map);
+
for (; vec < end; vec++)
*vec = 0;
ht->ht_fill = 0;
void
hash_free (struct hash_table *ht, int free_items)
{
+ /* It's illegal to free while in hash_map*(). */
+ assert (! ht->ht_in_map);
+
if (free_items)
hash_free_items (ht);
else
void **slot;
void **end = &ht->ht_vec[ht->ht_size];
+ ht->ht_in_map = 1;
+
for (slot = ht->ht_vec; slot < end; slot++)
{
if (!HASH_VACANT (*slot))
(*map) (*slot);
}
+
+ ht->ht_in_map = 0;
}
void
void **slot;
void **end = &ht->ht_vec[ht->ht_size];
+ ht->ht_in_map = 1;
+
for (slot = ht->ht_vec; slot < end; slot++)
{
if (!HASH_VACANT (*slot))
(*map) (*slot, arg);
}
+
+ ht->ht_in_map = 0;
}
/* Double the size of the hash table in the event of overflow... */
unsigned long ht_collisions; /* # of failed calls to comparison function */
unsigned long ht_lookups; /* # of queries */
unsigned int ht_rehashes; /* # of times we've expanded table */
+ unsigned int ht_in_map:1; /* 1 if we're inside a hash_map*() function */
};
typedef int (*qsort_cmp_t) __P((void const *, void const *));
',
'', "hello.x.d\nhello.x\nworld.x.d\nworld.x\n");
+# SV 67046. Rehashing of hash table files during iteration.
+my $files = "";
+for my $k (1 .. 1000) {
+ $files = "$files file$k";
+}
+run_make_test(qq!
+all: .EXTRA_PREREQS := $files
+all:;
+file%:;
+!,
+ '', "#MAKE#: 'all' is up to date.");
-
-# This tells the test driver that the perl test script executed properly.
1;