diff options
author | Nanang Izzuddin <nanang@teluu.com> | 2012-03-22 11:29:20 +0000 |
---|---|---|
committer | Nanang Izzuddin <nanang@teluu.com> | 2012-03-22 11:29:20 +0000 |
commit | 759520a6f180a638027fdc7be58e12772247fe47 (patch) | |
tree | 4f070ee1947464a3a2ec66b875796f1b76aa1470 | |
parent | 6496121f32e986850b48f6d5637e21ccddb1bb22 (diff) |
Close #1466 (using PJLIB outside PJSUA-LIB context):
- static reference counter for PJLIB init/shutdown.
- implemented atexit() in PJMEDIA and PJSIP level: pjmedia_endpt_atexit() & pjsip_endpt_atexit().
- updated pjmedia/transport_srtp.c, pjsip/sip_timer.c, and pjsip/sip_replaces.c to use the new atexit() functions.
- API change: pjmedia_srtp_init_lib() now requires 'pjmedia_endpt' param.
git-svn-id: http://svn.pjsip.org/repos/pjproject/branches/1.x@3986 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r-- | pjlib/src/pj/os_core_symbian.cpp | 20 | ||||
-rw-r--r-- | pjlib/src/pj/os_core_unix.c | 20 | ||||
-rw-r--r-- | pjlib/src/pj/os_core_win32.c | 20 | ||||
-rw-r--r-- | pjmedia/include/pjmedia/endpoint.h | 20 | ||||
-rw-r--r-- | pjmedia/include/pjmedia/transport_srtp.h | 6 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/endpoint.c | 43 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/transport_srtp.c | 20 | ||||
-rw-r--r-- | pjsip/include/pjsip/sip_endpoint.h | 19 | ||||
-rw-r--r-- | pjsip/src/pjsip-ua/sip_replaces.c | 7 | ||||
-rw-r--r-- | pjsip/src/pjsip-ua/sip_timer.c | 6 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_endpoint.c | 40 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_media.c | 4 |
12 files changed, 211 insertions, 14 deletions
diff --git a/pjlib/src/pj/os_core_symbian.cpp b/pjlib/src/pj/os_core_symbian.cpp index abf01b85..52733560 100644 --- a/pjlib/src/pj/os_core_symbian.cpp +++ b/pjlib/src/pj/os_core_symbian.cpp @@ -75,6 +75,9 @@ struct pj_sem_t int max; }; +/* Flag and reference counter for PJLIB instance */ +static int initialized; + /* Flags to indicate which TLS variables have been used */ static int tls_vars[PJ_MAX_TLS]; @@ -83,8 +86,6 @@ static unsigned atexit_count; static void (*atexit_func[32])(void); - - ///////////////////////////////////////////////////////////////////////////// // // CPjTimeoutTimer implementation @@ -335,6 +336,12 @@ PJ_DEF(pj_status_t) pj_init(void) char stack_ptr; pj_status_t status; + /* Check if PJLIB have been initialized */ + if (initialized) { + ++initialized; + return PJ_SUCCESS; + } + pj_ansi_strcpy(main_thread.obj_name, "pjthread"); // Init main thread @@ -368,6 +375,10 @@ PJ_DEF(pj_status_t) pj_init(void) stack_ptr = '\0'; #endif + /* Flag PJLIB as initialized */ + ++initialized; + pj_assert(initialized == 1); + PJ_LOG(5,(THIS_FILE, "PJLIB initialized.")); return PJ_SUCCESS; @@ -390,6 +401,11 @@ PJ_DEF(pj_status_t) pj_atexit(pj_exit_callback func) PJ_DEF(void) pj_shutdown(void) { + /* Only perform shutdown operation when 'initialized' reaches zero */ + pj_assert(initialized > 0); + if (--initialized != 0) + return; + /* Call atexit() functions */ while (atexit_count > 0) { (*atexit_func[atexit_count-1])(); diff --git a/pjlib/src/pj/os_core_unix.c b/pjlib/src/pj/os_core_unix.c index 3fcfa565..00087b64 100644 --- a/pjlib/src/pj/os_core_unix.c +++ b/pjlib/src/pj/os_core_unix.c @@ -102,6 +102,11 @@ struct pj_event_t #endif /* PJ_HAS_EVENT_OBJ */ +/* + * Flag and reference counter for PJLIB instance. + */ +static int initialized; + #if PJ_HAS_THREADS static pj_thread_t main_thread; static long thread_tls_id; @@ -127,6 +132,12 @@ PJ_DEF(pj_status_t) pj_init(void) pj_str_t guid; pj_status_t rc; + /* Check if PJLIB have been initialized */ + if (initialized) { + ++initialized; + return PJ_SUCCESS; + } + #if PJ_HAS_THREADS /* Init this thread's TLS. */ if ((rc=pj_thread_init()) != 0) { @@ -167,6 +178,10 @@ PJ_DEF(pj_status_t) pj_init(void) } #endif + /* Flag PJLIB as initialized */ + ++initialized; + pj_assert(initialized == 1); + PJ_LOG(4,(THIS_FILE, "pjlib %s for POSIX initialized", PJ_VERSION)); @@ -192,6 +207,11 @@ PJ_DEF(void) pj_shutdown() { int i; + /* Only perform shutdown operation when 'initialized' reaches zero */ + pj_assert(initialized > 0); + if (--initialized != 0) + return; + /* Call atexit() functions */ for (i=atexit_count-1; i>=0; --i) { (*atexit_func[i])(); diff --git a/pjlib/src/pj/os_core_win32.c b/pjlib/src/pj/os_core_win32.c index 2b7c2c91..55d7b1b9 100644 --- a/pjlib/src/pj/os_core_win32.c +++ b/pjlib/src/pj/os_core_win32.c @@ -117,6 +117,11 @@ struct pj_atomic_t }; /* + * Flag and reference counter for PJLIB instance. + */ +static int initialized; + +/* * Static global variables. */ static pj_thread_desc main_thread; @@ -142,6 +147,12 @@ PJ_DEF(pj_status_t) pj_init(void) pj_str_t guid; pj_status_t rc; + /* Check if PJLIB have been initialized */ + if (initialized) { + ++initialized; + return PJ_SUCCESS; + } + /* Init Winsock.. */ if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) { return PJ_RETURN_OS_ERROR(WSAGetLastError()); @@ -187,6 +198,10 @@ PJ_DEF(pj_status_t) pj_init(void) } #endif + /* Flag PJLIB as initialized */ + ++initialized; + pj_assert(initialized == 1); + PJ_LOG(4,(THIS_FILE, "pjlib %s for win32 initialized", PJ_VERSION)); @@ -213,6 +228,11 @@ PJ_DEF(void) pj_shutdown() { int i; + /* Only perform shutdown operation when 'initialized' reaches zero */ + pj_assert(initialized > 0); + if (--initialized != 0) + return; + /* Display stack usage */ #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 { diff --git a/pjmedia/include/pjmedia/endpoint.h b/pjmedia/include/pjmedia/endpoint.h index 37778b7a..2455bcea 100644 --- a/pjmedia/include/pjmedia/endpoint.h +++ b/pjmedia/include/pjmedia/endpoint.h @@ -60,6 +60,12 @@ typedef enum pjmedia_endpt_flag /** + * Type of callback to register to pjmedia_endpt_atexit(). + */ +typedef void (*pjmedia_endpt_exit_callback)(pjmedia_endpt *endpt); + + +/** * Create an instance of media endpoint. * * @param pf Pool factory, which will be used by the media endpoint @@ -204,6 +210,20 @@ PJ_DECL(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt, PJ_DECL(pj_status_t) pjmedia_endpt_dump(pjmedia_endpt *endpt); +/** + * Register cleanup function to be called by media endpoint when + * #pjmedia_endpt_destroy() is called. + * + * @param endpt The media endpoint. + * @param func The function to be registered. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjmedia_endpt_atexit(pjmedia_endpt *endpt, + pjmedia_endpt_exit_callback func); + + + PJ_END_DECL diff --git a/pjmedia/include/pjmedia/transport_srtp.h b/pjmedia/include/pjmedia/transport_srtp.h index 3a4820e8..910ec1d0 100644 --- a/pjmedia/include/pjmedia/transport_srtp.h +++ b/pjmedia/include/pjmedia/transport_srtp.h @@ -200,8 +200,12 @@ typedef struct pjmedia_srtp_info * will also invoke this function. This function will also register SRTP * library deinitialization to #pj_atexit(), so the deinitialization * of SRTP library will be performed automatically by PJLIB destructor. + * + * @param endpt The media endpoint instance. + * + * @return PJ_SUCCESS on success. */ -PJ_DECL(pj_status_t) pjmedia_srtp_init_lib(void); +PJ_DECL(pj_status_t) pjmedia_srtp_init_lib(pjmedia_endpt *endpt); /** diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c index a9adfc2b..43ed4ccf 100644 --- a/pjmedia/src/pjmedia/endpoint.c +++ b/pjmedia/src/pjmedia/endpoint.c @@ -23,6 +23,7 @@ #include <pjmedia-audiodev/audiodev.h> #include <pj/assert.h> #include <pj/ioqueue.h> +#include <pj/lock.h> #include <pj/log.h> #include <pj/os.h> #include <pj/pool.h> @@ -56,6 +57,14 @@ static int PJ_THREAD_FUNC worker_proc(void*); #define MAX_THREADS 16 +/* List of media endpoint exit callback. */ +typedef struct exit_cb +{ + PJ_DECL_LIST_MEMBER (struct exit_cb); + pjmedia_endpt_exit_callback func; +} exit_cb; + + /** Concrete declaration of media endpoint. */ struct pjmedia_endpt { @@ -85,6 +94,9 @@ struct pjmedia_endpt /** Is telephone-event enable */ pj_bool_t has_telephone_event; + + /** List of exit callback. */ + exit_cb exit_cb_list; }; /** @@ -128,6 +140,9 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf, if (status != PJ_SUCCESS) goto on_error; + /* Initialize exit callback list. */ + pj_list_init(&endpt->exit_cb_list); + /* Create ioqueue if none is specified. */ if (endpt->ioqueue == NULL) { @@ -188,6 +203,7 @@ PJ_DEF(pjmedia_codec_mgr*) pjmedia_endpt_get_codec_mgr(pjmedia_endpt *endpt) */ PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt) { + exit_cb *ecb; unsigned i; PJ_ASSERT_RETURN(endpt, PJ_EINVAL); @@ -203,6 +219,13 @@ PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt) } } + /* Call all registered exit callbacks */ + ecb = endpt->exit_cb_list.next; + while (ecb != &endpt->exit_cb_list) { + (*ecb->func)(endpt); + ecb = ecb->next; + } + /* Destroy internal ioqueue */ if (endpt->ioqueue && endpt->own_ioqueue) { pj_ioqueue_destroy(endpt->ioqueue); @@ -628,3 +651,23 @@ PJ_DEF(pj_status_t) pjmedia_endpt_dump(pjmedia_endpt *endpt) return PJ_SUCCESS; } + +PJ_DEF(pj_status_t) pjmedia_endpt_atexit( pjmedia_endpt *endpt, + pjmedia_endpt_exit_callback func) +{ + exit_cb *new_cb; + + PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL); + + if (endpt->quit_flag) + return PJ_EINVALIDOP; + + new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb); + new_cb->func = func; + + pj_enter_critical_section(); + pj_list_push_back(&endpt->exit_cb_list, new_cb); + pj_leave_critical_section(); + + return PJ_SUCCESS; +} diff --git a/pjmedia/src/pjmedia/transport_srtp.c b/pjmedia/src/pjmedia/transport_srtp.c index b37fd79b..76bd1518 100644 --- a/pjmedia/src/pjmedia/transport_srtp.c +++ b/pjmedia/src/pjmedia/transport_srtp.c @@ -270,9 +270,9 @@ const char* get_libsrtp_errstr(int err) } static pj_bool_t libsrtp_initialized; -static void pjmedia_srtp_deinit_lib(void); +static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt); -PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(void) +PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(pjmedia_endpt *endpt) { if (libsrtp_initialized == PJ_FALSE) { err_status_t err; @@ -284,7 +284,8 @@ PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(void) return PJMEDIA_ERRNO_FROM_LIBSRTP(err); } - if (pj_atexit(pjmedia_srtp_deinit_lib) != PJ_SUCCESS) { + if (pjmedia_endpt_atexit(endpt, pjmedia_srtp_deinit_lib) != PJ_SUCCESS) + { /* There will be memory leak when it fails to schedule libsrtp * deinitialization, however the memory leak could be harmless, * since in modern OS's memory used by an application is released @@ -299,10 +300,19 @@ PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(void) return PJ_SUCCESS; } -static void pjmedia_srtp_deinit_lib(void) +static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt) { err_status_t err; + /* Note that currently this SRTP init/deinit is not equipped with + * reference counter, it should be safe as normally there is only + * one single instance of media endpoint and even if it isn't, the + * pjmedia_transport_srtp_create() will invoke SRTP init (the only + * drawback should be the delay described by #788). + */ + + PJ_UNUSED_ARG(endpt); + err = srtp_deinit(); if (err != err_status_ok) { PJ_LOG(4, (THIS_FILE, "Failed to deinitialize libsrtp: %s", @@ -410,7 +420,7 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_create( } /* Init libsrtp. */ - status = pjmedia_srtp_init_lib(); + status = pjmedia_srtp_init_lib(endpt); if (status != PJ_SUCCESS) return status; diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h index e957271c..bc652e60 100644 --- a/pjsip/include/pjsip/sip_endpoint.h +++ b/pjsip/include/pjsip/sip_endpoint.h @@ -62,6 +62,13 @@ PJ_BEGIN_DECL * @{ */ + +/** + * Type of callback to register to pjsip_endpt_atexit(). + */ +typedef void (*pjsip_endpt_exit_callback)(pjsip_endpoint *endpt); + + /** * Create an instance of SIP endpoint from the specified pool factory. * The pool factory reference then will be kept by the endpoint, so that @@ -511,6 +518,18 @@ PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *e); PJ_DECL(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail ); +/** + * Register cleanup function to be called by SIP endpoint when + * #pjsip_endpt_destroy() is called. + * + * @param endpt The SIP endpoint. + * @param func The function to be registered. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjsip_endpt_atexit(pjsip_endpoint *endpt, + pjsip_endpt_exit_callback func); + /** * @} diff --git a/pjsip/src/pjsip-ua/sip_replaces.c b/pjsip/src/pjsip-ua/sip_replaces.c index 4707a510..70329f97 100644 --- a/pjsip/src/pjsip-ua/sip_replaces.c +++ b/pjsip/src/pjsip-ua/sip_replaces.c @@ -162,8 +162,10 @@ static pjsip_hdr *parse_hdr_replaces(pjsip_parse_ctx *ctx) /* Deinitialize Replaces */ -static void pjsip_replaces_deinit_module(void) +static void pjsip_replaces_deinit_module(pjsip_endpoint *endpt) { + PJ_TODO(provide_initialized_flag_for_each_endpoint); + PJ_UNUSED_ARG(endpt); is_initialized = PJ_FALSE; } @@ -191,7 +193,8 @@ PJ_DEF(pj_status_t) pjsip_replaces_init_module(pjsip_endpoint *endpt) 1, &STR_REPLACES); /* Register deinit module to be executed when PJLIB shutdown */ - if (pj_atexit(&pjsip_replaces_deinit_module) != PJ_SUCCESS) { + if (pjsip_endpt_atexit(endpt, &pjsip_replaces_deinit_module) != PJ_SUCCESS) + { /* Failure to register this function may cause this module won't * work properly when the stack is restarted (without quitting * application). diff --git a/pjsip/src/pjsip-ua/sip_timer.c b/pjsip/src/pjsip-ua/sip_timer.c index d907794f..17c83c24 100644 --- a/pjsip/src/pjsip-ua/sip_timer.c +++ b/pjsip/src/pjsip-ua/sip_timer.c @@ -495,8 +495,10 @@ static void stop_timer(pjsip_inv_session *inv) } /* Deinitialize Session Timers */ -static void pjsip_timer_deinit_module(void) +static void pjsip_timer_deinit_module(pjsip_endpoint *endpt) { + PJ_TODO(provide_initialized_flag_for_each_endpoint); + PJ_UNUSED_ARG(endpt); is_initialized = PJ_FALSE; } @@ -531,7 +533,7 @@ PJ_DEF(pj_status_t) pjsip_timer_init_module(pjsip_endpoint *endpt) return status; /* Register deinit module to be executed when PJLIB shutdown */ - if (pj_atexit(&pjsip_timer_deinit_module) != PJ_SUCCESS) { + if (pjsip_endpt_atexit(endpt, &pjsip_timer_deinit_module) != PJ_SUCCESS) { /* Failure to register this function may cause this module won't * work properly when the stack is restarted (without quitting * application). diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c index 6d3bcdd2..0125ae39 100644 --- a/pjsip/src/pjsip/sip_endpoint.c +++ b/pjsip/src/pjsip/sip_endpoint.c @@ -40,6 +40,15 @@ #define MAX_METHODS 32 + +/* List of SIP endpoint exit callback. */ +typedef struct exit_cb +{ + PJ_DECL_LIST_MEMBER (struct exit_cb); + pjsip_endpt_exit_callback func; +} exit_cb; + + /** * The SIP endpoint. */ @@ -86,6 +95,9 @@ struct pjsip_endpoint /** Additional request headers. */ pjsip_hdr req_hdr; + + /** List of exit callback. */ + exit_cb exit_cb_list; }; @@ -445,6 +457,9 @@ PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf, /* Init modules list. */ pj_list_init(&endpt->module_list); + /* Initialize exit callback list. */ + pj_list_init(&endpt->exit_cb_list); + /* Create R/W mutex for module manipulation. */ status = pj_rwmutex_create(endpt->pool, "ept%p", &endpt->mod_mutex); if (status != PJ_SUCCESS) @@ -559,9 +574,17 @@ on_error: PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt) { pjsip_module *mod; + exit_cb *ecb; PJ_LOG(5, (THIS_FILE, "Destroying endpoing instance..")); + /* Call all registered exit callbacks */ + ecb = endpt->exit_cb_list.next; + while (ecb != &endpt->exit_cb_list) { + (*ecb->func)(endpt); + ecb = ecb->next; + } + /* Phase 1: stop all modules */ mod = endpt->module_list.prev; while (mod != &endpt->module_list) { @@ -1178,3 +1201,20 @@ PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail ) #endif } + +PJ_DEF(pj_status_t) pjsip_endpt_atexit( pjsip_endpoint *endpt, + pjsip_endpt_exit_callback func) +{ + exit_cb *new_cb; + + PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL); + + new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb); + new_cb->func = func; + + pj_mutex_lock(endpt->mutex); + pj_list_push_back(&endpt->exit_cb_list, new_cb); + pj_mutex_unlock(endpt->mutex); + + return PJ_SUCCESS; +} diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index d36c9fc2..2a9927a7 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -335,8 +335,8 @@ pj_status_t pjsua_media_subsys_init(const pjsua_media_config *cfg) PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) - /* Initialize SRTP library. */ - status = pjmedia_srtp_init_lib(); + /* Initialize SRTP library (ticket #788). */ + status = pjmedia_srtp_init_lib(pjsua_var.med_endpt); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error initializing SRTP library", status); |