static void unp_disconnect(struct unpcb *);
static void unp_shutdown(struct unpcb *);
static void unp_drop(struct unpcb *, int);
-static void unp_gc(void);
+__private_extern__ void unp_gc(void);
static void unp_scan(struct mbuf *, void (*)(struct fileglob *));
static void unp_mark(struct fileglob *);
static void unp_discard(struct fileglob *);
* gets them (resulting in a "panic: closef: count < 0").
*/
sorflush(unp->unp_socket);
+
+ /* Per domain mutex deadlock avoidance */
+ socket_unlock(unp->unp_socket, 0);
unp_gc();
+ socket_lock(unp->unp_socket, 0);
}
if (unp->unp_addr)
FREE(unp->unp_addr, M_SONAME);
}
static int unp_defer, unp_gcing, unp_gcwait;
+static thread_t unp_gcthread = NULL;
/* always called under uipc_lock */
void
unp_gc_wait(void)
{
+ if (unp_gcthread == current_thread())
+ return;
+
while (unp_gcing != 0) {
unp_gcwait = 1;
msleep(&unp_gcing, uipc_lock, 0 , "unp_gc_wait", NULL);
}
-static void
+__private_extern__ void
unp_gc(void)
{
struct fileglob *fg, *nextfg;
struct socket *so;
- struct fileglob **extra_ref, **fpp;
+ static struct fileglob **extra_ref;
+ struct fileglob **fpp;
int nunref, i;
int need_gcwakeup = 0;
}
unp_gcing = 1;
unp_defer = 0;
+ unp_gcthread = current_thread();
lck_mtx_unlock(uipc_lock);
/*
* before going through all this, set all FDs to
* to see if we hold any file descriptors in its
* message buffers. Follow those links and mark them
* as accessible too.
+ *
+ * In case a file is passed onto itself we need to
+ * release the file lock.
*/
- unp_scan(so->so_rcv.sb_mb, unp_mark);
lck_mtx_unlock(&fg->fg_lock);
+
+ unp_scan(so->so_rcv.sb_mb, unp_mark);
}
} while (unp_defer);
/*
tfg = *fpp;
if (tfg->fg_type == DTYPE_SOCKET && tfg->fg_data != NULL) {
- int locked = 0;
-
so = (struct socket *)(tfg->fg_data);
- /* XXXX */
- /* Assume local sockets use a global lock */
- if (so->so_proto->pr_domain->dom_family != PF_LOCAL) {
- socket_lock(so, 0);
- locked = 1;
- }
+ socket_lock(so, 0);
+
sorflush(so);
- if (locked)
- socket_unlock(so, 0);
+ socket_unlock(so, 0);
}
}
for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
lck_mtx_lock(uipc_lock);
unp_gcing = 0;
+ unp_gcthread = NULL;
if (unp_gcwait != 0) {
unp_gcwait = 0;