capisuite/src/application/idlescript.cpp

187 lines
6.0 KiB
C++

/* @file incomingscript.cpp
@brief Contains IncomingScript - Incoming call handling. One object for each incoming call is created.
@author Gernot Hillier <gernot@hillier.de>
$Revision: 1.2 $
*/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "idlescript.h"
#include "capisuitemodule.h"
void* idlescript_exec_handler(void* arg)
{
if (!arg) {
cerr << "FATAL ERROR: no IdleScript reference given in idlescript_exec_handler" << endl;
exit(1);
}
pthread_cleanup_push(idlescript_cleanup_handler,arg);
IdleScript *instance=static_cast<IdleScript*>(arg);
instance->run();
pthread_cleanup_pop(1); // run the cleanup_handler and then deregister it
}
void idlescript_cleanup_handler(void* arg)
{
if (!arg) {
cerr << "FATAL ERROR: no IdleScript reference given in idlescript_exec_handler" << endl;
exit(1);
}
IdleScript *instance=static_cast<IdleScript*>(arg);
instance->final();
}
IdleScript::IdleScript(ostream &debug, unsigned short debug_level, ostream &error, Capi *capi, string idlescript, int idlescript_interval, PyThreadState *py_state, PycStringIO_CAPI* cStringIO) throw (ApplicationError)
:PythonScript(debug,debug_level,error,idlescript,"idle",cStringIO),idlescript_interval(idlescript_interval),py_state(py_state),capi(capi),active(true)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
int ret=pthread_create(&thread_handle, &attr, idlescript_exec_handler, this); // start thread as detached
if (ret)
throw ApplicationError("error while creating thread","IdleScript::IdleScript()");
if (debug_level>=3)
debug << prefix() << "IdleScript created." << endl;
}
IdleScript::~IdleScript()
{
if (debug_level>=3)
debug << prefix() << "IdleScript deleted" << endl;
}
void
IdleScript::run() throw()
{
int count=0,errorcount=0;
timespec delay_time;
delay_time.tv_sec=0; delay_time.tv_nsec=100000000; // 100 msec
while (1) {
pthread_testcancel(); // cancellation point
nanosleep(&delay_time,NULL);
count++;
if (active && (count>=idlescript_interval*10)) {
count=0;
PyObject *capi_ref=NULL;
try {
if (debug_level>=3)
debug << prefix() << "executing idlescript..." << endl;
PyEval_RestoreThread(py_state); // acquire lock, switch to right thread context
capisuitemodule_init();
capi_ref=PyCObject_FromVoidPtr(capi,NULL); // new ref
if (!capi_ref)
throw ApplicationError("unable to create CObject from Capi reference","IdleScript::run()");
args=Py_BuildValue("(O)",capi_ref); // args = new ref
if (!args)
throw ApplicationError("can't build arguments","IdleScript::run()");
PythonScript::run();
Py_DECREF(args);
args=NULL;
Py_DECREF(capi_ref);
capi_ref=NULL;
if (PyEval_SaveThread()!=py_state) // release lock
throw ApplicationError("can't release thread lock","IdleScript::run()");
errorcount=0;
if (debug_level>=3)
debug << prefix() << "idlescript finished..." << endl;
}
catch (ApplicationError e) {
errorcount++;
error << prefix() << "IdleScript " << this << " Error occured. " << endl;
error << prefix() << "message was: " << e << endl;
if (errorcount>9) {
error << prefix() << "Too much subsequent errors. Disabling idle script." << endl;
active=false;
}
if (args)
Py_DECREF(args);
if (capi_ref)
Py_DECREF(capi_ref);
if (PyEval_SaveThread()!=py_state) // release lock
throw ApplicationError("can't release thread lock","IdleScript::run()");
}
}
}
}
void
IdleScript::requestTerminate()
{
pthread_cancel(thread_handle);
}
void
IdleScript::activate()
{
active=true;
}
/* History
Old Log (for new changes see ChangeLog):
Revision 1.1.1.1 2003/02/19 08:19:53 gernot
initial checkin of 0.4
Revision 1.12 2003/02/10 14:17:09 ghillie
merged from NATIVE_PTHREADS to HEAD
Revision 1.11.2.1 2003/02/09 15:03:41 ghillie
- rewritten to use native pthread_* calls instead of CommonC++ Thread
Revision 1.11 2003/01/19 16:50:27 ghillie
- removed severity in exceptions. No FATAL-automatic-exit any more.
Removed many FATAL conditions, other ones are exiting now by themselves
Revision 1.10 2003/01/18 12:52:50 ghillie
- pass on reference to Python C API to PythonScript
Revision 1.9 2003/01/17 15:11:34 ghillie
- added debug output for finish of idlescript
Revision 1.8 2003/01/06 21:02:01 ghillie
- won't exit if script causes too much errors - only temporarily deactivate
script execution, can be re-enabled with activate()
- added debug output for script execution
Revision 1.7 2003/01/06 16:21:58 ghillie
- renamed terminate() to requestTerminate() to avoid endless recursion
- use finish flag instead of call to terminate() in requestTerminate() and run()
Revision 1.6 2003/01/04 16:00:53 ghillie
- log improvements: log_level, timestamp
Revision 1.5 2002/12/16 13:12:44 ghillie
- removed double output of error message
Revision 1.4 2002/12/14 14:02:22 ghillie
- added terminate() method (make terminate public)
- added error counting code to de-activate idle-script after 10 errors
Revision 1.3 2002/12/13 09:57:10 ghillie
- error message formatting done by exception classes now
Revision 1.2 2002/12/11 13:03:50 ghillie
- finished (use Thred::sleep() instead of nanosleep(), fix in if condition)
Revision 1.1 2002/12/10 15:54:08 ghillie
- initial checkin, will take over functionality from FlowControl::executeIdleScript()
*/