diff options
Diffstat (limited to 'libnetfs')
-rw-r--r-- | libnetfs/drop-node.c | 1 | ||||
-rw-r--r-- | libnetfs/init-init.c | 2 | ||||
-rw-r--r-- | libnetfs/make-node.c | 2 | ||||
-rw-r--r-- | libnetfs/netfs.h | 42 | ||||
-rw-r--r-- | libnetfs/nput.c | 27 | ||||
-rw-r--r-- | libnetfs/nref.c | 10 | ||||
-rw-r--r-- | libnetfs/nrele.c | 37 |
7 files changed, 83 insertions, 38 deletions
diff --git a/libnetfs/drop-node.c b/libnetfs/drop-node.c index 2fe5ce9f..f0d69be9 100644 --- a/libnetfs/drop-node.c +++ b/libnetfs/drop-node.c @@ -25,5 +25,4 @@ netfs_drop_node (struct node *np) { fshelp_drop_transbox (&np->transbox); netfs_node_norefs (np); - pthread_spin_unlock (&netfs_node_refcnt_lock); } diff --git a/libnetfs/init-init.c b/libnetfs/init-init.c index a088ad51..9ca1aacf 100644 --- a/libnetfs/init-init.c +++ b/libnetfs/init-init.c @@ -24,8 +24,6 @@ /* For safe inlining of netfs_node_netnode and netfs_netnode_node. */ size_t const _netfs_sizeof_struct_node = sizeof (struct node); -pthread_spinlock_t netfs_node_refcnt_lock = PTHREAD_SPINLOCK_INITIALIZER; - struct node *netfs_root_node = 0; struct port_bucket *netfs_port_bucket = 0; struct port_class *netfs_protid_class = 0; diff --git a/libnetfs/make-node.c b/libnetfs/make-node.c index 6bd8109c..a292dc62 100644 --- a/libnetfs/make-node.c +++ b/libnetfs/make-node.c @@ -27,7 +27,7 @@ init_node (struct node *np, struct netnode *nn) np->nn = nn; pthread_mutex_init (&np->lock, NULL); - np->references = 1; + refcounts_init (&np->refcounts, 1, 0); np->sockaddr = MACH_PORT_NULL; np->owner = 0; diff --git a/libnetfs/netfs.h b/libnetfs/netfs.h index 67a6a9a0..6c989a48 100644 --- a/libnetfs/netfs.h +++ b/libnetfs/netfs.h @@ -82,8 +82,8 @@ struct node pthread_mutex_t lock; - /* The number of references to this node. */ - int references; + /* Hard and soft references to this node. */ + refcounts_t refcounts; mach_port_t sockaddr; @@ -397,10 +397,6 @@ netfs_netnode_node (struct netnode *netnode) return (struct node *) ((char *) netnode - _netfs_sizeof_struct_node); } -/* Whenever node->references is to be touched, this lock must be - held. Cf. netfs_nrele, netfs_nput, netfs_nref and netfs_drop_node. */ -extern pthread_spinlock_t netfs_node_refcnt_lock; - /* Normally called in main. This function sets up some of the netfs server's internal state. */ void netfs_init (void); @@ -425,22 +421,38 @@ struct protid *netfs_make_protid (struct peropen *po, struct iouser *user); struct peropen *netfs_make_peropen (struct node *, int, struct peropen *context); -/* Add a reference to node NP. Unless you already hold a reference, +/* Add a hard reference to node NP. Unless you already hold a reference, NP must be locked. */ void netfs_nref (struct node *np); -/* Releases a node. Drops a reference to node NP, which must not be - locked by the caller. If this was the last reference, drops the - node. The node cannot be used again without first obtaining a - reference to it. */ +/* Add a light reference to a node. */ +void netfs_nref_light (struct node *np); + +/* Releases a hard reference on NP. If NP is locked by anyone, then + this cannot be the last hard reference (because you must hold a + hard reference in order to hold the lock). If this is the last + hard reference then request soft references to be dropped. */ void netfs_nrele (struct node *np); -/* Puts a node back. Drops a reference to the node NP, which must be - locked by the caller (this lock will be released by netfs_nput). - If this was the last reference, drops the node. The node cannot be - used again without first obtaining a reference to it. */ +/* Release a soft reference on NP. If NP is locked by anyone, then + this cannot be the last reference (because you must hold a hard + reference in order to hold the lock). */ +void netfs_nrele_light (struct node *np); + +/* Puts a node back by releasing a hard reference on NP, which must + be locked by the caller (this lock will be released by netfs_nput). + If this was the last reference, then request soft references to be + dropped. */ void netfs_nput (struct node *np); +/* The user must define this function in order to drop the soft references + that this node may have. When this function is called, node NP has just + lost its hard references and is now trying to also drop its soft references. + If the node is stored in another data structure (for caching purposes), + this allows the user to remove it so that the node can be safely deleted + from memory. */ +void netfs_try_dropping_softrefs (struct node *np); + /* Called internally when no more references to node NP exist. */ void netfs_drop_node (struct node *np); diff --git a/libnetfs/nput.c b/libnetfs/nput.c index 522c714a..b04fc4b0 100644 --- a/libnetfs/nput.c +++ b/libnetfs/nput.c @@ -23,15 +23,24 @@ void netfs_nput (struct node *np) { - pthread_spin_lock (&netfs_node_refcnt_lock); - assert (np->references); - np->references--; - if (np->references == 0) + struct references result; + + refcounts_demote (&np->refcounts, &result); + + if (result.hard == 0) + netfs_try_dropping_softrefs (np); + + refcounts_deref_weak (&np->refcounts, &result); + + if (result.hard == 0 && result.weak == 0) netfs_drop_node (np); - /* netfs_drop_node drops netfs_node_refcnt_lock for us. */ else - { - pthread_spin_unlock (&netfs_node_refcnt_lock); - pthread_mutex_unlock (&np->lock); - } + pthread_mutex_unlock (&np->lock); +} + +/* The last hard reference to NP has gone away; the user must define + this function in order to drop all the soft references. */ +void __attribute__ ((weak)) +netfs_try_dropping_softrefs (struct node *np) +{ } diff --git a/libnetfs/nref.c b/libnetfs/nref.c index 86b49927..a40cf4db 100644 --- a/libnetfs/nref.c +++ b/libnetfs/nref.c @@ -23,7 +23,11 @@ void netfs_nref (struct node *np) { - pthread_spin_lock (&netfs_node_refcnt_lock); - np->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + refcounts_ref (&np->refcounts, NULL); +} + +void +netfs_nref_light (struct node *np) +{ + refcounts_ref_weak (&np->refcounts, NULL); } diff --git a/libnetfs/nrele.c b/libnetfs/nrele.c index 6f9a0144..4dddd1f4 100644 --- a/libnetfs/nrele.c +++ b/libnetfs/nrele.c @@ -23,15 +23,38 @@ void netfs_nrele (struct node *np) { - pthread_spin_lock (&netfs_node_refcnt_lock); - assert (np->references); - np->references--; - if (np->references == 0) + struct references result; + int locked = FALSE; + + refcounts_demote (&np->refcounts, &result); + + if (result.hard == 0) + { + pthread_mutex_lock (&np->lock); + netfs_try_dropping_softrefs (np); + locked = TRUE; + } + + refcounts_deref_weak (&np->refcounts, &result); + + if (result.hard == 0 && result.weak == 0) + { + if (! locked) + pthread_mutex_lock (&np->lock); + netfs_drop_node (np); + } else if (locked) + pthread_mutex_unlock (&np->lock); +} + +void +netfs_nrele_light (struct node *np) +{ + struct references result; + + refcounts_deref_weak (&np->refcounts, &result); + if (result.hard == 0 && result.weak == 0) { pthread_mutex_lock (&np->lock); netfs_drop_node (np); - /* netfs_drop_node drops netfs_node_refcnt_lock for us. */ } - else - pthread_spin_unlock (&netfs_node_refcnt_lock); } |