Use OperatingSystem executeCommand:... instead of popen().
--- a/PipeStr.st Sat Sep 07 14:11:39 1996 +0200
+++ b/PipeStr.st Mon Sep 09 12:30:27 1996 +0200
@@ -11,7 +11,7 @@
"
NonPositionableExternalStream subclass:#PipeStream
- instanceVariableNames:'commandString'
+ instanceVariableNames:'commandString pid exitStatus exitSema'
classVariableNames:'BrokenPipeSignal'
poolDictionaries:''
category:'Streams-External'
@@ -130,7 +130,7 @@
%}
! !
-!PipeStream class methodsFor:'documentation'!
+!PipeStream class methodsFor:'documentation'!
copyright
"
@@ -184,7 +184,7 @@
"
! !
-!PipeStream class methodsFor:'initialization'!
+!PipeStream class methodsFor:'initialization'!
initialize
"setup the signal"
@@ -196,7 +196,7 @@
]
! !
-!PipeStream class methodsFor:'instance creation'!
+!PipeStream class methodsFor:'instance creation'!
readingFrom:commandString
"create and return a new pipeStream which can read from the unix command
@@ -204,7 +204,16 @@
^ (self basicNew) readingFrom:commandString
- "PipeStream readingFrom:'ls -l'"
+ "
+ PipeStream readingFrom:'ls -l'
+
+ |s|
+ s := PipeStream readingFrom:'sh -c sleep\ 600'.
+ (Delay forSeconds:2) wait.
+ s shutDown
+ "
+
+ "Modified: 24.4.1996 / 09:09:25 / stefan"
!
writingTo:commandString
@@ -216,7 +225,7 @@
"PipeStream writingTo:'sort'"
! !
-!PipeStream class methodsFor:'Signal constants'!
+!PipeStream class methodsFor:'Signal constants'!
brokenPipeSignal
"return the signal used to handle SIGPIPE unix-signals"
@@ -230,30 +239,38 @@
"return the command string"
^ commandString
+!
+
+exitStatus
+ "return exitStatus"
+
+ ^ exitStatus
+
+ "Created: 28.12.1995 / 14:54:41 / stefan"
+!
+
+pid
+ "return pid"
+
+ ^ pid
+
+ "Created: 28.12.1995 / 14:54:30 / stefan"
! !
!PipeStream methodsFor:'instance release'!
closeFile
- "low level close - redefined since we close a pipe here.
+ "low level close
This waits for the command to finish.
Use shutDown for a fast (nonBlocking) close."
-%{ /* UNLIMITEDSTACK */
-#if !defined(transputer) && !defined(MSDOS_LIKE)
- OBJ fp;
-
- if ((fp = __INST(filePointer)) != nil) {
- __INST(filePointer) = nil;
- /*
- * allow interrupt even when blocking here ...
- */
- __BEGIN_INTERRUPTABLE__
- pclose(__FILEVal(fp));
- __END_INTERRUPTABLE__
- }
-#endif /* not transputer && not MSDOS_LIKE */
-%}
+ filePointer notNil ifTrue:[
+ super closeFile.
+ filePointer := nil.
+ pid notNil ifTrue:[
+ exitSema wait.
+ ].
+ ].
!
closeFileDescriptor
@@ -270,8 +287,8 @@
if ((fp = __INST(filePointer)) != nil) {
__INST(filePointer) = nil;
+ f = __FILEVal(fp);
__BEGIN_INTERRUPTABLE__
- f = __FILEVal(fp);
close(fileno(f));
__END_INTERRUPTABLE__
}
@@ -286,12 +303,27 @@
!
shutDown
- "close the Stream, ignoring any broken-pipe errors"
+ "close the Stream, ignoring any broken-pipe errors.
+ Terminate the command"
BrokenPipeSignal catch:[
- Lobby unregister:self.
- self closeFileDescriptor
+ |tpid|
+
+ Lobby unregister:self.
+ self closeFileDescriptor.
+ tpid := pid. "copy pid to avoid race"
+ tpid notNil ifTrue:[
+ "/
+ "/ Terminate both the process and group, just in case the
+ "/ operating system does not support process groups.
+ "/
+ OperatingSystem terminateProcess:tpid.
+ OperatingSystem terminateProcessGroup:tpid.
+ pid := nil.
+ ].
]
+
+ "Modified: 23.5.1996 / 09:15:41 / stefan"
! !
!PipeStream methodsFor:'private'!
@@ -323,68 +355,79 @@
!
openPipeFor:aCommandString withMode:mode
- "open a pipe to the unix command in aCcommandString;
+ "open a pipe to the unix command in commandString;
mode may be 'r' or 'w'"
- |retVal|
+ |blocked pipeFdArray execFdArray execFd myFd|
filePointer notNil ifTrue:[
- "the pipe was already open ...
- this should (can) not happen."
- ^ self errorOpen
+ "the pipe was already open ...
+ this should (can) not happen."
+ ^ self errorOpen
+ ].
+ lastErrorNumber := nil.
+ exitStatus := nil.
+ exitSema := Semaphore new.
+
+ pipeFdArray := OperatingSystem makePipe.
+ pipeFdArray isNil ifTrue:[
+ lastErrorNumber := OperatingSystem currentErrorNumber.
+ ^ self openError
+ ].
+
+ mode = 'r' ifTrue:[
+ execFd := pipeFdArray at:2.
+ execFdArray := Array with:0 with:execFd with:2.
+ myFd := pipeFdArray at:1.
+ ] ifFalse:[
+ execFd := pipeFdArray at:1.
+ execFdArray := Array with:execFd with:1 with:2.
+ myFd := pipeFdArray at:2.
].
-%{ /* STACK: 32000 */
-#if !defined(transputer) && !defined(MSDOS_LIKE)
- FILE *f;
- OBJ fp;
-
- __INST(lastErrorNumber) = nil;
-
- if (__isString(aCommandString) && __isString(mode)) {
- __BEGIN_INTERRUPTABLE__
- do {
-# ifdef LINUX
- /* LINUX returns a non-NULL f even when interrupted */
- errno = 0;
- f = (FILE *)popen((char *) __stringVal(aCommandString),
- (char *) __stringVal(mode));
- if (errno == EINTR)
- f = NULL;
-# else
- f = (FILE *)popen((char *) __stringVal(aCommandString),
- (char *) __stringVal(mode));
-# endif /* LINUX */
- } while ((f == NULL) && (errno == EINTR));
- __END_INTERRUPTABLE__
+ blocked := OperatingSystem blockInterrupts.
+ pid := OperatingSystem exec:'/bin/sh'
+ withArguments:(Array with:'sh' with:'-c' with:aCommandString)
+ fileDescriptors:execFdArray
+ closeDescriptors:(Array with:myFd)
+ fork:true
+ newPgrp:true.
- if (f == NULL) {
- __INST(lastErrorNumber) = __MKSMALLINT(errno);
- } else {
- clearerr(f);
- __INST(filePointer) = fp = __MKOBJ(f); __STORE(self, fp);
- retVal = self;
- }
- }
-#endif /* not transputer && not MSDOS_LIKE */
-%}.
- retVal notNil ifTrue:[
- commandString := aCommandString.
- buffered := true.
- hitEOF := false.
- binary := false.
- Lobby register:self
+ OperatingSystem closeFd:execFd.
+ pid > 0 ifTrue:[
+ self fileDescriptor:myFd withMode:mode.
+ Processor monitorPid:pid action:[ :stat |
+ exitStatus := stat.
+ pid := nil.
+ exitSema signal.
+ ].
+ ] ifFalse:[
+ pid := nil.
+ lastErrorNumber := OperatingSystem currentErrorNumber.
+ OperatingSystem closeFd:myFd.
+ ].
+ blocked ifFalse:[
+ OperatingSystem unblockInterrupts
].
- lastErrorNumber notNil ifTrue:[
- "
- the pipe open failed for some reason ...
- ... this may be either due to an invalid command string,
- or due to the system running out of memory (when forking
- the unix process)
- "
- ^ self openError
+
+ lastErrorNumber isNil ifTrue:[
+ commandString := aCommandString.
+ buffered := true.
+ hitEOF := false.
+ binary := false.
+ Lobby register:self
+ ] ifFalse:[
+ "
+ the pipe open failed for some reason ...
+ ... this may be either due to an invalid command string,
+ or due to the system running out of memory (when forking
+ the unix process)
+ "
+ ^ self openError
].
- ^ retVal
+ ^ self
+
+ "Modified: 23.4.1996 / 17:05:59 / stefan"
!
readingFrom:command
@@ -401,9 +444,9 @@
^ self openPipeFor:command withMode:'w'
! !
-!PipeStream class methodsFor:'documentation'!
+!PipeStream class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/Attic/PipeStr.st,v 1.43 1996-04-25 17:01:50 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/Attic/PipeStr.st,v 1.44 1996-09-09 10:30:27 stefan Exp $'
! !
PipeStream initialize!
--- a/PipeStream.st Sat Sep 07 14:11:39 1996 +0200
+++ b/PipeStream.st Mon Sep 09 12:30:27 1996 +0200
@@ -11,7 +11,7 @@
"
NonPositionableExternalStream subclass:#PipeStream
- instanceVariableNames:'commandString'
+ instanceVariableNames:'commandString pid exitStatus exitSema'
classVariableNames:'BrokenPipeSignal'
poolDictionaries:''
category:'Streams-External'
@@ -130,7 +130,7 @@
%}
! !
-!PipeStream class methodsFor:'documentation'!
+!PipeStream class methodsFor:'documentation'!
copyright
"
@@ -184,7 +184,7 @@
"
! !
-!PipeStream class methodsFor:'initialization'!
+!PipeStream class methodsFor:'initialization'!
initialize
"setup the signal"
@@ -196,7 +196,7 @@
]
! !
-!PipeStream class methodsFor:'instance creation'!
+!PipeStream class methodsFor:'instance creation'!
readingFrom:commandString
"create and return a new pipeStream which can read from the unix command
@@ -204,7 +204,16 @@
^ (self basicNew) readingFrom:commandString
- "PipeStream readingFrom:'ls -l'"
+ "
+ PipeStream readingFrom:'ls -l'
+
+ |s|
+ s := PipeStream readingFrom:'sh -c sleep\ 600'.
+ (Delay forSeconds:2) wait.
+ s shutDown
+ "
+
+ "Modified: 24.4.1996 / 09:09:25 / stefan"
!
writingTo:commandString
@@ -216,7 +225,7 @@
"PipeStream writingTo:'sort'"
! !
-!PipeStream class methodsFor:'Signal constants'!
+!PipeStream class methodsFor:'Signal constants'!
brokenPipeSignal
"return the signal used to handle SIGPIPE unix-signals"
@@ -230,30 +239,38 @@
"return the command string"
^ commandString
+!
+
+exitStatus
+ "return exitStatus"
+
+ ^ exitStatus
+
+ "Created: 28.12.1995 / 14:54:41 / stefan"
+!
+
+pid
+ "return pid"
+
+ ^ pid
+
+ "Created: 28.12.1995 / 14:54:30 / stefan"
! !
!PipeStream methodsFor:'instance release'!
closeFile
- "low level close - redefined since we close a pipe here.
+ "low level close
This waits for the command to finish.
Use shutDown for a fast (nonBlocking) close."
-%{ /* UNLIMITEDSTACK */
-#if !defined(transputer) && !defined(MSDOS_LIKE)
- OBJ fp;
-
- if ((fp = __INST(filePointer)) != nil) {
- __INST(filePointer) = nil;
- /*
- * allow interrupt even when blocking here ...
- */
- __BEGIN_INTERRUPTABLE__
- pclose(__FILEVal(fp));
- __END_INTERRUPTABLE__
- }
-#endif /* not transputer && not MSDOS_LIKE */
-%}
+ filePointer notNil ifTrue:[
+ super closeFile.
+ filePointer := nil.
+ pid notNil ifTrue:[
+ exitSema wait.
+ ].
+ ].
!
closeFileDescriptor
@@ -270,8 +287,8 @@
if ((fp = __INST(filePointer)) != nil) {
__INST(filePointer) = nil;
+ f = __FILEVal(fp);
__BEGIN_INTERRUPTABLE__
- f = __FILEVal(fp);
close(fileno(f));
__END_INTERRUPTABLE__
}
@@ -286,12 +303,27 @@
!
shutDown
- "close the Stream, ignoring any broken-pipe errors"
+ "close the Stream, ignoring any broken-pipe errors.
+ Terminate the command"
BrokenPipeSignal catch:[
- Lobby unregister:self.
- self closeFileDescriptor
+ |tpid|
+
+ Lobby unregister:self.
+ self closeFileDescriptor.
+ tpid := pid. "copy pid to avoid race"
+ tpid notNil ifTrue:[
+ "/
+ "/ Terminate both the process and group, just in case the
+ "/ operating system does not support process groups.
+ "/
+ OperatingSystem terminateProcess:tpid.
+ OperatingSystem terminateProcessGroup:tpid.
+ pid := nil.
+ ].
]
+
+ "Modified: 23.5.1996 / 09:15:41 / stefan"
! !
!PipeStream methodsFor:'private'!
@@ -323,68 +355,79 @@
!
openPipeFor:aCommandString withMode:mode
- "open a pipe to the unix command in aCcommandString;
+ "open a pipe to the unix command in commandString;
mode may be 'r' or 'w'"
- |retVal|
+ |blocked pipeFdArray execFdArray execFd myFd|
filePointer notNil ifTrue:[
- "the pipe was already open ...
- this should (can) not happen."
- ^ self errorOpen
+ "the pipe was already open ...
+ this should (can) not happen."
+ ^ self errorOpen
+ ].
+ lastErrorNumber := nil.
+ exitStatus := nil.
+ exitSema := Semaphore new.
+
+ pipeFdArray := OperatingSystem makePipe.
+ pipeFdArray isNil ifTrue:[
+ lastErrorNumber := OperatingSystem currentErrorNumber.
+ ^ self openError
+ ].
+
+ mode = 'r' ifTrue:[
+ execFd := pipeFdArray at:2.
+ execFdArray := Array with:0 with:execFd with:2.
+ myFd := pipeFdArray at:1.
+ ] ifFalse:[
+ execFd := pipeFdArray at:1.
+ execFdArray := Array with:execFd with:1 with:2.
+ myFd := pipeFdArray at:2.
].
-%{ /* STACK: 32000 */
-#if !defined(transputer) && !defined(MSDOS_LIKE)
- FILE *f;
- OBJ fp;
-
- __INST(lastErrorNumber) = nil;
-
- if (__isString(aCommandString) && __isString(mode)) {
- __BEGIN_INTERRUPTABLE__
- do {
-# ifdef LINUX
- /* LINUX returns a non-NULL f even when interrupted */
- errno = 0;
- f = (FILE *)popen((char *) __stringVal(aCommandString),
- (char *) __stringVal(mode));
- if (errno == EINTR)
- f = NULL;
-# else
- f = (FILE *)popen((char *) __stringVal(aCommandString),
- (char *) __stringVal(mode));
-# endif /* LINUX */
- } while ((f == NULL) && (errno == EINTR));
- __END_INTERRUPTABLE__
+ blocked := OperatingSystem blockInterrupts.
+ pid := OperatingSystem exec:'/bin/sh'
+ withArguments:(Array with:'sh' with:'-c' with:aCommandString)
+ fileDescriptors:execFdArray
+ closeDescriptors:(Array with:myFd)
+ fork:true
+ newPgrp:true.
- if (f == NULL) {
- __INST(lastErrorNumber) = __MKSMALLINT(errno);
- } else {
- clearerr(f);
- __INST(filePointer) = fp = __MKOBJ(f); __STORE(self, fp);
- retVal = self;
- }
- }
-#endif /* not transputer && not MSDOS_LIKE */
-%}.
- retVal notNil ifTrue:[
- commandString := aCommandString.
- buffered := true.
- hitEOF := false.
- binary := false.
- Lobby register:self
+ OperatingSystem closeFd:execFd.
+ pid > 0 ifTrue:[
+ self fileDescriptor:myFd withMode:mode.
+ Processor monitorPid:pid action:[ :stat |
+ exitStatus := stat.
+ pid := nil.
+ exitSema signal.
+ ].
+ ] ifFalse:[
+ pid := nil.
+ lastErrorNumber := OperatingSystem currentErrorNumber.
+ OperatingSystem closeFd:myFd.
+ ].
+ blocked ifFalse:[
+ OperatingSystem unblockInterrupts
].
- lastErrorNumber notNil ifTrue:[
- "
- the pipe open failed for some reason ...
- ... this may be either due to an invalid command string,
- or due to the system running out of memory (when forking
- the unix process)
- "
- ^ self openError
+
+ lastErrorNumber isNil ifTrue:[
+ commandString := aCommandString.
+ buffered := true.
+ hitEOF := false.
+ binary := false.
+ Lobby register:self
+ ] ifFalse:[
+ "
+ the pipe open failed for some reason ...
+ ... this may be either due to an invalid command string,
+ or due to the system running out of memory (when forking
+ the unix process)
+ "
+ ^ self openError
].
- ^ retVal
+ ^ self
+
+ "Modified: 23.4.1996 / 17:05:59 / stefan"
!
readingFrom:command
@@ -401,9 +444,9 @@
^ self openPipeFor:command withMode:'w'
! !
-!PipeStream class methodsFor:'documentation'!
+!PipeStream class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/PipeStream.st,v 1.43 1996-04-25 17:01:50 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/PipeStream.st,v 1.44 1996-09-09 10:30:27 stefan Exp $'
! !
PipeStream initialize!