diff options
Diffstat (limited to 'libctf')
-rw-r--r-- | libctf/ChangeLog | 16 | ||||
-rw-r--r-- | libctf/ctf-create.c | 4 | ||||
-rw-r--r-- | libctf/ctf-impl.h | 2 | ||||
-rw-r--r-- | libctf/ctf-link.c | 2 | ||||
-rw-r--r-- | libctf/ctf-open.c | 51 |
5 files changed, 67 insertions, 8 deletions
diff --git a/libctf/ChangeLog b/libctf/ChangeLog index f756fc4..4830284 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,5 +1,21 @@ 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... (ctf_link_type_key): ... this, adjusting member prefixes to match. diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index a538b2d..a964c20 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -516,8 +516,9 @@ ctf_serialize (ctf_file_t *fp) } (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) @@ -565,6 +566,7 @@ ctf_serialize (ctf_file_t *fp) 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)); diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index b9d52af..4c8a37c 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -291,6 +291,7 @@ struct ctf_file 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. */ @@ -536,6 +537,7 @@ extern ctf_file_t *ctf_simple_open_internal (const char *, size_t, const char *, 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_ diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c index c331fde..bcfd256 100644 --- a/libctf/ctf-link.c +++ b/libctf/ctf-link.c @@ -222,7 +222,7 @@ ctf_create_per_cu (ctf_file_t *fp, const char *filename, const char *cuname) 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); } diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c index 24899f0..87bff2f 100644 --- a/libctf/ctf-open.c +++ b/libctf/ctf-open.c @@ -1657,9 +1657,17 @@ ctf_file_close (ctf_file_t *fp) 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) { @@ -1816,13 +1824,44 @@ ctf_import (ctf_file_t *fp, ctf_file_t *pfp) 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; @@ -1832,7 +1871,7 @@ ctf_import (ctf_file_t *fp, ctf_file_t *pfp) return err; fp->ctf_flags |= LCTF_CHILD; - pfp->ctf_refcnt++; + fp->ctf_parent_unreffed = 1; } fp->ctf_parent = pfp; |