From c26aec892f26ee21067a0beb9dd79a8c834e6dba Mon Sep 17 00:00:00 2001 From: Omer Zak Date: Sun, 22 May 2016 11:03:43 +0300 Subject: Added all old files of interest to version control. --- pysmob.c | 342 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 pysmob.c (limited to 'pysmob.c') diff --git a/pysmob.c b/pysmob.c new file mode 100644 index 0000000..98c26f4 --- /dev/null +++ b/pysmob.c @@ -0,0 +1,342 @@ +// pysmob implementation +// +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2008 Omer Zak. +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library, in a file named COPYING; if not, write to the +// Free Software Foundation, Inc., 59 Temple Place, Suite 330, +// Boston, MA 02111-1307 USA +// +// For licensing issues, contact . +// +//////////////////////////////////////////////////////////////////////// +// +// Implements the Guile SMOB type, which encapsulates Python objects. +// While those SMOBs can be used to encapsulate any PyObject* object, +// they are typically used to encapsulate only class instances. +// +//////////////////////////////////////////////////////////////////////// +// +// Note about verbosity handling: +// +// This module uses printf() rather than scm_simple_format & Co. for +// PYGUILE_VERBOSE_GC and PYGUILE_VERBOSE_GC_DETAILED. +// The reason is that scm_* functions cannot be used during garbage +// collection. +// +//////////////////////////////////////////////////////////////////////// +#include "pysmob.h" +#include "verbose.h" + +#ifndef Py_ssize_t +#define Py_ssize_t int +#endif /* Py_ssize_t */ + +static scm_t_bits tag_pysmob; + +//////////////////////////////////////////////////////////////////////// +// Wrapped PyObject memory management +//////////////////////////////////////////////////////////////////////// + +static PyObject *pdict_wrapped_pyobjects; +// Pointer at Dict, whose keys are addresses of wrapped PyObjects. +// (The keys have to be addresses, because the objects themselves +// can be mutable and hence unsuitable for use as Dict keys.) + +//scm_t_c_hook_function clear_pdict_values; +//scm_t_c_hook_function delete_unmarked_pdict_keys; + +void * +clear_pdict_values(void *hook_data, void *func_data, void *data) +{ + if (pyguile_verbosity_test(PYGUILE_VERBOSE_GC)) { + //scm_simple_format(scm_current_output_port(),scm_makfrom0str("# Starting garbage collection (mark phase) - entered clear_pdict_values\n"),SCM_EOL); + printf("# Starting garbage collection (mark phase) - entered clear_pdict_values\n"); + } + PyObject *pdict = (PyObject *)func_data; + if (!PyDict_CheckExact(pdict)) { + scm_misc_error("clear_pdict_values","invalid pysmobs Dict",SCM_EOL); // NOT COVERED BY TESTS + } + + PyObject *key; + PyObject *value; + Py_ssize_t pos = 0; + while(PyDict_Next(pdict,&pos,&key,&value)) { + Py_INCREF(Py_False); + if (0 != PyDict_SetItem(pdict, + key, + Py_False)) { + Py_DECREF(Py_False); // NOT COVERED BY TESTS + scm_misc_error("clear_pdict_values","failed to clear pysmobs Dict",SCM_EOL); // NOT COVERED BY TESTS + } + } + return(NULL); +} + +void * +delete_unmarked_pdict_keys(void *hook_data, void *func_data, void *data) +{ + if (pyguile_verbosity_test(PYGUILE_VERBOSE_GC)) { + //scm_simple_format(scm_current_output_port(),scm_makfrom0str("# Going to finish garbage collection (sweep phase) - entered delete_unmarked_pdict_keys\n"),SCM_EOL); + printf("# Going to finish garbage collection (sweep phase) - entered delete_unmarked_pdict_keys\n"); + } + PyObject *pdict = (PyObject *)func_data; + if (!PyDict_CheckExact(pdict)) { + scm_misc_error("delete_unmarked_pdict_keys","invalid pysmobs Dict",SCM_EOL); // NOT COVERED BY TESTS + } + + PyObject *pdict_clone = PyDict_Copy(pdict); + if (NULL == pdict_clone) { + PyErr_Clear(); // NOT COVERED BY TESTS + scm_misc_error("delete_ummarked_pdict_keys","failed to prepare for deleting from Dict",SCM_EOL); // NOT COVERED BY TESTS + } + + PyObject *key; + PyObject *value; + Py_ssize_t pos = 0; + while(PyDict_Next(pdict_clone,&pos,&key,&value)) { + if (Py_False == value) { + Py_INCREF(key); + if (0 != PyDict_DelItem(pdict,key)) { + PyErr_Clear(); // NOT COVERED BY TESTS + Py_DECREF(key); // NOT COVERED BY TESTS + Py_DECREF(pdict_clone); // NOT COVERED BY TESTS + scm_misc_error("delete_ummarked_pdict_keys","failed to delete item from Dict",SCM_EOL); // NOT COVERED BY TESTS + } + long pptr = PyLong_AsLong(key); + Py_DECREF((PyObject *)pptr); // Actually delete (if necessary) the formerly-wrapped PyObject. + Py_DECREF(key); + if (pyguile_verbosity_test(PYGUILE_VERBOSE_GC_DETAILED)) { + //scm_simple_format(scm_current_output_port(),scm_makfrom0str("# delete_unmarked_pdict_keys: deleting ~S\n"),scm_list_1(scm_long2num(pptr))); + printf("# delete_unmarked_pdict_keys: deleting 0x%08lX\n",pptr); + } + } + } + Py_DECREF(pdict_clone); + return(NULL); +} + + +//////////////////////////////////////////////////////////////////////// +// Private functions +//////////////////////////////////////////////////////////////////////// + +static SCM +mark_pysmob(SCM psmob) +{ + // New system of garbage collection: + // Each time we wrap a PyObject, we add its address, as a key, to + // a Python Dict, which will serve as hash table. + // + // Python facilities will be used for this purpose. + // + // When starting the mark phase, we clear all values in the + // aforementioned Python Dict. + // + // For each pysmob to be marked, we mark the corresponding Python + // Dict value. + // + // At end of the sweep phase, we delete from the Python Dict any + // items not marked. + // The reference counting will be maintained by ownership by the + // Python Dict. Guile will not deal with reference counting + // related to pysmobs at all. + + long key = (long) unwrap_pysmob(psmob); + PyObject *pkey = PyLong_FromLong(key); + if (NULL == pkey) { + PyErr_Clear(); // NOT COVERED BY TESTS + scm_memory_error("mark_pysmob"); // NOT COVERED BY TESTS + } + int ret = PyDict_Contains(pdict_wrapped_pyobjects,pkey); + if (-1 == ret) { + PyErr_Clear(); // NOT COVERED BY TESTS + Py_DECREF(pkey); // NOT COVERED BY TESTS + scm_misc_error("mark_pysmob","error when checking pysmobs Dict for ~S",scm_list_1(psmob)); // NOT COVERED BY TESTS + } + if (0 == ret) { + Py_DECREF(pkey); + scm_misc_error("mark_pysmob","smob not found in pysmobs Dict: ~S",scm_list_1(psmob)); + } + Py_INCREF(Py_True); + if (0 != PyDict_SetItem(pdict_wrapped_pyobjects, + pkey, + Py_True)) { + Py_DECREF(pkey); + scm_misc_error("mark_pysmob","failed to mark pysmob ~S",scm_list_1(psmob)); + } + if (pyguile_verbosity_test(PYGUILE_VERBOSE_GC_DETAILED)) { + //scm_simple_format(scm_current_output_port(),scm_makfrom0str("# mark_pysmob: marking ~S\n"),scm_list_1(scm_long2num(key))); + printf("# mark_pysmob: marking 0x%08lX\n",key); + } + + // scm_gc_mark(any SCM object referred to by the Python object); + // One SCM object is returned to the caller (who will mark it). + return(SCM_UNSPECIFIED); // No need to mark any SCM object for now + // (until PyObjects learn to hold wrapped SCM objects). +} + + +//static size_t +//free_pysmob(SCM psmob) +//{ +// PyObject *pobj = unwrap_pysmob(psmob); +// if (pyguile_verbosity_test(PYGUILE_VERBOSE_GC_DETAILED)) { +// scm_simple_format(scm_current_output_port(),scm_makfrom0str("# free_pysmob: freeing object ~S\n"),scm_list_1(scm_long2num((long)pobj))); +// } +// Py_XDECREF(pobj); +// return(0); +//} + +static int +print_pysmob(SCM smob, SCM port, scm_print_state* prstate) +{ + if (!SCM_SMOB_PREDICATE(tag_pysmob,smob)) { + scm_wrong_type_arg("print-pysmob",SCM_ARG1,smob); // NOT COVERED BY TESTS + } + if (!SCM_PORTP(port)) { + scm_wrong_type_arg("print-pysmob",SCM_ARG2,port); // NOT COVERED BY TESTS + } + // I don't know how to validate the 3rd argument. + PyObject *prepr = PyObject_Repr(unwrap_pysmob(smob)); + if (NULL != prepr) { + char *pstr = PyString_AsString(prepr); + scm_puts("(python-eval ",port); + scm_puts(pstr, port); + scm_puts(" #t)",port); + Py_DECREF(prepr); // also invalidates pstr. + } + else { + scm_misc_error("print-pysmob","repr(~S) failure",scm_list_1(smob)); // NOT COVERED BY TESTS + //scm_puts("*nil*", port); + } + return(1); // Nonzero means success. +} + +static SCM +equalp_pysmob(SCM smob1, SCM smob2) +{ + if (!SCM_SMOB_PREDICATE(tag_pysmob,smob1)) { + scm_wrong_type_arg("equalp-pysmob",SCM_ARG1,smob1); + } + if (!SCM_SMOB_PREDICATE(tag_pysmob,smob2)) { + scm_wrong_type_arg("equalp-pysmob",SCM_ARG2,smob2); + } + PyObject *pobj1 = unwrap_pysmob(smob1); + if (NULL == pobj1) { + scm_misc_error("equalp-pysmob","argument 1 (~S) unwrapping failure", // NOT COVERED BY TESTS + scm_list_1(smob1)); + } + PyObject *pobj2 = unwrap_pysmob(smob2); + if (NULL == pobj2) { + scm_misc_error("equalp-pysmob","argument 2 (~S) unwrapping failure", // NOT COVERED BY TESTS + scm_list_1(smob2)); + } + switch (PyObject_RichCompareBool(pobj1,pobj2,Py_EQ)) { + case 0: + return(SCM_BOOL_F); + case 1: + return(SCM_BOOL_T); + case -1: + default: + // Error. + scm_misc_error("equalp-pysmob","comparison failure ~S vs. ~S", + scm_list_2(smob1,smob2)); + return(SCM_UNDEFINED); + } +} + +//////////////////////////////////////////////////////////////////////// +// Public functions +//////////////////////////////////////////////////////////////////////// + + +// Return nonzero if sobj is of type pysmob. +int +IS_PYSMOBP(SCM sobj) +{ + return(SCM_SMOB_PREDICATE(tag_pysmob,sobj)); +} + +// Create a pysmob corresponding to a PyObject. +SCM +wrap_pyobject(PyObject *pobj) +{ + if (NULL == pobj) { + scm_misc_error("wrap-pyobject","NULL PyObject",SCM_EOL); // NOT COVERED BY TESTS + //return(SCM_UNSPECIFIED); + } + else { + if (pyguile_verbosity_test(PYGUILE_VERBOSE_NEW_PYSMOB)) { + scm_simple_format(scm_current_output_port(),scm_makfrom0str("# wrap_pyobject: new wrapped object ~S\n"),scm_list_1(scm_long2num((long)pobj))); + } + Py_INCREF(pobj); + Py_INCREF(Py_True); + PyDict_SetItem(pdict_wrapped_pyobjects, + PyLong_FromLong((long)pobj), + Py_True); + SCM_RETURN_NEWSMOB(tag_pysmob,pobj); + } +} + +// Provide reference to PyObject embedded in a pysmob. +// No ownership transfer is implied. +PyObject * +unwrap_pysmob(SCM sobj) +{ + if (!SCM_SMOB_PREDICATE(tag_pysmob,sobj)) { + scm_wrong_type_arg("unwrap-pysmob",SCM_ARG1,sobj); // NOT COVERED BY TESTS + } + PyObject *pobj = (PyObject *)SCM_SMOB_DATA(sobj); + if (pyguile_verbosity_test(PYGUILE_VERBOSE_UNWRAP_PYSMOB)) { + // The scm_simple_format code can safely be invoked if we know + // that we are not inside garbage collection. + // TODO: invoke a flag for this purpose. + //scm_simple_format(scm_current_output_port(),scm_makfrom0str("# unwrap_pysmob: accessing object ~S\n"),scm_list_1(scm_long2num((long)pobj))); + printf("# unwrap_pysmob: accessing object 0x%08lX\n",(long)pobj); + } + return(pobj); +} + +//////////////////////////////////////////////////////////////////////// + +void finalize_pysmob_type(void) +{ + Py_DECREF(pdict_wrapped_pyobjects); +} + +void init_pysmob_type(void) +{ + tag_pysmob = scm_make_smob_type("pysmob",0); + scm_set_smob_mark (tag_pysmob, mark_pysmob); + //scm_set_smob_free(tag_pysmob,free_pysmob); // does nothing in the new scheme of managing PyObjects during garbage collection. + scm_set_smob_print(tag_pysmob,print_pysmob); + scm_set_smob_equalp(tag_pysmob,equalp_pysmob); + + // Py_Initialize must have already been invoked + // by init_pysmob_type()'s caller. + pdict_wrapped_pyobjects = PyDict_New(); + if (atexit(finalize_pysmob_type)) { + fprintf(stderr,"cannot set pysmob finalization function\n"); // NOT COVERED BY TESTS + exit(1); // NOT COVERED BY TESTS + } + + // Register garbage collection hooks. + scm_c_hook_add(&scm_before_mark_c_hook,&clear_pdict_values, + (void *)pdict_wrapped_pyobjects,0); + scm_c_hook_add(&scm_after_sweep_c_hook,&delete_unmarked_pdict_keys, + (void *)pdict_wrapped_pyobjects,0); +} + +// End of pysmob.c -- cgit v1.2.3