Module Name: src
Committed By: rillig
Date: Sun Nov 29 18:49:36 UTC 2020
Modified Files:
src/usr.bin/make: dir.c
src/usr.bin/make/unit-tests: Makefile
Log Message:
make(1): clean up memory management for CachedDirs
Previously, the reference count for a newly created CacheDir had been
set to 1 in CacheNewDir. This was wrong because at that point, the
object had not been referenced by any nonlocal variable. The reference
count is no longer incremented at this point.
All callers of CacheNewDir either append the newly created CachedDir to
a SearchPath via Lst_Append and CachedDir_Ref, or they assign it to a
global variable via CachedDir_Assign.
Since the reference count is no longer wrongly incremented, it does not
need to be decremented more than necessary in Dir_End. To keep the code
simple and maintainable, all assignments to global variables are now
handled by CachedDir_Assign. Adding a CachedDir to a list is still done
manually via Lst_Append, and the corresponding code for decrementing is
in SearchPath_Clean and SearchPath_Free. These details may be cleaned
up in a follow-up commit.
As a result, when OpenDirs_Done is called in the unit tests, the list of
open directories is empty. It had been non-empty in a single unit test
before (dep-wildcards.mk), as a result of calling Dir_Expand.
The additional debug logging for the reference counting is not enabled
by default since it contains memory addresses, which makes the output
dependent on the memory allocator.
The function CachedDir_Destroy has been merged into CachedDir_Undef,
which had only been used in Dir_End before. The new name emphasizes
that it corresponds to CachedDir_Ref.
To generate a diff of this commit:
cvs rdiff -u -r1.240 -r1.241 src/usr.bin/make/dir.c
cvs rdiff -u -r1.228 -r1.229 src/usr.bin/make/unit-tests/Makefile
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.bin/make/dir.c
diff -u src/usr.bin/make/dir.c:1.240 src/usr.bin/make/dir.c:1.241
--- src/usr.bin/make/dir.c:1.240 Sun Nov 29 16:37:10 2020
+++ src/usr.bin/make/dir.c Sun Nov 29 18:49:36 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: dir.c,v 1.240 2020/11/29 16:37:10 rillig Exp $ */
+/* $NetBSD: dir.c,v 1.241 2020/11/29 18:49:36 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -136,7 +136,7 @@
#include "job.h"
/* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */
-MAKE_RCSID("$NetBSD: dir.c,v 1.240 2020/11/29 16:37:10 rillig Exp $");
+MAKE_RCSID("$NetBSD: dir.c,v 1.241 2020/11/29 18:49:36 rillig Exp $");
#define DIR_DEBUG0(text) DEBUG0(DIR, text)
#define DIR_DEBUG1(fmt, arg1) DEBUG1(DIR, fmt, arg1)
@@ -299,6 +299,10 @@ CachedDir_New(const char *name)
dir->hits = 0;
HashSet_Init(&dir->files);
+#ifdef DEBUG_REFCNT
+ DEBUG2(DIR, "CachedDir %p new for \"%s\"\n", dir, dir->name);
+#endif
+
return dir;
}
@@ -306,15 +310,31 @@ static CachedDir *
CachedDir_Ref(CachedDir *dir)
{
dir->refCount++;
- DEBUG2(DIR, "CachedDir refCount++ to %d for \"%s\"\n",
- dir->refCount, dir->name);
+
+#ifdef DEBUG_REFCNT
+ DEBUG3(DIR, "CachedDir %p ++ %d for \"%s\"\n",
+ dir, dir->refCount, dir->name);
+#endif
+
return dir;
}
-/* Free a cached directory with reference count 0. */
static void
-CachedDir_Free0(CachedDir *dir)
+CachedDir_Unref(CachedDir *dir)
{
+ dir->refCount--;
+
+#ifdef DEBUG_REFCNT
+ DEBUG3(DIR, "CachedDir %p -- %d for \"%s\"\n",
+ dir, dir->refCount, dir->name);
+#endif
+
+ if (dir->refCount > 0)
+ return;
+
+#ifdef DEBUG_REFCNT
+ DEBUG2(DIR, "CachedDir %p free for \"%s\"\n", dir, dir->name);
+#endif
OpenDirs_Remove(&openDirs, dir->name);
@@ -323,24 +343,6 @@ CachedDir_Free0(CachedDir *dir)
free(dir);
}
-static void
-CachedDir_Unref(CachedDir *dir)
-{
- dir->refCount--;
- DEBUG2(DIR, "CachedDir refCount-- to %d for \"%s\"\n",
- dir->refCount, dir->name);
-}
-
-/* Nuke a directory descriptor, if it is no longer used. */
-static void
-CachedDir_Destroy(CachedDir *dir)
-{
- CachedDir_Unref(dir);
-
- if (dir->refCount == 0)
- CachedDir_Free0(dir);
-}
-
/* Update the value of the CachedDir variable, updating the reference counts. */
static void
CachedDir_Assign(CachedDir **var, CachedDir *dir)
@@ -352,7 +354,7 @@ CachedDir_Assign(CachedDir **var, Cached
if (dir != NULL)
CachedDir_Ref(dir);
if (prev != NULL)
- CachedDir_Destroy(prev);
+ CachedDir_Unref(prev);
}
static void
@@ -374,7 +376,7 @@ OpenDirs_Done(OpenDirs *odirs)
CachedDir *dir = ln->datum;
DIR_DEBUG2("OpenDirs_Done: refCount %d for \"%s\"\n",
dir->refCount, dir->name);
- CachedDir_Destroy(dir); /* removes the dir from odirs->list */
+ CachedDir_Unref(dir); /* removes the dir from odirs->list */
ln = next;
}
Lst_Done(&odirs->list);
@@ -502,11 +504,7 @@ Dir_InitCur(const char *cdname)
if (dir == NULL)
return;
- if (cur != NULL && cur != dir) {
- CachedDir_Unref(cur); /* XXX: why unref twice? */
- CachedDir_Destroy(cur);
- }
- cur = CachedDir_Ref(dir);
+ CachedDir_Assign(&cur, dir);
}
/* (Re)initialize "dot" (current/object directory) path hash.
@@ -514,31 +512,16 @@ Dir_InitCur(const char *cdname)
void
Dir_InitDot(void)
{
- if (dot != NULL) {
- /* Remove old entry from openDirs, but do not destroy. */
- /* XXX: Why not destroy? It's reference-counted after all. */
- OpenDirs_Remove(&openDirs, dot->name);
- }
-
- /* XXX: Before assigning to the global variable, refCount++. */
- dot = Dir_AddDir(NULL, ".");
+ CachedDir *dir;
- if (dot == NULL) {
+ dir = Dir_AddDir(NULL, ".");
+ if (dir == NULL) {
Error("Cannot open `.' (%s)", strerror(errno));
exit(1);
}
- /*
- * We always need to have dot around, so we increment its reference
- * count to make sure it's not destroyed.
- */
- /*
- * XXX: This is just the normal reference counting. Why is the above
- * comment so long? And why doesn't the normal reference counting
- * suffice? This sounds like someone misunderstood reference counting
- * here.
- */
- CachedDir_Ref(dot);
+ CachedDir_Assign(&dot, dir);
+
Dir_SetPATH(); /* initialize */
}
@@ -547,13 +530,9 @@ void
Dir_End(void)
{
#ifdef CLEANUP
- if (cur != NULL) {
- CachedDir_Unref(cur); /* XXX: why unref twice? */
- CachedDir_Destroy(cur);
- }
+ CachedDir_Assign(&cur, NULL);
+ CachedDir_Assign(&dot, NULL);
CachedDir_Assign(&dotLast, NULL);
- CachedDir_Unref(dot); /* XXX: why unref twice? */
- CachedDir_Destroy(dot);
SearchPath_Clear(&dirSearchPath);
OpenDirs_Done(&openDirs);
HashTable_Done(&mtimes);
@@ -953,9 +932,7 @@ Dir_Expand(const char *word, SearchPath
partPath = SearchPath_New();
(void)Dir_AddDir(partPath, dirpath);
DirExpandPath(cp + 1, partPath, expansions);
- Lst_Free(partPath);
- /* XXX: Should the dirs in partPath be freed here?
- * It's not obvious whether to free them or not. */
+ SearchPath_Free(partPath);
}
}
@@ -1514,7 +1491,6 @@ CacheNewDir(const char *name, SearchPath
DIR_DEBUG1("Caching %s ...\n", name);
dir = CachedDir_New(name);
- CachedDir_Ref(dir); /* XXX: why here already? */
while ((dp = readdir(d)) != NULL) {
@@ -1534,7 +1510,7 @@ CacheNewDir(const char *name, SearchPath
OpenDirs_Add(&openDirs, dir);
if (path != NULL)
- Lst_Append(path, dir);
+ Lst_Append(path, CachedDir_Ref(dir));
DIR_DEBUG1("Caching %s done\n", name);
return dir;
@@ -1565,8 +1541,7 @@ Dir_AddDir(SearchPath *path, const char
return pathDir;
}
- CachedDir_Ref(dotLast);
- Lst_Prepend(path, dotLast);
+ Lst_Prepend(path, CachedDir_Ref(dotLast));
}
if (path != NULL) {
@@ -1644,7 +1619,7 @@ SearchPath_Free(SearchPath *path)
for (ln = path->first; ln != NULL; ln = ln->next) {
CachedDir *dir = ln->datum;
- CachedDir_Destroy(dir);
+ CachedDir_Unref(dir);
}
Lst_Free(path);
}
@@ -1656,7 +1631,7 @@ SearchPath_Clear(SearchPath *path)
{
while (!Lst_IsEmpty(path)) {
CachedDir *dir = Lst_Dequeue(path);
- CachedDir_Destroy(dir);
+ CachedDir_Unref(dir);
}
}
Index: src/usr.bin/make/unit-tests/Makefile
diff -u src/usr.bin/make/unit-tests/Makefile:1.228 src/usr.bin/make/unit-tests/Makefile:1.229
--- src/usr.bin/make/unit-tests/Makefile:1.228 Sun Nov 29 14:29:19 2020
+++ src/usr.bin/make/unit-tests/Makefile Sun Nov 29 18:49:36 2020
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.228 2020/11/29 14:29:19 rillig Exp $
+# $NetBSD: Makefile,v 1.229 2020/11/29 18:49:36 rillig Exp $
#
# Unit tests for make(1)
#
@@ -440,7 +440,7 @@ FLAGS.varname-empty= -dv '$${:U}=cmdline
# Some tests need extra postprocessing.
SED_CMDS.dir= ${:D remove output from -DCLEANUP mode }
SED_CMDS.dir+= -e '/^OpenDirs_Done:/d'
-SED_CMDS.dir+= -e '/^CachedDir refCount/d'
+SED_CMDS.dir+= -e '/^CachedDir /d'
SED_CMDS.export= -e '/^[^=_A-Za-z0-9]*=/d'
SED_CMDS.export-all= ${SED_CMDS.export}
SED_CMDS.export-env= ${SED_CMDS.export}