From 714b8dc501067d9ceccc8e07517b4d8a4b4465df Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Mon, 2 May 2011 14:43:00 +0100 Subject: [PATCH 1/3] Improved thread interlocks in tests. --- Lib/test/test_logging.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 96f82151b60..7a723e0e08d 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1385,7 +1385,10 @@ class DatagramHandlerTest(BaseTest): logger = logging.getLogger("udp") logger.error("spam") self.handled.wait() - self.assertEqual(self.log_output, "spam\n") + self.handled.clear() + logger.error("eggs") + self.handled.wait() + self.assertEqual(self.log_output, "spam\neggs\n") @unittest.skipUnless(threading, 'Threading required for this test.') From cafa2efedbaa4e0d4023e1cde48fc8f58d1a44cb Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 May 2011 16:11:28 +0200 Subject: [PATCH 2/3] logging: don't define QueueListener if Python has no thread support --- Lib/logging/handlers.py | 184 ++++++++++++++++++++------------------- Lib/test/test_logging.py | 2 + Misc/NEWS | 2 + 3 files changed, 98 insertions(+), 90 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 3a48628d55f..306cf866983 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -27,7 +27,10 @@ To use, simply 'import logging.handlers' and log away! import logging, socket, os, pickle, struct, time, re from stat import ST_DEV, ST_INO, ST_MTIME import queue -import threading +try: + import threading +except ImportError: + threading = None try: import codecs @@ -1218,106 +1221,107 @@ class QueueHandler(logging.Handler): except: self.handleError(record) -class QueueListener(object): - """ - This class implements an internal threaded listener which watches for - LogRecords being added to a queue, removes them and passes them to a - list of handlers for processing. - """ - _sentinel = None +if threading: + class QueueListener(object): + """ + This class implements an internal threaded listener which watches for + LogRecords being added to a queue, removes them and passes them to a + list of handlers for processing. + """ + _sentinel = None - def __init__(self, queue, *handlers): - """ - Initialise an instance with the specified queue and - handlers. - """ - self.queue = queue - self.handlers = handlers - self._stop = threading.Event() - self._thread = None + def __init__(self, queue, *handlers): + """ + Initialise an instance with the specified queue and + handlers. + """ + self.queue = queue + self.handlers = handlers + self._stop = threading.Event() + self._thread = None - def dequeue(self, block): - """ - Dequeue a record and return it, optionally blocking. + def dequeue(self, block): + """ + Dequeue a record and return it, optionally blocking. - The base implementation uses get. You may want to override this method - if you want to use timeouts or work with custom queue implementations. - """ - return self.queue.get(block) + The base implementation uses get. You may want to override this method + if you want to use timeouts or work with custom queue implementations. + """ + return self.queue.get(block) - def start(self): - """ - Start the listener. + def start(self): + """ + Start the listener. - This starts up a background thread to monitor the queue for - LogRecords to process. - """ - self._thread = t = threading.Thread(target=self._monitor) - t.setDaemon(True) - t.start() + This starts up a background thread to monitor the queue for + LogRecords to process. + """ + self._thread = t = threading.Thread(target=self._monitor) + t.setDaemon(True) + t.start() - def prepare(self , record): - """ - Prepare a record for handling. + def prepare(self , record): + """ + Prepare a record for handling. - This method just returns the passed-in record. You may want to - override this method if you need to do any custom marshalling or - manipulation of the record before passing it to the handlers. - """ - return record + This method just returns the passed-in record. You may want to + override this method if you need to do any custom marshalling or + manipulation of the record before passing it to the handlers. + """ + return record - def handle(self, record): - """ - Handle a record. + def handle(self, record): + """ + Handle a record. - This just loops through the handlers offering them the record - to handle. - """ - record = self.prepare(record) - for handler in self.handlers: - handler.handle(record) + This just loops through the handlers offering them the record + to handle. + """ + record = self.prepare(record) + for handler in self.handlers: + handler.handle(record) - def _monitor(self): - """ - Monitor the queue for records, and ask the handler - to deal with them. + def _monitor(self): + """ + Monitor the queue for records, and ask the handler + to deal with them. - This method runs on a separate, internal thread. - The thread will terminate if it sees a sentinel object in the queue. - """ - q = self.queue - has_task_done = hasattr(q, 'task_done') - while not self._stop.isSet(): - try: - record = self.dequeue(True) - if record is self._sentinel: + This method runs on a separate, internal thread. + The thread will terminate if it sees a sentinel object in the queue. + """ + q = self.queue + has_task_done = hasattr(q, 'task_done') + while not self._stop.isSet(): + try: + record = self.dequeue(True) + if record is self._sentinel: + break + self.handle(record) + if has_task_done: + q.task_done() + except queue.Empty: + pass + # There might still be records in the queue. + while True: + try: + record = self.dequeue(False) + if record is self._sentinel: + break + self.handle(record) + if has_task_done: + q.task_done() + except queue.Empty: break - self.handle(record) - if has_task_done: - q.task_done() - except queue.Empty: - pass - # There might still be records in the queue. - while True: - try: - record = self.dequeue(False) - if record is self._sentinel: - break - self.handle(record) - if has_task_done: - q.task_done() - except queue.Empty: - break - def stop(self): - """ - Stop the listener. + def stop(self): + """ + Stop the listener. - This asks the thread to terminate, and then waits for it to do so. - Note that if you don't call this before your application exits, there - may be some records still left on the queue, which won't be processed. - """ - self._stop.set() - self.queue.put_nowait(self._sentinel) - self._thread.join() - self._thread = None + This asks the thread to terminate, and then waits for it to do so. + Note that if you don't call this before your application exits, there + may be some records still left on the queue, which won't be processed. + """ + self._stop.set() + self.queue.put_nowait(self._sentinel) + self._thread.join() + self._thread = None diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 6623a0f5322..90d293e3abe 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -2093,6 +2093,8 @@ class QueueHandlerTest(BaseTest): self.assertEqual(data.name, self.que_logger.name) self.assertEqual((data.msg, data.args), (msg, None)) + @unittest.skipUnless(hasattr(logging.handlers, 'QueueListener'), + 'logging.handlers.QueueListener required for this test') def test_queue_listener(self): handler = TestHandler(Matcher()) listener = logging.handlers.QueueListener(self.queue, handler) diff --git a/Misc/NEWS b/Misc/NEWS index 2a500949bc1..8ca2f02bfc0 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -79,6 +79,8 @@ Core and Builtins Library ------- +- logging: don't define QueueListener if Python has no thread support. + - Issue #11277: mmap.mmap() calls fcntl(fd, F_FULLFSYNC) on Mac OS X to get around a mmap bug with sparse files. Patch written by Steffen Daode Nurpmeso. From 72c53b5dccb02f7a14edbfa4a197827b29e454e9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 2 May 2011 16:15:43 +0200 Subject: [PATCH 3/3] cleanup signalmodule.c: use PyModule_AddIntMacro() --- Modules/signalmodule.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 305261cb01e..0cb27209eaf 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -720,24 +720,16 @@ PyInit_signal(void) Py_DECREF(x); #ifdef SIG_BLOCK - x = PyLong_FromLong(SIG_BLOCK); - if (!x || PyDict_SetItemString(d, "SIG_BLOCK", x) < 0) - goto finally; - Py_DECREF(x); + if (PyModule_AddIntMacro(m, SIG_BLOCK)) + goto finally; #endif - #ifdef SIG_UNBLOCK - x = PyLong_FromLong(SIG_UNBLOCK); - if (!x || PyDict_SetItemString(d, "SIG_UNBLOCK", x) < 0) - goto finally; - Py_DECREF(x); + if (PyModule_AddIntMacro(m, SIG_UNBLOCK)) + goto finally; #endif - #ifdef SIG_SETMASK - x = PyLong_FromLong(SIG_SETMASK); - if (!x || PyDict_SetItemString(d, "SIG_SETMASK", x) < 0) - goto finally; - Py_DECREF(x); + if (PyModule_AddIntMacro(m, SIG_SETMASK)) + goto finally; #endif x = IntHandler = PyDict_GetItemString(d, "default_int_handler");