Source code for gym_nethack.nhdaemon

import os, sys, subprocess

import zmq

from gym_nethack.conn import nethack_path, nethack_dir

'''
def spawn_daemon(proc_id):
    """Spawn a completely detached subprocess (i.e., a daemon).
    source: https://stackoverflow.com/questions/972362/spawning-process-from-python/972383#972383
    """
    path_to_executable = sys.executable
    args = [sys.executable, '-m', 'nhdaemon', str(proc_id)]
    # fork the first time (to make a non-session-leader child process)
    try:
        pid = os.fork()
    except OSError as e:
        raise RuntimeError("1st fork failed: %s [%d]" % (e.strerror, e.errno))
    if pid != 0:
        # parent (calling) process is all done
        return

    # detach from controlling terminal (to make child a session-leader)
    os.setsid()
    try:
        pid = os.fork()
    except OSError as e:
        raise RuntimeError("2nd fork failed: %s [%d]" % (e.strerror, e.errno))
        raise Exception("%s [%d]" % (e.strerror, e.errno))
    if pid != 0:
        # child process is all done
        os._exit(0)

    # grandchild process now non-session-leader, detached from parent
    # grandchild process must now close all open files
    try:
        maxfd = os.sysconf("SC_OPEN_MAX")
    except (AttributeError, ValueError):
        maxfd = 1024

    for fd in range(maxfd):
        try:
           os.close(fd)
        except OSError: # ERROR, fd wasn't open to begin with (ignored)
           pass

    # redirect stdin, stdout and stderr to /dev/null
    os.open(os.devnull, os.O_RDWR)  # standard input (0)
    os.dup2(0, 1)
    os.dup2(0, 2)

    # and finally let's execute the executable for the daemon!
    try:
      os.execv(path_to_executable, args)
    except Exception:
      # oops, we're cut off from the world, let's just give up
      os._exit(255)
'''
[docs]def nh_daemon(): proc_id = int(sys.argv[1]) if len(sys.argv) > 1 else 0 nh_port = 5555 + proc_id gym_port = 5555 - proc_id - 1 print("Daemon launched for NH port", nh_port, "; listening on port", gym_port) context = zmq.Context() daemon_socket = context.socket(zmq.REP) daemon_socket.bind("tcp://*:" + str(gym_port)) while True: message = daemon_socket.recv().decode("cp437" if os.name == "nt" else "utf-8") if 'exit' in message: break if 'test' in message: daemon_socket.send("done".encode()) continue assert 'launch' in message daemon_socket.send("done".encode()) if sys.platform == "win32": os.system("cd " + nethack_dir + " & NetHack.exe -port " + str(nh_port) + "\"") else: subprocess.call(nethack_path + " -port " + str(nh_port) + " &", shell=True) print("Received:", message)
if __name__ == '__main__': nh_daemon()