from __future__ import print_function
import gevent.monkey
gevent.monkey.patch_all()
import gevent
import os

import multiprocessing

hub = gevent.get_hub()
pid = os.getpid()
newpid = None


def on_fork():
    global newpid
    newpid = os.getpid()

fork_watcher = hub.loop.fork(ref=False)
fork_watcher.start(on_fork)


def run(q):
    # libev only calls fork callbacks at the beginning of
    # the loop; we use callbacks extensively so it takes *two*
    # calls to sleep (with a timer) to actually get wrapped
    # around to the beginning of the loop.
    gevent.sleep(0.01)
    gevent.sleep(0.01)
    q.put(newpid)


def test():
    # Use a thread to make us multi-threaded
    hub.threadpool.apply(lambda: None)
    # If the Queue is global, q.get() hangs on Windows; must pass as
    # an argument.
    q = multiprocessing.Queue()
    p = multiprocessing.Process(target=run, args=(q,))
    p.start()
    p.join()
    p_val = q.get()

    assert p_val is not None, "The fork watcher didn't run"
    assert p_val != pid

if __name__ == '__main__':
    # Must call for Windows to fork properly; the fork can't be in the top-level
    multiprocessing.freeze_support()
    # fork watchers weren't firing in multi-threading processes.
    # This test is designed to prove that they are.
    # However, it fails on Windows: The fork watcher never runs!
    # This makes perfect sense: on Windows, our patches to os.fork()
    # that call gevent.hub.reinit() don't get used; os.fork doesn't
    # exist and multiprocessing.Process uses the windows-specific _subprocess.CreateProcess()
    # to create a whole new process that has no relation to the current process;
    # that process then calls multiprocessing.forking.main() to do its work.
    # Since no state is shared, a fork watcher cannot exist in that process.
    test()
