Coroutines don't require copying anywhere. Creating a coroutine can be done in a couple of instructions (allocate a new stack and set the top of the stack to the code of the coroutine), and yielding is also just a few instructions (mov a new stack pointer and return).
Essentially if you view coroutines and continuations as data structures then continuations are a functional / non destructive version of coroutines, and like other functional data structures they are slower.
I don't know how Ruby fibers are implemented but they seem to have coroutine semantics, so they are probably very efficient as well.
Adapting a callback library to coroutines is very simple. You have a user coroutine that runs the user code, and you have a system coroutine that manages the resource that calls you back when it's ready (e.g. downloading a web page). When the user code requests something from the resource it yields to the system coroutine. When the system has the response ready the system yields to the user code again.
This is nearly the same for continuations, the difference is that yielding involves copying the stack of the continuation that is yielded to.
And it appears that Ilya (the OP) has been looking at this approach using fibers too http://www.igvita.com/2010/03/22/untangling-evented-code-wit... - and the comment thread on the OP suggests that this is in use at Postrank.