The cooperative multitasking model of F#'s async makes good progress in solving your first point. There are essentially two ways of assigning the result of code blocks to variables: doing "let a = foo bar" which runs the code without a yield and "let! a = foo bar" which can yield as required inside foo. So you always know which library functions are safe (and you can even write unsafe ones yourself) and can write cooperative threads very easily (just as easily as usual threads).
Is that a language feature specifically tailored for cooperative multitasking?
That sounds good, except passing an argument ("yielder") that cannot be captured/stored (so you have to take it as an argument) sounds like it would require less language magic to solve the same problem.