Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 24 Sep 2000 12:53:12 -0700
From:      Alfred Perlstein <bright@wintelcom.net>
To:        Bosko Milekic <bmilekic@technokratis.com>
Cc:        arch@FreeBSD.ORG, cp@FreeBSD.ORG
Subject:   Re: need advice, fsetown annoyances and mpsafeness.
Message-ID:  <20000924125311.Q9141@fw.wintelcom.net>
In-Reply-To: <Pine.BSF.4.21.0009241420280.14398-100000@jehovah.technokratis.com>; from bmilekic@technokratis.com on Sun, Sep 24, 2000 at 02:37:52PM -0400
References:  <20000924103303.M9141@fw.wintelcom.net> <Pine.BSF.4.21.0009241420280.14398-100000@jehovah.technokratis.com>

next in thread | previous in thread | raw e-mail | index | archive | help
* Bosko Milekic <bmilekic@technokratis.com> [000924 11:34] wrote:
> 
> 
> On Sun, 24 Sep 2000, Alfred Perlstein wrote:
> 
> > What it then does is walk through the sigio structs hung from itself
> > and using a back-pointer that points to the pointer within the
> > object (socket/tty) it raises splhigh and NULLs it out, lowers spl,
> > then frees the sigio.
> > 
> >   	s = splhigh();
> > 	*(sigio->sio_myref) = NULL;
> > 	splx(s);
> 
> 	Why can't this be done with an atomic operation? If you're holding
>   the sigio struct, then are you not also ensuring that sigio->sio_myref
>   won't change. Setting the pointer within the object to NULL should be
>   atomic in itself, AFAIK. I'm wondering what would happen if the object is
>   destroyed just before you splhigh() up there (in other words, did you
>   leave something out of the example you posted above?)
> 	Assuming something was left out, then I'm wondering if it would be
>   profitable in this case to distinguish between the nature of the object
>   and optionally provide a pointer to a mutex in the sigio struct which
>   should be aquired in order to do this manipulation.

It's really a lot more evil than you think.

The race is in the object (socket/tty) checking the pointer and
then dereferencing it.

A broken solution is to lock the sigio struct or provide a backreference
to the socket/tty lock, after banging my head against my desk for some time I came across this solution:

(assuming pfind/pgfind return the proc/pgrp locked)

/*
 * called by the owner of a sigio struct such as a tty/socket to remove
 * a struct sigio from itself, called at object destruction or at the
 * the time that sigio/sigurg is no longer wanted/needed
 * it will lock and unlock the proc/pgrp target of the sigio
 */
void
funsetown_obj(sigio)
	struct sigio *sigio;
{
	pid_t	pid;

	if (sigio == NULL)
		return;

	/*
	 * ok this is somewhat tricky, we examine what the sigio is attached
	 * to, whatever it is proc/pgrp we need to use the search functions
	 * to ensure atomicity.  If we get back ESRCH that's ok, that means
	 * we lost the race, just free it.
	 * if we get back a pointer we then need to make sure that the pgid
	 * hasn't been NULLed out because we lost the race between looking
	 * at the sigio and locking the proc/pgrp
	 * (most likely pid/pgid wraparound)
	 */
	pid = sigio->sio_pgid;

	if (pid < 0) {
		struct pgrp *p;

		if ((pgrp = pgfind(pid)) != NULL) {
			/* funsetown_proc would have set this to zero */
			if (sigio->sio_pgid != 0)
				SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio,
					sigio, sio_pgsigio);
			PGRP_UNLOCK(&sigio->sio_pgrp);
		}
	} else if (pid > 0) {
		struct proc *p;

		if ((p = pfind(pid)) != NULL) {
			/* funsetown_proc would have set this to zero */
			if (sigio->sio_pgid != 0)
				SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio,
					sigio, sio_pgsigio);
			PROC_UNLOCK(&sigio->sio_proc);
		}
	}

out:
	crfree(sigio->sio_ucred);
	FREE(sigio, M_SIGIO);
}

/*
 * NULL out a sigio struct attached to a process/pgrp
 * must be called with the object (struct proc/pgrp) locked
 * this is to be called from the perspective of the process/pgrp
 *
 * called from the proc/pgid at teardown
 * proc/pgid must be locked
 */
void
funsetown_proc(sigio)
	struct sigio *sigio;
{
	int s;

	if (sigio == NULL)
		return;
	if (sigio->sio_pgid < 0) {
		SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio,
			     sigio, sio_pgsigio);
	} else /* if ((*sigiop)->sio_pgid > 0) */ {
		SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio,
			     sigio, sio_pgsigio);
	}
	sigio->sio_pgid = 0;
}

/*
 * Free a list of sigio structures.
 *
 * called from the proc/pgid at teardown
 * proc/pgid must be locked
 */
void
funsetownlst(sigiolst)
	struct sigiolst *sigiolst;
{
	struct sigio *sigio;

	while ((sigio = SLIST_FIRST(sigiolst)) != NULL)
		funsetown(sigio);
}



Questions?  Comments?

-- 
-Alfred Perlstein - [bright@wintelcom.net|alfred@freebsd.org]
"I have the heart of a child; I keep it in a jar on my desk."


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20000924125311.Q9141>