mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Add a python wrapper for pread
This commit is contained in:
parent
0594f026ba
commit
a00d61d921
@ -65,6 +65,19 @@ class TestCopyFiles(unittest.TestCase):
|
|||||||
contents = set(os.listdir(self.tdir)) - {'base', 'src'}
|
contents = set(os.listdir(self.tdir)) - {'base', 'src'}
|
||||||
self.ae(contents, {'One', 'three'})
|
self.ae(contents, {'One', 'three'})
|
||||||
|
|
||||||
|
def test_pread_all(self):
|
||||||
|
from calibre_extensions.speedup import pread_all
|
||||||
|
n = os.path.join(self.tdir, 'base')
|
||||||
|
data = os.urandom(1137*1024)
|
||||||
|
with open(n, 'wb') as f:
|
||||||
|
f.write(data)
|
||||||
|
with open(n, 'rb') as f:
|
||||||
|
for n, offset in {
|
||||||
|
0:0, 3:0, 13:13
|
||||||
|
}.items():
|
||||||
|
self.assertEqual(data[offset:offset+n], pread_all(f.fileno(), n, offset))
|
||||||
|
self.assertEqual(data, pread_all(f.fileno(), len(data)))
|
||||||
|
|
||||||
def test_copying_of_trees(self):
|
def test_copying_of_trees(self):
|
||||||
src, dest = self.s(), self.d()
|
src, dest = self.s(), self.d()
|
||||||
copy_tree(src, dest)
|
copy_tree(src, dest)
|
||||||
|
@ -28,6 +28,11 @@ typedef unsigned __int8 uint8_t;
|
|||||||
#else
|
#else
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
barename(PyObject *self, PyObject *tag) {
|
barename(PyObject *self, PyObject *tag) {
|
||||||
@ -705,6 +710,69 @@ deepcopy(PyObject *self, PyObject *o) {
|
|||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
pread_all(PyObject *self, PyObject *args) {
|
||||||
|
int fd; unsigned long long n, offset = 0;
|
||||||
|
if (!PyArg_ParseTuple(args, "iK|K", &fd, &n, &offset)) return NULL;
|
||||||
|
#ifdef _WIN32
|
||||||
|
PyObject *msvcrt = PyImport_ImportModule("msvcrt");
|
||||||
|
if (!msvcrt) return NULL;
|
||||||
|
PyObject *get_osfhandle = PyObject_GetAttrString(msvcrt, "get_osfhandle");
|
||||||
|
Py_CLEAR(msvcrt);
|
||||||
|
if (!get_osfhandle) return NULL;
|
||||||
|
PyObject *ret = PyObject_CallFunctionObjArgs(get_osfhandle, PyTuple_GET_ITEM(args, 0), NULL);
|
||||||
|
Py_CLEAR(get_osfhandle);
|
||||||
|
if (!ret) return NULL;
|
||||||
|
HANDLE file = (HANDLE)PyLong_AsUnsignedLongLong(ret);
|
||||||
|
Py_CLEAR(ret);
|
||||||
|
#endif
|
||||||
|
PyObject *output = PyBytes_FromStringAndSize(NULL, n);
|
||||||
|
if (!output || !n) return output;
|
||||||
|
size_t pos = 0;
|
||||||
|
char *buf = PyBytes_AS_STRING(output);
|
||||||
|
int saved_errno = 0;
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
while (pos < n) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
DWORD nr = 0;
|
||||||
|
OVERLAPPED overlapped;
|
||||||
|
memset(&overlapped, 0, sizeof(OVERLAPPED));
|
||||||
|
overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
|
||||||
|
overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
|
||||||
|
SetLastError(0);
|
||||||
|
BOOL ok = ReadFile(file, buf + pos, n - pos, &nr, &overlapped);
|
||||||
|
if (!ok) {
|
||||||
|
DWORD err = GetLastError();
|
||||||
|
if (err != ERROR_HANDLE_EOF) saved_errno = err;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ssize_t nr = pread64(fd, buf + pos, n - pos, offset);
|
||||||
|
if (nr < 0) {
|
||||||
|
if (errno == EINTR || errno == EAGAIN || errno == EBUSY) continue;
|
||||||
|
saved_errno = errno;
|
||||||
|
break;
|
||||||
|
} else if (nr == 0) break;
|
||||||
|
#endif
|
||||||
|
pos += nr;
|
||||||
|
offset += nr;
|
||||||
|
}
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if (saved_errno != 0) {
|
||||||
|
Py_CLEAR(output);
|
||||||
|
#ifdef _WIN32
|
||||||
|
PyErr_SetFromWindowsErr(saved_errno);
|
||||||
|
#else
|
||||||
|
errno = saved_errno;
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (pos < n && _PyBytes_Resize(&output, pos) != 0) return NULL;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
static PyMethodDef speedup_methods[] = {
|
static PyMethodDef speedup_methods[] = {
|
||||||
{"deepcopy", deepcopy, METH_O,
|
{"deepcopy", deepcopy, METH_O,
|
||||||
"deepcopy(object)\n\nFast implementation of deepcopy()"
|
"deepcopy(object)\n\nFast implementation of deepcopy()"
|
||||||
@ -752,6 +820,13 @@ static PyMethodDef speedup_methods[] = {
|
|||||||
"set_thread_name(name)\n\nWrapper for pthread_setname_np"
|
"set_thread_name(name)\n\nWrapper for pthread_setname_np"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{"pread_all", pread_all, METH_VARARGS,
|
||||||
|
"pread_all(fd, n, offset)\n\nRead upto n bytes from the specified fd at offset in a thread safe manner."
|
||||||
|
" If less than n bytes are returned it means there were less than n bytes in the file at offset."
|
||||||
|
" Only works with seekable regular files, not sockets/ttys/etc. Note that on Windows it moves the file pointer"
|
||||||
|
" so cannot be mixed with calls to tell() or ordinary reads."
|
||||||
|
},
|
||||||
|
|
||||||
{"get_num_of_significant_chars", get_num_of_significant_chars, METH_O,
|
{"get_num_of_significant_chars", get_num_of_significant_chars, METH_O,
|
||||||
"get_num_of_significant_chars(elem)\n\nGet the number of chars in specified tag"
|
"get_num_of_significant_chars(elem)\n\nGet the number of chars in specified tag"
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user