+ var stderr: Writer = new Stderr is protected writable, lazy
+
+ # Enumeration for buffer mode full (flushes when buffer is full)
+ fun buffer_mode_full: Int is extern "file_Sys_Sys_buffer_mode_full_0"
+ # Enumeration for buffer mode line (flushes when a `\n` is encountered)
+ fun buffer_mode_line: Int is extern "file_Sys_Sys_buffer_mode_line_0"
+ # Enumeration for buffer mode none (flushes ASAP when something is written)
+ fun buffer_mode_none: Int is extern "file_Sys_Sys_buffer_mode_none_0"
+
+ # returns first available stream to read or write to
+ # return null on interruption (possibly a signal)
+ protected fun poll( streams : Sequence[FileStream] ) : nullable FileStream
+ do
+ var in_fds = new Array[Int]
+ var out_fds = new Array[Int]
+ var fd_to_stream = new HashMap[Int,FileStream]
+ for s in streams do
+ var fd = s.fd
+ if s isa FileReader then in_fds.add( fd )
+ if s isa FileWriter then out_fds.add( fd )
+
+ fd_to_stream[fd] = s
+ end
+
+ var polled_fd = intern_poll( in_fds, out_fds )
+
+ if polled_fd == null then
+ return null
+ else
+ return fd_to_stream[polled_fd]
+ end
+ end
+
+ private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]) : nullable Int is extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{
+ int in_len, out_len, total_len;
+ struct pollfd *c_fds;
+ sigset_t sigmask;
+ int i;
+ int first_polled_fd = -1;
+ int result;
+
+ in_len = Array_of_Int_length( in_fds );
+ out_len = Array_of_Int_length( out_fds );
+ total_len = in_len + out_len;
+ c_fds = malloc( sizeof(struct pollfd) * total_len );
+
+ /* input streams */
+ for ( i=0; i<in_len; i ++ ) {
+ int fd;
+ fd = Array_of_Int__index( in_fds, i );
+
+ c_fds[i].fd = fd;
+ c_fds[i].events = POLLIN;
+ }
+
+ /* output streams */
+ for ( i=0; i<out_len; i ++ ) {
+ int fd;
+ fd = Array_of_Int__index( out_fds, i );
+
+ c_fds[i].fd = fd;
+ c_fds[i].events = POLLOUT;
+ }
+
+ /* poll all fds, unlimited timeout */
+ result = poll( c_fds, total_len, -1 );
+
+ if ( result > 0 ) {
+ /* analyse results */
+ for ( i=0; i<total_len; i++ )
+ if ( c_fds[i].revents & c_fds[i].events || /* awaited event */
+ c_fds[i].revents & POLLHUP ) /* closed */
+ {
+ first_polled_fd = c_fds[i].fd;
+ break;
+ }
+
+ return Int_as_nullable( first_polled_fd );
+ }
+ else if ( result < 0 )
+ fprintf( stderr, "Error in Stream:poll: %s\n", strerror( errno ) );
+
+ return null_Int();
+ `}