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

        Return self is used as a optimization. Coroutine is also a Operation
        which handles it's own completion (resuming the caller and the waiters).
        """
        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]
            )
        #~ assert self.state < self.STATE_COMPLETED, \
            #~ "%s called with:%s, last one:%s, expected state less than %s!" % (
                #~ self,
                #~ op,
                #~ isinstance(self.lastop, CoroutineException) and ''.join(traceback.format_exception(*self.lastop.message)) or self.lastop,
                #~ self._state_names[self.STATE_COMPLETED]
            #~ )
        #~ self.lastop = op
        if self.debug:
            print
            if isinstance(op, CoroutineException):
                print 'Running %r with exception:' % self,
                if len(op.args) == 3:
                    print '[[['
                    traceback.print_exception(*op.args)
                    print ']]]'
                else:
                    print op.args
            else:
                print 'Running %r with: %r' % (self, op)
        global ident
        ident = self
        try:
            if self.state == self.STATE_RUNNING:
                if self.debug:
                    traceback.print_stack(self.coro.gi_frame)
                if isinstance(op, CoroutineException):
                    rop = self.coro.throw(*op.args)
                else:
                    rop = self.coro.send(op and op.finalize(sched))
            elif self.state == self.STATE_NEED_INIT:
                assert op is None
                self.coro = self.coro(*self.f_args, **self.f_kws)
                del self.f_args
                del self.f_kws
                if self._valid_gen(self.coro):
                    self.state = self.STATE_RUNNING
                    rop = None
                else:
                    self.state = self.STATE_COMPLETED
                    self.result = self.coro
                    self.coro = None
                    rop = self
            else:
                return None

        except StopIteration, e:
            self.state = self.STATE_COMPLETED
            self.result = e.args and e.args[0]
            if hasattr(self.coro, 'close'):
                self.coro.close()
            rop = self
        except (KeyboardInterrupt, GeneratorExit, SystemExit):
            raise
        except:
            self.state = self.STATE_FAILED
            self.result = None
            self.exception = sys.exc_info()
            if hasattr(self.coro, 'close'):
                self.coro.close()
            if not self.caller:
                self.handle_error(op)
            rop = self
            sys.exc_clear()
        finally:
            ident = None
        if self.debug:
            print "Yields %s." % rop
        return rop