Ignore:
Timestamp:
Feb 13, 2008 3:17:28 PM (15 years ago)
Author:
bennylp
Message:

Ticket #474: option in ioqueue to control concurrency (to allow/disallow simultaneous/multiple callback calls)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib/include/pj/ioqueue.h

    r1748 r1789  
    102102 * \section pj_ioqueue_concurrency_sec Concurrency Rules 
    103103 * 
    104  * The items below describe rules that must be obeyed when using the I/O  
    105  * queue, with regard to concurrency: 
    106  *  - simultaneous operations (by different threads) to different key is safe. 
    107  *  - simultaneous operations to the same key is also safe, except 
    108  *    <b>unregistration</b>, which is described below. 
    109  *  - <b>care must be taken when unregistering a key</b> from the 
     104 * The ioqueue has been fine tuned to allow multiple threads to poll the 
     105 * handles simultaneously, to maximize scalability when the application is 
     106 * running on multiprocessor systems. When more than one threads are polling 
     107 * the ioqueue and there are more than one handles are signaled, more than 
     108 * one threads will execute the callback simultaneously to serve the events. 
     109 * These parallel executions are completely safe when the events happen for 
     110 * two different handles. 
     111 * 
     112 * However, with multithreading, care must be taken when multiple events  
     113 * happen on the same handle, or when event is happening on a handle (and  
     114 * the callback is being executed) and application is performing  
     115 * unregistration to the handle at the same time. 
     116 * 
     117 * The treatments of above scenario differ according to the concurrency 
     118 * setting that are applied to the handle. 
     119 * 
     120 * \subsection pj_ioq_concur_set Concurrency Settings for Handles 
     121 * 
     122 * Concurrency can be set on per handle (key) basis, by using 
     123 * #pj_ioqueue_set_concurrency() function. The default key concurrency value  
     124 * for the handle is inherited from the key concurrency setting of the ioqueue,  
     125 * and the key concurrency setting for the ioqueue can be changed by using 
     126 * #pj_ioqueue_set_default_concurrency(). The default key concurrency setting  
     127 * for ioqueue itself is controlled by compile time setting 
     128 * PJ_IOQUEUE_DEFAULT_ALLOW_CONCURRENCY. 
     129 * 
     130 * Note that this key concurrency setting only controls whether multiple 
     131 * threads are allowed to operate <b>on the same key</b> at the same time.  
     132 * The ioqueue itself always allows multiple threads to enter the ioqeuue at  
     133 * the same time, and also simultaneous callback calls to <b>differrent  
     134 * keys</b> is always allowed regardless to the key concurrency setting. 
     135 * 
     136 * \subsection pj_ioq_parallel Parallel Callback Executions for the Same Handle 
     137 * 
     138 * Note that when key concurrency is enabled (i.e. parallel callback calls on 
     139 * the same key is allowed; this is the default setting), the ioqueue will only 
     140 * perform simultaneous callback executions on the same key when the key has 
     141 * invoked multiple pending operations. This could be done for example by 
     142 * calling #pj_ioqueue_recvfrom() more than once on the same key, each with 
     143 * the same key but different operation key (pj_ioqueue_op_key_t). With this 
     144 * scenario, when multiple packets arrive on the key at the same time, more 
     145 * than one threads may execute the callback simultaneously, each with the 
     146 * same key but different operation key. 
     147 * 
     148 * When there is only one pending operation on the key (e.g. there is only one 
     149 * #pj_ioqueue_recvfrom() invoked on the key), then events occuring to the 
     150 * same key will be queued by the ioqueue, thus no simultaneous callback calls 
     151 * will be performed. 
     152 * 
     153 * \subsection pj_ioq_allow_concur Concurrency is Enabled (Default Value) 
     154 * 
     155 * The default setting for the ioqueue is to allow multiple threads to 
     156 * execute callbacks for the same handle/key. This setting is selected to 
     157 * promote good performance and scalability for application. 
     158 * 
     159 * However this setting has a major drawback with regard to synchronization, 
     160 * and application MUST carefully follow the following guidelines to ensure  
     161 * that parallel access to the key does not cause problems: 
     162 * 
     163 *  - Always note that callback may be called simultaneously for the same 
     164 *    key. 
     165 *  - <b>Care must be taken when unregistering a key</b> from the 
    110166 *    ioqueue. Application must take care that when one thread is issuing 
    111  *    an unregistration, other thread is not simultaneously invoking an 
    112  *    operation <b>to the same key</b>. 
     167 *    an unregistration, other thread is not simultaneously invoking the 
     168 *    callback <b>to the same key</b>. 
    113169 *\n 
    114170 *    This happens because the ioqueue functions are working with a pointer 
     
    116172 *    has been rendered invalid by other threads before the ioqueue has a 
    117173 *    chance to acquire mutex on it. 
     174 * 
     175 * \subsection pj_ioq_disallow_concur Concurrency is Disabled 
     176 * 
     177 * Alternatively, application may disable key concurrency to make  
     178 * synchronization easier. As noted above, there are three ways to control 
     179 * key concurrency setting: 
     180 *  - by controlling on per handle/key basis, with #pj_ioqueue_set_concurrency(). 
     181 *  - by changing default key concurrency setting on the ioqueue, with 
     182 *    #pj_ioqueue_set_default_concurrency(). 
     183 *  - by changing the default concurrency on compile time, by declaring 
     184 *    PJ_IOQUEUE_DEFAULT_ALLOW_CONCURRENCY macro to zero in your config_site.h 
    118185 * 
    119186 * \section pj_ioqeuue_examples_sec Examples 
     
    292359 
    293360/** 
     361 * Set default concurrency policy for this ioqueue. If this function is not 
     362 * called, the default concurrency policy for the ioqueue is controlled by  
     363 * compile time setting PJ_IOQUEUE_DEFAULT_ALLOW_CONCURRENCY. 
     364 * 
     365 * Note that changing the concurrency setting to the ioqueue will only affect 
     366 * subsequent key registrations. To modify the concurrency setting for 
     367 * individual key, use #pj_ioqueue_set_concurrency(). 
     368 * 
     369 * @param ioqueue       The ioqueue instance. 
     370 * @param allow         Non-zero to allow concurrent callback calls, or 
     371 *                      PJ_FALSE to disallow it. 
     372 * 
     373 * @return              PJ_SUCCESS on success or the appropriate error code. 
     374 */ 
     375PJ_DECL(pj_status_t) pj_ioqueue_set_default_concurrency(pj_ioqueue_t *ioqueue, 
     376                                                        pj_bool_t allow); 
     377 
     378/** 
    294379 * Register a socket to the I/O queue framework.  
    295380 * When a socket is registered to the IOQueue, it may be modified to use 
     
    367452                                               void **old_data); 
    368453 
     454/** 
     455 * Configure whether the ioqueue is allowed to call the key's callback 
     456 * concurrently/in parallel. The default concurrency setting for the key 
     457 * is controlled by ioqueue's default concurrency value, which can be 
     458 * changed by calling #pj_ioqueue_set_default_concurrency(). 
     459 * 
     460 * If concurrency is allowed for the key, it means that if there are more 
     461 * than one pending operations complete simultaneously, more than one 
     462 * threads may call the key's  callback at the same time. This generally 
     463 * would promote good scalability for application, at the expense of more 
     464 * complexity to manage the concurrent accesses in application's code. 
     465 * 
     466 * Alternatively application may disable the concurrent access by 
     467 * setting the \a allow flag to false. With concurrency disabled, only 
     468 * one thread can call the key's callback at one time. 
     469 * 
     470 * @param key       The key that was previously obtained from registration. 
     471 * @param allow     Set this to non-zero to allow concurrent callback calls 
     472 *                  and zero (PJ_FALSE) to disallow it. 
     473 * 
     474 * @return          PJ_SUCCESS on success or the appropriate error code. 
     475 */ 
     476PJ_DECL(pj_status_t) pj_ioqueue_set_concurrency(pj_ioqueue_key_t *key, 
     477                                                pj_bool_t allow); 
     478 
     479/** 
     480 * Acquire the key's mutex. When the key's concurrency is disabled,  
     481 * application may call this function to synchronize its operation 
     482 * with the key's callback (i.e. this function will block until the 
     483 * key's callback returns). 
     484 * 
     485 * @param key       The key that was previously obtained from registration. 
     486 * 
     487 * @return          PJ_SUCCESS on success or the appropriate error code. 
     488 */ 
     489PJ_DECL(pj_status_t) pj_ioqueue_lock_key(pj_ioqueue_key_t *key); 
     490 
     491/** 
     492 * Release the lock previously acquired with pj_ioqueue_lock_key(). 
     493 * 
     494 * @param key       The key that was previously obtained from registration. 
     495 * 
     496 * @return          PJ_SUCCESS on success or the appropriate error code. 
     497 */ 
     498PJ_DECL(pj_status_t) pj_ioqueue_unlock_key(pj_ioqueue_key_t *key); 
    369499 
    370500/** 
Note: See TracChangeset for help on using the changeset viewer.