void XBPyThread::Process() { CLog::Log(LOGDEBUG,"Python thread: start processing"); char path[1024]; char sourcedir[1024]; // get the global lock PyEval_AcquireLock(); m_threadState = Py_NewInterpreter(); PyEval_ReleaseLock(); if (!m_threadState) { CLog::Log(LOGERROR,"Python thread: FAILED to get thread state!"); return; } PyEval_AcquireLock(); // swap in my thread state PyThreadState_Swap(m_threadState); m_pExecuter->InitializeInterpreter(); // get path from script file name and add python path's // this is used for python so it will search modules from script path first strcpy(sourcedir, source); #ifndef _LINUX strcpy(strrchr(sourcedir, PATH_SEPARATOR_CHAR), ";"); #else strcpy(strrchr(sourcedir, PATH_SEPARATOR_CHAR), ":"); #endif strcpy(path, sourcedir); #ifndef _LINUX strcat(path, dll_getenv("PYTHONPATH")); #else #ifdef __APPLE__ strcat(path, _P("Q:\\system\\python\\python24.zlib:")); strcat(path, _P("Q:\\system\\python\\lib-osx")); #else strcat(path, Py_GetPath()); #endif #endif // set current directory and python's path. if (argv != NULL) { PySys_SetArgv(argc, argv); } PySys_SetPath(path); #ifdef _LINUX // Replace the : at the end with ; so it will be EXACTLY like the xbox version strcpy(strrchr(sourcedir, ':'), ";"); #endif xbp_chdir(sourcedir); // XXX, there is a ';' at the end if (type == 'F') { // run script from file FILE *fp = fopen(source, "r"); if (fp) { if (PyRun_SimpleFile(fp, source) == -1) { CLog::Log(LOGERROR, "Scriptresult: Error\n"); if (PyErr_Occurred()) PyErr_Print(); } else CLog::Log(LOGINFO, "Scriptresult: Succes\n"); fclose(fp); } else CLog::Log(LOGERROR, "%s not found!\n", source); } else { //run script if (PyRun_SimpleString(source) == -1) { CLog::Log(LOGERROR, "Scriptresult: Error\n"); if (PyErr_Occurred()) PyErr_Print(); } else CLog::Log(LOGINFO, "Scriptresult: Success\n"); } PyEval_ReleaseLock(); // when a script uses threads or timers - we have to wait for them to be over before we terminate the interpreter. // so first - release the lock and allow the threads to terminate. ::Sleep(500); PyEval_AcquireLock(); PyThreadState_Swap(m_threadState); // look waiting for the running threads to end PyRun_SimpleString( "import threading\n" "import sys\n" "try:\n" "\tthreads = list(threading.enumerate())\n" "except:\n" "\tprint 'error listing threads'\n" "while threading.activeCount() > 1:\n" "\tfor thread in threads:\n" "\t\tif thread <> threading.currentThread():\n" "\t\t\tprint 'waiting for thread - ' + thread.getName()\n" "\t\t\tthread.join(1000)\n" ); m_pExecuter->DeInitializeInterpreter(); Py_EndInterpreter(m_threadState); m_threadState = NULL; PyEval_ReleaseLock(); }
int PYTHON_WRAP(chdir)(const char *dirname) { return xbp_chdir(dirname); }
void XBPyThread::Process() { CLog::Log(LOGDEBUG,"Python thread: start processing"); int m_Py_file_input = Py_file_input; // get the global lock PyEval_AcquireLock(); PyThreadState* state = Py_NewInterpreter(); if (!state) { PyEval_ReleaseLock(); CLog::Log(LOGERROR,"Python thread: FAILED to get thread state!"); return; } // swap in my thread state PyThreadState_Swap(state); m_pExecuter->InitializeInterpreter(); CLog::Log(LOGDEBUG, "%s - The source file to load is %s", __FUNCTION__, m_source); // get path from script file name and add python path's // this is used for python so it will search modules from script path first CStdString scriptDir; CUtil::GetDirectory(_P(m_source), scriptDir); CUtil::RemoveSlashAtEnd(scriptDir); CStdString path = scriptDir; // add on any addon modules the user has installed ADDON::VECADDONS addons; ADDON::CAddonMgr::Get().GetAddons(ADDON::ADDON_SCRIPT_MODULE, addons); for (unsigned int i = 0; i < addons.size(); ++i) path += PY_PATH_SEP + _P(addons[i]->LibPath()); // and add on whatever our default path is path += PY_PATH_SEP; #if (defined USE_EXTERNAL_PYTHON) { // we want to use sys.path so it includes site-packages // if this fails, default to using Py_GetPath PyObject *sysMod(PyImport_ImportModule("sys")); // must call Py_DECREF when finished PyObject *sysModDict(PyModule_GetDict(sysMod)); // borrowed ref, no need to delete PyObject *pathObj(PyDict_GetItemString(sysModDict, "path")); // borrowed ref, no need to delete if( pathObj && PyList_Check(pathObj) ) { for( int i = 0; i < PyList_Size(pathObj); i++ ) { PyObject *e = PyList_GetItem(pathObj, i); // borrowed ref, no need to delete if( e && PyString_Check(e) ) { path += PyString_AsString(e); // returns internal data, don't delete or modify path += PY_PATH_SEP; } } } else { path += Py_GetPath(); } Py_DECREF(sysMod); // release ref to sysMod } #else path += Py_GetPath(); #endif // set current directory and python's path. if (m_argv != NULL) PySys_SetArgv(m_argc, m_argv); CLog::Log(LOGDEBUG, "%s - Setting the Python path to %s", __FUNCTION__, path.c_str()); PySys_SetPath((char *)path.c_str()); CLog::Log(LOGDEBUG, "%s - Entering source directory %s", __FUNCTION__, scriptDir.c_str()); PyObject* module = PyImport_AddModule((char*)"__main__"); PyObject* moduleDict = PyModule_GetDict(module); // when we are done initing we store thread state so we can be aborted PyThreadState_Swap(NULL); PyEval_ReleaseLock(); // we need to check if we was asked to abort before we had inited bool stopping = false; { CSingleLock lock(m_pExecuter->m_critSection); m_threadState = state; stopping = m_stopping; } PyEval_AcquireLock(); PyThreadState_Swap(state); xbp_chdir(scriptDir.c_str()); if (!stopping) { if (m_type == 'F') { // run script from file FILE *fp = fopen_utf8(_P(m_source).c_str(), "r"); if (fp) { PyObject *f = PyString_FromString(_P(m_source).c_str()); PyDict_SetItemString(moduleDict, "__file__", f); Py_DECREF(f); PyRun_File(fp, _P(m_source).c_str(), m_Py_file_input, moduleDict, moduleDict); fclose(fp); } else CLog::Log(LOGERROR, "%s not found!", m_source); } else { //run script PyRun_String(m_source, m_Py_file_input, moduleDict, moduleDict); } } if (!PyErr_Occurred()) CLog::Log(LOGINFO, "Scriptresult: Success"); else if (PyErr_ExceptionMatches(PyExc_SystemExit)) CLog::Log(LOGINFO, "Scriptresult: Aborted"); else { PyObject* exc_type; PyObject* exc_value; PyObject* exc_traceback; PyObject* pystring; pystring = NULL; PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); if (exc_type == 0 && exc_value == 0 && exc_traceback == 0) { CLog::Log(LOGINFO, "Strange: No Python exception occured"); } else { if (exc_type != NULL && (pystring = PyObject_Str(exc_type)) != NULL && (PyString_Check(pystring))) { PyObject *tracebackModule; CLog::Log(LOGINFO, "-->Python script returned the following error<--"); CLog::Log(LOGERROR, "Error Type: %s", PyString_AsString(PyObject_Str(exc_type))); if (PyObject_Str(exc_value)) CLog::Log(LOGERROR, "Error Contents: %s", PyString_AsString(PyObject_Str(exc_value))); tracebackModule = PyImport_ImportModule((char*)"traceback"); if (tracebackModule != NULL) { PyObject *tbList, *emptyString, *strRetval; tbList = PyObject_CallMethod(tracebackModule, (char*)"format_exception", (char*)"OOO", exc_type, exc_value == NULL ? Py_None : exc_value, exc_traceback == NULL ? Py_None : exc_traceback); emptyString = PyString_FromString(""); strRetval = PyObject_CallMethod(emptyString, (char*)"join", (char*)"O", tbList); CLog::Log(LOGERROR, "%s", PyString_AsString(strRetval)); Py_DECREF(tbList); Py_DECREF(emptyString); Py_DECREF(strRetval); Py_DECREF(tracebackModule); } CLog::Log(LOGINFO, "-->End of Python script error report<--"); } else { pystring = NULL; CLog::Log(LOGINFO, "<unknown exception type>"); } CGUIDialogKaiToast *pDlgToast = (CGUIDialogKaiToast*)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST); if (pDlgToast) { CStdString desc; CStdString path; CStdString script; CUtil::Split(m_source, path, script); if (script.Equals("default.py")) { CStdString path2; CUtil::RemoveSlashAtEnd(path); CUtil::Split(path, path2, script); } desc.Format(g_localizeStrings.Get(2100), script); pDlgToast->QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(257), desc); } } Py_XDECREF(exc_type); Py_XDECREF(exc_value); // caller owns all 3 Py_XDECREF(exc_traceback); // already NULL'd out Py_XDECREF(pystring); } PyObject *m = PyImport_AddModule((char*)"xbmc"); if(!m || PyObject_SetAttrString(m, (char*)"abortRequested", PyBool_FromLong(1))) CLog::Log(LOGERROR, "Scriptresult: failed to set abortRequested"); // make sure all sub threads have finished for(PyThreadState* s = state->interp->tstate_head, *old = NULL; s;) { if(s == state) { s = s->next; continue; } if(old != s) { CLog::Log(LOGINFO, "Scriptresult: Waiting on thread %"PRIu64, (uint64_t)s->thread_id); old = s; } Py_BEGIN_ALLOW_THREADS Sleep(100); Py_END_ALLOW_THREADS s = state->interp->tstate_head; } // pending calls must be cleared out PyXBMC_ClearPendingCalls(state); PyThreadState_Swap(NULL); PyEval_ReleaseLock(); { CSingleLock lock(m_pExecuter->m_critSection); m_threadState = NULL; } PyEval_AcquireLock(); PyThreadState_Swap(state); m_pExecuter->DeInitializeInterpreter(); Py_EndInterpreter(state); PyThreadState_Swap(NULL); PyEval_ReleaseLock(); }