diff --git a/src/calibre/startup.py b/src/calibre/startup.py index c18375b6fc..100d7110dc 100644 --- a/src/calibre/startup.py +++ b/src/calibre/startup.py @@ -17,7 +17,7 @@ __builtin__.__dict__['_'] = lambda s: s # immediately translated to the environment language __builtin__.__dict__['__'] = lambda s: s -from calibre.constants import iswindows, preferred_encoding, plugins, isosx, islinux, isfrozen, DEBUG +from calibre.constants import iswindows, preferred_encoding, plugins, isosx, islinux, isfrozen, DEBUG, isfreebsd _run_once = False winutil = winutilerror = None @@ -172,36 +172,28 @@ if not _run_once: bound_signal.connect(slot, **kw) __builtin__.__dict__['connect_lambda'] = connect_lambda - if islinux: + if islinux or isosx or isfreebsd: # Name all threads at the OS level created using the threading module, see # http://bugs.python.org/issue15500 - import ctypes, ctypes.util, threading - libpthread_path = ctypes.util.find_library("pthread") - if libpthread_path: - libpthread = ctypes.CDLL(libpthread_path) - if hasattr(libpthread, "pthread_setname_np"): - pthread_setname_np = libpthread.pthread_setname_np - pthread_setname_np.argtypes = [ctypes.c_void_p, ctypes.c_char_p] - pthread_setname_np.restype = ctypes.c_int - orig_start = threading.Thread.start + import threading - def new_start(self): - orig_start(self) - try: + orig_start = threading.Thread.start + + def new_start(self): + orig_start(self) + try: + name = self.name + if not name or name.startswith('Thread-'): + name = self.__class__.__name__ + if name == 'Thread': name = self.name - if not name or name.startswith('Thread-'): - name = self.__class__.__name__ - if name == 'Thread': - name = self.name - if name: - if isinstance(name, unicode): - name = name.encode('ascii', 'replace') - ident = getattr(self, "ident", None) - if ident is not None: - pthread_setname_np(ident, name[:15]) - except Exception: - pass # Don't care about failure to set name - threading.Thread.start = new_start + if name: + if isinstance(name, unicode): + name = name.encode('ascii', 'replace').decode('ascii') + plugins['speedup'][0].set_thread_name(name[:15]) + except Exception: + pass # Don't care about failure to set name + threading.Thread.start = new_start def test_lopen(): diff --git a/src/calibre/utils/speedup.c b/src/calibre/utils/speedup.c index 69e2631233..daf07e5f21 100644 --- a/src/calibre/utils/speedup.c +++ b/src/calibre/utils/speedup.c @@ -1,10 +1,12 @@ #define UNICODE #include #include +#include #include #include #include +#include #define _USE_MATH_DEFINES #include #include @@ -42,7 +44,7 @@ speedup_parse_date(PyObject *self, PyObject *args) { year = strtol(raw, &end, 10); if ((end - raw) != 4) Py_RETURN_NONE; raw += 5; - + month = strtol(raw, &end, 10); if ((end - raw) != 2) Py_RETURN_NONE; @@ -51,7 +53,7 @@ speedup_parse_date(PyObject *self, PyObject *args) { day = strtol(raw, &end, 10); if ((end - raw) != 2) Py_RETURN_NONE; raw += 3; - + hour = strtol(raw, &end, 10); if ((end - raw) != 2) Py_RETURN_NONE; raw += 3; @@ -88,7 +90,7 @@ static PyObject* speedup_pdf_float(PyObject *self, PyObject *args) { double f = 0.0, a = 0.0; char *buf = "0", *dot; - void *free_buf = NULL; + void *free_buf = NULL; int precision = 6, l = 0; PyObject *ret; @@ -215,7 +217,7 @@ speedup_create_texture(PyObject *self, PyObject *args, PyObject *kw) { } } - // Create the texture in PPM (P6) format + // Create the texture in PPM (P6) format memcpy(ppm, header, strlen(header)); t = ppm + strlen(header); for (i = 0, j = 0; j < width * height; i += 3, j += 1) { @@ -340,7 +342,7 @@ clean_xml_chars(PyObject *self, PyObject *text) { for (; i < PyUnicode_GET_SIZE(text); i++) { ch = PyUnicode_AS_UNICODE(text)[i]; #ifdef Py_UNICODE_WIDE - if ((0x20 <= ch && ch <= 0xd7ff && ch != 0x7f) || ch == 9 || ch == 10 || ch == 13 || (0xe000 <= ch && ch <= 0xfffd) || (0xffff < ch && ch <= 0x10ffff)) + if ((0x20 <= ch && ch <= 0xd7ff && ch != 0x7f) || ch == 9 || ch == 10 || ch == 13 || (0xe000 <= ch && ch <= 0xfffd) || (0xffff < ch && ch <= 0x10ffff)) buf[j++] = ch; #else if ((0x20 <= ch && ch <= 0xd7ff && ch != 0x7f) || ch == 9 || ch == 10 || ch == 13 || (0xd000 <= ch && ch <= 0xfffd)) { @@ -349,7 +351,7 @@ clean_xml_chars(PyObject *self, PyObject *text) { if (ch <= 0xdbff && i + 1 < PyUnicode_GET_SIZE(text) && 0xdc00 <= PyUnicode_AS_UNICODE(text)[i + 1] && PyUnicode_AS_UNICODE(text)[i+1] <= 0xdfff) { buf[j++] = ch; buf[j++] = PyUnicode_AS_UNICODE(text)[++i]; } - } else + } else buf[j++] = ch; } #endif @@ -490,6 +492,48 @@ speedup_iso_8601(PyObject *self, PyObject *args) { return Py_BuildValue("NOi", PyDateTime_FromDateAndTime(year, month, day, hour, minute, second, usecond), (tzhour == 1000) ? Py_False : Py_True, tzsign*60*(tzhour*60 + tzminute)); } +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#define FREEBSD_SET_NAME +#endif +#if defined(__APPLE__) +// I cant figure out how to get pthread.h to include this definition on macOS. MACOSX_DEPLOYMENT_TARGET does not work. +extern int pthread_setname_np(const char *name); +#elif defined(FREEBSD_SET_NAME) +// Function has a different name on FreeBSD +void pthread_set_name_np(pthread_t tid, const char *name); +#else +// Need _GNU_SOURCE for pthread_setname_np on linux and that causes other issues on systems with old glibc +extern int pthread_setname_np(pthread_t, const char *name); +#endif + + +static PyObject* +set_thread_name(PyObject *self, PyObject *args) { + (void)(self); (void)(args); +#if defined(_MSC_VER) + PyErr_SetString(PyExc_OSError, "Setting thread names not supported on windows"); + return NULL; +#else + char *name; + int ret; + if (!PyArg_ParseTuple(args, "s", &name)) return NULL; + while (1) { + errno = 0; +#if defined(__APPLE__) + ret = pthread_setname_np(name); +#elif defined(FREEBSD_SET_NAME) + pthread_set_name_np(pthread_self(), name); + ret = 0; +#else + ret = pthread_setname_np(pthread_self(), name); +#endif + if (ret != 0 && (errno == EINTR || errno == EAGAIN)) continue; + break; + } + if (ret != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } + Py_RETURN_NONE; +#endif +} static PyMethodDef speedup_methods[] = { {"parse_date", speedup_parse_date, METH_VARARGS, @@ -534,6 +578,10 @@ static PyMethodDef speedup_methods[] = { "clean_xml_chars(unicode_object)\n\nRemove codepoints in unicode_object that are not allowed in XML" }, + {"set_thread_name", set_thread_name, METH_VARARGS, + "set_thread_name(name)\n\nWrapper for pthread_setname_np" + }, + {NULL, NULL, 0, NULL} };