Thanks a lot for the patch. In my opinion I think this part should go in a different file.
The patch looks good overall some comments questions/inlined. > -----Mesaj original----- > De la: dev [mailto:dev-boun...@openvswitch.org] În numele Paul Boca > Trimis: Wednesday, July 6, 2016 3:38 PM > Către: dev@openvswitch.org > Subiect: [ovs-dev] [PATCH V6 12/17] python tests: Ported Python daemon to > Windows > > Used subprocess.Popen instead os.fork (not implemented on windows) and > repaced of os.pipe with Windows pipes. > > To be able to identify the child process I added an extra parameter to > daemon process '--pipe-handle', this parameter also contains the parent > Windows pipe handle, used by the child to signal the start. > > The PID file is created directly on Windows, without using a temporary file > because the symbolic link doesn't inheriths the file lock set on temporary > file. > > Signed-off-by: Paul-Daniel Boca <pb...@cloudbasesolutions.com> > import errno > -import fcntl > import os > -import resource > import signal > import sys > import time > +import threading [Alin Gabriel Serdean: ] is threading needed for both or just on Windows? > > import ovs.dirs > import ovs.fatal_signal > @@ -28,6 +27,15 @@ import ovs.timeval > import ovs.util > import ovs.vlog > > +if sys.platform == "win32": > + import ovs.fcntl_win as fcntl > + import win32file, win32pipe, win32api, win32security, win32con, > pywintypes [Alin Gabriel Serdean: ] this is an external library we need to add it to the docs as a prerequisite > + import msvcrt > + import subprocess > +else: > + import fcntl > + import resource > + > vlog = ovs.vlog.Vlog("daemon") > > # --detach: Should we run in the background? > @@ -53,6 +61,9 @@ _monitor = False > # File descriptor used by daemonize_start() and daemonize_complete(). > _daemonize_fd = None > > +# Running as the child process - Windows only. > +_detached = False > + [Alin Gabriel Serdean: ] Maybe add it just on windows with the sys check > RESTART_EXIT_CODE = 5 > > > @@ -109,13 +120,20 @@ def set_monitor(): > global _monitor > _monitor = True > > +def set_detached(wp): > + """Sets up a following call to daemonize() to fork a supervisory process > to > + monitor the daemon and restart it if it dies due to an error signal.""" > + global _detached > + global _daemonize_fd > + _detached = True > + _daemonize_fd = int(wp) > + [Alin Gabriel Serdean: ] [Alin Gabriel Serdean: ] Maybe add it just on windows with the sys check or add a comment that it should be used on windows only > > def _fatal(msg): > vlog.err(msg) > sys.stderr.write("%s\n" % msg) > sys.exit(1) > > - > def _make_pidfile(): > """If a pidfile has been configured, creates it and stores the running > process's pid in it. Ensures that the pidfile will be deleted when the > @@ - > 123,8 +141,12 @@ def _make_pidfile(): > pid = os.getpid() > > # Create a temporary pidfile. > - tmpfile = "%s.tmp%d" % (_pidfile, pid) > - ovs.fatal_signal.add_file_to_unlink(tmpfile) > + if sys.platform == "win32": > + tmpfile = _pidfile [Alin Gabriel Serdean: ] shouldn't we add "ovs.fatal_signal.add_file_to_unlink" here as well or we cannot use it? > + else: > + tmpfile = "%s.tmp%d" % (_pidfile, pid) > + ovs.fatal_signal.add_file_to_unlink(tmpfile) > + > try: > # This is global to keep Python from garbage-collecting and > # therefore closing our file after this function exits. That would > @@ - > 147,40 +169,47 @@ def _make_pidfile(): > _fatal("%s: write failed: %s" % (tmpfile, e.strerror)) > > try: > - # Rename or link it to the correct name. > - if _overwrite_pidfile: > - try: > - os.rename(tmpfile, _pidfile) > - except OSError as e: > - _fatal("failed to rename \"%s\" to \"%s\" (%s)" > - % (tmpfile, _pidfile, e.strerror)) > - else: > - while True: > + if sys.platform != "win32": > + # Rename or link it to the correct name. > + if _overwrite_pidfile: > try: > - os.link(tmpfile, _pidfile) > - error = 0 > + os.rename(tmpfile, _pidfile) > except OSError as e: > - error = e.errno > - if error == errno.EEXIST: > - _check_already_running() > - elif error != errno.EINTR: > - break > - if error: > - _fatal("failed to link \"%s\" as \"%s\" (%s)" > - % (tmpfile, _pidfile, os.strerror(error))) > - > - # Ensure that the pidfile will get deleted on exit. > - ovs.fatal_signal.add_file_to_unlink(_pidfile) > - > - # Delete the temporary pidfile if it still exists. > - if not _overwrite_pidfile: > - error = ovs.fatal_signal.unlink_file_now(tmpfile) > - if error: > - _fatal("%s: unlink failed (%s)" % (tmpfile, os.strerror(error))) > + _fatal("failed to rename \"%s\" to \"%s\" (%s)" > + % (tmpfile, _pidfile, e.strerror)) > + else: > + while True: > + try: > + os.link(tmpfile, _pidfile) > + error = 0 > + except OSError as e: > + error = e.errno > + if error == errno.EEXIST: > + _check_already_running() > + elif error != errno.EINTR: > + break > + if error: > + _fatal("failed to link \"%s\" as \"%s\" (%s)" > + % (tmpfile, _pidfile, os.strerror(error))) > + > + # Ensure that the pidfile will get deleted on exit. > + ovs.fatal_signal.add_file_to_unlink(_pidfile) > + > + # Delete the temporary pidfile if it still exists. > + if not _overwrite_pidfile: > + error = ovs.fatal_signal.unlink_file_now(tmpfile) > + if error: > + _fatal("%s: unlink failed (%s)" % (tmpfile, > os.strerror(error))) > + else: > + # Ensure that the pidfile will gets closed and deleted on exit. > + ovs.fatal_signal.add_file_to_close_and_unlink(_pidfile, > + file_handle) [Alin Gabriel Serdean: ] can't we use ovs.fatal_signal.add_file_to_unlink? Shouldn't we retry to rename the file? > > global _pidfile_dev > global _pidfile_ino > @@ -204,6 +233,97 @@ def _waitpid(pid, options): > pass > return -e.errno, 0 > > +def _windows_create_pipe(): > + sAttrs = win32security.SECURITY_ATTRIBUTES() > + sAttrs.bInheritHandle = 1 > + > + (read_pipe, write_pipe) = win32pipe.CreatePipe(sAttrs, 0) > + pid = win32api.GetCurrentProcess() > + write_pipe2 = win32api.DuplicateHandle(pid, write_pipe, pid, 0, 1, > win32con.DUPLICATE_SAME_ACCESS) [Alin Gabriel Serdean: ] maybe I am missing something but why do we need the duplicate? > + win32file.CloseHandle(write_pipe) > + > + return (read_pipe, write_pipe2) > + > +def __windows_fork_notify_startup(fd): > + if fd is not None: > + try: > + win32file.WriteFile(fd, "0", None) > + except: > + win32file.WriteFile(fd, bytes("0", 'UTF-8'), None) [Alin Gabriel Serdean: ] I don't really understand the utf-8 part and also that may throw an exception as well > + > +def _windows_read_pipe(fd): > + if fd is not None: > + sAttrs = win32security.SECURITY_ATTRIBUTES() > + sAttrs.bInheritHandle = 1 > + overlapped = pywintypes.OVERLAPPED() [Alin Gabriel Serdean: ] sAttrs and overlapped not used > + try: > + (ret, data) = win32file.ReadFile(fd, 1, None) > + return data > + except pywintypes.error as e: > + raise OSError(errno.EIO, "", "") > + > +def _windows_detach(proc, wfd): > + """ If the child process closes and it was detached > + then close the communication pipe so the parent process > + can terminate """ > + proc.wait() > + win32file.CloseHandle(wfd) > + > +def _windows_fork_and_wait_for_startup(): > + if _detached: > + return 0 > + > + ''' close the log file, on Windows cannot be moved while the parent has > + a reference on it.''' > + vlog.close_log_file() > + > + try: > + (rfd, wfd) = _windows_create_pipe() > + except OSError as e: [Alin Gabriel Serdean: ] I think it's a pywintypes.error not oserror > + sys.stderr.write("pipe failed: %s\n" % os.strerror(e.errno)) > + sys.exit(1) > + > + try: > + proc = subprocess.Popen("%s %s --pipe-handle=%ld" % > (sys.executable, " ".join(sys.argv), int(wfd)), close_fds=False, shell=False) > + pid = proc.pid > + #start a thread and wait the subprocess exit code > + thread = threading.Thread(target=_windows_detach, args=(proc, wfd)) > + thread.daemon = True > + thread.start() > + except OSError as e: [Alin Gabriel Serdean: ] pywintypes.error needs to be treated as well because closehandle can throw an exception > + sys.stderr.write("could not fork: %s\n" % os.strerror(e.errno)) > + sys.exit(1) > + _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev