Пример #1
0
/*
 * Get the current Fiber reference on the current thread. The first time this
 * function is called on a given (real) thread, the main Fiber is created.
 */
static Fiber *
get_current(void)
{
    Fiber *current;
    PyObject *tstate_dict;

    /* get current Fiber from the active thread-state */
    tstate_dict = PyThreadState_GetDict();
    if (tstate_dict == NULL) {
        if (!PyErr_Occurred()) {
            PyErr_NoMemory();
        }
        return NULL;
    }
    current = (Fiber *)PyDict_GetItem(tstate_dict, current_fiber_key);
    if (current == NULL) {
        current = fiber_create_main();
        if (current == NULL) {
            return NULL;
        }
        /* Keep a reference to the main fiber in the thread dict. The main
         * fiber is special because we don't require the user to keep a
         * reference to it. It should be deleted when the thread exits. */
        if (PyDict_SetItem(tstate_dict, main_fiber_key, (PyObject *) current) < 0) {
            Py_DECREF(current);
            return NULL;
        }
        /* current starts out as main */
        if (PyDict_SetItem(tstate_dict, current_fiber_key, (PyObject *) current) < 0) {
            Py_DECREF(current);
            return NULL;
        }
        /* return a borrowed ref. refcount should be 2 after this */
        Py_DECREF(current);
    }

    ASSERT(current != NULL);
    return current;
}
Пример #2
0
/*
 * Update the current Fiber reference on the current thread. The first time this
 * function is called on a given (real) thread, the main Fiber is created.
 */
static Fiber *
update_current(void)
{
	Fiber *current, *previous;
	PyObject *exc, *val, *tb, *tstate_dict;

restart:
	/* save current exception */
	PyErr_Fetch(&exc, &val, &tb);

	/* get current Fiber from the active thread-state */
	tstate_dict = PyThreadState_GetDict();
        if (tstate_dict == NULL) {
            if (!PyErr_Occurred()) {
                PyErr_NoMemory();
            }
            return NULL;
        }
	current = (Fiber *)PyDict_GetItem(tstate_dict, current_fiber_key);
	if (current) {
	    /* found - remove it, to avoid keeping a ref */
	    Py_INCREF(current);
	    PyDict_DelItem(tstate_dict, current_fiber_key);
	} else {
            /* first time we see this thread-state, create main Fiber */
            current = fiber_create_main();
            if (current == NULL) {
                Py_XDECREF(exc);
                Py_XDECREF(val);
                Py_XDECREF(tb);
                return NULL;
	    }
	    if (_global_state.current == NULL) {
	        /* First time a main Fiber is allocated in any thread */
	        _global_state.current = current;
	    }
        }
        ASSERT(current->ts_dict == tstate_dict);

retry:
	Py_INCREF(current);
	previous = _global_state.current;
	_global_state.current = current;

        if (PyDict_GetItem(previous->ts_dict, current_fiber_key) != (PyObject *)previous) {
            /* save previous as the current Fiber of its own (real) thread */
            if (PyDict_SetItem(previous->ts_dict, current_fiber_key, (PyObject*) previous) < 0) {
                Py_DECREF(previous);
                Py_DECREF(current);
                Py_XDECREF(exc);
                Py_XDECREF(val);
                Py_XDECREF(tb);
                return NULL;
            }
            Py_DECREF(previous);
        }
        ASSERT(Py_REFCNT(previous) >= 1);

	if (_global_state.current != current) {
            /* some Python code executed above and there was a thread switch,
             * so the global current points to some other Fiber again. We need to
             * delete current_fiber_key and retry. */
            PyDict_DelItem(tstate_dict, current_fiber_key);
            goto retry;
	}

	/* release the extra reference */
        Py_DECREF(current);

	/* restore current exception */
	PyErr_Restore(exc, val, tb);

	/* thread switch could happen during PyErr_Restore, in that
	   case there's nothing to do except restart from scratch. */
	if (_global_state.current->ts_dict != tstate_dict) {
            goto restart;
        }

	return current;
}