diff options
Diffstat (limited to 'pjlib/include/pj')
-rw-r--r-- | pjlib/include/pj/activesock.h | 7 | ||||
-rw-r--r-- | pjlib/include/pj/config.h | 16 | ||||
-rw-r--r-- | pjlib/include/pj/errno.h | 5 | ||||
-rw-r--r-- | pjlib/include/pj/ioqueue.h | 13 | ||||
-rw-r--r-- | pjlib/include/pj/lock.h | 252 | ||||
-rw-r--r-- | pjlib/include/pj/timer.h | 66 | ||||
-rw-r--r-- | pjlib/include/pj/types.h | 3 |
7 files changed, 360 insertions, 2 deletions
diff --git a/pjlib/include/pj/activesock.h b/pjlib/include/pj/activesock.h index 5a201864..11fa6589 100644 --- a/pjlib/include/pj/activesock.h +++ b/pjlib/include/pj/activesock.h @@ -174,6 +174,11 @@ typedef struct pj_activesock_cb typedef struct pj_activesock_cfg { /** + * Optional group lock to be assigned to the ioqueue key. + */ + pj_grp_lock_t *grp_lock; + + /** * Number of concurrent asynchronous operations that is to be supported * by the active socket. This value only affects socket receive and * accept operations -- the active socket will issue one or more @@ -290,7 +295,6 @@ PJ_DECL(pj_status_t) pj_activesock_create_udp(pj_pool_t *pool, pj_activesock_t **p_asock, pj_sockaddr *bound_addr); - /** * Close the active socket. This will unregister the socket from the * ioqueue and ultimately close the socket. @@ -548,6 +552,7 @@ PJ_DECL(pj_status_t) pj_activesock_start_connect(pj_activesock_t *asock, const pj_sockaddr_t *remaddr, int addr_len); + #endif /* PJ_HAS_TCP */ /** diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h index 2568214d..9b504c3a 100644 --- a/pjlib/include/pj/config.h +++ b/pjlib/include/pj/config.h @@ -488,6 +488,14 @@ /** + * Set this to 1 to enable debugging on the group lock. Default: 0 + */ +#ifndef PJ_GRP_LOCK_DEBUG +# define PJ_GRP_LOCK_DEBUG 0 +#endif + + +/** * Specify this as \a stack_size argument in #pj_thread_create() to specify * that thread should use default stack size for the current platform. * @@ -1122,6 +1130,14 @@ #endif /** + * Simulate race condition by sleeping the thread in strategic locations. + * Default: no! + */ +#ifndef PJ_RACE_ME +# define PJ_RACE_ME(x) +#endif + +/** * Function attributes to inform that the function may throw exception. * * @param x The exception list, enclosed in parenthesis. diff --git a/pjlib/include/pj/errno.h b/pjlib/include/pj/errno.h index 66fea949..e9e403ce 100644 --- a/pjlib/include/pj/errno.h +++ b/pjlib/include/pj/errno.h @@ -422,6 +422,11 @@ PJ_DECL(pj_status_t) pj_register_strerror(pj_status_t start_code, * Unsupported address family */ #define PJ_EAFNOTSUP (PJ_ERRNO_START_STATUS + 22)/* 70022 */ +/** + * @hideinitializer + * Object no longer exists + */ +#define PJ_EGONE (PJ_ERRNO_START_STATUS + 23)/* 70023 */ /** @} */ /* pj_errnum */ diff --git a/pjlib/include/pj/ioqueue.h b/pjlib/include/pj/ioqueue.h index 40bb403c..1e983327 100644 --- a/pjlib/include/pj/ioqueue.h +++ b/pjlib/include/pj/ioqueue.h @@ -405,6 +405,19 @@ PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool, pj_ioqueue_key_t **key ); /** + * Variant of pj_ioqueue_register_sock() with additional group lock parameter. + * If group lock is set for the key, the key will add the reference counter + * when the socket is registered and decrease it when it is destroyed. + */ +PJ_DECL(pj_status_t) pj_ioqueue_register_sock2(pj_pool_t *pool, + pj_ioqueue_t *ioque, + pj_sock_t sock, + pj_grp_lock_t *grp_lock, + void *user_data, + const pj_ioqueue_callback *cb, + pj_ioqueue_key_t **key ); + +/** * Unregister from the I/O Queue framework. Caller must make sure that * the key doesn't have any pending operations before calling this function, * by calling #pj_ioqueue_is_pending() for all previously submitted diff --git a/pjlib/include/pj/lock.h b/pjlib/include/pj/lock.h index b8bdb0f9..b1a5d72e 100644 --- a/pjlib/include/pj/lock.h +++ b/pjlib/include/pj/lock.h @@ -147,6 +147,258 @@ PJ_DECL(pj_status_t) pj_lock_destroy( pj_lock_t *lock ); /** @} */ + +/** + * @defgroup PJ_GRP_LOCK Group Lock + * @ingroup PJ_LOCK + * @{ + * + * Group lock is a synchronization object to manage concurrency among members + * within the same logical group. Example of such groups are: + * + * - dialog, which has members such as the dialog itself, an invite session, + * and several transactions + * - ICE, which has members such as ICE stream transport, ICE session, STUN + * socket, TURN socket, and down to ioqueue key + * + * Group lock has three functions: + * + * - mutual exclusion: to protect resources from being accessed by more than + * one threads at the same time + * - session management: to make sure that the resource is not destroyed + * while others are still using or about to use it. + * - lock coordinator: to provide uniform lock ordering among more than one + * lock objects, which is necessary to avoid deadlock. + * + * The requirements of the group lock are: + * + * - must satisfy all the functions above + * - must allow members to join or leave the group (for example, + * transaction may be added or removed from a dialog) + * - must be able to synchronize with external lock (for example, a dialog + * lock must be able to sync itself with PJSUA lock) + * + * Please see https://trac.pjsip.org/repos/wiki/Group_Lock for more info. + */ + +/** + * Settings for creating the group lock. + */ +typedef struct pj_grp_lock_config +{ + /** + * Creation flags, currently must be zero. + */ + unsigned flags; + +} pj_grp_lock_config; + + +/** + * Initialize the config with the default values. + * + * @param cfg The config to be initialized. + */ +PJ_DECL(void) pj_grp_lock_config_default(pj_grp_lock_config *cfg); + +/** + * Create a group lock object. Initially the group lock will have reference + * counter of one. + * + * @param pool The group lock only uses the pool parameter to get + * the pool factory, from which it will create its own + * pool. + * @param cfg Optional configuration. + * @param p_grp_lock Pointer to receive the newly created group lock. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_grp_lock_create(pj_pool_t *pool, + const pj_grp_lock_config *cfg, + pj_grp_lock_t **p_grp_lock); + +/** + * Forcibly destroy the group lock, ignoring the reference counter value. + * + * @param grp_lock The group lock. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_grp_lock_destroy( pj_grp_lock_t *grp_lock); + +/** + * Move the contents of the old lock to the new lock and destroy the + * old lock. + * + * @param old_lock The old group lock to be destroyed. + * @param new_lock The new group lock. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_grp_lock_replace(pj_grp_lock_t *old_lock, + pj_grp_lock_t *new_lock); + +/** + * Acquire lock on the specified group lock. + * + * @param grp_lock The group lock. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_grp_lock_acquire( pj_grp_lock_t *grp_lock); + +/** + * Acquire lock on the specified group lock if it is available, otherwise + * return immediately wihout waiting. + * + * @param grp_lock The group lock. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_grp_lock_tryacquire( pj_grp_lock_t *grp_lock); + +/** + * Release the previously held lock. This may cause the group lock + * to be destroyed if it is the last one to hold the reference counter. + * In that case, the function will return PJ_EGONE. + * + * @param grp_lock The group lock. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_grp_lock_release( pj_grp_lock_t *grp_lock); + +/** + * Add a destructor handler, to be called by the group lock when it is + * about to be destroyed. + * + * @param grp_lock The group lock. + * @param pool Pool to allocate memory for the handler. + * @param member A pointer to be passed to the handler. + * @param handler The destroy handler. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_grp_lock_add_handler(pj_grp_lock_t *grp_lock, + pj_pool_t *pool, + void *member, + void (*handler)(void *member)); + +/** + * Remove previously registered handler. All parameters must be the same + * as when the handler was added. + * + * @param grp_lock The group lock. + * @param member A pointer to be passed to the handler. + * @param handler The destroy handler. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_grp_lock_del_handler(pj_grp_lock_t *grp_lock, + void *member, + void (*handler)(void *member)); + +/** + * Increment reference counter to prevent the group lock grom being destroyed. + * + * @param grp_lock The group lock. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +#if !PJ_GRP_LOCK_DEBUG +PJ_DECL(pj_status_t) pj_grp_lock_add_ref(pj_grp_lock_t *grp_lock); + +#define pj_grp_lock_add_ref_dbg(grp_lock, x, y) pj_grp_lock_add_ref(grp_lock) + +#else + +#define pj_grp_lock_add_ref(g) pj_grp_lock_add_ref_dbg(g, __FILE__, __LINE__) + +PJ_DECL(pj_status_t) pj_grp_lock_add_ref_dbg(pj_grp_lock_t *grp_lock, + const char *file, + int line); +#endif + +/** + * Decrement the reference counter. When the counter value reaches zero, the + * group lock will be destroyed and all destructor handlers will be called. + * + * @param grp_lock The group lock. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +#if !PJ_GRP_LOCK_DEBUG +PJ_DECL(pj_status_t) pj_grp_lock_dec_ref(pj_grp_lock_t *grp_lock); + +#define pj_grp_lock_dec_ref_dbg(grp_lock, x, y) pj_grp_lock_dec_ref(grp_lock) +#else + +#define pj_grp_lock_dec_ref(g) pj_grp_lock_dec_ref_dbg(g, __FILE__, __LINE__) + +PJ_DECL(pj_status_t) pj_grp_lock_dec_ref_dbg(pj_grp_lock_t *grp_lock, + const char *file, + int line); + +#endif + +/** + * Get current reference count value. This normally is only used for + * debugging purpose. + * + * @param grp_lock The group lock. + * + * @return The reference count value. + */ +PJ_DECL(int) pj_grp_lock_get_ref(pj_grp_lock_t *grp_lock); + + +/** + * Dump group lock info for debugging purpose. If group lock debugging is + * enabled (via PJ_GRP_LOCK_DEBUG) macro, this will print the group lock + * reference counter value along with the source file and line. If + * debugging is disabled, this will only print the reference counter. + * + * @param grp_lock The group lock. + */ +PJ_DECL(void) pj_grp_lock_dump(pj_grp_lock_t *grp_lock); + + +/** + * Synchronize an external lock with the group lock, by adding it to the + * list of locks to be acquired by the group lock when the group lock is + * acquired. + * + * The ''pos'' argument specifies the lock order and also the relative + * position with regard to lock ordering against the group lock. Locks with + * lower ''pos'' value will be locked first, and those with negative value + * will be locked before the group lock (the group lock's ''pos'' value is + * zero). + * + * @param grp_lock The group lock. + * @param ext_lock The external lock + * @param pos The position. + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_grp_lock_chain_lock(pj_grp_lock_t *grp_lock, + pj_lock_t *ext_lock, + int pos); + +/** + * Remove an external lock from group lock's list of synchronized locks. + * + * @param grp_lock The group lock. + * @param ext_lock The external lock + * + * @return PJ_SUCCESS or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_grp_lock_unchain_lock(pj_grp_lock_t *grp_lock, + pj_lock_t *ext_lock); + + +/** @} */ + + PJ_END_DECL diff --git a/pjlib/include/pj/timer.h b/pjlib/include/pj/timer.h index c2182ce3..59149385 100644 --- a/pjlib/include/pj/timer.h +++ b/pjlib/include/pj/timer.h @@ -24,6 +24,7 @@ */ #include <pj/types.h> +#include <pj/lock.h> PJ_BEGIN_DECL @@ -118,6 +119,12 @@ typedef struct pj_timer_entry */ pj_time_val _timer_value; + /** + * Internal: the group lock used by this entry, set when + * pj_timer_heap_schedule_w_lock() is used. + */ + pj_grp_lock_t *_grp_lock; + #if PJ_TIMER_DEBUG const char *src_file; int src_line; @@ -229,7 +236,46 @@ PJ_DECL(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht, #endif /* PJ_TIMER_DEBUG */ /** - * Cancel a previously registered timer. + * Schedule a timer entry which will expire AFTER the specified delay, and + * increment the reference counter of the group lock while the timer entry + * is active. The group lock reference counter will automatically be released + * after the timer callback is called or when the timer is cancelled. + * + * @param ht The timer heap. + * @param entry The entry to be registered. + * @param id_val The value to be set to the "id" field of the timer entry + * once the timer is scheduled. + * @param delay The interval to expire. + * @param grp_lock The group lock. + * + * @return PJ_SUCCESS, or the appropriate error code. + */ +#if PJ_TIMER_DEBUG +# define pj_timer_heap_schedule_w_grp_lock(ht,e,d,id,g) \ + pj_timer_heap_schedule_w_grp_lock_dbg(ht,e,d,id,g,__FILE__,__LINE__) + + PJ_DECL(pj_status_t) pj_timer_heap_schedule_w_grp_lock_dbg( + pj_timer_heap_t *ht, + pj_timer_entry *entry, + const pj_time_val *delay, + int id_val, + pj_grp_lock_t *grp_lock, + const char *src_file, + int src_line); +#else +PJ_DECL(pj_status_t) pj_timer_heap_schedule_w_grp_lock( + pj_timer_heap_t *ht, + pj_timer_entry *entry, + const pj_time_val *delay, + int id_val, + pj_grp_lock_t *grp_lock); +#endif /* PJ_TIMER_DEBUG */ + + +/** + * Cancel a previously registered timer. This will also decrement the + * reference counter of the group lock associated with the timer entry, + * if the entry was scheduled with one. * * @param ht The timer heap. * @param entry The entry to be cancelled. @@ -241,6 +287,24 @@ PJ_DECL(int) pj_timer_heap_cancel( pj_timer_heap_t *ht, pj_timer_entry *entry); /** + * Cancel only if the previously registered timer is active. This will + * also decrement the reference counter of the group lock associated + * with the timer entry, if the entry was scheduled with one. In any + * case, set the "id" to the specified value. + * + * @param ht The timer heap. + * @param entry The entry to be cancelled. + * @param id_val Value to be set to "id" + * + * @return The number of timer cancelled, which should be one if the + * entry has really been registered, or zero if no timer was + * cancelled. + */ +PJ_DECL(int) pj_timer_heap_cancel_if_active(pj_timer_heap_t *ht, + pj_timer_entry *entry, + int id_val); + +/** * Get the number of timer entries. * * @param ht The timer heap. diff --git a/pjlib/include/pj/types.h b/pjlib/include/pj/types.h index 9f05ce44..04e426b5 100644 --- a/pjlib/include/pj/types.h +++ b/pjlib/include/pj/types.h @@ -231,6 +231,9 @@ typedef struct pj_thread_t pj_thread_t; /** Lock object. */ typedef struct pj_lock_t pj_lock_t; +/** Group lock */ +typedef struct pj_grp_lock_t pj_grp_lock_t; + /** Mutex handle. */ typedef struct pj_mutex_t pj_mutex_t; |