From f9d20c37864316e0cd343e0b9bbac638a7590ad5 Mon Sep 17 00:00:00 2001
From: Vladimir Marangozov <vladimir.marangozov@t-online.de>
Date: Sun, 6 Aug 2000 22:45:31 +0000
Subject: Neil Schemenauer: GC enable(), disable(), isenabled() interface.

Small stylistic changes by VM:
- is_enabled() -> isenabled()
- static ... Py_<func> -> static ... gc_<func>
---
 Doc/lib/libgc.tex   | 26 +++++++++++----
 Lib/test/test_gc.py | 12 +++++++
 Modules/gcmodule.c  | 92 +++++++++++++++++++++++++++++++++++++++++++----------
 3 files changed, 107 insertions(+), 23 deletions(-)

diff --git a/Doc/lib/libgc.tex b/Doc/lib/libgc.tex
index c5ecfcf..9e097ec 100644
--- a/Doc/lib/libgc.tex
+++ b/Doc/lib/libgc.tex
@@ -5,18 +5,30 @@
 \moduleauthor{Neil Schemenauer}{nascheme@enme.ucalgary.ca}
 \sectionauthor{Neil Schemenauer}{nascheme@enme.ucalgary.ca}
 
-This module provides an interface to the optional garbage collector.
-It provides the ability to disable the collector, tune the collection
+This module provides an interface to the optional garbage collector.  It
+provides the ability to disable the collector, tune the collection
 frequency, and set debugging options.  It also provides access to
-unreachable objects that the collector found but cannot free.  Since
-the collector supplements the reference counting already used in
-Python, you can disable the collector if you are sure your program
-does not create reference cycles.  The collector can be disabled by
-calling \code{gc.set_threshold(0)}.  To debug a leaking program call
+unreachable objects that the collector found but cannot free.  Since the
+collector supplements the reference counting already used in Python, you
+can disable the collector if you are sure your program does not create
+reference cycles.  Automatic collection can be disabled by calling
+\code{gc.disable()}.  To debug a leaking program call
 \code{gc.set_debug(gc.DEBUG_LEAK)}.
 
 The \module{gc} module provides the following functions:
 
+\begin{funcdesc}{enable}{}
+Enable automatic garbage collection.
+\end{funcdesc}
+
+\begin{funcdesc}{disable}{}
+Disable automatic garbage collection.
+\end{funcdesc}
+
+\begin{funcdesc}{isenabled}{}
+Returns true if automatic collection is enabled.
+\end{funcdesc}
+
 \begin{funcdesc}{collect}{}
 Run a full collection.  All generations are examined and the
 number of unreachable objects found is returned.
diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py
index 943f837..7f8e424 100644
--- a/Lib/test/test_gc.py
+++ b/Lib/test/test_gc.py
@@ -75,6 +75,11 @@ def test_function():
 
 
 def test_all():
+
+    enabled = gc.isenabled()
+    gc.disable()
+    assert not gc.isenabled()
+
     test_list()
     test_dict()
     test_tuple()
@@ -84,4 +89,11 @@ def test_all():
     test_finalizer()
     test_function()
 
+    # test gc.enable() even if GC is disabled by default
+    gc.enable()
+    assert gc.isenabled()
+    if not enabled:
+        gc.disable()
+
+
 test_all()
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 60b4fe7..8e495e6 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -39,6 +39,7 @@ static PyGC_Head generation2 = {&generation2, &generation2, 0};
 static int generation = 0; /* current generation being collected */
 
 /* collection frequencies, XXX tune these */
+static int enabled = 1; /* automatic collection enabled? */
 static int threshold0 = 100; /* net new containers before collection */
 static int threshold1 = 10;  /* generation0 collections before collecting 1 */
 static int threshold2 = 10;  /* generation1 collections before collecting 2 */
@@ -492,7 +493,7 @@ _PyGC_Insert(PyObject *op)
 		abort();
 	}
 #endif
-	if (threshold0 && allocated > threshold0 && !collecting) {
+	if (allocated > threshold0 && enabled && threshold0 && !collecting) {
 		collecting++;
 		collect_generations();
 		collecting--;
@@ -516,15 +517,68 @@ _PyGC_Remove(PyObject *op)
 	}
 }
 
+static char gc_enable__doc__[] =
+"enable() -> None\n"
+"\n"
+"Enable automatic garbage collection.\n"
+;
+
+static PyObject *
+gc_enable(PyObject *self, PyObject *args)
+{
+
+	if (!PyArg_ParseTuple(args, ":enable"))	/* check no args */
+		return NULL;
+
+	enabled = 1;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static char gc_disable__doc__[] =
+"disable() -> None\n"
+"\n"
+"Disable automatic garbage collection.\n"
+;
+
+static PyObject *
+gc_disable(PyObject *self, PyObject *args)
+{
+
+	if (!PyArg_ParseTuple(args, ":disable"))	/* check no args */
+		return NULL;
+
+	enabled = 0;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static char gc_isenabled__doc__[] =
+"isenabled() -> status\n"
+"\n"
+"Returns true if automatic garbage collection is enabled.\n"
+;
+
+static PyObject *
+gc_isenabled(PyObject *self, PyObject *args)
+{
+
+	if (!PyArg_ParseTuple(args, ":isenabled"))	/* check no args */
+		return NULL;
+
+	return Py_BuildValue("i", enabled);
+}
 
-static char collect__doc__[] =
+static char gc_collect__doc__[] =
 "collect() -> n\n"
 "\n"
 "Run a full collection.  The number of unreachable objects is returned.\n"
 ;
 
 static PyObject *
-Py_collect(PyObject *self, PyObject *args)
+gc_collect(PyObject *self, PyObject *args)
 {
 	long n;
 
@@ -539,7 +593,7 @@ Py_collect(PyObject *self, PyObject *args)
 	return Py_BuildValue("i", n);
 }
 
-static char set_debug__doc__[] = 
+static char gc_set_debug__doc__[] = 
 "set_debug(flags) -> None\n"
 "\n"
 "Set the garbage collection debugging flags. Debugging information is\n"
@@ -556,7 +610,7 @@ static char set_debug__doc__[] =
 ;
 
 static PyObject *
-Py_set_debug(PyObject *self, PyObject *args)
+gc_set_debug(PyObject *self, PyObject *args)
 {
 	if (!PyArg_ParseTuple(args, "l:get_debug", &debug))
 		return NULL;
@@ -565,14 +619,14 @@ Py_set_debug(PyObject *self, PyObject *args)
 	return Py_None;
 }
 
-static char get_debug__doc__[] = 
+static char gc_get_debug__doc__[] = 
 "get_debug() -> flags\n"
 "\n"
 "Get the garbage collection debugging flags.\n"
 ;
 
 static PyObject *
-Py_get_debug(PyObject *self, PyObject *args)
+gc_get_debug(PyObject *self, PyObject *args)
 {
 	if (!PyArg_ParseTuple(args, ":get_debug"))	/* no args */
 		return NULL;
@@ -580,7 +634,7 @@ Py_get_debug(PyObject *self, PyObject *args)
 	return Py_BuildValue("i", debug);
 }
 
-static char set_thresh__doc__[] =
+static char gc_set_thresh__doc__[] =
 "set_threshold(threshold0, [threhold1, threshold2]) -> None\n"
 "\n"
 "Sets the collection thresholds.  Setting threshold0 to zero disables\n"
@@ -588,7 +642,7 @@ static char set_thresh__doc__[] =
 ;
 
 static PyObject *
-Py_set_thresh(PyObject *self, PyObject *args)
+gc_set_thresh(PyObject *self, PyObject *args)
 {
 	if (!PyArg_ParseTuple(args, "i|ii:set_threshold", &threshold0, 
 				&threshold1, &threshold2))
@@ -598,14 +652,14 @@ Py_set_thresh(PyObject *self, PyObject *args)
 	return Py_None;
 }
 
-static char get_thresh__doc__[] =
+static char gc_get_thresh__doc__[] =
 "get_threshold() -> (threshold0, threshold1, threshold2)\n"
 "\n"
 "Return the current collection thresholds\n"
 ;
 
 static PyObject *
-Py_get_thresh(PyObject *self, PyObject *args)
+gc_get_thresh(PyObject *self, PyObject *args)
 {
 	if (!PyArg_ParseTuple(args, ":get_threshold"))	/* no args */
 		return NULL;
@@ -617,6 +671,9 @@ Py_get_thresh(PyObject *self, PyObject *args)
 static char gc__doc__ [] =
 "This module provides access to the garbage collector for reference cycles.\n"
 "\n"
+"enable() -- Enable automatic garbage collection.\n"
+"disable() -- Disable automatic garbage collection.\n"
+"isenabled() -- Returns true if automatic collection is enabled.\n"
 "collect() -- Do a full collection right now.\n"
 "set_debug() -- Set debugging flags.\n"
 "get_debug() -- Get debugging flags.\n"
@@ -625,11 +682,14 @@ static char gc__doc__ [] =
 ;
 
 static PyMethodDef GcMethods[] = {
-	{"set_debug",		Py_set_debug,  METH_VARARGS, set_debug__doc__},
-	{"get_debug",		Py_get_debug,  METH_VARARGS, get_debug__doc__},
-	{"set_threshold",	Py_set_thresh, METH_VARARGS, set_thresh__doc__},
-	{"get_threshold",	Py_get_thresh, METH_VARARGS, get_thresh__doc__},
-	{"collect",		Py_collect,    METH_VARARGS, collect__doc__},
+	{"enable",	   gc_enable,     METH_VARARGS, gc_enable__doc__},
+	{"disable",	   gc_disable,    METH_VARARGS, gc_disable__doc__},
+	{"isenabled",	   gc_isenabled,  METH_VARARGS, gc_isenabled__doc__},
+	{"set_debug",	   gc_set_debug,  METH_VARARGS, gc_set_debug__doc__},
+	{"get_debug",	   gc_get_debug,  METH_VARARGS, gc_get_debug__doc__},
+	{"set_threshold",  gc_set_thresh, METH_VARARGS, gc_set_thresh__doc__},
+	{"get_threshold",  gc_get_thresh, METH_VARARGS, gc_get_thresh__doc__},
+	{"collect",	   gc_collect,    METH_VARARGS, gc_collect__doc__},
 	{NULL,	NULL}		/* Sentinel */
 };
 
-- 
cgit v0.12

