Esempio n. 1
0
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();
}
Esempio n. 2
0
int PYTHON_WRAP(chdir)(const char *dirname)
{
  return xbp_chdir(dirname);
}
Esempio n. 3
0
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();
}