DUM Threading

From reSIProcate
Jump to navigation Jump to search

The Dialog Usage Manager (DUM) supports a few threading options - which are summarized below.

NOTE: There is no threading protection in the DUM methods themseleves. If your application itself is multi-threaded you MUST provide your own protection (mutexing) if you plan on calling dum->process and/or other DUM API's from different threads. This can also be accomplished by queueing DumCommands to the dum process loop from your application threads.


Single Threaded[edit]

Your application, DUM, the stack and transports all run in the same thread. This is how the BasicCall sample works. A process loop is required:

  while (!dumShutDown)
  {
     FdSet fdset;
     stack->buildFdSet(fdset);
     int err = fdset.selectMilliSeconds(stack->getTimeTillNextProcessMS());
     assert ( err != -1 );
     stack->process(fdset);
     while(dumUas->process());
  }


Separate Stack Thread[edit]

Your application and DUM run in the same thread, the stack and transports run in another thread. To run in this mode you must use or emulate the functionality in StackThread.cxx or InterruptableStackThread.cxx to startup and run the stack thread. Then you must periodically call the dum->process() method from your application so that DUM can peform its processing. The important thing to remember here, is that DUM is not part of the core stack, it sits on top.


Separate DUM and/or Stack Threads[edit]

A class called DumThread is in the works. This will allow you to run all of resiprocate in it's own thread (or threads) and your application in another thread. You can use StackThread (or InterruptableStackThread) and DumThread together to have the stack and dum run in seperate threads. In this scenario your application runs in it's own seperate thread.

NOTE: There is no threading protection in the DUM methods themseleves. If your application itself is multi-threaded you MUST provide your own protection (mutexing) if you plan on calling dum->process and/or other DUM API's from different threads. This can also be accomplished by queueing DumCommands to the dum process loop from your application threads.

A good sample of use of both StackThread and DumThread can be found in the repro proxy server - look at repro/repro.cxx

StackThread vs InterruptableStackThread[edit]

If your application has any UAC capabilities (ie. ability to emit new requests), then you should consider using InterruptableStackThread instead of StackThread. This version of the stack thread supports the ability to interrupt the fd process loop immediately when an application (TU/DUM) requests a message to be sent. It accomplishes this via a pseudo fd that is manually signalled when a message is queued to the SipStack fifo. In order to use InterruptableStackThread you must pass an instance of SelectInterruptor to the SipStack constructor as an AsyncProcessHandler. This same instance must also be passed to the InterruptableStackThread consturctor. For example:

class UserAgent
{
public:
   UserAgent() : 
#if defined(USE_SSL)
      mSecurity(new resip::Security),
#else
      mSecurity(0),
#endif
      mStack(mSecurity, resip::DnsStub::EmptyNameserverList, &mSelectInterruptor),
      mDum(mStack),
      mStackThread(mStack, mSelectInterruptor)
{ }

void startStackTread()
{
   mStackThread.run(); 
}

void shutdownStackThread()
{
   mStackThread.shutdown();
   mStackThread.join();
}

...

private:
  resip::Security* mSecurity;
  resip::SelectInterruptor mSelectInterruptor;
  resip::SipStack mStack;
  resip::DialogUsageManager mDum;
  resip::InterruptableStackThread mStackThread;
}


Tips on Making Thread Safe Calls when using DUM[edit]

There is no threading protection in the DUM methods themseleves. If your application itself is multi-threaded you MUST provide your own protection (mutexing) if you plan on calling dum->process and/or other DUM API's from different threads. This can also be accomplished by queueing DumCommands to the dum process loop from your application threads.

Mutexing Solution[edit]

To ensure all DUM API calls are made from the same thread, you can mutex the dum process() calls and any other API calls that you call from seperate threads. If you use this approach you cannot make use of the supplied DumThread class without modification.

Queueing DUM Commands Solution[edit]

Some DUM classes, notedly InviteSession, provide methods to post DumCommands to the dum process loop (eg. provideOfferCommand). Your application can use them to call DUM methods from another thread. Make sure though, that no other thread unsafe method is called (eg. makeXXXX methods are not thread safe). If you need to call some of these methods, you must create your own commands.

Sample code - for ending a DialogSet from another thread:

class AppDialogSetEndCommand : public DumCommand
{
public:
   AppDialogSetEndCommand(AppDialogSetHandle h) : mHandle(h) {}
   void executeCommand()
   { 
     if(mHandle.isValid()) 
     { 
        mHandle->end();
     }
   }
   Message* clone() const { assert(false); return 0 }
   std::ostream& encode(std::ostream& strm) const { return strm; }
   std::ostream& encodeBrief(std::ostream& strm) const { return strm; }
private:
     AppDialogSetHandle mHandle;
};
AppDialogSetEndCommand* cmd = new AppDialogSetEndCommand(myAppDialogSet->getHandle);
dum->post(cmd);  // Note:  Ownership passed to dum
Note:  You can also use stack->postMS(*cmd, timeInMs, dum) in order to have the command
       posted to dum at a later time.  In this case the stack will clone the message so
       it is safe to delete after calling postMS.