+2020-07-22 Nick Alcock <nick.alcock@oracle.com>
+
+ * ctf-impl.c (ctf_file_t) <ctf_parent_unreffed>: New.
+ (ctf_import_unref): New.
+ * ctf-open.c (ctf_file_close) Drop the refcount all the way to
+ zero. Don't recurse back in if the refcount is already zero.
+ (ctf_import): Check ctf_parent_unreffed before deciding whether
+ to close a pre-existing parent. Set it to zero.
+ (ctf_import_unreffed): New, as above, setting
+ ctf_parent_unreffed to 1.
+ * ctf-create.c (ctf_serialize): Do not ctf_import into the new
+ child: use direct assignment, and set unreffed on the new and
+ old children.
+ * ctf-link.c (ctf_create_per_cu): Import the parent using
+ ctf_import_unreffed.
+
2020-07-22 Nick Alcock <nick.alcock@oracle.com>
* ctf-impl.h (ctf_link_type_mapping_key): Rename to...
}
(void) ctf_setmodel (nfp, ctf_getmodel (fp));
- (void) ctf_import (nfp, fp->ctf_parent);
+ nfp->ctf_parent = fp->ctf_parent;
+ nfp->ctf_parent_unreffed = fp->ctf_parent_unreffed;
nfp->ctf_refcnt = fp->ctf_refcnt;
nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY;
if (nfp->ctf_dynbase == NULL)
fp->ctf_syn_ext_strtab = NULL;
fp->ctf_link_cu_mapping = NULL;
fp->ctf_link_type_mapping = NULL;
+ fp->ctf_parent_unreffed = 1;
fp->ctf_dvhash = NULL;
memset (&fp->ctf_dvdefs, 0, sizeof (ctf_list_t));
const char *ctf_cuname; /* Compilation unit name (if any). */
char *ctf_dyncuname; /* Dynamically allocated name of CU. */
struct ctf_file *ctf_parent; /* Parent CTF container (if any). */
+ int ctf_parent_unreffed; /* Parent set by ctf_import_unref? */
const char *ctf_parlabel; /* Label in parent container (if any). */
const char *ctf_parname; /* Basename of parent (if any). */
char *ctf_dynparname; /* Dynamically allocated name of parent. */
extern ctf_file_t *ctf_bufopen_internal (const ctf_sect_t *, const ctf_sect_t *,
const ctf_sect_t *, ctf_dynhash_t *,
int, int *);
+extern int ctf_import_unref (ctf_file_t *fp, ctf_file_t *pfp);
extern int ctf_serialize (ctf_file_t *);
_libctf_malloc_
if (ctf_dynhash_insert (fp->ctf_link_outputs, dynname, cu_fp) < 0)
goto oom;
- ctf_import (cu_fp, fp);
+ ctf_import_unref (cu_fp, fp);
ctf_cuname_set (cu_fp, cuname);
ctf_parent_name_set (cu_fp, _CTF_SECTION);
}
return;
}
+ /* It is possible to recurse back in here, notably if dicts in the
+ ctf_link_inputs or ctf_link_outputs cite this dict as a parent without
+ using ctf_import_unref. Do nothing in that case. */
+ if (fp->ctf_refcnt == 0)
+ return;
+
+ fp->ctf_refcnt--;
free (fp->ctf_dyncuname);
free (fp->ctf_dynparname);
- ctf_file_close (fp->ctf_parent);
+ if (fp->ctf_parent && !fp->ctf_parent_unreffed)
+ ctf_file_close (fp->ctf_parent);
for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
{
if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
return (ctf_set_errno (fp, ECTF_DMODEL));
- if (fp->ctf_parent != NULL)
+ if (fp->ctf_parent && !fp->ctf_parent_unreffed)
+ ctf_file_close (fp->ctf_parent);
+ fp->ctf_parent = NULL;
+
+ if (pfp != NULL)
{
- fp->ctf_parent->ctf_refcnt--;
- ctf_file_close (fp->ctf_parent);
- fp->ctf_parent = NULL;
+ int err;
+
+ if (fp->ctf_parname == NULL)
+ if ((err = ctf_parent_name_set (fp, "PARENT")) < 0)
+ return err;
+
+ fp->ctf_flags |= LCTF_CHILD;
+ pfp->ctf_refcnt++;
+ fp->ctf_parent_unreffed = 0;
}
+ fp->ctf_parent = pfp;
+ return 0;
+}
+
+/* Like ctf_import, but does not increment the refcount on the imported parent
+ or close it at any point: as a result it can go away at any time and the
+ caller must do all freeing itself. Used internally to avoid refcount
+ loops. */
+int
+ctf_import_unref (ctf_file_t *fp, ctf_file_t *pfp)
+{
+ if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0))
+ return (ctf_set_errno (fp, EINVAL));
+
+ if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel)
+ return (ctf_set_errno (fp, ECTF_DMODEL));
+
+ if (fp->ctf_parent && !fp->ctf_parent_unreffed)
+ ctf_file_close (fp->ctf_parent);
+ fp->ctf_parent = NULL;
+
if (pfp != NULL)
{
int err;
return err;
fp->ctf_flags |= LCTF_CHILD;
- pfp->ctf_refcnt++;
+ fp->ctf_parent_unreffed = 1;
}
fp->ctf_parent = pfp;