[hydra-commits] ken.hunt: branch techdemo/ken.hunt/embeddedPythonTest r630 - in /techdemo/tea...

SVN commits to the Hydra project hydra-commits at lists.digium.com
Thu May 20 14:31:31 CDT 2010


Author: ken.hunt
Date: Thu May 20 14:31:30 2010
New Revision: 630

URL: https://origsvn.digium.com/svn-view/hydra?view=rev&rev=630
Log:
thread testing

Added:
    techdemo/team/ken.hunt/embeddedPythonTest/threadtest/
    techdemo/team/ken.hunt/embeddedPythonTest/threadtest/CMakeLists.txt   (with props)
    techdemo/team/ken.hunt/embeddedPythonTest/threadtest/iworkqueue.h   (with props)
    techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.cpp   (with props)
    techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.h   (with props)
    techdemo/team/ken.hunt/embeddedPythonTest/threadtest/threadtest.cpp   (with props)
Modified:
    techdemo/team/ken.hunt/embeddedPythonTest/CMakeLists.txt
    techdemo/team/ken.hunt/embeddedPythonTest/bin/install_release.bat
    techdemo/team/ken.hunt/embeddedPythonTest/source/Server.cpp

Modified: techdemo/team/ken.hunt/embeddedPythonTest/CMakeLists.txt
URL: https://origsvn.digium.com/svn-view/hydra/techdemo/team/ken.hunt/embeddedPythonTest/CMakeLists.txt?view=diff&rev=630&r1=629&r2=630
==============================================================================
--- techdemo/team/ken.hunt/embeddedPythonTest/CMakeLists.txt (original)
+++ techdemo/team/ken.hunt/embeddedPythonTest/CMakeLists.txt Thu May 20 14:31:30 2010
@@ -5,4 +5,5 @@
 hydra_project(embedPythonTest 3.4 CXX CSharp)
 
 add_subdirectory(slice)
-add_subdirectory(source)
+add_subdirectory(source)
+add_subdirectory(threadtest)

Modified: techdemo/team/ken.hunt/embeddedPythonTest/bin/install_release.bat
URL: https://origsvn.digium.com/svn-view/hydra/techdemo/team/ken.hunt/embeddedPythonTest/bin/install_release.bat?view=diff&rev=630&r1=629&r2=630
==============================================================================
--- techdemo/team/ken.hunt/embeddedPythonTest/bin/install_release.bat (original)
+++ techdemo/team/ken.hunt/embeddedPythonTest/bin/install_release.bat Thu May 20 14:31:30 2010
@@ -9,3 +9,5 @@
 copy /Y /B ..\build\slice\Media\Release\MediaSinkIf_CXX.dll
 copy /Y /B ..\build\slice\Media\Release\MediaTranslationIf_CXX.dll
 
+copy /Y /B ..\build\threadtest\Release\threadtest.exe
+

Modified: techdemo/team/ken.hunt/embeddedPythonTest/source/Server.cpp
URL: https://origsvn.digium.com/svn-view/hydra/techdemo/team/ken.hunt/embeddedPythonTest/source/Server.cpp?view=diff&rev=630&r1=629&r2=630
==============================================================================
--- techdemo/team/ken.hunt/embeddedPythonTest/source/Server.cpp (original)
+++ techdemo/team/ken.hunt/embeddedPythonTest/source/Server.cpp Thu May 20 14:31:30 2010
@@ -8,8 +8,6 @@
 #include "RoutingServiceIf.h"
 
 using namespace std;
-using namespace Hydra;
-
 
 class LookupServiceImpl : public Hydra::Routing::LookupService 
 {

Added: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/CMakeLists.txt
URL: https://origsvn.digium.com/svn-view/hydra/techdemo/team/ken.hunt/embeddedPythonTest/threadtest/CMakeLists.txt?view=auto&rev=630
==============================================================================
--- techdemo/team/ken.hunt/embeddedPythonTest/threadtest/CMakeLists.txt (added)
+++ techdemo/team/ken.hunt/embeddedPythonTest/threadtest/CMakeLists.txt Thu May 20 14:31:30 2010
@@ -1,0 +1,12 @@
+
+hydra_component_init(threadtest CXX)
+INCLUDE(findPythonInterp)
+INCLUDE(findPythonLibs)
+get_filename_component(PY_LOC ${PYTHON_LIBRARIES} PATH)
+LINK_DIRECTORIES(${PY_LOC})
+include_directories(${PYTHON_INCLUDE_DIRS})
+hydra_component_add_file(threadtest  threadtest.cpp)
+hydra_component_add_file(threadtest  pyworkqueue.cpp)
+hydra_component_add_boost_libraries(threadtest core)
+hydra_component_build_standalone(threadtest)
+hydra_component_install(threadtest)

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/CMakeLists.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/CMakeLists.txt
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/CMakeLists.txt
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/iworkqueue.h
URL: https://origsvn.digium.com/svn-view/hydra/techdemo/team/ken.hunt/embeddedPythonTest/threadtest/iworkqueue.h?view=auto&rev=630
==============================================================================
--- techdemo/team/ken.hunt/embeddedPythonTest/threadtest/iworkqueue.h (added)
+++ techdemo/team/ken.hunt/embeddedPythonTest/threadtest/iworkqueue.h Thu May 20 14:31:30 2010
@@ -1,0 +1,33 @@
+#pragma once
+#ifndef _IWORKQUEUE_H
+#define _IWORKQUEUE_H
+
+#include "boost/shared_ptr.hpp"
+
+namespace hydra
+{
+class IWorkQueue
+{
+public:
+
+   class IWork
+   {
+   public:
+      virtual void DoWork() = 0;
+   };
+ 
+   typedef boost::shared_ptr<IWork> IWorkPtr;
+
+   virtual void Enqueue(IWorkPtr w) = 0;
+   virtual void Terminate() = 0;
+   virtual void Join() = 0;
+
+protected:
+   IWorkQueue() {};  // Hide the constructor for interface
+};
+typedef IWorkQueue::IWorkPtr IWorkPtr;
+
+};
+
+#endif
+

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/iworkqueue.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/iworkqueue.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/iworkqueue.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.cpp
URL: https://origsvn.digium.com/svn-view/hydra/techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.cpp?view=auto&rev=630
==============================================================================
--- techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.cpp (added)
+++ techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.cpp Thu May 20 14:31:30 2010
@@ -1,0 +1,242 @@
+/**
+ * A simple Work Queue implementation. On construction, starts an internal thread. 
+ * Work can be enqueued via the thread-safe Enqueue method. All work must implement the IWork interface.
+ */
+#include <iostream>
+#include <boost/shared_ptr.hpp>
+#include <boost/bind.hpp>
+#include <Python.h>
+#include <pystate.h>
+
+#include "pyworkqueue.h"
+
+using namespace hydra;
+using namespace boost;
+
+namespace hydra
+{
+class PyWorkQueuePriv
+{
+public:
+	PyWorkQueuePriv(std::string id, bool paused) 
+	     : mQid(id),
+		    mInitialized(false), 
+          mPyInitialized(false),
+	       mPaused(paused), 
+		    mFinished(false), 
+		    mThread(boost::bind(&PyWorkQueuePriv::Execute, this))
+  {
+  }
+
+  ~PyWorkQueuePriv()
+  {
+      // Clear my thread state
+      PyEval_AcquireLock();
+      PyThreadState_Swap(NULL);
+      PyThreadState_Clear(mMyThreadState);
+      PyThreadState_Delete(mMyThreadState);
+      PyEval_ReleaseLock();
+  }
+
+  IWorkPtr Dequeue();
+  IWorkPtr WaitAndDequeue();
+  void Execute();
+
+  PyThreadState *mMainThreadState;
+  PyThreadState * mMyThreadState;
+  std::string mQid;
+  bool mInitialized;
+  bool mPyInitialized;
+  bool mFinished;
+  bool mPaused;
+  std::list<IWorkPtr> mQueue;
+  boost::thread mThread;
+  boost::mutex mQueueMutex;
+  boost::condition mEmptyQueueCondition;
+  boost::mutex mPauseMutex;
+  boost::condition mPauseCondition;
+};
+}
+
+PyWorkQueue::PyWorkQueue(std::string qid, PyThreadState *mainThreadState, bool runByDefault) : mImpl(new PyWorkQueuePriv(qid, !runByDefault))
+{
+  mImpl->mInitialized = true; 
+  mImpl->mMainThreadState = mainThreadState;
+}
+
+PyWorkQueue::~PyWorkQueue()
+{
+    Terminate();
+
+	// Wait for worker thread to shut down. 
+	mImpl->mThread.join(); // If you don't do this, then the mImpl is trashed and Execute has bad "this" ptr on other thread. 
+}
+
+bool PyWorkQueue::IsRunning() 
+{ 
+	return (mImpl->mInitialized && !mImpl->mPaused && !mImpl->mFinished);
+}
+
+/**
+ * Pause the WorkQueue's thread.
+ */
+void PyWorkQueue::Pause()
+{
+   boost::mutex::scoped_lock lock(mImpl->mPauseMutex);
+   mImpl->mPaused = true;
+}
+
+
+/**
+ * Resume from a Paused state. 
+ */
+void PyWorkQueue::Resume()
+{
+   boost::mutex::scoped_lock lock(mImpl->mPauseMutex);
+   mImpl->mPaused = false;
+   mImpl->mPauseCondition.notify_all();
+}
+
+/** 
+ * Stops this thread from executing. 
+ */
+void PyWorkQueue::Terminate()
+{
+  mImpl->mFinished = true;
+  mImpl->mPaused = false;
+  mImpl->mPauseCondition.notify_all();      // In case the thread was waiting on the PauseCondition.
+  mImpl->mEmptyQueueCondition.notify_all(); // In case the thread was waiting on an EmptyQueueCondition
+}
+
+/**
+ * A convenience method to determine if there is any pending work on the queue. 
+ */
+bool PyWorkQueue::WorkPending()
+{
+   return !mImpl->mQueue.empty();
+}
+
+/**
+ * Allows other thread to join to this thread. The caller needs to 
+ * call this object's Terminate method, or the join will block
+ * indefinitely.
+ */
+void PyWorkQueue::Join()
+{
+   mImpl->mThread.join();
+}
+
+/**
+ * Enqueue an item of work for processing on this queue's thread. 
+ */
+void PyWorkQueue::Enqueue(IWorkPtr w)
+{
+   boost::mutex::scoped_lock lock(mImpl->mQueueMutex);
+   bool wasEmpty = mImpl->mQueue.empty();
+   mImpl->mQueue.push_back(w);
+   int size = mImpl->mQueue.size();
+   lock.unlock();
+ 
+   if (wasEmpty)
+   { 
+      mImpl->mEmptyQueueCondition.notify_all();
+   }
+}
+
+/**
+ * This is a private no-op implementation of a work item. Returned from WaitAndDequeue 
+ * if the program is Terminated while waiting on the EmptyQueueCondition.  
+ */
+class NO_WORK_CLASS : public IWorkQueue::IWork
+{
+public:
+    NO_WORK_CLASS() {};
+    void DoWork() {}   // Do nothing
+};
+static shared_ptr<IWorkQueue::IWork> NO_WORK_PTR(new NO_WORK_CLASS());
+
+/**
+ * This method returns the next work from the queue. If no work available,
+ * this method waits on the EmptyQueueCondition. 
+ */
+IWorkPtr PyWorkQueuePriv::WaitAndDequeue()
+{
+    boost::mutex::scoped_lock lock(mQueueMutex);
+
+    int size = mQueue.size(); // debugging
+
+    while (mQueue.empty())
+    {
+		if (mFinished)
+        {
+           return NO_WORK_PTR;
+        }
+
+        mEmptyQueueCondition.wait(lock);
+    }
+    
+    size = mQueue.size(); // debugging
+
+    shared_ptr<IWorkQueue::IWork> work = mQueue.front();
+    mQueue.pop_front();
+
+    return work;
+}
+
+/**
+ * This is the thread's event loop. The thread terminates when this method returns.
+ */
+void PyWorkQueuePriv::Execute()
+{
+   while (!mInitialized)
+   {
+      // The thread can start before the constructor has finished initializing the object.
+	  // Can lead to strange behavior. 
+      continue;
+   }
+
+   if (!mPyInitialized)
+   {
+      mPyInitialized = true;
+
+      // get the global lock
+      PyEval_AcquireLock();
+
+      // get a reference to the PyInterpreterState
+      PyInterpreterState * mainInterpreterState = mMainThreadState->interp;
+
+      // create a thread state object for this thread
+      mMyThreadState = PyThreadState_New(mainInterpreterState);
+
+      // free the lock
+      PyEval_ReleaseLock();
+   }
+
+   while (!mFinished)
+   {
+      { // scope the lock
+         boost::mutex::scoped_lock lock(mPauseMutex);
+         while(mPaused)
+         {
+            mPauseCondition.wait(lock);
+         }
+
+         if (mFinished) // In case Terminate was called while in PauseCondition
+            break;
+      }
+
+      shared_ptr<IWorkQueue::IWork> work  = WaitAndDequeue();
+
+     // swap in my thread state
+      PyEval_AcquireLock();
+      PyThreadState_Swap(mMyThreadState);
+
+      work->DoWork();
+
+      // clear the thread state
+      PyThreadState_Swap(NULL);
+      PyEval_ReleaseLock();
+   }
+
+}
+

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.h
URL: https://origsvn.digium.com/svn-view/hydra/techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.h?view=auto&rev=630
==============================================================================
--- techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.h (added)
+++ techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.h Thu May 20 14:31:30 2010
@@ -1,0 +1,40 @@
+#pragma once
+#ifndef _WORKQUEUE_H
+#define _WORKQUEUE_H
+
+#include <list>
+#include <boost/thread.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/shared_ptr.hpp>
+#include <Python.h>
+
+#include "iworkqueue.h"
+
+namespace hydra
+{
+class PyWorkQueuePriv;
+
+class PyWorkQueue : public IWorkQueue,  boost::noncopyable
+{
+public:
+  PyWorkQueue(std::string id, PyThreadState *mainThreadState, bool runByDefault=false);
+  ~PyWorkQueue();
+
+  virtual void Enqueue(IWorkPtr w);
+  virtual void Terminate();
+  virtual void Join();
+
+  // This implementation adds the concept of Pausing to the generic IWorkQueue. 
+  bool IsRunning();
+  bool WorkPending();
+  void Pause();
+  void Resume();
+
+private:
+  boost::shared_ptr<PyWorkQueuePriv> mImpl;
+};
+
+};
+
+#endif
+

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/pyworkqueue.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/threadtest.cpp
URL: https://origsvn.digium.com/svn-view/hydra/techdemo/team/ken.hunt/embeddedPythonTest/threadtest/threadtest.cpp?view=auto&rev=630
==============================================================================
--- techdemo/team/ken.hunt/embeddedPythonTest/threadtest/threadtest.cpp (added)
+++ techdemo/team/ken.hunt/embeddedPythonTest/threadtest/threadtest.cpp Thu May 20 14:31:30 2010
@@ -1,0 +1,160 @@
+#include <iostream>
+#include <string>
+#include <boost/cast.hpp>
+#include <boost/shared_ptr.hpp>
+#include <stdio.h>
+#include "pyworkqueue.h"
+
+#ifndef __cplusplus
+#define __cplusplus 1
+#endif
+
+#include <Python.h>
+
+using namespace hydra;
+
+/**
+ * OS Portable sleep util function.
+ */
+void sleep(int secs)
+{
+	boost::posix_time::seconds workTime(secs);  
+    boost::this_thread::sleep(workTime); 
+}
+
+class TestWork : public hydra::IWorkQueue::IWork
+{
+public:
+    TestWork(std::string id, int val) : mTestVal(val), mId(id) {}
+    ~TestWork() 
+    {
+       std::cout << "TestWork::~TestWork: Deleting " << mId << std::endl;
+    }
+
+    void DoWork() 
+    {   
+         std::cout << "Looking up " << mTestVal << std::endl;
+
+         PyObject *pName, *pModule;
+
+        // Make sure  pythonScripts folder is in  PYTHONPATH
+         pName = PyString_FromString("lookup");
+         pModule = PyImport_Import(pName);
+         Py_DECREF(pName);
+
+         if (pModule != 0)
+         {
+            PyObject *pFunc = PyObject_GetAttrString(pModule, "lookup");
+            if (pFunc != 0 && PyCallable_Check(pFunc))
+            {
+               PyObject *pArgs = PyTuple_New(1);
+               PyObject *pValue = PyInt_FromLong(mTestVal);
+               if (!pValue)
+               {
+                  Py_DECREF(pArgs);
+                  Py_DECREF(pFunc);
+                  Py_DECREF(pModule);
+                  std::cout << "NO VALUE FOUND. " << std::endl;
+                  return ;
+               }
+               PyTuple_SetItem(pArgs, 0, pValue); // pValue ref given up here.
+
+               pValue = PyObject_CallObject(pFunc, pArgs);
+               Py_DECREF(pArgs);
+
+               if (pValue != 0)
+               {
+                  std::cout << "Found: " <<  PyInt_AsLong(pValue) << std::endl;
+                  Py_DECREF(pValue);
+               }
+               else
+               {
+                  PyErr_Print();
+               }
+             
+               Py_DECREF(pFunc);
+               Py_DECREF(pModule);
+            }
+            else if (PyErr_Occurred())
+            {
+               PyErr_Print();
+            }
+         }
+         else
+         {
+            PyErr_Print();
+         }
+    }
+
+private:
+   int mTestVal;
+   std::string mId;
+};
+
+int main(int argc, char* argv[])
+{
+   // Init Python
+   Py_Initialize();
+
+   // init thread support.
+   PyEval_InitThreads();
+
+   PyThreadState * mainThreadState = NULL;
+   mainThreadState = PyThreadState_Get();
+   PyEval_ReleaseLock();
+   
+   PyWorkQueue wqueue1("wq1", mainThreadState, true);
+   PyWorkQueue wqueue2("wq2", mainThreadState, true);
+
+   boost::shared_ptr<IWorkQueue::IWork> wq1_w1(new TestWork("WorkOnQueue1", 110));
+   boost::shared_ptr<IWorkQueue::IWork> wq1_w2(new TestWork("WorkOnQueue1", 120));
+   boost::shared_ptr<IWorkQueue::IWork> wq1_w3(new TestWork("WorkOnQueue1", 130));
+   boost::shared_ptr<IWorkQueue::IWork> wq1_w4(new TestWork("WorkOnQueue1", 140));
+   boost::shared_ptr<IWorkQueue::IWork> wq1_w5(new TestWork("WorkOnQueue1", 150));
+   boost::shared_ptr<IWorkQueue::IWork> wq1_w6(new TestWork("WorkOnQueue1", 160));
+   boost::shared_ptr<IWorkQueue::IWork> wq1_w7(new TestWork("WorkOnQueue1", 170));
+   boost::shared_ptr<IWorkQueue::IWork> wq1_w8(new TestWork("WorkOnQueue1", 180));
+
+   boost::shared_ptr<IWorkQueue::IWork> wq2_w1(new TestWork("WorkOnQueue2", 210));
+   boost::shared_ptr<IWorkQueue::IWork> wq2_w2(new TestWork("WorkOnQueue2", 220));
+   boost::shared_ptr<IWorkQueue::IWork> wq2_w3(new TestWork("WorkOnQueue2", 230));
+   boost::shared_ptr<IWorkQueue::IWork> wq2_w4(new TestWork("WorkOnQueue2", 240));
+   boost::shared_ptr<IWorkQueue::IWork> wq2_w5(new TestWork("WorkOnQueue2", 250));
+   boost::shared_ptr<IWorkQueue::IWork> wq2_w6(new TestWork("WorkOnQueue2", 260));
+   boost::shared_ptr<IWorkQueue::IWork> wq2_w7(new TestWork("WorkOnQueue2", 270));
+   boost::shared_ptr<IWorkQueue::IWork> wq2_w8(new TestWork("WorkOnQueue2", 280));
+
+   wqueue1.Enqueue(wq1_w1);
+   wqueue2.Enqueue(wq2_w1);
+
+   wqueue1.Enqueue(wq1_w2);
+   wqueue2.Enqueue(wq2_w2);
+
+   wqueue1.Enqueue(wq1_w3);
+   wqueue2.Enqueue(wq2_w3);
+
+   wqueue1.Enqueue(wq1_w4);
+   wqueue2.Enqueue(wq2_w4);
+
+   wqueue1.Enqueue(wq1_w5);
+   wqueue2.Enqueue(wq2_w5);
+
+   wqueue1.Enqueue(wq1_w6);
+   wqueue2.Enqueue(wq2_w6);
+
+   wqueue1.Enqueue(wq1_w7);
+   wqueue2.Enqueue(wq2_w7);
+
+   wqueue1.Enqueue(wq1_w8);
+   wqueue2.Enqueue(wq2_w8);
+
+   sleep(5);
+
+   wqueue1.Terminate();
+   wqueue2.Terminate();
+   wqueue1.Join();
+   wqueue2.Join();
+
+   PyEval_AcquireLock();
+   Py_Finalize();
+}

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/threadtest.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/threadtest.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: techdemo/team/ken.hunt/embeddedPythonTest/threadtest/threadtest.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the asterisk-scf-commits mailing list