ExternalStream.st
changeset 23897 cb46a48b02b5
parent 23879 363bed19a5fa
child 23899 d7faafb6ee88
--- a/ExternalStream.st	Wed Mar 13 17:04:15 2019 +0100
+++ b/ExternalStream.st	Wed Mar 13 17:08:50 2019 +0100
@@ -1897,7 +1897,7 @@
 
 !ExternalStream class methodsFor:'defaults'!
 
-bufferSizeForBulkFileCopy
+bufferSizeForBulkCopy
     "return the size of buffer used when copying big files/buld data from one stream to another.
      Due to a bug on older Windows systems, the default used
      is chosen very conservatively, as the copy used to fail with big buffers.
@@ -1911,14 +1911,16 @@
     DefaultCopyBufferSize notNil ifTrue:[^ DefaultCopyBufferSize].
 
     OperatingSystem isMSDOSlike ifTrue:[
-	OperatingSystem isWin7Like ifTrue:[
-	    ^ 64*1024
-	] ifFalse:[
-	    "/ mhmh - NT hangs, when copying bigger blocks to a network drive - why ?
-	    ^ 1 * 1024.
-	].
+        OperatingSystem isWin7Like ifTrue:[
+            ^ 64*1024
+        ] ifFalse:[
+            "/ mhmh - NT hangs, when copying bigger blocks to a network drive - why ?
+            ^ 1 * 1024.
+        ].
     ].
     ^ 32 * 1024.
+
+    "Created: / 13-03-2019 / 16:49:17 / Stefan Vogel"
 !
 
 defaultCopyBufferSize:anInteger
@@ -3138,37 +3140,57 @@
     "Modified: / 15.1.1998 / 11:49:48 / stefan"
 !
 
-copyToEndFrom:inStream
-    "read from inStream, and write all data up to the end to the receiver.
+copy:numberOfBytesOrNil into:outStream bufferSize:bufferSize
+    "read from the receiver, and write numberOfBytes data to another aWriteStream.
      Return the number of bytes which have been transferred.
-     Same functionality as copyToEnd:, but reversed arg and receiver
-     (useful in a cascade message of the writeStream)"
-
-    ^ inStream copyToEndInto:self bufferSize:(self class bufferSizeForBulkFileCopy)
+     If nuberOfBytesOrNil is nil, copy until the end of myself.
+     Redefined to use operating system features to do a fast copy."
+
+    |pos n nWritten|
+
+    outStream isExternalStream ifTrue:[
+        "sendfile() in Linux does not support any combination of file/pipe/socket fds.
+         #copyFromFd:toFd:startIndex:count is curently not available in windows."
+
+        pos := self position.
+        numberOfBytesOrNil isNil ifTrue:[
+            n := self size - pos.
+        ] ifFalse:[
+            n := numberOfBytesOrNil.
+        ].
+        nWritten := OperatingSystem
+                        copyFromFd:self fileHandle
+                        toFd:outStream fileHandle
+                        startIndex:pos
+                        count:n.
+        nWritten > 0 ifTrue:[
+            self position:pos+nWritten.
+        ].
+        nWritten = n ifTrue:[
+            ^ self
+        ].
+    ].
+
+    "fall back..."
+    ^ super copy:numberOfBytesOrNil into:outStream bufferSize:bufferSize.
 
     "
      |in out|
 
-     in := 'Makefile' asFilename readStream.
-     out := Stdout.
+     in := 'Make.proto' asFilename readStream.
+     in copyToEndInto:Stdout.
+     in close.
+
+     |in out|
+
+     in := 'Make.proto' asFilename readStream.
+     out := '/tmp/test' asFilename writeStream.
      in copyToEndInto:out.
-     in close.
+     in close. out close.
+     '/tmp/test' asFilename contents.
     "
-!
-
-copyToEndInto:outStream
-    "copy the data into another stream."
-
-    ^ self copyToEndInto:outStream bufferSize:(self class bufferSizeForBulkFileCopy)
-
-    "
-     |in out|
-
-     in := 'Makefile' asFilename readStream.
-     out := Stdout.
-     in copyToEndInto:out.
-     in close.
-    "
+
+    "Created: / 13-03-2019 / 16:27:04 / Stefan Vogel"
 !
 
 ioctl:ioctlNumber
@@ -3722,102 +3744,102 @@
      || (__INST(handleType) == @symbol(socketFilePointer))
      || (__INST(handleType) == @symbol(socketHandle))
      || (__INST(handleType) == @symbol(pipeFilePointer))) {
-	if (((fp = __INST(handle)) != nil)
-	    && (__INST(mode) != @symbol(writeonly))
-	    && __bothSmallInteger(count, start)
-	) {
-	    f = __FILEVal(fp);
-
-	    cnt = __intVal(count);
-	    offs = __intVal(start) - 1;
-
-	    if (__isExternalBytesLike(anObject)) {
-		OBJ sz;
-
-		nInstBytes = 0;
-		extPtr = (char *)(__externalBytesAddress(anObject));
-		if (extPtr == NULL) goto bad;
-		sz = __externalBytesSize(anObject);
-		if (__isSmallInteger(sz)) {
-		    objSize = __intVal(sz);
-		} else {
-		    objSize = 0; /* unknown */
-		}
-	    } else {
-		OBJ oClass = __Class(anObject);
-		int nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars);
-
-		nInstBytes = OHDR_SIZE + __OBJS2BYTES__(nInstVars);
-
-		switch (__intVal(__ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
-		    case BYTEARRAY:
-		    case WORDARRAY:
-		    case LONGARRAY:
-		    case SWORDARRAY:
-		    case SLONGARRAY:
-		    case FLOATARRAY:
-			break;
-		    case DOUBLEARRAY:
+        if (((fp = __INST(handle)) != nil)
+            && (__INST(mode) != @symbol(writeonly))
+            && __bothSmallInteger(count, start)
+        ) {
+            f = __FILEVal(fp);
+
+            cnt = __intVal(count);
+            offs = __intVal(start) - 1;
+
+            if (__isExternalBytesLike(anObject)) {
+                OBJ sz;
+
+                nInstBytes = 0;
+                extPtr = (char *)(__externalBytesAddress(anObject));
+                if (extPtr == NULL) goto bad;
+                sz = __externalBytesSize(anObject);
+                if (__isSmallInteger(sz)) {
+                    objSize = __intVal(sz);
+                } else {
+                    objSize = 0; /* unknown */
+                }
+            } else {
+                OBJ oClass = __Class(anObject);
+                int nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars);
+
+                nInstBytes = OHDR_SIZE + __OBJS2BYTES__(nInstVars);
+
+                switch (__intVal(__ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
+                    case BYTEARRAY:
+                    case WORDARRAY:
+                    case LONGARRAY:
+                    case SWORDARRAY:
+                    case SLONGARRAY:
+                    case FLOATARRAY:
+                        break;
+                    case DOUBLEARRAY:
 #ifdef __NEED_DOUBLE_ALIGN
-			nInstBytes = (nInstBytes-1+__DOUBLE_ALIGN) &~ (__DOUBLE_ALIGN-1);
+                        nInstBytes = (nInstBytes-1+__DOUBLE_ALIGN) &~ (__DOUBLE_ALIGN-1);
 #endif
-			break;
-		    case LONGLONGARRAY:
-		    case SLONGLONGARRAY:
+                        break;
+                    case LONGLONGARRAY:
+                    case SLONGLONGARRAY:
 #ifdef __NEED_LONGLONG_ALIGN
-			nInstBytes = (nInstBytes-1+__LONGLONG_ALIGN) &~ (__LONGLONG_ALIGN-1);
+                        nInstBytes = (nInstBytes-1+__LONGLONG_ALIGN) &~ (__LONGLONG_ALIGN-1);
 #endif
-			break;
-		    default:
-			goto bad;
-		}
-		extPtr = (char *)0;
-		objSize = __Size(anObject) - nInstBytes;
-	    }
-
-	    if ((offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs))) {
-		_buffered = (__INST(buffered) == true);
-		if (_buffered) {
-		    __READING__(f);
-		}
-
-		if (extPtr) {
-		    __READAVAILBYTES__(ret, f, extPtr+offs, cnt, _buffered, __INST(handleType));
-		} else {
-		    /*
-		     * on interrupt, anObject may be moved to another location.
-		     * So we pass (char *)__InstPtr(anObject) + nInstBytes + offs to the macro __READ_BYTES__,
-		     * to get a new address.
-		     */
-		    offs += nInstBytes;
-		    __READAVAILBYTES_OBJ__(ret, f, anObject, offs, cnt, _buffered, __INST(handleType));
-		}
-		/* 0 is NOT an EOF condition here ... */
-		if (ret >= 0) {
-		    if (__isSmallInteger(__INST(position))) {
-			INT np = __intVal(__INST(position)) + ret;
-			OBJ t;
-
-			t = __MKINT(np); __INST(position) = t; __STORE(self, t);
-		    } else {
-			__INST(position) = nil; /* i.e. do not know */
-		    }
-		    RETURN (__mkSmallInteger(ret));
-		}
-		__INST(position) = nil;
+                        break;
+                    default:
+                        goto bad;
+                }
+                extPtr = (char *)0;
+                objSize = __Size(anObject) - nInstBytes;
+            }
+
+            if ((offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs))) {
+                _buffered = (__INST(buffered) == true);
+                if (_buffered) {
+                    __READING__(f);
+                }
+
+                if (extPtr) {
+                    __READAVAILBYTES__(ret, f, extPtr+offs, cnt, _buffered, __INST(handleType));
+                } else {
+                    /*
+                     * on interrupt, anObject may be moved to another location.
+                     * So we pass (char *)__InstPtr(anObject) + nInstBytes + offs to the macro __READ_BYTES__,
+                     * to get a new address.
+                     */
+                    offs += nInstBytes;
+                    __READAVAILBYTES_OBJ__(ret, f, anObject, offs, cnt, _buffered, __INST(handleType));
+                }
+                /* 0 is NOT an EOF condition here ... */
+                if (ret >= 0) {
+                    if (__isSmallInteger(__INST(position))) {
+                        INT np = __intVal(__INST(position)) + ret;
+                        OBJ t;
+
+                        t = __MKINT(np); __INST(position) = t; __STORE(self, t);
+                    } else {
+                        __INST(position) = nil; /* i.e. do not know */
+                    }
+                    RETURN (__mkSmallInteger(ret));
+                }
+                __INST(position) = nil;
 # ifdef __win32__
-		__threadErrno = __WIN32_ERR(GetLastError());
+                __threadErrno = __WIN32_ERR(GetLastError());
 # endif
-		error = __mkSmallInteger(__threadErrno);
-	    }
-	}
+                error = __mkSmallInteger(__threadErrno);
+            }
+        }
     }
 bad: ;
 %}.
     hitEOF ifTrue:[^ 0].
     error notNil ifTrue:[
-	lastErrorNumber := error.
-	^ self readError:error
+        lastErrorNumber := error.
+        ^ self readError:error
     ].
     handle isNil ifTrue:[^ self errorNotOpen].
     (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
@@ -3826,7 +3848,7 @@
     "
     ^ self primitiveFailed
 
-    "Modified: / 22-11-2018 / 14:44:51 / Stefan Vogel"
+    "Modified: / 13-03-2019 / 17:07:07 / Stefan Vogel"
 !
 
 nextByte