Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
BC
public
belle-sip
Commits
c620c945
Commit
c620c945
authored
Mar 04, 2013
by
Simon Morlat
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
implement thread-safe garbage collection of unowned objects.
parent
e94fb368
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
209 additions
and
27 deletions
+209
-27
include/belle-sip/belle-sip.h
include/belle-sip/belle-sip.h
+2
-1
include/belle-sip/object.h
include/belle-sip/object.h
+9
-0
include/belle-sip/sipstack.h
include/belle-sip/sipstack.h
+5
-0
src/belle_sip_internal.h
src/belle_sip_internal.h
+4
-1
src/belle_sip_loop.c
src/belle_sip_loop.c
+4
-2
src/belle_sip_object.c
src/belle_sip_object.c
+137
-22
src/port.c
src/port.c
+22
-0
src/port.h
src/port.h
+21
-0
src/sipstack.c
src/sipstack.c
+1
-0
tester/belle_sip_tester.c
tester/belle_sip_tester.c
+4
-1
No files found.
include/belle-sip/belle-sip.h
View file @
c620c945
...
...
@@ -102,7 +102,8 @@ BELLE_SIP_DECLARE_TYPES_BEGIN(belle_sip,1)
BELLE_SIP_TYPE_ID
(
belle_sip_header_refer_to_t
),
BELLE_SIP_TYPE_ID
(
belle_sip_header_referred_by_t
),
BELLE_SIP_TYPE_ID
(
belle_sip_header_replaces_t
),
BELLE_SIP_TYPE_ID
(
belle_sip_hop_t
)
BELLE_SIP_TYPE_ID
(
belle_sip_hop_t
),
BELLE_SIP_TYPE_ID
(
belle_sip_object_pool_t
)
BELLE_SIP_DECLARE_TYPES_END
...
...
include/belle-sip/object.h
View file @
c620c945
...
...
@@ -134,6 +134,8 @@ struct _belle_sip_object{
int
ref
;
char
*
name
;
struct
weak_ref
*
weak_refs
;
struct
belle_sip_object_pool
*
pool
;
struct
_belle_sip_list
*
pool_iterator
;
};
...
...
@@ -305,7 +307,14 @@ typedef struct belle_sip_interface_desc{
}
/**
* Object holding unowned objects - used as a kind of garbage collector for temporary objects.
**/
typedef
struct
belle_sip_object_pool
belle_sip_object_pool_t
;
belle_sip_object_pool_t
*
belle_sip_object_pool_push
(
void
);
void
belle_sip_object_pool_pop
(
void
);
void
belle_sip_object_pool_clean
(
belle_sip_object_pool_t
*
obj
);
#endif
include/belle-sip/sipstack.h
View file @
c620c945
...
...
@@ -76,6 +76,11 @@ BELLESIP_EXPORT void belle_sip_stack_set_resolver_tx_delay(belle_sip_stack_t *st
**/
BELLESIP_EXPORT
void
belle_sip_stack_set_resolver_send_error
(
belle_sip_stack_t
*
stack
,
int
send_error
);
void
belle_sip_stack_push_pool
(
belle_sip_stack_t
*
stack
);
void
belle_sip_stack_pop_pool
(
belle_sip_stack_t
*
stack
);
BELLE_SIP_END_DECLS
#endif
...
...
src/belle_sip_internal.h
View file @
c620c945
...
...
@@ -113,9 +113,11 @@ typedef struct weak_ref{
void
*
belle_sip_object_get_interface_methods
(
belle_sip_object_t
*
obj
,
belle_sip_interface_id_t
ifid
);
void
belle_sip_object_delete_unowned
(
void
);
/*used internally by unref()*/
void
belle_sip_object_delete
(
void
*
obj
);
belle_sip_object_pool_t
*
belle_sip_object_pool_get_current
(
void
);
void
belle_sip_object_pool_add
(
belle_sip_object_pool_t
*
pool
,
belle_sip_object_t
*
obj
);
void
belle_sip_object_pool_remove
(
belle_sip_object_pool_t
*
pool
,
belle_sip_object_t
*
obj
);
#define BELLE_SIP_OBJECT_VPTR(obj,object_type) ((BELLE_SIP_OBJECT_VPTR_TYPE(object_type)*)(((belle_sip_object_t*)obj)->vptr))
...
...
@@ -183,6 +185,7 @@ BELLE_SIP_DECLARE_VPTR(belle_sip_header_refer_to_t);
BELLE_SIP_DECLARE_VPTR
(
belle_sip_header_referred_by_t
);
BELLE_SIP_DECLARE_VPTR
(
belle_sip_header_replaces_t
);
BELLE_SIP_DECLARE_VPTR
(
belle_sip_hop_t
);
BELLE_SIP_DECLARE_VPTR
(
belle_sip_object_pool_t
);
typedef
void
(
*
belle_sip_source_remove_callback_t
)(
belle_sip_source_t
*
);
...
...
src/belle_sip_loop.c
View file @
c620c945
...
...
@@ -230,6 +230,7 @@ belle_sip_socket_t belle_sip_source_get_socket(const belle_sip_source_t* source)
struct
belle_sip_main_loop
{
belle_sip_object_t
base
;
belle_sip_list_t
*
sources
;
belle_sip_object_pool_t
*
pool
;
int
nsources
;
int
run
;
};
...
...
@@ -250,7 +251,7 @@ static void belle_sip_main_loop_destroy(belle_sip_main_loop_t *ml){
while
(
ml
->
sources
){
belle_sip_main_loop_remove_source
(
ml
,(
belle_sip_source_t
*
)
ml
->
sources
->
data
);
}
belle_sip_object_
delete_unowned
();
belle_sip_object_
pool_pop
();
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES
(
belle_sip_main_loop_t
);
...
...
@@ -258,6 +259,7 @@ BELLE_SIP_INSTANCIATE_VPTR(belle_sip_main_loop_t,belle_sip_object_t,belle_sip_ma
belle_sip_main_loop_t
*
belle_sip_main_loop_new
(
void
){
belle_sip_main_loop_t
*
m
=
belle_sip_object_new
(
belle_sip_main_loop_t
);
m
->
pool
=
belle_sip_object_pool_push
();
return
m
;
}
...
...
@@ -411,7 +413,7 @@ void belle_sip_main_loop_iterate(belle_sip_main_loop_t *ml){
}
else
belle_sip_main_loop_remove_source
(
ml
,
s
);
}
belle_sip_list_free_with_data
(
copy
,
belle_sip_object_unref
);
belle_sip_object_
delete_unowned
(
);
belle_sip_object_
pool_clean
(
ml
->
pool
);
}
void
belle_sip_main_loop_run
(
belle_sip_main_loop_t
*
ml
){
...
...
src/belle_sip_object.c
View file @
c620c945
...
...
@@ -18,7 +18,6 @@
#include "belle_sip_internal.h"
static
belle_sip_list_t
*
unowned_objects
=
NULL
;
static
int
has_type
(
belle_sip_object_t
*
obj
,
belle_sip_type_id_t
id
){
belle_sip_object_vptr_t
*
vptr
=
obj
->
vptr
;
...
...
@@ -40,33 +39,20 @@ belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle_sip_object_vptr
obj
->
vptr
=
vptr
;
obj
->
size
=
objsize
;
if
(
obj
->
ref
==
0
){
unowned_objects
=
belle_sip_list_prepend
(
unowned_objects
,
obj
);
belle_sip_object_pool_t
*
pool
=
belle_sip_object_pool_get_current
();
if
(
pool
)
belle_sip_object_pool_add
(
pool
,
obj
);
}
return
obj
;
}
void
belle_sip_object_delete_unowned
(
void
){
belle_sip_list_t
*
elem
,
*
next
;
for
(
elem
=
unowned_objects
;
elem
!=
NULL
;
elem
=
next
){
belle_sip_object_t
*
obj
=
(
belle_sip_object_t
*
)
elem
->
data
;
if
(
obj
->
ref
==
0
){
belle_sip_message
(
"Garbage collecting unowned object of type %s"
,
obj
->
vptr
->
type_name
);
obj
->
ref
=-
1
;
belle_sip_object_delete
(
obj
);
next
=
elem
->
next
;
unowned_objects
=
belle_sip_list_delete_link
(
unowned_objects
,
elem
);
}
else
next
=
elem
->
next
;
}
}
int
belle_sip_object_is_initially_unowned
(
const
belle_sip_object_t
*
obj
){
return
obj
->
vptr
->
initially_unowned
;
}
belle_sip_object_t
*
belle_sip_object_ref
(
void
*
obj
){
belle_sip_object_t
*
o
=
BELLE_SIP_OBJECT
(
obj
);
if
(
o
->
ref
==
0
){
unowned_objects
=
belle_sip_list_remove
(
unowned_objects
,
obj
);
if
(
o
->
ref
==
0
&&
o
->
pool
){
belle_sip_object_pool_remove
(
o
->
pool
,
obj
);
}
o
->
ref
++
;
return
obj
;
...
...
@@ -74,9 +60,9 @@ belle_sip_object_t * belle_sip_object_ref(void *obj){
void
belle_sip_object_unref
(
void
*
ptr
){
belle_sip_object_t
*
obj
=
BELLE_SIP_OBJECT
(
ptr
);
if
(
obj
->
ref
==-
1
)
belle_sip_fatal
(
"Object
of typ
e [%s] freed twice !"
,
obj
->
name
);
if
(
obj
->
ref
==
0
){
unowned_objects
=
belle_sip_list_remove
(
unowned_objects
,
obj
);
if
(
obj
->
ref
==-
1
)
belle_sip_fatal
(
"Object
with nam
e [%s] freed twice !"
,
obj
->
name
);
if
(
obj
->
ref
==
0
&&
obj
->
pool
){
belle_sip_object_pool_remove
(
obj
->
pool
,
obj
);
obj
->
ref
=-
1
;
belle_sip_object_delete
(
obj
);
return
;
...
...
@@ -208,7 +194,8 @@ belle_sip_object_t *belle_sip_object_clone(const belle_sip_object_t *obj){
newobj
->
size
=
obj
->
size
;
_belle_sip_object_copy
(
newobj
,
obj
);
if
(
newobj
->
ref
==
0
){
unowned_objects
=
belle_sip_list_prepend
(
unowned_objects
,
newobj
);
belle_sip_object_pool_t
*
pool
=
belle_sip_object_pool_get_current
();
if
(
pool
)
belle_sip_object_pool_add
(
pool
,
newobj
);
}
return
newobj
;
}
...
...
@@ -361,4 +348,132 @@ char *belle_sip_object_describe_type_from_name(const char *name){
#endif
struct
belle_sip_object_pool
{
belle_sip_object_t
base
;
belle_sip_list_t
*
objects
;
belle_sip_thread_t
thread_id
;
};
static
void
belle_sip_object_pool_destroy
(
belle_sip_object_pool_t
*
pool
){
belle_sip_object_pool_clean
(
pool
);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES
(
belle_sip_object_pool_t
);
BELLE_SIP_INSTANCIATE_VPTR
(
belle_sip_object_pool_t
,
belle_sip_object_t
,
belle_sip_object_pool_destroy
,
NULL
,
NULL
,
FALSE
);
belle_sip_object_pool_t
*
belle_sip_object_pool_new
(
void
){
belle_sip_object_pool_t
*
pool
=
belle_sip_object_new
(
belle_sip_object_pool_t
);
pool
->
thread_id
=
belle_sip_thread_self
();
return
pool
;
}
void
belle_sip_object_pool_add
(
belle_sip_object_pool_t
*
pool
,
belle_sip_object_t
*
obj
){
if
(
obj
->
pool
!=
NULL
){
belle_sip_fatal
(
"It is not possible to add an object to multiple pools."
);
}
pool
->
objects
=
belle_sip_list_prepend
(
pool
->
objects
,
obj
);
obj
->
pool_iterator
=
pool
->
objects
;
obj
->
pool
=
pool
;
}
void
belle_sip_object_pool_remove
(
belle_sip_object_pool_t
*
pool
,
belle_sip_object_t
*
obj
){
belle_sip_thread_t
tid
=
belle_sip_thread_self
();
if
(
obj
->
pool
!=
pool
){
belle_sip_fatal
(
"Attempting to remove object from an incorrect pool: obj->pool=%p, pool=%p"
,
obj
->
pool
,
pool
);
return
;
}
if
(
tid
!=
pool
->
thread_id
){
belle_sip_fatal
(
"It is forbidden (and unsafe()) to ref()/unref() an unowned object outside of the thread that created it."
);
return
;
}
pool
->
objects
=
belle_sip_list_delete_link
(
pool
->
objects
,
obj
->
pool_iterator
);
obj
->
pool_iterator
=
NULL
;
obj
->
pool
=
NULL
;
}
void
belle_sip_object_pool_clean
(
belle_sip_object_pool_t
*
pool
){
belle_sip_list_t
*
elem
,
*
next
;
for
(
elem
=
pool
->
objects
;
elem
!=
NULL
;
elem
=
next
){
belle_sip_object_t
*
obj
=
(
belle_sip_object_t
*
)
elem
->
data
;
if
(
obj
->
ref
==
0
){
belle_sip_message
(
"Garbage collecting unowned object of type %s"
,
obj
->
vptr
->
type_name
);
obj
->
ref
=-
1
;
belle_sip_object_delete
(
obj
);
next
=
elem
->
next
;
belle_sip_free
(
elem
);
}
else
{
belle_sip_fatal
(
"Object %p is in unowned list but with ref count %i, bug."
,
obj
,
obj
->
ref
);
next
=
elem
->
next
;
}
}
pool
->
objects
=
NULL
;
}
static
void
cleanup_pool_stack
(
void
*
data
){
belle_sip_list_t
**
pool_stack
=
(
belle_sip_list_t
**
)
data
;
belle_sip_list_free_with_data
(
*
pool_stack
,
belle_sip_object_unref
);
belle_sip_message
(
"Object pools for thread [%u] cleaned while exiting"
,(
unsigned
long
)
belle_sip_thread_self
());
*
pool_stack
=
NULL
;
belle_sip_free
(
pool_stack
);
}
static
belle_sip_list_t
**
get_current_pool_stack
(
void
){
static
belle_sip_thread_key_t
pools_key
;
static
int
pools_key_created
=
0
;
belle_sip_list_t
**
pool_stack
;
if
(
!
pools_key_created
){
pools_key_created
=
1
;
if
(
belle_sip_thread_key_create
(
&
pools_key
,
cleanup_pool_stack
)
!=
0
){
return
NULL
;
}
}
pool_stack
=
(
belle_sip_list_t
**
)
belle_sip_thread_getspecific
(
pools_key
);
if
(
pool_stack
==
NULL
){
pool_stack
=
belle_sip_new
(
belle_sip_list_t
*
);
*
pool_stack
=
NULL
;
belle_sip_thread_setspecific
(
pools_key
,
pool_stack
);
}
return
pool_stack
;
}
belle_sip_object_pool_t
*
belle_sip_object_pool_push
(
void
){
belle_sip_list_t
**
pools
=
get_current_pool_stack
();
belle_sip_object_pool_t
*
pool
;
if
(
pools
==
NULL
)
{
belle_sip_error
(
"Not possible to create a pool."
);
return
NULL
;
}
pool
=
belle_sip_object_pool_new
();
*
pools
=
belle_sip_list_prepend
(
*
pools
,
pool
);
return
pool
;
}
void
belle_sip_object_pool_pop
(
void
){
belle_sip_list_t
**
pools
=
get_current_pool_stack
();
belle_sip_object_pool_t
*
pool
;
if
(
pools
==
NULL
)
{
belle_sip_error
(
"Not possible to pop a pool."
);
return
;
}
if
(
*
pools
==
NULL
){
belle_sip_error
(
"There is no current pool in stack."
);
return
;
}
pool
=
(
belle_sip_object_pool_t
*
)(
*
pools
)
->
data
;
*
pools
=
belle_sip_list_remove_link
(
*
pools
,
*
pools
);
belle_sip_object_unref
(
pool
);
}
belle_sip_object_pool_t
*
belle_sip_object_pool_get_current
(
void
){
belle_sip_list_t
**
pools
=
get_current_pool_stack
();
if
(
pools
==
NULL
)
return
NULL
;
if
(
*
pools
==
NULL
){
belle_sip_warning
(
"There is no object pool created. Use belle_sip_stack_push_pool() to create one. Unowned objects not unref'd will be leaked."
);
return
NULL
;
}
return
(
belle_sip_object_pool_t
*
)(
*
pools
)
->
data
;
}
src/port.c
View file @
c620c945
...
...
@@ -68,6 +68,28 @@ const char *belle_sip_get_socket_error_string_from_code(int code){
return
(
const
char
*
)
msgBuf
;
}
int
belle_sip_thread_key_create
(
belle_sip_thread_key_t
*
key
,
void
(
*
destructor
)(
void
*
)
){
*
key
=
TlsAlloc
();
if
(
*
key
==
TLS_OUT_OF_INDEXES
){
belle_sip_error
(
"TlsAlloc(): TLS_OUT_OF_INDEXES."
);
return
-
1
;
}
return
0
;
}
int
belle_sip_thread_setspecific
(
belle_sip_thread_key_t
key
,
const
void
*
value
){
return
TlsSetValue
(
key
,
value
)
?
0
:
-
1
;
}
const
void
*
belle_sip_thread_getspecific
(
belle_sip_thread_key_t
key
){
return
TlsGetValue
(
key
);
}
int
belle_sip_thread_key_delete
(
belle_sip_thread_key_t
key
){
return
TlsFree
(
key
)
?
0
:
-
1
;
}
#ifdef WINAPI_FAMILY_PHONE_APP
void
belle_sip_sleep
(
unsigned
int
ms
)
{
HANDLE
sleepEvent
=
CreateEventEx
(
NULL
,
NULL
,
CREATE_EVENT_MANUAL_RESET
,
EVENT_ALL_ACCESS
);
...
...
src/port.h
View file @
c620c945
...
...
@@ -28,6 +28,7 @@
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <pthread.h>
#else
...
...
@@ -72,6 +73,17 @@ int belle_sip_socket_set_nonblocking (belle_sip_socket_t sock);
#if defined(WIN32)
typedef
HANDLE
belle_sip_thread_t
;
#define belle_sip_thread_self() GetCurrentThread()
typedef
DWORD
belle_sip_thread_key_t
;
int
belle_sip_thread_key_create
(
belle_sip_thread_key_t
*
key
,
void
(
*
destructor
)(
void
*
)
);
int
belle_sip_thread_setspecific
(
belle_sip_thread_key_t
key
,
const
void
*
value
);
const
void
*
belle_sip_thread_getspecific
(
belle_sip_thread_key_t
key
);
int
belle_sip_thread_key_delete
(
belle_sip_thread_key_t
key
);
static
inline
void
close_socket
(
belle_sip_socket_t
s
){
closesocket
(
s
);
}
...
...
@@ -100,6 +112,15 @@ static inline int inet_aton(const char *ip, struct in_addr *p){
#else
typedef
pthread_t
belle_sip_thread_t
;
#define belle_sip_thread_self() pthread_self()
typedef
pthread_key_t
belle_sip_thread_key_t
;
#define belle_sip_thread_key_create(key,destructor) pthread_key_create(key,destructor)
#define belle_sip_thread_setspecific(key,value) pthread_setspecific(key,value)
#define belle_sip_thread_getspecific(key) pthread_getspecific(key)
#define belle_sip_thread_key_delete(key) pthread_key_delete(key)
static
inline
void
close_socket
(
belle_sip_socket_t
s
){
close
(
s
);
}
...
...
src/sipstack.c
View file @
c620c945
...
...
@@ -164,3 +164,4 @@ void belle_sip_stack_set_resolver_send_error(belle_sip_stack_t *stack, int send_
const
char
*
belle_sip_version_to_string
()
{
return
PACKAGE_VERSION
;
}
tester/belle_sip_tester.c
View file @
c620c945
...
...
@@ -129,7 +129,8 @@ int belle_sip_tester_run_tests(const char *suite_name, const char *test_name) {
for
(
i
=
0
;
i
<
belle_sip_tester_nb_test_suites
();
i
++
)
{
run_test_suite
(
test_suite
[
i
]);
}
belle_sip_object_pool_push
();
#if HAVE_CU_GET_SUITE
if
(
suite_name
){
CU_pSuite
suite
;
...
...
@@ -157,6 +158,8 @@ int belle_sip_tester_run_tests(const char *suite_name, const char *test_name) {
}
}
belle_sip_object_pool_pop
();
CU_cleanup_registry
();
return
CU_get_error
();
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment