On Thu, Jul 29, 1999 at 12:19:10 +0200, George Russell wrote:
> I would like to add my strong support, as the person in charge of
> transferring the UniForM workbench, for the implementation of wait
> functions on input and output handles and input on Posix.FD which don't
> block everything else to be done urgently.

Wanna have a workaround for this? :-)

Today, I was playing around with green-card, and now I do have an (almost)
non-blocking hGetline...

Consider this piece of code, which was suggested by Peter Amstutz, who
started this thread:

\begin{code}
main = do
    hSetBuffering stdin NoBuffering
    forkIO (loop 'a')
    booga
  where
      loop ch = hPutChar stdout ch >> loop ch
      booga   = do out <- almostPreemptiveGetLine 100 stdin
                   hPutStrLn stdout out
                   booga
\end{code}

After starting this program, you get blasted by 'a' chars, and if you type
in a line (still getting your terminal full of a's), it is printed in the
middle of these a's, just as one would expect...

Do I get a cookie now? :-)


How was this achieved?
Basically, I made a Haskell wrapper for select(2), so if one needs another
preemptive Input/Output function, it is possible to (non-blockingly) test,
whether there is I/O ready...

This is not really a solution, but I bet, it'll work in quite some
situations until Concurrent Haskell is *really* preemptive. ;-)

BTW: This should work with sockets, too, I didn't test, but I did a directly
coded (i.e. without green-card), similar function for sockets some weeks
ago, which worked...

Source code (~5K) follows in attachment...


Cheers,
Michael
-- 
W*ndoze NT is faster...                                 CRASHING!
{-
 - HSelect.gc - a Haskell interface for select(2)
 - Copyright (C) 1999 Michael Weber <[EMAIL PROTECTED]>
 - Version 0.1
 -
 - This library is free software; you can redistribute it and/or
 - modify it under the terms of the GNU Library General Public
 - License as published by the Free Software Foundation; either
 - version 2 of the License, or (at your option) any later version.
 -              
 - This library is distributed in the hope that it will be useful,
 - but WITHOUT ANY WARRANTY; without even the implied warranty of
 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - Library General Public License for more details.
 -                              
 - You should have received a copy of the GNU Library General Public
 - License along with this library; if not, write to the Free
 - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 -}
 
module HSelect 
    ( FdStatus(..) -- :: Error | Timeout | IOAvail
    , FdList       -- :: [Int]
    , testHandles  -- :: [Handle] -> [Handle] -> [Handle] -> Int -> Int -> IO FdStatus
    , testFds      -- :: FdList -> FdList -> FdList -> Int -> Int -> IO FdStatus
    ) 
where

import StdDIS
import Monad (zipWithM_)
import IO(Handle)
import PrelHandle (getHandleFd)

%#include "hSelect.h"

-- The Good... ----------------------------------------------------------------
type FdList = [Int]

%enum FdStatus (Eq,Show) Int 
%    [ Error   = {-1}
%    , Timeout = {0}
%    , IOAvail = {1}
%    ]

testHandles :: [Handle] -> [Handle] -> [Handle] -> Int -> Int -> IO FdStatus
testHandles inh outh exh tsec tmsec = do
    inFd  <- mapM getHandleFd inh
    outFd <- mapM getHandleFd outh
    exFd  <- mapM getHandleFd exh
    testFds inFd outFd exFd tsec tmsec

%fun testFds :: FdList -> FdList -> FdList -> Int -> Int -> IO FdStatus

-- ...the Bad... --------------------------------------------------------------
%dis fdList x = fdList_ (addr ({int *} x))

-- stolen and adjusted from Green-Cards lib/ghc/StdDIS.gc
marshall_fdList_ :: FdList -> IO Addr
marshall_fdList_ cs =
 do arr <- allocIntStar (1 + length cs)
    zipWithM_ (writeIntAddr arr) [0..] (cs ++ [-1])
    return arr

unmarshall_fdList_ :: Addr -> IO FdList
unmarshall_fdList_ ptr = reads [] 0
  where
    reads str i =
      readIntAddr ptr i >>= \c ->
      if c == -1 then
        return (reverse str)
      else
        reads (c:str) (i+1)

%fun allocIntStar :: Int -> IO Addr
%{ res1 = (int *)calloc(sizeof(int),arg1); %}
%result (addr ({int*} res1))

%fun writeIntAddr :: Addr -> Int -> Int -> IO ()
%call (addr ({int*} s)) (int i) (int v)
%{ s[i] = v; %}

%fun readIntAddr :: Addr -> Int -> IO Int
%call (addr ({int *} s)) (int i)
%{ res1 = s[i]; %}

-- ...and the Ugly! :-) -------------------------------------------------------
%C
% #include <stdio.h>
% #include <unistd.h>
% #include <sys/types.h>
% #include <sys/time.h>
%
% int 
% testFds (int *arg1, int *arg2, int *arg3, int arg4, int arg5)
% {
%     fd_set set_in;
%     fd_set set_out;
%     fd_set set_ex;
%     struct timeval timeout;
%
%     FD_ZERO (&set_in);
%     FD_ZERO (&set_out);
%     FD_ZERO (&set_ex);
%     while ((*arg1) >= 0) {
%          FD_SET (*arg1, &set_in);
%          arg1++;
%     }
%     while ((*arg2) >= 0) {
%          printf ("<<testFds out: %d >>\n", *arg2);
%          FD_SET (*arg2, &set_out);
%          arg2++;
%     }
%     while ((*arg3) >= 0) {
%          printf ("<<testFds ex: %d >>\n", *arg3);
%          FD_SET (*arg3, &set_ex);
%          arg3++;
%     }
%     timeout.tv_sec  = arg4;
%     timeout.tv_usec = arg5;
%     /* TEMP_FAILURE_RETRY(select(...)) on Linux? */
%     return select (FD_SETSIZE, &set_in, &set_out, &set_ex, &timeout);
% }
#ifndef HSELECT_H
#define HSELECT_H

/*
 * hSelect.h - part of HSelect, a Haskell interface for select(2)
 * Copyright (C) 1999 Michael Weber <[EMAIL PROTECTED]>
 */

int testFds (int *, int *, int *, int, int);

#endif /* HSELECT_H */
TOP = ..
include $(TOP)/mk/boilerplate.mk

HS_PROG = hsel_test
HS_SRCS = HSelect.hs StdDIS.hs test.hs
C_SRCS  = HSelect_stub.c
HS_OBJS += $(C_OBJS)

CLEAN_FILES += HSelect_stub.c HSelect.hs StdDIS.hs

SRC_HC_OPTS += -recomp -cpp -fglasgow-exts -fvia-C -syslib concurrent
SRC_GREENCARD_OPTS += --haskell98 --target ghc

include $(TOP)/mk/target.mk
{- 
 - test.hs - Test for HSelect module
 -}
module Main where

import Concurrent
import HSelect
import IO

-- timeout says, how "preemptive" aPGetLine is...
almostPreemptiveGetLine :: Int -> Handle -> IO String
almostPreemptiveGetLine timeout handle = loop ""
  where 
      loop str = do
          tst <- testHandles [handle] [] [] 0 timeout {- msec -}
          if tst == IOAvail then getL str
                            else loop str
      getL s = do
          c <- hGetChar handle
          if c == '\n' then return (reverse s)
                       else loop (c:s)
      

main = do
    hSetBuffering stdin NoBuffering
    forkIO (loop 'a')
    booga
  where
      loop ch = hPutChar stdout ch >> loop ch
      booga   = do out <- almostPreemptiveGetLine 100 stdin
                   hPutStrLn stdout out
                   booga

Reply via email to