Tasks with multiple steps

This patch adds an API for creating tasks that consist of multiple
steps, each of which is represented by its own task function (with its
own `ud` and `i` parameters).  You add each step using a separate
function call, which means that the implementations of each step can be
decoupled into separate source files.  That's going to let us implement
“afters” easily, with a separate bookkeeping step whose implementation
is hidden away behind an API.