patch-1.3.78 linux/net/unix/garbage.c
Next file: linux/scripts/Configure
Previous file: linux/net/unix/af_unix.c
Back to the patch index
Back to the overall index
- Lines: 271
- Date:
Mon Mar 25 08:58:28 1996
- Orig file:
v1.3.77/linux/net/unix/garbage.c
- Orig date:
Tue Mar 5 10:11:16 1996
diff -u --recursive --new-file v1.3.77/linux/net/unix/garbage.c linux/net/unix/garbage.c
@@ -1,13 +1,38 @@
/*
- * NET3: Garbage Collector For AF_UNIX sockets (STUB)
+ * NET3: Garbage Collector For AF_UNIX sockets (STUBS)
*
- * Authors:
+ * Garbage Collector:
+ * Copyright (C) Barak A. Pearlmutter.
+ * Released under the GPL version 2 or later.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- * Fixes:
+ * NOTE:
+ * We don't actually call this yet. I'm finishing some tests before I
+ * enable it. The bold can add it in themselves.
+ *
+ * Chopped about by Alan Cox 22/3/96 to make it fit the AF_UNIX socket problem.
+ * If it doesnt work blame me, it worked when Barak sent it.
+ *
+ * Assumptions:
+ *
+ * - object w/ a bit
+ * - free list
+ *
+ * Current optimizations:
+ *
+ * - explicit stack instead of recursion
+ * - tail recurse on first born instead of immediate push/pop
+ *
+ * Future optimizations:
+ *
+ * - don't just push entire root set; process in place
+ * - use linked list for internal stack
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
*
*/
@@ -35,19 +60,218 @@
#include <net/tcp.h>
#include <net/af_unix.h>
#include <linux/proc_fs.h>
+
+/* Internal data structures and random procedures: */
+
+#define MAX_STACK 1000 /* Maximum depth of tree (about 1 page) */
+static unix_socket **stack; /* stack of objects to mark */
+static int in_stack = 0; /* first free entry in stack */
+
+
+extern inline unix_socket *unix_get_socket(struct file *filp)
+{
+ struct socket *s;
+ /*
+ * Socket ?
+ */
+ if(filp->f_inode->i_mode!=S_IFSOCK)
+ return NULL;
+ s=&(filp->f_inode->u.socket_i);
+ /*
+ * AF_UNIX ?
+ */
+ if(s->ops!=&unix_proto_ops)
+ return NULL;
+ /*
+ * Got one.
+ */
+ return s->data;
+}
+
+/*
+ * Keep the number of times in flight count for the file
+ * descriptor if it is for an AF_UNIX socket.
+ */
+
+void unix_inflight(struct file *fp)
+{
+ unix_socket *s=unix_get_socket(fp);
+ if(s)
+ s->protinfo.af_unix.inflight++;
+}
+
+void unix_notinflight(struct file *fp)
+{
+ unix_socket *s=unix_get_socket(fp);
+ if(s)
+ s->protinfo.af_unix.inflight--;
+}
+
+
/*
- * Garbage Collector Stubs
+ * Garbage Collector Support Functions
*/
+extern inline void push_stack(unix_socket *x)
+{
+ if (in_stack == MAX_STACK)
+ panic("can't push onto full stack");
+ stack[in_stack++] = x;
+}
-int unix_gc_free=128; /* GC slots free */
+extern inline unix_socket *pop_stack(void)
+{
+ if (in_stack == 0)
+ panic("can't pop empty gc stack");
+ return stack[--in_stack];
+}
+
+extern inline int empty_stack(void)
+{
+ return in_stack == 0;
+}
-void unix_gc_remove(struct file *fp)
+extern inline void maybe_mark_and_push(unix_socket *x)
{
- ;
+ if (x->protinfo.af_unix.marksweep&MARKED)
+ return;
+ x->protinfo.af_unix.marksweep|=MARKED;
+ push_stack(x);
}
-void unix_gc_add(struct sock *sk, struct file *fp)
+
+/* The external entry point: unix_gc() */
+
+void unix_gc(void)
{
- ;
+ static int in_unix_gc=0;
+ unix_socket *s;
+ unix_socket *next;
+
+ /*
+ * Avoid a recursive GC.
+ */
+
+ if(in_unix_gc)
+ return;
+ in_unix_gc=1;
+
+ stack=(unix_socket **)get_free_page(GFP_KERNEL);
+
+ /*
+ * Assume everything is now unmarked
+ */
+
+ /* Invariant to be maintained:
+ - everything marked is either:
+ -- (a) on the stack, or
+ -- (b) has all of its children marked
+ - everything on the stack is always marked
+ - nothing is ever pushed onto the stack twice, because:
+ -- nothing previously marked is ever pushed on the stack
+ */
+
+ /*
+ * Push root set
+ */
+
+ for(s=unix_socket_list;s!=NULL;s=s->next)
+ {
+ /*
+ * If all instances of the descriptor are not
+ * in flight we are in use.
+ */
+ if(s->socket && s->socket->file && s->socket->file->f_count > s->protinfo.af_unix.inflight)
+ maybe_mark_and_push(s);
+ }
+
+ /*
+ * Mark phase
+ */
+
+ while (!empty_stack())
+ {
+ unix_socket *x = pop_stack();
+ unix_socket *f=NULL,*sk;
+ struct sk_buff *skb;
+tail:
+ skb=skb_peek(&x->receive_queue);
+
+ /*
+ * Loop through all but first born
+ */
+
+ while(skb && skb != (struct sk_buff *)&x->receive_queue)
+ {
+ /*
+ * Do we have file descriptors ?
+ */
+ if(skb->h.filp)
+ {
+ /*
+ * Process the descriptors of this socket
+ */
+ int nfd=*(int *)skb->h.filp;
+ struct file **fp=(struct file **)(skb->h.filp+sizeof(int));
+ while(nfd--)
+ {
+ /*
+ * Get the socket the fd matches if
+ * it indeed does so
+ */
+ if((sk=unix_get_socket(*fp++))!=NULL)
+ {
+ /*
+ * Remember the first, mark the
+ * rest.
+ */
+ if(f==NULL)
+ f=sk;
+ else
+ maybe_mark_and_push(sk);
+ }
+ }
+ }
+ skb=skb->next;
+ }
+ /*
+ * Handle first born specially
+ */
+
+ if (f)
+ {
+ if (!(f->protinfo.af_unix.marksweep&MARKED))
+ {
+ f->protinfo.af_unix.marksweep|=MARKED;
+ x=f;
+ f=NULL;
+ goto tail;
+ }
+ }
+ }
+
+ /*
+ * Sweep phase. NOTE: this part dominates the time complexity
+ */
+
+ for(s=unix_socket_list;s!=NULL;s=next)
+ {
+ next=s->next;
+ if (!(s->protinfo.af_unix.marksweep&MARKED))
+ {
+ /*
+ * We exist only in the passing tree of sockets
+ * that is no longer connected to active descriptors
+ * Time to die..
+ */
+ if(s->socket && s->socket->file)
+ close_fp(s->socket->file);
+ }
+ else
+ s->protinfo.af_unix.marksweep&=~MARKED; /* unmark everything for next collection */
+ }
+
+ in_unix_gc=0;
+
+ free_page((long)stack);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this