Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 19 Dec 1998 00:44:03 -0800
From:      Don Lewis <Don.Lewis@tsc.tdk.com>
To:        Matthew Dillon <dillon@apollo.backplane.com>, freebsd-current@FreeBSD.ORG
Subject:   Re: asleep()/await(), M_AWAIT, etc...
Message-ID:  <199812190844.AAA11936@salsa.gv.tsc.tdk.com>
In-Reply-To: Matthew Dillon <dillon@apollo.backplane.com> "asleep()/await(), M_AWAIT, etc..." (Dec 17, 12:05am)

next in thread | previous in thread | raw e-mail | index | archive | help
On Dec 17, 12:05am, Matthew Dillon wrote:
} Subject: asleep()/await(), M_AWAIT, etc...

}     We add an await() kernel function.  This function initiates any timeout
}     and puts the process to sleep, but only if it is still on a sleep queue.
}     If someone (i.e. an interrupt) wakes up the sleep address after the
}     process calls asleep() but before it calls await(), the slpque is
}     cleared and the await() winds up being a NOP.

How likely is this to happen if the process doesn't go to sleep for some
other reason inbetween the asleep() and the await()?  The CPU can execute
a *lot* of code in the time it takes for physical I/O to happen.

}     The purpose of the new routines is to allow blocking conditions to
}     propogate up a subroutine chain and get handled at a higher level rather
}     then at a lower level in those areas of code that cannot afford to 
}     leave exclusive locks sitting around.  For example, if bread() blocks
}     waiting for a low level disk I/O on a block device, the vnode remains
}     locked throughout which badly mars potential parallelism when multiple
}     programs are accessing the same file.  There is no reason to leave the
}     high level vnode locked while bringing a page into the VM buffer cache!

What happens if some other process decides to truncate the file while
another process is in the middle of paging in a piece of it?  If there
is no reason to care about this sort of thing, then there is no reason
to hold the lock across the bread(), which would probably be a simple
tweak to the existing code.  I suspect that's not the case.  If you want
to get some parallelism, it might be simpler to implement shared and
exclusive locks.  Operations that can operate in parallel (such as reads)
would use shared locks, whereas some other operations would need to
use exclusive locks.

}     Another example:  If a piece of critically locked code needs to allocate
}     memory but cannot afford to block with the lock intact, we can implement
}     M_AWAIT.  The code would allocate memory using M_AWAIT and if the 
}     allocation fails would be able to unwind the lock(s), await(), and retry.
}     This is something the current code cannot do at all.

Most things that allocate memory want to scribble on it right after they
allocate it.  Using M_AWAIT would take a fair amount of rewriting.  You
can already do something similar without M_AWAIT by using M_NOWAIT.  If
that fails, unwind the lock, use M_WAITOK, and relock the object.  However,
it would probably be cleaner to just do do MALLOC(..., M_WAITOK) before
grabbing the lock, if possible.

There may be cases where this is not possible.  For example, the amount of
the memory you need to allocate depends on the object that you have locked.
If you have the object unlocked while the memory is being allocated, another
process may touch the object while it is unlocked and you'll end up allocating
the wrong amount of memory.  The only scheme that works in this case is
locking the object first and leaving it locked across MALLOC(..., M_WAITOK).


NOTE: some of the softupdates panics before 3.0-RELEASE were caused by
vnodes inadvertently being unlocked and then relocked in some low level
routines, which allowed files to be fiddled with by one process while
another process thought it had exclusive access.

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



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