Commit 1bc81fbe authored by Pekka Pessi's avatar Pekka Pessi

Using su_home_t reference counting in nua.

darcs-hash:20060110140603-65a35-1fc0af7c610f8c52c910ed763d13acf716e5f223.gz
parent be8a1fb7
......@@ -1404,7 +1404,6 @@ void nua_handle_destroy(nua_handle_t *nh)
}
/*# Send a request to the protocol thread */
void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
nua_event_t event,
......@@ -1440,12 +1439,12 @@ void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
e->e_always = always;
e->e_event = event;
e->e_nh = nh_incref(nh);
e->e_nh = nua_handle_ref(nh);
e->e_status = status;
e->e_phrase = phrase;
if (su_msg_send(sumsg) != 0)
nh_decref(nh);
nua_handle_unref(nh);
}
else {
assert(0);
......@@ -1462,15 +1461,16 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
enter;
if (nh && nh != nh->nh_nua->nua_handles) {
if (nh && !NH_IS_DEFAULT(nh)) {
if (!nh->nh_ref_by_user && nh->nh_valid) {
nh->nh_ref_by_user = 1;
nh_incref(nh);
nua_handle_ref(nh);
}
}
if (!nh || !nh->nh_valid) { /* Handle has been destroyed */
if (nh && nh != nh->nh_nua->nua_handles && nh_decref(nh)) {
if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
SU_DEBUG_9(("nua(%p): freed by application\n", nh));
}
if (e->e_msg)
......@@ -1505,7 +1505,7 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
if (e->e_msg)
msg_destroy(e->e_msg);
if (nh && nh != nh->nh_nua->nua_handles && nh_decref(nh)) {
if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
SU_DEBUG_9(("nua(%p): freed by application\n", nh));
}
......@@ -1542,7 +1542,7 @@ void nua_destroy_event(nua_saved_event_t saved[1])
if (e->e_msg)
msg_destroy(e->e_msg);
if (nh && nh != nh->nh_nua->nua_handles && nh_decref(nh)) {
if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
SU_DEBUG_9(("nua(%p): freed by application\n", nh));
}
......
......@@ -214,6 +214,12 @@ nua_handle_t *nua_handle(nua_t *nua, nua_hmagic_t *hmagic,
/** Destroy a handle */
void nua_handle_destroy(nua_handle_t *h);
/** Make a new reference to handle */
nua_handle_t *nua_handle_ref(nua_handle_t *);
/** Destroy reference to handle */
int nua_handle_unref(nua_handle_t *);
/** Bind a callback context to an operation handle. */
void nua_handle_bind(nua_handle_t *nh, nua_hmagic_t *magic);
......
......@@ -147,14 +147,6 @@ nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic,
p_to = (void *)-1;
}
#if defined(HAVE_PTHREAD_H) && defined(SU_HAVE_PTHREADS)
#if __CYGWIN__
SU_PORT_INITREF(nh);
#else
pthread_rwlock_init(nh->nh_refcount, NULL);
#endif
#endif
nh->nh_valid = nua_handle;
nh->nh_nua = nua;
nh->nh_magic = hmagic;
......@@ -167,11 +159,49 @@ nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic,
SIPTAG_FROM_REF(nh->nh_ds->ds_local),
SIPTAG_TO_REF(nh->nh_ds->ds_remote),
TAG_END());
/* This far, we have nothing to destruct */
/* su_home_desctructor(nh, nh_destructor); */
if (su_home_is_threadsafe(nua->nua_home)) {
if (su_home_threadsafe(nh->nh_home) < 0) {
su_home_unref(nh->nh_home);
nh = NULL;
}
}
}
return nh_incref(nh);
return nh;
}
#if 0
/* nua handle destructor. It does nothing. */
static void nh_destructor(void *arg)
{
nua_handle_t *nh = arg;
/* Xyzzy */
(void)nh;
}
#endif
/** Make a new reference to handle.
*
* @note All handle references are destroyed when the nua object is destroyed.
*/
nua_handle_t *nua_handle_ref(nua_handle_t *nh)
{
return (nua_handle_t *)su_home_ref(nh->nh_home);
}
/** Destroy reference to handle. */
int nua_handle_unref(nua_handle_t *nh)
{
return su_home_unref(nh->nh_home);
}
/** Get name for a NUA event. */
char const *nua_event_name(nua_event_t event)
{
......@@ -243,6 +273,7 @@ char const *nua_callstate_name(enum nua_callstate state)
{
switch (state) {
case nua_callstate_init: return "init";
case nua_callstate_authenticating: return "authenticating";
case nua_callstate_calling: return "calling";
case nua_callstate_proceeding: return "proceeding";
case nua_callstate_completing: return "completing";
......@@ -255,4 +286,3 @@ char const *nua_callstate_name(enum nua_callstate state)
default: return "UNKNOWN";
}
}
......@@ -236,25 +236,18 @@ int ua_init(su_root_t *root, nua_t *nua)
dnh = su_home_clone(home, sizeof (*dnh) + sizeof(*dnhp));
if (!dnh)
return -1;
nua_handle_ref(dnh);
nua->nua_root = root;
nua->nua_handles_tail = &nua->nua_handles;
nh_append(nua, dnh);
#if defined(HAVE_PTHREAD_H) && defined(SU_HAVE_PTHREADS)
#if __CYGWIN__
SU_PORT_INITREF(dnh);
#else
pthread_rwlock_init(dnh->nh_refcount, NULL);
#endif
#endif
dnh->nh_valid = nua_handle;
dnh->nh_nua = nua;
dnh->nh_ds->ds_local = sip_from_init(nua->nua_from);
dnh->nh_ds->ds_remote = nua->nua_from;
nh_incref(dnh); dnh->nh_ref_by_stack = 1;
nh_incref(dnh); dnh->nh_ref_by_user = 1;
dnh->nh_ref_by_stack = 1; dnh->nh_ref_by_user = 1;
dnh->nh_prefs = dnhp = (void *)(dnh + 1);
......@@ -593,13 +586,13 @@ int ua_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
assert(t == t_end); assert(b == end);
e->e_event = event;
e->e_nh = nh ? nh_incref(nh) : nua->nua_dhandle;
e->e_nh = nh ? nua_handle_ref(nh) : nua->nua_dhandle;
e->e_status = status;
e->e_phrase = strcpy(end, phrase ? phrase : "");
e->e_msg = msg;
if (su_msg_send(sumsg) != 0)
nh_decref(nh);
nua_handle_unref(nh);
}
ta_end(ta);
......@@ -634,7 +627,7 @@ void ua_signal(nua_t *nua, su_msg_r msg, nua_event_data_t *e)
nh_append(nua, nh);
if (!nh->nh_ref_by_stack) {
nh->nh_ref_by_stack = 1;
nh_incref(nh);
nua_handle_ref(nh);
}
}
......@@ -734,7 +727,7 @@ void ua_signal(nua_t *nua, su_msg_r msg, nua_event_data_t *e)
su_msg_destroy(nua->nua_signal);
if (nh != nua->nua_dhandle)
nh_decref(nh);
nua_handle_unref(nh);
}
/* ====================================================================== */
......@@ -743,7 +736,7 @@ static int nh_call_pending(nua_handle_t *nh, sip_time_t time);
/** Timer routine.
*
* Go through all handles and execute pending tasks
* Go through all active handles and execute pending tasks
*/
void ua_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a)
{
......@@ -780,7 +773,7 @@ int nh_call_pending(nua_handle_t *nh, sip_time_t now)
if (du == NULL)
return 0;
nh_incref(nh);
nua_handle_ref(nh);
while (du) {
nh_pending_f *pending = du->du_pending;
......@@ -805,7 +798,7 @@ int nh_call_pending(nua_handle_t *nh, sip_time_t now)
}
}
nh_decref(nh);
nua_handle_unref(nh);
return 1;
}
......@@ -1439,6 +1432,24 @@ nua_handle_t *nh_validate(nua_t *nua, nua_handle_t *maybe)
return NULL;
}
static void
ua_destroy(nua_t *nua, nua_handle_t *nh, tagi_t const *tags)
{
nh_call_pending(nh, 0); /* Call pending operations with 0 */
if (nh->nh_notifier)
ua_terminate(nua, nh, 0, NULL);
#if 0
if (nh->nh_ref_by_user) {
nh->nh_ref_by_user = 0;
nua_handle_unref(nh);
}
#endif
nh_destroy(nua, nh);
}
#define nh_is_inserted(nh) ((nh)->nh_prev != NULL)
/** Remove a handle from list of handles */
......@@ -1458,6 +1469,7 @@ void nh_remove(nua_t *nua, nua_handle_t *nh)
nh->nh_next = NULL;
}
static
void nh_destroy(nua_t *nua, nua_handle_t *nh)
{
......@@ -1487,7 +1499,7 @@ void nh_destroy(nua_t *nua, nua_handle_t *nh)
if (nh_is_inserted(nh))
nh_remove(nua, nh);
nh_decref(nh);
nua_handle_unref(nh); /* Remove stack reference */
}
static
......@@ -2451,7 +2463,7 @@ dialog_usage_add(nua_handle_t *nh,
nh, dialog_usage_name(du),
event ? " with event " : "", event ? event->o_type :""));
nh_incref(nh);
nua_handle_ref(nh);
return ds->ds_usage = du;
}
......@@ -2543,7 +2555,7 @@ dialog_usage_remove_at(nua_handle_t *nh,
break;
}
nh_decref(nh);
nua_handle_unref(nh);
su_free(nh->nh_home, du);
}
......@@ -4901,8 +4913,8 @@ nh_referral_check(nua_t *nua, nua_handle_t *nh, tagi_t const *tags)
if (ref_handle != ref->ref_handle) {
if (ref->ref_handle)
nh_decref(ref->ref_handle);
ref->ref_handle = nh_incref(ref_handle);
nua_handle_unref(ref->ref_handle);
ref->ref_handle = nua_handle_ref(ref_handle);
}
#if 0
......@@ -4960,7 +4972,7 @@ nh_referral_respond(nua_handle_t *nh, unsigned status, char const *phrase)
su_free(nh->nh_home, ref->ref_event), ref->ref_event = NULL;
nh_decref(ref->ref_handle), ref->ref_handle = NULL;
nua_handle_unref(ref->ref_handle), ref->ref_handle = NULL;
}
......@@ -7111,22 +7123,3 @@ ua_respond(nua_t *nua, nua_handle_t *nh,
500, "Responding to a Non-Existing Request", TAG_END());
}
}
/* ======================================================================== */
/* Destroy a handle */
static void
ua_destroy(nua_t *nua, nua_handle_t *nh, tagi_t const *tags)
{
nh_call_pending(nh, 0);
if (nh->nh_notifier)
ua_terminate(nua, nh, 0, NULL);
if (nh->nh_ref_by_user) {
nh->nh_ref_by_user = 0;
nh_decref(nh);
}
nh_destroy(nua, nh);
}
......@@ -60,36 +60,6 @@
#define SU_LOG (nua_log)
#include <su_debug.h>
#if __CYGWIN__
#if defined(SU_HAVE_PTHREADS) && defined(HAVE_PTHREAD_H)
/* Debugging versions */
#define SU_PORT_INITREF(p) (pthread_mutex_init((p)->sup_reflock, NULL), printf("initref(%p)\n", (p)))
#define SU_PORT_INCREF(p, f) (pthread_mutex_lock(p->sup_reflock), p->sup_ref++, pthread_mutex_unlock(p->sup_reflock), printf("incref(%p) by %s\n", (p), f))
#define SU_PORT_DECREF(p, f) do { \
pthread_mutex_lock(p->sup_reflock); p->sup_ref--; pthread_mutex_unlock(p->sup_reflock); \
if ((p->sup_ref) == 0) { \
SU_DEBUG_9(("nua(%p): zapped\n", nh)); \
su_home_zap(p->nh_home); } \
else { printf("decref(%p) to %u by %s\n", (p), p->sup_ref, f); } } while(0)
#define SU_PORT_ZAPREF(p, f) do { printf("zapref(%p) by %s\n", (p), f), \
pthread_mutex_lock(p->sup_reflock); p->sup_ref--; pthread_mutex_unlock(p->sup_reflock); \
if ((p->sup_ref) != 0) { \
assert(!"SU_PORT_ZAPREF"); } \
su_port_destroy(p); } while(0)
#define SU_PORT_INITLOCK(p) \
(pthread_mutex_init((p)->sup_mutex, NULL), printf("init_lock(%p)\n", p))
#define SU_PORT_LOCK(p, f) \
(printf("%ld at %s locking(%p)...", pthread_self(), f, p), pthread_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", pthread_self(), f, p))
#define SU_PORT_UNLOCK(p, f) \
(pthread_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", pthread_self(), f, p))
#endif /* defined(SU_HAVE_PTHREAD) && defined(HAVE_PTHREAD_H) */
#endif /* __CYGWIN__ */
SOFIA_BEGIN_DECLS
#if HAVE_SIGCOMP
......@@ -512,6 +482,8 @@ struct nua_handle_s
(nh)->nh_phrase, \
SIPTAG_WARNING_STR(nh->nh_warning)
#define NH_IS_DEFAULT(nh) ((nh) == (nh)->nh_nua->nua_handles)
extern char const nua_500_error[];
#define NUA_500_ERROR 500, nua_500_error
......@@ -594,71 +566,6 @@ struct nua_s {
#define __func__ "nua"
#endif
/*# Increase reference count by one.
*
* Reference conting works pretty simple. Currently, application can have a
* single reference to a handle, stack can keep multiple references. When
* application creates a handle, it gets a reference to it. When such a
* handle is sent to stack, stack checks the nh_ref_by_stack and makes sure
* that it has a reference. Likewise, when stack creates a handle, and it is
* sent to application, the application side of nua checks nh_ref_by_appl
* and increases the reference count if needed.
*
* When application calls nua_handle_destroy(), it marks the handle as
* invalid, sends a nua_r_destroy signal to stack and decreases its
* reference count.
*
*/
static inline
nua_handle_t *nh_incref(nua_handle_t *nh)
{
nh_enter;
if (nh) {
#if HAVE_PTHREAD_H
#if __CYGWIN__
SU_PORT_INCREF(nh, (char *) NULL);
#else
pthread_rwlock_rdlock(nh->nh_refcount);
#endif
#else
nh->nh_refcount++; /* XXX */
#endif
}
return nh;
}
/*# Decrease reference count by one, return false if no more references */
static inline
int nh_decref(nua_handle_t *nh)
{
nh_enter;
if (nh == NULL)
return 1;
#if HAVE_PTHREAD_H
#if __CYGWIN__
SU_PORT_DECREF(nh, (char *) NULL);
#else
pthread_rwlock_unlock(nh->nh_refcount);
if (pthread_rwlock_trywrlock(nh->nh_refcount) == 0) {
SU_DEBUG_9(("nua(%p): zapped\n", nh));
su_home_zap(nh->nh_home);
return 0;
}
#endif
return 1;
#else
if (--nh->nh_refcount == 0) {
SU_DEBUG_9(("nua(%p): zapped\n", nh));
su_home_zap(nh->nh_home);
}
return 1;
#endif
}
/* Internal prototypes */
int ua_init(su_root_t *root, nua_t *nua);
void ua_deinit(su_root_t *root, nua_t *nua);
......
......@@ -725,6 +725,12 @@ int test_params(struct context *ctx)
TEST_1(ctx->a.nua);
nh = nua_handle(ctx->a.nua, NULL, TAG_END()); TEST_1(nh);
nua_handle_unref(nh);
nh = nua_handle(ctx->a.nua, NULL, TAG_END()); TEST_1(nh);
nua_handle_destroy(nh);
from = sip_from_make(tmphome, Alice);
nh = nua_handle(ctx->a.nua, NULL, TAG_END());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment