aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2022-07-19 12:16:15 +0200
committerJohn Ankarström <john@ankarstrom.se>2022-07-19 12:16:15 +0200
commit34c32802122ff80e79d850d44cbc84624d9a5840 (patch)
treeb03f55581dda8ad8560ca8e0fd2f2eb341392345
parent2a7f4bcd4c04d0e48e580c4b11a94174bc5b09ae (diff)
downloadEpisodeBrowser-34c32802122ff80e79d850d44cbc84624d9a5840.tar.gz
Fix Prolog memory leaks.
Apparently foreign frames ARE needed when calling Prolog from C. The official documentation is very terse and could make this clearer. To summarize, whenever a term is created (e.g., PL_new_term_refs), its reference count is increased by one. It is garbage-collected when its reference count hits zero. But the reference count is never decreased unless (a) control returns to Prolog after executing a foreign predicate -- which does not happen in my application -- or (b) the foreign frame in which the term was created is closed. In other words, terms must be created within a foreign frame. This is achieved by initializing a Frame object before creating the term and destroying it once the term has served its purpose. The destructor for Frame does not DISCARD the frame, only CLOSE it. The former would also invalidate all data bound by the terms, which is usually undesirable.
-rw-r--r--c/datalistview.cpp1
-rw-r--r--c/pl.cpp26
-rw-r--r--c/pl.h12
3 files changed, 39 insertions, 0 deletions
diff --git a/c/datalistview.cpp b/c/datalistview.cpp
index c83c65f..704b689 100644
--- a/c/datalistview.cpp
+++ b/c/datalistview.cpp
@@ -39,6 +39,7 @@ void DataListView::ShowEpisode(const int iEpisode)
lviKey.mask = LVIF_TEXT;
lviValue.mask = LVIF_TEXT;
+ Frame f;
const term_t t = PL_new_term_refs(3);
if (!PL_put_integer(t,iEpisode)) return;
const qid_t q = PL_open_query(NULL, PL_Q_NORMAL,
diff --git a/c/pl.cpp b/c/pl.cpp
index fe65714..a40865f 100644
--- a/c/pl.cpp
+++ b/c/pl.cpp
@@ -3,6 +3,31 @@
#include "pl.h"
+Frame::Frame()
+{
+ m_f = PL_open_foreign_frame();
+}
+
+Frame::~Frame()
+{
+ PL_close_foreign_frame(m_f);
+}
+
+void Frame::Close()
+{
+ PL_close_foreign_frame(m_f);
+}
+
+void Frame::Discard()
+{
+ PL_discard_foreign_frame(m_f);
+}
+
+void Frame::Rewind()
+{
+ PL_rewind_foreign_frame(m_f);
+}
+
Query::Query(const module_t ctx, const predicate_t p, const term_t t0)
{
m_q = PL_open_query(ctx, PL_Q_CATCH_EXCEPTION, p, t0);
@@ -50,6 +75,7 @@ int PL_get_tchars(const term_t t, TCHAR** const pTsz, const int iFlags)
int Plx(const char* const szMod, const char* const szPred)
{
+ Frame f;
const term_t t = PL_new_term_refs(0);
Query q(NULL, PL_predicate(szPred, 0, szMod), t);
return q.NextSolution();
diff --git a/c/pl.h b/c/pl.h
index 1ad0967..4268dad 100644
--- a/c/pl.h
+++ b/c/pl.h
@@ -7,6 +7,17 @@
int PL_get_tchars(term_t t, TCHAR** pTsz, int iFlags);
int Plx(const char* szMod, const char* szPred);
+struct Frame
+{
+ Frame();
+ ~Frame();
+ void Close();
+ void Discard();
+ void Rewind();
+private:
+ fid_t m_f;
+};
+
struct Query
{
Query(module_t ctx, predicate_t p, term_t t0);
@@ -65,6 +76,7 @@ int Countv(const int i, T, R... rest) { return Countv(i+1, rest...); }
template <typename ...T>
int Plx(const char* const szMod, const char* const szPred, T... args)
{
+ Frame f;
const int iArity = Countv(0, args...);
const term_t t = PL_new_term_refs(iArity);
if (!PlPutv(t, args...)) return 0;