From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from pigeon.gentoo.org ([208.92.234.80] helo=lists.gentoo.org) by finch.gentoo.org with esmtp (Exim 4.60) (envelope-from ) id 1Ruu5Q-0007ZX-NQ for garchives@archives.gentoo.org; Tue, 07 Feb 2012 23:04:32 +0000 Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id E31C2E05DB; Tue, 7 Feb 2012 23:04:23 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) by pigeon.gentoo.org (Postfix) with ESMTP id A2955E05DB for ; Tue, 7 Feb 2012 23:04:23 +0000 (UTC) Received: from pelican.gentoo.org (unknown [66.219.59.40]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 1926F1B4011 for ; Tue, 7 Feb 2012 23:04:23 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by pelican.gentoo.org (Postfix) with ESMTP id 8752180044 for ; Tue, 7 Feb 2012 23:04:22 +0000 (UTC) From: "Zac Medico" To: gentoo-commits@lists.gentoo.org Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Zac Medico" Message-ID: Subject: [gentoo-commits] proj/portage:master commit in: pym/_emerge/ X-VCS-Repository: proj/portage X-VCS-Files: pym/_emerge/PollScheduler.py pym/_emerge/Scheduler.py X-VCS-Directories: pym/_emerge/ X-VCS-Committer: zmedico X-VCS-Committer-Name: Zac Medico X-VCS-Revision: e9d1125f6730c85c4b384a580da55da68338acf1 Date: Tue, 7 Feb 2012 23:04:22 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: quoted-printable X-Archives-Salt: f75bb6a1-2d4c-4226-82d0-760c7c729b7e X-Archives-Hash: ecb9d4401a9c89a0b0932bfd87835d6c commit: e9d1125f6730c85c4b384a580da55da68338acf1 Author: Zac Medico gentoo org> AuthorDate: Tue Feb 7 19:11:50 2012 +0000 Commit: Zac Medico gentoo org> CommitDate: Tue Feb 7 19:11:50 2012 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=3Dproj/portage.git;a= =3Dcommit;h=3De9d1125f PollScheduler: add timeout_add like glib's This will be useful as a substitute for recursion, in order to avoid hitting the recursion limit for bug #402335. --- pym/_emerge/PollScheduler.py | 89 ++++++++++++++++++++++++++++++++++++= ++++-- pym/_emerge/Scheduler.py | 8 ++-- 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/pym/_emerge/PollScheduler.py b/pym/_emerge/PollScheduler.py index fd9dfc0..fd57359 100644 --- a/pym/_emerge/PollScheduler.py +++ b/pym/_emerge/PollScheduler.py @@ -24,7 +24,12 @@ from _emerge.PollSelectAdapter import PollSelectAdapte= r class PollScheduler(object): =20 class _sched_iface_class(SlotObject): - __slots__ =3D ("output", "register", "schedule", "unregister") + __slots__ =3D ("output", "register", "schedule", + "source_remove", "timeout_add", "unregister") + + class _timeout_handler_class(SlotObject): + __slots__ =3D ("args", "function", "interval", "source_id", + "timestamp") =20 def __init__(self): self._terminated =3D threading.Event() @@ -37,13 +42,17 @@ class PollScheduler(object): self._poll_event_handler_ids =3D {} # Increment id for each new handler. self._event_handler_id =3D 0 + self._timeout_handlers =3D {} self._poll_obj =3D create_poll_instance() + self._polling =3D False self._scheduling =3D False self._background =3D False self.sched_iface =3D self._sched_iface_class( output=3Dself._task_output, register=3Dself._register, schedule=3Dself._schedule_wait, + source_remove=3Dself._unregister, + timeout_add=3Dself._timeout_add, unregister=3Dself._unregister) =20 def terminate(self): @@ -82,7 +91,7 @@ class PollScheduler(object): should return False immediately (since there's no need to schedule anything after _terminate_tasks() has been called). """ - raise NotImplementedError() + pass =20 def _schedule(self): """ @@ -140,6 +149,23 @@ class PollScheduler(object): StopIteration if timeout is None and there are no file descriptors to poll. """ + if self._polling: + return + self._polling =3D True + try: + self._do_poll(timeout=3Dtimeout) + finally: + self._polling =3D False + + def _do_poll(self, timeout=3DNone): + """ + All poll() calls pass through here. The poll events + are added directly to self._poll_event_queue. + In order to avoid endless blocking, this raises + StopIteration if timeout is None and there are + no file descriptors to poll. + """ + self._run_timeouts() if not self._poll_event_handlers: self._schedule() if timeout is None and \ @@ -226,6 +252,51 @@ class PollScheduler(object): =20 return bool(events_handled) =20 + def _timeout_add(self, interval, function, *args): + """ + Like glib.timeout_add(), interval argument is the number of + milliseconds between calls to your function, and your function + should return False to stop being called, or True to continue + being called. Any additional positional arguments given here + are passed to your function when it's called. + + NOTE: Timeouts registered by this function currently do not + keep the main loop running when there are no remaining callbacks + registered for IO events. This is not an issue if the purpose of + the timeout is to place an upper limit on the time allowed for + a particular IO event to occur, since the handler associated with + the IO event will serve to keep the main loop running. + """ + self._event_handler_id +=3D 1 + source_id =3D self._event_handler_id + self._timeout_handlers[source_id] =3D \ + self._timeout_handler_class( + interval=3Dinterval, function=3Dfunction, args=3Dargs, + source_id=3Dsource_id, timestamp=3Dtime.time()) + return source_id + + def _run_timeouts(self): + ready_timeouts =3D [] + current_time =3D time.time() + for x in self._timeout_handlers.values(): + elapsed_seconds =3D current_time - x.timestamp + # elapsed_seconds < 0 means the system clock has been adjusted + if elapsed_seconds < 0 or \ + (x.interval - 1000 * elapsed_seconds) <=3D 0: + ready_timeouts.append(x) + + # Iterate of our local list, since self._timeout_handlers can be + # modified during the exection of these callbacks. + for x in ready_timeouts: + if x.source_id not in self._timeout_handlers: + # it got cancelled while executing another timeout + continue + x.timestamp =3D time.time() + if not x.function(*x.args): + self._unregister(x.source_id) + + return bool(ready_timeouts) + def _register(self, f, eventmask, handler): """ @rtype: Integer @@ -242,7 +313,17 @@ class PollScheduler(object): return reg_id =20 def _unregister(self, reg_id): - f =3D self._poll_event_handler_ids[reg_id] + """ + Like glib.source_remove(), this returns True if the given reg_id + is found and removed, and False if the reg_id is invalid or has + already been removed. + """ + timeout_handler =3D self._timeout_handlers.pop(reg_id, None) + if timeout_handler is not None: + return True + f =3D self._poll_event_handler_ids.pop(reg_id, None) + if f is None: + return False self._poll_obj.unregister(f) if self._poll_event_queue: # Discard any unhandled events that belong to this file, @@ -262,7 +343,7 @@ class PollScheduler(object): self._poll_event_queue[:] =3D remaining_events =20 del self._poll_event_handlers[f] - del self._poll_event_handler_ids[reg_id] + return True =20 def _schedule_wait(self, wait_ids=3DNone, timeout=3DNone, condition=3DN= one): """ diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py index d09b474..5b56650 100644 --- a/pym/_emerge/Scheduler.py +++ b/pym/_emerge/Scheduler.py @@ -79,11 +79,9 @@ class Scheduler(PollScheduler): _opts_no_self_update =3D frozenset(["--buildpkgonly", "--fetchonly", "--fetch-all-uri", "--pretend"]) =20 - class _iface_class(SlotObject): + class _iface_class(PollScheduler._sched_iface_class): __slots__ =3D ("fetch", - "output", "register", "schedule", - "scheduleSetup", "scheduleUnpack", "scheduleYield", - "unregister") + "scheduleSetup", "scheduleUnpack", "scheduleYield") =20 class _fetch_iface_class(SlotObject): __slots__ =3D ("log_file", "schedule") @@ -223,6 +221,8 @@ class Scheduler(PollScheduler): scheduleSetup=3Dself._schedule_setup, scheduleUnpack=3Dself._schedule_unpack, scheduleYield=3Dself._schedule_yield, + source_remove=3Dself._unregister, + timeout_add=3Dself._timeout_add, unregister=3Dself._unregister) =20 self._prefetchers =3D weakref.WeakValueDictionary()