Skip to content

Commit c8a6f92

Browse files
pj_threading on external threads (#4626)
1 parent e3cfd0e commit c8a6f92

File tree

4 files changed

+455
-73
lines changed

4 files changed

+455
-73
lines changed

pjlib/include/pj/os.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,33 @@ PJ_DECL(pj_status_t) pj_thread_create( pj_pool_t *pool,
202202
unsigned flags,
203203
pj_thread_t **thread );
204204

205+
/**
206+
* Create a new thread, use preallocated space for thread descriptor
207+
* and thread stack.
208+
* To avoid pool allocation, function does not support suspended thread.
209+
*
210+
*
211+
* @param thread_name The optional name to be assigned to the thread.
212+
* @param proc Thread entry function.
213+
* @param arg Argument to be passed to the thread entry function.
214+
* @param stack_size The size of the stack for the new thread, or ZERO or
215+
* PJ_THREAD_DEFAULT_STACK_SIZE to let the
216+
* library choose the reasonable size for the stack.
217+
* @param stack_addr Preallocated space of size stack_size for the stack
218+
* for the new thread, used if PJ_THREAD_ALLOCATE_STACK
219+
* macro defined and is not 0. Otherwise ignored.
220+
* @param thread Pointer to preallocated thread descriptor to hold
221+
* the newly created thread.
222+
*
223+
* @return PJ_SUCCESS on success, or the error code.
224+
*/
225+
PJ_DECL(pj_status_t) pj_thread_create2( const char *thread_name,
226+
pj_thread_proc *proc,
227+
void *arg,
228+
pj_size_t stack_size,
229+
void *stack_addr,
230+
pj_thread_t *thread );
231+
205232
/**
206233
* Register a thread that was created by external or native API to PJLIB.
207234
* This function must be called in the context of the thread being registered.
@@ -222,6 +249,46 @@ PJ_DECL(pj_status_t) pj_thread_register ( const char *thread_name,
222249
pj_thread_desc desc,
223250
pj_thread_t **thread);
224251

252+
253+
/**
254+
* Detach pjsip library from the current thread without terminating
255+
* the OS thread, frees the resources allocated by pjlib for the calling thread,
256+
* including freeing the tls slot in which pj_thread_t is stored.
257+
* However, the memory allocated for the pj_thread_t itself will only be released
258+
* when the pool used to create the thread is destroyed.
259+
*
260+
* An application should call this function when leaving threads created by
261+
* an external module (e.g. audio thread, threads from an external thread pool,
262+
* etc). Such a thread is registered with pj_thread_register() and detached
263+
* with pj_thread_unregister() when finished using.
264+
*
265+
* @return PJ_SUCCESS on success.
266+
*/
267+
PJ_DECL(pj_status_t) pj_thread_unregister();
268+
269+
/**
270+
* Register a thread that was created by external or native API to PJLIB.
271+
*
272+
* This function is a complete copy of pj_thread_register(), with the only
273+
* difference being that on Windows it returns a pj_thread_t suitable for
274+
* waiting for the thread to terminate. This function should only be used
275+
* if the application requires calling pj_thread_join() for the current thread;
276+
* otherwise, use pj_thread_register().
277+
*
278+
* @param thread_name The optional name to be assigned to the thread.
279+
* @param desc Thread descriptor, which must be available throughout
280+
* the lifetime of the thread.
281+
* @param thread Pointer to hold the created thread handle.
282+
*
283+
* @return PJ_SUCCESS on success, or the error code.
284+
*
285+
* @see pj_thread_register()
286+
*/
287+
PJ_DECL(pj_status_t) pj_thread_attach ( const char *thread_name,
288+
pj_thread_desc desc,
289+
pj_thread_t **thread);
290+
291+
225292
/**
226293
* Check if this thread has been registered to PJLIB.
227294
*

pjlib/src/pj/os_core_unix.c

Lines changed: 129 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -736,33 +736,21 @@ static void *thread_main(void *param)
736736

737737
return result;
738738
}
739-
#endif
740739

741-
/*
742-
* pj_thread_create(...)
743-
*/
744-
PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
745-
const char *thread_name,
746-
pj_thread_proc *proc,
747-
void *arg,
748-
pj_size_t stack_size,
749-
unsigned flags,
750-
pj_thread_t **ptr_thread)
740+
static pj_status_t create_thread(const char *thread_name,
741+
pj_thread_proc *proc,
742+
void *arg,
743+
pj_size_t stack_size,
744+
void *stack_addr,
745+
pj_thread_t *rec)
751746
{
752-
#if PJ_HAS_THREADS
753-
pj_thread_t *rec;
754747
pthread_attr_t thread_attr;
755-
void *stack_addr;
756748
int rc;
757749

758750
PJ_UNUSED_ARG(stack_addr);
759751

760752
PJ_CHECK_STACK();
761-
PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
762-
763-
/* Create thread record and assign name for the thread */
764-
rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));
765-
PJ_ASSERT_RETURN(rec, PJ_ENOMEM);
753+
PJ_ASSERT_RETURN(proc && rec, PJ_EINVAL);
766754

767755
/* Set name. */
768756
if (!thread_name)
@@ -783,19 +771,6 @@ PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
783771
rec->stk_max_usage = 0;
784772
#endif
785773

786-
/* Emulate suspended thread with mutex. */
787-
if (flags & PJ_THREAD_SUSPENDED) {
788-
rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);
789-
if (rc != PJ_SUCCESS) {
790-
return rc;
791-
}
792-
793-
pj_mutex_lock(rec->suspended_mutex);
794-
} else {
795-
pj_assert(rec->suspended_mutex == NULL);
796-
}
797-
798-
799774
/* Init thread attributes */
800775
pthread_attr_init(&thread_attr);
801776

@@ -811,8 +786,7 @@ PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
811786

812787
#if defined(PJ_THREAD_ALLOCATE_STACK) && PJ_THREAD_ALLOCATE_STACK!=0
813788
/* Allocate memory for the stack */
814-
stack_addr = pj_pool_alloc(pool, stack_size);
815-
PJ_ASSERT_RETURN(stack_addr, PJ_ENOMEM);
789+
PJ_ASSERT_RETURN(stack_addr, PJ_EINVAL);
816790

817791
rc = pthread_attr_setstackaddr(&thread_attr, stack_addr);
818792
if (rc != 0) {
@@ -834,10 +808,85 @@ PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
834808
/* Destroy thread attributes */
835809
pthread_attr_destroy(&thread_attr);
836810

837-
*ptr_thread = rec;
838-
839811
PJ_LOG(6, (rec->obj_name, "Thread created"));
840812
return PJ_SUCCESS;
813+
814+
}
815+
816+
#endif
817+
818+
/*
819+
* pj_thread_create(...)
820+
*/
821+
PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
822+
const char *thread_name,
823+
pj_thread_proc *proc,
824+
void *arg,
825+
pj_size_t stack_size,
826+
unsigned flags,
827+
pj_thread_t **ptr_thread)
828+
{
829+
#if PJ_HAS_THREADS
830+
pj_status_t status;
831+
pj_thread_t *rec;
832+
void *stack_addr = NULL;
833+
int rc;
834+
835+
PJ_CHECK_STACK();
836+
PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
837+
838+
/* Create thread record and assign name for the thread */
839+
rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));
840+
PJ_ASSERT_RETURN(rec, PJ_ENOMEM);
841+
842+
#if defined(PJ_THREAD_ALLOCATE_STACK) && PJ_THREAD_ALLOCATE_STACK!=0
843+
/* Allocate memory for the stack */
844+
stack_addr = pj_pool_alloc(pool, stack_size);
845+
PJ_ASSERT_RETURN(stack_addr, PJ_ENOMEM);
846+
#endif /* PJ_THREAD_ALLOCATE_STACK */
847+
848+
/* Emulate suspended thread with mutex. */
849+
if (flags & PJ_THREAD_SUSPENDED) {
850+
rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);
851+
if (rc != PJ_SUCCESS) {
852+
return rc;
853+
}
854+
855+
pj_mutex_lock(rec->suspended_mutex);
856+
} else {
857+
pj_assert(rec->suspended_mutex == NULL);
858+
}
859+
860+
status = create_thread(thread_name, proc, arg, stack_size, stack_addr, rec);
861+
if (status == PJ_SUCCESS) {
862+
/* Success! */
863+
*ptr_thread = rec;
864+
}
865+
return status;
866+
867+
#else
868+
pj_assert(!"Threading is disabled!");
869+
return PJ_EINVALIDOP;
870+
#endif
871+
}
872+
873+
PJ_DEF(pj_status_t) pj_thread_create2( const char *thread_name,
874+
pj_thread_proc *proc,
875+
void *arg,
876+
pj_size_t stack_size,
877+
void *stack_addr,
878+
pj_thread_t *thread )
879+
{
880+
#if PJ_HAS_THREADS
881+
882+
PJ_CHECK_STACK();
883+
PJ_ASSERT_RETURN(proc && thread, PJ_EINVAL);
884+
885+
if (thread == pj_thread_this())
886+
return PJ_ECANCELLED;
887+
888+
return create_thread(thread_name, proc, arg, stack_size, stack_addr, thread);
889+
841890
#else
842891
pj_assert(!"Threading is disabled!");
843892
return PJ_EINVALIDOP;
@@ -937,12 +986,49 @@ PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
937986
#endif
938987
}
939988

989+
/*
990+
* pj_thread_unregister()
991+
*/
992+
PJ_DEF(pj_status_t) pj_thread_unregister()
993+
{
994+
#if PJ_HAS_THREADS
995+
pj_status_t status;
996+
//int result;
997+
pj_thread_t *rec;
998+
PJ_CHECK_STACK();
999+
1000+
rec = pj_thread_this();
1001+
PJ_ASSERT_RETURN(rec, PJ_EBUG);
1002+
1003+
if ((status = pj_thread_destroy(rec)) != PJ_SUCCESS)
1004+
return status;
1005+
//else if ((result = pthread_detach(rec->thread)) != 0)
1006+
// return PJ_RETURN_OS_ERROR(result);
1007+
else
1008+
return pj_thread_local_set(thread_tls_id, NULL);
1009+
#else
1010+
pj_assert(!"No multithreading support!");
1011+
return PJ_EINVALIDOP;
1012+
#endif
1013+
}
1014+
1015+
/*
1016+
* pj_thread_attach()
1017+
*/
1018+
PJ_DEF(pj_status_t) pj_thread_attach(const char *cstr_thread_name,
1019+
pj_thread_desc desc,
1020+
pj_thread_t **thread_ptr)
1021+
{
1022+
return pj_thread_register(cstr_thread_name, desc, thread_ptr);
1023+
}
1024+
9401025
/*
9411026
* pj_thread_destroy()
9421027
*/
9431028
PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
9441029
{
9451030
PJ_CHECK_STACK();
1031+
PJ_ASSERT_RETURN(p, PJ_EINVAL);
9461032

9471033
/* Destroy mutex used to suspend thread */
9481034
if (p->suspended_mutex) {
@@ -1005,7 +1091,13 @@ PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
10051091
{
10061092
char stk_ptr;
10071093
pj_uint32_t usage;
1008-
pj_thread_t *thread = pj_thread_this();
1094+
pj_thread_t *thread;
1095+
1096+
/* may be called after pj_thread_unregister() */
1097+
if (!pj_thread_is_registered())
1098+
return;
1099+
1100+
thread = pj_thread_this();
10091101

10101102
/* Calculate current usage. */
10111103
usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :

0 commit comments

Comments
 (0)