aboutsummaryrefslogtreecommitdiff
path: root/libports/port-deref.c
diff options
context:
space:
mode:
Diffstat (limited to 'libports/port-deref.c')
-rw-r--r--libports/port-deref.c34
1 files changed, 16 insertions, 18 deletions
diff --git a/libports/port-deref.c b/libports/port-deref.c
index cf9b2383..b97dd13d 100644
--- a/libports/port-deref.c
+++ b/libports/port-deref.c
@@ -25,26 +25,24 @@ void
ports_port_deref (void *portstruct)
{
struct port_info *pi = portstruct;
- int trieddroppingweakrefs = 0;
-
- retry:
-
- pthread_mutex_lock (&_ports_lock);
-
- if (pi->refcnt == 1 && pi->weakrefcnt
- && pi->class->dropweak_routine && !trieddroppingweakrefs)
+ struct references result;
+
+ if (pi->class->dropweak_routine)
{
- pthread_mutex_unlock (&_ports_lock);
- (*pi->class->dropweak_routine) (pi);
- trieddroppingweakrefs = 1;
- goto retry;
+ /* If we need to call the dropweak routine, we need to hold one
+ reference while doing so. We use a weak reference for this
+ purpose, which we acquire by demoting our hard reference to a
+ weak one. */
+ refcounts_demote (&pi->refcounts, &result);
+
+ if (result.hard == 0 && result.weak > 1)
+ (*pi->class->dropweak_routine) (pi);
+
+ refcounts_deref_weak (&pi->refcounts, &result);
}
-
- assert (pi->refcnt);
+ else
+ refcounts_deref (&pi->refcounts, &result);
- pi->refcnt--;
- if (pi->refcnt == 0 && pi->weakrefcnt == 0)
+ if (result.hard == 0 && result.weak == 0)
_ports_complete_deallocate (pi);
- else
- pthread_mutex_unlock (&_ports_lock);
}