Extending python3, how does the garbage collection work

Viewed 92

I'm making my own PriorityQueue in C as a python module. I read the basics of python ownership and reference system, so I thought I'd do the following:

In push(): Accept an priority(int) and an object to be saved. Increment the reference count on the object to be saved, since we will be keeping that.

In pop(): Delete the object from my priorityqueue, but don't decrement the reference counter, since that might destroy the object. Instead I transfer my reference ownership to the python function calling my function.

This seemed to work at first hand. But when actually using it in an application I get the following error: Fatal Python error: GC object already tracked

What does this mean? The stacktrace is not useful at all, it's all inside python files I don't recognize(sre_parse and apport_python_hook).

Just for clarity, these are my C push and pop functions: (self->heap[index]->key is the priority of the element at that index self->heap[index]->value is the object)

PyObject* pop(CDSHeap *self) {
    //If there aare no elements
    if (self->heap[0].value == 0 || self->end == 0) {
        Py_RETURN_NONE;
    }
    //If there is only one element
    if (self->end == 1) {
        PyObject* result = self->heap[0].value;
        self->heap[0].key = 0;
        self->end = 0;
        return result;
    }
    //Two or more elements:
    //First save the result:
    PyObject* result = self->heap[0].value;
    //Get the last element, and place it at the top
    while (self->heap[self->end].value == 0) self->end--;
    self->heap[0].value = self->heap[self->end].value;
    self->heap[0].key = self->heap[self->end].key;
    self->heap[self->end].value = 0;
    //Reheapify the heap
    int ptr = 0;
    while (self->end >= ptr) {
        if (self->heap[ptr*2+1].value != 0 && self->heap[ptr*2+1].key < self->heap[ptr].key
        && (self->heap[ptr*2+2].value == 0 || self->heap[ptr*2+1].key <= self->heap[ptr*2+2].key)) {
            swapElement(self->heap, ptr, ptr*2+1);
            ptr = ptr*2+1;
        }else 
        if (self->heap[ptr*2+2].value != 0 && self->heap[ptr*2+2].value < self->heap[ptr].value) {
            swapElement(self->heap, ptr, ptr*2+2); 
            ptr = ptr*2+2;
        } else {
            break;
        }
    }   
    return result;
}

PyObject* push(CDSHeap *self, PyObject* args) {
    int k;
    PyObject *obj;
    if (!PyArg_ParseTuple(args, "iO",&k, &obj)){
        return NULL;
    }   
    Py_INCREF(obj);

    //Add the element to the end of the heap
    self->heap[self->end].key = k;
    self->heap[self->end].value = obj;
    //Increment the size and reheapify
    int ptr = self->end++;
    while (ptr > 0) {
        int parent = (ptr-1)/2;
        if (self->heap[ptr].key < self->heap[parent].key) {
            swapElement(self->heap, ptr, parent);
            ptr = parent;
        } else {
            Py_RETURN_NONE;
        }
    }
    Py_RETURN_NONE;
}
0 Answers
Related