diff options
Diffstat (limited to 'libports/port-deref.c')
-rw-r--r-- | libports/port-deref.c | 34 |
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); } |