<html>
<head>
<base href="https://wiki.asterisk.org/wiki">
<link rel="stylesheet" href="/wiki/s/2041/1/7/_/styles/combined.css?spaceKey=TOP&forWysiwyg=true" type="text/css">
</head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
<h2><a href="https://wiki.asterisk.org/wiki/display/TOP/SIP+Threading+Model">SIP Threading Model</a></h2>
<h4>Page <b>added</b> by <a href="https://wiki.asterisk.org/wiki/display/~mmichelson">Mark Michelson</a>
</h4>
<br/>
<div class="notificationGreySide">
<div class='panelMacro'><table class='warningMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/forbidden.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td><b>Achtung!</b><br />This is a work in progress.</td></tr></table></div>
<h1><a name="SIPThreadingModel-Thecurrentmodel"></a>The current model</h1>
<p>The current (Feb 17) model is flawed. The SIP session gateway can receive stimuli either from PJSIP or from Ice. </p>
<p>The PJSIP manager creates a single thread that constantly services queued events (e.g. incoming SIP messages). The biggest issue is that the time taken to process certain types of incoming SIP messages, like INVITEs, can take an inordinately long time. Specifically, remote procedure calls in the INVITE-handling code cause the thread to wait a long time. The waiting period is long enough that the queue of unhandled messages may grow faster than our code can handle them.</p>
<p>In addition, the Ice-induced operations run in multiple threads, not in the same thread that the PJSIP manager uses for presenting incoming messages. This means that there is contention for resources common to the Ice threads and the PJSIP manager thread.</p>
<p>h1 Potential Methods of improvement</p>
<h3><a name="SIPThreadingModel-MoreAMI"></a>More AMI</h3>
<p>One potential fix for the problem is to use AMI for all RPCs in the code that handles incoming messages. Using AMI means that the thread is not stuck waiting, thus the growing message queue may be serviced. AMI is already used in some places in the SIP code, especially for operations that are known to potentially block for a long time. AMI has some disadvantages though:</p>
<ul>
        <li>Using AMI can decrease the readability of the code, especially for operations that make multiple RPCs.</li>
        <li>Object lifetime can be a pitfall.</li>
        <li>Adding AMI does nothing to alleviate any concurrency issues. If anything, it increases the number of threads potentially vying for the same resources.</li>
</ul>
<h3><a name="SIPThreadingModel-ListenforSIPmessagesinmultiplethreads."></a>Listen for SIP messages in multiple threads.</h3>
<p>PJSIP's event-handling functions are thread safe, so they may be called from multiple threads at once. This means there can be more concurrent threads handling incoming SIP messages. If one thread is blocking, there may be another thread ready to handle the message. The problem with this approach is that there is no application-level logic behind which thread handles which message. The result is that like with AMI, this actually results in more concurrent threads attempting to access the same resources.</p>
<h3><a name="SIPThreadingModel-Funneltasksintoathreadpool"></a>Funnel tasks into a thread pool</h3>
<p>Using a thread pool would have similar advantages to using multiple threads for handling PJSIP events. That is, if a single thread is blocked, there may be other threads currently available to handle the task. What's different though is that since we will be delegating the work ourselves, we can distribute work based on application-level concepts. As an example, a single thread can be responsible for handling all tasks related to a specific session. This can eliminate some of the contention between threads. In addition, tasks that originate from PJSIP and tasks that originate from Ice can use the same thread pool, once again leading to less contention between threads. </p>
<p>The issue about implementing a thread pool is that currently there is no thread pool implementation in Asterisk SCF. Ice and Boost do not contain thread pool implementations that Asterisk SCF could use either. There is a thread pool proposal <a href="/wiki/display/TOP/Thread+Pools" title="Thread Pools">here</a>, but it has yet to be finalized. Use of a thread pool also is complicated because there are lots of ways one could potentially be used.</p>
<h3><a name="SIPThreadingModel-Conclusions"></a>Conclusions</h3>
<p>To maximize efficiency of the SIP component, it seems that the use of a thread pool to place tasks into logical areas is a good start to making the SIP component run more smoothly. As new RPCs are added to SIP components, a decision can be made regarding the feasibility of making the operation use AMI or not.</p>
<h1><a name="SIPThreadingModel-Threadpooloperation"></a>Thread pool operation</h1>
<h3><a name="SIPThreadingModel-AnoverviewofanincomingPJSIPmessage"></a>An overview of an incoming PJSIP message</h3>
<p>A message starts out within the PJSIP endpoint. The PJSIP endpoint contains a list of all registered PJSIP modules. The endpoint iterates through the list of modules, passing the message to each one until a module reports that it has handled the message. What's important to note are the major locks that are encountered during this process.</p>
<p>Assume that a message arrives that belongs to an in-dialog transaction. Here is a breakdown of the steps:</p>
<ol>
        <li>Endpoint receives the message, passes the message to the transaction layer</li>
        <li>Transaction layer locks the <b>transaction layer lock</b> to search for a matching transaction.</li>
        <li>Once the transaction is found, the <b>transaction layer lock</b> is released, and the <b>transaction lock</b> is acquired.</li>
        <li>The transaction layer passes the message up to the user agent layer.</li>
        <li>The user agent layer locks the <b>user agent layer lock</b> to search for a matching dialog.</li>
        <li>Once the dialog is found, the "user agent layer lock* is released, and the <b>dialog lock</b> is acquired.</li>
        <li>The dialog layer then passes the message to the next layer up. In the case of media sessions, this is the INVITE session module of PJSIP, followed then by our PJSipSessionModule. In other cases, there may not be another layer between the user agent layer and us. The important thing to note is that there are no additional locks acquired during this time since data at this point is protected by the <b>dialog lock</b>.</li>
</ol>
<p>This specific sequence was chosen because it encounters the most locks and illustrates where in the chain of calls the specific locks are acquired.</p>
<h3><a name="SIPThreadingModel-AnoverviewofanoutgoingPJSIPmessage"></a>An overview of an outgoing PJSIP message</h3>
<p>Well...it's the opposite of an incoming one. Like with the incoming message example, we'll show an outgoing message that belongs both to an existing dialog and transaction.</p>
<ol>
        <li>Our application gives the signal to send a message. It will either use a function provided by a layer between us and the dialog layer (like the INVITE session module) or a function provided by the user agent layer.</li>
        <li>Once within the user agent layer, the <b>dialog lock</b> is acquired, and the message is passed down to the transaction layer</li>
        <li>Once within the transaction layer, the <b>transaction lock</b> is acquired, and the message is passed down to the transport layer</li>
</ol>
<p>Beyond this point is unimportant to us. Again, take note of the locks that are acquired in this sequence.</p>
</div>
<div id="commentsSection" class="wiki-content pageSection">
<div style="float: right;">
<a href="https://wiki.asterisk.org/wiki/users/viewnotifications.action" class="grey">Change Notification Preferences</a>
</div>
<a href="https://wiki.asterisk.org/wiki/display/TOP/SIP+Threading+Model">View Online</a>
|
<a href="https://wiki.asterisk.org/wiki/display/TOP/SIP+Threading+Model?showComments=true&showCommentArea=true#addcomment">Add Comment</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>