Attachment "sendfile.diff" to
ticket [6ad9883ccf]
added by
chw
2023-12-24 13:43:59.
Index: unix/tclUnixFCmd.c
==================================================================
--- unix/tclUnixFCmd.c
+++ unix/tclUnixFCmd.c
@@ -47,10 +47,13 @@
#endif
#endif /* !HAVE_STRUCT_STAT_ST_BLKSIZE */
#ifdef HAVE_FTS
#include <fts.h>
#endif
+#ifdef linux
+#include <sys/sendfile.h>
+#endif
/*
* The following constants specify the type of callback when
* TraverseUnixTree() calls the traverseProc()
*/
@@ -545,10 +548,13 @@
{
int srcFd, dstFd;
size_t blockSize; /* Optimal I/O blocksize for filesystem */
char *buffer; /* Data buffer for copy */
ssize_t nread;
+#ifdef linux
+ size_t count, sfBlockSize;
+#endif
#ifdef DJGPP
#define BINMODE |O_BINARY
#else
#define BINMODE
@@ -598,10 +604,39 @@
*/
if (blockSize <= 0) {
blockSize = DEFAULT_COPY_BLOCK_SIZE;
}
+
+#ifdef linux
+ /*
+ * Try to use sendfile() system call for speed.
+ */
+
+ sfBlockSize = statBufPtr->st_size;
+ if (sfBlockSize > 0x10000000) {
+ sfBlockSize = 0x10000000; /* Should be < 0x7FFFF000. */
+ } else if (sfBlockSize <= 0) {
+ sfBlockSize = blockSize * 256;
+ }
+ count = 0;
+ do {
+ nread = sendfile(dstFd, srcFd, NULL, sfBlockSize);
+ if (nread == -1) {
+ if ((count == 0) && ((errno == EINVAL) || (errno == ENOSYS))) {
+ /* Fallback to slow r/w based copy operation. */
+ goto slowCopy;
+ }
+ break;
+ }
+ count++;
+ } while (nread > 0);
+ goto done;
+
+ slowCopy:
+#endif
+
buffer = (char *)Tcl_Alloc(blockSize);
while (1) {
nread = read(srcFd, buffer, blockSize);
if ((nread == -1) || (nread == 0)) {
break;
@@ -611,10 +646,14 @@
break;
}
}
Tcl_Free(buffer);
+
+#ifdef linux
+ done:
+#endif
close(srcFd);
if ((close(dstFd) != 0) || (nread == -1)) {
unlink(dst); /* INTL: Native. */
return TCL_ERROR;
}