/* * Create main Fiber. There is always a main Fiber for a given (real) thread, * and it's parent is always NULL. */ static Fiber * fiber_create_main(void) { Fiber *t_main; PyObject *dict = PyThreadState_GetDict(); PyTypeObject *cls = (PyTypeObject *)&FiberType; if (dict == NULL) { if (!PyErr_Occurred()) { PyErr_NoMemory(); } return NULL; } /* create the main Fiber for this thread */ t_main = (Fiber *)cls->tp_new(cls, NULL, NULL); if (!t_main) { return NULL; } Py_INCREF(dict); t_main->ts_dict = dict; t_main->parent = NULL; t_main->thread_h = stacklet_newthread(); t_main->stacklet_h = NULL; t_main->initialized = True; t_main->is_main = True; return t_main; }
extern "C" int Py_ReprEnter(PyObject* obj) noexcept { PyObject* dict; PyObject* list; Py_ssize_t i; dict = PyThreadState_GetDict(); if (dict == NULL) return 0; list = PyDict_GetItemString(dict, KEY); if (list == NULL) { list = PyList_New(0); if (list == NULL) return -1; if (PyDict_SetItemString(dict, KEY, list) < 0) return -1; Py_DECREF(list); } i = PyList_GET_SIZE(list); while (--i >= 0) { if (PyList_GET_ITEM(list, i) == obj) return 1; } PyList_Append(list, obj); return 0; }
// dtor static void AtTime_dealloc( PyObject* self ) { AtTime * at = (AtTime*)self; PyObject * tsd = PyThreadState_GetDict(); PyObject * atd = PyDict_GetItemString(tsd, "_AtTime" ); if( atd ) { PyObject * cur_stack = PyDict_GetItemString( atd, "current_stack" ); PyObject * time_stack = PyDict_GetItemString( atd, "time_stack" ); Py_ssize_t time_top = PyList_Size(time_stack) - 1; PyObject * hashKey = PyLong_FromLong( PyObject_Hash((PyObject*)self) ); Py_ssize_t pos = PySequence_Index(cur_stack, hashKey); Py_DECREF(hashKey); // Restore the correct time value if we are current if( PyList_Size(cur_stack) == pos + 1 ) { thread_local(current_time) = PyLong_AsLong( PyList_GetItem( time_stack, time_top ) ); //PySys_WriteStdout( "Current AtTime object destroyed, restoring thread_local(current_time) to %i\n", thread_local(current_time) ); PySequence_DelItem(time_stack,time_top); } else // If we aren't current, then we delete the time at the position one above where we are in the current_stack PySequence_DelItem(time_stack,pos+1); PySequence_DelItem(cur_stack,pos); // If we are the last AtTime object local to this thread, then remove the _AtTime thread-local dict if( PyList_Size(cur_stack) == 0 ) { thread_local(use_time_context) = (PyDict_GetItemString( atd, "restore_use_time_context" ) == Py_True) ? TRUE : FALSE; //PySys_WriteStdout( "Last AtTime object destroyed, setting thread_local(use_time_context) to FALSE\n" ); PyDict_DelItemString(tsd, "_AtTime"); } } self->ob_type->tp_free(self); }
static PyObject* get_inprogress_dict(void) { static PyObject *key; PyObject *tstate_dict, *inprogress; if (key == NULL) { key = PyString_InternFromString("cmp_state"); if (key == NULL) return NULL; } tstate_dict = PyThreadState_GetDict(); if (tstate_dict == NULL) { PyErr_BadInternalCall(); return NULL; } inprogress = PyDict_GetItem(tstate_dict, key); if (inprogress == NULL) { inprogress = PyDict_New(); if (inprogress == NULL) return NULL; if (PyDict_SetItem(tstate_dict, key, inprogress) == -1) { Py_DECREF(inprogress); return NULL; } Py_DECREF(inprogress); } return inprogress; }
static PyObject * _ldict(localobject *self) { PyObject *tdict, *ldict; tdict = PyThreadState_GetDict(); if (tdict == NULL) { PyErr_SetString(PyExc_SystemError, "Couldn't get thread-state dictionary"); return NULL; } ldict = PyDict_GetItem(tdict, self->key); if (ldict == NULL) { ldict = PyDict_New(); /* we own ldict */ if (ldict == NULL) return NULL; else { int i = PyDict_SetItem(tdict, self->key, ldict); Py_DECREF(ldict); /* now ldict is borrowed */ if (i < 0) return NULL; } Py_CLEAR(self->dict); Py_INCREF(ldict); self->dict = ldict; /* still borrowed */ if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init && Py_TYPE(self)->tp_init((PyObject*)self, self->args, self->kw) < 0) { /* we need to get rid of ldict from thread so we create a new one the next time we do an attr acces */ PyDict_DelItem(tdict, self->key); return NULL; } } /* The call to tp_init above may have caused another thread to run. Install our ldict again. */ if (self->dict != ldict) { Py_CLEAR(self->dict); Py_INCREF(ldict); self->dict = ldict; } return ldict; }
static PyObject * local_new(PyTypeObject *type, PyObject *args, PyObject *kw) { localobject *self; PyObject *tdict; // 好囧的判断. if (type->tp_init == PyBaseObject_Type.tp_init && ((args && PyObject_IsTrue(args)) || (kw && PyObject_IsTrue(kw)))) { PyErr_SetString(PyExc_TypeError, "Initialization arguments are not supported"); return NULL; } self = (localobject *)type->tp_alloc(type, 0); if (self == NULL) return NULL; Py_XINCREF(args); self->args = args; Py_XINCREF(kw); self->kw = kw; self->dict = NULL; /* making sure */ self->key = PyString_FromFormat("thread.local.%p", self); if (self->key == NULL) goto err; self->dict = PyDict_New(); if (self->dict == NULL) goto err; tdict = PyThreadState_GetDict(); if (tdict == NULL) { PyErr_SetString(PyExc_SystemError, "Couldn't get thread-state dictionary"); goto err; } // dict里存的是localobject里的(key, value)的引用, 参考local_dealloc(), localobject ref -> 0时, 会进行清理. // 也就是不能认为thread._local()提供了一个thread global的存储, thread global要通过 returns of thread._local()的生命周期保证. if (PyDict_SetItem(tdict, self->key, self->dict) < 0) goto err; return (PyObject *)self; err: Py_DECREF(self); return NULL; }
static PyObject * AtTime_call( AtTime* self, PyObject* args, PyObject* kwds ) { if( !PyTuple_Check(args) || (PyTuple_Size(args) != 1) || (!PyNumber_Check(PyTuple_GetItem(args,0))) ) { PyErr_SetString( PyExc_AttributeError, "Calling AtTime instances require a single time(int) argument" ); return 0; } int timeValue = PyInt_AsLong(PyTuple_GetItem(args,0)); if( PyErr_Occurred() ) return 0; PyObject * tsd = PyThreadState_GetDict(); PyObject * atd = PyDict_GetItemString(tsd, "_AtTime" ); // New reference is either transfered to a list, or decremented below PyObject * hashKey = PyLong_FromLong( PyObject_Hash((PyObject*)self) ); if( !atd ) { // New ref atd = PyDict_New(); PyDict_SetItemString( tsd, "_AtTime", atd ); // tsd now has a ref to atd Py_DECREF(atd); // New refs PyObject * time_stack = PyList_New(1), * cur_stack = PyList_New(1); // PyList_SetItem steals a reference PyList_SetItem( time_stack, 0, PyLong_FromLong(thread_local(current_time)) ); // Give our hashKey reference to cur_stack PyList_SetItem( cur_stack, 0, hashKey ); // Dicts take their own reference, so we release ours after this PyDict_SetItemString( atd, "time_stack", time_stack ); PyDict_SetItemString( atd, "current_stack", cur_stack ); Py_DECREF(time_stack); Py_DECREF(cur_stack); PyObject * utl = PyBool_FromLong( thread_local(use_time_context) ); // takes it's own ref, so we release ours PyDict_SetItemString( atd, "restore_use_time_context", utl ); Py_DECREF(utl); thread_local(use_time_context) = TRUE; //PySys_WriteStdout( "First AtTime struct activated, setting thread_local(use_time_context) to TRUE\n" ); } else {
static PyObject * local_new(PyTypeObject *type, PyObject *args, PyObject *kw) { localobject *self; PyObject *tdict; if (type->tp_init == PyBaseObject_Type.tp_init && ((args && PyObject_IsTrue(args)) || (kw && PyObject_IsTrue(kw)))) { PyErr_SetString(PyExc_TypeError, "Initialization arguments are not supported"); return NULL; } self = (localobject *)type->tp_alloc(type, 0); if (self == NULL) return NULL; Py_XINCREF(args); self->args = args; Py_XINCREF(kw); self->kw = kw; self->dict = NULL; /* making sure */ self->key = PyUnicode_FromFormat("thread.local.%p", self); if (self->key == NULL) goto err; self->dict = PyDict_New(); if (self->dict == NULL) goto err; tdict = PyThreadState_GetDict(); if (tdict == NULL) { PyErr_SetString(PyExc_SystemError, "Couldn't get thread-state dictionary"); goto err; } if (PyDict_SetItem(tdict, self->key, self->dict) < 0) goto err; return (PyObject *)self; err: Py_DECREF(self); return NULL; }
static uintptr_t _current_context_id(PyThreadState *ts) { uintptr_t rc; PyObject *callback_rc; if (context_id_callback) { callback_rc = PyObject_CallFunctionObjArgs(context_id_callback, NULL); if (!callback_rc) { PyErr_Print(); goto error; } rc = (uintptr_t)PyLong_AsLong(callback_rc); Py_DECREF(callback_rc); if (PyErr_Occurred()) { yerr("context id callback returned non-integer"); goto error; } return rc; } else { // Use thread_id instead of ts pointer, because when we create/delete many threads, some // of them do not show up in the thread_stats, because ts pointers are recycled in the VM. // Also, OS tids are recycled, too. The only valid way is to give ctx's custom tids which // are hold in a per-thread structure. Again: we use an integer instead of directly mapping the ctx // pointer to some per-thread structure because other threading libraries do not necessarily // have direct ThreadState->Thread mapping. Greenlets, for example, will only have a single // thread. Therefore, we need to identify the "context" concept independent from ThreadState // objects. // TODO: Any more optimization? This has increased the runtime factor from 7x to 11x. // and also we may have a memory leak below. We maybe can optimize the common case. PyObject *d = PyThreadState_GetDict(); PyObject *ytid = PyDict_GetItemString(d, "_yappi_tid"); if (!ytid) { ytid = PyLong_FromLong(ycurthreadindex++); PyDict_SetItemString(d, "_yappi_tid", ytid); } rc = PyLong_AsLong(ytid); return rc; } error: PyErr_Clear(); Py_CLEAR(context_id_callback); // don't use callback again return 0; }
NPY_NO_EXPORT PyObject * get_global_ext_obj(void) { PyObject *thedict; PyObject *ref = NULL; #if USE_USE_DEFAULTS==1 if (PyUFunc_NUM_NODEFAULTS != 0) { #endif thedict = PyThreadState_GetDict(); if (thedict == NULL) { thedict = PyEval_GetBuiltins(); } ref = PyDict_GetItem(thedict, npy_um_str_pyvals_name); #if USE_USE_DEFAULTS==1 } #endif return ref; }
static PyGreenlet* green_create_main(void) { PyGreenlet* gmain; PyObject* dict = PyThreadState_GetDict(); if (dict == NULL) { if (!PyErr_Occurred()) PyErr_NoMemory(); return NULL; } /* create the main greenlet for this thread */ gmain = (PyGreenlet*) PyType_GenericAlloc(&PyGreenlet_Type, 0); if (gmain == NULL) return NULL; gmain->stack_start = (char*) 1; gmain->stack_stop = (char*) -1; gmain->run_info = dict; Py_INCREF(dict); return gmain; }
extern "C" void Py_ReprLeave(PyObject* obj) noexcept { PyObject* dict; PyObject* list; Py_ssize_t i; dict = PyThreadState_GetDict(); if (dict == NULL) return; list = PyDict_GetItemString(dict, KEY); if (list == NULL || !PyList_Check(list)) return; i = PyList_GET_SIZE(list); /* Count backwards because we always expect obj to be list[-1] */ while (--i >= 0) { if (PyList_GET_ITEM(list, i) == obj) { PyList_SetSlice(list, i, i + 1, NULL); break; } } }
PyObject* GetClassForThread(const char* szModule, const char* szClass) { // Returns the given class, specific to the current thread's interpreter. For performance // these are cached for each thread. // // This is for internal use only, so we'll cache using only the class name. Make sure they // are unique. (That is, don't try to import classes with the same name from two different // modules.) PyObject* dict = PyThreadState_GetDict(); I(dict); if (dict == 0) { // I don't know why there wouldn't be thread state so I'm going to raise an exception // unless I find more info. return PyErr_Format(PyExc_Exception, "pyodbc: PyThreadState_GetDict returned NULL"); } // Check the cache. GetItemString returns a borrowed reference. PyObject* cls = PyDict_GetItemString(dict, szClass); if (cls) { Py_INCREF(cls); return cls; } // Import the class and cache it. GetAttrString returns a new reference. PyObject* mod = PyImport_ImportModule(szModule); if (!mod) return 0; cls = PyObject_GetAttrString(mod, szClass); Py_DECREF(mod); if (!cls) return 0; // SetItemString increments the refcount (not documented) PyDict_SetItemString(dict, szClass, cls); return cls; }
/* * 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; }
DEFINEFN PyObject* psyco_thread_dict() { PyObject* dict = PyThreadState_GetDict(); PyObject* result; bool err; if (dict == NULL) return NULL; result = PyDict_GetItem(dict, thread_dict_key); if (result == NULL) { result = PyDict_New(); if (result == NULL) return NULL; err = PyDict_SetItem(dict, thread_dict_key, result); Py_DECREF(result); /* one reference left in 'dict' */ if (err) result = NULL; } return result; }
/* This function creates and returns a thread-local Python object that has space to store two integer error numbers; once created the Python object is kept alive in the thread state dictionary as long as the thread itself. */ PyObject * _ctypes_get_errobj(int **pspace) { PyObject *dict = PyThreadState_GetDict(); PyObject *errobj; static PyObject *error_object_name; if (dict == 0) { PyErr_SetString(PyExc_RuntimeError, "cannot get thread state"); return NULL; } if (error_object_name == NULL) { error_object_name = PyUnicode_InternFromString("ctypes.error_object"); if (error_object_name == NULL) return NULL; } errobj = PyDict_GetItem(dict, error_object_name); if (errobj) Py_INCREF(errobj); else { void *space = PyMem_Malloc(sizeof(int) * 2); if (space == NULL) return NULL; memset(space, 0, sizeof(int) * 2); errobj = PyCapsule_New(space, CTYPES_CAPSULE_NAME_PYMEM, pymem_destructor); if (errobj == NULL) return NULL; if (-1 == PyDict_SetItem(dict, error_object_name, errobj)) { Py_DECREF(errobj); return NULL; } } *pspace = (int *)PyCapsule_GetPointer(errobj, CTYPES_CAPSULE_NAME_PYMEM); return errobj; }
/* This function creates and returns a thread-local Python object that has space to store two integer error numbers; once created the Python object is kept alive in the thread state dictionary as long as the thread itself. */ PyObject * get_error_object(int **pspace) { PyObject *dict = PyThreadState_GetDict(); PyObject *errobj; static PyObject *error_object_name; if (dict == 0) { PyErr_SetString(PyExc_RuntimeError, "cannot get thread state"); return NULL; } if (error_object_name == NULL) { error_object_name = PyString_InternFromString("ctypes.error_object"); if (error_object_name == NULL) return NULL; } errobj = PyDict_GetItem(dict, error_object_name); if (errobj) Py_INCREF(errobj); else { void *space = PyMem_Malloc(sizeof(int) * 2); if (space == NULL) return NULL; memset(space, 0, sizeof(int) * 2); errobj = PyCObject_FromVoidPtr(space, PyMem_Free); if (errobj == NULL) return NULL; if (-1 == PyDict_SetItem(dict, error_object_name, errobj)) { Py_DECREF(errobj); return NULL; } } *pspace = (int *)PyCObject_AsVoidPtr(errobj); return errobj; }
bool py_execute(PyCodeObject* py_func, DSMSession* sc_sess, DSMCondition::EventType event, map<string,string>* event_params, bool expect_int_result) { // acquire the GIL PYLOCK; bool py_res = false; DBG("add main \n"); PyObject* m = PyImport_AddModule("__main__"); if (m == NULL) { ERROR("getting main module\n"); return false; } DBG("get globals \n"); PyObject* globals = PyModule_GetDict(m); PyObject* locals = getPyLocals(sc_sess); PyObject* params = PyDict_New(); if (NULL != event_params) { for (map<string,string>::iterator it=event_params->begin(); it != event_params->end(); it++) { PyObject* v = PyString_FromString(it->second.c_str()); PyDict_SetItemString(params, it->first.c_str(), v); Py_DECREF(v); } } PyDict_SetItemString(locals, "params", params); PyObject *t = PyInt_FromLong(event); PyDict_SetItemString(locals, "type", t); PyObject* py_sc_sess = PyCObject_FromVoidPtr(sc_sess,NULL); PyObject* ts_dict = PyThreadState_GetDict(); PyDict_SetItemString(ts_dict, "_dsm_sess_", py_sc_sess); Py_DECREF(py_sc_sess); // call the function PyObject* res = PyEval_EvalCode((PyCodeObject*)py_func, globals, locals); if(PyErr_Occurred()) PyErr_Print(); PyDict_DelItemString(locals, "params"); PyDict_Clear(params); Py_DECREF(params); PyDict_DelItemString(locals, "type"); Py_DECREF(t); // ts_dict = PyThreadState_GetDict(); // should be the same as before PyDict_DelItemString(ts_dict, "_dsm_sess_"); if (NULL == res) { ERROR("evaluating python code\n"); } else if (PyBool_Check(res)) { py_res = PyInt_AsLong(res); Py_DECREF(res); } else { if (expect_int_result) { ERROR("unknown result from python code\n"); } Py_DECREF(res); } return py_res; }
static int Fiber_tp_init(Fiber *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"target", "args", "kwargs", "parent", NULL}; PyObject *target, *t_args, *t_kwargs; Fiber *parent; target = t_args = t_kwargs = NULL; parent = NULL; if (self->initialized) { PyErr_SetString(PyExc_RuntimeError, "object was already initialized"); return -1; } if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOO!:__init__", kwlist, &target, &t_args, &t_kwargs, &FiberType, &parent)) { return -1; } if (!CHECK_STATE) { return -1; } if (parent) { /* check if parent is on the same (real) thread */ if (parent->ts_dict != PyThreadState_GetDict()) { PyErr_SetString(PyExc_FiberError, "parent cannot be on a different thread"); return -1; } if (parent->stacklet_h == EMPTY_STACKLET_HANDLE) { PyErr_SetString(PyExc_ValueError, "parent must not have ended"); return -1; } } else { parent = _global_state.current; } if (target) { if (!PyCallable_Check(target)) { PyErr_SetString(PyExc_TypeError, "if specified, target must be a callable"); return -1; } if (t_args) { if (!PyTuple_Check(t_args)) { PyErr_SetString(PyExc_TypeError, "args must be a tuple"); return -1; } } else { t_args = PyTuple_New(0); } if (t_kwargs) { if (!PyDict_Check(t_kwargs)) { PyErr_SetString(PyExc_TypeError, "kwargs must be a dict"); return -1; } } } Py_XINCREF(target); Py_XINCREF(t_args); Py_XINCREF(t_kwargs); self->target = target; self->args = t_args; self->kwargs = t_kwargs; Py_INCREF(parent); self->parent = parent; self->thread_h = parent->thread_h; self->ts_dict = parent->ts_dict; Py_INCREF(self->ts_dict); self->initialized = True; return 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; }