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,
163 true,
false, get_type_index());
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) {
217 if (_owner != NULL && _owner != Py_None && _state != S_inactive) {
218 unregister_from_owner();
225 if (_owner != Py_None && _state != S_inactive) {
235 PyObject *PythonTask::
251 __setattr__(PyObject *
self, PyObject *attr, PyObject *v) {
252 if (PyObject_GenericSetAttr(
self, attr, v) == 0) {
256 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
262 if (task_cat.is_debug()) {
263 PyObject *str = PyObject_Repr(v);
265 << *
this <<
": task."
266 #if PY_MAJOR_VERSION >= 3
267 << PyUnicode_AsUTF8(attr) <<
" = "
268 << PyUnicode_AsUTF8(str) <<
"\n";
270 << PyString_AsString(attr) <<
" = "
271 << PyString_AsString(str) <<
"\n";
276 return PyDict_SetItem(__dict__, attr, v);
289 __delattr__(PyObject *
self, PyObject *attr) {
290 if (PyObject_GenericSetAttr(
self, attr, NULL) == 0) {
294 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
300 if (PyDict_DelItem(__dict__, attr) == -1) {
302 #if PY_MAJOR_VERSION < 3
303 PyErr_Format(PyExc_AttributeError,
304 "'PythonTask' object has no attribute '%.400s'",
305 PyString_AS_STRING(attr));
307 PyErr_Format(PyExc_AttributeError,
308 "'PythonTask' object has no attribute '%U'",
326 PyObject *PythonTask::
327 __getattr__(PyObject *attr)
const {
334 PyObject *item = PyDict_GetItem(__dict__, attr);
338 #if PY_MAJOR_VERSION < 3
339 PyErr_Format(PyExc_AttributeError,
340 "'PythonTask' object has no attribute '%.400s'",
341 PyString_AS_STRING(attr));
343 PyErr_Format(PyExc_AttributeError,
344 "'PythonTask' object has no attribute '%U'",
361 __traverse__(visitproc visit,
void *arg) {
364 Py_VISIT(_upon_death);
367 Py_VISIT(_generator);
380 Py_CLEAR(_upon_death);
383 Py_CLEAR(_generator);
399 return _function != Py_None;
410 AsyncTask::DoneStatus PythonTask::
412 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
414 PyGILState_STATE gstate;
415 gstate = PyGILState_Ensure();
418 DoneStatus result = do_python_task();
420 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
421 PyGILState_Release(gstate);
434 AsyncTask::DoneStatus PythonTask::
436 PyObject *result = NULL;
438 if (_generator == (PyObject *)NULL) {
440 PyObject *args = get_args();
446 if (result != (PyObject *)NULL && PyGen_Check(result)) {
450 if (task_cat.is_debug()) {
451 #if PY_MAJOR_VERSION >= 3
452 PyObject *str = PyObject_ASCII(_function);
454 << PyUnicode_AsUTF8(str) <<
" in " << *
this
455 <<
" yielded a generator.\n";
457 PyObject *str = PyObject_Repr(_function);
459 << PyString_AsString(str) <<
" in " << *
this
460 <<
" yielded a generator.\n";
470 if (_generator != (PyObject *)NULL) {
472 PyObject *func = PyObject_GetAttrString(_generator,
"next");
473 nassertr(func != (PyObject *)NULL, DS_interrupt);
475 result = PyObject_CallObject(func, NULL);
478 if (result == (PyObject *)NULL && PyErr_Occurred() &&
479 PyErr_ExceptionMatches(PyExc_StopIteration)) {
482 Py_DECREF(_generator);
488 if (result == (PyObject *)NULL) {
489 if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) {
492 if (task_cat.is_debug()) {
494 <<
"SystemExit occurred in " << *
this <<
"\n";
498 <<
"Exception occurred in " << *
this <<
"\n";
503 if (result == Py_None) {
508 #if PY_MAJOR_VERSION >= 3
509 if (PyLong_Check(result)) {
510 long retval = PyLong_AS_LONG(result);
512 if (PyInt_Check(result)) {
513 long retval = PyInt_AS_LONG(result);
518 Py_XDECREF(_generator);
529 return (DoneStatus) retval;
543 #if PY_MAJOR_VERSION >= 3
544 PyObject *str = PyObject_ASCII(result);
546 << *
this <<
" returned " << PyUnicode_AsUTF8(str);
548 PyObject *str = PyObject_Repr(result);
550 << *
this <<
" returned " << PyString_AsString(str);
554 string message = strm.str();
555 nassert_raise(message);
570 AsyncTask::upon_birth(manager);
594 AsyncTask::upon_death(manager, clean_exit);
596 if (_upon_death != Py_None) {
597 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
599 PyGILState_STATE gstate;
600 gstate = PyGILState_Ensure();
603 call_function(_upon_death);
605 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
606 PyGILState_Release(gstate);
609 unregister_from_owner();
618 register_to_owner() {
619 if (_owner != Py_None && !_registered_to_owner) {
620 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
622 PyGILState_STATE gstate;
623 gstate = PyGILState_Ensure();
626 _registered_to_owner =
true;
627 call_owner_method(
"_addTask");
629 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
630 PyGILState_Release(gstate);
641 unregister_from_owner() {
643 if (_owner != Py_None && _registered_to_owner) {
644 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
646 PyGILState_STATE gstate;
647 gstate = PyGILState_Ensure();
650 _registered_to_owner =
false;
651 call_owner_method(
"_clearTask");
653 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
654 PyGILState_Release(gstate);
667 call_owner_method(
const char *method_name) {
668 if (_owner != Py_None) {
669 PyObject *func = PyObject_GetAttrString(_owner, (
char *)method_name);
670 if (func == (PyObject *)NULL) {
671 #if PY_MAJOR_VERSION >= 3
672 PyObject *str = PyObject_ASCII(_owner);
674 <<
"Owner object " << PyUnicode_AsUTF8(str) <<
" added to "
675 << *
this <<
" has no method " << method_name <<
"().\n";
677 PyObject *str = PyObject_Repr(_owner);
679 <<
"Owner object " << PyString_AsString(str) <<
" added to "
680 << *
this <<
" has no method " << method_name <<
"().\n";
698 call_function(PyObject *
function) {
699 if (
function != Py_None) {
702 DTool_CreatePyInstanceTyped(
this, Dtool_TypedReferenceCount,
703 true,
false, get_type_index());
704 PyObject *args = Py_BuildValue(
"(O)",
self);
707 PyObject *result = PyObject_CallObject(
function, args);
713 #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.
This class represents a concrete task performed by an AsyncManager.
TypeHandle is the identifier used to differentiate C++ class types.