From ae0a6aa6b65d4155b69b2ca0d4005a44035b86d4 Mon Sep 17 00:00:00 2001 From: krangelov Date: Sat, 11 Sep 2021 16:33:22 +0200 Subject: [PATCH] clean up everything after revision is not needed anymore. --- src/runtime/c/Makefile.am | 1 + src/runtime/c/pgf/data.cxx | 39 ++++++ src/runtime/c/pgf/data.h | 63 +++------ src/runtime/c/pgf/db.cxx | 20 +-- src/runtime/c/pgf/db.h | 16 +-- src/runtime/c/pgf/expr.cxx | 150 ++++++++++++++++++++ src/runtime/c/pgf/expr.h | 65 +++++++++ src/runtime/c/pgf/namespace.h | 159 +++++++++++++++++----- src/runtime/c/pgf/pgf.cxx | 44 +++--- src/runtime/c/pgf/reader.cxx | 4 + src/runtime/haskell/tests/transactions.hs | 10 +- 11 files changed, 455 insertions(+), 116 deletions(-) create mode 100644 src/runtime/c/pgf/data.cxx diff --git a/src/runtime/c/Makefile.am b/src/runtime/c/Makefile.am index be022e7b9..1d1ccaa06 100644 --- a/src/runtime/c/Makefile.am +++ b/src/runtime/c/Makefile.am @@ -17,6 +17,7 @@ libpgf_la_SOURCES = \ pgf/reader.h \ pgf/printer.cxx \ pgf/printer.h \ + pgf/data.cxx \ pgf/data.h \ pgf/expr.cxx \ pgf/expr.h \ diff --git a/src/runtime/c/pgf/data.cxx b/src/runtime/c/pgf/data.cxx new file mode 100644 index 000000000..bffbce7f4 --- /dev/null +++ b/src/runtime/c/pgf/data.cxx @@ -0,0 +1,39 @@ +#include "data.h" + +void PgfFlag::release(ref flag) +{ + pgf_literal_free(flag->value); +} + +void PgfAbsFun::release(ref absfun) +{ + pgf_type_free(absfun->type); + + if (absfun->defns != 0) { + for (size_t i = 0; i < absfun->defns->len; i++) { + ref eq = *vector_elem(absfun->defns, i); + pgf_expr_free(eq->body); + + for (size_t j = 0; j < eq->patts.len; j++) { + PgfPatt patt = *vector_elem(ref>::from_ptr(&eq->patts), j); + pgf_patt_free(patt); + } + } + + PgfDB::free(absfun->defns); + } +} + +void PgfAbsCat::release(ref abscat) +{ + pgf_context_free(abscat->context); +} + +void PgfPGF::release(ref pgf) +{ + namespace_release(pgf->gflags); + PgfDB::free(pgf->abstract.name); + namespace_release(pgf->abstract.aflags); + namespace_release(pgf->abstract.funs); + namespace_release(pgf->abstract.cats); +} diff --git a/src/runtime/c/pgf/data.h b/src/runtime/c/pgf/data.h index 02b35143a..c7e5089c7 100644 --- a/src/runtime/c/pgf/data.h +++ b/src/runtime/c/pgf/data.h @@ -63,54 +63,11 @@ class PgfPGF; #include "expr.h" struct PGF_INTERNAL_DECL PgfFlag { + size_t ref_count; PgfLiteral value; PgfText name; -}; -// PgfPatt - -typedef object PgfPatt; - -struct PGF_INTERNAL_DECL PgfPattApp { - static const uint8_t tag = 0; - - ref ctor; - PgfVector args; -}; - -struct PGF_INTERNAL_DECL PgfPattVar { - static const uint8_t tag = 1; - - PgfText name; -}; - -struct PGF_INTERNAL_DECL PgfPattAs { - static const uint8_t tag = 2; - - PgfPatt patt; - PgfText name; -}; - -struct PGF_INTERNAL_DECL PgfPattWild { - static const uint8_t tag = 3; -}; - -struct PGF_INTERNAL_DECL PgfPattLit { - static const uint8_t tag = 4; - - PgfLiteral lit; -}; - -struct PGF_INTERNAL_DECL PgfPattImplArg { - static const uint8_t tag = 5; - - PgfPatt patt; -}; - -struct PGF_INTERNAL_DECL PgfPattTilde { - static const uint8_t tag = 6; - - PgfExpr expr; + static void release(ref pgf); }; typedef struct { @@ -119,18 +76,26 @@ typedef struct { } PgfEquation; struct PGF_INTERNAL_DECL PgfAbsFun { + size_t ref_count; + ref type; int arity; ref>> defns; PgfExprProb ep; PgfText name; + + static void release(ref cat); }; -typedef struct { +struct PGF_INTERNAL_DECL PgfAbsCat { + size_t ref_count; + ref> context; prob_t prob; PgfText name; -} PgfAbsCat; + + static void release(ref cat); +}; typedef struct { ref name; @@ -140,6 +105,8 @@ typedef struct { } PgfAbstr; struct PGF_INTERNAL_DECL PgfPGF { + size_t ref_count; + uint16_t major_version; uint16_t minor_version; Namespace gflags; @@ -153,6 +120,8 @@ struct PGF_INTERNAL_DECL PgfPGF { // The name lets the user to find a particular revision in // the database. PgfText name; + + static void release(ref pgf); }; extern PGF_INTERNAL_DECL diff --git a/src/runtime/c/pgf/db.cxx b/src/runtime/c/pgf/db.cxx index 44bc78a04..8f0bf4daa 100644 --- a/src/runtime/c/pgf/db.cxx +++ b/src/runtime/c/pgf/db.cxx @@ -5,9 +5,9 @@ #include "data.h" -PGF_INTERNAL __thread unsigned char* current_base __attribute__((tls_model("initial-exec"))) = NULL; -PGF_INTERNAL __thread PgfDB* current_db __attribute__((tls_model("initial-exec"))) = NULL; -PGF_INTERNAL __thread DB_scope *last_db_scope __attribute__((tls_model("initial-exec"))) = NULL; +PGF_INTERNAL unsigned char* current_base = NULL; +PGF_INTERNAL PgfDB* current_db = NULL; +PGF_INTERNAL DB_scope *last_db_scope = NULL; #ifndef DEFAULT_TOP_PAD #define DEFAULT_TOP_PAD (0) @@ -369,6 +369,7 @@ ref PgfDB::get_revision(PgfText *name) PGF_INTERNAL void PgfDB::set_revision(ref pgf) { + pgf->ref_count++; Namespace nmsp = namespace_insert(current_db->ms->revisions, pgf); namespace_release(current_db->ms->revisions); current_db->ms->revisions = nmsp; @@ -993,6 +994,13 @@ ref PgfDB::revision2pgf(PgfRevision revision) return pgf; } +PGF_INTERNAL +bool PgfDB::is_persistant_revision(ref pgf) +{ + return (pgf->prev == 0 && pgf->next == 0 && + current_db->ms->transient_revisions != pgf); +} + PGF_INTERNAL void PgfDB::link_transient_revision(ref pgf) { @@ -1003,7 +1011,7 @@ void PgfDB::link_transient_revision(ref pgf) } PGF_INTERNAL -bool PgfDB::unlink_transient_revision(ref pgf) +void PgfDB::unlink_transient_revision(ref pgf) { if (pgf->next != 0) pgf->next->prev = pgf->prev; @@ -1011,10 +1019,6 @@ bool PgfDB::unlink_transient_revision(ref pgf) pgf->prev->next = pgf->next; else if (current_db->ms->transient_revisions == pgf) current_db->ms->transient_revisions = pgf->next; - else - return false; - - return true; } DB_scope::DB_scope(PgfDB *db, DB_scope_mode tp) diff --git a/src/runtime/c/pgf/db.h b/src/runtime/c/pgf/db.h index ac8e0558b..ddbe5a846 100644 --- a/src/runtime/c/pgf/db.h +++ b/src/runtime/c/pgf/db.h @@ -5,8 +5,8 @@ class PgfDB; -extern PGF_INTERNAL_DECL __thread unsigned char* current_base __attribute__((tls_model("initial-exec"))); -extern PGF_INTERNAL_DECL __thread PgfDB* current_db __attribute__((tls_model("initial-exec"))); +extern PGF_INTERNAL_DECL unsigned char* current_base; +extern PGF_INTERNAL_DECL PgfDB* current_db; struct malloc_state; @@ -75,14 +75,15 @@ public: template static void free(ref o) { - return current_db->free_internal(o.as_object()); + current_db->free_internal(o.as_object()); } static PGF_INTERNAL_DECL ref get_revision(PgfText *name); static PGF_INTERNAL_DECL void set_revision(ref pgf); static PGF_INTERNAL_DECL ref revision2pgf(PgfRevision revision); + static PGF_INTERNAL_DECL bool is_persistant_revision(ref pgf); static PGF_INTERNAL_DECL void link_transient_revision(ref pgf); - static PGF_INTERNAL_DECL bool unlink_transient_revision(ref pgf); + static PGF_INTERNAL_DECL void unlink_transient_revision(ref pgf); PGF_INTERNAL_DECL static void sync(); @@ -92,11 +93,6 @@ private: PGF_INTERNAL_DECL object malloc_internal(size_t bytes); PGF_INTERNAL_DECL void free_internal(object o); - PGF_INTERNAL_DECL object get_root_internal(); - PGF_INTERNAL_DECL void set_root_internal(object root_offset); - - PGF_INTERNAL_DECL unsigned char* relocate(unsigned char* ptr); - friend class DB_scope; }; @@ -112,6 +108,6 @@ private: DB_scope* next_scope; }; -extern PGF_INTERNAL_DECL thread_local DB_scope *last_db_scope; +extern PGF_INTERNAL_DECL DB_scope *last_db_scope; #endif diff --git a/src/runtime/c/pgf/expr.cxx b/src/runtime/c/pgf/expr.cxx index d94153d73..0d0266726 100644 --- a/src/runtime/c/pgf/expr.cxx +++ b/src/runtime/c/pgf/expr.cxx @@ -920,3 +920,153 @@ exit: return type; } + + +PGF_INTERNAL +void pgf_literal_free(PgfLiteral literal) +{ + switch (ref::get_tag(literal)) { + case PgfLiteralInt::tag: { + PgfDB::free(ref::untagged(literal)); + break; + } + case PgfLiteralFlt::tag: { + PgfDB::free(ref::untagged(literal)); + break; + } + case PgfLiteralStr::tag: { + PgfDB::free(ref::untagged(literal)); + break; + } + default: + throw pgf_error("Unknown literal tag"); + } +} + +PGF_INTERNAL +void pgf_expr_free(PgfExpr expr) +{ + switch (ref::get_tag(expr)) { + case PgfExprAbs::tag: { + auto eabs = ref::untagged(expr); + pgf_expr_free(eabs->body); + PgfDB::free(eabs); + break; + } + case PgfExprApp::tag: { + auto eapp = ref::untagged(expr); + pgf_expr_free(eapp->fun); + pgf_expr_free(eapp->arg); + PgfDB::free(eapp); + break; + } + case PgfExprLit::tag: { + auto elit = ref::untagged(expr); + pgf_literal_free(elit->lit); + PgfDB::free(elit); + break; + } + case PgfExprMeta::tag: { + PgfDB::free(ref::untagged(expr)); + break; + } + case PgfExprFun::tag: { + PgfDB::free(ref::untagged(expr)); + break; + } + case PgfExprVar::tag: { + PgfDB::free(ref::untagged(expr)); + break; + } + case PgfExprTyped::tag: { + auto etyped = ref::untagged(expr); + pgf_expr_free(etyped->expr); + pgf_type_free(etyped->type); + PgfDB::free(etyped); + break; + } + case PgfExprImplArg::tag: { + auto eimpl = ref::untagged(expr); + pgf_expr_free(eimpl->expr); + PgfDB::free(eimpl); + break; + } + default: + throw pgf_error("Unknown expression tag"); + } +} + +PGF_INTERNAL +void pgf_context_free(ref> hypos) +{ + for (size_t i = 0; i < hypos->len; i++) { + PgfDB::free(vector_elem(hypos, i)->cid); + pgf_type_free(vector_elem(hypos, i)->type); + } + + PgfDB::free(hypos); +} + +PGF_INTERNAL +void pgf_type_free(ref dtyp) +{ + pgf_context_free(dtyp->hypos); + + for (size_t i = 0; i < dtyp->exprs->len; i++) { + pgf_expr_free(*vector_elem(dtyp->exprs, i)); + } + PgfDB::free(dtyp->exprs); + + PgfDB::free(dtyp); +} + +PGF_INTERNAL +void pgf_patt_free(PgfPatt patt) +{ + switch (ref::get_tag(patt)) { + case PgfPattApp::tag: { + auto papp = ref::untagged(patt); + PgfDB::free(papp->ctor); + for (size_t i = 0; i < papp->args.len; i++) { + PgfPatt patt = *vector_elem(ref>::from_ptr(&papp->args), i); + pgf_patt_free(patt); + } + PgfDB::free(papp); + break; + } + case PgfPattVar::tag: { + PgfDB::free(ref::untagged(patt)); + break; + } + case PgfPattAs::tag: { + auto pas = ref::untagged(patt); + pgf_patt_free(pas->patt); + PgfDB::free(pas); + break; + } + case PgfPattWild::tag: { + PgfDB::free(ref::untagged(patt)); + break; + } + case PgfPattLit::tag: { + auto plit = ref::untagged(patt); + pgf_literal_free(plit->lit); + PgfDB::free(plit); + break; + } + case PgfPattImplArg::tag: { + auto pimpl = ref::untagged(patt); + pgf_patt_free(pimpl->patt); + PgfDB::free(pimpl); + break; + } + case PgfPattTilde::tag: { + auto ptilde = ref::untagged(patt); + pgf_patt_free(ptilde->expr); + PgfDB::free(ptilde); + break; + } + default: + throw pgf_error("Unknown pattern tag"); + } +} diff --git a/src/runtime/c/pgf/expr.h b/src/runtime/c/pgf/expr.h index 1ac3c80ac..bcc45bef4 100644 --- a/src/runtime/c/pgf/expr.h +++ b/src/runtime/c/pgf/expr.h @@ -87,6 +87,52 @@ struct PGF_INTERNAL_DECL PgfExprImplArg { PgfExpr expr; }; +// PgfPatt + +typedef object PgfPatt; + +struct PGF_INTERNAL_DECL PgfPattApp { + static const uint8_t tag = 0; + + ref ctor; + PgfVector args; +}; + +struct PGF_INTERNAL_DECL PgfPattVar { + static const uint8_t tag = 1; + + PgfText name; +}; + +struct PGF_INTERNAL_DECL PgfPattAs { + static const uint8_t tag = 2; + + PgfPatt patt; + PgfText name; +}; + +struct PGF_INTERNAL_DECL PgfPattWild { + static const uint8_t tag = 3; +}; + +struct PGF_INTERNAL_DECL PgfPattLit { + static const uint8_t tag = 4; + + PgfLiteral lit; +}; + +struct PGF_INTERNAL_DECL PgfPattImplArg { + static const uint8_t tag = 5; + + PgfPatt patt; +}; + +struct PGF_INTERNAL_DECL PgfPattTilde { + static const uint8_t tag = 6; + + PgfExpr expr; +}; + typedef float prob_t; typedef struct { @@ -191,4 +237,23 @@ public: PGF_INTERNAL_DECL extern PgfText wildcard; +/* The following functions release the memory in the database, + * allocated for values of the corresponding types. + */ + +PGF_INTERNAL_DECL +void pgf_literal_free(PgfLiteral literal); + +PGF_INTERNAL_DECL +void pgf_expr_free(PgfExpr expr); + +PGF_INTERNAL_DECL +void pgf_context_free(ref> hypos); + +PGF_INTERNAL_DECL +void pgf_type_free(ref dtyp); + +PGF_INTERNAL_DECL +void pgf_patt_free(PgfPatt patt); + #endif /* EXPR_H_ */ diff --git a/src/runtime/c/pgf/namespace.h b/src/runtime/c/pgf/namespace.h index 32b8668f7..af1dc1f1c 100644 --- a/src/runtime/c/pgf/namespace.h +++ b/src/runtime/c/pgf/namespace.h @@ -3,6 +3,19 @@ #include "db.h" +// #define DEBUG_NAMESPACE + +/* Namespace expects that the class V contains: + * + * - A member 'size_t ref_count' which keeps track of the number of + * references to the particular object. + * - A member 'PgfText name' which contains the name of the object. + * - A method: + * static void release(ref object) + * which is executed when ref_count becomes zero. After that the memory + * for the object is released as well. + */ + template class Node; @@ -29,6 +42,10 @@ public: node->value = value; node->left = 0; node->right = 0; + +#ifdef DEBUG_NAMESPACE + printf("new node %6ld %s\n", node.as_object(), node->value->name.text); +#endif return node; } @@ -41,21 +58,48 @@ public: node->value = value; node->left = left; node->right = right; + +#ifdef DEBUG_NAMESPACE + printf("new node %6ld %s(%ld,%ld)\n", node.as_object(), node->value->name.text, left.as_object(), right.as_object()); +#endif return node; } + static + void add_node_ref(ref node) + { + node->ref_count++; +#ifdef DEBUG_NAMESPACE + printf("add_ref node %6ld %s (ref_count=%ld)\n", node.as_object(), node->value->name.text, node->ref_count); +#endif + } + + static + void add_value_ref(ref value) + { + value->ref_count++; +#ifdef DEBUG_NAMESPACE + printf("add_ref value %5ld %s (ref_count=%ld)\n", value.as_object(), value->name.text, value->ref_count); +#endif + } + static ref balanceL(ref value, ref left, ref right) { if (right == 0) { if (left == 0) { + value->ref_count++; return new_node(value); } else { if (left->left == 0) { if (left->right == 0) { - left->ref_count++; + add_value_ref(value); + add_node_ref(left); return new_node(value,left,0); } else { + add_value_ref(value); + add_value_ref(left->value); + add_value_ref(left->right->value); Namespace new_left = new_node(left->value); Namespace new_right = new_node(value); return new_node(left->right->value, @@ -64,15 +108,19 @@ public: } } else { if (left->right == 0) { + add_value_ref(value); Namespace new_right = new_node(value); - left->left->ref_count++; + add_value_ref(left->value); + add_node_ref(left->left); return new_node(left->value, left->left, new_right); } else { if (left->right->sz < 2 * left->left->sz) { - left->left->ref_count++; - left->right->ref_count++; + add_value_ref(value); + add_value_ref(left->value); + add_node_ref(left->left); + add_node_ref(left->right); Namespace new_right = new_node(value, left->right, @@ -81,11 +129,14 @@ public: left->left, new_right); } else { - left->left->ref_count++; + add_value_ref(value); + add_value_ref(left->value); + add_value_ref(left->right->value); + add_node_ref(left->left); if (left->right->left != 0) - left->right->left->ref_count++; + add_node_ref(left->right->left); if (left->right->right != 0) - left->right->right->ref_count++; + add_node_ref(left->right->right); Namespace new_left = new_node(left->value, left->left, @@ -103,14 +154,17 @@ public: } } else { if (left == 0) { - right->ref_count++; + add_value_ref(value); + add_node_ref(right); return new_node(value,0,right); } else { if (left->sz > 3*right->sz) { if (left->right->sz < 2*left->left->sz) { - left->left->ref_count++; - left->right->ref_count++; - right->ref_count++; + add_value_ref(value); + add_value_ref(left->value); + add_node_ref(left->left); + add_node_ref(left->right); + add_node_ref(right); Namespace new_right = new_node(value, left->right, @@ -119,12 +173,15 @@ public: left->left, new_right); } else { - left->left->ref_count++; + add_value_ref(value); + add_value_ref(left->value); + add_value_ref(left->right->value); + add_node_ref(left->left); if (left->right->left != 0) - left->right->left->ref_count++; + add_node_ref(left->right->left); if (left->right->right != 0) - left->right->right->ref_count++; - right->ref_count++; + add_node_ref(left->right->right); + add_node_ref(right); Namespace new_left = new_node(left->value, left->left, @@ -138,8 +195,9 @@ public: new_right); } } else { - left->ref_count++; - right->ref_count++; + add_value_ref(value); + add_node_ref(left); + add_node_ref(right); return new_node(value,left,right); } } @@ -151,14 +209,18 @@ public: { if (left == 0) { if (right == 0) { + add_value_ref(value); return new_node(value); } else { if (right->left == 0) { if (right->right == 0) { - right->ref_count++; + add_value_ref(value); + add_node_ref(right); return new_node(value,0,right); } else { - right->right->ref_count++; + add_value_ref(value); + add_value_ref(right->value); + add_node_ref(right->right); Namespace new_left = new_node(value); return new_node(right->value, @@ -167,6 +229,9 @@ public: } } else { if (right->right == 0) { + add_value_ref(value); + add_value_ref(right->value); + add_value_ref(right->left->value); Namespace new_left = new_node(value); Namespace new_right = @@ -176,8 +241,10 @@ public: new_right); } else { if (right->left->sz < 2 * right->right->sz) { - right->left->ref_count++; - right->right->ref_count++; + add_value_ref(value); + add_value_ref(right->value); + add_node_ref(right->left); + add_node_ref(right->right); Namespace new_left = new_node(value, 0, @@ -186,11 +253,14 @@ public: new_left, right->right); } else { + add_value_ref(value); + add_value_ref(right->value); + add_value_ref(right->left->value); if (right->left->left != 0) - right->left->left->ref_count++; + add_node_ref(right->left->left); if (right->left->right != 0) - right->left->right->ref_count++; - right->right->ref_count++; + add_node_ref(right->left->right); + add_node_ref(right->right); Namespace new_left = new_node(value, 0, @@ -208,14 +278,17 @@ public: } } else { if (right == 0) { - left->ref_count++; + add_value_ref(value); + add_node_ref(left); return new_node(value,left,0); } else { if (right->sz > 3*left->sz) { if (right->left->sz < 2*right->right->sz) { - left->ref_count++; - right->left->ref_count++; - right->right->ref_count++; + add_value_ref(value); + add_value_ref(right->value); + add_node_ref(left); + add_node_ref(right->left); + add_node_ref(right->right); Namespace new_left = new_node(value, left, @@ -224,12 +297,15 @@ public: new_left, right->right); } else { - left->ref_count++; + add_value_ref(value); + add_value_ref(right->value); + add_value_ref(right->left->value); + add_node_ref(left); if (right->left->left != 0) - right->left->left->ref_count++; + add_node_ref(right->left->left); if (right->left->right != 0) - right->left->right->ref_count++; - right->right->ref_count++; + add_node_ref(right->left->right); + add_node_ref(right->right); Namespace new_left = new_node(value, left, @@ -243,8 +319,9 @@ public: new_right); } } else { - left->ref_count++; - right->ref_count++; + add_value_ref(value); + add_node_ref(left); + add_node_ref(right); return new_node(value,left,right); } } @@ -416,9 +493,23 @@ void namespace_release(Namespace node) if (node == 0) return; +#ifdef DEBUG_NAMESPACE + printf("release node %6ld %s (ref_count=%ld)\n", node.as_object(), node->value->name.text, node->ref_count-1); +#endif + if (!(--node->ref_count)) { namespace_release(node->left); namespace_release(node->right); + +#ifdef DEBUG_NAMESPACE + printf("release value %5ld %s (ref_count=%ld)\n", node->value.as_object(), node->value->name.text, node->value->ref_count-1); +#endif + + if (!(--node->value->ref_count)) { + V::release(node->value); + PgfDB::free(node->value); + } + PgfDB::free(node); } } diff --git a/src/runtime/c/pgf/pgf.cxx b/src/runtime/c/pgf/pgf.cxx index cc8a1417b..8676a73fc 100644 --- a/src/runtime/c/pgf/pgf.cxx +++ b/src/runtime/c/pgf/pgf.cxx @@ -116,9 +116,11 @@ PgfDB *pgf_read_ngf(const char *fpath, { DB_scope scope(db, WRITER_SCOPE); - if (PgfDB::get_revision(&master) == 0) { + ref pgf = PgfDB::get_revision(&master); + if (pgf == 0) { is_new = true; - ref pgf = PgfDB::malloc(master.size+1); + pgf = PgfDB::malloc(master.size+1); + pgf->ref_count = 1; pgf->major_version = 2; pgf->minor_version = 0; pgf->gflags = 0; @@ -131,10 +133,10 @@ PgfDB *pgf_read_ngf(const char *fpath, pgf->next = 0; memcpy(&pgf->name, &master, sizeof(PgfText)+master.size+1); PgfDB::set_revision(pgf); - *revision = pgf.as_object(); } else { - *revision = PgfDB::get_revision(&master).as_object(); + Node::add_value_ref(pgf); } + *revision = pgf.as_object(); } return db; @@ -159,15 +161,20 @@ PGF_API_DECL void pgf_free_revision(PgfDB *db, PgfRevision revision) { try { - DB_scope scope(db, READER_SCOPE); + DB_scope scope(db, WRITER_SCOPE); ref pgf = PgfDB::revision2pgf(revision); - if (PgfDB::unlink_transient_revision(pgf)) { - namespace_release(pgf->gflags); - PgfDB::free(pgf->abstract.name); - namespace_release(pgf->abstract.aflags); - namespace_release(pgf->abstract.funs); - namespace_release(pgf->abstract.cats); + if (pgf->ref_count == 1 && PgfDB::is_persistant_revision(pgf)) { + // Someone is trying to release the last reference count + // to a persistant revision. Mostly likely this is an + // error in the reference counting for one of the clients. + // The best that we can do is to ignore the request. + return; + } + + if (!(--pgf->ref_count)) { + PgfDB::unlink_transient_revision(pgf); + PgfPGF::release(pgf); PgfDB::free(pgf); } } catch (std::runtime_error& e) { @@ -461,26 +468,27 @@ PgfRevision pgf_clone_revision(PgfDB *db, PgfRevision revision, (name == NULL) ? pgf->name.size : name->size; ref new_pgf = PgfDB::malloc(name_size+1); + new_pgf->ref_count = 1; new_pgf->major_version = pgf->major_version; new_pgf->minor_version = pgf->minor_version; new_pgf->gflags = pgf->gflags; if (pgf->gflags != 0) - pgf->gflags->ref_count++; + Node::add_node_ref(pgf->gflags); new_pgf->abstract.name = textdup_db(&(*pgf->abstract.name)); new_pgf->abstract.aflags = pgf->abstract.aflags; if (pgf->abstract.aflags != 0) - pgf->abstract.aflags->ref_count++; + Node::add_node_ref(pgf->abstract.aflags); new_pgf->abstract.funs = pgf->abstract.funs; if (pgf->abstract.funs != 0) - pgf->abstract.funs->ref_count++; + Node::add_node_ref(pgf->abstract.funs); new_pgf->abstract.cats = pgf->abstract.cats; if (pgf->abstract.cats != 0) - pgf->abstract.cats->ref_count++; + Node::add_node_ref(pgf->abstract.cats); new_pgf->prev = 0; new_pgf->next = 0; @@ -519,7 +527,9 @@ PgfRevision pgf_checkout_revision(PgfDB *db, PgfText *name, { PGF_API_BEGIN { DB_scope scope(db, WRITER_SCOPE); - return PgfDB::get_revision(name).as_object(); + ref pgf = PgfDB::get_revision(name); + Node::add_value_ref(pgf); + return pgf.as_object(); } PGF_API_END return 0; @@ -539,6 +549,7 @@ void pgf_create_function(PgfDB *db, PgfRevision revision, ref pgf = PgfDB::revision2pgf(revision); ref absfun = PgfDB::malloc(name->size+1); + absfun->ref_count = 1; absfun->type = m->match_type(&u, ty); absfun->arity = 0; absfun->defns = 0; @@ -586,6 +597,7 @@ void pgf_create_category(PgfDB *db, PgfRevision revision, ref pgf = PgfDB::revision2pgf(revision); ref abscat = PgfDB::malloc(name->size+1); + abscat->ref_count = 1; abscat->context = vector_new(n_hypos); abscat->prob = prob; memcpy(&abscat->name, name, sizeof(PgfText)+name->size+1); diff --git a/src/runtime/c/pgf/reader.cxx b/src/runtime/c/pgf/reader.cxx index 2a378ea64..f69cf9cd7 100644 --- a/src/runtime/c/pgf/reader.cxx +++ b/src/runtime/c/pgf/reader.cxx @@ -227,6 +227,7 @@ PgfLiteral PgfReader::read_literal() ref PgfReader::read_flag() { ref flag = read_name(&PgfFlag::name); + flag->ref_count = 1; flag->value = read_literal(); return flag; } @@ -380,6 +381,7 @@ ref PgfReader::read_absfun() { ref absfun = read_name(&PgfAbsFun::name); + absfun->ref_count = 1; ref efun = ref::from_ptr((PgfExprFun*) &absfun->name); absfun->ep.expr = ref::tagged(efun); @@ -405,6 +407,7 @@ ref PgfReader::read_absfun() ref PgfReader::read_abscat() { ref abscat = read_name(&PgfAbsCat::name); + abscat->ref_count = 1; abscat->context = read_vector(&PgfReader::read_hypo); // for now we just read the set of functions per category and ignore them @@ -430,6 +433,7 @@ ref PgfReader::read_pgf() { ref pgf = PgfDB::malloc(master.size+1); + pgf->ref_count = 1; pgf->major_version = read_u16be(); pgf->minor_version = read_u16be(); diff --git a/src/runtime/haskell/tests/transactions.hs b/src/runtime/haskell/tests/transactions.hs index 1447bed7d..37e75776e 100644 --- a/src/runtime/haskell/tests/transactions.hs +++ b/src/runtime/haskell/tests/transactions.hs @@ -1,6 +1,8 @@ import Test.HUnit import PGF2 import PGF2.Transactions +import System.Mem +import System.Exit (exitSuccess, exitFailure) main = do gr1 <- readPGF "tests/basic.pgf" @@ -16,7 +18,7 @@ main = do gr6 <- modifyPGF gr1 (dropFunction "ind" >> dropCategory "S") - runTestTTAndExit $ + c <- runTestTT $ TestList $ [TestCase (assertEqual "original functions" ["c","ind","s","z"] (functions gr1)) ,TestCase (assertEqual "extended functions" ["c","foo","ind","s","z"] (functions gr2)) @@ -35,3 +37,9 @@ main = do ,TestCase (assertEqual "old function prob" (-log 0) (functionProb gr1 "foo")) ,TestCase (assertEqual "new function prob" pi (functionProb gr2 "foo")) ] + + performMajorGC + + if (errors c == 0) && (failures c == 0) + then exitSuccess + else exitFailure