From 8f09ec61f8d24fcd4ad4a4438be4d90300d55175 Mon Sep 17 00:00:00 2001 From: Aymeric Augustin Date: Wed, 30 Oct 2013 23:08:12 +0100 Subject: [PATCH 1/2] Add instant autoreload on platforms supporting kqueue. --- django/utils/autoreload.py | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py index ba98530f1b..9acd52e6e8 100644 --- a/django/utils/autoreload.py +++ b/django/utils/autoreload.py @@ -65,6 +65,16 @@ try: except ImportError: pass +try: + import select + select.kevent, select.kqueue + USE_KQUEUE = True + + import resource + NOFILES_SOFT, NOFILES_HARD = resource.getrlimit(resource.RLIMIT_NOFILE) +except AttributeError: + USE_KQUEUE = False + RUN_RELOADER = True _mtimes = {} @@ -119,6 +129,39 @@ def inotify_code_changed(): # If we are here the code must have changed. return True +def kqueue_code_changed(): + """ + Checks for changed code using kqueue. After being called + it blocks until a change event has been fired. + """ + # Maximum number of open file descriptors is typically too low (256). + filenames = list(gen_filenames()) + resource.setrlimit(resource.RLIMIT_NOFILE, + (NOFILES_SOFT + len(filenames), NOFILES_HARD)) + + kqueue = select.kqueue() + fds = [open(filename) for filename in filenames] + + _filter = select.KQ_FILTER_VNODE + flags = select.KQ_EV_ADD + fflags = ( + select.KQ_NOTE_DELETE | + select.KQ_NOTE_WRITE | + select.KQ_NOTE_EXTEND | + select.KQ_NOTE_ATTRIB | + select.KQ_NOTE_LINK | + select.KQ_NOTE_RENAME | + select.KQ_NOTE_REVOKE + ) + kevents = [select.kevent(fd, _filter, flags, fflags) for fd in fds] + kqueue.control(kevents, 1) + + for fd in fds: + fd.close() + kqueue.close() + + return True + def code_changed(): global _mtimes, _win for filename in gen_filenames(): @@ -178,6 +221,8 @@ def reloader_thread(): ensure_echo_on() if USE_INOTIFY: fn = inotify_code_changed + elif USE_KQUEUE: + fn = kqueue_code_changed else: fn = code_changed while RUN_RELOADER: From 47217f2f290264b0467a079492779cbf3cbfa4f0 Mon Sep 17 00:00:00 2001 From: Aymeric Augustin Date: Thu, 31 Oct 2013 10:15:42 +0100 Subject: [PATCH 2/2] Reduce the set of events that trigger a reload. This seems to avoid multiple reloads. --- django/utils/autoreload.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py index 9acd52e6e8..6816403cc7 100644 --- a/django/utils/autoreload.py +++ b/django/utils/autoreload.py @@ -144,15 +144,7 @@ def kqueue_code_changed(): _filter = select.KQ_FILTER_VNODE flags = select.KQ_EV_ADD - fflags = ( - select.KQ_NOTE_DELETE | - select.KQ_NOTE_WRITE | - select.KQ_NOTE_EXTEND | - select.KQ_NOTE_ATTRIB | - select.KQ_NOTE_LINK | - select.KQ_NOTE_RENAME | - select.KQ_NOTE_REVOKE - ) + fflags = select.KQ_NOTE_DELETE | select.KQ_NOTE_WRITE | select.KQ_NOTE_RENAME kevents = [select.kevent(fd, _filter, flags, fflags) for fd in fds] kqueue.control(kevents, 1)