15 #include "pythonTask.h" 17 #include "config_event.h" 24 Configure(config_pythonTask);
25 ConfigureFn(config_pythonTask) {
26 PythonTask::init_type();
30 extern struct Dtool_PyTypedObject Dtool_TypedReferenceCount;
39 PythonTask(PyObject *
function,
const string &name) :
46 _registered_to_owner =
false;
49 set_function(
function);
50 set_args(Py_None,
true);
51 set_upon_death(Py_None);
54 __dict__ = PyDict_New();
56 #ifndef SIMPLE_THREADS 58 #ifdef WITH_THREAD // This symbol defined within Python.h 74 Py_XDECREF(_generator);
76 Py_XDECREF(_upon_death);
87 set_function(PyObject *
function) {
88 Py_XDECREF(_function);
92 if (_function != Py_None && !PyCallable_Check(_function)) {
93 nassert_raise(
"Invalid function passed to PythonTask");
103 PyObject *PythonTask::
105 Py_INCREF(_function);
117 set_args(PyObject *args,
bool append_task) {
121 if (args == Py_None) {
123 _args = PyTuple_New(0);
125 if (PySequence_Check(args)) {
126 _args = PySequence_Tuple(args);
131 nassert_raise(
"Invalid args passed to PythonTask");
132 _args = PyTuple_New(0);
135 _append_task = append_task;
144 PyObject *PythonTask::
152 int num_args = PyTuple_GET_SIZE(_args);
153 PyObject *with_task = PyTuple_New(num_args + 1);
154 for (
int i = 0; i < num_args; ++i) {
155 PyObject *item = PyTuple_GET_ITEM(_args, i);
157 PyTuple_SET_ITEM(with_task, i, item);
162 DTool_CreatePyInstanceTyped(
this, Dtool_TypedReferenceCount,
164 PyTuple_SET_ITEM(with_task, num_args,
self);
181 set_upon_death(PyObject *upon_death) {
182 Py_XDECREF(_upon_death);
184 _upon_death = upon_death;
185 Py_INCREF(_upon_death);
186 if (_upon_death != Py_None && !PyCallable_Check(_upon_death)) {
187 nassert_raise(
"Invalid upon_death function passed to PythonTask");
197 PyObject *PythonTask::
199 Py_INCREF(_upon_death);
216 set_owner(PyObject *owner) {
218 if (owner != Py_None) {
219 PyObject *add = PyObject_GetAttrString(owner,
"_addTask");
220 PyObject *clear = PyObject_GetAttrString(owner,
"_clearTask");
222 if (add == NULL || !PyCallable_Check(add) ||
223 clear == NULL || !PyCallable_Check(clear)) {
224 Dtool_Raise_TypeError(
"owner object should have _addTask and _clearTask methods");
230 if (_owner != NULL && _owner != Py_None && _state != S_inactive) {
231 unregister_from_owner();
238 if (_owner != Py_None && _state != S_inactive) {
248 PyObject *PythonTask::
264 __setattr__(PyObject *
self, PyObject *attr, PyObject *v) {
265 if (PyObject_GenericSetAttr(
self, attr, v) == 0) {
269 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
275 if (task_cat.is_debug()) {
276 PyObject *str = PyObject_Repr(v);
278 << *
this <<
": task." 279 #if PY_MAJOR_VERSION >= 3 280 << PyUnicode_AsUTF8(attr) <<
" = " 281 << PyUnicode_AsUTF8(str) <<
"\n";
283 << PyString_AsString(attr) <<
" = " 284 << PyString_AsString(str) <<
"\n";
289 return PyDict_SetItem(__dict__, attr, v);
302 __delattr__(PyObject *
self, PyObject *attr) {
303 if (PyObject_GenericSetAttr(
self, attr, NULL) == 0) {
307 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
313 if (PyDict_DelItem(__dict__, attr) == -1) {
315 #if PY_MAJOR_VERSION < 3 316 PyErr_Format(PyExc_AttributeError,
317 "'PythonTask' object has no attribute '%.400s'",
318 PyString_AS_STRING(attr));
320 PyErr_Format(PyExc_AttributeError,
321 "'PythonTask' object has no attribute '%U'",
339 PyObject *PythonTask::
340 __getattr__(PyObject *attr)
const {
347 PyObject *item = PyDict_GetItem(__dict__, attr);
351 #if PY_MAJOR_VERSION < 3 352 PyErr_Format(PyExc_AttributeError,
353 "'PythonTask' object has no attribute '%.400s'",
354 PyString_AS_STRING(attr));
356 PyErr_Format(PyExc_AttributeError,
357 "'PythonTask' object has no attribute '%U'",
374 __traverse__(visitproc visit,
void *arg) {
416 return _function != Py_None;
427 AsyncTask::DoneStatus PythonTask::
429 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 431 PyGILState_STATE gstate;
432 gstate = PyGILState_Ensure();
435 DoneStatus result = do_python_task();
437 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 438 PyGILState_Release(gstate);
451 AsyncTask::DoneStatus PythonTask::
453 PyObject *result = NULL;
455 if (_generator == (PyObject *)NULL) {
457 PyObject *args = get_args();
463 if (result != (PyObject *)NULL && PyGen_Check(result)) {
467 if (task_cat.is_debug()) {
468 #if PY_MAJOR_VERSION >= 3 469 PyObject *str = PyObject_ASCII(_function);
471 << PyUnicode_AsUTF8(str) <<
" in " << *
this 472 <<
" yielded a generator.\n";
474 PyObject *str = PyObject_Repr(_function);
476 << PyString_AsString(str) <<
" in " << *
this 477 <<
" yielded a generator.\n";
487 if (_generator != (PyObject *)NULL) {
489 PyObject *func = PyObject_GetAttrString(_generator,
"next");
490 nassertr(func != (PyObject *)NULL, DS_interrupt);
492 result = PyObject_CallObject(func, NULL);
495 if (result == (PyObject *)NULL && PyErr_Occurred() &&
496 PyErr_ExceptionMatches(PyExc_StopIteration)) {
499 Py_DECREF(_generator);
505 if (result == (PyObject *)NULL) {
506 if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) {
509 if (task_cat.is_debug()) {
511 <<
"SystemExit occurred in " << *
this <<
"\n";
515 <<
"Exception occurred in " << *
this <<
"\n";
520 if (result == Py_None) {
525 #if PY_MAJOR_VERSION >= 3 526 if (PyLong_Check(result)) {
527 long retval = PyLong_AS_LONG(result);
529 if (PyInt_Check(result)) {
530 long retval = PyInt_AS_LONG(result);
535 Py_XDECREF(_generator);
546 return (DoneStatus) retval;
560 #if PY_MAJOR_VERSION >= 3 561 PyObject *str = PyObject_ASCII(result);
563 str = PyUnicode_FromString(
"<repr error>");
566 << *
this <<
" returned " << PyUnicode_AsUTF8(str);
568 PyObject *str = PyObject_Repr(result);
570 str = PyString_FromString(
"<repr error>");
573 << *
this <<
" returned " << PyString_AsString(str);
577 string message = strm.str();
578 nassert_raise(message);
593 AsyncTask::upon_birth(manager);
617 AsyncTask::upon_death(manager, clean_exit);
619 if (_upon_death != Py_None) {
620 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 622 PyGILState_STATE gstate;
623 gstate = PyGILState_Ensure();
626 call_function(_upon_death);
628 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 629 PyGILState_Release(gstate);
632 unregister_from_owner();
641 register_to_owner() {
642 if (_owner != Py_None && !_registered_to_owner) {
643 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 645 PyGILState_STATE gstate;
646 gstate = PyGILState_Ensure();
649 _registered_to_owner =
true;
650 call_owner_method(
"_addTask");
652 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 653 PyGILState_Release(gstate);
664 unregister_from_owner() {
666 if (_owner != Py_None && _registered_to_owner) {
667 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 669 PyGILState_STATE gstate;
670 gstate = PyGILState_Ensure();
673 _registered_to_owner =
false;
674 call_owner_method(
"_clearTask");
676 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 677 PyGILState_Release(gstate);
690 call_owner_method(
const char *method_name) {
691 if (_owner != Py_None) {
692 PyObject *func = PyObject_GetAttrString(_owner, (
char *)method_name);
693 if (func == (PyObject *)NULL) {
695 <<
"Owner object added to " << *
this <<
" has no method " 696 << method_name <<
"().\n";
712 call_function(PyObject *
function) {
713 if (
function != Py_None) {
716 DTool_CreatePyInstanceTyped(
this, Dtool_TypedReferenceCount,
718 PyObject *args = Py_BuildValue(
"(O)",
self);
721 PyObject *result = PyObject_CallObject(
function, args);
727 #endif // HAVE_PYTHON A class to manage a loose queue of isolated tasks, which can be performed either synchronously (in th...
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
void ref() const
Explicitly increments the reference count.
This class represents a concrete task performed by an AsyncManager.
TypeHandle is the identifier used to differentiate C++ class types.
int get_type_index() const
Returns the internal index number associated with this object's TypeHandle, a unique number for each ...