Handle the operation:

        * if coro is in STATE_RUNNING, send or throw the given op

        * if coro is in STATE_NEED_INIT, call the init function and if it
          doesn't return a generator, set STATE_COMPLETED and set the result
          to whatever the function returned.

          * if StopIteration is raised, set STATE_COMPLETED and return self.

          * if any other exception is raised, set STATE_FAILED, handle error
            or send it to the caller, return self

def run_op(self, op, sched):
        """
        Handle the operation:

        * if coro is in STATE_RUNNING, send or throw the given op

        * if coro is in STATE_NEED_INIT, call the init function and if it
          doesn't return a generator, set STATE_COMPLETED and set the result
          to whatever the function returned.

          * if StopIteration is raised, set STATE_COMPLETED and return self.

          * if any other exception is raised, set STATE_FAILED, handle error
            or send it to the caller, return self

        """
        if op is self:
            import warnings
            warnings.warn("Running coro %s with itself. Something is fishy."%op)
        assert self.state < self.STATE_COMPLETED, \
            "%s called with %s op %r, coroutine state (%s) should be less than %s!" % (
                self, isinstance(op, CoroutineException) and op or
                (hasattr(op, 'state') and {0:'RUNNING', 1:'FINALIZED', 2:'ERRORED'}[op.state] or 'NOP'), op,
                self._state_names[self.state],
                self._state_names[self.STATE_COMPLETED]
            )
        coroutines.ident = self

        try:
            if self.state == self.STATE_RUNNING:
                if self.debug:
                    traceback.print_stack(self.coro.gr_frame)

                if isinstance(op, CoroutineException):
                    rop = self.coro.throw(*op.args)
                else:
                    rop = self.coro.switch(op and op.finalize(sched))
            elif self.state == self.STATE_NEED_INIT:
                assert op is None
                rop = self.coro.switch(*self.f_args, **self.f_kws)
                self.state = self.STATE_RUNNING

                del self.f_args
                del self.f_kws
            else:
                return None

        except StopIteration, e:
            self.state = self.STATE_COMPLETED
            self.result = e.args and e.args[0]
            #~ del self.coro
            rop = self
        except (KeyboardInterrupt, GeneratorExit, SystemExit):
            raise
        except:
            self.state = self.STATE_FAILED
            self.result = None
            self.exception = sys.exc_info()
            if not self.caller:
                self.handle_error()
            rop = self
            sys.exc_clear()
            #~ del self.coro
        finally:
            coroutines.ident = None
        return rop