@@ -19,43 +19,43 @@ const LibraryExample = {
1919 PHPWASM . EventEmitter = ENVIRONMENT_IS_NODE
2020 ? require ( 'events' ) . EventEmitter
2121 : class EventEmitter {
22- constructor ( ) {
23- this . listeners = { } ;
24- }
25- emit ( eventName , data ) {
26- if ( this . listeners [ eventName ] ) {
27- this . listeners [ eventName ] . forEach (
28- ( callback ) => {
29- callback ( data ) ;
30- }
31- ) ;
32- }
22+ constructor ( ) {
23+ this . listeners = { } ;
24+ }
25+ emit ( eventName , data ) {
26+ if ( this . listeners [ eventName ] ) {
27+ this . listeners [ eventName ] . forEach (
28+ ( callback ) => {
29+ callback ( data ) ;
30+ }
31+ ) ;
3332 }
34- once ( eventName , callback ) {
35- const self = this ;
36- function removedCallback ( ) {
37- callback ( ...arguments ) ;
38- self . removeListener ( eventName , removedCallback ) ;
39- }
40- this . on ( eventName , removedCallback ) ;
33+ }
34+ once ( eventName , callback ) {
35+ const self = this ;
36+ function removedCallback ( ) {
37+ callback ( ...arguments ) ;
38+ self . removeListener ( eventName , removedCallback ) ;
4139 }
42- removeAllListeners ( eventName ) {
43- if ( eventName ) {
44- delete this . listeners [ eventName ] ;
45- } else {
46- this . listeners = { } ;
47- }
40+ this . on ( eventName , removedCallback ) ;
41+ }
42+ removeAllListeners ( eventName ) {
43+ if ( eventName ) {
44+ delete this . listeners [ eventName ] ;
45+ } else {
46+ this . listeners = { } ;
4847 }
49- removeListener ( eventName , callback ) {
50- if ( this . listeners [ eventName ] ) {
51- const idx =
52- this . listeners [ eventName ] . indexOf ( callback ) ;
53- if ( idx !== - 1 ) {
54- this . listeners [ eventName ] . splice ( idx , 1 ) ;
55- }
48+ }
49+ removeListener ( eventName , callback ) {
50+ if ( this . listeners [ eventName ] ) {
51+ const idx =
52+ this . listeners [ eventName ] . indexOf ( callback ) ;
53+ if ( idx !== - 1 ) {
54+ this . listeners [ eventName ] . splice ( idx , 1 ) ;
5655 }
5756 }
58- } ;
57+ }
58+ } ;
5959 PHPWASM . child_proc_by_fd = { } ;
6060 PHPWASM . child_proc_by_pid = { } ;
6161 PHPWASM . input_devices = { } ;
@@ -180,7 +180,7 @@ const LibraryExample = {
180180 } ;
181181 return [ promise , cancel ] ;
182182 } ,
183- noop : function ( ) { } ,
183+ noop : function ( ) { } ,
184184
185185 spawnProcess : function ( command , args , options ) {
186186 if ( Module [ 'spawnProcess' ] ) {
@@ -205,8 +205,8 @@ const LibraryExample = {
205205 }
206206 const e = new Error (
207207 'popen(), proc_open() etc. are unsupported in the browser. Call php.setSpawnHandler() ' +
208- 'and provide a callback to handle spawning processes, or disable a popen(), proc_open() ' +
209- 'and similar functions via php.ini.'
208+ 'and provide a callback to handle spawning processes, or disable a popen(), proc_open() ' +
209+ 'and similar functions via php.ini.'
210210 ) ;
211211 e . code = 'SPAWN_UNSUPPORTED' ;
212212 throw e ;
@@ -256,7 +256,7 @@ const LibraryExample = {
256256 const device = FS . createDevice (
257257 '/dev' ,
258258 filename ,
259- function ( ) { } ,
259+ function ( ) { } ,
260260 function ( byte ) {
261261 try {
262262 dataBuffer . push ( byte ) ;
@@ -323,7 +323,7 @@ const LibraryExample = {
323323 argsArray . push ( UTF8ToString ( HEAPU32 [ charPointer >> 2 ] ) ) ;
324324 }
325325 }
326-
326+
327327 const cwdstr = cwdPtr ? UTF8ToString ( cwdPtr ) : null ;
328328 let envObject = null ;
329329
@@ -449,7 +449,7 @@ const LibraryExample = {
449449 stderrAt += data . length ;
450450 } ) ;
451451 cp . stderr . on ( 'end' , function ( data ) {
452- FS . close ( stderrStream ) ;
452+ FS . close ( stdoutStream ) ;
453453 } ) ;
454454 }
455455
@@ -534,13 +534,14 @@ const LibraryExample = {
534534 return - 1 ;
535535 }
536536 if ( PHPWASM . child_proc_by_pid [ pid ] . exited ) {
537- HEAPU32 [ exitCodePtr >> 2 ] =
538- PHPWASM . child_proc_by_pid [ pid ] . exitCode ;
537+ HEAPU32 [ exitCodePtr >> 2 ] =
538+ PHPWASM . child_proc_by_pid [ pid ] . exitCode ;
539539 return 1 ;
540540 }
541541 return 0 ;
542542 } ,
543543
544+
544545 js_waitpid : function ( pid , exitCodePtr ) {
545546 if ( ! PHPWASM . child_proc_by_pid [ pid ] ) {
546547 return - 1 ;
@@ -549,7 +550,7 @@ const LibraryExample = {
549550 const poll = function ( ) {
550551 if ( PHPWASM . child_proc_by_pid [ pid ] ?. exited ) {
551552 HEAPU32 [ exitCodePtr >> 2 ] =
552- PHPWASM . child_proc_by_pid [ pid ] . exitCode ;
553+ PHPWASM . child_proc_by_pid [ pid ] . exitCode ;
553554 wakeUp ( pid ) ;
554555 } else {
555556 setTimeout ( poll , 50 ) ;
@@ -760,74 +761,91 @@ const LibraryExample = {
760761 * @see https://github.com/emscripten-core/emscripten/issues/13214
761762 */
762763 js_fd_read : function ( fd , iov , iovcnt , pnum ) {
763- var returnCode ;
764- var stream ;
765- try {
766- stream = SYSCALLS . getStreamFromFD ( fd ) ;
767- var num = doReadv ( stream , iov , iovcnt ) ;
768- HEAPU32 [ pnum >> 2 ] = num ;
769- returnCode = 0 ;
770- } catch ( e ) {
771- if ( typeof FS == 'undefined' || ! ( e . name === 'ErrnoError' ) ) throw e ;
772- returnCode = e . errno ;
764+ // Only run the read operation on a regular call,
765+ // never when rewinding the stack.
766+ if ( Asyncify . state === Asyncify . State . Normal ) {
767+ var returnCode ;
768+ var stream ;
769+ let num = 0 ;
770+ try {
771+ stream = SYSCALLS . getStreamFromFD ( fd ) ;
772+ const num = doReadv ( stream , iov , iovcnt ) ;
773+ HEAPU32 [ pnum >> 2 ] = num ;
774+ return 0 ;
775+ } catch ( e ) {
776+ // Rethrow any unexpected non-filesystem errors.
777+ if ( typeof FS == "undefined" || ! ( e . name === "ErrnoError" ) ) {
778+ throw e ;
779+ }
780+ // Only return synchronously if this isn't an asynchronous pipe.
781+ // Error code 6 indicates EWOULDBLOCK – this is our signal to wait.
782+ // We also need to distinguish between a process pipe and a file pipe, otherwise
783+ // reading from an empty file would block until the timeout.
784+ if ( e . errno !== 6 || ! ( stream ?. fd in PHPWASM . child_proc_by_fd ) ) {
785+ // On failure, yield 0 bytes read to indicate EOF.
786+ HEAPU32 [ pnum >> 2 ] = 0 ;
787+ return returnCode
788+ }
789+ }
773790 }
774791
775- // If it's a blocking process pipe, wait for it to become readable.
776- // We need to distinguish between a process pipe and a file pipe, otherwise
777- // reading from an empty file would block until the timeout.
778- if (
779- returnCode === 6 /*EWOULDBLOCK*/ &&
780- stream ?. fd in PHPWASM . child_proc_by_fd
781- ) {
782- // You might wonder why we duplicate the code here instead of always using
783- // Asyncify.handleSleep(). The reason is performance. Most of the time,
784- // the read operation will work synchronously and won't require yielding
785- // back to JS. In these cases we don't want to pay the Asyncify overhead,
786- // save the stack, yield back to JS, restore the stack etc.
787- return Asyncify . handleSleep ( function ( wakeUp ) {
788- var retries = 0 ;
789- var interval = 50 ;
790- var timeout = 5000 ;
791- // We poll for data and give up after a timeout.
792- // We can't simply rely on PHP timeout here because we don't want
793- // to, say, block the entire PHPUnit test suite without any visible
794- // feedback.
795- var maxRetries = timeout / interval ;
796- function poll ( ) {
797- var returnCode ;
798- var stream ;
799- try {
800- stream = SYSCALLS . getStreamFromFD ( fd ) ;
801- var num = doReadv ( stream , iov , iovcnt ) ;
802- HEAPU32 [ pnum >> 2 ] = num ;
803- returnCode = 0 ;
804- } catch ( e ) {
805- if (
806- typeof FS == 'undefined' ||
807- ! ( e . name === 'ErrnoError' )
808- ) {
809- console . error ( e ) ;
810- throw e ;
811- }
812- returnCode = e . errno ;
813- }
814-
792+ // At this point we know we have to poll.
793+ // You might wonder why we duplicate the code here instead of always using
794+ // Asyncify.handleSleep(). The reason is performance. Most of the time,
795+ // the read operation will work synchronously and won't require yielding
796+ // back to JS. In these cases we don't want to pay the Asyncify overhead,
797+ // save the stack, yield back to JS, restore the stack etc.
798+ return Asyncify . handleSleep ( function ( wakeUp ) {
799+ var retries = 0 ;
800+ var interval = 50 ;
801+ var timeout = 5000 ;
802+ // We poll for data and give up after a timeout.
803+ // We can't simply rely on PHP timeout here because we don't want
804+ // to, say, block the entire PHPUnit test suite without any visible
805+ // feedback.
806+ var maxRetries = timeout / interval ;
807+ function poll ( ) {
808+ var returnCode ;
809+ var stream ;
810+ let num ;
811+ try {
812+ stream = SYSCALLS . getStreamFromFD ( fd ) ;
813+ num = doReadv ( stream , iov , iovcnt ) ;
814+ returnCode = 0 ;
815+ } catch ( e ) {
815816 if (
816- returnCode !== 6 ||
817- ++ retries > maxRetries ||
818- ! ( fd in PHPWASM . child_proc_by_fd ) ||
819- PHPWASM . child_proc_by_fd [ fd ] ?. exited ||
820- FS . isClosed ( stream )
817+ typeof FS == 'undefined' ||
818+ ! ( e . name === 'ErrnoError' )
821819 ) {
822- wakeUp ( returnCode ) ;
823- } else {
824- setTimeout ( poll , interval ) ;
820+ console . error ( e ) ;
821+ throw e ;
825822 }
823+ returnCode = e . errno ;
826824 }
827- poll ( ) ;
828- } ) ;
829- }
830- return returnCode ;
825+
826+ const success = returnCode === 0 ;
827+ const failure = (
828+ ++ retries > maxRetries ||
829+ ! ( fd in PHPWASM . child_proc_by_fd ) ||
830+ PHPWASM . child_proc_by_fd [ fd ] ?. exited ||
831+ FS . isClosed ( stream )
832+ ) ;
833+
834+ if ( success ) {
835+ HEAPU32 [ pnum >> 2 ] = num ;
836+ wakeUp ( 0 ) ;
837+ } else if ( failure ) {
838+ // On failure, yield 0 bytes read to indicate EOF.
839+ HEAPU32 [ pnum >> 2 ] = 0 ;
840+ // If the failure is due to a timeout, return 0 to indicate that we
841+ // reached EOF. Otherwise, propagate the error code.
842+ wakeUp ( returnCode === 6 ? 0 : returnCode ) ;
843+ } else {
844+ setTimeout ( poll , interval ) ;
845+ }
846+ }
847+ poll ( ) ;
848+ } ) ;
831849 } ,
832850
833851 /**
0 commit comments