'Starts the `IOLoop`, runs the given function, and stops the loop.
The function must return either a yieldable object or
``None``. If the function returns a yieldable object, the
`IOLoop` will run until the yieldable is resolved (and
`run_sync()` will return the yieldable\'s result). If it raises
an exception, the `IOLoop` will stop and the exception will be
re-raised to the caller.
The keyword-only argument ``timeout`` may be used to set
a maximum duration for the function.  If the timeout expires,
a `tornado.util.TimeoutError` is raised.
This method is useful in conjunction with `tornado.gen.coroutine`
to allow asynchronous calls in a ``main()`` function::
@gen.coroutine
def main():
# do stuff...
if __name__ == \'__main__\':
IOLoop.current().run_sync(main)
.. versionchanged:: 4.3
Returning a non-``None``, non-yieldable value is now an error.'

def run_sync(self, func, timeout=None):

    future_cell = [None]
    def run():
        try:
            result = func()
            if (result is not None):
                from tornado.gen import convert_yielded
                result = convert_yielded(result)
        except Exception:
            future_cell[0] = TracebackFuture()
            future_cell[0].set_exc_info(sys.exc_info())
        else:
            if is_future(result):
                future_cell[0] = result
            else:
                future_cell[0] = TracebackFuture()
                future_cell[0].set_result(result)
        self.add_future(future_cell[0], (lambda future: self.stop()))
    self.add_callback(run)
    if (timeout is not None):
        timeout_handle = self.add_timeout((self.time() + timeout), self.stop)
    self.start()
    if (timeout is not None):
        self.remove_timeout(timeout_handle)
    if (not future_cell[0].done()):
        raise TimeoutError(('Operation    timed    out    after    %s    seconds' % timeout))
    return future_cell[0].result()
