00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "pythonTask.h"
00016 #include "pnotify.h"
00017
00018 #ifdef HAVE_PYTHON
00019 #include "py_panda.h"
00020
00021 TypeHandle PythonTask::_type_handle;
00022
00023 #ifndef CPPPARSER
00024 IMPORT_THIS struct Dtool_PyTypedObject Dtool_TypedReferenceCount;
00025 #endif
00026
00027
00028
00029
00030
00031
00032 PythonTask::
00033 PythonTask(PyObject *function, const string &name) :
00034 AsyncTask(name)
00035 {
00036 _function = NULL;
00037 _args = NULL;
00038 _upon_death = NULL;
00039 _owner = NULL;
00040 _registered_to_owner = false;
00041 _generator = NULL;
00042
00043 set_function(function);
00044 set_args(Py_None, true);
00045 set_upon_death(Py_None);
00046 set_owner(Py_None);
00047
00048 _dict = PyDict_New();
00049
00050 #ifndef SIMPLE_THREADS
00051
00052
00053 #ifdef WITH_THREAD // This symbol defined within Python.h
00054 PyEval_InitThreads();
00055 #endif
00056 #endif
00057 }
00058
00059
00060
00061
00062
00063
00064 PythonTask::
00065 ~PythonTask() {
00066 Py_DECREF(_function);
00067 Py_DECREF(_args);
00068 Py_DECREF(_dict);
00069 Py_XDECREF(_generator);
00070 Py_XDECREF(_owner);
00071 Py_XDECREF(_upon_death);
00072 }
00073
00074
00075
00076
00077
00078
00079
00080
00081 void PythonTask::
00082 set_function(PyObject *function) {
00083 Py_XDECREF(_function);
00084
00085 _function = function;
00086 Py_INCREF(_function);
00087 if (_function != Py_None && !PyCallable_Check(_function)) {
00088 nassert_raise("Invalid function passed to PythonTask");
00089 }
00090 }
00091
00092
00093
00094
00095
00096
00097
00098 PyObject *PythonTask::
00099 get_function() {
00100 Py_INCREF(_function);
00101 return _function;
00102 }
00103
00104
00105
00106
00107
00108
00109
00110
00111 void PythonTask::
00112 set_args(PyObject *args, bool append_task) {
00113 Py_XDECREF(_args);
00114 _args = NULL;
00115
00116 if (args == Py_None) {
00117
00118 _args = PyTuple_New(0);
00119 } else {
00120 if (PySequence_Check(args)) {
00121 _args = PySequence_Tuple(args);
00122 }
00123 }
00124
00125 if (_args == NULL) {
00126 nassert_raise("Invalid args passed to PythonTask");
00127 _args = PyTuple_New(0);
00128 }
00129
00130 _append_task = append_task;
00131 }
00132
00133
00134
00135
00136
00137
00138
00139 PyObject *PythonTask::
00140 get_args() {
00141 if (_append_task) {
00142
00143
00144
00145
00146
00147 int num_args = PyTuple_GET_SIZE(_args);
00148 PyObject *with_task = PyTuple_New(num_args + 1);
00149 for (int i = 0; i < num_args; ++i) {
00150 PyObject *item = PyTuple_GET_ITEM(_args, i);
00151 Py_INCREF(item);
00152 PyTuple_SET_ITEM(with_task, i, item);
00153 }
00154
00155 this->ref();
00156 PyObject *self =
00157 DTool_CreatePyInstanceTyped(this, Dtool_TypedReferenceCount,
00158 true, false, get_type_index());
00159 PyTuple_SET_ITEM(with_task, num_args, self);
00160 return with_task;
00161
00162 } else {
00163 Py_INCREF(_args);
00164 return _args;
00165 }
00166 }
00167
00168
00169
00170
00171
00172
00173
00174
00175 void PythonTask::
00176 set_upon_death(PyObject *upon_death) {
00177 Py_XDECREF(_upon_death);
00178
00179 _upon_death = upon_death;
00180 Py_INCREF(_upon_death);
00181 if (_upon_death != Py_None && !PyCallable_Check(_upon_death)) {
00182 nassert_raise("Invalid upon_death function passed to PythonTask");
00183 }
00184 }
00185
00186
00187
00188
00189
00190
00191
00192 PyObject *PythonTask::
00193 get_upon_death() {
00194 Py_INCREF(_upon_death);
00195 return _upon_death;
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 void PythonTask::
00211 set_owner(PyObject *owner) {
00212 if (_owner != NULL && _owner != Py_None && _state != S_inactive) {
00213 unregister_from_owner();
00214 }
00215
00216 Py_XDECREF(_owner);
00217 _owner = owner;
00218 Py_INCREF(_owner);
00219
00220 if (_owner != Py_None && _state != S_inactive) {
00221 register_to_owner();
00222 }
00223 }
00224
00225
00226
00227
00228
00229
00230 PyObject *PythonTask::
00231 get_owner() {
00232 Py_INCREF(_owner);
00233 return _owner;
00234 }
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 int PythonTask::
00246 __setattr__(const string &attr_name, PyObject *v) {
00247 if (task_cat.is_debug()) {
00248 PyObject *str = PyObject_Repr(v);
00249 task_cat.debug()
00250 << *this << ": task." << attr_name << " = "
00251 << PyString_AsString(str) << "\n";
00252 Py_DECREF(str);
00253 }
00254
00255 if (attr_name == "delayTime") {
00256 if (v == Py_None) {
00257 clear_delay();
00258 } else {
00259 double delay = PyFloat_AsDouble(v);
00260 if (!PyErr_Occurred()) {
00261 set_delay(delay);
00262 }
00263 }
00264
00265 } else if (attr_name == "name") {
00266 char *name = PyString_AsString(v);
00267 if (name != (char *)NULL) {
00268 set_name(name);
00269 }
00270
00271 } else if (attr_name == "id" || attr_name == "time" ||
00272 attr_name == "frame" || attr_name == "wakeTime") {
00273 nassert_raise("Cannot set constant value");
00274 return true;
00275
00276 } else {
00277 return PyDict_SetItemString(_dict, attr_name.c_str(), v);
00278 }
00279
00280 return 0;
00281 }
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 int PythonTask::
00293 __setattr__(const string &attr_name) {
00294 return PyDict_DelItemString(_dict, attr_name.c_str());
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 PyObject *PythonTask::
00307 __getattr__(const string &attr_name) const {
00308 if (attr_name == "time") {
00309 return PyFloat_FromDouble(get_elapsed_time());
00310 } else if (attr_name == "name") {
00311 return PyString_FromString(get_name().c_str());
00312 } else if (attr_name == "wakeTime") {
00313 return PyFloat_FromDouble(get_wake_time());
00314 } else if (attr_name == "delayTime") {
00315 if (!has_delay()) {
00316 Py_RETURN_NONE;
00317 }
00318 return PyFloat_FromDouble(get_delay());
00319 } else if (attr_name == "frame") {
00320 return PyInt_FromLong(get_elapsed_frames());
00321 } else if (attr_name == "id") {
00322 return PyInt_FromLong(_task_id);
00323 } else {
00324 return PyMapping_GetItemString(_dict, (char *)attr_name.c_str());
00325 }
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 bool PythonTask::
00339 is_runnable() {
00340 return _function != Py_None;
00341 }
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 AsyncTask::DoneStatus PythonTask::
00352 do_task() {
00353 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
00354
00355 PyGILState_STATE gstate;
00356 gstate = PyGILState_Ensure();
00357 #endif
00358
00359 DoneStatus result = do_python_task();
00360
00361 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
00362 PyGILState_Release(gstate);
00363 #endif
00364
00365 return result;
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375 AsyncTask::DoneStatus PythonTask::
00376 do_python_task() {
00377 PyObject *result = NULL;
00378
00379 if (_generator == (PyObject *)NULL) {
00380
00381 PyObject *args = get_args();
00382 result =
00383 Thread::get_current_thread()->call_python_func(_function, args);
00384 Py_DECREF(args);
00385
00386 #ifdef PyGen_Check
00387 if (result != (PyObject *)NULL && PyGen_Check(result)) {
00388
00389
00390
00391 if (task_cat.is_debug()) {
00392 PyObject *str = PyObject_Repr(_function);
00393 task_cat.debug()
00394 << PyString_AsString(str) << " in " << *this
00395 << " yielded a generator.\n";
00396 Py_DECREF(str);
00397 }
00398 _generator = result;
00399 result = NULL;
00400 }
00401 #endif
00402 }
00403
00404 if (_generator != (PyObject *)NULL) {
00405
00406 PyObject *func = PyObject_GetAttrString(_generator, "next");
00407 nassertr(func != (PyObject *)NULL, DS_interrupt);
00408
00409 result = PyObject_CallObject(func, NULL);
00410 Py_DECREF(func);
00411
00412 if (result == (PyObject *)NULL && PyErr_Occurred() &&
00413 PyErr_ExceptionMatches(PyExc_StopIteration)) {
00414
00415 PyErr_Clear();
00416 Py_DECREF(_generator);
00417 _generator = NULL;
00418 return DS_done;
00419 }
00420 }
00421
00422 if (result == (PyObject *)NULL) {
00423 task_cat.error()
00424 << "Exception occurred in " << *this << "\n";
00425 return DS_interrupt;
00426 }
00427
00428 if (result == Py_None) {
00429 Py_DECREF(result);
00430 return DS_done;
00431 }
00432
00433 if (PyInt_Check(result)) {
00434 int retval = PyInt_AS_LONG(result);
00435 switch (retval) {
00436 case DS_again:
00437 Py_XDECREF(_generator);
00438 _generator = NULL;
00439
00440
00441 case DS_done:
00442 case DS_cont:
00443 case DS_pickup:
00444 case DS_exit:
00445 case DS_pause:
00446
00447 Py_DECREF(result);
00448 return (DoneStatus)retval;
00449
00450 case -1:
00451
00452 Py_DECREF(result);
00453 return DS_done;
00454
00455 default:
00456
00457 break;
00458 }
00459 }
00460
00461 PyObject *str = PyObject_Repr(result);
00462 ostringstream strm;
00463 strm
00464 << *this << " returned " << PyString_AsString(str);
00465 Py_DECREF(str);
00466 Py_DECREF(result);
00467 string message = strm.str();
00468 nassert_raise(message);
00469
00470 return DS_interrupt;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481 void PythonTask::
00482 upon_birth(AsyncTaskManager *manager) {
00483 AsyncTask::upon_birth(manager);
00484 register_to_owner();
00485 }
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 void PythonTask::
00506 upon_death(AsyncTaskManager *manager, bool clean_exit) {
00507 AsyncTask::upon_death(manager, clean_exit);
00508
00509 if (_upon_death != Py_None) {
00510 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
00511
00512 PyGILState_STATE gstate;
00513 gstate = PyGILState_Ensure();
00514 #endif
00515
00516 call_function(_upon_death);
00517
00518 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
00519 PyGILState_Release(gstate);
00520 #endif
00521 }
00522 unregister_from_owner();
00523 }
00524
00525
00526
00527
00528
00529
00530 void PythonTask::
00531 register_to_owner() {
00532 if (_owner != Py_None && !_registered_to_owner) {
00533 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
00534
00535 PyGILState_STATE gstate;
00536 gstate = PyGILState_Ensure();
00537 #endif
00538
00539 _registered_to_owner = true;
00540 call_owner_method("_addTask");
00541
00542 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
00543 PyGILState_Release(gstate);
00544 #endif
00545 }
00546 }
00547
00548
00549
00550
00551
00552
00553 void PythonTask::
00554 unregister_from_owner() {
00555
00556 if (_owner != Py_None && _registered_to_owner) {
00557 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
00558
00559 PyGILState_STATE gstate;
00560 gstate = PyGILState_Ensure();
00561 #endif
00562
00563 _registered_to_owner = false;
00564 call_owner_method("_clearTask");
00565
00566 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
00567 PyGILState_Release(gstate);
00568 #endif
00569 }
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579 void PythonTask::
00580 call_owner_method(const char *method_name) {
00581 if (_owner != Py_None) {
00582 PyObject *func = PyObject_GetAttrString(_owner, (char *)method_name);
00583 if (func == (PyObject *)NULL) {
00584 PyObject *str = PyObject_Repr(_owner);
00585 task_cat.error()
00586 << "Owner object " << PyString_AsString(str) << " added to "
00587 << *this << " has no method " << method_name << "().\n";
00588 Py_DECREF(str);
00589
00590 } else {
00591 call_function(func);
00592 Py_DECREF(func);
00593 }
00594 }
00595 }
00596
00597
00598
00599
00600
00601
00602
00603 void PythonTask::
00604 call_function(PyObject *function) {
00605 if (function != Py_None) {
00606 this->ref();
00607 PyObject *self =
00608 DTool_CreatePyInstanceTyped(this, Dtool_TypedReferenceCount,
00609 true, false, get_type_index());
00610 PyObject *args = Py_BuildValue("(O)", self);
00611 Py_DECREF(self);
00612
00613 PyObject *result = PyObject_CallObject(function, args);
00614 Py_XDECREF(result);
00615 Py_DECREF(args);
00616 }
00617 }
00618
00619 #endif // HAVE_PYTHON